Document the auto_savepoint option for connect_info
[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
a3628767 433=item auto_savepoint
434
435If this option is true, L<DBIx::Class> will use savepoints when nesting
436transactions, making it possible to recover from failure in the inner
437transaction without having to abort all outer transactions.
438
2cc3a7be 439=back
440
441These options can be mixed in with your other L<DBI> connection attributes,
442or placed in a seperate hashref after all other normal L<DBI> connection
443arguments.
444
445Every time C<connect_info> is invoked, any previous settings for
446these options will be cleared before setting the new ones, regardless of
447whether any options are specified in the new C<connect_info>.
448
77d76d0f 449Another Important Note:
450
451DBIC can do some wonderful magic with handling exceptions,
c64db0f4 452disconnections, and transactions when you use C<< AutoCommit => 1 >>
77d76d0f 453combined with C<txn_do> for transaction support.
454
c64db0f4 455If you set C<< AutoCommit => 0 >> in your connect info, then you are always
77d76d0f 456in an assumed transaction between commits, and you're telling us you'd
457like to manage that manually. A lot of DBIC's magic protections
458go away. We can't protect you from exceptions due to database
459disconnects because we don't know anything about how to restart your
460transactions. You're on your own for handling all sorts of exceptional
c64db0f4 461cases if you choose the C<< AutoCommit => 0 >> path, just as you would
77d76d0f 462be with raw DBI.
463
2cc3a7be 464Examples:
465
466 # Simple SQLite connection
bb4f246d 467 ->connect_info([ 'dbi:SQLite:./foo.db' ]);
6789ebe3 468
2cc3a7be 469 # Connect via subref
bb4f246d 470 ->connect_info([ sub { DBI->connect(...) } ]);
6789ebe3 471
2cc3a7be 472 # A bit more complicated
bb4f246d 473 ->connect_info(
474 [
475 'dbi:Pg:dbname=foo',
476 'postgres',
477 'my_pg_password',
77d76d0f 478 { AutoCommit => 1 },
2cc3a7be 479 { quote_char => q{"}, name_sep => q{.} },
480 ]
481 );
482
483 # Equivalent to the previous example
484 ->connect_info(
485 [
486 'dbi:Pg:dbname=foo',
487 'postgres',
488 'my_pg_password',
77d76d0f 489 { AutoCommit => 1, quote_char => q{"}, name_sep => q{.} },
bb4f246d 490 ]
491 );
6789ebe3 492
2cc3a7be 493 # Subref + DBIC-specific connection options
bb4f246d 494 ->connect_info(
495 [
496 sub { DBI->connect(...) },
2cc3a7be 497 {
498 quote_char => q{`},
499 name_sep => q{@},
500 on_connect_do => ['SET search_path TO myschema,otherschema,public'],
b33697ef 501 disable_sth_caching => 1,
2cc3a7be 502 },
bb4f246d 503 ]
504 );
6789ebe3 505
004d31fb 506=cut
507
046ad905 508sub connect_info {
509 my ($self, $info_arg) = @_;
4c248161 510
046ad905 511 return $self->_connect_info if !$info_arg;
4c248161 512
046ad905 513 # Kill sql_maker/_sql_maker_opts, so we get a fresh one with only
514 # the new set of options
515 $self->_sql_maker(undef);
516 $self->_sql_maker_opts({});
fdad5fab 517 $self->_connect_info([@$info_arg]); # copy for _connect_info
486ad69b 518
fdad5fab 519 my $dbi_info = [@$info_arg]; # copy for _dbi_connect_info
8df3d107 520
541df64a 521 my $last_info = $dbi_info->[-1];
046ad905 522 if(ref $last_info eq 'HASH') {
9a0891be 523 $last_info = { %$last_info }; # so delete is non-destructive
5322ea52 524 my @storage_option = qw(
525 on_connect_do on_disconnect_do disable_sth_caching unsafe cursor_class
d6feb60f 526 auto_savepoint
5322ea52 527 );
579ca3f7 528 for my $storage_opt (@storage_option) {
b33697ef 529 if(my $value = delete $last_info->{$storage_opt}) {
530 $self->$storage_opt($value);
531 }
046ad905 532 }
533 for my $sql_maker_opt (qw/limit_dialect quote_char name_sep/) {
534 if(my $opt_val = delete $last_info->{$sql_maker_opt}) {
535 $self->_sql_maker_opts->{$sql_maker_opt} = $opt_val;
536 }
537 }
9a0891be 538 # re-insert modified hashref
539 $dbi_info->[-1] = $last_info;
486ad69b 540
046ad905 541 # Get rid of any trailing empty hashref
541df64a 542 pop(@$dbi_info) if !keys %$last_info;
046ad905 543 }
fdad5fab 544 $self->_dbi_connect_info($dbi_info);
d7c4c15c 545
fdad5fab 546 $self->_connect_info;
046ad905 547}
004d31fb 548
046ad905 549=head2 on_connect_do
4c248161 550
046ad905 551This method is deprecated in favor of setting via L</connect_info>.
486ad69b 552
f11383c2 553=head2 dbh_do
554
3ff1602f 555Arguments: ($subref | $method_name), @extra_coderef_args?
046ad905 556
3ff1602f 557Execute the given $subref or $method_name using the new exception-based
558connection management.
046ad905 559
d4f16b21 560The first two arguments will be the storage object that C<dbh_do> was called
561on and a database handle to use. Any additional arguments will be passed
562verbatim to the called subref as arguments 2 and onwards.
563
564Using this (instead of $self->_dbh or $self->dbh) ensures correct
565exception handling and reconnection (or failover in future subclasses).
566
567Your subref should have no side-effects outside of the database, as
568there is the potential for your subref to be partially double-executed
569if the database connection was stale/dysfunctional.
046ad905 570
56769f7c 571Example:
f11383c2 572
56769f7c 573 my @stuff = $schema->storage->dbh_do(
574 sub {
d4f16b21 575 my ($storage, $dbh, @cols) = @_;
576 my $cols = join(q{, }, @cols);
577 $dbh->selectrow_array("SELECT $cols FROM foo");
046ad905 578 },
579 @column_list
56769f7c 580 );
f11383c2 581
582=cut
583
584sub dbh_do {
046ad905 585 my $self = shift;
3ff1602f 586 my $code = shift;
aa27edf7 587
6ad1059d 588 my $dbh = $self->_dbh;
589
590 return $self->$code($dbh, @_) if $self->{_in_dbh_do}
cb19f4dd 591 || $self->{transaction_depth};
592
1b994857 593 local $self->{_in_dbh_do} = 1;
594
f11383c2 595 my @result;
596 my $want_array = wantarray;
597
598 eval {
6ad1059d 599 $self->_verify_pid if $dbh;
600 if( !$dbh ) {
601 $self->_populate_dbh;
602 $dbh = $self->_dbh;
603 }
604
f11383c2 605 if($want_array) {
6ad1059d 606 @result = $self->$code($dbh, @_);
f11383c2 607 }
56769f7c 608 elsif(defined $want_array) {
6ad1059d 609 $result[0] = $self->$code($dbh, @_);
f11383c2 610 }
56769f7c 611 else {
6ad1059d 612 $self->$code($dbh, @_);
56769f7c 613 }
f11383c2 614 };
56769f7c 615
aa27edf7 616 my $exception = $@;
617 if(!$exception) { return $want_array ? @result : $result[0] }
618
619 $self->throw_exception($exception) if $self->connected;
620
621 # We were not connected - reconnect and retry, but let any
622 # exception fall right through this time
623 $self->_populate_dbh;
3ff1602f 624 $self->$code($self->_dbh, @_);
aa27edf7 625}
626
627# This is basically a blend of dbh_do above and DBIx::Class::Storage::txn_do.
628# It also informs dbh_do to bypass itself while under the direction of txn_do,
1b994857 629# via $self->{_in_dbh_do} (this saves some redundant eval and errorcheck, etc)
aa27edf7 630sub txn_do {
631 my $self = shift;
632 my $coderef = shift;
633
634 ref $coderef eq 'CODE' or $self->throw_exception
635 ('$coderef must be a CODE reference');
636
d6feb60f 637 return $coderef->(@_) if $self->{transaction_depth} && ! $self->auto_savepoint;
57c18b65 638
1b994857 639 local $self->{_in_dbh_do} = 1;
f11383c2 640
aa27edf7 641 my @result;
642 my $want_array = wantarray;
643
d4f16b21 644 my $tried = 0;
645 while(1) {
646 eval {
647 $self->_verify_pid if $self->_dbh;
648 $self->_populate_dbh if !$self->_dbh;
aa27edf7 649
d4f16b21 650 $self->txn_begin;
651 if($want_array) {
652 @result = $coderef->(@_);
653 }
654 elsif(defined $want_array) {
655 $result[0] = $coderef->(@_);
656 }
657 else {
658 $coderef->(@_);
659 }
660 $self->txn_commit;
661 };
aa27edf7 662
d4f16b21 663 my $exception = $@;
664 if(!$exception) { return $want_array ? @result : $result[0] }
665
666 if($tried++ > 0 || $self->connected) {
667 eval { $self->txn_rollback };
668 my $rollback_exception = $@;
669 if($rollback_exception) {
670 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
671 $self->throw_exception($exception) # propagate nested rollback
672 if $rollback_exception =~ /$exception_class/;
673
674 $self->throw_exception(
675 "Transaction aborted: ${exception}. "
676 . "Rollback failed: ${rollback_exception}"
677 );
678 }
679 $self->throw_exception($exception)
aa27edf7 680 }
56769f7c 681
d4f16b21 682 # We were not connected, and was first try - reconnect and retry
683 # via the while loop
684 $self->_populate_dbh;
685 }
f11383c2 686}
687
9b83fccd 688=head2 disconnect
689
046ad905 690Our C<disconnect> method also performs a rollback first if the
9b83fccd 691database is not in C<AutoCommit> mode.
692
693=cut
694
412db1f4 695sub disconnect {
696 my ($self) = @_;
697
92925617 698 if( $self->connected ) {
6d2e7a96 699 my $connection_do = $self->on_disconnect_do;
700 $self->_do_connection_actions($connection_do) if ref($connection_do);
701
57c18b65 702 $self->_dbh->rollback unless $self->_dbh_autocommit;
92925617 703 $self->_dbh->disconnect;
704 $self->_dbh(undef);
dbaee748 705 $self->{_dbh_gen}++;
92925617 706 }
412db1f4 707}
708
f11383c2 709sub connected {
710 my ($self) = @_;
412db1f4 711
1346e22d 712 if(my $dbh = $self->_dbh) {
713 if(defined $self->_conn_tid && $self->_conn_tid != threads->tid) {
dbaee748 714 $self->_dbh(undef);
715 $self->{_dbh_gen}++;
716 return;
1346e22d 717 }
56769f7c 718 else {
719 $self->_verify_pid;
649bfb8c 720 return 0 if !$self->_dbh;
56769f7c 721 }
1346e22d 722 return ($dbh->FETCH('Active') && $dbh->ping);
723 }
724
725 return 0;
412db1f4 726}
727
f11383c2 728# handle pid changes correctly
56769f7c 729# NOTE: assumes $self->_dbh is a valid $dbh
f11383c2 730sub _verify_pid {
731 my ($self) = @_;
732
6ae3f9b9 733 return if defined $self->_conn_pid && $self->_conn_pid == $$;
f11383c2 734
f11383c2 735 $self->_dbh->{InactiveDestroy} = 1;
d3abf3fe 736 $self->_dbh(undef);
dbaee748 737 $self->{_dbh_gen}++;
f11383c2 738
739 return;
740}
741
412db1f4 742sub ensure_connected {
743 my ($self) = @_;
744
745 unless ($self->connected) {
8b445e33 746 $self->_populate_dbh;
747 }
412db1f4 748}
749
c235bbae 750=head2 dbh
751
752Returns the dbh - a data base handle of class L<DBI>.
753
754=cut
755
412db1f4 756sub dbh {
757 my ($self) = @_;
758
759 $self->ensure_connected;
8b445e33 760 return $self->_dbh;
761}
762
f1f56aad 763sub _sql_maker_args {
764 my ($self) = @_;
765
6e399b4f 766 return ( bindtype=>'columns', limit_dialect => $self->dbh, %{$self->_sql_maker_opts} );
f1f56aad 767}
768
48c69e7c 769sub sql_maker {
770 my ($self) = @_;
fdc1c3d0 771 unless ($self->_sql_maker) {
95ba7ee4 772 my $sql_maker_class = $self->sql_maker_class;
773 $self->_sql_maker($sql_maker_class->new( $self->_sql_maker_args ));
48c69e7c 774 }
775 return $self->_sql_maker;
776}
777
3ff1602f 778sub _rebless {}
779
8b445e33 780sub _populate_dbh {
781 my ($self) = @_;
7e47ea83 782 my @info = @{$self->_dbi_connect_info || []};
8b445e33 783 $self->_dbh($self->_connect(@info));
2fd24e78 784
77d76d0f 785 # Always set the transaction depth on connect, since
786 # there is no transaction in progress by definition
57c18b65 787 $self->{transaction_depth} = $self->_dbh_autocommit ? 0 : 1;
77d76d0f 788
2fd24e78 789 if(ref $self eq 'DBIx::Class::Storage::DBI') {
790 my $driver = $self->_dbh->{Driver}->{Name};
efe6365b 791 if ($self->load_optional_class("DBIx::Class::Storage::DBI::${driver}")) {
2fd24e78 792 bless $self, "DBIx::Class::Storage::DBI::${driver}";
3ff1602f 793 $self->_rebless();
2fd24e78 794 }
843f8ecd 795 }
2fd24e78 796
6d2e7a96 797 my $connection_do = $self->on_connect_do;
798 $self->_do_connection_actions($connection_do) if ref($connection_do);
5ef3e508 799
1346e22d 800 $self->_conn_pid($$);
801 $self->_conn_tid(threads->tid) if $INC{'threads.pm'};
8b445e33 802}
803
6d2e7a96 804sub _do_connection_actions {
805 my $self = shift;
806 my $connection_do = shift;
807
808 if (ref $connection_do eq 'ARRAY') {
809 $self->_do_query($_) foreach @$connection_do;
810 }
811 elsif (ref $connection_do eq 'CODE') {
812 $connection_do->();
813 }
814
815 return $self;
816}
817
579ca3f7 818sub _do_query {
819 my ($self, $action) = @_;
820
6d2e7a96 821 if (ref $action eq 'CODE') {
1dafdb2a 822 $action = $action->($self);
823 $self->_do_query($_) foreach @$action;
579ca3f7 824 }
825 else {
1bd1640b 826 my @to_run = (ref $action eq 'ARRAY') ? (@$action) : ($action);
827 $self->_query_start(@to_run);
828 $self->_dbh->do(@to_run);
829 $self->_query_end(@to_run);
579ca3f7 830 }
831
832 return $self;
833}
834
8b445e33 835sub _connect {
836 my ($self, @info) = @_;
5ef3e508 837
9d31f7dc 838 $self->throw_exception("You failed to provide any connection info")
61646ebd 839 if !@info;
9d31f7dc 840
90ec6cad 841 my ($old_connect_via, $dbh);
842
5ef3e508 843 if ($INC{'Apache/DBI.pm'} && $ENV{MOD_PERL}) {
61646ebd 844 $old_connect_via = $DBI::connect_via;
845 $DBI::connect_via = 'connect';
5ef3e508 846 }
847
75db246c 848 eval {
f5de3933 849 if(ref $info[0] eq 'CODE') {
850 $dbh = &{$info[0]}
851 }
852 else {
853 $dbh = DBI->connect(@info);
61646ebd 854 }
855
e7827df0 856 if($dbh && !$self->unsafe) {
664612fb 857 my $weak_self = $self;
858 weaken($weak_self);
61646ebd 859 $dbh->{HandleError} = sub {
664612fb 860 $weak_self->throw_exception("DBI Exception: $_[0]")
61646ebd 861 };
2ab60eb9 862 $dbh->{ShowErrorStatement} = 1;
61646ebd 863 $dbh->{RaiseError} = 1;
864 $dbh->{PrintError} = 0;
f5de3933 865 }
75db246c 866 };
90ec6cad 867
868 $DBI::connect_via = $old_connect_via if $old_connect_via;
869
d92a4015 870 $self->throw_exception("DBI Connection failed: " . ($@||$DBI::errstr))
871 if !$dbh || $@;
90ec6cad 872
57c18b65 873 $self->_dbh_autocommit($dbh->{AutoCommit});
874
e571e823 875 $dbh;
8b445e33 876}
877
adb3554a 878sub svp_begin {
879 my ($self, $name) = @_;
880
881 $self->throw_exception("You failed to provide a savepoint name!") if !$name;
882
883 if($self->{transaction_depth} == 0) {
884 warn("Can't use savepoints without a transaction.");
885 return 0;
886 }
887
888 if(!$self->can('_svp_begin')) {
889 warn("Your Storage implementation doesn't support savepoints!");
890 return 0;
891 }
892 $self->debugobj->svp_begin($name) if $self->debug;
eeb8cfeb 893 $self->_svp_begin($name);
adb3554a 894}
895
896sub svp_release {
897 my ($self, $name) = @_;
898
899 $self->throw_exception("You failed to provide a savepoint name!") if !$name;
900
901 if($self->{transaction_depth} == 0) {
902 warn("Can't use savepoints without a transaction.");
903 return 0;
904 }
905
906 if(!$self->can('_svp_release')) {
907 warn("Your Storage implementation doesn't support savepoint releasing!");
908 return 0;
909 }
910 $self->debugobj->svp_release($name) if $self->debug;
eeb8cfeb 911 $self->_svp_release($name);
adb3554a 912}
913
914sub svp_rollback {
915 my ($self, $name) = @_;
916
917 $self->throw_exception("You failed to provide a savepoint name!") if !$name;
918
919 if($self->{transaction_depth} == 0) {
920 warn("Can't use savepoints without a transaction.");
921 return 0;
922 }
923
924 if(!$self->can('_svp_rollback')) {
925 warn("Your Storage implementation doesn't support savepoints!");
926 return 0;
927 }
928 $self->debugobj->svp_rollback($name) if $self->debug;
eeb8cfeb 929 $self->_svp_rollback($name);
adb3554a 930}
d32d82f9 931
8091aa91 932sub txn_begin {
d79f59b9 933 my $self = shift;
291bf95f 934 $self->ensure_connected();
57c18b65 935 if($self->{transaction_depth} == 0) {
77d76d0f 936 $self->debugobj->txn_begin()
937 if $self->debug;
938 # this isn't ->_dbh-> because
939 # we should reconnect on begin_work
940 # for AutoCommit users
941 $self->dbh->begin_work;
d6feb60f 942 } elsif ($self->auto_savepoint) {
943 $self->svp_begin ("savepoint_$self->{transaction_depth}");
986e4fca 944 }
57c18b65 945 $self->{transaction_depth}++;
8091aa91 946}
8b445e33 947
8091aa91 948sub txn_commit {
d79f59b9 949 my $self = shift;
77d76d0f 950 if ($self->{transaction_depth} == 1) {
951 my $dbh = $self->_dbh;
952 $self->debugobj->txn_commit()
953 if ($self->debug);
954 $dbh->commit;
955 $self->{transaction_depth} = 0
57c18b65 956 if $self->_dbh_autocommit;
77d76d0f 957 }
958 elsif($self->{transaction_depth} > 1) {
d6feb60f 959 $self->{transaction_depth}--;
960 $self->svp_release ("savepoint_$self->{transaction_depth}")
961 if $self->auto_savepoint;
77d76d0f 962 }
d32d82f9 963}
964
77d76d0f 965sub txn_rollback {
966 my $self = shift;
967 my $dbh = $self->_dbh;
77d76d0f 968 eval {
77d76d0f 969 if ($self->{transaction_depth} == 1) {
d32d82f9 970 $self->debugobj->txn_rollback()
971 if ($self->debug);
77d76d0f 972 $self->{transaction_depth} = 0
57c18b65 973 if $self->_dbh_autocommit;
974 $dbh->rollback;
d32d82f9 975 }
77d76d0f 976 elsif($self->{transaction_depth} > 1) {
977 $self->{transaction_depth}--;
d6feb60f 978 if ($self->auto_savepoint) {
979 $self->svp_rollback ("savepoint_$self->{transaction_depth}");
980 $self->svp_release ("savepoint_$self->{transaction_depth}");
981 }
986e4fca 982 }
f11383c2 983 else {
d32d82f9 984 die DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION->new;
986e4fca 985 }
77d76d0f 986 };
a62cf8d4 987 if ($@) {
988 my $error = $@;
989 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
990 $error =~ /$exception_class/ and $self->throw_exception($error);
77d76d0f 991 # ensure that a failed rollback resets the transaction depth
57c18b65 992 $self->{transaction_depth} = $self->_dbh_autocommit ? 0 : 1;
77d76d0f 993 $self->throw_exception($error);
8091aa91 994 }
995}
8b445e33 996
b7151206 997# This used to be the top-half of _execute. It was split out to make it
998# easier to override in NoBindVars without duping the rest. It takes up
999# all of _execute's args, and emits $sql, @bind.
1000sub _prep_for_execute {
d944c5ae 1001 my ($self, $op, $extra_bind, $ident, $args) = @_;
b7151206 1002
d944c5ae 1003 my ($sql, @bind) = $self->sql_maker->$op($ident, @$args);
db4b5f11 1004 unshift(@bind,
1005 map { ref $_ eq 'ARRAY' ? $_ : [ '!!dummy', $_ ] } @$extra_bind)
1006 if $extra_bind;
b7151206 1007
d944c5ae 1008 return ($sql, \@bind);
b7151206 1009}
1010
e5d9ee92 1011sub _fix_bind_params {
1012 my ($self, @bind) = @_;
1013
1014 ### Turn @bind from something like this:
1015 ### ( [ "artist", 1 ], [ "cdid", 1, 3 ] )
1016 ### to this:
1017 ### ( "'1'", "'1'", "'3'" )
1018 return
1019 map {
1020 if ( defined( $_ && $_->[1] ) ) {
1021 map { qq{'$_'}; } @{$_}[ 1 .. $#$_ ];
1022 }
1023 else { q{'NULL'}; }
1024 } @bind;
1025}
1026
1027sub _query_start {
1028 my ( $self, $sql, @bind ) = @_;
1029
1030 if ( $self->debug ) {
1031 @bind = $self->_fix_bind_params(@bind);
1032 $self->debugobj->query_start( $sql, @bind );
1033 }
1034}
1035
1036sub _query_end {
1037 my ( $self, $sql, @bind ) = @_;
1038
1039 if ( $self->debug ) {
1040 @bind = $self->_fix_bind_params(@bind);
1041 $self->debugobj->query_end( $sql, @bind );
1042 }
1043}
1044
baa31d2f 1045sub _dbh_execute {
1046 my ($self, $dbh, $op, $extra_bind, $ident, $bind_attributes, @args) = @_;
7af8b477 1047
eda28767 1048 if( blessed($ident) && $ident->isa("DBIx::Class::ResultSource") ) {
b7ce6568 1049 $ident = $ident->from();
1050 }
d944c5ae 1051
1052 my ($sql, $bind) = $self->_prep_for_execute($op, $extra_bind, $ident, \@args);
d92a4015 1053
e5d9ee92 1054 $self->_query_start( $sql, @$bind );
95dad7e2 1055
61646ebd 1056 my $sth = $self->sth($sql,$op);
6e399b4f 1057
61646ebd 1058 my $placeholder_index = 1;
6e399b4f 1059
61646ebd 1060 foreach my $bound (@$bind) {
1061 my $attributes = {};
1062 my($column_name, @data) = @$bound;
6e399b4f 1063
61646ebd 1064 if ($bind_attributes) {
1065 $attributes = $bind_attributes->{$column_name}
1066 if defined $bind_attributes->{$column_name};
1067 }
6e399b4f 1068
61646ebd 1069 foreach my $data (@data) {
1070 $data = ref $data ? ''.$data : $data; # stringify args
0b5dee17 1071
61646ebd 1072 $sth->bind_param($placeholder_index, $data, $attributes);
1073 $placeholder_index++;
95dad7e2 1074 }
61646ebd 1075 }
d92a4015 1076
61646ebd 1077 # Can this fail without throwing an exception anyways???
1078 my $rv = $sth->execute();
1079 $self->throw_exception($sth->errstr) if !$rv;
d92a4015 1080
e5d9ee92 1081 $self->_query_end( $sql, @$bind );
baa31d2f 1082
d944c5ae 1083 return (wantarray ? ($rv, $sth, @$bind) : $rv);
223b8fe3 1084}
1085
baa31d2f 1086sub _execute {
1087 my $self = shift;
3ff1602f 1088 $self->dbh_do('_dbh_execute', @_)
baa31d2f 1089}
1090
8b445e33 1091sub insert {
7af8b477 1092 my ($self, $source, $to_insert) = @_;
1093
1094 my $ident = $source->from;
8b646589 1095 my $bind_attributes = $self->source_bind_attributes($source);
1096
a982c051 1097 foreach my $col ( $source->columns ) {
1098 if ( !defined $to_insert->{$col} ) {
1099 my $col_info = $source->column_info($col);
1100
1101 if ( $col_info->{auto_nextval} ) {
6088eb64 1102 $self->ensure_connected;
a982c051 1103 $to_insert->{$col} = $self->_sequence_fetch( 'nextval', $col_info->{sequence} || $self->_dbh_get_autoinc_seq($self->dbh, $source) );
1104 }
1105 }
1106 }
1107
61646ebd 1108 $self->_execute('insert' => [], $source, $bind_attributes, $to_insert);
8e08ecc4 1109
8b445e33 1110 return $to_insert;
1111}
1112
744076d8 1113## Still not quite perfect, and EXPERIMENTAL
1114## Currently it is assumed that all values passed will be "normal", i.e. not
1115## scalar refs, or at least, all the same type as the first set, the statement is
1116## only prepped once.
54e0bd06 1117sub insert_bulk {
9fdf90df 1118 my ($self, $source, $cols, $data) = @_;
744076d8 1119 my %colvalues;
9fdf90df 1120 my $table = $source->from;
744076d8 1121 @colvalues{@$cols} = (0..$#$cols);
1122 my ($sql, @bind) = $self->sql_maker->insert($table, \%colvalues);
7af8b477 1123
e5d9ee92 1124 $self->_query_start( $sql, @bind );
894328b8 1125 my $sth = $self->sth($sql);
54e0bd06 1126
54e0bd06 1127# @bind = map { ref $_ ? ''.$_ : $_ } @bind; # stringify args
1128
744076d8 1129 ## This must be an arrayref, else nothing works!
9fdf90df 1130
744076d8 1131 my $tuple_status = [];
9fdf90df 1132
1133 ##use Data::Dumper;
1134 ##print STDERR Dumper( $data, $sql, [@bind] );
eda28767 1135
61646ebd 1136 my $time = time();
8b646589 1137
61646ebd 1138 ## Get the bind_attributes, if any exist
1139 my $bind_attributes = $self->source_bind_attributes($source);
9fdf90df 1140
61646ebd 1141 ## Bind the values and execute
1142 my $placeholder_index = 1;
9fdf90df 1143
61646ebd 1144 foreach my $bound (@bind) {
9fdf90df 1145
61646ebd 1146 my $attributes = {};
1147 my ($column_name, $data_index) = @$bound;
eda28767 1148
61646ebd 1149 if( $bind_attributes ) {
1150 $attributes = $bind_attributes->{$column_name}
1151 if defined $bind_attributes->{$column_name};
1152 }
9fdf90df 1153
61646ebd 1154 my @data = map { $_->[$data_index] } @$data;
9fdf90df 1155
61646ebd 1156 $sth->bind_param_array( $placeholder_index, [@data], $attributes );
1157 $placeholder_index++;
54e0bd06 1158 }
61646ebd 1159 my $rv = $sth->execute_array({ArrayTupleStatus => $tuple_status});
1160 $self->throw_exception($sth->errstr) if !$rv;
1161
e5d9ee92 1162 $self->_query_end( $sql, @bind );
54e0bd06 1163 return (wantarray ? ($rv, $sth, @bind) : $rv);
1164}
1165
8b445e33 1166sub update {
7af8b477 1167 my $self = shift @_;
1168 my $source = shift @_;
8b646589 1169 my $bind_attributes = $self->source_bind_attributes($source);
8b646589 1170
b7ce6568 1171 return $self->_execute('update' => [], $source, $bind_attributes, @_);
8b445e33 1172}
1173
7af8b477 1174
8b445e33 1175sub delete {
7af8b477 1176 my $self = shift @_;
1177 my $source = shift @_;
1178
1179 my $bind_attrs = {}; ## If ever it's needed...
7af8b477 1180
b7ce6568 1181 return $self->_execute('delete' => [], $source, $bind_attrs, @_);
8b445e33 1182}
1183
de705b51 1184sub _select {
8b445e33 1185 my ($self, $ident, $select, $condition, $attrs) = @_;
223b8fe3 1186 my $order = $attrs->{order_by};
95ba7ee4 1187
223b8fe3 1188 if (ref $condition eq 'SCALAR') {
1189 $order = $1 if $$condition =~ s/ORDER BY (.*)$//i;
1190 }
95ba7ee4 1191
1192 my $for = delete $attrs->{for};
1193 my $sql_maker = $self->sql_maker;
1194 local $sql_maker->{for} = $for;
1195
8839560b 1196 if (exists $attrs->{group_by} || $attrs->{having}) {
bc0c9800 1197 $order = {
1198 group_by => $attrs->{group_by},
1199 having => $attrs->{having},
1200 ($order ? (order_by => $order) : ())
1201 };
54540863 1202 }
7af8b477 1203 my $bind_attrs = {}; ## Future support
1204 my @args = ('select', $attrs->{bind}, $ident, $bind_attrs, $select, $condition, $order);
9229f20a 1205 if ($attrs->{software_limit} ||
1206 $self->sql_maker->_default_limit_syntax eq "GenericSubQ") {
1207 $attrs->{software_limit} = 1;
5c91499f 1208 } else {
0823196c 1209 $self->throw_exception("rows attribute must be positive if present")
1210 if (defined($attrs->{rows}) && !($attrs->{rows} > 0));
e60dc79f 1211
1212 # MySQL actually recommends this approach. I cringe.
1213 $attrs->{rows} = 2**48 if not defined $attrs->{rows} and defined $attrs->{offset};
5c91499f 1214 push @args, $attrs->{rows}, $attrs->{offset};
1215 }
95ba7ee4 1216
de705b51 1217 return $self->_execute(@args);
1218}
1219
8b646589 1220sub source_bind_attributes {
1221 my ($self, $source) = @_;
1222
1223 my $bind_attributes;
1224 foreach my $column ($source->columns) {
1225
1226 my $data_type = $source->column_info($column)->{data_type} || '';
1227 $bind_attributes->{$column} = $self->bind_attribute_by_data_type($data_type)
eda28767 1228 if $data_type;
8b646589 1229 }
1230
1231 return $bind_attributes;
1232}
1233
9b83fccd 1234=head2 select
1235
d3b0e369 1236=over 4
1237
1238=item Arguments: $ident, $select, $condition, $attrs
1239
1240=back
1241
9b83fccd 1242Handle a SQL select statement.
1243
1244=cut
1245
de705b51 1246sub select {
1247 my $self = shift;
1248 my ($ident, $select, $condition, $attrs) = @_;
e4eb8ee1 1249 return $self->cursor_class->new($self, \@_, $attrs);
8b445e33 1250}
1251
1a14aa3f 1252sub select_single {
de705b51 1253 my $self = shift;
1254 my ($rv, $sth, @bind) = $self->_select(@_);
6157db4f 1255 my @row = $sth->fetchrow_array;
a3eaff0e 1256 # Need to call finish() to work round broken DBDs
6157db4f 1257 $sth->finish();
1258 return @row;
1a14aa3f 1259}
1260
9b83fccd 1261=head2 sth
1262
d3b0e369 1263=over 4
1264
1265=item Arguments: $sql
1266
1267=back
1268
9b83fccd 1269Returns a L<DBI> sth (statement handle) for the supplied SQL.
1270
1271=cut
1272
d4f16b21 1273sub _dbh_sth {
1274 my ($self, $dbh, $sql) = @_;
b33697ef 1275
d32d82f9 1276 # 3 is the if_active parameter which avoids active sth re-use
b33697ef 1277 my $sth = $self->disable_sth_caching
1278 ? $dbh->prepare($sql)
1279 : $dbh->prepare_cached($sql, {}, 3);
1280
d92a4015 1281 # XXX You would think RaiseError would make this impossible,
1282 # but apparently that's not true :(
61646ebd 1283 $self->throw_exception($dbh->errstr) if !$sth;
b33697ef 1284
1285 $sth;
d32d82f9 1286}
1287
8b445e33 1288sub sth {
cb5f2eea 1289 my ($self, $sql) = @_;
3ff1602f 1290 $self->dbh_do('_dbh_sth', $sql);
8b445e33 1291}
1292
d4f16b21 1293sub _dbh_columns_info_for {
1294 my ($self, $dbh, $table) = @_;
a32e8402 1295
d32d82f9 1296 if ($dbh->can('column_info')) {
a953d8d9 1297 my %result;
d32d82f9 1298 eval {
1299 my ($schema,$tab) = $table =~ /^(.+?)\.(.+)$/ ? ($1,$2) : (undef,$table);
1300 my $sth = $dbh->column_info( undef,$schema, $tab, '%' );
1301 $sth->execute();
1302 while ( my $info = $sth->fetchrow_hashref() ){
1303 my %column_info;
1304 $column_info{data_type} = $info->{TYPE_NAME};
1305 $column_info{size} = $info->{COLUMN_SIZE};
1306 $column_info{is_nullable} = $info->{NULLABLE} ? 1 : 0;
1307 $column_info{default_value} = $info->{COLUMN_DEF};
1308 my $col_name = $info->{COLUMN_NAME};
1309 $col_name =~ s/^\"(.*)\"$/$1/;
1310
1311 $result{$col_name} = \%column_info;
0d67fe74 1312 }
d32d82f9 1313 };
093fc7a6 1314 return \%result if !$@ && scalar keys %result;
d32d82f9 1315 }
0d67fe74 1316
d32d82f9 1317 my %result;
88262f96 1318 my $sth = $dbh->prepare($self->sql_maker->select($table, undef, \'1 = 0'));
d32d82f9 1319 $sth->execute;
1320 my @columns = @{$sth->{NAME_lc}};
1321 for my $i ( 0 .. $#columns ){
1322 my %column_info;
248bf0d0 1323 $column_info{data_type} = $sth->{TYPE}->[$i];
d32d82f9 1324 $column_info{size} = $sth->{PRECISION}->[$i];
1325 $column_info{is_nullable} = $sth->{NULLABLE}->[$i] ? 1 : 0;
0d67fe74 1326
d32d82f9 1327 if ($column_info{data_type} =~ m/^(.*?)\((.*?)\)$/) {
1328 $column_info{data_type} = $1;
1329 $column_info{size} = $2;
0d67fe74 1330 }
1331
d32d82f9 1332 $result{$columns[$i]} = \%column_info;
1333 }
248bf0d0 1334 $sth->finish;
1335
1336 foreach my $col (keys %result) {
1337 my $colinfo = $result{$col};
1338 my $type_num = $colinfo->{data_type};
1339 my $type_name;
1340 if(defined $type_num && $dbh->can('type_info')) {
1341 my $type_info = $dbh->type_info($type_num);
1342 $type_name = $type_info->{TYPE_NAME} if $type_info;
1343 $colinfo->{data_type} = $type_name if $type_name;
1344 }
1345 }
d32d82f9 1346
1347 return \%result;
1348}
1349
1350sub columns_info_for {
1351 my ($self, $table) = @_;
3ff1602f 1352 $self->dbh_do('_dbh_columns_info_for', $table);
a953d8d9 1353}
1354
9b83fccd 1355=head2 last_insert_id
1356
1357Return the row id of the last insert.
1358
1359=cut
1360
d4f16b21 1361sub _dbh_last_insert_id {
1362 my ($self, $dbh, $source, $col) = @_;
1363 # XXX This is a SQLite-ism as a default... is there a DBI-generic way?
1364 $dbh->func('last_insert_rowid');
1365}
1366
843f8ecd 1367sub last_insert_id {
d4f16b21 1368 my $self = shift;
3ff1602f 1369 $self->dbh_do('_dbh_last_insert_id', @_);
843f8ecd 1370}
1371
9b83fccd 1372=head2 sqlt_type
1373
1374Returns the database driver name.
1375
1376=cut
1377
d4f16b21 1378sub sqlt_type { shift->dbh->{Driver}->{Name} }
1c339d71 1379
a71859b4 1380=head2 bind_attribute_by_data_type
1381
1382Given a datatype from column info, returns a database specific bind attribute for
1383$dbh->bind_param($val,$attribute) or nothing if we will let the database planner
1384just handle it.
1385
1386Generally only needed for special case column types, like bytea in postgres.
1387
1388=cut
1389
1390sub bind_attribute_by_data_type {
1391 return;
1392}
1393
58ded37e 1394=head2 create_ddl_dir
9b83fccd 1395
1396=over 4
1397
c9d2e0a2 1398=item Arguments: $schema \@databases, $version, $directory, $preversion, $sqlt_args
9b83fccd 1399
1400=back
1401
d3b0e369 1402Creates a SQL file based on the Schema, for each of the specified
9b83fccd 1403database types, in the given directory.
1404
9b83fccd 1405=cut
1406
e673f011 1407sub create_ddl_dir
1408{
c9d2e0a2 1409 my ($self, $schema, $databases, $version, $dir, $preversion, $sqltargs) = @_;
e673f011 1410
1411 if(!$dir || !-d $dir)
1412 {
1413 warn "No directory given, using ./\n";
1414 $dir = "./";
1415 }
1416 $databases ||= ['MySQL', 'SQLite', 'PostgreSQL'];
1417 $databases = [ $databases ] if(ref($databases) ne 'ARRAY');
1418 $version ||= $schema->VERSION || '1.x';
9e7b9292 1419 $sqltargs = { ( add_drop_table => 1 ), %{$sqltargs || {}} };
e673f011 1420
b6d9f089 1421 $self->throw_exception(q{Can't create a ddl file without SQL::Translator 0.09: '}
40dce2a5 1422 . $self->_check_sqlt_message . q{'})
1423 if !$self->_check_sqlt_version;
e673f011 1424
45f1a484 1425 my $sqlt = SQL::Translator->new( $sqltargs );
b7e303a8 1426
1427 $sqlt->parser('SQL::Translator::Parser::DBIx::Class');
1428 my $sqlt_schema = $sqlt->translate({ data => $schema }) or die $sqlt->error;
1429
e673f011 1430 foreach my $db (@$databases)
1431 {
1432 $sqlt->reset();
c9d2e0a2 1433 $sqlt = $self->configure_sqlt($sqlt, $db);
b7e303a8 1434 $sqlt->{schema} = $sqlt_schema;
e673f011 1435 $sqlt->producer($db);
1436
1437 my $file;
1438 my $filename = $schema->ddl_filename($db, $dir, $version);
1439 if(-e $filename)
1440 {
c9d2e0a2 1441 warn("$filename already exists, skipping $db");
b98d9e8a 1442 next unless ($preversion);
1443 } else {
1444 my $output = $sqlt->translate;
1445 if(!$output)
1446 {
1447 warn("Failed to translate to $db, skipping. (" . $sqlt->error . ")");
c9d2e0a2 1448 next;
b98d9e8a 1449 }
1450 if(!open($file, ">$filename"))
1451 {
1452 $self->throw_exception("Can't open $filename for writing ($!)");
1453 next;
1454 }
1455 print $file $output;
1456 close($file);
1457 }
c9d2e0a2 1458 if($preversion)
1459 {
40dce2a5 1460 require SQL::Translator::Diff;
c9d2e0a2 1461
1462 my $prefilename = $schema->ddl_filename($db, $dir, $preversion);
e2c0df8e 1463# print "Previous version $prefilename\n";
c9d2e0a2 1464 if(!-e $prefilename)
1465 {
1466 warn("No previous schema file found ($prefilename)");
1467 next;
1468 }
c9d2e0a2 1469
2dc2cd0f 1470 my $difffile = $schema->ddl_filename($db, $dir, $version, $preversion);
1471 print STDERR "Diff: $difffile: $db, $dir, $version, $preversion \n";
1472 if(-e $difffile)
1473 {
1474 warn("$difffile already exists, skipping");
1475 next;
1476 }
1477
b7e303a8 1478 my $source_schema;
1479 {
45f1a484 1480 my $t = SQL::Translator->new($sqltargs);
c9d2e0a2 1481 $t->debug( 0 );
1482 $t->trace( 0 );
b7e303a8 1483 $t->parser( $db ) or die $t->error;
45f1a484 1484 $t = $self->configure_sqlt($t, $db);
b7e303a8 1485 my $out = $t->translate( $prefilename ) or die $t->error;
1486 $source_schema = $t->schema;
1487 unless ( $source_schema->name ) {
1488 $source_schema->name( $prefilename );
c9d2e0a2 1489 }
b7e303a8 1490 }
c9d2e0a2 1491
2dc2cd0f 1492 # The "new" style of producers have sane normalization and can support
1493 # diffing a SQL file against a DBIC->SQLT schema. Old style ones don't
1494 # And we have to diff parsed SQL against parsed SQL.
1495 my $dest_schema = $sqlt_schema;
1496
3ce95357 1497 unless ( "SQL::Translator::Producer::$db"->can('preprocess_schema') ) {
45f1a484 1498 my $t = SQL::Translator->new($sqltargs);
2dc2cd0f 1499 $t->debug( 0 );
1500 $t->trace( 0 );
1501 $t->parser( $db ) or die $t->error;
45f1a484 1502 $t = $self->configure_sqlt($t, $db);
2dc2cd0f 1503 my $out = $t->translate( $filename ) or die $t->error;
1504 $dest_schema = $t->schema;
1505 $dest_schema->name( $filename )
1506 unless $dest_schema->name;
1507 }
c9d2e0a2 1508
1509 my $diff = SQL::Translator::Diff::schema_diff($source_schema, $db,
2dc2cd0f 1510 $dest_schema, $db,
45f1a484 1511 $sqltargs
c9d2e0a2 1512 );
c9d2e0a2 1513 if(!open $file, ">$difffile")
1514 {
1515 $self->throw_exception("Can't write to $difffile ($!)");
1516 next;
1517 }
1518 print $file $diff;
1519 close($file);
1520 }
e673f011 1521 }
c9d2e0a2 1522}
e673f011 1523
c9d2e0a2 1524sub configure_sqlt() {
1525 my $self = shift;
1526 my $tr = shift;
1527 my $db = shift || $self->sqlt_type;
1528 if ($db eq 'PostgreSQL') {
1529 $tr->quote_table_names(0);
1530 $tr->quote_field_names(0);
1531 }
1532 return $tr;
e673f011 1533}
1534
9b83fccd 1535=head2 deployment_statements
1536
d3b0e369 1537=over 4
1538
1539=item Arguments: $schema, $type, $version, $directory, $sqlt_args
1540
1541=back
1542
1543Returns the statements used by L</deploy> and L<DBIx::Class::Schema/deploy>.
1544The database driver name is given by C<$type>, though the value from
1545L</sqlt_type> is used if it is not specified.
1546
1547C<$directory> is used to return statements from files in a previously created
1548L</create_ddl_dir> directory and is optional. The filenames are constructed
1549from L<DBIx::Class::Schema/ddl_filename>, the schema name and the C<$version>.
1550
1551If no C<$directory> is specified then the statements are constructed on the
1552fly using L<SQL::Translator> and C<$version> is ignored.
1553
1554See L<SQL::Translator/METHODS> for a list of values for C<$sqlt_args>.
9b83fccd 1555
1556=cut
1557
e673f011 1558sub deployment_statements {
1559 my ($self, $schema, $type, $version, $dir, $sqltargs) = @_;
915919c5 1560 # Need to be connected to get the correct sqlt_type
c377d939 1561 $self->ensure_connected() unless $type;
e673f011 1562 $type ||= $self->sqlt_type;
1563 $version ||= $schema->VERSION || '1.x';
1564 $dir ||= './';
c9d2e0a2 1565 my $filename = $schema->ddl_filename($type, $dir, $version);
1566 if(-f $filename)
1567 {
1568 my $file;
1569 open($file, "<$filename")
1570 or $self->throw_exception("Can't open $filename ($!)");
1571 my @rows = <$file>;
1572 close($file);
1573 return join('', @rows);
1574 }
1575
b6d9f089 1576 $self->throw_exception(q{Can't deploy without SQL::Translator 0.09: '}
40dce2a5 1577 . $self->_check_sqlt_message . q{'})
1578 if !$self->_check_sqlt_version;
1579
1580 require SQL::Translator::Parser::DBIx::Class;
1581 eval qq{use SQL::Translator::Producer::${type}};
1582 $self->throw_exception($@) if $@;
1583
1584 # sources needs to be a parser arg, but for simplicty allow at top level
1585 # coming in
1586 $sqltargs->{parser_args}{sources} = delete $sqltargs->{sources}
1587 if exists $sqltargs->{sources};
1588
1589 my $tr = SQL::Translator->new(%$sqltargs);
1590 SQL::Translator::Parser::DBIx::Class::parse( $tr, $schema );
1591 return "SQL::Translator::Producer::${type}"->can('produce')->($tr);
e673f011 1592
c9d2e0a2 1593 return;
e673f011 1594
1c339d71 1595}
843f8ecd 1596
1c339d71 1597sub deploy {
260129d8 1598 my ($self, $schema, $type, $sqltargs, $dir) = @_;
1599 foreach my $statement ( $self->deployment_statements($schema, $type, undef, $dir, { no_comments => 1, %{ $sqltargs || {} } } ) ) {
61bf0de5 1600 foreach my $line ( split(";\n", $statement)) {
1601 next if($line =~ /^--/);
1602 next if(!$line);
1603# next if($line =~ /^DROP/m);
1604 next if($line =~ /^BEGIN TRANSACTION/m);
1605 next if($line =~ /^COMMIT/m);
1606 next if $line =~ /^\s+$/; # skip whitespace only
e5d9ee92 1607 $self->_query_start($line);
61bf0de5 1608 eval {
1609 $self->dbh->do($line); # shouldn't be using ->dbh ?
1610 };
1611 if ($@) {
1612 warn qq{$@ (running "${line}")};
1613 }
e5d9ee92 1614 $self->_query_end($line);
e4fe9ba3 1615 }
75d07914 1616 }
1c339d71 1617}
843f8ecd 1618
9b83fccd 1619=head2 datetime_parser
1620
1621Returns the datetime parser class
1622
1623=cut
1624
f86fcf0d 1625sub datetime_parser {
1626 my $self = shift;
114780ee 1627 return $self->{datetime_parser} ||= do {
1628 $self->ensure_connected;
1629 $self->build_datetime_parser(@_);
1630 };
f86fcf0d 1631}
1632
9b83fccd 1633=head2 datetime_parser_type
1634
1635Defines (returns) the datetime parser class - currently hardwired to
1636L<DateTime::Format::MySQL>
1637
1638=cut
1639
f86fcf0d 1640sub datetime_parser_type { "DateTime::Format::MySQL"; }
1641
9b83fccd 1642=head2 build_datetime_parser
1643
1644See L</datetime_parser>
1645
1646=cut
1647
f86fcf0d 1648sub build_datetime_parser {
1649 my $self = shift;
1650 my $type = $self->datetime_parser_type(@_);
1651 eval "use ${type}";
1652 $self->throw_exception("Couldn't load ${type}: $@") if $@;
1653 return $type;
1654}
1655
40dce2a5 1656{
1657 my $_check_sqlt_version; # private
1658 my $_check_sqlt_message; # private
1659 sub _check_sqlt_version {
1660 return $_check_sqlt_version if defined $_check_sqlt_version;
b6d9f089 1661 eval 'use SQL::Translator "0.09"';
b7e303a8 1662 $_check_sqlt_message = $@ || '';
1663 $_check_sqlt_version = !$@;
40dce2a5 1664 }
1665
1666 sub _check_sqlt_message {
1667 _check_sqlt_version if !defined $_check_sqlt_message;
1668 $_check_sqlt_message;
1669 }
1670}
1671
c756145c 1672sub DESTROY {
1673 my $self = shift;
f5de3933 1674 return if !$self->_dbh;
c756145c 1675 $self->_verify_pid;
1676 $self->_dbh(undef);
1677}
92925617 1678
8b445e33 16791;
1680
9b83fccd 1681=head1 SQL METHODS
1682
1683The module defines a set of methods within the DBIC::SQL::Abstract
1684namespace. These build on L<SQL::Abstract::Limit> to provide the
1685SQL query functions.
1686
1687The following methods are extended:-
1688
1689=over 4
1690
1691=item delete
1692
1693=item insert
1694
1695=item select
1696
1697=item update
1698
1699=item limit_dialect
1700
2cc3a7be 1701See L</connect_info> for details.
1702For setting, this method is deprecated in favor of L</connect_info>.
bb4f246d 1703
9b83fccd 1704=item quote_char
1705
2cc3a7be 1706See L</connect_info> for details.
1707For setting, this method is deprecated in favor of L</connect_info>.
bb4f246d 1708
9b83fccd 1709=item name_sep
1710
2cc3a7be 1711See L</connect_info> for details.
1712For setting, this method is deprecated in favor of L</connect_info>.
bb4f246d 1713
9b83fccd 1714=back
1715
8b445e33 1716=head1 AUTHORS
1717
daec44b8 1718Matt S. Trout <mst@shadowcatsystems.co.uk>
8b445e33 1719
9f19b1d6 1720Andy Grundman <andy@hybridized.org>
1721
8b445e33 1722=head1 LICENSE
1723
1724You may distribute this code under the same terms as Perl itself.
1725
1726=cut