Dean,

Thanks for the intro to SQL::Preproc. I'll add it to my "see also" section (possibly along with SQL::String). I wasn't specifically aware of your module, but I had seen things like it in other languages.

Yes, SQL-Interpolate does support variable references embedded in strings. However, you need to enable the optional SQL::Interpolate::Filter module: http://search.cpan.org/dist/SQL-Interpolate/lib/SQL/Interpolate/Filter.pm

Your example can then be rewritten as something like

use DBIx::Interpolate FILTER => 1, qw(:all);
...
my ($col1, $col2, $col3, $param1, $param2) = (...);
my $ref = $dbx->selectall_arrayref(sql[
    select * into $col1, $col2, $col3
    from mytable
    where somecolumn = $param1 or othercolumn < $param2
]);

Now, the above approach does use source filtering. Since a number of people I talked to distrust source filtering, I moved this capability into the separate module and made it entirely optional. The source filtering I use is quite robust, and I did much testing, but it could fail on very quite obscure cases. sql[...] behaves like a Perl "quote-like" operator (similar to that provided in SQL::Quotelike http://search.cpan.org/~rgarcia/Sub-Quotelike-0.03/lib/Sub/Quotelike.pm but I found that module's source filtering to be too simplistic). Each sql[...] operator is translated into an object constructor, SQL::Interpolate::SQL->(...) and supports the concatenation operator, so it can be used as almost any standard Perl expression:

  return sql[select * from mytable] . sql[where x=$x] if $condition.

_All_ variables referenced within the operator (e.g. "$x" above) are properly converted to DBI bind variables stored in the object. I'm somewhat fond of your use of the ":" syntax though since this might clarify the special meaning and differentiate it from the standard Perl string interpolation.

Unfortunately, I know no good way around using source filtering here due to the scoping issues (a subroutines cannot typically see the lexical variables of its caller). I think PadWalker (http://search.cpan.org/dist/PadWalker/PadWalker.pm) is promising way around this, but it was not quite stable enough the last time I tested it.

I believe our modules have a similar aim. Some differences I see are that the core SQL::Interpolate module is not dependent on source filtering, and the SQL is treated more as a first-class object separate from the Perl code. In your module the SQL is more an extension to the Perl language via source filtering. Further, SQL::Preproc extends the SQL syntax (e.g. "SELECT * INTO :$x") to support returning variables from queries. In contrast, SQL::Interpolate does not extend the SQL syntax (and does it's best to not extend Perl), but it deals only with interpolating Perl variables into queries, whereas returning variables from queries is the job of something like DBI, DBIx::Interpolate, or DBIx::Simple).

best regards, davidm


Dean Arnold wrote:
David Manura wrote:

SQL-Interpolate 0.31 is now available on CPAN: http://search.cpan.org/dist/SQL-Interpolate/ . This includes a new ("WHERE", {x => [EMAIL PROTECTED], ...}) syntax, bug fixes, and clarified documentation. Discussions on the module will now take place on the CPAN::Forum (http://www.cpanforum.com/dist/SQL-Interpolate).


Have you considered just embedding the variable references
in the SQL string (ala SQL::Preproc
http://search.cpan.org/~darnold/SQL-Preproc-0.10/Preproc.pod) ?
E.g.,

my ($col1, $col2, $col3, $param1, $param2);
#...set values...
my $sth = $dbh->prepare(
'select * into :$col1, :$col2, :$col3
from mytable
where somecolumn = :$param1 or othercolumn < :$param2');

While double quoted SQL strings are problematic, single quoted
SQL and heredocs should be OK, (and, of course, escaping
the perl variable in double quoted strings works too).

You should be able to collect/translate the placeholders
at runtime, and use eval {} to apply them to the
translated statement. (which is different than SQL::Prepoc,
which uses a source filter to collect/translate).

Dean Arnold
Presicient Corp.

Reply via email to