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