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