First stab at adding resultsources to each join in select - works won-der-ful-ly
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI.pm
CommitLineData
8b445e33 1package DBIx::Class::Storage::DBI;
e673f011 2# -*- mode: cperl; cperl-indent-level: 2 -*-
8b445e33 3
a62cf8d4 4use base 'DBIx::Class::Storage';
5
eda28767 6use strict;
20a2c954 7use warnings;
550adccc 8use Carp::Clan qw/^DBIx::Class/;
8b445e33 9use DBI;
6f4ddea1 10use DBIx::Class::SQLAHacks;
28927b50 11use DBIx::Class::Storage::DBI::Cursor;
4c248161 12use DBIx::Class::Storage::Statistics;
ba61fa2a 13use Scalar::Util();
15827712 14use List::Util();
046ad905 15
541df64a 16__PACKAGE__->mk_group_accessors('simple' =>
17 qw/_connect_info _dbi_connect_info _dbh _sql_maker _sql_maker_opts
92fe2181 18 _conn_pid _conn_tid transaction_depth _dbh_autocommit savepoints/
046ad905 19);
20
92fe2181 21# the values for these accessors are picked out (and deleted) from
22# the attribute hashref passed to connect_info
23my @storage_options = qw/
24 on_connect_do on_disconnect_do disable_sth_caching unsafe auto_savepoint
25/;
26__PACKAGE__->mk_group_accessors('simple' => @storage_options);
27
28
29# default cursor class, overridable in connect_info attributes
e4eb8ee1 30__PACKAGE__->cursor_class('DBIx::Class::Storage::DBI::Cursor');
31
95ba7ee4 32__PACKAGE__->mk_group_accessors('inherited' => qw/sql_maker_class/);
6f4ddea1 33__PACKAGE__->sql_maker_class('DBIx::Class::SQLAHacks');
95ba7ee4 34
bd7efd39 35
b327f988 36=head1 NAME
37
38DBIx::Class::Storage::DBI - DBI storage handler
39
40=head1 SYNOPSIS
41
5d52945a 42 my $schema = MySchema->connect('dbi:SQLite:my.db');
43
44 $schema->storage->debug(1);
45 $schema->dbh_do("DROP TABLE authors");
46
47 $schema->resultset('Book')->search({
48 written_on => $schema->storage->datetime_parser(DateTime->now)
49 });
50
b327f988 51=head1 DESCRIPTION
52
046ad905 53This class represents the connection to an RDBMS via L<DBI>. See
54L<DBIx::Class::Storage> for general information. This pod only
55documents DBI-specific methods and behaviors.
b327f988 56
57=head1 METHODS
58
9b83fccd 59=cut
60
8b445e33 61sub new {
046ad905 62 my $new = shift->next::method(@_);
82cc0386 63
d79f59b9 64 $new->transaction_depth(0);
2cc3a7be 65 $new->_sql_maker_opts({});
ddf66ced 66 $new->{savepoints} = [];
1b994857 67 $new->{_in_dbh_do} = 0;
dbaee748 68 $new->{_dbh_gen} = 0;
82cc0386 69
046ad905 70 $new;
1c339d71 71}
72
1b45b01e 73=head2 connect_info
74
92fe2181 75This method is normally called by L<DBIx::Class::Schema/connection>, which
76encapsulates its argument list in an arrayref before passing them here.
77
78The argument list may contain:
79
80=over
81
82=item *
83
5d52945a 84The same 4-element argument set one would normally pass to
40911cb3 85L<DBI/connect>, optionally followed by
86L<extra attributes|/DBIx::Class specific connection attributes>
87recognized by DBIx::Class:
92fe2181 88
5d52945a 89 $connect_info_args = [ $dsn, $user, $password, \%dbi_attributes?, \%extra_attributes? ];
92fe2181 90
91=item *
1b45b01e 92
40911cb3 93A single code reference which returns a connected
94L<DBI database handle|DBI/connect> optionally followed by
95L<extra attributes|/DBIx::Class specific connection attributes> recognized
96by DBIx::Class:
1b45b01e 97
5d52945a 98 $connect_info_args = [ sub { DBI->connect (...) }, \%extra_attributes? ];
92fe2181 99
100=item *
101
5d52945a 102A single hashref with all the attributes and the dsn/user/password
103mixed together:
92fe2181 104
105 $connect_info_args = [{
106 dsn => $dsn,
107 user => $user,
34f1f658 108 password => $pass,
92fe2181 109 %dbi_attributes,
110 %extra_attributes,
111 }];
112
113This is particularly useful for L<Catalyst> based applications, allowing the
40911cb3 114following config (L<Config::General> style):
92fe2181 115
116 <Model::DB>
117 schema_class App::DB
118 <connect_info>
119 dsn dbi:mysql:database=test
120 user testuser
121 password TestPass
122 AutoCommit 1
123 </connect_info>
124 </Model::DB>
125
126=back
127
5d52945a 128Please note that the L<DBI> docs recommend that you always explicitly
129set C<AutoCommit> to either I<0> or I<1>. L<DBIx::Class> further
130recommends that it be set to I<1>, and that you perform transactions
40911cb3 131via our L<DBIx::Class::Schema/txn_do> method. L<DBIx::Class> will set it
132to I<1> if you do not do explicitly set it to zero. This is the default
133for most DBDs. See L</DBIx::Class and AutoCommit> for details.
92fe2181 134
135=head3 DBIx::Class specific connection attributes
136
137In addition to the standard L<DBI|DBI/ATTRIBUTES_COMMON_TO_ALL_HANDLES>
138L<connection|DBI/Database_Handle_Attributes> attributes, DBIx::Class recognizes
139the following connection options. These options can be mixed in with your other
140L<DBI> connection attributes, or placed in a seperate hashref
141(C<\%extra_attributes>) as shown above.
142
143Every time C<connect_info> is invoked, any previous settings for
144these options will be cleared before setting the new ones, regardless of
145whether any options are specified in the new C<connect_info>.
d7c4c15c 146
2cc3a7be 147
5d52945a 148=over
2cc3a7be 149
150=item on_connect_do
151
6d2e7a96 152Specifies things to do immediately after connecting or re-connecting to
153the database. Its value may contain:
154
155=over
156
00f57441 157=item a scalar
158
159This contains one SQL statement to execute.
160
6d2e7a96 161=item an array reference
162
163This contains SQL statements to execute in order. Each element contains
164a string or a code reference that returns a string.
165
166=item a code reference
167
168This contains some code to execute. Unlike code references within an
169array reference, its return value is ignored.
170
171=back
579ca3f7 172
173=item on_disconnect_do
174
5d52945a 175Takes arguments in the same form as L</on_connect_do> and executes them
6d2e7a96 176immediately before disconnecting from the database.
579ca3f7 177
5d52945a 178Note, this only runs if you explicitly call L</disconnect> on the
579ca3f7 179storage object.
2cc3a7be 180
b33697ef 181=item disable_sth_caching
182
183If set to a true value, this option will disable the caching of
184statement handles via L<DBI/prepare_cached>.
185
2cc3a7be 186=item limit_dialect
187
188Sets the limit dialect. This is useful for JDBC-bridge among others
189where the remote SQL-dialect cannot be determined by the name of the
5d52945a 190driver alone. See also L<SQL::Abstract::Limit>.
2cc3a7be 191
192=item quote_char
d7c4c15c 193
2cc3a7be 194Specifies what characters to use to quote table and column names. If
5d52945a 195you use this you will want to specify L</name_sep> as well.
2cc3a7be 196
5d52945a 197C<quote_char> expects either a single character, in which case is it
198is placed on either side of the table/column name, or an arrayref of length
1992 in which case the table/column name is placed between the elements.
2cc3a7be 200
5d52945a 201For example under MySQL you should use C<< quote_char => '`' >>, and for
202SQL Server you should use C<< quote_char => [qw/[ ]/] >>.
2cc3a7be 203
204=item name_sep
205
40911cb3 206This only needs to be used in conjunction with C<quote_char>, and is used to
2cc3a7be 207specify the charecter that seperates elements (schemas, tables, columns) from
208each other. In most cases this is simply a C<.>.
209
5d52945a 210The consequences of not supplying this value is that L<SQL::Abstract>
211will assume DBIx::Class' uses of aliases to be complete column
212names. The output will look like I<"me.name"> when it should actually
213be I<"me"."name">.
214
61646ebd 215=item unsafe
216
217This Storage driver normally installs its own C<HandleError>, sets
2ab60eb9 218C<RaiseError> and C<ShowErrorStatement> on, and sets C<PrintError> off on
219all database handles, including those supplied by a coderef. It does this
220so that it can have consistent and useful error behavior.
61646ebd 221
222If you set this option to a true value, Storage will not do its usual
2ab60eb9 223modifications to the database handle's attributes, and instead relies on
224the settings in your connect_info DBI options (or the values you set in
225your connection coderef, in the case that you are connecting via coderef).
61646ebd 226
227Note that your custom settings can cause Storage to malfunction,
228especially if you set a C<HandleError> handler that suppresses exceptions
229and/or disable C<RaiseError>.
230
a3628767 231=item auto_savepoint
232
233If this option is true, L<DBIx::Class> will use savepoints when nesting
234transactions, making it possible to recover from failure in the inner
235transaction without having to abort all outer transactions.
236
34f1f658 237=item cursor_class
238
239Use this argument to supply a cursor class other than the default
240L<DBIx::Class::Storage::DBI::Cursor>.
241
2cc3a7be 242=back
243
5d52945a 244Some real-life examples of arguments to L</connect_info> and
245L<DBIx::Class::Schema/connect>
2cc3a7be 246
247 # Simple SQLite connection
bb4f246d 248 ->connect_info([ 'dbi:SQLite:./foo.db' ]);
6789ebe3 249
2cc3a7be 250 # Connect via subref
bb4f246d 251 ->connect_info([ sub { DBI->connect(...) } ]);
6789ebe3 252
2cc3a7be 253 # A bit more complicated
bb4f246d 254 ->connect_info(
255 [
256 'dbi:Pg:dbname=foo',
257 'postgres',
258 'my_pg_password',
77d76d0f 259 { AutoCommit => 1 },
2cc3a7be 260 { quote_char => q{"}, name_sep => q{.} },
261 ]
262 );
263
264 # Equivalent to the previous example
265 ->connect_info(
266 [
267 'dbi:Pg:dbname=foo',
268 'postgres',
269 'my_pg_password',
77d76d0f 270 { AutoCommit => 1, quote_char => q{"}, name_sep => q{.} },
bb4f246d 271 ]
272 );
6789ebe3 273
92fe2181 274 # Same, but with hashref as argument
5d52945a 275 # See parse_connect_info for explanation
92fe2181 276 ->connect_info(
277 [{
278 dsn => 'dbi:Pg:dbname=foo',
279 user => 'postgres',
280 password => 'my_pg_password',
281 AutoCommit => 1,
282 quote_char => q{"},
283 name_sep => q{.},
284 }]
285 );
286
287 # Subref + DBIx::Class-specific connection options
bb4f246d 288 ->connect_info(
289 [
290 sub { DBI->connect(...) },
2cc3a7be 291 {
292 quote_char => q{`},
293 name_sep => q{@},
294 on_connect_do => ['SET search_path TO myschema,otherschema,public'],
b33697ef 295 disable_sth_caching => 1,
2cc3a7be 296 },
bb4f246d 297 ]
298 );
6789ebe3 299
92fe2181 300
301
004d31fb 302=cut
303
046ad905 304sub connect_info {
305 my ($self, $info_arg) = @_;
4c248161 306
046ad905 307 return $self->_connect_info if !$info_arg;
4c248161 308
92fe2181 309 my @args = @$info_arg; # take a shallow copy for further mutilation
310 $self->_connect_info([@args]); # copy for _connect_info
311
312
313 # combine/pre-parse arguments depending on invocation style
314
315 my %attrs;
316 if (ref $args[0] eq 'CODE') { # coderef with optional \%extra_attributes
317 %attrs = %{ $args[1] || {} };
318 @args = $args[0];
319 }
320 elsif (ref $args[0] eq 'HASH') { # single hashref (i.e. Catalyst config)
321 %attrs = %{$args[0]};
322 @args = ();
323 for (qw/password user dsn/) {
324 unshift @args, delete $attrs{$_};
325 }
326 }
34f1f658 327 else { # otherwise assume dsn/user/password + \%attrs + \%extra_attrs
92fe2181 328 %attrs = (
329 % { $args[3] || {} },
330 % { $args[4] || {} },
331 );
332 @args = @args[0,1,2];
333 }
334
046ad905 335 # Kill sql_maker/_sql_maker_opts, so we get a fresh one with only
336 # the new set of options
337 $self->_sql_maker(undef);
338 $self->_sql_maker_opts({});
8df3d107 339
92fe2181 340 if(keys %attrs) {
341 for my $storage_opt (@storage_options, 'cursor_class') { # @storage_options is declared at the top of the module
342 if(my $value = delete $attrs{$storage_opt}) {
b33697ef 343 $self->$storage_opt($value);
344 }
046ad905 345 }
346 for my $sql_maker_opt (qw/limit_dialect quote_char name_sep/) {
92fe2181 347 if(my $opt_val = delete $attrs{$sql_maker_opt}) {
046ad905 348 $self->_sql_maker_opts->{$sql_maker_opt} = $opt_val;
349 }
350 }
046ad905 351 }
d7c4c15c 352
92fe2181 353 %attrs = () if (ref $args[0] eq 'CODE'); # _connect() never looks past $args[0] in this case
354
355 $self->_dbi_connect_info([@args, keys %attrs ? \%attrs : ()]);
fdad5fab 356 $self->_connect_info;
046ad905 357}
004d31fb 358
046ad905 359=head2 on_connect_do
4c248161 360
5d52945a 361This method is deprecated in favour of setting via L</connect_info>.
486ad69b 362
92fe2181 363
f11383c2 364=head2 dbh_do
365
3ff1602f 366Arguments: ($subref | $method_name), @extra_coderef_args?
046ad905 367
3ff1602f 368Execute the given $subref or $method_name using the new exception-based
369connection management.
046ad905 370
d4f16b21 371The first two arguments will be the storage object that C<dbh_do> was called
372on and a database handle to use. Any additional arguments will be passed
373verbatim to the called subref as arguments 2 and onwards.
374
375Using this (instead of $self->_dbh or $self->dbh) ensures correct
376exception handling and reconnection (or failover in future subclasses).
377
378Your subref should have no side-effects outside of the database, as
379there is the potential for your subref to be partially double-executed
380if the database connection was stale/dysfunctional.
046ad905 381
56769f7c 382Example:
f11383c2 383
56769f7c 384 my @stuff = $schema->storage->dbh_do(
385 sub {
d4f16b21 386 my ($storage, $dbh, @cols) = @_;
387 my $cols = join(q{, }, @cols);
388 $dbh->selectrow_array("SELECT $cols FROM foo");
046ad905 389 },
390 @column_list
56769f7c 391 );
f11383c2 392
393=cut
394
395sub dbh_do {
046ad905 396 my $self = shift;
3ff1602f 397 my $code = shift;
aa27edf7 398
6ad1059d 399 my $dbh = $self->_dbh;
400
401 return $self->$code($dbh, @_) if $self->{_in_dbh_do}
cb19f4dd 402 || $self->{transaction_depth};
403
1b994857 404 local $self->{_in_dbh_do} = 1;
405
f11383c2 406 my @result;
407 my $want_array = wantarray;
408
409 eval {
6ad1059d 410 $self->_verify_pid if $dbh;
37976db0 411 if(!$self->_dbh) {
6ad1059d 412 $self->_populate_dbh;
413 $dbh = $self->_dbh;
414 }
415
f11383c2 416 if($want_array) {
6ad1059d 417 @result = $self->$code($dbh, @_);
f11383c2 418 }
56769f7c 419 elsif(defined $want_array) {
6ad1059d 420 $result[0] = $self->$code($dbh, @_);
f11383c2 421 }
56769f7c 422 else {
6ad1059d 423 $self->$code($dbh, @_);
56769f7c 424 }
f11383c2 425 };
56769f7c 426
aa27edf7 427 my $exception = $@;
428 if(!$exception) { return $want_array ? @result : $result[0] }
429
430 $self->throw_exception($exception) if $self->connected;
431
432 # We were not connected - reconnect and retry, but let any
433 # exception fall right through this time
434 $self->_populate_dbh;
3ff1602f 435 $self->$code($self->_dbh, @_);
aa27edf7 436}
437
438# This is basically a blend of dbh_do above and DBIx::Class::Storage::txn_do.
439# It also informs dbh_do to bypass itself while under the direction of txn_do,
1b994857 440# via $self->{_in_dbh_do} (this saves some redundant eval and errorcheck, etc)
aa27edf7 441sub txn_do {
442 my $self = shift;
443 my $coderef = shift;
444
445 ref $coderef eq 'CODE' or $self->throw_exception
446 ('$coderef must be a CODE reference');
447
d6feb60f 448 return $coderef->(@_) if $self->{transaction_depth} && ! $self->auto_savepoint;
57c18b65 449
1b994857 450 local $self->{_in_dbh_do} = 1;
f11383c2 451
aa27edf7 452 my @result;
453 my $want_array = wantarray;
454
d4f16b21 455 my $tried = 0;
456 while(1) {
457 eval {
458 $self->_verify_pid if $self->_dbh;
459 $self->_populate_dbh if !$self->_dbh;
aa27edf7 460
d4f16b21 461 $self->txn_begin;
462 if($want_array) {
463 @result = $coderef->(@_);
464 }
465 elsif(defined $want_array) {
466 $result[0] = $coderef->(@_);
467 }
468 else {
469 $coderef->(@_);
470 }
471 $self->txn_commit;
472 };
aa27edf7 473
d4f16b21 474 my $exception = $@;
475 if(!$exception) { return $want_array ? @result : $result[0] }
476
477 if($tried++ > 0 || $self->connected) {
478 eval { $self->txn_rollback };
479 my $rollback_exception = $@;
480 if($rollback_exception) {
481 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
482 $self->throw_exception($exception) # propagate nested rollback
483 if $rollback_exception =~ /$exception_class/;
484
485 $self->throw_exception(
486 "Transaction aborted: ${exception}. "
487 . "Rollback failed: ${rollback_exception}"
488 );
489 }
490 $self->throw_exception($exception)
aa27edf7 491 }
56769f7c 492
d4f16b21 493 # We were not connected, and was first try - reconnect and retry
494 # via the while loop
495 $self->_populate_dbh;
496 }
f11383c2 497}
498
9b83fccd 499=head2 disconnect
500
046ad905 501Our C<disconnect> method also performs a rollback first if the
9b83fccd 502database is not in C<AutoCommit> mode.
503
504=cut
505
412db1f4 506sub disconnect {
507 my ($self) = @_;
508
92925617 509 if( $self->connected ) {
6d2e7a96 510 my $connection_do = $self->on_disconnect_do;
511 $self->_do_connection_actions($connection_do) if ref($connection_do);
512
57c18b65 513 $self->_dbh->rollback unless $self->_dbh_autocommit;
92925617 514 $self->_dbh->disconnect;
515 $self->_dbh(undef);
dbaee748 516 $self->{_dbh_gen}++;
92925617 517 }
412db1f4 518}
519
e96a93df 520=head2 with_deferred_fk_checks
521
522=over 4
523
524=item Arguments: C<$coderef>
525
526=item Return Value: The return value of $coderef
527
528=back
529
530Storage specific method to run the code ref with FK checks deferred or
531in MySQL's case disabled entirely.
532
533=cut
534
535# Storage subclasses should override this
536sub with_deferred_fk_checks {
537 my ($self, $sub) = @_;
538
539 $sub->();
540}
541
f11383c2 542sub connected {
543 my ($self) = @_;
412db1f4 544
1346e22d 545 if(my $dbh = $self->_dbh) {
546 if(defined $self->_conn_tid && $self->_conn_tid != threads->tid) {
dbaee748 547 $self->_dbh(undef);
548 $self->{_dbh_gen}++;
549 return;
1346e22d 550 }
56769f7c 551 else {
552 $self->_verify_pid;
649bfb8c 553 return 0 if !$self->_dbh;
56769f7c 554 }
1346e22d 555 return ($dbh->FETCH('Active') && $dbh->ping);
556 }
557
558 return 0;
412db1f4 559}
560
f11383c2 561# handle pid changes correctly
56769f7c 562# NOTE: assumes $self->_dbh is a valid $dbh
f11383c2 563sub _verify_pid {
564 my ($self) = @_;
565
6ae3f9b9 566 return if defined $self->_conn_pid && $self->_conn_pid == $$;
f11383c2 567
f11383c2 568 $self->_dbh->{InactiveDestroy} = 1;
d3abf3fe 569 $self->_dbh(undef);
dbaee748 570 $self->{_dbh_gen}++;
f11383c2 571
572 return;
573}
574
412db1f4 575sub ensure_connected {
576 my ($self) = @_;
577
578 unless ($self->connected) {
8b445e33 579 $self->_populate_dbh;
580 }
412db1f4 581}
582
c235bbae 583=head2 dbh
584
585Returns the dbh - a data base handle of class L<DBI>.
586
587=cut
588
412db1f4 589sub dbh {
590 my ($self) = @_;
591
592 $self->ensure_connected;
8b445e33 593 return $self->_dbh;
594}
595
f1f56aad 596sub _sql_maker_args {
597 my ($self) = @_;
598
e5938571 599 return ( bindtype=>'columns', array_datatypes => 1, limit_dialect => $self->dbh, %{$self->_sql_maker_opts} );
f1f56aad 600}
601
48c69e7c 602sub sql_maker {
603 my ($self) = @_;
fdc1c3d0 604 unless ($self->_sql_maker) {
95ba7ee4 605 my $sql_maker_class = $self->sql_maker_class;
606 $self->_sql_maker($sql_maker_class->new( $self->_sql_maker_args ));
48c69e7c 607 }
608 return $self->_sql_maker;
609}
610
3ff1602f 611sub _rebless {}
612
8b445e33 613sub _populate_dbh {
614 my ($self) = @_;
7e47ea83 615 my @info = @{$self->_dbi_connect_info || []};
8b445e33 616 $self->_dbh($self->_connect(@info));
2fd24e78 617
9b3e916d 618 $self->_conn_pid($$);
619 $self->_conn_tid(threads->tid) if $INC{'threads.pm'};
620
d40080c3 621 $self->_determine_driver;
622
77d76d0f 623 # Always set the transaction depth on connect, since
624 # there is no transaction in progress by definition
57c18b65 625 $self->{transaction_depth} = $self->_dbh_autocommit ? 0 : 1;
77d76d0f 626
361ca8e5 627 my $connection_do = $self->on_connect_do;
00f57441 628 $self->_do_connection_actions($connection_do) if $connection_do;
8b445e33 629}
630
d40080c3 631sub _determine_driver {
632 my ($self) = @_;
633
634 if (ref $self eq 'DBIx::Class::Storage::DBI') {
635 my $driver;
636
637 if ($self->_dbh) { # we are connected
638 $driver = $self->_dbh->{Driver}{Name};
639 } else {
640 # try to use dsn to not require being connected, the driver may still
641 # force a connection in _rebless to determine version
642 ($driver) = $self->_dbi_connect_info->[0] =~ /dbi:([^:]+):/i;
643 }
644
645 if ($self->load_optional_class("DBIx::Class::Storage::DBI::${driver}")) {
646 bless $self, "DBIx::Class::Storage::DBI::${driver}";
647 $self->_rebless();
648 }
649 }
650}
651
6d2e7a96 652sub _do_connection_actions {
653 my $self = shift;
654 my $connection_do = shift;
655
00f57441 656 if (!ref $connection_do) {
657 $self->_do_query($connection_do);
658 }
659 elsif (ref $connection_do eq 'ARRAY') {
6d2e7a96 660 $self->_do_query($_) foreach @$connection_do;
661 }
662 elsif (ref $connection_do eq 'CODE') {
257d8d68 663 $connection_do->($self);
6d2e7a96 664 }
00f57441 665 else {
666 $self->throw_exception (sprintf ("Don't know how to process conection actions of type '%s'", ref $connection_do) );
667 }
6d2e7a96 668
669 return $self;
670}
671
579ca3f7 672sub _do_query {
673 my ($self, $action) = @_;
674
6d2e7a96 675 if (ref $action eq 'CODE') {
1dafdb2a 676 $action = $action->($self);
677 $self->_do_query($_) foreach @$action;
579ca3f7 678 }
679 else {
c9225efc 680 # Most debuggers expect ($sql, @bind), so we need to exclude
681 # the attribute hash which is the second argument to $dbh->do
682 # furthermore the bind values are usually to be presented
683 # as named arrayref pairs, so wrap those here too
684 my @do_args = (ref $action eq 'ARRAY') ? (@$action) : ($action);
685 my $sql = shift @do_args;
686 my $attrs = shift @do_args;
687 my @bind = map { [ undef, $_ ] } @do_args;
688
689 $self->_query_start($sql, @bind);
690 $self->_dbh->do($sql, $attrs, @do_args);
691 $self->_query_end($sql, @bind);
579ca3f7 692 }
693
694 return $self;
695}
696
8b445e33 697sub _connect {
698 my ($self, @info) = @_;
5ef3e508 699
9d31f7dc 700 $self->throw_exception("You failed to provide any connection info")
61646ebd 701 if !@info;
9d31f7dc 702
90ec6cad 703 my ($old_connect_via, $dbh);
704
5ef3e508 705 if ($INC{'Apache/DBI.pm'} && $ENV{MOD_PERL}) {
61646ebd 706 $old_connect_via = $DBI::connect_via;
707 $DBI::connect_via = 'connect';
5ef3e508 708 }
709
75db246c 710 eval {
f5de3933 711 if(ref $info[0] eq 'CODE') {
712 $dbh = &{$info[0]}
713 }
714 else {
715 $dbh = DBI->connect(@info);
61646ebd 716 }
717
e7827df0 718 if($dbh && !$self->unsafe) {
664612fb 719 my $weak_self = $self;
ba61fa2a 720 Scalar::Util::weaken($weak_self);
61646ebd 721 $dbh->{HandleError} = sub {
9bf06dc0 722 if ($weak_self) {
723 $weak_self->throw_exception("DBI Exception: $_[0]");
724 }
725 else {
726 croak ("DBI Exception: $_[0]");
727 }
61646ebd 728 };
2ab60eb9 729 $dbh->{ShowErrorStatement} = 1;
61646ebd 730 $dbh->{RaiseError} = 1;
731 $dbh->{PrintError} = 0;
f5de3933 732 }
75db246c 733 };
90ec6cad 734
735 $DBI::connect_via = $old_connect_via if $old_connect_via;
736
d92a4015 737 $self->throw_exception("DBI Connection failed: " . ($@||$DBI::errstr))
738 if !$dbh || $@;
90ec6cad 739
57c18b65 740 $self->_dbh_autocommit($dbh->{AutoCommit});
741
e571e823 742 $dbh;
8b445e33 743}
744
adb3554a 745sub svp_begin {
746 my ($self, $name) = @_;
adb3554a 747
ddf66ced 748 $name = $self->_svp_generate_name
749 unless defined $name;
750
751 $self->throw_exception ("You can't use savepoints outside a transaction")
752 if $self->{transaction_depth} == 0;
753
754 $self->throw_exception ("Your Storage implementation doesn't support savepoints")
755 unless $self->can('_svp_begin');
756
757 push @{ $self->{savepoints} }, $name;
adb3554a 758
adb3554a 759 $self->debugobj->svp_begin($name) if $self->debug;
ddf66ced 760
761 return $self->_svp_begin($name);
adb3554a 762}
763
764sub svp_release {
765 my ($self, $name) = @_;
766
ddf66ced 767 $self->throw_exception ("You can't use savepoints outside a transaction")
768 if $self->{transaction_depth} == 0;
adb3554a 769
ddf66ced 770 $self->throw_exception ("Your Storage implementation doesn't support savepoints")
771 unless $self->can('_svp_release');
772
773 if (defined $name) {
774 $self->throw_exception ("Savepoint '$name' does not exist")
775 unless grep { $_ eq $name } @{ $self->{savepoints} };
776
777 # Dig through the stack until we find the one we are releasing. This keeps
778 # the stack up to date.
779 my $svp;
adb3554a 780
ddf66ced 781 do { $svp = pop @{ $self->{savepoints} } } while $svp ne $name;
782 } else {
783 $name = pop @{ $self->{savepoints} };
adb3554a 784 }
ddf66ced 785
adb3554a 786 $self->debugobj->svp_release($name) if $self->debug;
ddf66ced 787
788 return $self->_svp_release($name);
adb3554a 789}
790
791sub svp_rollback {
792 my ($self, $name) = @_;
793
ddf66ced 794 $self->throw_exception ("You can't use savepoints outside a transaction")
795 if $self->{transaction_depth} == 0;
adb3554a 796
ddf66ced 797 $self->throw_exception ("Your Storage implementation doesn't support savepoints")
798 unless $self->can('_svp_rollback');
799
800 if (defined $name) {
801 # If they passed us a name, verify that it exists in the stack
802 unless(grep({ $_ eq $name } @{ $self->{savepoints} })) {
803 $self->throw_exception("Savepoint '$name' does not exist!");
804 }
adb3554a 805
ddf66ced 806 # Dig through the stack until we find the one we are releasing. This keeps
807 # the stack up to date.
808 while(my $s = pop(@{ $self->{savepoints} })) {
809 last if($s eq $name);
810 }
811 # Add the savepoint back to the stack, as a rollback doesn't remove the
812 # named savepoint, only everything after it.
813 push(@{ $self->{savepoints} }, $name);
814 } else {
815 # We'll assume they want to rollback to the last savepoint
816 $name = $self->{savepoints}->[-1];
adb3554a 817 }
ddf66ced 818
adb3554a 819 $self->debugobj->svp_rollback($name) if $self->debug;
ddf66ced 820
821 return $self->_svp_rollback($name);
822}
823
824sub _svp_generate_name {
825 my ($self) = @_;
826
827 return 'savepoint_'.scalar(@{ $self->{'savepoints'} });
adb3554a 828}
d32d82f9 829
8091aa91 830sub txn_begin {
d79f59b9 831 my $self = shift;
291bf95f 832 $self->ensure_connected();
57c18b65 833 if($self->{transaction_depth} == 0) {
77d76d0f 834 $self->debugobj->txn_begin()
835 if $self->debug;
836 # this isn't ->_dbh-> because
837 # we should reconnect on begin_work
838 # for AutoCommit users
839 $self->dbh->begin_work;
d6feb60f 840 } elsif ($self->auto_savepoint) {
ddf66ced 841 $self->svp_begin;
986e4fca 842 }
57c18b65 843 $self->{transaction_depth}++;
8091aa91 844}
8b445e33 845
8091aa91 846sub txn_commit {
d79f59b9 847 my $self = shift;
77d76d0f 848 if ($self->{transaction_depth} == 1) {
849 my $dbh = $self->_dbh;
850 $self->debugobj->txn_commit()
851 if ($self->debug);
852 $dbh->commit;
853 $self->{transaction_depth} = 0
57c18b65 854 if $self->_dbh_autocommit;
77d76d0f 855 }
856 elsif($self->{transaction_depth} > 1) {
d6feb60f 857 $self->{transaction_depth}--;
ddf66ced 858 $self->svp_release
d6feb60f 859 if $self->auto_savepoint;
77d76d0f 860 }
d32d82f9 861}
862
77d76d0f 863sub txn_rollback {
864 my $self = shift;
865 my $dbh = $self->_dbh;
77d76d0f 866 eval {
77d76d0f 867 if ($self->{transaction_depth} == 1) {
d32d82f9 868 $self->debugobj->txn_rollback()
869 if ($self->debug);
77d76d0f 870 $self->{transaction_depth} = 0
57c18b65 871 if $self->_dbh_autocommit;
872 $dbh->rollback;
d32d82f9 873 }
77d76d0f 874 elsif($self->{transaction_depth} > 1) {
875 $self->{transaction_depth}--;
d6feb60f 876 if ($self->auto_savepoint) {
ddf66ced 877 $self->svp_rollback;
878 $self->svp_release;
d6feb60f 879 }
986e4fca 880 }
f11383c2 881 else {
d32d82f9 882 die DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION->new;
986e4fca 883 }
77d76d0f 884 };
a62cf8d4 885 if ($@) {
886 my $error = $@;
887 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
888 $error =~ /$exception_class/ and $self->throw_exception($error);
77d76d0f 889 # ensure that a failed rollback resets the transaction depth
57c18b65 890 $self->{transaction_depth} = $self->_dbh_autocommit ? 0 : 1;
77d76d0f 891 $self->throw_exception($error);
8091aa91 892 }
893}
8b445e33 894
b7151206 895# This used to be the top-half of _execute. It was split out to make it
896# easier to override in NoBindVars without duping the rest. It takes up
897# all of _execute's args, and emits $sql, @bind.
898sub _prep_for_execute {
d944c5ae 899 my ($self, $op, $extra_bind, $ident, $args) = @_;
b7151206 900
ba61fa2a 901 if( Scalar::Util::blessed($ident) && $ident->isa("DBIx::Class::ResultSource") ) {
59af6677 902 $ident = $ident->from();
903 }
904
d944c5ae 905 my ($sql, @bind) = $self->sql_maker->$op($ident, @$args);
59af6677 906
db4b5f11 907 unshift(@bind,
908 map { ref $_ eq 'ARRAY' ? $_ : [ '!!dummy', $_ ] } @$extra_bind)
909 if $extra_bind;
d944c5ae 910 return ($sql, \@bind);
b7151206 911}
912
e5d9ee92 913sub _fix_bind_params {
914 my ($self, @bind) = @_;
915
916 ### Turn @bind from something like this:
917 ### ( [ "artist", 1 ], [ "cdid", 1, 3 ] )
918 ### to this:
919 ### ( "'1'", "'1'", "'3'" )
920 return
921 map {
922 if ( defined( $_ && $_->[1] ) ) {
923 map { qq{'$_'}; } @{$_}[ 1 .. $#$_ ];
924 }
925 else { q{'NULL'}; }
926 } @bind;
927}
928
929sub _query_start {
930 my ( $self, $sql, @bind ) = @_;
931
932 if ( $self->debug ) {
933 @bind = $self->_fix_bind_params(@bind);
50336325 934
e5d9ee92 935 $self->debugobj->query_start( $sql, @bind );
936 }
937}
938
939sub _query_end {
940 my ( $self, $sql, @bind ) = @_;
941
942 if ( $self->debug ) {
943 @bind = $self->_fix_bind_params(@bind);
944 $self->debugobj->query_end( $sql, @bind );
945 }
946}
947
baa31d2f 948sub _dbh_execute {
949 my ($self, $dbh, $op, $extra_bind, $ident, $bind_attributes, @args) = @_;
d944c5ae 950
951 my ($sql, $bind) = $self->_prep_for_execute($op, $extra_bind, $ident, \@args);
d92a4015 952
e5d9ee92 953 $self->_query_start( $sql, @$bind );
95dad7e2 954
61646ebd 955 my $sth = $self->sth($sql,$op);
6e399b4f 956
61646ebd 957 my $placeholder_index = 1;
6e399b4f 958
61646ebd 959 foreach my $bound (@$bind) {
960 my $attributes = {};
961 my($column_name, @data) = @$bound;
6e399b4f 962
61646ebd 963 if ($bind_attributes) {
964 $attributes = $bind_attributes->{$column_name}
965 if defined $bind_attributes->{$column_name};
966 }
6e399b4f 967
61646ebd 968 foreach my $data (@data) {
272ffdb8 969 my $ref = ref $data;
970 $data = $ref && $ref ne 'ARRAY' ? ''.$data : $data; # stringify args (except arrayrefs)
0b5dee17 971
61646ebd 972 $sth->bind_param($placeholder_index, $data, $attributes);
973 $placeholder_index++;
95dad7e2 974 }
61646ebd 975 }
d92a4015 976
61646ebd 977 # Can this fail without throwing an exception anyways???
978 my $rv = $sth->execute();
979 $self->throw_exception($sth->errstr) if !$rv;
d92a4015 980
e5d9ee92 981 $self->_query_end( $sql, @$bind );
baa31d2f 982
d944c5ae 983 return (wantarray ? ($rv, $sth, @$bind) : $rv);
223b8fe3 984}
985
baa31d2f 986sub _execute {
987 my $self = shift;
3ff1602f 988 $self->dbh_do('_dbh_execute', @_)
baa31d2f 989}
990
8b445e33 991sub insert {
7af8b477 992 my ($self, $source, $to_insert) = @_;
ba61fa2a 993
7af8b477 994 my $ident = $source->from;
8b646589 995 my $bind_attributes = $self->source_bind_attributes($source);
996
c3af542a 997 my $updated_cols = {};
998
2eebd801 999 $self->ensure_connected;
a982c051 1000 foreach my $col ( $source->columns ) {
1001 if ( !defined $to_insert->{$col} ) {
1002 my $col_info = $source->column_info($col);
1003
1004 if ( $col_info->{auto_nextval} ) {
c3af542a 1005 $updated_cols->{$col} = $to_insert->{$col} = $self->_sequence_fetch( 'nextval', $col_info->{sequence} || $self->_dbh_get_autoinc_seq($self->dbh, $source) );
a982c051 1006 }
1007 }
1008 }
1009
61646ebd 1010 $self->_execute('insert' => [], $source, $bind_attributes, $to_insert);
8e08ecc4 1011
c3af542a 1012 return $updated_cols;
8b445e33 1013}
1014
744076d8 1015## Still not quite perfect, and EXPERIMENTAL
1016## Currently it is assumed that all values passed will be "normal", i.e. not
1017## scalar refs, or at least, all the same type as the first set, the statement is
1018## only prepped once.
54e0bd06 1019sub insert_bulk {
9fdf90df 1020 my ($self, $source, $cols, $data) = @_;
744076d8 1021 my %colvalues;
9fdf90df 1022 my $table = $source->from;
744076d8 1023 @colvalues{@$cols} = (0..$#$cols);
1024 my ($sql, @bind) = $self->sql_maker->insert($table, \%colvalues);
7af8b477 1025
e5d9ee92 1026 $self->_query_start( $sql, @bind );
894328b8 1027 my $sth = $self->sth($sql);
54e0bd06 1028
54e0bd06 1029# @bind = map { ref $_ ? ''.$_ : $_ } @bind; # stringify args
1030
744076d8 1031 ## This must be an arrayref, else nothing works!
1032 my $tuple_status = [];
8b646589 1033
61646ebd 1034 ## Get the bind_attributes, if any exist
1035 my $bind_attributes = $self->source_bind_attributes($source);
9fdf90df 1036
61646ebd 1037 ## Bind the values and execute
1038 my $placeholder_index = 1;
9fdf90df 1039
61646ebd 1040 foreach my $bound (@bind) {
9fdf90df 1041
61646ebd 1042 my $attributes = {};
1043 my ($column_name, $data_index) = @$bound;
eda28767 1044
61646ebd 1045 if( $bind_attributes ) {
1046 $attributes = $bind_attributes->{$column_name}
1047 if defined $bind_attributes->{$column_name};
1048 }
9fdf90df 1049
61646ebd 1050 my @data = map { $_->[$data_index] } @$data;
9fdf90df 1051
61646ebd 1052 $sth->bind_param_array( $placeholder_index, [@data], $attributes );
1053 $placeholder_index++;
54e0bd06 1054 }
d35a6fed 1055 my $rv = eval { $sth->execute_array({ArrayTupleStatus => $tuple_status}) };
1056 if (my $err = $@) {
1057 my $i = 0;
1058 ++$i while $i <= $#$tuple_status && !ref $tuple_status->[$i];
1059
1060 $self->throw_exception($sth->errstr || "Unexpected populate error: $err")
1061 if ($i > $#$tuple_status);
1062
1063 require Data::Dumper;
1064 local $Data::Dumper::Terse = 1;
1065 local $Data::Dumper::Indent = 1;
1066 local $Data::Dumper::Useqq = 1;
1067 local $Data::Dumper::Quotekeys = 0;
1068
1069 $self->throw_exception(sprintf "%s for populate slice:\n%s",
1070 $tuple_status->[$i][1],
1071 Data::Dumper::Dumper(
1072 { map { $cols->[$_] => $data->[$i][$_] } (0 .. $#$cols) }
1073 ),
1074 );
1075 }
61646ebd 1076 $self->throw_exception($sth->errstr) if !$rv;
1077
e5d9ee92 1078 $self->_query_end( $sql, @bind );
54e0bd06 1079 return (wantarray ? ($rv, $sth, @bind) : $rv);
1080}
1081
8b445e33 1082sub update {
7af8b477 1083 my $self = shift @_;
1084 my $source = shift @_;
8b646589 1085 my $bind_attributes = $self->source_bind_attributes($source);
8b646589 1086
b7ce6568 1087 return $self->_execute('update' => [], $source, $bind_attributes, @_);
8b445e33 1088}
1089
7af8b477 1090
8b445e33 1091sub delete {
7af8b477 1092 my $self = shift @_;
1093 my $source = shift @_;
1094
ba61fa2a 1095 my $bind_attrs = $self->source_bind_attributes($source);
7af8b477 1096
b7ce6568 1097 return $self->_execute('delete' => [], $source, $bind_attrs, @_);
8b445e33 1098}
1099
b2f73c30 1100# We were sent here because the $rs contains a complex search
1101# which will require a subquery to select the correct rows
1102# (i.e. joined or limited resultsets)
1103#
1104# Genarating a single PK column subquery is trivial and supported
1105# by all RDBMS. However if we have a multicolumn PK, things get ugly.
613f65e5 1106# Look at _multipk_update_delete()
b2f73c30 1107sub subq_update_delete {
1108 my $self = shift;
1109 my ($rs, $op, $values) = @_;
1110
613f65e5 1111 my $rsrc = $rs->result_source;
1112
1113 # we already check this, but double check naively just in case. Should be removed soon
1114 my $sel = $rs->_resolved_attrs->{select};
1115 $sel = [ $sel ] unless ref $sel eq 'ARRAY';
1116 my @pcols = $rsrc->primary_columns;
1117 if (@$sel != @pcols) {
1118 $self->throw_exception (
1119 'Subquery update/delete can not be called on resultsets selecting a'
1120 .' number of columns different than the number of primary keys'
1121 );
1122 }
1123
1124 if (@pcols == 1) {
1125 return $self->$op (
1126 $rsrc,
1127 $op eq 'update' ? $values : (),
1128 { $pcols[0] => { -in => $rs->as_query } },
1129 );
b2f73c30 1130 }
613f65e5 1131
b2f73c30 1132 else {
1133 return $self->_multipk_update_delete (@_);
1134 }
1135}
1136
613f65e5 1137# ANSI SQL does not provide a reliable way to perform a multicol-PK
1138# resultset update/delete involving subqueries. So by default resort
1139# to simple (and inefficient) delete_all style per-row opearations,
1140# while allowing specific storages to override this with a faster
1141# implementation.
1142#
1143sub _multipk_update_delete {
1144 return shift->_per_row_update_delete (@_);
b2f73c30 1145}
1146
613f65e5 1147# This is the default loop used to delete/update rows for multi PK
1148# resultsets, and used by mysql exclusively (because it can't do anything
1149# else).
b2f73c30 1150#
1151# We do not use $row->$op style queries, because resultset update/delete
1152# is not expected to cascade (this is what delete_all/update_all is for).
1153#
1154# There should be no race conditions as the entire operation is rolled
1155# in a transaction.
613f65e5 1156#
1157sub _per_row_update_delete {
b2f73c30 1158 my $self = shift;
1159 my ($rs, $op, $values) = @_;
1160
1161 my $rsrc = $rs->result_source;
1162 my @pcols = $rsrc->primary_columns;
1163
1164 my $guard = $self->txn_scope_guard;
1165
ab807c12 1166 # emulate the return value of $sth->execute for non-selects
19431116 1167 my $row_cnt = '0E0';
ab807c12 1168
1169 my $subrs_cur = $rs->cursor;
b2f73c30 1170 while (my @pks = $subrs_cur->next) {
1171
1172 my $cond;
1173 for my $i (0.. $#pcols) {
1174 $cond->{$pcols[$i]} = $pks[$i];
1175 }
1176
1177 $self->$op (
1178 $rsrc,
1179 $op eq 'update' ? $values : (),
1180 $cond,
1181 );
19431116 1182
1183 $row_cnt++;
b2f73c30 1184 }
1185
1186 $guard->commit;
1187
19431116 1188 return $row_cnt;
b2f73c30 1189}
1190
de705b51 1191sub _select {
59af6677 1192 my $self = shift;
1193 my $sql_maker = $self->sql_maker;
1194 local $sql_maker->{for};
1195 return $self->_execute($self->_select_args(@_));
1196}
1197
1198sub _select_args {
8b445e33 1199 my ($self, $ident, $select, $condition, $attrs) = @_;
223b8fe3 1200 my $order = $attrs->{order_by};
95ba7ee4 1201
95ba7ee4 1202 my $for = delete $attrs->{for};
1203 my $sql_maker = $self->sql_maker;
cc3b7709 1204 $sql_maker->{for} = $for;
95ba7ee4 1205
15827712 1206 my @in_order_attrs = qw/group_by having _virtual_order_by/;
1207 if (List::Util::first { exists $attrs->{$_} } (@in_order_attrs) ) {
bc0c9800 1208 $order = {
15827712 1209 ($order
1210 ? (order_by => $order)
1211 : ()
1212 ),
1213 ( map { $_ => $attrs->{$_} } (@in_order_attrs) )
bc0c9800 1214 };
54540863 1215 }
ba61fa2a 1216
1217 # the reason this is so contrived is because we have several tables in
1218 # from, each with its own set of bindattrs
1219 my $alias2source;
1220 if ( Scalar::Util::blessed($ident) && $ident->isa("DBIx::Class::ResultSource") ) {
1221 $alias2source->{$ident->alias} = $ident;
1222 }
1223 elsif (ref $ident eq 'ARRAY') {
1224
1225 for (@$ident) {
1226 my $tabinfo;
1227 if (ref $_ eq 'HASH') {
1228 $tabinfo = $_;
1229 }
1230 if (ref $_ eq 'ARRAY' and ref $_->[0] eq 'HASH') {
1231 $tabinfo = $_->[0];
1232 }
1233
1234 $alias2source->{$tabinfo->{-alias}} = $tabinfo->{-result_source}
1235 if ($tabinfo->{-result_source});
1236 }
1237 }
1238
1239 my $bind_attrs = {};
1240 for my $alias (keys %$alias2source) {
1241 my $bindtypes = $self->source_bind_attributes ($alias2source->{$alias}) || {};
1242 for my $col (keys %$bindtypes) {
1243
1244 my $fqcn = join ('.', $alias, $col);
1245 $bind_attrs->{$fqcn} = $bindtypes->{$col} if $bindtypes->{$col};
1246
1247 # so that unqualified searches can be bound too
1248 $bind_attrs->{$col} = $bind_attrs->{$fqcn} if $alias eq 'me';
1249 }
1250 }
1251
7af8b477 1252 my @args = ('select', $attrs->{bind}, $ident, $bind_attrs, $select, $condition, $order);
9229f20a 1253 if ($attrs->{software_limit} ||
fde3719a 1254 $sql_maker->_default_limit_syntax eq "GenericSubQ") {
9229f20a 1255 $attrs->{software_limit} = 1;
5c91499f 1256 } else {
0823196c 1257 $self->throw_exception("rows attribute must be positive if present")
1258 if (defined($attrs->{rows}) && !($attrs->{rows} > 0));
e60dc79f 1259
1260 # MySQL actually recommends this approach. I cringe.
1261 $attrs->{rows} = 2**48 if not defined $attrs->{rows} and defined $attrs->{offset};
5c91499f 1262 push @args, $attrs->{rows}, $attrs->{offset};
1263 }
59af6677 1264 return @args;
de705b51 1265}
1266
1685b25e 1267sub count {
1268 my ($self, $source, $attrs) = @_;
1269
7fc9269f 1270 my $tmp_attrs = { %$attrs };
1271
1685b25e 1272 # take off any column specs, any pagers, record_filter is cdbi, and no point of ordering a count
7fc9269f 1273 delete $tmp_attrs->{$_} for (qw/columns +columns select +select as +as rows offset page pager order_by record_filter/);
1685b25e 1274
7fc9269f 1275 $tmp_attrs->{select} = { count => '*' };
1276 $tmp_attrs->{as} = [qw/count/];
1685b25e 1277
7fc9269f 1278 my $tmp_rs = $source->resultset_class->new($source, $tmp_attrs);
1685b25e 1279 my ($count) = $tmp_rs->cursor->next;
1280
7fc9269f 1281 # if the offset/rows attributes are still present, we did not use
1282 # a subquery, so we need to make the calculations in software
1283 $count -= $attrs->{offset} if $attrs->{offset};
1284 $count = $attrs->{rows} if $attrs->{rows} and $attrs->{rows} < $count;
1285 $count = 0 if ($count < 0);
1286
1685b25e 1287 return $count;
1288}
1289
7fc9269f 1290sub count_grouped {
1291 my ($self, $source, $attrs) = @_;
1292
1293 # copy for the subquery, we need to do some adjustments to it too
1294 my $sub_attrs = { %$attrs };
1295
1296 # these can not go in the subquery, and there is no point of ordering it
1297 delete $sub_attrs->{$_} for qw/prefetch collapse select +select as +as columns +columns order_by/;
1298
1299 # if we prefetch, we group_by primary keys only as this is what we would get out of the rs via ->next/->all
1300 # simply deleting group_by suffices, as the code below will re-fill it
1301 # Note: we check $attrs, as $sub_attrs has collapse deleted
1302 if (ref $attrs->{collapse} and keys %{$attrs->{collapse}} ) {
1303 delete $sub_attrs->{group_by};
1304 }
1305
1306 $sub_attrs->{columns} = $sub_attrs->{group_by} ||= [ map { "$attrs->{alias}.$_" } ($source->primary_columns) ];
1307
1308 $attrs->{from} = [{
1309 count_subq => $source->resultset_class->new ($source, $sub_attrs )->as_query
1310 }];
1311
1312 # the subquery replaces this
1313 delete $attrs->{$_} for qw/where bind prefetch collapse distinct group_by having having_bind rows offset page pager/;
1314
1315 return $self->count ($source, $attrs);
1316}
1317
8b646589 1318sub source_bind_attributes {
1319 my ($self, $source) = @_;
1320
1321 my $bind_attributes;
1322 foreach my $column ($source->columns) {
1323
1324 my $data_type = $source->column_info($column)->{data_type} || '';
1325 $bind_attributes->{$column} = $self->bind_attribute_by_data_type($data_type)
eda28767 1326 if $data_type;
8b646589 1327 }
1328
1329 return $bind_attributes;
1330}
1331
9b83fccd 1332=head2 select
1333
d3b0e369 1334=over 4
1335
1336=item Arguments: $ident, $select, $condition, $attrs
1337
1338=back
1339
9b83fccd 1340Handle a SQL select statement.
1341
1342=cut
1343
de705b51 1344sub select {
1345 my $self = shift;
1346 my ($ident, $select, $condition, $attrs) = @_;
e4eb8ee1 1347 return $self->cursor_class->new($self, \@_, $attrs);
8b445e33 1348}
1349
1a14aa3f 1350sub select_single {
de705b51 1351 my $self = shift;
1352 my ($rv, $sth, @bind) = $self->_select(@_);
6157db4f 1353 my @row = $sth->fetchrow_array;
27252a4a 1354 my @nextrow = $sth->fetchrow_array if @row;
1355 if(@row && @nextrow) {
1a4e8d7c 1356 carp "Query returned more than one row. SQL that returns multiple rows is DEPRECATED for ->find and ->single";
1357 }
a3eaff0e 1358 # Need to call finish() to work round broken DBDs
6157db4f 1359 $sth->finish();
1360 return @row;
1a14aa3f 1361}
1362
9b83fccd 1363=head2 sth
1364
d3b0e369 1365=over 4
1366
1367=item Arguments: $sql
1368
1369=back
1370
9b83fccd 1371Returns a L<DBI> sth (statement handle) for the supplied SQL.
1372
1373=cut
1374
d4f16b21 1375sub _dbh_sth {
1376 my ($self, $dbh, $sql) = @_;
b33697ef 1377
d32d82f9 1378 # 3 is the if_active parameter which avoids active sth re-use
b33697ef 1379 my $sth = $self->disable_sth_caching
1380 ? $dbh->prepare($sql)
1381 : $dbh->prepare_cached($sql, {}, 3);
1382
d92a4015 1383 # XXX You would think RaiseError would make this impossible,
1384 # but apparently that's not true :(
61646ebd 1385 $self->throw_exception($dbh->errstr) if !$sth;
b33697ef 1386
1387 $sth;
d32d82f9 1388}
1389
8b445e33 1390sub sth {
cb5f2eea 1391 my ($self, $sql) = @_;
3ff1602f 1392 $self->dbh_do('_dbh_sth', $sql);
8b445e33 1393}
1394
d4f16b21 1395sub _dbh_columns_info_for {
1396 my ($self, $dbh, $table) = @_;
a32e8402 1397
d32d82f9 1398 if ($dbh->can('column_info')) {
a953d8d9 1399 my %result;
d32d82f9 1400 eval {
1401 my ($schema,$tab) = $table =~ /^(.+?)\.(.+)$/ ? ($1,$2) : (undef,$table);
1402 my $sth = $dbh->column_info( undef,$schema, $tab, '%' );
1403 $sth->execute();
1404 while ( my $info = $sth->fetchrow_hashref() ){
1405 my %column_info;
1406 $column_info{data_type} = $info->{TYPE_NAME};
1407 $column_info{size} = $info->{COLUMN_SIZE};
1408 $column_info{is_nullable} = $info->{NULLABLE} ? 1 : 0;
1409 $column_info{default_value} = $info->{COLUMN_DEF};
1410 my $col_name = $info->{COLUMN_NAME};
1411 $col_name =~ s/^\"(.*)\"$/$1/;
1412
1413 $result{$col_name} = \%column_info;
0d67fe74 1414 }
d32d82f9 1415 };
093fc7a6 1416 return \%result if !$@ && scalar keys %result;
d32d82f9 1417 }
0d67fe74 1418
d32d82f9 1419 my %result;
88262f96 1420 my $sth = $dbh->prepare($self->sql_maker->select($table, undef, \'1 = 0'));
d32d82f9 1421 $sth->execute;
1422 my @columns = @{$sth->{NAME_lc}};
1423 for my $i ( 0 .. $#columns ){
1424 my %column_info;
248bf0d0 1425 $column_info{data_type} = $sth->{TYPE}->[$i];
d32d82f9 1426 $column_info{size} = $sth->{PRECISION}->[$i];
1427 $column_info{is_nullable} = $sth->{NULLABLE}->[$i] ? 1 : 0;
0d67fe74 1428
d32d82f9 1429 if ($column_info{data_type} =~ m/^(.*?)\((.*?)\)$/) {
1430 $column_info{data_type} = $1;
1431 $column_info{size} = $2;
0d67fe74 1432 }
1433
d32d82f9 1434 $result{$columns[$i]} = \%column_info;
1435 }
248bf0d0 1436 $sth->finish;
1437
1438 foreach my $col (keys %result) {
1439 my $colinfo = $result{$col};
1440 my $type_num = $colinfo->{data_type};
1441 my $type_name;
1442 if(defined $type_num && $dbh->can('type_info')) {
1443 my $type_info = $dbh->type_info($type_num);
1444 $type_name = $type_info->{TYPE_NAME} if $type_info;
1445 $colinfo->{data_type} = $type_name if $type_name;
1446 }
1447 }
d32d82f9 1448
1449 return \%result;
1450}
1451
1452sub columns_info_for {
1453 my ($self, $table) = @_;
3ff1602f 1454 $self->dbh_do('_dbh_columns_info_for', $table);
a953d8d9 1455}
1456
9b83fccd 1457=head2 last_insert_id
1458
1459Return the row id of the last insert.
1460
1461=cut
1462
d4f16b21 1463sub _dbh_last_insert_id {
93b7182b 1464 # All Storage's need to register their own _dbh_last_insert_id
1465 # the old SQLite-based method was highly inappropriate
1466
1467 my $self = shift;
1468 my $class = ref $self;
1469 $self->throw_exception (<<EOE);
1470
1471No _dbh_last_insert_id() method found in $class.
1472Since the method of obtaining the autoincrement id of the last insert
1473operation varies greatly between different databases, this method must be
1474individually implemented for every storage class.
1475EOE
d4f16b21 1476}
1477
843f8ecd 1478sub last_insert_id {
d4f16b21 1479 my $self = shift;
3ff1602f 1480 $self->dbh_do('_dbh_last_insert_id', @_);
843f8ecd 1481}
1482
9b83fccd 1483=head2 sqlt_type
1484
1485Returns the database driver name.
1486
1487=cut
1488
d4f16b21 1489sub sqlt_type { shift->dbh->{Driver}->{Name} }
1c339d71 1490
a71859b4 1491=head2 bind_attribute_by_data_type
1492
5d52945a 1493Given a datatype from column info, returns a database specific bind
40911cb3 1494attribute for C<< $dbh->bind_param($val,$attribute) >> or nothing if we will
5d52945a 1495let the database planner just handle it.
a71859b4 1496
1497Generally only needed for special case column types, like bytea in postgres.
1498
1499=cut
1500
1501sub bind_attribute_by_data_type {
1502 return;
1503}
1504
10976519 1505=head2 create_ddl_dir (EXPERIMENTAL)
9b83fccd 1506
1507=over 4
1508
348d7c84 1509=item Arguments: $schema \@databases, $version, $directory, $preversion, \%sqlt_args
9b83fccd 1510
1511=back
1512
d3b0e369 1513Creates a SQL file based on the Schema, for each of the specified
10976519 1514database engines in C<\@databases> in the given directory.
1515(note: specify L<SQL::Translator> names, not L<DBI> driver names).
1516
1517Given a previous version number, this will also create a file containing
1518the ALTER TABLE statements to transform the previous schema into the
1519current one. Note that these statements may contain C<DROP TABLE> or
1520C<DROP COLUMN> statements that can potentially destroy data.
1521
1522The file names are created using the C<ddl_filename> method below, please
1523override this method in your schema if you would like a different file
1524name format. For the ALTER file, the same format is used, replacing
1525$version in the name with "$preversion-$version".
1526
1527See L<SQL::Translator/METHODS> for a list of values for C<\%sqlt_args>.
1528The most common value for this would be C<< { add_drop_table => 1 } >>
1529to have the SQL produced include a C<DROP TABLE> statement for each table
1530created. For quoting purposes supply C<quote_table_names> and
1531C<quote_field_names>.
1532
1533If no arguments are passed, then the following default values are assumed:
1534
1535=over 4
1536
1537=item databases - ['MySQL', 'SQLite', 'PostgreSQL']
1538
1539=item version - $schema->schema_version
1540
1541=item directory - './'
1542
1543=item preversion - <none>
1544
1545=back
9b83fccd 1546
348d7c84 1547By default, C<\%sqlt_args> will have
1548
1549 { add_drop_table => 1, ignore_constraint_names => 1, ignore_index_names => 1 }
1550
1551merged with the hash passed in. To disable any of those features, pass in a
1552hashref like the following
1553
1554 { ignore_constraint_names => 0, # ... other options }
1555
10976519 1556
1557Note that this feature is currently EXPERIMENTAL and may not work correctly
1558across all databases, or fully handle complex relationships.
1559
1560WARNING: Please check all SQL files created, before applying them.
1561
9b83fccd 1562=cut
1563
99a74c4a 1564sub create_ddl_dir {
c9d2e0a2 1565 my ($self, $schema, $databases, $version, $dir, $preversion, $sqltargs) = @_;
e673f011 1566
99a74c4a 1567 if(!$dir || !-d $dir) {
341d5ede 1568 carp "No directory given, using ./\n";
e673f011 1569 $dir = "./";
1570 }
1571 $databases ||= ['MySQL', 'SQLite', 'PostgreSQL'];
1572 $databases = [ $databases ] if(ref($databases) ne 'ARRAY');
b1f9d92e 1573
1574 my $schema_version = $schema->schema_version || '1.x';
1575 $version ||= $schema_version;
1576
d4d46d19 1577 $sqltargs = {
1578 add_drop_table => 1,
1579 ignore_constraint_names => 1,
1580 ignore_index_names => 1,
1581 %{$sqltargs || {}}
1582 };
e673f011 1583
228d5eae 1584 $self->throw_exception(q{Can't create a ddl file without SQL::Translator 0.09003: '}
40dce2a5 1585 . $self->_check_sqlt_message . q{'})
1586 if !$self->_check_sqlt_version;
e673f011 1587
45f1a484 1588 my $sqlt = SQL::Translator->new( $sqltargs );
b7e303a8 1589
1590 $sqlt->parser('SQL::Translator::Parser::DBIx::Class');
341d5ede 1591 my $sqlt_schema = $sqlt->translate({ data => $schema })
1592 or $self->throw_exception ($sqlt->error);
b7e303a8 1593
99a74c4a 1594 foreach my $db (@$databases) {
e673f011 1595 $sqlt->reset();
b7e303a8 1596 $sqlt->{schema} = $sqlt_schema;
e673f011 1597 $sqlt->producer($db);
1598
1599 my $file;
99a74c4a 1600 my $filename = $schema->ddl_filename($db, $version, $dir);
b1f9d92e 1601 if (-e $filename && ($version eq $schema_version )) {
99a74c4a 1602 # if we are dumping the current version, overwrite the DDL
341d5ede 1603 carp "Overwriting existing DDL file - $filename";
99a74c4a 1604 unlink($filename);
1605 }
c9d2e0a2 1606
99a74c4a 1607 my $output = $sqlt->translate;
1608 if(!$output) {
341d5ede 1609 carp("Failed to translate to $db, skipping. (" . $sqlt->error . ")");
99a74c4a 1610 next;
1611 }
1612 if(!open($file, ">$filename")) {
1613 $self->throw_exception("Can't open $filename for writing ($!)");
1614 next;
1615 }
1616 print $file $output;
1617 close($file);
1618
1619 next unless ($preversion);
c9d2e0a2 1620
99a74c4a 1621 require SQL::Translator::Diff;
2dc2cd0f 1622
99a74c4a 1623 my $prefilename = $schema->ddl_filename($db, $preversion, $dir);
1624 if(!-e $prefilename) {
341d5ede 1625 carp("No previous schema file found ($prefilename)");
99a74c4a 1626 next;
1627 }
c9d2e0a2 1628
99a74c4a 1629 my $difffile = $schema->ddl_filename($db, $version, $dir, $preversion);
1630 if(-e $difffile) {
341d5ede 1631 carp("Overwriting existing diff file - $difffile");
99a74c4a 1632 unlink($difffile);
1633 }
1634
1635 my $source_schema;
1636 {
1637 my $t = SQL::Translator->new($sqltargs);
1638 $t->debug( 0 );
1639 $t->trace( 0 );
341d5ede 1640
1641 $t->parser( $db )
1642 or $self->throw_exception ($t->error);
1643
1644 my $out = $t->translate( $prefilename )
1645 or $self->throw_exception ($t->error);
1646
99a74c4a 1647 $source_schema = $t->schema;
341d5ede 1648
1649 $source_schema->name( $prefilename )
1650 unless ( $source_schema->name );
99a74c4a 1651 }
c9d2e0a2 1652
99a74c4a 1653 # The "new" style of producers have sane normalization and can support
1654 # diffing a SQL file against a DBIC->SQLT schema. Old style ones don't
1655 # And we have to diff parsed SQL against parsed SQL.
1656 my $dest_schema = $sqlt_schema;
341d5ede 1657
99a74c4a 1658 unless ( "SQL::Translator::Producer::$db"->can('preprocess_schema') ) {
1659 my $t = SQL::Translator->new($sqltargs);
1660 $t->debug( 0 );
1661 $t->trace( 0 );
341d5ede 1662
1663 $t->parser( $db )
1664 or $self->throw_exception ($t->error);
1665
1666 my $out = $t->translate( $filename )
1667 or $self->throw_exception ($t->error);
1668
99a74c4a 1669 $dest_schema = $t->schema;
341d5ede 1670
99a74c4a 1671 $dest_schema->name( $filename )
1672 unless $dest_schema->name;
1673 }
1674
1675 my $diff = SQL::Translator::Diff::schema_diff($source_schema, $db,
1676 $dest_schema, $db,
1677 $sqltargs
1678 );
1679 if(!open $file, ">$difffile") {
1680 $self->throw_exception("Can't write to $difffile ($!)");
1681 next;
c9d2e0a2 1682 }
99a74c4a 1683 print $file $diff;
1684 close($file);
e673f011 1685 }
c9d2e0a2 1686}
e673f011 1687
9b83fccd 1688=head2 deployment_statements
1689
d3b0e369 1690=over 4
1691
1692=item Arguments: $schema, $type, $version, $directory, $sqlt_args
1693
1694=back
1695
1696Returns the statements used by L</deploy> and L<DBIx::Class::Schema/deploy>.
10976519 1697
1698The L<SQL::Translator> (not L<DBI>) database driver name can be explicitly
1699provided in C<$type>, otherwise the result of L</sqlt_type> is used as default.
d3b0e369 1700
1701C<$directory> is used to return statements from files in a previously created
1702L</create_ddl_dir> directory and is optional. The filenames are constructed
1703from L<DBIx::Class::Schema/ddl_filename>, the schema name and the C<$version>.
1704
1705If no C<$directory> is specified then the statements are constructed on the
1706fly using L<SQL::Translator> and C<$version> is ignored.
1707
1708See L<SQL::Translator/METHODS> for a list of values for C<$sqlt_args>.
9b83fccd 1709
1710=cut
1711
e673f011 1712sub deployment_statements {
1713 my ($self, $schema, $type, $version, $dir, $sqltargs) = @_;
915919c5 1714 # Need to be connected to get the correct sqlt_type
c377d939 1715 $self->ensure_connected() unless $type;
e673f011 1716 $type ||= $self->sqlt_type;
b1f9d92e 1717 $version ||= $schema->schema_version || '1.x';
e673f011 1718 $dir ||= './';
0233fc64 1719 my $filename = $schema->ddl_filename($type, $version, $dir);
c9d2e0a2 1720 if(-f $filename)
1721 {
1722 my $file;
1723 open($file, "<$filename")
1724 or $self->throw_exception("Can't open $filename ($!)");
1725 my @rows = <$file>;
1726 close($file);
1727 return join('', @rows);
1728 }
1729
228d5eae 1730 $self->throw_exception(q{Can't deploy without SQL::Translator 0.09003: '}
40dce2a5 1731 . $self->_check_sqlt_message . q{'})
1732 if !$self->_check_sqlt_version;
1733
1734 require SQL::Translator::Parser::DBIx::Class;
1735 eval qq{use SQL::Translator::Producer::${type}};
1736 $self->throw_exception($@) if $@;
1737
1738 # sources needs to be a parser arg, but for simplicty allow at top level
1739 # coming in
1740 $sqltargs->{parser_args}{sources} = delete $sqltargs->{sources}
1741 if exists $sqltargs->{sources};
1742
1743 my $tr = SQL::Translator->new(%$sqltargs);
1744 SQL::Translator::Parser::DBIx::Class::parse( $tr, $schema );
1745 return "SQL::Translator::Producer::${type}"->can('produce')->($tr);
1c339d71 1746}
843f8ecd 1747
1c339d71 1748sub deploy {
260129d8 1749 my ($self, $schema, $type, $sqltargs, $dir) = @_;
11d8c781 1750 my $deploy = sub {
1751 my $line = shift;
1752 return if($line =~ /^--/);
1753 return if(!$line);
1754 # next if($line =~ /^DROP/m);
1755 return if($line =~ /^BEGIN TRANSACTION/m);
1756 return if($line =~ /^COMMIT/m);
1757 return if $line =~ /^\s+$/; # skip whitespace only
1758 $self->_query_start($line);
1759 eval {
1760 $self->dbh->do($line); # shouldn't be using ->dbh ?
1761 };
1762 if ($@) {
341d5ede 1763 carp qq{$@ (running "${line}")};
11d8c781 1764 }
1765 $self->_query_end($line);
1766 };
10976519 1767 my @statements = $self->deployment_statements($schema, $type, undef, $dir, { %{ $sqltargs || {} }, no_comments => 1 } );
11d8c781 1768 if (@statements > 1) {
1769 foreach my $statement (@statements) {
1770 $deploy->( $statement );
1771 }
1772 }
1773 elsif (@statements == 1) {
1774 foreach my $line ( split(";\n", $statements[0])) {
1775 $deploy->( $line );
e4fe9ba3 1776 }
75d07914 1777 }
1c339d71 1778}
843f8ecd 1779
9b83fccd 1780=head2 datetime_parser
1781
1782Returns the datetime parser class
1783
1784=cut
1785
f86fcf0d 1786sub datetime_parser {
1787 my $self = shift;
114780ee 1788 return $self->{datetime_parser} ||= do {
1789 $self->ensure_connected;
1790 $self->build_datetime_parser(@_);
1791 };
f86fcf0d 1792}
1793
9b83fccd 1794=head2 datetime_parser_type
1795
1796Defines (returns) the datetime parser class - currently hardwired to
1797L<DateTime::Format::MySQL>
1798
1799=cut
1800
f86fcf0d 1801sub datetime_parser_type { "DateTime::Format::MySQL"; }
1802
9b83fccd 1803=head2 build_datetime_parser
1804
1805See L</datetime_parser>
1806
1807=cut
1808
f86fcf0d 1809sub build_datetime_parser {
1810 my $self = shift;
1811 my $type = $self->datetime_parser_type(@_);
1812 eval "use ${type}";
1813 $self->throw_exception("Couldn't load ${type}: $@") if $@;
1814 return $type;
1815}
1816
40dce2a5 1817{
1818 my $_check_sqlt_version; # private
1819 my $_check_sqlt_message; # private
1820 sub _check_sqlt_version {
1821 return $_check_sqlt_version if defined $_check_sqlt_version;
228d5eae 1822 eval 'use SQL::Translator "0.09003"';
b7e303a8 1823 $_check_sqlt_message = $@ || '';
1824 $_check_sqlt_version = !$@;
40dce2a5 1825 }
1826
1827 sub _check_sqlt_message {
1828 _check_sqlt_version if !defined $_check_sqlt_message;
1829 $_check_sqlt_message;
1830 }
1831}
1832
106d5f3b 1833=head2 is_replicating
1834
1835A boolean that reports if a particular L<DBIx::Class::Storage::DBI> is set to
1836replicate from a master database. Default is undef, which is the result
1837returned by databases that don't support replication.
1838
1839=cut
1840
1841sub is_replicating {
1842 return;
1843
1844}
1845
1846=head2 lag_behind_master
1847
1848Returns a number that represents a certain amount of lag behind a master db
1849when a given storage is replicating. The number is database dependent, but
1850starts at zero and increases with the amount of lag. Default in undef
1851
1852=cut
1853
1854sub lag_behind_master {
1855 return;
1856}
1857
c756145c 1858sub DESTROY {
1859 my $self = shift;
f5de3933 1860 return if !$self->_dbh;
c756145c 1861 $self->_verify_pid;
1862 $self->_dbh(undef);
1863}
92925617 1864
8b445e33 18651;
1866
92fe2181 1867=head1 USAGE NOTES
1868
1869=head2 DBIx::Class and AutoCommit
1870
1871DBIx::Class can do some wonderful magic with handling exceptions,
1872disconnections, and transactions when you use C<< AutoCommit => 1 >>
1873combined with C<txn_do> for transaction support.
1874
1875If you set C<< AutoCommit => 0 >> in your connect info, then you are always
1876in an assumed transaction between commits, and you're telling us you'd
1877like to manage that manually. A lot of the magic protections offered by
1878this module will go away. We can't protect you from exceptions due to database
1879disconnects because we don't know anything about how to restart your
1880transactions. You're on your own for handling all sorts of exceptional
1881cases if you choose the C<< AutoCommit => 0 >> path, just as you would
1882be with raw DBI.
1883
1884
9b83fccd 1885
8b445e33 1886=head1 AUTHORS
1887
daec44b8 1888Matt S. Trout <mst@shadowcatsystems.co.uk>
8b445e33 1889
9f19b1d6 1890Andy Grundman <andy@hybridized.org>
1891
8b445e33 1892=head1 LICENSE
1893
1894You may distribute this code under the same terms as Perl itself.
1895
1896=cut