=cut
sub cursor {
- my ($self) = @_;
-
- my $attrs = $self->_resolved_attrs_copy;
+ my $self = shift;
- return $self->{cursor}
- ||= $self->result_source->storage->select($attrs->{from}, $attrs->{select},
- $attrs->{where},$attrs);
+ return $self->{cursor} ||= do {
+ my $attrs = { %{$self->_resolved_attrs } };
+ $self->result_source->storage->select(
+ $attrs->{from}, $attrs->{select}, $attrs->{where}, $attrs
+ );
+ };
}
=head2 single
$self->throw_exception('single() only takes search conditions, no attributes. You want ->search( $cond, $attrs )->single()');
}
- my $attrs = $self->_resolved_attrs_copy;
+ my $attrs = { %{$self->_resolved_attrs} };
if (keys %{$attrs->{collapse}}) {
$self->throw_exception(
return $self->search(@_)->count if @_ and defined $_[0];
return scalar @{ $self->get_cache } if $self->get_cache;
- my $attrs = $self->_resolved_attrs_copy;
+ my $attrs = { %{ $self->_resolved_attrs } };
# this is a little optimization - it is faster to do the limit
# adjustments in software, instead of a subquery
sub reset {
my ($self) = @_;
- delete $self->{_attrs} if exists $self->{_attrs};
$self->{all_cache_position} = 0;
$self->cursor->reset;
return $self;
my $attrs = { %{$self->_resolved_attrs} };
+ my $join_classifications;
my $existing_group_by = delete $attrs->{group_by};
- my $needs_subq = defined $existing_group_by;
- # simplify the joinmap and maybe decide if a subquery is necessary
- my $relation_classifications = {};
+ # do we need a subquery for any reason?
+ my $needs_subq = (
+ defined $existing_group_by
+ or
+ # if {from} is unparseable wrap a subq
+ ref($attrs->{from}) ne 'ARRAY'
+ or
+ # limits call for a subq
+ $self->_has_resolved_attr(qw/rows offset/)
+ );
- if (ref($attrs->{from}) eq 'ARRAY') {
- # if we already know we need a subq, no point of classifying relations
- if (!$needs_subq and @{$attrs->{from}} > 1) {
- $attrs->{from} = $storage->_prune_unused_joins ($attrs->{from}, $attrs->{select}, $cond, $attrs);
+ # simplify the joinmap, so we can further decide if a subq is necessary
+ if (!$needs_subq and @{$attrs->{from}} > 1) {
+ $attrs->{from} = $storage->_prune_unused_joins ($attrs->{from}, $attrs->{select}, $cond, $attrs);
- $relation_classifications = $storage->_resolve_aliastypes_from_select_args (
+ # check if there are any joins left after the prune
+ if ( @{$attrs->{from}} > 1 ) {
+ $join_classifications = $storage->_resolve_aliastypes_from_select_args (
[ @{$attrs->{from}}[1 .. $#{$attrs->{from}}] ],
$attrs->{select},
$cond,
$attrs
);
+
+ # any non-pruneable joins imply subq
+ $needs_subq = scalar keys %{ $join_classifications->{restricting} || {} };
}
}
- else {
- $needs_subq ||= 1; # if {from} is unparseable assume the worst
- }
+
+ # check if the head is composite (by now all joins are thrown out unless $needs_subq)
+ $needs_subq ||= (
+ (ref $attrs->{from}[0]) ne 'HASH'
+ or
+ ref $attrs->{from}[0]{ $attrs->{from}[0]{-alias} }
+ );
# do we need anything like a subquery?
- if (
- ! $needs_subq
- and
- ! keys %{ $relation_classifications->{restricting} || {} }
- and
- ! $self->_has_resolved_attr(qw/rows offset/) # limits call for a subq
- ) {
+ unless ($needs_subq) {
# 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. Tell SQLMaker to dequalify idents via a gross hack.
local $sqla->{_dequalify_idents} = 1;
\[ $sqla->_recurse_where($self->{cond}) ];
};
+
return $rsrc->storage->$op(
$rsrc,
$op eq 'update' ? $values : (),
);
}
elsif ($storage->_use_multicolumn_in) {
- # This is hideously ugly, but SQLA does not understand multicol IN expressions
- my $sql_maker = $storage->sql_maker;
- my ($sql, @bind) = @${$subrs->as_query};
- $sql = sprintf ('(%s) IN %s', # the as_query already comes with a set of parenthesis
- join (', ', map { $sql_maker->_quote ($_) } @$idcols),
- $sql,
- );
-
return $storage->$op (
$rsrc,
$op eq 'update' ? $values : (),
- \[$sql, @bind],
+ # no syntax for calling this properly yet
+ # !!! EXPERIMENTAL API !!! WILL CHANGE !!!
+ $storage->sql_maker->_where_op_multicolumn_in (
+ $idcols, # how do I convey a list of idents...? can binds reside on lhs?
+ $subrs->as_query
+ ),
);
}
else {
# if all else fails - get all primary keys and operate over a ORed set
# wrap in a transaction for consistency
- # this is where the group_by starts to matter
+ # this is where the group_by/multiplication starts to matter
if (
$existing_group_by
or
- keys %{ $relation_classifications->{multiplying} || {} }
+ keys %{ $join_classifications->{multiplying} || {} }
) {
# make sure if there is a supplied group_by it matches the columns compiled above
# perfectly. Anything else can not be sanely executed on most databases so croak
return unless @$data;
if(defined wantarray) {
- my @created;
- foreach my $item (@$data) {
- push(@created, $self->create($item));
- }
+ my @created = map { $self->create($_) } @$data;
return wantarray ? @created : \@created;
}
else {
## inherit the data locked in the conditions of the resultset
my ($rs_data) = $self->_merge_with_rscond({});
delete @{$rs_data}{@columns};
- my @inherit_cols = keys %$rs_data;
- my @inherit_data = values %$rs_data;
## do bulk insert on current row
$rsrc->storage->insert_bulk(
$rsrc,
- [@columns, @inherit_cols],
- [ map { [ @$_{@columns}, @inherit_data ] } @$data ],
+ [@columns, keys %$rs_data],
+ [ map { [ @$_{@columns}, values %$rs_data ] } @$data ],
);
## do the has_many relationships
sub as_query {
my $self = shift;
- my $attrs = $self->_resolved_attrs_copy;
+ my $attrs = { %{ $self->_resolved_attrs } };
# For future use:
#
=cut
sub current_source_alias {
- my ($self) = @_;
-
- return ($self->{attrs} || {})->{alias} || 'me';
+ return (shift->{attrs} || {})->{alias} || 'me';
}
=head2 as_subselect_rs
return {%$attrs, from => $from, seen_join => $seen};
}
-# too many times we have to do $attrs = { %{$self->_resolved_attrs} }
-sub _resolved_attrs_copy {
- my $self = shift;
- return { %{$self->_resolved_attrs (@_)} };
-}
-
sub _resolved_attrs {
my $self = shift;
return $self->{_attrs} if $self->{_attrs};