further refinements to storage_exceptions
[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
56769f7c 467Execute the given subref with the underlying database handle as its
468first argument, using the new exception-based connection management.
469Example:
f11383c2 470
56769f7c 471 my @stuff = $schema->storage->dbh_do(
472 sub {
473 shift->selectrow_array("SELECT * FROM foo")
474 }
475 );
f11383c2 476
477=cut
478
479sub dbh_do {
480 my ($self, $todo) = @_;
481
482 my @result;
483 my $want_array = wantarray;
484
485 eval {
56769f7c 486 $self->_verify_pid if $self->_dbh;
f11383c2 487 $self->_populate_dbh if !$self->_dbh;
488 my $dbh = $self->_dbh;
489 local $dbh->{RaiseError} = 1;
490 local $dbh->{PrintError} = 0;
491 if($want_array) {
492 @result = $todo->($dbh);
493 }
56769f7c 494 elsif(defined $want_array) {
f11383c2 495 $result[0] = $todo->($dbh);
496 }
56769f7c 497 else {
498 $todo->($dbh);
499 }
f11383c2 500 };
56769f7c 501
f11383c2 502 if($@) {
503 my $exception = $@;
504 $self->connected
505 ? $self->throw_exception($exception)
506 : $self->_populate_dbh;
507
508 my $dbh = $self->_dbh;
509 local $dbh->{RaiseError} = 1;
510 local $dbh->{PrintError} = 0;
56769f7c 511 return $todo->($dbh);
f11383c2 512 }
56769f7c 513
f11383c2 514 return $want_array ? @result : $result[0];
515}
516
9b83fccd 517=head2 disconnect
518
519Disconnect the L<DBI> handle, performing a rollback first if the
520database is not in C<AutoCommit> mode.
521
522=cut
523
412db1f4 524sub disconnect {
525 my ($self) = @_;
526
92925617 527 if( $self->connected ) {
528 $self->_dbh->rollback unless $self->_dbh->{AutoCommit};
529 $self->_dbh->disconnect;
530 $self->_dbh(undef);
531 }
412db1f4 532}
533
9b83fccd 534=head2 connected
535
536Check if the L<DBI> handle is connected. Returns true if the handle
537is connected.
538
539=cut
540
f11383c2 541sub connected {
542 my ($self) = @_;
412db1f4 543
1346e22d 544 if(my $dbh = $self->_dbh) {
545 if(defined $self->_conn_tid && $self->_conn_tid != threads->tid) {
1346e22d 546 return $self->_dbh(undef);
547 }
56769f7c 548 else {
549 $self->_verify_pid;
550 }
1346e22d 551 return ($dbh->FETCH('Active') && $dbh->ping);
552 }
553
554 return 0;
412db1f4 555}
556
f11383c2 557# handle pid changes correctly
56769f7c 558# NOTE: assumes $self->_dbh is a valid $dbh
f11383c2 559sub _verify_pid {
560 my ($self) = @_;
561
56769f7c 562 return if $self->_conn_pid == $$;
f11383c2 563
f11383c2 564 $self->_dbh->{InactiveDestroy} = 1;
d3abf3fe 565 $self->_dbh(undef);
f11383c2 566
567 return;
568}
569
9b83fccd 570=head2 ensure_connected
571
572Check whether the database handle is connected - if not then make a
573connection.
574
575=cut
576
412db1f4 577sub ensure_connected {
578 my ($self) = @_;
579
580 unless ($self->connected) {
8b445e33 581 $self->_populate_dbh;
582 }
412db1f4 583}
584
c235bbae 585=head2 dbh
586
587Returns the dbh - a data base handle of class L<DBI>.
588
589=cut
590
412db1f4 591sub dbh {
592 my ($self) = @_;
593
594 $self->ensure_connected;
8b445e33 595 return $self->_dbh;
596}
597
f1f56aad 598sub _sql_maker_args {
599 my ($self) = @_;
600
2cc3a7be 601 return ( limit_dialect => $self->dbh, %{$self->_sql_maker_opts} );
f1f56aad 602}
603
9b83fccd 604=head2 sql_maker
605
606Returns a C<sql_maker> object - normally an object of class
607C<DBIC::SQL::Abstract>.
608
609=cut
610
48c69e7c 611sub sql_maker {
612 my ($self) = @_;
fdc1c3d0 613 unless ($self->_sql_maker) {
f1f56aad 614 $self->_sql_maker(new DBIC::SQL::Abstract( $self->_sql_maker_args ));
48c69e7c 615 }
616 return $self->_sql_maker;
617}
618
1b45b01e 619sub connect_info {
bb4f246d 620 my ($self, $info_arg) = @_;
621
f11383c2 622 return $self->_connect_info if !$info_arg;
623
624 # Kill sql_maker/_sql_maker_opts, so we get a fresh one with only
625 # the new set of options
626 $self->_sql_maker(undef);
627 $self->_sql_maker_opts({});
1b45b01e 628
f11383c2 629 my $info = [ @$info_arg ]; # copy because we can alter it
630 my $last_info = $info->[-1];
631 if(ref $last_info eq 'HASH') {
632 if(my $on_connect_do = delete $last_info->{on_connect_do}) {
633 $self->on_connect_do($on_connect_do);
634 }
635 for my $sql_maker_opt (qw/limit_dialect quote_char name_sep/) {
636 if(my $opt_val = delete $last_info->{$sql_maker_opt}) {
637 $self->_sql_maker_opts->{$sql_maker_opt} = $opt_val;
638 }
1b45b01e 639 }
640
f11383c2 641 # Get rid of any trailing empty hashref
642 pop(@$info) if !keys %$last_info;
bb4f246d 643 }
644
f11383c2 645 $self->_connect_info($info);
1b45b01e 646}
647
8b445e33 648sub _populate_dbh {
649 my ($self) = @_;
1b45b01e 650 my @info = @{$self->_connect_info || []};
8b445e33 651 $self->_dbh($self->_connect(@info));
2fd24e78 652
653 if(ref $self eq 'DBIx::Class::Storage::DBI') {
654 my $driver = $self->_dbh->{Driver}->{Name};
efe6365b 655 if ($self->load_optional_class("DBIx::Class::Storage::DBI::${driver}")) {
2fd24e78 656 bless $self, "DBIx::Class::Storage::DBI::${driver}";
657 $self->_rebless() if $self->can('_rebless');
658 }
843f8ecd 659 }
2fd24e78 660
d7c4c15c 661 # if on-connect sql statements are given execute them
662 foreach my $sql_statement (@{$self->on_connect_do || []}) {
4c248161 663 $self->debugobj->query_start($sql_statement) if $self->debug();
d7c4c15c 664 $self->_dbh->do($sql_statement);
4c248161 665 $self->debugobj->query_end($sql_statement) if $self->debug();
d7c4c15c 666 }
5ef3e508 667
1346e22d 668 $self->_conn_pid($$);
669 $self->_conn_tid(threads->tid) if $INC{'threads.pm'};
8b445e33 670}
671
672sub _connect {
673 my ($self, @info) = @_;
5ef3e508 674
9d31f7dc 675 $self->throw_exception("You failed to provide any connection info")
676 if !@info;
677
90ec6cad 678 my ($old_connect_via, $dbh);
679
5ef3e508 680 if ($INC{'Apache/DBI.pm'} && $ENV{MOD_PERL}) {
90ec6cad 681 $old_connect_via = $DBI::connect_via;
5ef3e508 682 $DBI::connect_via = 'connect';
5ef3e508 683 }
684
75db246c 685 eval {
bb4f246d 686 $dbh = ref $info[0] eq 'CODE'
687 ? &{$info[0]}
688 : DBI->connect(@info);
75db246c 689 };
90ec6cad 690
691 $DBI::connect_via = $old_connect_via if $old_connect_via;
692
75db246c 693 if (!$dbh || $@) {
694 $self->throw_exception("DBI Connection failed: " . ($@ || $DBI::errstr));
695 }
90ec6cad 696
e571e823 697 $dbh;
8b445e33 698}
699
8091aa91 700=head2 txn_begin
8b445e33 701
8091aa91 702Calls begin_work on the current dbh.
8b445e33 703
181a28f4 704See L<DBIx::Class::Schema> for the txn_do() method, which allows for
705an entire code block to be executed transactionally.
706
8b445e33 707=cut
708
8091aa91 709sub txn_begin {
d79f59b9 710 my $self = shift;
a32e8402 711 if ($self->{transaction_depth}++ == 0) {
f11383c2 712 $self->dbh_do(sub {
713 my $dbh = shift;
714 if ($dbh->{AutoCommit}) {
715 $self->debugobj->txn_begin()
716 if ($self->debug);
717 $dbh->begin_work;
718 }
719 });
986e4fca 720 }
8091aa91 721}
8b445e33 722
8091aa91 723=head2 txn_commit
8b445e33 724
8091aa91 725Issues a commit against the current dbh.
8b445e33 726
8091aa91 727=cut
728
729sub txn_commit {
d79f59b9 730 my $self = shift;
f11383c2 731 $self->dbh_do(sub {
732 my $dbh = shift;
733 if ($self->{transaction_depth} == 0) {
734 unless ($dbh->{AutoCommit}) {
735 $self->debugobj->txn_commit()
736 if ($self->debug);
737 $dbh->commit;
738 }
986e4fca 739 }
f11383c2 740 else {
741 if (--$self->{transaction_depth} == 0) {
742 $self->debugobj->txn_commit()
743 if ($self->debug);
744 $dbh->commit;
745 }
986e4fca 746 }
f11383c2 747 });
8091aa91 748}
749
750=head2 txn_rollback
751
181a28f4 752Issues a rollback against the current dbh. A nested rollback will
753throw a L<DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION> exception,
754which allows the rollback to propagate to the outermost transaction.
8b445e33 755
756=cut
757
8091aa91 758sub txn_rollback {
d79f59b9 759 my $self = shift;
a62cf8d4 760
761 eval {
f11383c2 762 $self->dbh_do(sub {
763 my $dbh = shift;
764 if ($self->{transaction_depth} == 0) {
765 unless ($dbh->{AutoCommit}) {
766 $self->debugobj->txn_rollback()
767 if ($self->debug);
768 $dbh->rollback;
769 }
986e4fca 770 }
771 else {
f11383c2 772 if (--$self->{transaction_depth} == 0) {
773 $self->debugobj->txn_rollback()
774 if ($self->debug);
775 $dbh->rollback;
776 }
777 else {
778 die DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION->new;
779 }
986e4fca 780 }
f11383c2 781 });
a62cf8d4 782 };
783
784 if ($@) {
785 my $error = $@;
786 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
787 $error =~ /$exception_class/ and $self->throw_exception($error);
788 $self->{transaction_depth} = 0; # ensure that a failed rollback
789 $self->throw_exception($error); # resets the transaction depth
8091aa91 790 }
791}
8b445e33 792
223b8fe3 793sub _execute {
794 my ($self, $op, $extra_bind, $ident, @args) = @_;
795 my ($sql, @bind) = $self->sql_maker->$op($ident, @args);
944f30bf 796 unshift(@bind, @$extra_bind) if $extra_bind;
f59ffc79 797 if ($self->debug) {
e673f011 798 my @debug_bind = map { defined $_ ? qq{'$_'} : q{'NULL'} } @bind;
4c248161 799 $self->debugobj->query_start($sql, @debug_bind);
f59ffc79 800 }
75db246c 801 my $sth = eval { $self->sth($sql,$op) };
802
803 if (!$sth || $@) {
ec0ff6f6 804 $self->throw_exception(
805 'no sth generated via sql (' . ($@ || $self->_dbh->errstr) . "): $sql"
806 );
75db246c 807 }
438adc0e 808 @bind = map { ref $_ ? ''.$_ : $_ } @bind; # stringify args
701da8c4 809 my $rv;
75d07914 810 if ($sth) {
4c248161 811 my $time = time();
95dad7e2 812 $rv = eval { $sth->execute(@bind) };
813
814 if ($@ || !$rv) {
815 $self->throw_exception("Error executing '$sql': ".($@ || $sth->errstr));
816 }
75d07914 817 } else {
1c339d71 818 $self->throw_exception("'$sql' did not generate a statement.");
701da8c4 819 }
4c248161 820 if ($self->debug) {
821 my @debug_bind = map { defined $_ ? qq{`$_'} : q{`NULL'} } @bind;
822 $self->debugobj->query_end($sql, @debug_bind);
823 }
223b8fe3 824 return (wantarray ? ($rv, $sth, @bind) : $rv);
825}
826
8b445e33 827sub insert {
828 my ($self, $ident, $to_insert) = @_;
bc0c9800 829 $self->throw_exception(
830 "Couldn't insert ".join(', ',
831 map "$_ => $to_insert->{$_}", keys %$to_insert
832 )." into ${ident}"
833 ) unless ($self->_execute('insert' => [], $ident, $to_insert));
8b445e33 834 return $to_insert;
835}
836
837sub update {
223b8fe3 838 return shift->_execute('update' => [], @_);
8b445e33 839}
840
841sub delete {
223b8fe3 842 return shift->_execute('delete' => [], @_);
8b445e33 843}
844
de705b51 845sub _select {
8b445e33 846 my ($self, $ident, $select, $condition, $attrs) = @_;
223b8fe3 847 my $order = $attrs->{order_by};
848 if (ref $condition eq 'SCALAR') {
849 $order = $1 if $$condition =~ s/ORDER BY (.*)$//i;
850 }
8839560b 851 if (exists $attrs->{group_by} || $attrs->{having}) {
bc0c9800 852 $order = {
853 group_by => $attrs->{group_by},
854 having => $attrs->{having},
855 ($order ? (order_by => $order) : ())
856 };
54540863 857 }
5c91499f 858 my @args = ('select', $attrs->{bind}, $ident, $select, $condition, $order);
9229f20a 859 if ($attrs->{software_limit} ||
860 $self->sql_maker->_default_limit_syntax eq "GenericSubQ") {
861 $attrs->{software_limit} = 1;
5c91499f 862 } else {
0823196c 863 $self->throw_exception("rows attribute must be positive if present")
864 if (defined($attrs->{rows}) && !($attrs->{rows} > 0));
5c91499f 865 push @args, $attrs->{rows}, $attrs->{offset};
866 }
de705b51 867 return $self->_execute(@args);
868}
869
9b83fccd 870=head2 select
871
872Handle a SQL select statement.
873
874=cut
875
de705b51 876sub select {
877 my $self = shift;
878 my ($ident, $select, $condition, $attrs) = @_;
cb5f2eea 879 return $self->cursor->new($self, \@_, $attrs);
8b445e33 880}
881
9b83fccd 882=head2 select_single
883
884Performs a select, fetch and return of data - handles a single row
885only.
886
887=cut
888
6157db4f 889# Need to call finish() to work round broken DBDs
890
1a14aa3f 891sub select_single {
de705b51 892 my $self = shift;
893 my ($rv, $sth, @bind) = $self->_select(@_);
6157db4f 894 my @row = $sth->fetchrow_array;
895 $sth->finish();
896 return @row;
1a14aa3f 897}
898
9b83fccd 899=head2 sth
900
901Returns a L<DBI> sth (statement handle) for the supplied SQL.
902
903=cut
904
8b445e33 905sub sth {
cb5f2eea 906 my ($self, $sql) = @_;
91fa659e 907 # 3 is the if_active parameter which avoids active sth re-use
f11383c2 908 return $self->dbh_do(sub { shift->prepare_cached($sql, {}, 3) });
8b445e33 909}
910
a953d8d9 911=head2 columns_info_for
912
913Returns database type info for a given table columns.
914
915=cut
916
917sub columns_info_for {
0d67fe74 918 my ($self, $table) = @_;
bfe10d87 919
56769f7c 920 $self->dbh_do(sub {
921 my $dbh = shift;
922
923 if ($dbh->can('column_info')) {
924 my %result;
925 eval {
926 my ($schema,$tab) = $table =~ /^(.+?)\.(.+)$/ ? ($1,$2) : (undef,$table);
927 my $sth = $dbh->column_info( undef,$schema, $tab, '%' );
928 $sth->execute();
929 while ( my $info = $sth->fetchrow_hashref() ){
930 my %column_info;
931 $column_info{data_type} = $info->{TYPE_NAME};
932 $column_info{size} = $info->{COLUMN_SIZE};
933 $column_info{is_nullable} = $info->{NULLABLE} ? 1 : 0;
934 $column_info{default_value} = $info->{COLUMN_DEF};
935 my $col_name = $info->{COLUMN_NAME};
936 $col_name =~ s/^\"(.*)\"$/$1/;
937
938 $result{$col_name} = \%column_info;
939 }
940 };
941 return \%result if !$@;
942 }
a32e8402 943
a953d8d9 944 my %result;
56769f7c 945 my $sth = $dbh->prepare("SELECT * FROM $table WHERE 1=0");
946 $sth->execute;
947 my @columns = @{$sth->{NAME_lc}};
948 for my $i ( 0 .. $#columns ){
949 my %column_info;
950 my $type_num = $sth->{TYPE}->[$i];
951 my $type_name;
952 if(defined $type_num && $dbh->can('type_info')) {
953 my $type_info = $dbh->type_info($type_num);
954 $type_name = $type_info->{TYPE_NAME} if $type_info;
0d67fe74 955 }
56769f7c 956 $column_info{data_type} = $type_name ? $type_name : $type_num;
957 $column_info{size} = $sth->{PRECISION}->[$i];
958 $column_info{is_nullable} = $sth->{NULLABLE}->[$i] ? 1 : 0;
0d67fe74 959
56769f7c 960 if ($column_info{data_type} =~ m/^(.*?)\((.*?)\)$/) {
961 $column_info{data_type} = $1;
962 $column_info{size} = $2;
963 }
0d67fe74 964
56769f7c 965 $result{$columns[$i]} = \%column_info;
0d67fe74 966 }
967
56769f7c 968 return \%result;
969 });
a953d8d9 970}
971
9b83fccd 972=head2 last_insert_id
973
974Return the row id of the last insert.
975
976=cut
977
843f8ecd 978sub last_insert_id {
979 my ($self, $row) = @_;
980
f11383c2 981 $self->dbh_do(sub { shift->func('last_insert_rowid') });
843f8ecd 982}
983
9b83fccd 984=head2 sqlt_type
985
986Returns the database driver name.
987
988=cut
989
f11383c2 990sub sqlt_type { shift->dbh_do(sub { shift->{Driver}->{Name} }) }
1c339d71 991
9b83fccd 992=head2 create_ddl_dir (EXPERIMENTAL)
993
994=over 4
995
996=item Arguments: $schema \@databases, $version, $directory, $sqlt_args
997
998=back
999
1000Creates an SQL file based on the Schema, for each of the specified
1001database types, in the given directory.
1002
1003Note that this feature is currently EXPERIMENTAL and may not work correctly
1004across all databases, or fully handle complex relationships.
1005
1006=cut
1007
e673f011 1008sub create_ddl_dir
1009{
1010 my ($self, $schema, $databases, $version, $dir, $sqltargs) = @_;
1011
1012 if(!$dir || !-d $dir)
1013 {
1014 warn "No directory given, using ./\n";
1015 $dir = "./";
1016 }
1017 $databases ||= ['MySQL', 'SQLite', 'PostgreSQL'];
1018 $databases = [ $databases ] if(ref($databases) ne 'ARRAY');
1019 $version ||= $schema->VERSION || '1.x';
9e7b9292 1020 $sqltargs = { ( add_drop_table => 1 ), %{$sqltargs || {}} };
e673f011 1021
1c339d71 1022 eval "use SQL::Translator";
1023 $self->throw_exception("Can't deploy without SQL::Translator: $@") if $@;
e673f011 1024
9e7b9292 1025 my $sqlt = SQL::Translator->new($sqltargs);
e673f011 1026 foreach my $db (@$databases)
1027 {
1028 $sqlt->reset();
1029 $sqlt->parser('SQL::Translator::Parser::DBIx::Class');
1030# $sqlt->parser_args({'DBIx::Class' => $schema);
1031 $sqlt->data($schema);
1032 $sqlt->producer($db);
1033
1034 my $file;
1035 my $filename = $schema->ddl_filename($db, $dir, $version);
1036 if(-e $filename)
1037 {
1038 $self->throw_exception("$filename already exists, skipping $db");
1039 next;
1040 }
1041 open($file, ">$filename")
1042 or $self->throw_exception("Can't open $filename for writing ($!)");
1043 my $output = $sqlt->translate;
1044#use Data::Dumper;
1045# print join(":", keys %{$schema->source_registrations});
1046# print Dumper($sqlt->schema);
1047 if(!$output)
1048 {
1049 $self->throw_exception("Failed to translate to $db. (" . $sqlt->error . ")");
1050 next;
1051 }
1052 print $file $output;
1053 close($file);
1054 }
1055
1056}
1057
9b83fccd 1058=head2 deployment_statements
1059
1060Create the statements for L</deploy> and
1061L<DBIx::Class::Schema/deploy>.
1062
1063=cut
1064
e673f011 1065sub deployment_statements {
1066 my ($self, $schema, $type, $version, $dir, $sqltargs) = @_;
915919c5 1067 # Need to be connected to get the correct sqlt_type
c377d939 1068 $self->ensure_connected() unless $type;
e673f011 1069 $type ||= $self->sqlt_type;
1070 $version ||= $schema->VERSION || '1.x';
1071 $dir ||= './';
0382d607 1072 eval "use SQL::Translator";
1073 if(!$@)
1074 {
1075 eval "use SQL::Translator::Parser::DBIx::Class;";
1076 $self->throw_exception($@) if $@;
1077 eval "use SQL::Translator::Producer::${type};";
1078 $self->throw_exception($@) if $@;
1079 my $tr = SQL::Translator->new(%$sqltargs);
1080 SQL::Translator::Parser::DBIx::Class::parse( $tr, $schema );
1081 return "SQL::Translator::Producer::${type}"->can('produce')->($tr);
1082 }
e673f011 1083
1084 my $filename = $schema->ddl_filename($type, $dir, $version);
1085 if(!-f $filename)
1086 {
0382d607 1087# $schema->create_ddl_dir([ $type ], $version, $dir, $sqltargs);
1088 $self->throw_exception("No SQL::Translator, and no Schema file found, aborting deploy");
1089 return;
e673f011 1090 }
1091 my $file;
1092 open($file, "<$filename")
1093 or $self->throw_exception("Can't open $filename ($!)");
1094 my @rows = <$file>;
1095 close($file);
1096
1097 return join('', @rows);
1098
1c339d71 1099}
843f8ecd 1100
9b83fccd 1101=head2 deploy
1102
1103Sends the appropriate statements to create or modify tables to the
1104db. This would normally be called through
1105L<DBIx::Class::Schema/deploy>.
1106
1107=cut
1108
1c339d71 1109sub deploy {
cb561d1a 1110 my ($self, $schema, $type, $sqltargs) = @_;
9e7b9292 1111 foreach my $statement ( $self->deployment_statements($schema, $type, undef, undef, { no_comments => 1, %{ $sqltargs || {} } } ) ) {
e4fe9ba3 1112 for ( split(";\n", $statement)) {
e673f011 1113 next if($_ =~ /^--/);
1114 next if(!$_);
1115# next if($_ =~ /^DROP/m);
1116 next if($_ =~ /^BEGIN TRANSACTION/m);
1117 next if($_ =~ /^COMMIT/m);
b489f68a 1118 next if $_ =~ /^\s+$/; # skip whitespace only
bdea30e3 1119 $self->debugobj->query_start($_) if $self->debug;
f11383c2 1120 $self->dbh->do($_) or warn "SQL was:\n $_"; # XXX exceptions?
4c248161 1121 $self->debugobj->query_end($_) if $self->debug;
e4fe9ba3 1122 }
75d07914 1123 }
1c339d71 1124}
843f8ecd 1125
9b83fccd 1126=head2 datetime_parser
1127
1128Returns the datetime parser class
1129
1130=cut
1131
f86fcf0d 1132sub datetime_parser {
1133 my $self = shift;
1134 return $self->{datetime_parser} ||= $self->build_datetime_parser(@_);
1135}
1136
9b83fccd 1137=head2 datetime_parser_type
1138
1139Defines (returns) the datetime parser class - currently hardwired to
1140L<DateTime::Format::MySQL>
1141
1142=cut
1143
f86fcf0d 1144sub datetime_parser_type { "DateTime::Format::MySQL"; }
1145
9b83fccd 1146=head2 build_datetime_parser
1147
1148See L</datetime_parser>
1149
1150=cut
1151
f86fcf0d 1152sub build_datetime_parser {
1153 my $self = shift;
1154 my $type = $self->datetime_parser_type(@_);
1155 eval "use ${type}";
1156 $self->throw_exception("Couldn't load ${type}: $@") if $@;
1157 return $type;
1158}
1159
a9f32dbc 1160sub DESTROY { shift->_dbh(undef) }
92925617 1161
8b445e33 11621;
1163
9b83fccd 1164=head1 SQL METHODS
1165
1166The module defines a set of methods within the DBIC::SQL::Abstract
1167namespace. These build on L<SQL::Abstract::Limit> to provide the
1168SQL query functions.
1169
1170The following methods are extended:-
1171
1172=over 4
1173
1174=item delete
1175
1176=item insert
1177
1178=item select
1179
1180=item update
1181
1182=item limit_dialect
1183
2cc3a7be 1184See L</connect_info> for details.
1185For setting, this method is deprecated in favor of L</connect_info>.
bb4f246d 1186
9b83fccd 1187=item quote_char
1188
2cc3a7be 1189See L</connect_info> for details.
1190For setting, this method is deprecated in favor of L</connect_info>.
bb4f246d 1191
9b83fccd 1192=item name_sep
1193
2cc3a7be 1194See L</connect_info> for details.
1195For setting, this method is deprecated in favor of L</connect_info>.
bb4f246d 1196
9b83fccd 1197=back
1198
92b858c9 1199=head1 ENVIRONMENT VARIABLES
1200
6fe735fa 1201=head2 DBIC_TRACE
92b858c9 1202
6fe735fa 1203If C<DBIC_TRACE> is set then SQL trace information
92b858c9 1204is produced (as when the L<debug> method is set).
1205
1206If the value is of the form C<1=/path/name> then the trace output is
1207written to the file C</path/name>.
1208
d1cceec4 1209This environment variable is checked when the storage object is first
1210created (when you call connect on your schema). So, run-time changes
1211to this environment variable will not take effect unless you also
1212re-connect on your schema.
1213
6fe735fa 1214=head2 DBIX_CLASS_STORAGE_DBI_DEBUG
1215
1216Old name for DBIC_TRACE
1217
8b445e33 1218=head1 AUTHORS
1219
daec44b8 1220Matt S. Trout <mst@shadowcatsystems.co.uk>
8b445e33 1221
9f19b1d6 1222Andy Grundman <andy@hybridized.org>
1223
8b445e33 1224=head1 LICENSE
1225
1226You may distribute this code under the same terms as Perl itself.
1227
1228=cut
1229