1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
|
NAME
DBIx::MultiStatementDo - Multiple SQL statements in a single do() call
with any DBI driver
VERSION
version 1.00009
SYNOPSIS
use DBI;
use DBIx::MultiStatementDo;
# Multiple SQL statements in a single string
my $sql_code = <<'SQL';
CREATE TABLE parent (a, b, c , d );
CREATE TABLE child (x, y, "w;", "z;z");
/* C-style comment; */
CREATE TRIGGER "check;delete;parent;" BEFORE DELETE ON parent WHEN
EXISTS (SELECT 1 FROM child WHERE old.a = x AND old.b = y)
BEGIN
SELECT RAISE(ABORT, 'constraint failed;'); -- Inlined SQL comment
END;
-- Standalone SQL; comment; w/ semicolons;
INSERT INTO parent (a, b, c, d) VALUES ('pippo;', 'pluto;', NULL, NULL);
SQL
my $dbh = DBI->connect( 'dbi:SQLite:dbname=my.db', '', '' );
my $batch = DBIx::MultiStatementDo->new( dbh => $dbh );
# Multiple SQL statements in a single call
my @results = $batch->do( $sql_code )
or die $batch->dbh->errstr;
print scalar(@results) . ' statements successfully executed!';
# 4 statements successfully executed!
DESCRIPTION
Some DBI drivers don't support the execution of multiple statements in a
single "do()" call. This module tries to overcome such limitation,
letting you execute any number of SQL statements (of any kind, not only
DDL statements) in a single batch, with any DBI driver.
Here is how DBIx::MultiStatementDo works: behind the scenes it parses
the SQL code, splits it into the atomic statements it is composed of and
executes them one by one. To split the SQL code SQL::SplitStatement is
used, which uses a more sophisticated logic than a raw "split" on the
";" (semicolon) character: first, various different statement terminator
*tokens* are recognized, then SQL::SplitStatement is able to correctly
handle the presence of said tokens inside identifiers, values, comments,
"BEGIN ... END" blocks (even nested), *dollar-quoted* strings, MySQL
custom "DELIMITER"s, procedural code etc., as (partially) exemplified in
the "SYNOPSIS" above.
Automatic transactions support is offered by default, so that you'll
have the *all-or-nothing* behaviour you would probably expect; if you
prefer, you can anyway disable it and manage the transactions yourself.
METHODS
"new"
* "DBIx::MultiStatementDo->new( %options )"
* "DBIx::MultiStatementDo->new( \%options )"
It creates and returns a new DBIx::MultiStatementDo object. It accepts
its options either as an hash or an hashref.
The following options are recognized:
* "dbh"
The database handle object as returned by DBI::connect(). This
option is required.
* "rollback"
A Boolean option which enables (when true) or disables (when false)
automatic transactions. It is set to a true value by default.
* "splitter_options"
This is the options hashref which is passed unaltered to
"SQL::SplitStatement->new()" to build the *splitter object*, which
is then internally used by DBIx::MultiStatementDo to split the given
SQL string.
It defaults to "undef", which should be the best value if the given
SQL string contains only standard SQL. If it contains contains also
procedural code, you may need to fine tune this option.
Please refer to SQL::SplitStatement::new() to see the options it
takes.
"do"
* "$batch->do( $sql_string | \@sql_statements )"
* "$batch->do( $sql_string | \@sql_statements , \%attr )"
* "$batch->do( $sql_string | \@sql_statements , \%attr, \@bind_values
| @bind_values )"
This is the method which actually executes the SQL statements against
your db. As its first (mandatory) argument, it takes an SQL string
containing one or more SQL statements. The SQL string is split into its
atomic statements, which are then executed one-by-one, in the same order
they appear in the given string.
The first argument can also be a reference to a list of (already split)
statements, in which case no split is performed and the statements are
executed as they appear in the list. The list can also be a two-elements
list, where the first element is the statements listref as above, and
the second is the *placeholder numbers* listref, exactly as returned by
the SQL::SplitStatement::split_with_placeholders() method.
Analogously to DBI's "do()", it optionally also takes an hashref of
attributes (which is passed unaltered to "$batch->dbh->do()" for each
atomic statement), and the *bind values*, either as a listref or a flat
list (see below for the difference).
In list context, "do" returns a list containing the values returned by
the "$batch->dbh->do()" call on each single atomic statement.
If the "rollback" option has been set (and therefore automatic
transactions are enabled), in case one of the atomic statements fails,
all the other succeeding statements executed so far, if any, are rolled
back and the method (immediately) returns an empty list (since no
statements have actually been committed).
If the "rollback" option is set to a false value (and therefore
automatic transactions are disabled), the method immediately returns at
the first failing statement as above, but it does not roll back any
prior succeeding statement, and therefore a list containing the values
returned by the statements (successfully) executed so far is returned
(and these statements are actually committed to the db, if
"$dbh->{AutoCommit}" is set).
In scalar context it returns, regardless of the value of the "rollback"
option, "undef" if any of the atomic statements failed, or a true value
if all of the atomic statements succeeded.
Note that to activate the automatic transactions you don't have to do
anything more than setting the "rollback" option to a true value (or
simply do nothing, as it is the default): DBIx::MultiStatementDo will
automatically (and temporarily, via "local") set "$dbh->{AutoCommit}"
and "$dbh->{RaiseError}" as needed. No other DBI db handle attribute is
ever touched, so that you can for example set "$dbh->{PrintError}" and
enjoy its effects in case of a failing statement.
If you want to disable the automatic transactions and manage them by
yourself, you can do something along this:
my $batch = DBIx::MultiStatementDo->new(
dbh => $dbh,
rollback => 0
);
my @results;
$batch->dbh->{AutoCommit} = 0;
$batch->dbh->{RaiseError} = 1;
eval {
@results = $batch->do( $sql_string );
$batch->dbh->commit;
1
} or eval {
$batch->dbh->rollback
};
Bind Values as a List Reference
The bind values can be passed as a reference to a list of listrefs, each
of which contains the bind values for the atomic statement it
corresponds to. The bind values *inner* lists must match the
corresponding atomic statements as returned by the internal *splitter
object*, with "undef" (or empty listref) elements where the
corresponding atomic statements have no *placeholders*.
Here is an example:
# 7 statements (SQLite valid SQL)
my $sql_code = <<'SQL';
CREATE TABLE state (id, name);
INSERT INTO state (id, name) VALUES (?, ?);
CREATE TABLE city (id, name, state_id);
INSERT INTO city (id, name, state_id) VALUES (?, ?, ?);
INSERT INTO city (id, name, state_id) VALUES (?, ?, ?);
DROP TABLE city;
DROP TABLE state
SQL
# Only 5 elements are required in the bind values list
my $bind_values = [
undef , # or []
[ 1, 'Nevada' ] ,
[] , # or undef
[ 1, 'Las Vegas' , 1 ],
[ 2, 'Carson City', 1 ]
];
my $batch = DBIx::MultiStatementDo->new( dbh => $dbh );
my @results = $batch->do( $sql_code, undef, $bind_values )
or die $batch->dbh->errstr;
If the last statements have no placeholders, the corresponding "undef"s
don't need to be present in the bind values list, as shown above. The
bind values list can also have more elements than the number of the
atomic statements, in which case the excess elements will simply be
ignored.
Bind Values as a Flat List
This is a much more powerful feature of "do": when it gets the bind
values as a flat list, it automatically assigns them to the
corresponding placeholders (no *interleaving* "undef"s are necessary in
this case).
In other words, you can regard the given SQL code as a single big
statement and pass the bind values exactly as you would do with the
ordinary DBI "do" method.
For example, given $sql_code from the example above, you could simply
do:
my @bind_values = ( 1, 'Nevada', 1, 'Las Vegas', 1, 2, 'Carson City', 1 );
my @results = $batch->do( $sql_code, undef, @bind_values )
or die $batch->dbh->errstr;
and get exactly the same result.
Difference between Bind Values as a List Reference and as a Flat List
If you want to pass the bind values as a flat list as described above,
you must pass the first parameter to "do" either as a string (so that
the internal splitting is performed) or, if you want to disable the
internal splitting, as a reference to the two-elements list containing
both the statements and the placeholder numbers listrefs (as described
above in do).
In other words, you can't pass the bind values as a flat list and pass
at the same time the (already split) statements without the placeholder
numbers listref. To do so, you need to pass the bind values as a list
reference instead, otherwise "do" throws an exception.
To summarize, bind values as a flat list is easier to use but it suffers
from this subtle limitation, while bind values as a list reference is a
little bit more cumbersome to use, but it has no limitations and can
therefore always be used.
Recognized Placeholders
The recognized placeholders are:
* *question mark* placeholders, represented by the "?" character;
* *dollar sign numbered* placeholders, represented by the "$1, $2,
..., $n" strings;
* *named parameters*, such as ":foo", ":bar", ":baz" etc.
"dbh"
* "$batch->dbh"
* "$batch->dbh( $new_dbh )"
Getter/setter method for the "dbh" option explained above.
"rollback"
* "$batch->rollback"
* "$batch->rollback( $boolean )"
Getter/setter method for the "rollback" option explained above.
"splitter_options"
* "$batch->splitter_options"
* "$batch->splitter_options( \%options )"
Getter/setter method for the "splitter_options" option explained
above.
"split" and "split_with_placeholders"
* "$batch->split( $sql_code )"
* "$batch->split_with_placeholders( $sql_code )"
These are the methods used internally to split the given SQL code. They
call respectively "split" and "split_with_placeholders" on a
SQL::SplitStatement instance built with the "splitter_options" described
above.
Normally they shouldn't be used directly, but they could be useful if
you want to see how your SQL code has been split.
If you want instead to see how your SQL code *will be* split, that is
before executing "do", you can use SQL::SplitStatement by yourself:
use SQL::SplitStatement;
my $splitter = SQL::SplitStatement->new( \%splitter_options );
my @statements = $splitter->split( $sql_code );
# Now you can check @statements if you want...
and then you can execute your statements preventing "do" from performing
the splitting again, by passing "\@statements" to it:
my $batch = DBIx::MultiStatementDo->new( dbh => $dbh );
my @results = $batch->do( \@statements ); # This does not perform the splitting again.
Warning! In previous versions, the "split_with_placeholders" (public)
method documented above did not work, so there is the possibility that
someone used the (private, undocumented) "_split_with_placeholders"
method instead (which worked correctly). In this case, please start
using the public method (which now works as advertised), since the
private method will be removed in future versions.
LIMITATIONS
Please look at: SQL::SplitStatement LIMITATIONS
DEPENDENCIES
DBIx::MultiStatementDo depends on the following modules:
* SQL::SplitStatement 0.10000 or newer
* Moose
AUTHOR
Emanuele Zeppieri, "<emazep@cpan.org>"
BUGS
No known bugs so far.
Please report any bugs or feature requests to "bug-dbix-MultiStatementDo
at rt.cpan.org", or through the web interface at
<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=DBIx-MultiStatementDo>.
I will be notified, and then you'll automatically be notified of
progress on your bug as I make changes.
SUPPORT
You can find documentation for this module with the perldoc command.
perldoc DBIx::MultiStatementDo
You can also look for information at:
* RT: CPAN's request tracker
<http://rt.cpan.org/NoAuth/Bugs.html?Dist=DBIx-MultiStatementDo>
* AnnoCPAN: Annotated CPAN documentation
<http://annocpan.org/dist/DBIx-MultiStatementDo>
* CPAN Ratings
<http://cpanratings.perl.org/d/DBIx-MultiStatementDo>
* Search CPAN
<http://search.cpan.org/dist/DBIx-MultiStatementDo/>
ACKNOWLEDGEMENTS
Matt S Trout, for having suggested a much more suitable name for this
module.
SEE ALSO
* SQL::SplitStatement
* DBI
LICENSE AND COPYRIGHT
Copyright 2010-2011 Emanuele Zeppieri.
This program is free software; you can redistribute it and/or modify it
under the terms of either: the GNU General Public License as published
by the Free Software Foundation, or the Artistic License.
See http://dev.perl.org/licenses/ for more information.
|