X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FStorage%2FDBI.pm;h=e07f11667d1f6fd06e0e9159fd7fe3e14da0a8fb;hb=555cc3f40384239505aeec3fb41d6f862dd0c050;hp=7be2455c6bcc1f4eaf1afba7093585be8627ef6d;hpb=8d56944855eaaaa09ee8563ec0700d7e1b54337a;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Storage/DBI.pm b/lib/DBIx/Class/Storage/DBI.pm index 7be2455..e07f116 100644 --- a/lib/DBIx/Class/Storage/DBI.pm +++ b/lib/DBIx/Class/Storage/DBI.pm @@ -451,13 +451,50 @@ L =cut sub connect_info { - my ($self, $info_arg) = @_; + my ($self, $info) = @_; - return $self->_connect_info if !$info_arg; + return $self->_connect_info if !$info; - my @args = @$info_arg; # take a shallow copy for further mutilation - $self->_connect_info([@args]); # copy for _connect_info + $self->_connect_info($info); # copy for _connect_info + + $info = $self->_normalize_connect_info($info) + if ref $info eq 'ARRAY'; + + for my $storage_opt (keys %{ $info->{storage_options} }) { + my $value = $info->{storage_options}{$storage_opt}; + + $self->$storage_opt($value); + } + + # Kill sql_maker/_sql_maker_opts, so we get a fresh one with only + # the new set of options + $self->_sql_maker(undef); + $self->_sql_maker_opts({}); + + for my $sql_maker_opt (keys %{ $info->{sql_maker_options} }) { + my $value = $info->{sql_maker_options}{$sql_maker_opt}; + + $self->_sql_maker_opts->{$sql_maker_opt} = $value; + } + + my %attrs = ( + %{ $self->_default_dbi_connect_attributes || {} }, + %{ $info->{attributes} || {} }, + ); + + my @args = @{ $info->{arguments} }; + $self->_dbi_connect_info([@args, + %attrs && !(ref $args[0] eq 'CODE') ? \%attrs : ()]); + + return $self->_connect_info; +} + +sub _normalize_connect_info { + my ($self, $info_arg) = @_; + my %info; + + my @args = @$info_arg; # take a shallow copy for further mutilation # combine/pre-parse arguments depending on invocation style @@ -494,36 +531,23 @@ sub connect_info { @args = @args[0,1,2]; } - # Kill sql_maker/_sql_maker_opts, so we get a fresh one with only - # the new set of options - $self->_sql_maker(undef); - $self->_sql_maker_opts({}); + $info{arguments} = \@args; - if(keys %attrs) { - for my $storage_opt (@storage_options, 'cursor_class') { # @storage_options is declared at the top of the module - if(my $value = delete $attrs{$storage_opt}) { - $self->$storage_opt($value); - } - } - for my $sql_maker_opt (qw/limit_dialect quote_char name_sep/) { - if(my $opt_val = delete $attrs{$sql_maker_opt}) { - $self->_sql_maker_opts->{$sql_maker_opt} = $opt_val; - } - } - } + my @storage_opts = grep exists $attrs{$_}, + @storage_options, 'cursor_class'; - if (ref $args[0] eq 'CODE') { - # _connect() never looks past $args[0] in this case - %attrs = () - } else { - %attrs = ( - %{ $self->_default_dbi_connect_attributes || {} }, - %attrs, - ); - } + @{ $info{storage_options} }{@storage_opts} = + delete @attrs{@storage_opts} if @storage_opts; + + my @sql_maker_opts = grep exists $attrs{$_}, + qw/limit_dialect quote_char name_sep/; + + @{ $info{sql_maker_options} }{@sql_maker_opts} = + delete @attrs{@sql_maker_opts} if @sql_maker_opts; + + $info{attributes} = \%attrs if %attrs; - $self->_dbi_connect_info([@args, keys %attrs ? \%attrs : ()]); - $self->_connect_info; + return \%info; } sub _default_dbi_connect_attributes { @@ -1026,7 +1050,7 @@ sub _connect { eval { if(ref $info[0] eq 'CODE') { - $dbh = &{$info[0]} + $dbh = $info[0]->(); } else { $dbh = DBI->connect(@info); @@ -1148,6 +1172,11 @@ sub _svp_generate_name { sub txn_begin { my $self = shift; + + # this means we have not yet connected and do not know the AC status + # (e.g. coderef $dbh) + $self->ensure_connected if (! defined $self->_dbh_autocommit); + if($self->{transaction_depth} == 0) { $self->debugobj->txn_begin() if $self->debug; @@ -1360,7 +1389,6 @@ sub insert { return $updated_cols; } -## Still not quite perfect, and EXPERIMENTAL ## Currently it is assumed that all values passed will be "normal", i.e. not ## scalar refs, or at least, all the same type as the first set, the statement is ## only prepped once. @@ -1440,9 +1468,13 @@ sub insert_bulk { ); } + # neither _execute_array, nor _execute_inserts_with_no_binds are + # atomic (even if _execute _array is a single call). Thus a safety + # scope guard + my $guard = $self->txn_scope_guard unless $self->{transaction_depth} != 0; + $self->_query_start( $sql, ['__BULK__'] ); my $sth = $self->sth($sql); - my $rv = do { if ($empty_bind) { # bind_param_array doesn't work if there are no binds @@ -1456,14 +1488,15 @@ sub insert_bulk { $self->_query_end( $sql, ['__BULK__'] ); + + $guard->commit if $guard; + return (wantarray ? ($rv, $sth, @bind) : $rv); } sub _execute_array { my ($self, $source, $sth, $bind, $cols, $data, @extra) = @_; - my $guard = $self->txn_scope_guard unless $self->{transaction_depth} != 0; - ## This must be an arrayref, else nothing works! my $tuple_status = []; @@ -1512,9 +1545,6 @@ sub _execute_array { }), ); } - - $guard->commit if $guard; - return $rv; } @@ -1527,8 +1557,6 @@ sub _dbh_execute_array { sub _dbh_execute_inserts_with_no_binds { my ($self, $sth, $count) = @_; - my $guard = $self->txn_scope_guard unless $self->{transaction_depth} != 0; - eval { my $dbh = $self->_get_dbh; local $dbh->{RaiseError} = 1; @@ -1544,13 +1572,11 @@ sub _dbh_execute_inserts_with_no_binds { $self->throw_exception($exception) if $exception; - $guard->commit if $guard; - return $count; } sub update { - my ($self, $source, @args) = @_; + my ($self, $source, @args) = @_; my $bind_attrs = $self->source_bind_attributes($source); @@ -1649,11 +1675,12 @@ sub _per_row_update_delete { my $row_cnt = '0E0'; my $subrs_cur = $rs->cursor; - while (my @pks = $subrs_cur->next) { + my @all_pk = $subrs_cur->all; + for my $pks ( @all_pk) { my $cond; for my $i (0.. $#pcols) { - $cond->{$pcols[$i]} = $pks[$i]; + $cond->{$pcols[$i]} = $pks->[$i]; } $self->$op ( @@ -1717,7 +1744,7 @@ sub _select_args { select => $select, from => $ident, where => $where, - $rs_alias + $rs_alias && $alias2source->{$rs_alias} ? ( _source_handle => $alias2source->{$rs_alias}->handle ) : () , @@ -1768,11 +1795,24 @@ sub _select_args { my @limit; - # see if we need to tear the prefetch apart (either limited has_many or grouped prefetch) - # otherwise delegate the limiting to the storage, unless software limit was requested + # see if we need to tear the prefetch apart otherwise delegate the limiting to the + # storage, unless software limit was requested if ( + #limited has_many ( $attrs->{rows} && keys %{$attrs->{collapse}} ) || + # limited prefetch with RNO subqueries + ( + $attrs->{rows} + && + $sql_maker->limit_dialect eq 'RowNumberOver' + && + $attrs->{_prefetch_select} + && + @{$attrs->{_prefetch_select}} + ) + || + # grouped prefetch ( $attrs->{group_by} && @{$attrs->{group_by}} @@ -1782,7 +1822,6 @@ sub _select_args { @{$attrs->{_prefetch_select}} ) ) { - ($ident, $select, $where, $attrs) = $self->_adjust_select_args_for_complex_prefetch ($ident, $select, $where, $attrs); } @@ -1823,6 +1862,9 @@ sub _select_args { push @limit, $attrs->{rows}, $attrs->{offset}; } + # try to simplify the joinmap further (prune unreferenced type-single joins) + $ident = $self->_prune_unused_joins ($ident, $select, $where, $attrs); + ### # This would be the point to deflate anything found in $where # (and leave $attrs->{bind} intact). Problem is - inflators historically @@ -2136,7 +2178,7 @@ sub is_datatype_numeric { } -=head2 create_ddl_dir (EXPERIMENTAL) +=head2 create_ddl_dir =over 4 @@ -2188,10 +2230,8 @@ hashref like the following { ignore_constraint_names => 0, # ... other options } -Note that this feature is currently EXPERIMENTAL and may not work correctly -across all databases, or fully handle complex relationships. - -WARNING: Please check all SQL files created, before applying them. +WARNING: You are strongly advised to check all SQL files created, before applying +them. =cut @@ -2532,7 +2572,8 @@ C<"$relname">. sub relname_to_table_alias { my ($self, $relname, $join_count) = @_; - my $alias = ($join_count > 1 ? join('_', $relname, $join_count) : $relname); + my $alias = ($join_count && $join_count > 1 ? + join('_', $relname, $join_count) : $relname); return $alias; }