Merge 'trunk' into 'DBIx-Class-current'
[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
20a2c954 6use strict;
7use warnings;
8b445e33 8use DBI;
aeaf3ce2 9use SQL::Abstract::Limit;
28927b50 10use DBIx::Class::Storage::DBI::Cursor;
4c248161 11use DBIx::Class::Storage::Statistics;
92b858c9 12use IO::File;
046ad905 13
14__PACKAGE__->mk_group_accessors(
15 'simple' =>
16 qw/_connect_info _dbh _sql_maker _sql_maker_opts _conn_pid _conn_tid
17 cursor on_connect_do transaction_depth/
18);
19
bd7efd39 20BEGIN {
21
cb5f2eea 22package DBIC::SQL::Abstract; # Would merge upstream, but nate doesn't reply :(
bd7efd39 23
24use base qw/SQL::Abstract::Limit/;
25
2cc3a7be 26# This prevents the caching of $dbh in S::A::L, I believe
27sub new {
28 my $self = shift->SUPER::new(@_);
29
30 # If limit_dialect is a ref (like a $dbh), go ahead and replace
31 # it with what it resolves to:
32 $self->{limit_dialect} = $self->_find_syntax($self->{limit_dialect})
33 if ref $self->{limit_dialect};
34
35 $self;
36}
37
260129d8 38sub _RowNumberOver {
39 my ($self, $sql, $order, $rows, $offset ) = @_;
40
41 $offset += 1;
42 my $last = $rows + $offset;
43 my ( $order_by ) = $self->_order_by( $order );
44
45 $sql = <<"";
46SELECT * FROM
47(
48 SELECT Q1.*, ROW_NUMBER() OVER( ) AS ROW_NUM FROM (
49 $sql
50 $order_by
51 ) Q1
52) Q2
53WHERE ROW_NUM BETWEEN $offset AND $last
54
55 return $sql;
56}
57
58
2cc3a7be 59# While we're at it, this should make LIMIT queries more efficient,
60# without digging into things too deeply
61sub _find_syntax {
62 my ($self, $syntax) = @_;
e4cc8257 63 my $dbhname = ref $syntax eq 'HASH' ? $syntax->{Driver}{Name} : '';
260129d8 64 if(ref($self) && $dbhname && $dbhname eq 'DB2') {
65 return 'RowNumberOver';
66 }
67
2cc3a7be 68 $self->{_cached_syntax} ||= $self->SUPER::_find_syntax($syntax);
69}
70
54540863 71sub select {
72 my ($self, $table, $fields, $where, $order, @rest) = @_;
6346a152 73 $table = $self->_quote($table) unless ref($table);
eac29141 74 local $self->{rownum_hack_count} = 1
75 if (defined $rest[0] && $self->{limit_dialect} eq 'RowNum');
54540863 76 @rest = (-1) unless defined $rest[0];
0823196c 77 die "LIMIT 0 Does Not Compute" if $rest[0] == 0;
78 # and anyway, SQL::Abstract::Limit will cause a barf if we don't first
8839560b 79 local $self->{having_bind} = [];
bc0c9800 80 my ($sql, @ret) = $self->SUPER::select(
81 $table, $self->_recurse_fields($fields), $where, $order, @rest
82 );
8839560b 83 return wantarray ? ($sql, @ret, @{$self->{having_bind}}) : $sql;
54540863 84}
85
6346a152 86sub insert {
87 my $self = shift;
88 my $table = shift;
89 $table = $self->_quote($table) unless ref($table);
90 $self->SUPER::insert($table, @_);
91}
92
93sub update {
94 my $self = shift;
95 my $table = shift;
96 $table = $self->_quote($table) unless ref($table);
97 $self->SUPER::update($table, @_);
98}
99
100sub delete {
101 my $self = shift;
102 my $table = shift;
103 $table = $self->_quote($table) unless ref($table);
104 $self->SUPER::delete($table, @_);
105}
106
54540863 107sub _emulate_limit {
108 my $self = shift;
109 if ($_[3] == -1) {
110 return $_[1].$self->_order_by($_[2]);
111 } else {
112 return $self->SUPER::_emulate_limit(@_);
113 }
114}
115
116sub _recurse_fields {
117 my ($self, $fields) = @_;
118 my $ref = ref $fields;
119 return $self->_quote($fields) unless $ref;
120 return $$fields if $ref eq 'SCALAR';
121
122 if ($ref eq 'ARRAY') {
eac29141 123 return join(', ', map {
124 $self->_recurse_fields($_)
125 .(exists $self->{rownum_hack_count}
126 ? ' AS col'.$self->{rownum_hack_count}++
127 : '')
128 } @$fields);
54540863 129 } elsif ($ref eq 'HASH') {
130 foreach my $func (keys %$fields) {
131 return $self->_sqlcase($func)
132 .'( '.$self->_recurse_fields($fields->{$func}).' )';
133 }
134 }
135}
136
137sub _order_by {
138 my $self = shift;
139 my $ret = '';
8839560b 140 my @extra;
54540863 141 if (ref $_[0] eq 'HASH') {
142 if (defined $_[0]->{group_by}) {
143 $ret = $self->_sqlcase(' group by ')
144 .$self->_recurse_fields($_[0]->{group_by});
145 }
8839560b 146 if (defined $_[0]->{having}) {
147 my $frag;
148 ($frag, @extra) = $self->_recurse_where($_[0]->{having});
149 push(@{$self->{having_bind}}, @extra);
150 $ret .= $self->_sqlcase(' having ').$frag;
151 }
54540863 152 if (defined $_[0]->{order_by}) {
7ce5cbe7 153 $ret .= $self->_order_by($_[0]->{order_by});
54540863 154 }
d09c569a 155 } elsif (ref $_[0] eq 'SCALAR') {
e535069e 156 $ret = $self->_sqlcase(' order by ').${ $_[0] };
d09c569a 157 } elsif (ref $_[0] eq 'ARRAY' && @{$_[0]}) {
158 my @order = @{+shift};
159 $ret = $self->_sqlcase(' order by ')
160 .join(', ', map {
161 my $r = $self->_order_by($_, @_);
162 $r =~ s/^ ?ORDER BY //i;
163 $r;
164 } @order);
54540863 165 } else {
166 $ret = $self->SUPER::_order_by(@_);
167 }
168 return $ret;
169}
170
f48dd03f 171sub _order_directions {
172 my ($self, $order) = @_;
173 $order = $order->{order_by} if ref $order eq 'HASH';
174 return $self->SUPER::_order_directions($order);
175}
176
2a816814 177sub _table {
bd7efd39 178 my ($self, $from) = @_;
179 if (ref $from eq 'ARRAY') {
180 return $self->_recurse_from(@$from);
181 } elsif (ref $from eq 'HASH') {
182 return $self->_make_as($from);
183 } else {
6346a152 184 return $from; # would love to quote here but _table ends up getting called
185 # twice during an ->select without a limit clause due to
186 # the way S::A::Limit->select works. should maybe consider
187 # bypassing this and doing S::A::select($self, ...) in
188 # our select method above. meantime, quoting shims have
189 # been added to select/insert/update/delete here
bd7efd39 190 }
191}
192
193sub _recurse_from {
194 my ($self, $from, @join) = @_;
195 my @sqlf;
196 push(@sqlf, $self->_make_as($from));
197 foreach my $j (@join) {
198 my ($to, $on) = @$j;
73856587 199
54540863 200 # check whether a join type exists
201 my $join_clause = '';
ca7b9fdf 202 my $to_jt = ref($to) eq 'ARRAY' ? $to->[0] : $to;
203 if (ref($to_jt) eq 'HASH' and exists($to_jt->{-join_type})) {
204 $join_clause = ' '.uc($to_jt->{-join_type}).' JOIN ';
54540863 205 } else {
206 $join_clause = ' JOIN ';
207 }
73856587 208 push(@sqlf, $join_clause);
209
bd7efd39 210 if (ref $to eq 'ARRAY') {
211 push(@sqlf, '(', $self->_recurse_from(@$to), ')');
212 } else {
96cdbbab 213 push(@sqlf, $self->_make_as($to));
bd7efd39 214 }
215 push(@sqlf, ' ON ', $self->_join_condition($on));
216 }
217 return join('', @sqlf);
218}
219
220sub _make_as {
221 my ($self, $from) = @_;
54540863 222 return join(' ', map { (ref $_ eq 'SCALAR' ? $$_ : $self->_quote($_)) }
bc0c9800 223 reverse each %{$self->_skip_options($from)});
73856587 224}
225
226sub _skip_options {
54540863 227 my ($self, $hash) = @_;
228 my $clean_hash = {};
229 $clean_hash->{$_} = $hash->{$_}
230 for grep {!/^-/} keys %$hash;
231 return $clean_hash;
bd7efd39 232}
233
234sub _join_condition {
235 my ($self, $cond) = @_;
5efe4c79 236 if (ref $cond eq 'HASH') {
237 my %j;
bc0c9800 238 for (keys %$cond) {
239 my $x = '= '.$self->_quote($cond->{$_}); $j{$_} = \$x;
240 };
5efe4c79 241 return $self->_recurse_where(\%j);
242 } elsif (ref $cond eq 'ARRAY') {
243 return join(' OR ', map { $self->_join_condition($_) } @$cond);
244 } else {
245 die "Can't handle this yet!";
246 }
bd7efd39 247}
248
2a816814 249sub _quote {
250 my ($self, $label) = @_;
251 return '' unless defined $label;
3b24f6ea 252 return "*" if $label eq '*';
41728a6e 253 return $label unless $self->{quote_char};
3b24f6ea 254 if(ref $self->{quote_char} eq "ARRAY"){
255 return $self->{quote_char}->[0] . $label . $self->{quote_char}->[1]
256 if !defined $self->{name_sep};
257 my $sep = $self->{name_sep};
258 return join($self->{name_sep},
259 map { $self->{quote_char}->[0] . $_ . $self->{quote_char}->[1] }
260 split(/\Q$sep\E/,$label));
261 }
2a816814 262 return $self->SUPER::_quote($label);
263}
264
7be93b07 265sub limit_dialect {
266 my $self = shift;
267 $self->{limit_dialect} = shift if @_;
268 return $self->{limit_dialect};
269}
270
2437a1e3 271sub quote_char {
272 my $self = shift;
273 $self->{quote_char} = shift if @_;
274 return $self->{quote_char};
275}
276
277sub name_sep {
278 my $self = shift;
279 $self->{name_sep} = shift if @_;
280 return $self->{name_sep};
281}
282
bd7efd39 283} # End of BEGIN block
284
b327f988 285=head1 NAME
286
287DBIx::Class::Storage::DBI - DBI storage handler
288
289=head1 SYNOPSIS
290
291=head1 DESCRIPTION
292
046ad905 293This class represents the connection to an RDBMS via L<DBI>. See
294L<DBIx::Class::Storage> for general information. This pod only
295documents DBI-specific methods and behaviors.
b327f988 296
297=head1 METHODS
298
9b83fccd 299=cut
300
8b445e33 301sub new {
046ad905 302 my $new = shift->next::method(@_);
82cc0386 303
28927b50 304 $new->cursor("DBIx::Class::Storage::DBI::Cursor");
d79f59b9 305 $new->transaction_depth(0);
2cc3a7be 306 $new->_sql_maker_opts({});
82cc0386 307
046ad905 308 $new;
1c339d71 309}
310
1b45b01e 311=head2 connect_info
312
bb4f246d 313The arguments of C<connect_info> are always a single array reference.
1b45b01e 314
bb4f246d 315This is normally accessed via L<DBIx::Class::Schema/connection>, which
316encapsulates its argument list in an arrayref before calling
317C<connect_info> here.
1b45b01e 318
bb4f246d 319The arrayref can either contain the same set of arguments one would
320normally pass to L<DBI/connect>, or a lone code reference which returns
321a connected database handle.
d7c4c15c 322
2cc3a7be 323In either case, if the final argument in your connect_info happens
324to be a hashref, C<connect_info> will look there for several
325connection-specific options:
326
327=over 4
328
329=item on_connect_do
330
331This can be set to an arrayref of literal sql statements, which will
332be executed immediately after making the connection to the database
333every time we [re-]connect.
334
335=item limit_dialect
336
337Sets the limit dialect. This is useful for JDBC-bridge among others
338where the remote SQL-dialect cannot be determined by the name of the
339driver alone.
340
341=item quote_char
d7c4c15c 342
2cc3a7be 343Specifies what characters to use to quote table and column names. If
344you use this you will want to specify L<name_sep> as well.
345
346quote_char expects either a single character, in which case is it is placed
347on either side of the table/column, or an arrayref of length 2 in which case the
348table/column name is placed between the elements.
349
350For example under MySQL you'd use C<quote_char =E<gt> '`'>, and user SQL Server you'd
351use C<quote_char =E<gt> [qw/[ ]/]>.
352
353=item name_sep
354
355This only needs to be used in conjunction with L<quote_char>, and is used to
356specify the charecter that seperates elements (schemas, tables, columns) from
357each other. In most cases this is simply a C<.>.
358
359=back
360
361These options can be mixed in with your other L<DBI> connection attributes,
362or placed in a seperate hashref after all other normal L<DBI> connection
363arguments.
364
365Every time C<connect_info> is invoked, any previous settings for
366these options will be cleared before setting the new ones, regardless of
367whether any options are specified in the new C<connect_info>.
368
f5de3933 369Important note: DBIC expects the returned database handle provided by
370a subref argument to have RaiseError set on it. If it doesn't, things
371might not work very well, YMMV. If you don't use a subref, DBIC will
372force this setting for you anyways. Setting HandleError to anything
373other than simple exception object wrapper might cause problems too.
374
2cc3a7be 375Examples:
376
377 # Simple SQLite connection
bb4f246d 378 ->connect_info([ 'dbi:SQLite:./foo.db' ]);
6789ebe3 379
2cc3a7be 380 # Connect via subref
bb4f246d 381 ->connect_info([ sub { DBI->connect(...) } ]);
6789ebe3 382
2cc3a7be 383 # A bit more complicated
bb4f246d 384 ->connect_info(
385 [
386 'dbi:Pg:dbname=foo',
387 'postgres',
388 'my_pg_password',
389 { AutoCommit => 0 },
2cc3a7be 390 { quote_char => q{"}, name_sep => q{.} },
391 ]
392 );
393
394 # Equivalent to the previous example
395 ->connect_info(
396 [
397 'dbi:Pg:dbname=foo',
398 'postgres',
399 'my_pg_password',
400 { AutoCommit => 0, quote_char => q{"}, name_sep => q{.} },
bb4f246d 401 ]
402 );
6789ebe3 403
2cc3a7be 404 # Subref + DBIC-specific connection options
bb4f246d 405 ->connect_info(
406 [
407 sub { DBI->connect(...) },
2cc3a7be 408 {
409 quote_char => q{`},
410 name_sep => q{@},
411 on_connect_do => ['SET search_path TO myschema,otherschema,public'],
412 },
bb4f246d 413 ]
414 );
6789ebe3 415
004d31fb 416=cut
417
046ad905 418sub connect_info {
419 my ($self, $info_arg) = @_;
4c248161 420
046ad905 421 return $self->_connect_info if !$info_arg;
4c248161 422
046ad905 423 # Kill sql_maker/_sql_maker_opts, so we get a fresh one with only
424 # the new set of options
425 $self->_sql_maker(undef);
426 $self->_sql_maker_opts({});
486ad69b 427
046ad905 428 my $info = [ @$info_arg ]; # copy because we can alter it
429 my $last_info = $info->[-1];
430 if(ref $last_info eq 'HASH') {
431 if(my $on_connect_do = delete $last_info->{on_connect_do}) {
432 $self->on_connect_do($on_connect_do);
433 }
434 for my $sql_maker_opt (qw/limit_dialect quote_char name_sep/) {
435 if(my $opt_val = delete $last_info->{$sql_maker_opt}) {
436 $self->_sql_maker_opts->{$sql_maker_opt} = $opt_val;
437 }
438 }
486ad69b 439
046ad905 440 # Get rid of any trailing empty hashref
441 pop(@$info) if !keys %$last_info;
442 }
d7c4c15c 443
046ad905 444 $self->_connect_info($info);
445}
004d31fb 446
046ad905 447=head2 on_connect_do
4c248161 448
046ad905 449This method is deprecated in favor of setting via L</connect_info>.
486ad69b 450
f11383c2 451=head2 dbh_do
452
046ad905 453Arguments: $subref, @extra_coderef_args?
454
56769f7c 455Execute the given subref with the underlying database handle as its
456first argument, using the new exception-based connection management.
046ad905 457
458Any additional arguments will be passed verbatim to the called subref
459as arguments 2 and onwards.
460
56769f7c 461Example:
f11383c2 462
56769f7c 463 my @stuff = $schema->storage->dbh_do(
464 sub {
046ad905 465 my $dbh = shift;
466 my $cols = join(q{, }, @_);
467 shift->selectrow_array("SELECT $cols FROM foo")
468 },
469 @column_list
56769f7c 470 );
f11383c2 471
472=cut
473
474sub dbh_do {
046ad905 475 my $self = shift;
aa27edf7 476 my $coderef = shift;
477
478 return $coderef->($self->_dbh, @_) if $self->{_in_txn_do};
479
480 ref $coderef eq 'CODE' or $self->throw_exception
481 ('$coderef must be a CODE reference');
f11383c2 482
483 my @result;
484 my $want_array = wantarray;
485
486 eval {
56769f7c 487 $self->_verify_pid if $self->_dbh;
f11383c2 488 $self->_populate_dbh if !$self->_dbh;
f11383c2 489 if($want_array) {
aa27edf7 490 @result = $coderef->($self->_dbh, @_);
f11383c2 491 }
56769f7c 492 elsif(defined $want_array) {
aa27edf7 493 $result[0] = $coderef->($self->_dbh, @_);
f11383c2 494 }
56769f7c 495 else {
aa27edf7 496 $coderef->($self->_dbh, @_);
56769f7c 497 }
f11383c2 498 };
56769f7c 499
aa27edf7 500 my $exception = $@;
501 if(!$exception) { return $want_array ? @result : $result[0] }
502
503 $self->throw_exception($exception) if $self->connected;
504
505 # We were not connected - reconnect and retry, but let any
506 # exception fall right through this time
507 $self->_populate_dbh;
508 $coderef->($self->_dbh, @_);
509}
510
511# This is basically a blend of dbh_do above and DBIx::Class::Storage::txn_do.
512# It also informs dbh_do to bypass itself while under the direction of txn_do,
513# via $self->{_in_txn_do} (this saves some redundant eval and errorcheck, etc)
514sub txn_do {
515 my $self = shift;
516 my $coderef = shift;
517
518 ref $coderef eq 'CODE' or $self->throw_exception
519 ('$coderef must be a CODE reference');
520
521 local $self->{_in_txn_do} = 1;
f11383c2 522
aa27edf7 523 my $tried = 0;
524
525 my @result;
526 my $want_array = wantarray;
527
528 START_TXN: eval {
529 $self->_verify_pid if $self->_dbh;
530 $self->_populate_dbh if !$self->_dbh;
531
532 $self->txn_begin;
533 if($want_array) {
534 @result = $coderef->(@_);
535 }
536 elsif(defined $want_array) {
537 $result[0] = $coderef->(@_);
538 }
539 else {
540 $coderef->(@_);
541 }
542 $self->txn_commit;
543 };
544
545 my $exception = $@;
546 if(!$exception) { return $want_array ? @result : $result[0] }
547
548 if($tried++ > 0 || $self->connected) {
549 eval { $self->txn_rollback };
550 my $rollback_exception = $@;
551 if($rollback_exception) {
552 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
553 $self->throw_exception($exception) # propagate nested rollback
554 if $rollback_exception =~ /$exception_class/;
555
556 $self->throw_exception(
557 "Transaction aborted: ${exception}. "
558 . "Rollback failed: ${rollback_exception}"
559 );
560 }
561 $self->throw_exception($exception)
f11383c2 562 }
56769f7c 563
aa27edf7 564 # We were not connected, and was first try - reconnect and retry
565 # XXX I know, gotos are evil. If you can find a better way
566 # to write this that doesn't duplicate a lot of code/structure,
567 # and behaves identically, feel free...
568
569 $self->_populate_dbh;
570 goto START_TXN;
f11383c2 571}
572
9b83fccd 573=head2 disconnect
574
046ad905 575Our C<disconnect> method also performs a rollback first if the
9b83fccd 576database is not in C<AutoCommit> mode.
577
578=cut
579
412db1f4 580sub disconnect {
581 my ($self) = @_;
582
92925617 583 if( $self->connected ) {
584 $self->_dbh->rollback unless $self->_dbh->{AutoCommit};
585 $self->_dbh->disconnect;
586 $self->_dbh(undef);
587 }
412db1f4 588}
589
f11383c2 590sub connected {
591 my ($self) = @_;
412db1f4 592
1346e22d 593 if(my $dbh = $self->_dbh) {
594 if(defined $self->_conn_tid && $self->_conn_tid != threads->tid) {
1346e22d 595 return $self->_dbh(undef);
596 }
56769f7c 597 else {
598 $self->_verify_pid;
599 }
1346e22d 600 return ($dbh->FETCH('Active') && $dbh->ping);
601 }
602
603 return 0;
412db1f4 604}
605
f11383c2 606# handle pid changes correctly
56769f7c 607# NOTE: assumes $self->_dbh is a valid $dbh
f11383c2 608sub _verify_pid {
609 my ($self) = @_;
610
56769f7c 611 return if $self->_conn_pid == $$;
f11383c2 612
f11383c2 613 $self->_dbh->{InactiveDestroy} = 1;
d3abf3fe 614 $self->_dbh(undef);
f11383c2 615
616 return;
617}
618
412db1f4 619sub ensure_connected {
620 my ($self) = @_;
621
622 unless ($self->connected) {
8b445e33 623 $self->_populate_dbh;
624 }
412db1f4 625}
626
c235bbae 627=head2 dbh
628
629Returns the dbh - a data base handle of class L<DBI>.
630
631=cut
632
412db1f4 633sub dbh {
634 my ($self) = @_;
635
636 $self->ensure_connected;
8b445e33 637 return $self->_dbh;
638}
639
f1f56aad 640sub _sql_maker_args {
641 my ($self) = @_;
642
2cc3a7be 643 return ( limit_dialect => $self->dbh, %{$self->_sql_maker_opts} );
f1f56aad 644}
645
48c69e7c 646sub sql_maker {
647 my ($self) = @_;
fdc1c3d0 648 unless ($self->_sql_maker) {
f1f56aad 649 $self->_sql_maker(new DBIC::SQL::Abstract( $self->_sql_maker_args ));
48c69e7c 650 }
651 return $self->_sql_maker;
652}
653
8b445e33 654sub _populate_dbh {
655 my ($self) = @_;
1b45b01e 656 my @info = @{$self->_connect_info || []};
8b445e33 657 $self->_dbh($self->_connect(@info));
2fd24e78 658
659 if(ref $self eq 'DBIx::Class::Storage::DBI') {
660 my $driver = $self->_dbh->{Driver}->{Name};
efe6365b 661 if ($self->load_optional_class("DBIx::Class::Storage::DBI::${driver}")) {
2fd24e78 662 bless $self, "DBIx::Class::Storage::DBI::${driver}";
663 $self->_rebless() if $self->can('_rebless');
664 }
843f8ecd 665 }
2fd24e78 666
d7c4c15c 667 # if on-connect sql statements are given execute them
668 foreach my $sql_statement (@{$self->on_connect_do || []}) {
4c248161 669 $self->debugobj->query_start($sql_statement) if $self->debug();
d7c4c15c 670 $self->_dbh->do($sql_statement);
4c248161 671 $self->debugobj->query_end($sql_statement) if $self->debug();
d7c4c15c 672 }
5ef3e508 673
1346e22d 674 $self->_conn_pid($$);
675 $self->_conn_tid(threads->tid) if $INC{'threads.pm'};
8b445e33 676}
677
678sub _connect {
679 my ($self, @info) = @_;
5ef3e508 680
9d31f7dc 681 $self->throw_exception("You failed to provide any connection info")
682 if !@info;
683
90ec6cad 684 my ($old_connect_via, $dbh);
685
5ef3e508 686 if ($INC{'Apache/DBI.pm'} && $ENV{MOD_PERL}) {
90ec6cad 687 $old_connect_via = $DBI::connect_via;
5ef3e508 688 $DBI::connect_via = 'connect';
5ef3e508 689 }
690
75db246c 691 eval {
f5de3933 692 if(ref $info[0] eq 'CODE') {
693 $dbh = &{$info[0]}
694 }
695 else {
696 $dbh = DBI->connect(@info);
697 $dbh->{RaiseError} = 1;
698 $dbh->{PrintError} = 0;
699 }
75db246c 700 };
90ec6cad 701
702 $DBI::connect_via = $old_connect_via if $old_connect_via;
703
75db246c 704 if (!$dbh || $@) {
705 $self->throw_exception("DBI Connection failed: " . ($@ || $DBI::errstr));
706 }
90ec6cad 707
e571e823 708 $dbh;
8b445e33 709}
710
d32d82f9 711sub __txn_begin {
712 my ($dbh, $self) = @_;
713 if ($dbh->{AutoCommit}) {
714 $self->debugobj->txn_begin()
715 if ($self->debug);
716 $dbh->begin_work;
717 }
718}
719
8091aa91 720sub txn_begin {
d79f59b9 721 my $self = shift;
d32d82f9 722 $self->dbh_do(\&__txn_begin, $self)
723 if $self->{transaction_depth}++ == 0;
724}
725
726sub __txn_commit {
727 my ($dbh, $self) = @_;
728 if ($self->{transaction_depth} == 0) {
729 unless ($dbh->{AutoCommit}) {
730 $self->debugobj->txn_commit()
731 if ($self->debug);
732 $dbh->commit;
733 }
734 }
735 else {
736 if (--$self->{transaction_depth} == 0) {
737 $self->debugobj->txn_commit()
738 if ($self->debug);
739 $dbh->commit;
740 }
986e4fca 741 }
8091aa91 742}
8b445e33 743
8091aa91 744sub txn_commit {
d79f59b9 745 my $self = shift;
d32d82f9 746 $self->dbh_do(\&__txn_commit, $self);
747}
748
749sub __txn_rollback {
750 my ($dbh, $self) = @_;
751 if ($self->{transaction_depth} == 0) {
752 unless ($dbh->{AutoCommit}) {
753 $self->debugobj->txn_rollback()
754 if ($self->debug);
755 $dbh->rollback;
756 }
757 }
758 else {
759 if (--$self->{transaction_depth} == 0) {
760 $self->debugobj->txn_rollback()
761 if ($self->debug);
762 $dbh->rollback;
986e4fca 763 }
f11383c2 764 else {
d32d82f9 765 die DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION->new;
986e4fca 766 }
d32d82f9 767 }
8091aa91 768}
769
8091aa91 770sub txn_rollback {
d79f59b9 771 my $self = shift;
d32d82f9 772 eval { $self->dbh_do(\&__txn_rollback, $self) };
a62cf8d4 773 if ($@) {
774 my $error = $@;
775 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
776 $error =~ /$exception_class/ and $self->throw_exception($error);
777 $self->{transaction_depth} = 0; # ensure that a failed rollback
778 $self->throw_exception($error); # resets the transaction depth
8091aa91 779 }
780}
8b445e33 781
223b8fe3 782sub _execute {
783 my ($self, $op, $extra_bind, $ident, @args) = @_;
784 my ($sql, @bind) = $self->sql_maker->$op($ident, @args);
944f30bf 785 unshift(@bind, @$extra_bind) if $extra_bind;
f59ffc79 786 if ($self->debug) {
e673f011 787 my @debug_bind = map { defined $_ ? qq{'$_'} : q{'NULL'} } @bind;
4c248161 788 $self->debugobj->query_start($sql, @debug_bind);
f59ffc79 789 }
75db246c 790 my $sth = eval { $self->sth($sql,$op) };
791
792 if (!$sth || $@) {
ec0ff6f6 793 $self->throw_exception(
794 'no sth generated via sql (' . ($@ || $self->_dbh->errstr) . "): $sql"
795 );
75db246c 796 }
438adc0e 797 @bind = map { ref $_ ? ''.$_ : $_ } @bind; # stringify args
701da8c4 798 my $rv;
75d07914 799 if ($sth) {
4c248161 800 my $time = time();
95dad7e2 801 $rv = eval { $sth->execute(@bind) };
802
803 if ($@ || !$rv) {
804 $self->throw_exception("Error executing '$sql': ".($@ || $sth->errstr));
805 }
75d07914 806 } else {
1c339d71 807 $self->throw_exception("'$sql' did not generate a statement.");
701da8c4 808 }
4c248161 809 if ($self->debug) {
810 my @debug_bind = map { defined $_ ? qq{`$_'} : q{`NULL'} } @bind;
811 $self->debugobj->query_end($sql, @debug_bind);
812 }
223b8fe3 813 return (wantarray ? ($rv, $sth, @bind) : $rv);
814}
815
8b445e33 816sub insert {
817 my ($self, $ident, $to_insert) = @_;
bc0c9800 818 $self->throw_exception(
819 "Couldn't insert ".join(', ',
820 map "$_ => $to_insert->{$_}", keys %$to_insert
821 )." into ${ident}"
822 ) unless ($self->_execute('insert' => [], $ident, $to_insert));
8b445e33 823 return $to_insert;
824}
825
826sub update {
223b8fe3 827 return shift->_execute('update' => [], @_);
8b445e33 828}
829
830sub delete {
223b8fe3 831 return shift->_execute('delete' => [], @_);
8b445e33 832}
833
de705b51 834sub _select {
8b445e33 835 my ($self, $ident, $select, $condition, $attrs) = @_;
223b8fe3 836 my $order = $attrs->{order_by};
837 if (ref $condition eq 'SCALAR') {
838 $order = $1 if $$condition =~ s/ORDER BY (.*)$//i;
839 }
8839560b 840 if (exists $attrs->{group_by} || $attrs->{having}) {
bc0c9800 841 $order = {
842 group_by => $attrs->{group_by},
843 having => $attrs->{having},
844 ($order ? (order_by => $order) : ())
845 };
54540863 846 }
5c91499f 847 my @args = ('select', $attrs->{bind}, $ident, $select, $condition, $order);
9229f20a 848 if ($attrs->{software_limit} ||
849 $self->sql_maker->_default_limit_syntax eq "GenericSubQ") {
850 $attrs->{software_limit} = 1;
5c91499f 851 } else {
0823196c 852 $self->throw_exception("rows attribute must be positive if present")
853 if (defined($attrs->{rows}) && !($attrs->{rows} > 0));
5c91499f 854 push @args, $attrs->{rows}, $attrs->{offset};
855 }
de705b51 856 return $self->_execute(@args);
857}
858
9b83fccd 859=head2 select
860
d3b0e369 861=over 4
862
863=item Arguments: $ident, $select, $condition, $attrs
864
865=back
866
9b83fccd 867Handle a SQL select statement.
868
869=cut
870
de705b51 871sub select {
872 my $self = shift;
873 my ($ident, $select, $condition, $attrs) = @_;
cb5f2eea 874 return $self->cursor->new($self, \@_, $attrs);
8b445e33 875}
876
1a14aa3f 877sub select_single {
de705b51 878 my $self = shift;
879 my ($rv, $sth, @bind) = $self->_select(@_);
6157db4f 880 my @row = $sth->fetchrow_array;
a3eaff0e 881 # Need to call finish() to work round broken DBDs
6157db4f 882 $sth->finish();
883 return @row;
1a14aa3f 884}
885
9b83fccd 886=head2 sth
887
d3b0e369 888=over 4
889
890=item Arguments: $sql
891
892=back
893
9b83fccd 894Returns a L<DBI> sth (statement handle) for the supplied SQL.
895
896=cut
897
d32d82f9 898sub __sth {
899 my ($dbh, $sql) = @_;
900 # 3 is the if_active parameter which avoids active sth re-use
901 $dbh->prepare_cached($sql, {}, 3);
902}
903
8b445e33 904sub sth {
cb5f2eea 905 my ($self, $sql) = @_;
d32d82f9 906 $self->dbh_do(\&__sth, $sql);
8b445e33 907}
908
bfe10d87 909
d32d82f9 910sub __columns_info_for {
911 my ($dbh, $self, $table) = @_;
a32e8402 912
d32d82f9 913 if ($dbh->can('column_info')) {
a953d8d9 914 my %result;
d32d82f9 915 eval {
916 my ($schema,$tab) = $table =~ /^(.+?)\.(.+)$/ ? ($1,$2) : (undef,$table);
917 my $sth = $dbh->column_info( undef,$schema, $tab, '%' );
918 $sth->execute();
919 while ( my $info = $sth->fetchrow_hashref() ){
920 my %column_info;
921 $column_info{data_type} = $info->{TYPE_NAME};
922 $column_info{size} = $info->{COLUMN_SIZE};
923 $column_info{is_nullable} = $info->{NULLABLE} ? 1 : 0;
924 $column_info{default_value} = $info->{COLUMN_DEF};
925 my $col_name = $info->{COLUMN_NAME};
926 $col_name =~ s/^\"(.*)\"$/$1/;
927
928 $result{$col_name} = \%column_info;
0d67fe74 929 }
d32d82f9 930 };
093fc7a6 931 return \%result if !$@ && scalar keys %result;
d32d82f9 932 }
0d67fe74 933
d32d82f9 934 my %result;
935 my $sth = $dbh->prepare("SELECT * FROM $table WHERE 1=0");
936 $sth->execute;
937 my @columns = @{$sth->{NAME_lc}};
938 for my $i ( 0 .. $#columns ){
939 my %column_info;
940 my $type_num = $sth->{TYPE}->[$i];
941 my $type_name;
942 if(defined $type_num && $dbh->can('type_info')) {
943 my $type_info = $dbh->type_info($type_num);
944 $type_name = $type_info->{TYPE_NAME} if $type_info;
945 }
946 $column_info{data_type} = $type_name ? $type_name : $type_num;
947 $column_info{size} = $sth->{PRECISION}->[$i];
948 $column_info{is_nullable} = $sth->{NULLABLE}->[$i] ? 1 : 0;
0d67fe74 949
d32d82f9 950 if ($column_info{data_type} =~ m/^(.*?)\((.*?)\)$/) {
951 $column_info{data_type} = $1;
952 $column_info{size} = $2;
0d67fe74 953 }
954
d32d82f9 955 $result{$columns[$i]} = \%column_info;
956 }
957
958 return \%result;
959}
960
961sub columns_info_for {
962 my ($self, $table) = @_;
963 $self->dbh_do(\&__columns_info_for, $self, $table);
a953d8d9 964}
965
9b83fccd 966=head2 last_insert_id
967
968Return the row id of the last insert.
969
970=cut
971
843f8ecd 972sub last_insert_id {
973 my ($self, $row) = @_;
974
f11383c2 975 $self->dbh_do(sub { shift->func('last_insert_rowid') });
843f8ecd 976}
977
9b83fccd 978=head2 sqlt_type
979
980Returns the database driver name.
981
982=cut
983
f11383c2 984sub sqlt_type { shift->dbh_do(sub { shift->{Driver}->{Name} }) }
1c339d71 985
9b83fccd 986=head2 create_ddl_dir (EXPERIMENTAL)
987
988=over 4
989
990=item Arguments: $schema \@databases, $version, $directory, $sqlt_args
991
992=back
993
d3b0e369 994Creates a SQL file based on the Schema, for each of the specified
9b83fccd 995database types, in the given directory.
996
997Note that this feature is currently EXPERIMENTAL and may not work correctly
998across all databases, or fully handle complex relationships.
999
1000=cut
1001
e673f011 1002sub create_ddl_dir
1003{
1004 my ($self, $schema, $databases, $version, $dir, $sqltargs) = @_;
1005
1006 if(!$dir || !-d $dir)
1007 {
1008 warn "No directory given, using ./\n";
1009 $dir = "./";
1010 }
1011 $databases ||= ['MySQL', 'SQLite', 'PostgreSQL'];
1012 $databases = [ $databases ] if(ref($databases) ne 'ARRAY');
1013 $version ||= $schema->VERSION || '1.x';
9e7b9292 1014 $sqltargs = { ( add_drop_table => 1 ), %{$sqltargs || {}} };
e673f011 1015
1c339d71 1016 eval "use SQL::Translator";
1017 $self->throw_exception("Can't deploy without SQL::Translator: $@") if $@;
e673f011 1018
9e7b9292 1019 my $sqlt = SQL::Translator->new($sqltargs);
e673f011 1020 foreach my $db (@$databases)
1021 {
1022 $sqlt->reset();
1023 $sqlt->parser('SQL::Translator::Parser::DBIx::Class');
1024# $sqlt->parser_args({'DBIx::Class' => $schema);
1025 $sqlt->data($schema);
1026 $sqlt->producer($db);
1027
1028 my $file;
1029 my $filename = $schema->ddl_filename($db, $dir, $version);
1030 if(-e $filename)
1031 {
1032 $self->throw_exception("$filename already exists, skipping $db");
1033 next;
1034 }
1035 open($file, ">$filename")
1036 or $self->throw_exception("Can't open $filename for writing ($!)");
1037 my $output = $sqlt->translate;
1038#use Data::Dumper;
1039# print join(":", keys %{$schema->source_registrations});
1040# print Dumper($sqlt->schema);
1041 if(!$output)
1042 {
1043 $self->throw_exception("Failed to translate to $db. (" . $sqlt->error . ")");
1044 next;
1045 }
1046 print $file $output;
1047 close($file);
1048 }
1049
1050}
1051
9b83fccd 1052=head2 deployment_statements
1053
d3b0e369 1054=over 4
1055
1056=item Arguments: $schema, $type, $version, $directory, $sqlt_args
1057
1058=back
1059
1060Returns the statements used by L</deploy> and L<DBIx::Class::Schema/deploy>.
1061The database driver name is given by C<$type>, though the value from
1062L</sqlt_type> is used if it is not specified.
1063
1064C<$directory> is used to return statements from files in a previously created
1065L</create_ddl_dir> directory and is optional. The filenames are constructed
1066from L<DBIx::Class::Schema/ddl_filename>, the schema name and the C<$version>.
1067
1068If no C<$directory> is specified then the statements are constructed on the
1069fly using L<SQL::Translator> and C<$version> is ignored.
1070
1071See L<SQL::Translator/METHODS> for a list of values for C<$sqlt_args>.
9b83fccd 1072
1073=cut
1074
e673f011 1075sub deployment_statements {
1076 my ($self, $schema, $type, $version, $dir, $sqltargs) = @_;
915919c5 1077 # Need to be connected to get the correct sqlt_type
c377d939 1078 $self->ensure_connected() unless $type;
e673f011 1079 $type ||= $self->sqlt_type;
1080 $version ||= $schema->VERSION || '1.x';
1081 $dir ||= './';
0382d607 1082 eval "use SQL::Translator";
1083 if(!$@)
1084 {
1085 eval "use SQL::Translator::Parser::DBIx::Class;";
1086 $self->throw_exception($@) if $@;
1087 eval "use SQL::Translator::Producer::${type};";
1088 $self->throw_exception($@) if $@;
1089 my $tr = SQL::Translator->new(%$sqltargs);
1090 SQL::Translator::Parser::DBIx::Class::parse( $tr, $schema );
1091 return "SQL::Translator::Producer::${type}"->can('produce')->($tr);
1092 }
e673f011 1093
1094 my $filename = $schema->ddl_filename($type, $dir, $version);
1095 if(!-f $filename)
1096 {
0382d607 1097# $schema->create_ddl_dir([ $type ], $version, $dir, $sqltargs);
1098 $self->throw_exception("No SQL::Translator, and no Schema file found, aborting deploy");
1099 return;
e673f011 1100 }
1101 my $file;
1102 open($file, "<$filename")
1103 or $self->throw_exception("Can't open $filename ($!)");
1104 my @rows = <$file>;
1105 close($file);
1106
1107 return join('', @rows);
1108
1c339d71 1109}
843f8ecd 1110
1c339d71 1111sub deploy {
260129d8 1112 my ($self, $schema, $type, $sqltargs, $dir) = @_;
1113 foreach my $statement ( $self->deployment_statements($schema, $type, undef, $dir, { no_comments => 1, %{ $sqltargs || {} } } ) ) {
e4fe9ba3 1114 for ( split(";\n", $statement)) {
e673f011 1115 next if($_ =~ /^--/);
1116 next if(!$_);
1117# next if($_ =~ /^DROP/m);
1118 next if($_ =~ /^BEGIN TRANSACTION/m);
1119 next if($_ =~ /^COMMIT/m);
b489f68a 1120 next if $_ =~ /^\s+$/; # skip whitespace only
bdea30e3 1121 $self->debugobj->query_start($_) if $self->debug;
f11383c2 1122 $self->dbh->do($_) or warn "SQL was:\n $_"; # XXX exceptions?
4c248161 1123 $self->debugobj->query_end($_) if $self->debug;
e4fe9ba3 1124 }
75d07914 1125 }
1c339d71 1126}
843f8ecd 1127
9b83fccd 1128=head2 datetime_parser
1129
1130Returns the datetime parser class
1131
1132=cut
1133
f86fcf0d 1134sub datetime_parser {
1135 my $self = shift;
1136 return $self->{datetime_parser} ||= $self->build_datetime_parser(@_);
1137}
1138
9b83fccd 1139=head2 datetime_parser_type
1140
1141Defines (returns) the datetime parser class - currently hardwired to
1142L<DateTime::Format::MySQL>
1143
1144=cut
1145
f86fcf0d 1146sub datetime_parser_type { "DateTime::Format::MySQL"; }
1147
9b83fccd 1148=head2 build_datetime_parser
1149
1150See L</datetime_parser>
1151
1152=cut
1153
f86fcf0d 1154sub build_datetime_parser {
1155 my $self = shift;
1156 my $type = $self->datetime_parser_type(@_);
1157 eval "use ${type}";
1158 $self->throw_exception("Couldn't load ${type}: $@") if $@;
1159 return $type;
1160}
1161
c756145c 1162sub DESTROY {
1163 my $self = shift;
f5de3933 1164 return if !$self->_dbh;
c756145c 1165 $self->_verify_pid;
1166 $self->_dbh(undef);
1167}
92925617 1168
8b445e33 11691;
1170
9b83fccd 1171=head1 SQL METHODS
1172
1173The module defines a set of methods within the DBIC::SQL::Abstract
1174namespace. These build on L<SQL::Abstract::Limit> to provide the
1175SQL query functions.
1176
1177The following methods are extended:-
1178
1179=over 4
1180
1181=item delete
1182
1183=item insert
1184
1185=item select
1186
1187=item update
1188
1189=item limit_dialect
1190
2cc3a7be 1191See L</connect_info> for details.
1192For setting, this method is deprecated in favor of L</connect_info>.
bb4f246d 1193
9b83fccd 1194=item quote_char
1195
2cc3a7be 1196See L</connect_info> for details.
1197For setting, this method is deprecated in favor of L</connect_info>.
bb4f246d 1198
9b83fccd 1199=item name_sep
1200
2cc3a7be 1201See L</connect_info> for details.
1202For setting, this method is deprecated in favor of L</connect_info>.
bb4f246d 1203
9b83fccd 1204=back
1205
8b445e33 1206=head1 AUTHORS
1207
daec44b8 1208Matt S. Trout <mst@shadowcatsystems.co.uk>
8b445e33 1209
9f19b1d6 1210Andy Grundman <andy@hybridized.org>
1211
8b445e33 1212=head1 LICENSE
1213
1214You may distribute this code under the same terms as Perl itself.
1215
1216=cut