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