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