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