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