NAME

SQL::Interpolate - Simplified interpolation of variables into SQL statements.


SYNOPSIS

  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);


NOTES

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.


Functions

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.