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