SQL::Interpolate - Simplified interpolation of variables into SQL statements.
use DBI; use SQL::Interpolate; my $rows = $dbh->selectall_arrayref(dbi_interpolate qq[ SELECT * FROM table WHERE color IN], \@colors, qq[ AND y = ], \$x, qq[ LIMIT], [1, 10] ); $dbh->do(dbi_interpolate qq[ INSERT INTO table ], { color => $new_color, shape => $new_shape} ); $dbh->do(dbi_interpolate qq[ UPDATE table SET ], { color => $new_color, shape => $new_shape}, qq[ WHERE color <> ], \$color ); my($sql, @bind) = sql_interpolate qq[ SELECT * FROM table WHERE color IN], \@colors, qq[ AND y = ], \$x ); $d->prepare($sql); $d->execute(@bind);
This module provides an easy way to interpolate variables into SQL statements. SQL::Interpolate enables you to do this:
my $rows = $dbh->selectall_arrayref(dbi_interpolate qq[ SELECT thid, date_modified, suid, title, state, num_messages FROM threads WHERE state <> ], \$state, qq[AND suid IN], \@suids, qq[ ORDER BY t.date_modified DESC LIMIT], [$page*$count, $count] );
rather than
my $where .= '(0 ' . join('', map {" OR suid = " . $dbh->quote($_)} @suid) . ')'; my $rows = $dbh->selectall_arrayref(qq( SELECT thid, date_modified, suid, title, state, num_messages FROM threads WHERE state <> ? AND $where ORDER BY t.date_modified DESC LIMIT ?, ? ), undef, $state, $page*$count, $count);
You can also do something like
$dbh->do(dbi_interpolate qq[ INSERT INTO table ], { color => $new_color, shape => $new_shape width => $width, height => $height, length => $length } );
rather than
$dbh->do(qq( INSERT INTO table (color, shape, width, height, length) VALUES(?, ?, ?, ?, ? ) ), undef, $new_color, $new_shape, $width, $height, $length);
The purpose of SQL::Interpolate, therefore, is to make SQL statements in Perl more natural, less redundant, and less error-prone. SQL::Interpolate takes your query specification and generates correctly formatted SQL statements and bind values. These result values can then be passed to DBI or used for another purpose. SQL::Interpolate serves a purpose similar to that of SQL::Abstract except that SQL::Interpolate still exposes and utilizes the full native SQL syntax of your database.
sql_interpolate
($sql, @bind) = &sql_interpolate(...);
This function strings to together the passed parameters to generate a properly formatted SQL statement with bind (``?'') parameters along with corresponding values in @bind.
To use sql_interpolate, pass it a list containing strings and references. The strings are copied mostly verbatim into the output SQL (unless fine adjustment is needed), while the references are dereferenced and interpolated into the SQL using binding (``?'') placeholders, and corresponding values are pushed into @bind.
For example,
my @colors = ('blue', 'green'); my($sql, @bind) = sql_interpolate qq[ SELECT * FROM table WHERE color IN], \@colors, qq[ AND y = ], \$x ;
is equivalent to the following (bar whitespaces):
my $sql = "SELECT * FROM table WHERE color IN (?, ?) AND y = ?"; my @bind = ('blue', 'green', $x);
Note that variables must be passed as references (e.g. \$x), otherwise they will be interpolated verbatim into the SQL. Also, whitespaces are automatically added between parameters, so you don't need to insert a space after the IN.
SQL::Interpolate will Do The Right Thing(TM)
on trivial cases. For
example, the above example will generate the following SQL if @colors
is an empty list:
SELECT * FROM table WHERE shape = 'square' AND NULL
because the following mechanical answer is not valid SQL:
SELECT * FROM table WHERE shape = 'square' AND color IN ()
A future version of SQL::Interpolate might optimize away such NULL expressions. However, without loss of generality, we can just as well let the database do this, as databases are designed to do query optimization.
Furthermore, variable interpolation is affected by context. So,
sql_interpolate(qq[ INSERT INTO mytable ], {color => 'blue', shape => 'square'} );
generates
INSERT INTO mytable (color, shape) VALUES(?, ?)
whereas the following containing the same hash expression
sql_interpolate(qq[ UPDATE mytable SET ], {color => 'blue', shape => 'square'} );
generates SQL containing a different corresponding sub-expression:
UPDATE mytable SET color = ?, shape = ?
=item C<dbi_interpolate>
($sql, $attr, @bind) = &dbi_interpolate(...);
This function is the same as sql_interpolate
except that is returns
an extra $attr value (set to undef) so that the return signature
matches the signature on many of the DBI module methods. This allows
you to construct and execute an SQL statement in a single statement as
shown in the SYNPOSIS.