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