X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FStorage%2FDBI.pm;h=5be636fadf15f1df6589abe0096f26c7ac7b3c9e;hb=e4eb8ee1d77be917d2d721695e203c941e0219a2;hp=d7b9cf9677be6d47144ad335f39e70a0e3ac90e0;hpb=664612fb99e660306214ca4bf8008a4c16a04d5b;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Storage/DBI.pm b/lib/DBIx/Class/Storage/DBI.pm index d7b9cf9..5be636f 100644 --- a/lib/DBIx/Class/Storage/DBI.pm +++ b/lib/DBIx/Class/Storage/DBI.pm @@ -9,15 +9,16 @@ use DBI; use SQL::Abstract::Limit; use DBIx::Class::Storage::DBI::Cursor; use DBIx::Class::Storage::Statistics; -use IO::File; use Scalar::Util qw/blessed weaken/; __PACKAGE__->mk_group_accessors('simple' => qw/_connect_info _dbi_connect_info _dbh _sql_maker _sql_maker_opts - _conn_pid _conn_tid disable_sth_caching cursor on_connect_do - transaction_depth unsafe/ + _conn_pid _conn_tid disable_sth_caching on_connect_do + transaction_depth unsafe _dbh_autocommit/ ); +__PACKAGE__->cursor_class('DBIx::Class::Storage::DBI::Cursor'); + BEGIN { package DBIC::SQL::Abstract; # Would merge upstream, but nate doesn't reply :( @@ -116,7 +117,7 @@ sub _emulate_limit { } sub _recurse_fields { - my ($self, $fields) = @_; + my ($self, $fields, $params) = @_; my $ref = ref $fields; return $self->_quote($fields) unless $ref; return $$fields if $ref eq 'SCALAR'; @@ -124,10 +125,10 @@ sub _recurse_fields { if ($ref eq 'ARRAY') { return join(', ', map { $self->_recurse_fields($_) - .(exists $self->{rownum_hack_count} - ? ' AS col'.$self->{rownum_hack_count}++ - : '') - } @$fields); + .(exists $self->{rownum_hack_count} && !($params && $params->{no_rownum_hack}) + ? ' AS col'.$self->{rownum_hack_count}++ + : '') + } @$fields); } elsif ($ref eq 'HASH') { foreach my $func (keys %$fields) { return $self->_sqlcase($func) @@ -143,7 +144,7 @@ sub _order_by { if (ref $_[0] eq 'HASH') { if (defined $_[0]->{group_by}) { $ret = $self->_sqlcase(' group by ') - .$self->_recurse_fields($_[0]->{group_by}); + .$self->_recurse_fields($_[0]->{group_by}, { no_rownum_hack => 1 }); } if (defined $_[0]->{having}) { my $frag; @@ -312,7 +313,6 @@ documents DBI-specific methods and behaviors. sub new { my $new = shift->next::method(@_); - $new->cursor("DBIx::Class::Storage::DBI::Cursor"); $new->transaction_depth(0); $new->_sql_maker_opts({}); $new->{_in_dbh_do} = 0; @@ -383,15 +383,14 @@ each other. In most cases this is simply a C<.>. =item unsafe This Storage driver normally installs its own C, sets -C on, and sets C off on all database handles, -including those supplied by a coderef. It does this so that it can -have consistent and useful error behavior. +C and C on, and sets C off on +all database handles, including those supplied by a coderef. It does this +so that it can have consistent and useful error behavior. If you set this option to a true value, Storage will not do its usual -modifications to the database handle's C, C, and -C attributes, and instead relies on the settings in your -connect_info DBI options (or the values you set in your connection -coderef, in the case that you are connecting via coderef). +modifications to the database handle's attributes, and instead relies on +the settings in your connect_info DBI options (or the values you set in +your connection coderef, in the case that you are connecting via coderef). Note that your custom settings can cause Storage to malfunction, especially if you set a C handler that suppresses exceptions @@ -481,6 +480,7 @@ sub connect_info { my $last_info = $dbi_info->[-1]; if(ref $last_info eq 'HASH') { + $last_info = { %$last_info }; # so delete is non-destructive for my $storage_opt (qw/on_connect_do disable_sth_caching unsafe/) { if(my $value = delete $last_info->{$storage_opt}) { $self->$storage_opt($value); @@ -491,6 +491,8 @@ sub connect_info { $self->_sql_maker_opts->{$sql_maker_opt} = $opt_val; } } + # re-insert modified hashref + $dbi_info->[-1] = $last_info; # Get rid of any trailing empty hashref pop(@$dbi_info) if !keys %$last_info; @@ -584,6 +586,8 @@ sub txn_do { ref $coderef eq 'CODE' or $self->throw_exception ('$coderef must be a CODE reference'); + return $coderef->(@_) if $self->{transaction_depth}; + local $self->{_in_dbh_do} = 1; my @result; @@ -644,7 +648,7 @@ sub disconnect { my ($self) = @_; if( $self->connected ) { - $self->_dbh->rollback unless $self->_dbh->{AutoCommit}; + $self->_dbh->rollback unless $self->_dbh_autocommit; $self->_dbh->disconnect; $self->_dbh(undef); $self->{_dbh_gen}++; @@ -725,7 +729,7 @@ sub _populate_dbh { # Always set the transaction depth on connect, since # there is no transaction in progress by definition - $self->{transaction_depth} = $self->_dbh->{AutoCommit} ? 0 : 1; + $self->{transaction_depth} = $self->_dbh_autocommit ? 0 : 1; if(ref $self eq 'DBIx::Class::Storage::DBI') { my $driver = $self->_dbh->{Driver}->{Name}; @@ -773,6 +777,7 @@ sub _connect { $dbh->{HandleError} = sub { $weak_self->throw_exception("DBI Exception: $_[0]") }; + $dbh->{ShowErrorStatement} = 1; $dbh->{RaiseError} = 1; $dbh->{PrintError} = 0; } @@ -783,13 +788,16 @@ sub _connect { $self->throw_exception("DBI Connection failed: " . ($@||$DBI::errstr)) if !$dbh || $@; + $self->_dbh_autocommit($dbh->{AutoCommit}); + $dbh; } sub txn_begin { my $self = shift; - if($self->{transaction_depth}++ == 0) { + $self->ensure_connected(); + if($self->{transaction_depth} == 0) { $self->debugobj->txn_begin() if $self->debug; # this isn't ->_dbh-> because @@ -797,6 +805,7 @@ sub txn_begin { # for AutoCommit users $self->dbh->begin_work; } + $self->{transaction_depth}++; } sub txn_commit { @@ -807,7 +816,7 @@ sub txn_commit { if ($self->debug); $dbh->commit; $self->{transaction_depth} = 0 - if $dbh->{AutoCommit}; + if $self->_dbh_autocommit; } elsif($self->{transaction_depth} > 1) { $self->{transaction_depth}-- @@ -817,15 +826,13 @@ sub txn_commit { sub txn_rollback { my $self = shift; my $dbh = $self->_dbh; - my $autocommit; eval { - $autocommit = $dbh->{AutoCommit}; if ($self->{transaction_depth} == 1) { $self->debugobj->txn_rollback() if ($self->debug); - $dbh->rollback; $self->{transaction_depth} = 0 - if $autocommit; + if $self->_dbh_autocommit; + $dbh->rollback; } elsif($self->{transaction_depth} > 1) { $self->{transaction_depth}--; @@ -839,7 +846,7 @@ sub txn_rollback { my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION"; $error =~ /$exception_class/ and $self->throw_exception($error); # ensure that a failed rollback resets the transaction depth - $self->{transaction_depth} = $autocommit ? 0 : 1; + $self->{transaction_depth} = $self->_dbh_autocommit ? 0 : 1; $self->throw_exception($error); } } @@ -1055,7 +1062,7 @@ Handle a SQL select statement. sub select { my $self = shift; my ($ident, $select, $condition, $attrs) = @_; - return $self->cursor->new($self, \@_, $attrs); + return $self->cursor_class->new($self, \@_, $attrs); } sub select_single { @@ -1200,7 +1207,7 @@ sub bind_attribute_by_data_type { return; } -=head2 create_ddl_dir (EXPERIMENTAL) +=head2 create_ddl_dir =over 4 @@ -1211,9 +1218,6 @@ sub bind_attribute_by_data_type { Creates a SQL file based on the Schema, for each of the specified database types, in the given directory. -Note that this feature is currently EXPERIMENTAL and may not work correctly -across all databases, or fully handle complex relationships. - =cut sub create_ddl_dir @@ -1404,16 +1408,21 @@ sub deployment_statements { sub deploy { my ($self, $schema, $type, $sqltargs, $dir) = @_; foreach my $statement ( $self->deployment_statements($schema, $type, undef, $dir, { no_comments => 1, %{ $sqltargs || {} } } ) ) { - for ( split(";\n", $statement)) { - next if($_ =~ /^--/); - next if(!$_); -# next if($_ =~ /^DROP/m); - next if($_ =~ /^BEGIN TRANSACTION/m); - next if($_ =~ /^COMMIT/m); - next if $_ =~ /^\s+$/; # skip whitespace only - $self->debugobj->query_start($_) if $self->debug; - $self->dbh->do($_); # shouldn't be using ->dbh ? - $self->debugobj->query_end($_) if $self->debug; + foreach my $line ( split(";\n", $statement)) { + next if($line =~ /^--/); + next if(!$line); +# next if($line =~ /^DROP/m); + next if($line =~ /^BEGIN TRANSACTION/m); + next if($line =~ /^COMMIT/m); + next if $line =~ /^\s+$/; # skip whitespace only + $self->debugobj->query_start($line) if $self->debug; + eval { + $self->dbh->do($line); # shouldn't be using ->dbh ? + }; + if ($@) { + warn qq{$@ (running "${line}")}; + } + $self->debugobj->query_end($line) if $self->debug; } } } @@ -1426,7 +1435,10 @@ Returns the datetime parser class sub datetime_parser { my $self = shift; - return $self->{datetime_parser} ||= $self->build_datetime_parser(@_); + return $self->{datetime_parser} ||= do { + $self->ensure_connected; + $self->build_datetime_parser(@_); + }; } =head2 datetime_parser_type