Review of
61f031bf made it clear that in order to make this work properly
pretty much the entire sqla logic will need to be replicated. So instead
the hacky approach was taken to abuse a botched version of SQLA which
is guaranteed to parse its own command tree correctly :)
my $rsrc = $self->result_source;
- # if a condition exists we need to strip all table qualifiers
- # if this is not possible we'll force a subquery below
- my $cond = $rsrc->schema->storage->_strip_cond_qualifiers ($self->{cond});
-
my $needs_group_by_subq = $self->_has_resolved_attr (qw/collapse group_by -join/);
- my $needs_subq = $needs_group_by_subq || (not defined $cond) || $self->_has_resolved_attr(qw/rows offset/);
+ my $needs_subq = $needs_group_by_subq || $self->_has_resolved_attr(qw/rows offset/);
if ($needs_group_by_subq or $needs_subq) {
return $self->result_source->storage->_subq_update_delete($subrs, $op, $values);
}
else {
+ # 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. What this code tries to do (badly) is to generate a condition
+ # with the qualifiers removed, by exploiting the quote mechanism of sqla
+ #
+ # this is atrocious and should be replaced by normal sqla introspection
+ # one sunny day
+ my ($sql, @bind) = do {
+ my $sqla = $rsrc->storage->sql_maker;
+ local $sqla->{_dequalify_idents} = 1;
+ $sqla->_recurse_where($self->{cond});
+ } if $self->{cond};
+
return $rsrc->storage->$op(
$rsrc,
$op eq 'update' ? $values : (),
- $cond,
+ $self->{cond} ? \[$sql, @bind] : (),
);
}
}
# as the value to abuse with MSSQL ordered subqueries)
sub __max_int () { 0x7FFFFFFF };
+# poor man's de-qualifier
+sub _quote {
+ $_[0]->next::method( ( $_[0]{_dequalify_idents} and ! ref $_[1] )
+ ? $_[1] =~ / ([^\.]+) $ /x
+ : $_[1]
+ );
+}
+
sub new {
my $self = shift->next::method(@_);
return \@new_from;
}
-# 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. What this code tries to do (badly) is introspect the condition
-# and remove all column qualifiers. If it bails out early (returns undef)
-# the calling code should try another approach (e.g. a subquery)
-
-sub _strip_cond_qualifiers_from_array {
- my ($self, $where) = @_;
- my @cond;
- for (my $i = 0; $i < @$where; $i++) {
- my $entry = $where->[$i];
- my $hash;
- my $ref = ref $entry;
- if ($ref eq 'HASH' or $ref eq 'ARRAY') {
- $hash = $self->_strip_cond_qualifiers($entry);
- }
- elsif (! $ref) {
- $entry =~ /([^.]+)$/;
- $hash->{$1} = $where->[++$i];
- }
- push @cond, $hash;
- }
- return \@cond;
-}
-
-sub _strip_cond_qualifiers {
- my ($self, $where) = @_;
-
- my $cond = {};
-
- # No-op. No condition, we're updating/deleting everything
- return $cond unless $where;
-
- if (ref $where eq 'ARRAY') {
- $cond = $self->_strip_cond_qualifiers_from_array($where);
- }
- elsif (ref $where eq 'HASH') {
- if ( (keys %$where) == 1 && ( (keys %{$where})[0] eq '-and' )) {
- $cond->{-and} =
- $self->_strip_cond_qualifiers_from_array($where->{-and});
- }
- else {
- foreach my $key (keys %$where) {
- if ($key eq '-or' && ref $where->{$key} eq 'ARRAY') {
- $cond->{$key} = $self->_strip_cond_qualifiers($where->{$key});
- }
- else {
- $key =~ /([^.]+)$/;
- $cond->{$1} = $where->{$key};
- }
- }
- }
- }
- else {
- return undef;
- }
-
- return $cond;
-}
-
sub _extract_order_criteria {
my ($self, $order_by, $sql_maker) = @_;