tests are a mess, but Versioned.pm should work now
[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
57c18b65 17 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
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
61646ebd 383=item unsafe
384
385This Storage driver normally installs its own C<HandleError>, sets
2ab60eb9 386C<RaiseError> and C<ShowErrorStatement> on, and sets C<PrintError> off on
387all database handles, including those supplied by a coderef. It does this
388so that it can have consistent and useful error behavior.
61646ebd 389
390If you set this option to a true value, Storage will not do its usual
2ab60eb9 391modifications to the database handle's attributes, and instead relies on
392the settings in your connect_info DBI options (or the values you set in
393your connection coderef, in the case that you are connecting via coderef).
61646ebd 394
395Note that your custom settings can cause Storage to malfunction,
396especially if you set a C<HandleError> handler that suppresses exceptions
397and/or disable C<RaiseError>.
398
2cc3a7be 399=back
400
401These options can be mixed in with your other L<DBI> connection attributes,
402or placed in a seperate hashref after all other normal L<DBI> connection
403arguments.
404
405Every time C<connect_info> is invoked, any previous settings for
406these options will be cleared before setting the new ones, regardless of
407whether any options are specified in the new C<connect_info>.
408
77d76d0f 409Another Important Note:
410
411DBIC can do some wonderful magic with handling exceptions,
412disconnections, and transactions when you use C<AutoCommit =&gt; 1>
413combined with C<txn_do> for transaction support.
414
415If you set C<AutoCommit =&gt; 0> in your connect info, then you are always
416in an assumed transaction between commits, and you're telling us you'd
417like to manage that manually. A lot of DBIC's magic protections
418go away. We can't protect you from exceptions due to database
419disconnects because we don't know anything about how to restart your
420transactions. You're on your own for handling all sorts of exceptional
421cases if you choose the C<AutoCommit =&gt 0> path, just as you would
422be with raw DBI.
423
2cc3a7be 424Examples:
425
426 # Simple SQLite connection
bb4f246d 427 ->connect_info([ 'dbi:SQLite:./foo.db' ]);
6789ebe3 428
2cc3a7be 429 # Connect via subref
bb4f246d 430 ->connect_info([ sub { DBI->connect(...) } ]);
6789ebe3 431
2cc3a7be 432 # A bit more complicated
bb4f246d 433 ->connect_info(
434 [
435 'dbi:Pg:dbname=foo',
436 'postgres',
437 'my_pg_password',
77d76d0f 438 { AutoCommit => 1 },
2cc3a7be 439 { quote_char => q{"}, name_sep => q{.} },
440 ]
441 );
442
443 # Equivalent to the previous example
444 ->connect_info(
445 [
446 'dbi:Pg:dbname=foo',
447 'postgres',
448 'my_pg_password',
77d76d0f 449 { AutoCommit => 1, quote_char => q{"}, name_sep => q{.} },
bb4f246d 450 ]
451 );
6789ebe3 452
2cc3a7be 453 # Subref + DBIC-specific connection options
bb4f246d 454 ->connect_info(
455 [
456 sub { DBI->connect(...) },
2cc3a7be 457 {
458 quote_char => q{`},
459 name_sep => q{@},
460 on_connect_do => ['SET search_path TO myschema,otherschema,public'],
b33697ef 461 disable_sth_caching => 1,
2cc3a7be 462 },
bb4f246d 463 ]
464 );
6789ebe3 465
004d31fb 466=cut
467
046ad905 468sub connect_info {
469 my ($self, $info_arg) = @_;
4c248161 470
046ad905 471 return $self->_connect_info if !$info_arg;
4c248161 472
046ad905 473 # Kill sql_maker/_sql_maker_opts, so we get a fresh one with only
474 # the new set of options
475 $self->_sql_maker(undef);
476 $self->_sql_maker_opts({});
fdad5fab 477 $self->_connect_info([@$info_arg]); # copy for _connect_info
486ad69b 478
fdad5fab 479 my $dbi_info = [@$info_arg]; # copy for _dbi_connect_info
8df3d107 480
541df64a 481 my $last_info = $dbi_info->[-1];
046ad905 482 if(ref $last_info eq 'HASH') {
9a0891be 483 $last_info = { %$last_info }; # so delete is non-destructive
7f3655d4 484 for my $storage_opt (
485 qw/on_connect_do disable_sth_caching unsafe cursor_class/
486 ) {
b33697ef 487 if(my $value = delete $last_info->{$storage_opt}) {
488 $self->$storage_opt($value);
489 }
046ad905 490 }
491 for my $sql_maker_opt (qw/limit_dialect quote_char name_sep/) {
492 if(my $opt_val = delete $last_info->{$sql_maker_opt}) {
493 $self->_sql_maker_opts->{$sql_maker_opt} = $opt_val;
494 }
495 }
9a0891be 496 # re-insert modified hashref
497 $dbi_info->[-1] = $last_info;
486ad69b 498
046ad905 499 # Get rid of any trailing empty hashref
541df64a 500 pop(@$dbi_info) if !keys %$last_info;
046ad905 501 }
fdad5fab 502 $self->_dbi_connect_info($dbi_info);
d7c4c15c 503
fdad5fab 504 $self->_connect_info;
046ad905 505}
004d31fb 506
046ad905 507=head2 on_connect_do
4c248161 508
046ad905 509This method is deprecated in favor of setting via L</connect_info>.
486ad69b 510
f11383c2 511=head2 dbh_do
512
046ad905 513Arguments: $subref, @extra_coderef_args?
514
d4f16b21 515Execute the given subref using the new exception-based connection management.
046ad905 516
d4f16b21 517The first two arguments will be the storage object that C<dbh_do> was called
518on and a database handle to use. Any additional arguments will be passed
519verbatim to the called subref as arguments 2 and onwards.
520
521Using this (instead of $self->_dbh or $self->dbh) ensures correct
522exception handling and reconnection (or failover in future subclasses).
523
524Your subref should have no side-effects outside of the database, as
525there is the potential for your subref to be partially double-executed
526if the database connection was stale/dysfunctional.
046ad905 527
56769f7c 528Example:
f11383c2 529
56769f7c 530 my @stuff = $schema->storage->dbh_do(
531 sub {
d4f16b21 532 my ($storage, $dbh, @cols) = @_;
533 my $cols = join(q{, }, @cols);
534 $dbh->selectrow_array("SELECT $cols FROM foo");
046ad905 535 },
536 @column_list
56769f7c 537 );
f11383c2 538
539=cut
540
541sub dbh_do {
046ad905 542 my $self = shift;
aa27edf7 543 my $coderef = shift;
544
aa27edf7 545 ref $coderef eq 'CODE' or $self->throw_exception
546 ('$coderef must be a CODE reference');
f11383c2 547
cb19f4dd 548 return $coderef->($self, $self->_dbh, @_) if $self->{_in_dbh_do}
549 || $self->{transaction_depth};
550
1b994857 551 local $self->{_in_dbh_do} = 1;
552
f11383c2 553 my @result;
554 my $want_array = wantarray;
555
556 eval {
56769f7c 557 $self->_verify_pid if $self->_dbh;
f11383c2 558 $self->_populate_dbh if !$self->_dbh;
f11383c2 559 if($want_array) {
d4f16b21 560 @result = $coderef->($self, $self->_dbh, @_);
f11383c2 561 }
56769f7c 562 elsif(defined $want_array) {
d4f16b21 563 $result[0] = $coderef->($self, $self->_dbh, @_);
f11383c2 564 }
56769f7c 565 else {
d4f16b21 566 $coderef->($self, $self->_dbh, @_);
56769f7c 567 }
f11383c2 568 };
56769f7c 569
aa27edf7 570 my $exception = $@;
571 if(!$exception) { return $want_array ? @result : $result[0] }
572
573 $self->throw_exception($exception) if $self->connected;
574
575 # We were not connected - reconnect and retry, but let any
576 # exception fall right through this time
577 $self->_populate_dbh;
d4f16b21 578 $coderef->($self, $self->_dbh, @_);
aa27edf7 579}
580
581# This is basically a blend of dbh_do above and DBIx::Class::Storage::txn_do.
582# It also informs dbh_do to bypass itself while under the direction of txn_do,
1b994857 583# via $self->{_in_dbh_do} (this saves some redundant eval and errorcheck, etc)
aa27edf7 584sub txn_do {
585 my $self = shift;
586 my $coderef = shift;
587
588 ref $coderef eq 'CODE' or $self->throw_exception
589 ('$coderef must be a CODE reference');
590
57c18b65 591 return $coderef->(@_) if $self->{transaction_depth};
592
1b994857 593 local $self->{_in_dbh_do} = 1;
f11383c2 594
aa27edf7 595 my @result;
596 my $want_array = wantarray;
597
d4f16b21 598 my $tried = 0;
599 while(1) {
600 eval {
601 $self->_verify_pid if $self->_dbh;
602 $self->_populate_dbh if !$self->_dbh;
aa27edf7 603
d4f16b21 604 $self->txn_begin;
605 if($want_array) {
606 @result = $coderef->(@_);
607 }
608 elsif(defined $want_array) {
609 $result[0] = $coderef->(@_);
610 }
611 else {
612 $coderef->(@_);
613 }
614 $self->txn_commit;
615 };
aa27edf7 616
d4f16b21 617 my $exception = $@;
618 if(!$exception) { return $want_array ? @result : $result[0] }
619
620 if($tried++ > 0 || $self->connected) {
621 eval { $self->txn_rollback };
622 my $rollback_exception = $@;
623 if($rollback_exception) {
624 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
625 $self->throw_exception($exception) # propagate nested rollback
626 if $rollback_exception =~ /$exception_class/;
627
628 $self->throw_exception(
629 "Transaction aborted: ${exception}. "
630 . "Rollback failed: ${rollback_exception}"
631 );
632 }
633 $self->throw_exception($exception)
aa27edf7 634 }
56769f7c 635
d4f16b21 636 # We were not connected, and was first try - reconnect and retry
637 # via the while loop
638 $self->_populate_dbh;
639 }
f11383c2 640}
641
9b83fccd 642=head2 disconnect
643
046ad905 644Our C<disconnect> method also performs a rollback first if the
9b83fccd 645database is not in C<AutoCommit> mode.
646
647=cut
648
412db1f4 649sub disconnect {
650 my ($self) = @_;
651
92925617 652 if( $self->connected ) {
57c18b65 653 $self->_dbh->rollback unless $self->_dbh_autocommit;
92925617 654 $self->_dbh->disconnect;
655 $self->_dbh(undef);
dbaee748 656 $self->{_dbh_gen}++;
92925617 657 }
412db1f4 658}
659
f11383c2 660sub connected {
661 my ($self) = @_;
412db1f4 662
1346e22d 663 if(my $dbh = $self->_dbh) {
664 if(defined $self->_conn_tid && $self->_conn_tid != threads->tid) {
dbaee748 665 $self->_dbh(undef);
666 $self->{_dbh_gen}++;
667 return;
1346e22d 668 }
56769f7c 669 else {
670 $self->_verify_pid;
649bfb8c 671 return 0 if !$self->_dbh;
56769f7c 672 }
1346e22d 673 return ($dbh->FETCH('Active') && $dbh->ping);
674 }
675
676 return 0;
412db1f4 677}
678
f11383c2 679# handle pid changes correctly
56769f7c 680# NOTE: assumes $self->_dbh is a valid $dbh
f11383c2 681sub _verify_pid {
682 my ($self) = @_;
683
56769f7c 684 return if $self->_conn_pid == $$;
f11383c2 685
f11383c2 686 $self->_dbh->{InactiveDestroy} = 1;
d3abf3fe 687 $self->_dbh(undef);
dbaee748 688 $self->{_dbh_gen}++;
f11383c2 689
690 return;
691}
692
412db1f4 693sub ensure_connected {
694 my ($self) = @_;
695
696 unless ($self->connected) {
8b445e33 697 $self->_populate_dbh;
698 }
412db1f4 699}
700
c235bbae 701=head2 dbh
702
703Returns the dbh - a data base handle of class L<DBI>.
704
705=cut
706
412db1f4 707sub dbh {
708 my ($self) = @_;
709
710 $self->ensure_connected;
8b445e33 711 return $self->_dbh;
712}
713
f1f56aad 714sub _sql_maker_args {
715 my ($self) = @_;
716
6e399b4f 717 return ( bindtype=>'columns', limit_dialect => $self->dbh, %{$self->_sql_maker_opts} );
f1f56aad 718}
719
48c69e7c 720sub sql_maker {
721 my ($self) = @_;
fdc1c3d0 722 unless ($self->_sql_maker) {
f1f56aad 723 $self->_sql_maker(new DBIC::SQL::Abstract( $self->_sql_maker_args ));
48c69e7c 724 }
725 return $self->_sql_maker;
726}
727
8b445e33 728sub _populate_dbh {
729 my ($self) = @_;
7e47ea83 730 my @info = @{$self->_dbi_connect_info || []};
8b445e33 731 $self->_dbh($self->_connect(@info));
2fd24e78 732
77d76d0f 733 # Always set the transaction depth on connect, since
734 # there is no transaction in progress by definition
57c18b65 735 $self->{transaction_depth} = $self->_dbh_autocommit ? 0 : 1;
77d76d0f 736
2fd24e78 737 if(ref $self eq 'DBIx::Class::Storage::DBI') {
738 my $driver = $self->_dbh->{Driver}->{Name};
efe6365b 739 if ($self->load_optional_class("DBIx::Class::Storage::DBI::${driver}")) {
2fd24e78 740 bless $self, "DBIx::Class::Storage::DBI::${driver}";
741 $self->_rebless() if $self->can('_rebless');
742 }
843f8ecd 743 }
2fd24e78 744
d7c4c15c 745 # if on-connect sql statements are given execute them
746 foreach my $sql_statement (@{$self->on_connect_do || []}) {
e5d9ee92 747 $self->_query_start($sql_statement);
d7c4c15c 748 $self->_dbh->do($sql_statement);
e5d9ee92 749 $self->_query_end($sql_statement);
d7c4c15c 750 }
5ef3e508 751
1346e22d 752 $self->_conn_pid($$);
753 $self->_conn_tid(threads->tid) if $INC{'threads.pm'};
8b445e33 754}
755
756sub _connect {
757 my ($self, @info) = @_;
5ef3e508 758
9d31f7dc 759 $self->throw_exception("You failed to provide any connection info")
61646ebd 760 if !@info;
9d31f7dc 761
90ec6cad 762 my ($old_connect_via, $dbh);
763
5ef3e508 764 if ($INC{'Apache/DBI.pm'} && $ENV{MOD_PERL}) {
61646ebd 765 $old_connect_via = $DBI::connect_via;
766 $DBI::connect_via = 'connect';
5ef3e508 767 }
768
75db246c 769 eval {
f5de3933 770 if(ref $info[0] eq 'CODE') {
771 $dbh = &{$info[0]}
772 }
773 else {
774 $dbh = DBI->connect(@info);
61646ebd 775 }
776
e7827df0 777 if($dbh && !$self->unsafe) {
664612fb 778 my $weak_self = $self;
779 weaken($weak_self);
61646ebd 780 $dbh->{HandleError} = sub {
664612fb 781 $weak_self->throw_exception("DBI Exception: $_[0]")
61646ebd 782 };
2ab60eb9 783 $dbh->{ShowErrorStatement} = 1;
61646ebd 784 $dbh->{RaiseError} = 1;
785 $dbh->{PrintError} = 0;
f5de3933 786 }
75db246c 787 };
90ec6cad 788
789 $DBI::connect_via = $old_connect_via if $old_connect_via;
790
d92a4015 791 $self->throw_exception("DBI Connection failed: " . ($@||$DBI::errstr))
792 if !$dbh || $@;
90ec6cad 793
57c18b65 794 $self->_dbh_autocommit($dbh->{AutoCommit});
795
e571e823 796 $dbh;
8b445e33 797}
798
d32d82f9 799
8091aa91 800sub txn_begin {
d79f59b9 801 my $self = shift;
291bf95f 802 $self->ensure_connected();
57c18b65 803 if($self->{transaction_depth} == 0) {
77d76d0f 804 $self->debugobj->txn_begin()
805 if $self->debug;
806 # this isn't ->_dbh-> because
807 # we should reconnect on begin_work
808 # for AutoCommit users
809 $self->dbh->begin_work;
986e4fca 810 }
57c18b65 811 $self->{transaction_depth}++;
8091aa91 812}
8b445e33 813
8091aa91 814sub txn_commit {
d79f59b9 815 my $self = shift;
77d76d0f 816 if ($self->{transaction_depth} == 1) {
817 my $dbh = $self->_dbh;
818 $self->debugobj->txn_commit()
819 if ($self->debug);
820 $dbh->commit;
821 $self->{transaction_depth} = 0
57c18b65 822 if $self->_dbh_autocommit;
77d76d0f 823 }
824 elsif($self->{transaction_depth} > 1) {
825 $self->{transaction_depth}--
826 }
d32d82f9 827}
828
77d76d0f 829sub txn_rollback {
830 my $self = shift;
831 my $dbh = $self->_dbh;
77d76d0f 832 eval {
77d76d0f 833 if ($self->{transaction_depth} == 1) {
d32d82f9 834 $self->debugobj->txn_rollback()
835 if ($self->debug);
77d76d0f 836 $self->{transaction_depth} = 0
57c18b65 837 if $self->_dbh_autocommit;
838 $dbh->rollback;
d32d82f9 839 }
77d76d0f 840 elsif($self->{transaction_depth} > 1) {
841 $self->{transaction_depth}--;
986e4fca 842 }
f11383c2 843 else {
d32d82f9 844 die DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION->new;
986e4fca 845 }
77d76d0f 846 };
a62cf8d4 847 if ($@) {
848 my $error = $@;
849 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
850 $error =~ /$exception_class/ and $self->throw_exception($error);
77d76d0f 851 # ensure that a failed rollback resets the transaction depth
57c18b65 852 $self->{transaction_depth} = $self->_dbh_autocommit ? 0 : 1;
77d76d0f 853 $self->throw_exception($error);
8091aa91 854 }
855}
8b445e33 856
b7151206 857# This used to be the top-half of _execute. It was split out to make it
858# easier to override in NoBindVars without duping the rest. It takes up
859# all of _execute's args, and emits $sql, @bind.
860sub _prep_for_execute {
d944c5ae 861 my ($self, $op, $extra_bind, $ident, $args) = @_;
b7151206 862
d944c5ae 863 my ($sql, @bind) = $self->sql_maker->$op($ident, @$args);
db4b5f11 864 unshift(@bind,
865 map { ref $_ eq 'ARRAY' ? $_ : [ '!!dummy', $_ ] } @$extra_bind)
866 if $extra_bind;
b7151206 867
d944c5ae 868 return ($sql, \@bind);
b7151206 869}
870
e5d9ee92 871sub _fix_bind_params {
872 my ($self, @bind) = @_;
873
874 ### Turn @bind from something like this:
875 ### ( [ "artist", 1 ], [ "cdid", 1, 3 ] )
876 ### to this:
877 ### ( "'1'", "'1'", "'3'" )
878 return
879 map {
880 if ( defined( $_ && $_->[1] ) ) {
881 map { qq{'$_'}; } @{$_}[ 1 .. $#$_ ];
882 }
883 else { q{'NULL'}; }
884 } @bind;
885}
886
887sub _query_start {
888 my ( $self, $sql, @bind ) = @_;
889
890 if ( $self->debug ) {
891 @bind = $self->_fix_bind_params(@bind);
892 $self->debugobj->query_start( $sql, @bind );
893 }
894}
895
896sub _query_end {
897 my ( $self, $sql, @bind ) = @_;
898
899 if ( $self->debug ) {
900 @bind = $self->_fix_bind_params(@bind);
901 $self->debugobj->query_end( $sql, @bind );
902 }
903}
904
baa31d2f 905sub _dbh_execute {
906 my ($self, $dbh, $op, $extra_bind, $ident, $bind_attributes, @args) = @_;
7af8b477 907
eda28767 908 if( blessed($ident) && $ident->isa("DBIx::Class::ResultSource") ) {
b7ce6568 909 $ident = $ident->from();
910 }
d944c5ae 911
912 my ($sql, $bind) = $self->_prep_for_execute($op, $extra_bind, $ident, \@args);
d92a4015 913
e5d9ee92 914 $self->_query_start( $sql, @$bind );
95dad7e2 915
61646ebd 916 my $sth = $self->sth($sql,$op);
6e399b4f 917
61646ebd 918 my $placeholder_index = 1;
6e399b4f 919
61646ebd 920 foreach my $bound (@$bind) {
921 my $attributes = {};
922 my($column_name, @data) = @$bound;
6e399b4f 923
61646ebd 924 if ($bind_attributes) {
925 $attributes = $bind_attributes->{$column_name}
926 if defined $bind_attributes->{$column_name};
927 }
6e399b4f 928
61646ebd 929 foreach my $data (@data) {
930 $data = ref $data ? ''.$data : $data; # stringify args
0b5dee17 931
61646ebd 932 $sth->bind_param($placeholder_index, $data, $attributes);
933 $placeholder_index++;
95dad7e2 934 }
61646ebd 935 }
d92a4015 936
61646ebd 937 # Can this fail without throwing an exception anyways???
938 my $rv = $sth->execute();
939 $self->throw_exception($sth->errstr) if !$rv;
d92a4015 940
e5d9ee92 941 $self->_query_end( $sql, @$bind );
baa31d2f 942
d944c5ae 943 return (wantarray ? ($rv, $sth, @$bind) : $rv);
223b8fe3 944}
945
baa31d2f 946sub _execute {
947 my $self = shift;
948 $self->dbh_do($self->can('_dbh_execute'), @_)
949}
950
8b445e33 951sub insert {
7af8b477 952 my ($self, $source, $to_insert) = @_;
953
954 my $ident = $source->from;
8b646589 955 my $bind_attributes = $self->source_bind_attributes($source);
956
61646ebd 957 $self->_execute('insert' => [], $source, $bind_attributes, $to_insert);
8e08ecc4 958
8b445e33 959 return $to_insert;
960}
961
744076d8 962## Still not quite perfect, and EXPERIMENTAL
963## Currently it is assumed that all values passed will be "normal", i.e. not
964## scalar refs, or at least, all the same type as the first set, the statement is
965## only prepped once.
54e0bd06 966sub insert_bulk {
9fdf90df 967 my ($self, $source, $cols, $data) = @_;
744076d8 968 my %colvalues;
9fdf90df 969 my $table = $source->from;
744076d8 970 @colvalues{@$cols} = (0..$#$cols);
971 my ($sql, @bind) = $self->sql_maker->insert($table, \%colvalues);
7af8b477 972
e5d9ee92 973 $self->_query_start( $sql, @bind );
894328b8 974 my $sth = $self->sth($sql);
54e0bd06 975
54e0bd06 976# @bind = map { ref $_ ? ''.$_ : $_ } @bind; # stringify args
977
744076d8 978 ## This must be an arrayref, else nothing works!
9fdf90df 979
744076d8 980 my $tuple_status = [];
9fdf90df 981
982 ##use Data::Dumper;
983 ##print STDERR Dumper( $data, $sql, [@bind] );
eda28767 984
61646ebd 985 my $time = time();
8b646589 986
61646ebd 987 ## Get the bind_attributes, if any exist
988 my $bind_attributes = $self->source_bind_attributes($source);
9fdf90df 989
61646ebd 990 ## Bind the values and execute
991 my $placeholder_index = 1;
9fdf90df 992
61646ebd 993 foreach my $bound (@bind) {
9fdf90df 994
61646ebd 995 my $attributes = {};
996 my ($column_name, $data_index) = @$bound;
eda28767 997
61646ebd 998 if( $bind_attributes ) {
999 $attributes = $bind_attributes->{$column_name}
1000 if defined $bind_attributes->{$column_name};
1001 }
9fdf90df 1002
61646ebd 1003 my @data = map { $_->[$data_index] } @$data;
9fdf90df 1004
61646ebd 1005 $sth->bind_param_array( $placeholder_index, [@data], $attributes );
1006 $placeholder_index++;
54e0bd06 1007 }
61646ebd 1008 my $rv = $sth->execute_array({ArrayTupleStatus => $tuple_status});
1009 $self->throw_exception($sth->errstr) if !$rv;
1010
e5d9ee92 1011 $self->_query_end( $sql, @bind );
54e0bd06 1012 return (wantarray ? ($rv, $sth, @bind) : $rv);
1013}
1014
8b445e33 1015sub update {
7af8b477 1016 my $self = shift @_;
1017 my $source = shift @_;
8b646589 1018 my $bind_attributes = $self->source_bind_attributes($source);
8b646589 1019
b7ce6568 1020 return $self->_execute('update' => [], $source, $bind_attributes, @_);
8b445e33 1021}
1022
7af8b477 1023
8b445e33 1024sub delete {
7af8b477 1025 my $self = shift @_;
1026 my $source = shift @_;
1027
1028 my $bind_attrs = {}; ## If ever it's needed...
7af8b477 1029
b7ce6568 1030 return $self->_execute('delete' => [], $source, $bind_attrs, @_);
8b445e33 1031}
1032
de705b51 1033sub _select {
8b445e33 1034 my ($self, $ident, $select, $condition, $attrs) = @_;
223b8fe3 1035 my $order = $attrs->{order_by};
1036 if (ref $condition eq 'SCALAR') {
1037 $order = $1 if $$condition =~ s/ORDER BY (.*)$//i;
1038 }
8839560b 1039 if (exists $attrs->{group_by} || $attrs->{having}) {
bc0c9800 1040 $order = {
1041 group_by => $attrs->{group_by},
1042 having => $attrs->{having},
1043 ($order ? (order_by => $order) : ())
1044 };
54540863 1045 }
7af8b477 1046 my $bind_attrs = {}; ## Future support
1047 my @args = ('select', $attrs->{bind}, $ident, $bind_attrs, $select, $condition, $order);
9229f20a 1048 if ($attrs->{software_limit} ||
1049 $self->sql_maker->_default_limit_syntax eq "GenericSubQ") {
1050 $attrs->{software_limit} = 1;
5c91499f 1051 } else {
0823196c 1052 $self->throw_exception("rows attribute must be positive if present")
1053 if (defined($attrs->{rows}) && !($attrs->{rows} > 0));
5c91499f 1054 push @args, $attrs->{rows}, $attrs->{offset};
1055 }
de705b51 1056 return $self->_execute(@args);
1057}
1058
8b646589 1059sub source_bind_attributes {
1060 my ($self, $source) = @_;
1061
1062 my $bind_attributes;
1063 foreach my $column ($source->columns) {
1064
1065 my $data_type = $source->column_info($column)->{data_type} || '';
1066 $bind_attributes->{$column} = $self->bind_attribute_by_data_type($data_type)
eda28767 1067 if $data_type;
8b646589 1068 }
1069
1070 return $bind_attributes;
1071}
1072
9b83fccd 1073=head2 select
1074
d3b0e369 1075=over 4
1076
1077=item Arguments: $ident, $select, $condition, $attrs
1078
1079=back
1080
9b83fccd 1081Handle a SQL select statement.
1082
1083=cut
1084
de705b51 1085sub select {
1086 my $self = shift;
1087 my ($ident, $select, $condition, $attrs) = @_;
e4eb8ee1 1088 return $self->cursor_class->new($self, \@_, $attrs);
8b445e33 1089}
1090
1a14aa3f 1091sub select_single {
de705b51 1092 my $self = shift;
1093 my ($rv, $sth, @bind) = $self->_select(@_);
6157db4f 1094 my @row = $sth->fetchrow_array;
a3eaff0e 1095 # Need to call finish() to work round broken DBDs
6157db4f 1096 $sth->finish();
1097 return @row;
1a14aa3f 1098}
1099
9b83fccd 1100=head2 sth
1101
d3b0e369 1102=over 4
1103
1104=item Arguments: $sql
1105
1106=back
1107
9b83fccd 1108Returns a L<DBI> sth (statement handle) for the supplied SQL.
1109
1110=cut
1111
d4f16b21 1112sub _dbh_sth {
1113 my ($self, $dbh, $sql) = @_;
b33697ef 1114
d32d82f9 1115 # 3 is the if_active parameter which avoids active sth re-use
b33697ef 1116 my $sth = $self->disable_sth_caching
1117 ? $dbh->prepare($sql)
1118 : $dbh->prepare_cached($sql, {}, 3);
1119
d92a4015 1120 # XXX You would think RaiseError would make this impossible,
1121 # but apparently that's not true :(
61646ebd 1122 $self->throw_exception($dbh->errstr) if !$sth;
b33697ef 1123
1124 $sth;
d32d82f9 1125}
1126
8b445e33 1127sub sth {
cb5f2eea 1128 my ($self, $sql) = @_;
d4f16b21 1129 $self->dbh_do($self->can('_dbh_sth'), $sql);
8b445e33 1130}
1131
d4f16b21 1132sub _dbh_columns_info_for {
1133 my ($self, $dbh, $table) = @_;
a32e8402 1134
d32d82f9 1135 if ($dbh->can('column_info')) {
a953d8d9 1136 my %result;
d32d82f9 1137 eval {
1138 my ($schema,$tab) = $table =~ /^(.+?)\.(.+)$/ ? ($1,$2) : (undef,$table);
1139 my $sth = $dbh->column_info( undef,$schema, $tab, '%' );
1140 $sth->execute();
1141 while ( my $info = $sth->fetchrow_hashref() ){
1142 my %column_info;
1143 $column_info{data_type} = $info->{TYPE_NAME};
1144 $column_info{size} = $info->{COLUMN_SIZE};
1145 $column_info{is_nullable} = $info->{NULLABLE} ? 1 : 0;
1146 $column_info{default_value} = $info->{COLUMN_DEF};
1147 my $col_name = $info->{COLUMN_NAME};
1148 $col_name =~ s/^\"(.*)\"$/$1/;
1149
1150 $result{$col_name} = \%column_info;
0d67fe74 1151 }
d32d82f9 1152 };
093fc7a6 1153 return \%result if !$@ && scalar keys %result;
d32d82f9 1154 }
0d67fe74 1155
d32d82f9 1156 my %result;
88262f96 1157 my $sth = $dbh->prepare($self->sql_maker->select($table, undef, \'1 = 0'));
d32d82f9 1158 $sth->execute;
1159 my @columns = @{$sth->{NAME_lc}};
1160 for my $i ( 0 .. $#columns ){
1161 my %column_info;
248bf0d0 1162 $column_info{data_type} = $sth->{TYPE}->[$i];
d32d82f9 1163 $column_info{size} = $sth->{PRECISION}->[$i];
1164 $column_info{is_nullable} = $sth->{NULLABLE}->[$i] ? 1 : 0;
0d67fe74 1165
d32d82f9 1166 if ($column_info{data_type} =~ m/^(.*?)\((.*?)\)$/) {
1167 $column_info{data_type} = $1;
1168 $column_info{size} = $2;
0d67fe74 1169 }
1170
d32d82f9 1171 $result{$columns[$i]} = \%column_info;
1172 }
248bf0d0 1173 $sth->finish;
1174
1175 foreach my $col (keys %result) {
1176 my $colinfo = $result{$col};
1177 my $type_num = $colinfo->{data_type};
1178 my $type_name;
1179 if(defined $type_num && $dbh->can('type_info')) {
1180 my $type_info = $dbh->type_info($type_num);
1181 $type_name = $type_info->{TYPE_NAME} if $type_info;
1182 $colinfo->{data_type} = $type_name if $type_name;
1183 }
1184 }
d32d82f9 1185
1186 return \%result;
1187}
1188
1189sub columns_info_for {
1190 my ($self, $table) = @_;
d4f16b21 1191 $self->dbh_do($self->can('_dbh_columns_info_for'), $table);
a953d8d9 1192}
1193
9b83fccd 1194=head2 last_insert_id
1195
1196Return the row id of the last insert.
1197
1198=cut
1199
d4f16b21 1200sub _dbh_last_insert_id {
1201 my ($self, $dbh, $source, $col) = @_;
1202 # XXX This is a SQLite-ism as a default... is there a DBI-generic way?
1203 $dbh->func('last_insert_rowid');
1204}
1205
843f8ecd 1206sub last_insert_id {
d4f16b21 1207 my $self = shift;
1208 $self->dbh_do($self->can('_dbh_last_insert_id'), @_);
843f8ecd 1209}
1210
9b83fccd 1211=head2 sqlt_type
1212
1213Returns the database driver name.
1214
1215=cut
1216
d4f16b21 1217sub sqlt_type { shift->dbh->{Driver}->{Name} }
1c339d71 1218
a71859b4 1219=head2 bind_attribute_by_data_type
1220
1221Given a datatype from column info, returns a database specific bind attribute for
1222$dbh->bind_param($val,$attribute) or nothing if we will let the database planner
1223just handle it.
1224
1225Generally only needed for special case column types, like bytea in postgres.
1226
1227=cut
1228
1229sub bind_attribute_by_data_type {
1230 return;
1231}
1232
58ded37e 1233=head2 create_ddl_dir
9b83fccd 1234
1235=over 4
1236
c9d2e0a2 1237=item Arguments: $schema \@databases, $version, $directory, $preversion, $sqlt_args
9b83fccd 1238
1239=back
1240
d3b0e369 1241Creates a SQL file based on the Schema, for each of the specified
9b83fccd 1242database types, in the given directory.
1243
9b83fccd 1244=cut
1245
e673f011 1246sub create_ddl_dir
1247{
c9d2e0a2 1248 my ($self, $schema, $databases, $version, $dir, $preversion, $sqltargs) = @_;
e673f011 1249
1250 if(!$dir || !-d $dir)
1251 {
1252 warn "No directory given, using ./\n";
1253 $dir = "./";
1254 }
1255 $databases ||= ['MySQL', 'SQLite', 'PostgreSQL'];
1256 $databases = [ $databases ] if(ref($databases) ne 'ARRAY');
1257 $version ||= $schema->VERSION || '1.x';
9e7b9292 1258 $sqltargs = { ( add_drop_table => 1 ), %{$sqltargs || {}} };
e673f011 1259
40dce2a5 1260 $self->throw_exception(q{Can't create a ddl file without SQL::Translator 0.08: '}
1261 . $self->_check_sqlt_message . q{'})
1262 if !$self->_check_sqlt_version;
e673f011 1263
c9d2e0a2 1264 my $sqlt = SQL::Translator->new({
1265# debug => 1,
1266 add_drop_table => 1,
1267 });
e673f011 1268 foreach my $db (@$databases)
1269 {
1270 $sqlt->reset();
1271 $sqlt->parser('SQL::Translator::Parser::DBIx::Class');
1272# $sqlt->parser_args({'DBIx::Class' => $schema);
c9d2e0a2 1273 $sqlt = $self->configure_sqlt($sqlt, $db);
e673f011 1274 $sqlt->data($schema);
1275 $sqlt->producer($db);
1276
1277 my $file;
1278 my $filename = $schema->ddl_filename($db, $dir, $version);
1279 if(-e $filename)
1280 {
c9d2e0a2 1281 warn("$filename already exists, skipping $db");
e673f011 1282 next;
1283 }
c9d2e0a2 1284
e673f011 1285 my $output = $sqlt->translate;
e673f011 1286 if(!$output)
1287 {
c9d2e0a2 1288 warn("Failed to translate to $db, skipping. (" . $sqlt->error . ")");
e673f011 1289 next;
1290 }
c9d2e0a2 1291 if(!open($file, ">$filename"))
1292 {
1293 $self->throw_exception("Can't open $filename for writing ($!)");
1294 next;
1295 }
e673f011 1296 print $file $output;
1297 close($file);
c9d2e0a2 1298
1299 if($preversion)
1300 {
40dce2a5 1301 require SQL::Translator::Diff;
c9d2e0a2 1302
1303 my $prefilename = $schema->ddl_filename($db, $dir, $preversion);
e2c0df8e 1304# print "Previous version $prefilename\n";
c9d2e0a2 1305 if(!-e $prefilename)
1306 {
1307 warn("No previous schema file found ($prefilename)");
1308 next;
1309 }
1310 #### We need to reparse the SQLite file we just wrote, so that
1311 ## Diff doesnt get all confoosed, and Diff is *very* confused.
1312 ## FIXME: rip Diff to pieces!
1313# my $target_schema = $sqlt->schema;
1314# unless ( $target_schema->name ) {
1315# $target_schema->name( $filename );
1316# }
1317 my @input;
1318 push @input, {file => $prefilename, parser => $db};
1319 push @input, {file => $filename, parser => $db};
1320 my ( $source_schema, $source_db, $target_schema, $target_db ) = map {
1321 my $file = $_->{'file'};
1322 my $parser = $_->{'parser'};
1323
1324 my $t = SQL::Translator->new;
1325 $t->debug( 0 );
1326 $t->trace( 0 );
1327 $t->parser( $parser ) or die $t->error;
1328 my $out = $t->translate( $file ) or die $t->error;
1329 my $schema = $t->schema;
1330 unless ( $schema->name ) {
1331 $schema->name( $file );
1332 }
1333 ($schema, $parser);
1334 } @input;
1335
1336 my $diff = SQL::Translator::Diff::schema_diff($source_schema, $db,
1337 $target_schema, $db,
1338 {}
1339 );
1340 my $difffile = $schema->ddl_filename($db, $dir, $version, $preversion);
1341 print STDERR "Diff: $difffile: $db, $dir, $version, $preversion \n";
1342 if(-e $difffile)
1343 {
1344 warn("$difffile already exists, skipping");
1345 next;
1346 }
1347 if(!open $file, ">$difffile")
1348 {
1349 $self->throw_exception("Can't write to $difffile ($!)");
1350 next;
1351 }
1352 print $file $diff;
1353 close($file);
1354 }
e673f011 1355 }
c9d2e0a2 1356}
e673f011 1357
c9d2e0a2 1358sub configure_sqlt() {
1359 my $self = shift;
1360 my $tr = shift;
1361 my $db = shift || $self->sqlt_type;
1362 if ($db eq 'PostgreSQL') {
1363 $tr->quote_table_names(0);
1364 $tr->quote_field_names(0);
1365 }
1366 return $tr;
e673f011 1367}
1368
9b83fccd 1369=head2 deployment_statements
1370
d3b0e369 1371=over 4
1372
1373=item Arguments: $schema, $type, $version, $directory, $sqlt_args
1374
1375=back
1376
1377Returns the statements used by L</deploy> and L<DBIx::Class::Schema/deploy>.
1378The database driver name is given by C<$type>, though the value from
1379L</sqlt_type> is used if it is not specified.
1380
1381C<$directory> is used to return statements from files in a previously created
1382L</create_ddl_dir> directory and is optional. The filenames are constructed
1383from L<DBIx::Class::Schema/ddl_filename>, the schema name and the C<$version>.
1384
1385If no C<$directory> is specified then the statements are constructed on the
1386fly using L<SQL::Translator> and C<$version> is ignored.
1387
1388See L<SQL::Translator/METHODS> for a list of values for C<$sqlt_args>.
9b83fccd 1389
1390=cut
1391
e673f011 1392sub deployment_statements {
1393 my ($self, $schema, $type, $version, $dir, $sqltargs) = @_;
915919c5 1394 # Need to be connected to get the correct sqlt_type
c377d939 1395 $self->ensure_connected() unless $type;
e673f011 1396 $type ||= $self->sqlt_type;
1397 $version ||= $schema->VERSION || '1.x';
1398 $dir ||= './';
c9d2e0a2 1399 my $filename = $schema->ddl_filename($type, $dir, $version);
1400 if(-f $filename)
1401 {
1402 my $file;
1403 open($file, "<$filename")
1404 or $self->throw_exception("Can't open $filename ($!)");
1405 my @rows = <$file>;
1406 close($file);
1407 return join('', @rows);
1408 }
1409
40dce2a5 1410 $self->throw_exception(q{Can't deploy without SQL::Translator 0.08: '}
1411 . $self->_check_sqlt_message . q{'})
1412 if !$self->_check_sqlt_version;
1413
1414 require SQL::Translator::Parser::DBIx::Class;
1415 eval qq{use SQL::Translator::Producer::${type}};
1416 $self->throw_exception($@) if $@;
1417
1418 # sources needs to be a parser arg, but for simplicty allow at top level
1419 # coming in
1420 $sqltargs->{parser_args}{sources} = delete $sqltargs->{sources}
1421 if exists $sqltargs->{sources};
1422
1423 my $tr = SQL::Translator->new(%$sqltargs);
1424 SQL::Translator::Parser::DBIx::Class::parse( $tr, $schema );
1425 return "SQL::Translator::Producer::${type}"->can('produce')->($tr);
e673f011 1426
c9d2e0a2 1427 return;
e673f011 1428
1c339d71 1429}
843f8ecd 1430
1c339d71 1431sub deploy {
260129d8 1432 my ($self, $schema, $type, $sqltargs, $dir) = @_;
1433 foreach my $statement ( $self->deployment_statements($schema, $type, undef, $dir, { no_comments => 1, %{ $sqltargs || {} } } ) ) {
61bf0de5 1434 foreach my $line ( split(";\n", $statement)) {
1435 next if($line =~ /^--/);
1436 next if(!$line);
1437# next if($line =~ /^DROP/m);
1438 next if($line =~ /^BEGIN TRANSACTION/m);
1439 next if($line =~ /^COMMIT/m);
1440 next if $line =~ /^\s+$/; # skip whitespace only
e5d9ee92 1441 $self->_query_start($line);
61bf0de5 1442 eval {
1443 $self->dbh->do($line); # shouldn't be using ->dbh ?
1444 };
1445 if ($@) {
1446 warn qq{$@ (running "${line}")};
1447 }
e5d9ee92 1448 $self->_query_end($line);
e4fe9ba3 1449 }
75d07914 1450 }
1c339d71 1451}
843f8ecd 1452
9b83fccd 1453=head2 datetime_parser
1454
1455Returns the datetime parser class
1456
1457=cut
1458
f86fcf0d 1459sub datetime_parser {
1460 my $self = shift;
114780ee 1461 return $self->{datetime_parser} ||= do {
1462 $self->ensure_connected;
1463 $self->build_datetime_parser(@_);
1464 };
f86fcf0d 1465}
1466
9b83fccd 1467=head2 datetime_parser_type
1468
1469Defines (returns) the datetime parser class - currently hardwired to
1470L<DateTime::Format::MySQL>
1471
1472=cut
1473
f86fcf0d 1474sub datetime_parser_type { "DateTime::Format::MySQL"; }
1475
9b83fccd 1476=head2 build_datetime_parser
1477
1478See L</datetime_parser>
1479
1480=cut
1481
f86fcf0d 1482sub build_datetime_parser {
1483 my $self = shift;
1484 my $type = $self->datetime_parser_type(@_);
1485 eval "use ${type}";
1486 $self->throw_exception("Couldn't load ${type}: $@") if $@;
1487 return $type;
1488}
1489
40dce2a5 1490{
1491 my $_check_sqlt_version; # private
1492 my $_check_sqlt_message; # private
1493 sub _check_sqlt_version {
1494 return $_check_sqlt_version if defined $_check_sqlt_version;
1495 eval 'use SQL::Translator 0.08';
1496 $_check_sqlt_message = $@ ? $@ : '';
1497 $_check_sqlt_version = $@ ? 0 : 1;
1498 }
1499
1500 sub _check_sqlt_message {
1501 _check_sqlt_version if !defined $_check_sqlt_message;
1502 $_check_sqlt_message;
1503 }
1504}
1505
c756145c 1506sub DESTROY {
1507 my $self = shift;
f5de3933 1508 return if !$self->_dbh;
c756145c 1509 $self->_verify_pid;
1510 $self->_dbh(undef);
1511}
92925617 1512
8b445e33 15131;
1514
9b83fccd 1515=head1 SQL METHODS
1516
1517The module defines a set of methods within the DBIC::SQL::Abstract
1518namespace. These build on L<SQL::Abstract::Limit> to provide the
1519SQL query functions.
1520
1521The following methods are extended:-
1522
1523=over 4
1524
1525=item delete
1526
1527=item insert
1528
1529=item select
1530
1531=item update
1532
1533=item limit_dialect
1534
2cc3a7be 1535See L</connect_info> for details.
1536For setting, this method is deprecated in favor of L</connect_info>.
bb4f246d 1537
9b83fccd 1538=item quote_char
1539
2cc3a7be 1540See L</connect_info> for details.
1541For setting, this method is deprecated in favor of L</connect_info>.
bb4f246d 1542
9b83fccd 1543=item name_sep
1544
2cc3a7be 1545See L</connect_info> for details.
1546For setting, this method is deprecated in favor of L</connect_info>.
bb4f246d 1547
9b83fccd 1548=back
1549
8b445e33 1550=head1 AUTHORS
1551
daec44b8 1552Matt S. Trout <mst@shadowcatsystems.co.uk>
8b445e33 1553
9f19b1d6 1554Andy Grundman <andy@hybridized.org>
1555
8b445e33 1556=head1 LICENSE
1557
1558You may distribute this code under the same terms as Perl itself.
1559
1560=cut