Wednesday, June 28, 2017

Binding parameters for Oracle INTERVAL Literals

If you've ever tried to use the Perl DBI to execute a SQL statement like this:

select sysdate + interval '1' month from dual

...and wanted to make the interval a parameter, you may have tried various permutations, gotten frustrated and just injected a string into the query.  There is a solution...
my $query;

eval {
  my $sth = $dbi->prepare($query = "select sysdate + interval ? day from dual");
  $sth->execute(30);
};

print $@ ? "NOPE: $@\n" : "Winner,winner,chicken dinner!\n$query\n";

eval {
  my $sth = $dbi->prepare($query = "select sysdate + interval ? from dual");
  $sth->execute("'30' day");
};

print $@ ? "NOPE: $@\n" : "Winner,winner,chicken dinner!\n$query\n";

eval {
  my $sth = $dbi->prepare($query = "select sysdate + ? day from dual");
  $sth->execute("interval '30' day");
};

print $@ ? "NOPE: $@\n" : "Winner,winner,chicken dinner!\n$query\n";


eval {
  my $sth = $dbi->prepare($query = "select sysdate + numtodsinterval(?, 'day') from dual");
  $sth->execute("30");
};

print $@ ? "NOPE: $@\n" : "Winner,winner,chicken dinner!\n$query\n";


So, it turns out that Oracle literals are a funny kinda bird.  Learn more here.  The secret is to use the function NUMTODSINTERVAL which will convert a numeric to a literal.  Then we bind the number, our winner is the last query that uses NUMTODSINTERVAL.

I have not been able to find any way to directly bind a LITERAL value other than to convert it using the aforementioned function.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.