Moved DBIC::SQL::Abstract inner classes to DBIx::Class::SQLAHacks namespace to decoup...
[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) {
e673f011 1305 warn "No directory given, using ./\n";
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');
1328 my $sqlt_schema = $sqlt->translate({ data => $schema }) or die $sqlt->error;
1329
99a74c4a 1330 foreach my $db (@$databases) {
e673f011 1331 $sqlt->reset();
b7e303a8 1332 $sqlt->{schema} = $sqlt_schema;
e673f011 1333 $sqlt->producer($db);
1334
1335 my $file;
99a74c4a 1336 my $filename = $schema->ddl_filename($db, $version, $dir);
b1f9d92e 1337 if (-e $filename && ($version eq $schema_version )) {
99a74c4a 1338 # if we are dumping the current version, overwrite the DDL
1339 warn "Overwriting existing DDL file - $filename";
1340 unlink($filename);
1341 }
c9d2e0a2 1342
99a74c4a 1343 my $output = $sqlt->translate;
1344 if(!$output) {
1345 warn("Failed to translate to $db, skipping. (" . $sqlt->error . ")");
1346 next;
1347 }
1348 if(!open($file, ">$filename")) {
1349 $self->throw_exception("Can't open $filename for writing ($!)");
1350 next;
1351 }
1352 print $file $output;
1353 close($file);
1354
1355 next unless ($preversion);
c9d2e0a2 1356
99a74c4a 1357 require SQL::Translator::Diff;
2dc2cd0f 1358
99a74c4a 1359 my $prefilename = $schema->ddl_filename($db, $preversion, $dir);
1360 if(!-e $prefilename) {
1361 warn("No previous schema file found ($prefilename)");
1362 next;
1363 }
c9d2e0a2 1364
99a74c4a 1365 my $difffile = $schema->ddl_filename($db, $version, $dir, $preversion);
1366 if(-e $difffile) {
1367 warn("Overwriting existing diff file - $difffile");
1368 unlink($difffile);
1369 }
1370
1371 my $source_schema;
1372 {
1373 my $t = SQL::Translator->new($sqltargs);
1374 $t->debug( 0 );
1375 $t->trace( 0 );
1376 $t->parser( $db ) or die $t->error;
99a74c4a 1377 my $out = $t->translate( $prefilename ) or die $t->error;
1378 $source_schema = $t->schema;
1379 unless ( $source_schema->name ) {
1380 $source_schema->name( $prefilename );
2dc2cd0f 1381 }
99a74c4a 1382 }
c9d2e0a2 1383
99a74c4a 1384 # The "new" style of producers have sane normalization and can support
1385 # diffing a SQL file against a DBIC->SQLT schema. Old style ones don't
1386 # And we have to diff parsed SQL against parsed SQL.
1387 my $dest_schema = $sqlt_schema;
1388
1389 unless ( "SQL::Translator::Producer::$db"->can('preprocess_schema') ) {
1390 my $t = SQL::Translator->new($sqltargs);
1391 $t->debug( 0 );
1392 $t->trace( 0 );
1393 $t->parser( $db ) or die $t->error;
99a74c4a 1394 my $out = $t->translate( $filename ) or die $t->error;
1395 $dest_schema = $t->schema;
1396 $dest_schema->name( $filename )
1397 unless $dest_schema->name;
1398 }
1399
1400 my $diff = SQL::Translator::Diff::schema_diff($source_schema, $db,
1401 $dest_schema, $db,
1402 $sqltargs
1403 );
1404 if(!open $file, ">$difffile") {
1405 $self->throw_exception("Can't write to $difffile ($!)");
1406 next;
c9d2e0a2 1407 }
99a74c4a 1408 print $file $diff;
1409 close($file);
e673f011 1410 }
c9d2e0a2 1411}
e673f011 1412
9b83fccd 1413=head2 deployment_statements
1414
d3b0e369 1415=over 4
1416
1417=item Arguments: $schema, $type, $version, $directory, $sqlt_args
1418
1419=back
1420
1421Returns the statements used by L</deploy> and L<DBIx::Class::Schema/deploy>.
1422The database driver name is given by C<$type>, though the value from
1423L</sqlt_type> is used if it is not specified.
1424
1425C<$directory> is used to return statements from files in a previously created
1426L</create_ddl_dir> directory and is optional. The filenames are constructed
1427from L<DBIx::Class::Schema/ddl_filename>, the schema name and the C<$version>.
1428
1429If no C<$directory> is specified then the statements are constructed on the
1430fly using L<SQL::Translator> and C<$version> is ignored.
1431
1432See L<SQL::Translator/METHODS> for a list of values for C<$sqlt_args>.
9b83fccd 1433
1434=cut
1435
e673f011 1436sub deployment_statements {
1437 my ($self, $schema, $type, $version, $dir, $sqltargs) = @_;
915919c5 1438 # Need to be connected to get the correct sqlt_type
c377d939 1439 $self->ensure_connected() unless $type;
e673f011 1440 $type ||= $self->sqlt_type;
b1f9d92e 1441 $version ||= $schema->schema_version || '1.x';
e673f011 1442 $dir ||= './';
0233fc64 1443 my $filename = $schema->ddl_filename($type, $version, $dir);
c9d2e0a2 1444 if(-f $filename)
1445 {
1446 my $file;
1447 open($file, "<$filename")
1448 or $self->throw_exception("Can't open $filename ($!)");
1449 my @rows = <$file>;
1450 close($file);
1451 return join('', @rows);
1452 }
1453
228d5eae 1454 $self->throw_exception(q{Can't deploy without SQL::Translator 0.09003: '}
40dce2a5 1455 . $self->_check_sqlt_message . q{'})
1456 if !$self->_check_sqlt_version;
1457
1458 require SQL::Translator::Parser::DBIx::Class;
1459 eval qq{use SQL::Translator::Producer::${type}};
1460 $self->throw_exception($@) if $@;
1461
1462 # sources needs to be a parser arg, but for simplicty allow at top level
1463 # coming in
1464 $sqltargs->{parser_args}{sources} = delete $sqltargs->{sources}
1465 if exists $sqltargs->{sources};
1466
1467 my $tr = SQL::Translator->new(%$sqltargs);
1468 SQL::Translator::Parser::DBIx::Class::parse( $tr, $schema );
1469 return "SQL::Translator::Producer::${type}"->can('produce')->($tr);
1c339d71 1470}
843f8ecd 1471
1c339d71 1472sub deploy {
260129d8 1473 my ($self, $schema, $type, $sqltargs, $dir) = @_;
11d8c781 1474 my $deploy = sub {
1475 my $line = shift;
1476 return if($line =~ /^--/);
1477 return if(!$line);
1478 # next if($line =~ /^DROP/m);
1479 return if($line =~ /^BEGIN TRANSACTION/m);
1480 return if($line =~ /^COMMIT/m);
1481 return if $line =~ /^\s+$/; # skip whitespace only
1482 $self->_query_start($line);
1483 eval {
1484 $self->dbh->do($line); # shouldn't be using ->dbh ?
1485 };
1486 if ($@) {
1487 warn qq{$@ (running "${line}")};
1488 }
1489 $self->_query_end($line);
1490 };
1491 my @statements = $self->deployment_statements($schema, $type, undef, $dir, { no_comments => 1, %{ $sqltargs || {} } } );
1492 if (@statements > 1) {
1493 foreach my $statement (@statements) {
1494 $deploy->( $statement );
1495 }
1496 }
1497 elsif (@statements == 1) {
1498 foreach my $line ( split(";\n", $statements[0])) {
1499 $deploy->( $line );
e4fe9ba3 1500 }
75d07914 1501 }
1c339d71 1502}
843f8ecd 1503
9b83fccd 1504=head2 datetime_parser
1505
1506Returns the datetime parser class
1507
1508=cut
1509
f86fcf0d 1510sub datetime_parser {
1511 my $self = shift;
114780ee 1512 return $self->{datetime_parser} ||= do {
1513 $self->ensure_connected;
1514 $self->build_datetime_parser(@_);
1515 };
f86fcf0d 1516}
1517
9b83fccd 1518=head2 datetime_parser_type
1519
1520Defines (returns) the datetime parser class - currently hardwired to
1521L<DateTime::Format::MySQL>
1522
1523=cut
1524
f86fcf0d 1525sub datetime_parser_type { "DateTime::Format::MySQL"; }
1526
9b83fccd 1527=head2 build_datetime_parser
1528
1529See L</datetime_parser>
1530
1531=cut
1532
f86fcf0d 1533sub build_datetime_parser {
1534 my $self = shift;
1535 my $type = $self->datetime_parser_type(@_);
1536 eval "use ${type}";
1537 $self->throw_exception("Couldn't load ${type}: $@") if $@;
1538 return $type;
1539}
1540
40dce2a5 1541{
1542 my $_check_sqlt_version; # private
1543 my $_check_sqlt_message; # private
1544 sub _check_sqlt_version {
1545 return $_check_sqlt_version if defined $_check_sqlt_version;
228d5eae 1546 eval 'use SQL::Translator "0.09003"';
b7e303a8 1547 $_check_sqlt_message = $@ || '';
1548 $_check_sqlt_version = !$@;
40dce2a5 1549 }
1550
1551 sub _check_sqlt_message {
1552 _check_sqlt_version if !defined $_check_sqlt_message;
1553 $_check_sqlt_message;
1554 }
1555}
1556
106d5f3b 1557=head2 is_replicating
1558
1559A boolean that reports if a particular L<DBIx::Class::Storage::DBI> is set to
1560replicate from a master database. Default is undef, which is the result
1561returned by databases that don't support replication.
1562
1563=cut
1564
1565sub is_replicating {
1566 return;
1567
1568}
1569
1570=head2 lag_behind_master
1571
1572Returns a number that represents a certain amount of lag behind a master db
1573when a given storage is replicating. The number is database dependent, but
1574starts at zero and increases with the amount of lag. Default in undef
1575
1576=cut
1577
1578sub lag_behind_master {
1579 return;
1580}
1581
c756145c 1582sub DESTROY {
1583 my $self = shift;
f5de3933 1584 return if !$self->_dbh;
c756145c 1585 $self->_verify_pid;
1586 $self->_dbh(undef);
1587}
92925617 1588
8b445e33 15891;
1590
92fe2181 1591=head1 USAGE NOTES
1592
1593=head2 DBIx::Class and AutoCommit
1594
1595DBIx::Class can do some wonderful magic with handling exceptions,
1596disconnections, and transactions when you use C<< AutoCommit => 1 >>
1597combined with C<txn_do> for transaction support.
1598
1599If you set C<< AutoCommit => 0 >> in your connect info, then you are always
1600in an assumed transaction between commits, and you're telling us you'd
1601like to manage that manually. A lot of the magic protections offered by
1602this module will go away. We can't protect you from exceptions due to database
1603disconnects because we don't know anything about how to restart your
1604transactions. You're on your own for handling all sorts of exceptional
1605cases if you choose the C<< AutoCommit => 0 >> path, just as you would
1606be with raw DBI.
1607
1608
9b83fccd 1609
8b445e33 1610=head1 AUTHORS
1611
daec44b8 1612Matt S. Trout <mst@shadowcatsystems.co.uk>
8b445e33 1613
9f19b1d6 1614Andy Grundman <andy@hybridized.org>
1615
8b445e33 1616=head1 LICENSE
1617
1618You may distribute this code under the same terms as Perl itself.
1619
1620=cut