X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FStorage%2FDBI.pm;h=1288c4785f687532192d98ffe667ff97a47b2bc7;hb=e92e86369d8d655c5d62940e9cbd4ed93e4c7985;hp=aab6f31c9bca84130d19d37d659eb7194ffbd98a;hpb=12b79b7c35d74e69a9d385b66287058d2b4befda;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Storage/DBI.pm b/lib/DBIx/Class/Storage/DBI.pm index aab6f31..1288c47 100644 --- a/lib/DBIx/Class/Storage/DBI.pm +++ b/lib/DBIx/Class/Storage/DBI.pm @@ -14,6 +14,7 @@ use DBIx::Class::Storage::Statistics; use Scalar::Util(); use List::Util(); use Data::Dumper::Concise(); +use Sub::Name (); # what version of sqlt do we require if deploy() without a ddl_dir is invoked # when changing also adjust the corresponding author_require in Makefile.PL @@ -63,7 +64,7 @@ for my $meth (@rdbms_specific_methods) { no strict qw/refs/; no warnings qw/redefine/; - *{__PACKAGE__ ."::$meth"} = sub { + *{__PACKAGE__ ."::$meth"} = Sub::Name::subname $meth => sub { if (not $_[0]->_driver_determined) { $_[0]->_determine_driver; goto $_[0]->can($meth); @@ -1549,48 +1550,25 @@ sub _dbh_execute_inserts_with_no_binds { } sub update { - my ($self, $source, $data, $where, @args) = @_; + my ($self, $source, @args) = @_; my $bind_attrs = $self->source_bind_attributes($source); - $where = $self->_strip_cond_qualifiers ($where); - return $self->_execute('update' => [], $source, $bind_attrs, $data, $where, @args); + return $self->_execute('update' => [], $source, $bind_attrs, @args); } sub delete { - my ($self, $source, $where, @args) = @_; + my ($self, $source, @args) = @_; my $bind_attrs = $self->source_bind_attributes($source); - $where = $self->_strip_cond_qualifiers ($where); - return $self->_execute('delete' => [], $source, $bind_attrs, $where, @args); -} - -# Most databases do not allow aliasing of tables in UPDATE/DELETE. Thus -# a condition containing 'me' or other table prefixes will not work -# at all. Since we employ subqueries when multiple tables are involved -# (joins), it is relatively safe to strip all column qualifiers. Worst -# case scenario the error message will be a bit misleading, if the -# user supplies a foreign qualifier without a join (the message would -# be "can't find column X", when in fact the user shoud join T containing -# T.X) -sub _strip_cond_qualifiers { - my ($self, $where) = @_; - - my $sqlmaker = $self->sql_maker; - my ($sql, @bind) = $sqlmaker->_recurse_where($where); - return undef unless $sql; - - my ($qquot, $qsep) = map { quotemeta $_ } ( ($sqlmaker->quote_char||''), ($sqlmaker->name_sep||'.') ); - $sql =~ s/ (?: $qquot [\w\-]+ $qquot | [\w\-]+ ) $qsep //gx; - - return \[$sql, @bind]; + return $self->_execute('delete' => [], $source, $bind_attrs, @args); } # We were sent here because the $rs contains a complex search # which will require a subquery to select the correct rows -# (i.e. joined or limited resultsets) +# (i.e. joined or limited resultsets, or non-introspectable conditions) # # Generating a single PK column subquery is trivial and supported # by all RDBMS. However if we have a multicolumn PK, things get ugly. @@ -1601,14 +1579,27 @@ sub _subq_update_delete { my $rsrc = $rs->result_source; - # we already check this, but double check naively just in case. Should be removed soon + # quick check if we got a sane rs on our hands + my @pcols = $rsrc->primary_columns; + unless (@pcols) { + $self->throw_exception ( + sprintf ( + "You must declare primary key(s) on source '%s' (via set_primary_key) in order to update or delete complex resultsets", + $rsrc->source_name || $rsrc->from + ) + ); + } + my $sel = $rs->_resolved_attrs->{select}; $sel = [ $sel ] unless ref $sel eq 'ARRAY'; - my @pcols = $rsrc->primary_columns; - if (@$sel != @pcols) { + + if ( + join ("\x00", map { join '.', $rs->{attrs}{alias}, $_ } sort @pcols) + ne + join ("\x00", sort @$sel ) + ) { $self->throw_exception ( - 'Subquery update/delete can not be called on resultsets selecting a' - .' number of columns different than the number of primary keys' + '_subq_update_delete can not be called on resultsets selecting columns other than the primary keys' ); } @@ -2009,7 +2000,7 @@ sub last_insert_id { This API is B, will almost definitely change in the future, and currently only used by L<::AutoCast|DBIx::Class::Storage::DBI::AutoCast> and -L<::Sybase|DBIx::Class::Storage::DBI::Sybase>. +L<::Sybase::ASE|DBIx::Class::Storage::DBI::Sybase::ASE>. The default implementation returns C, implement in your Storage driver if you need this functionality.