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