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