SQL-Abstract-More
view release on metacpan or search on metacpan
lib/SQL/Abstract/More.pm view on Meta::CPAN
# if right-associative, restore proper left-right order in pair
@_ = reverse @_ if $self->{join_assoc_right};
my ($left, $join_spec, $right) = @_;
# syntax for assembling all elements
my $syntax = $self->{join_syntax}{$join_spec->{operator}};
my ($sql, @bind);
{ no if $] ge '5.022000', warnings => 'redundant';
# because sprintf instructions may _intentionally_ omit %.. parameters
if ($join_spec->{using}) {
not $join_spec->{condition}
or puke "join specification has both {condition} and {using} fields";
$syntax =~ s/\bON\s+%s/USING (%s)/;
$sql = CORE::join ",", @{$join_spec->{using}};
}
elsif ($join_spec->{condition}) {
not $join_spec->{using}
or puke "join specification has both {condition} and {using} fields";
# compute the "ON" clause
($sql, @bind) = $self->where($join_spec->{condition});
$sql =~ s/^\s*WHERE\s+//;
# substitute left/right tables names for '%1$s', '%2$s'
$sql = sprintf $sql, $left->{name}, $right->{name};
}
# build the final sql
$sql = sprintf $syntax, $left->{sql}, $right->{sql}, $sql;
}
# add left/right bind parameters (if any) into the list
unshift @bind, @{$left->{bind}}, @{$right->{bind}};
# build result and return
my %result = (sql => $sql, bind => \@bind);
$result{name} = ($self->{join_assoc_right} ? $left : $right)->{name};
$result{aliased_tables} = $left->{aliased_tables};
foreach my $alias (keys %{$right->{aliased_tables}}) {
$result{aliased_tables}{$alias} = $right->{aliased_tables}{$alias};
}
return \%result;
}
#----------------------------------------------------------------------
# override of parent's "_where_field_IN"
#----------------------------------------------------------------------
sub _where_field_IN {
my ($self, $k, $op, $vals) = @_;
# special algorithm if the key is multi-columns (contains a multicols_sep)
if ($self->{multicols_sep}) {
my @cols = split m[$self->{multicols_sep}], $k;
if (@cols > 1) {
if ($self->{has_multicols_in_SQL}) {
# DBMS accepts special SQL syntax for multicolumns
return $self->_multicols_IN_through_SQL(\@cols, $op, $vals);
}
else {
# DBMS doesn't accept special syntax, so we must use boolean logic
return $self->_multicols_IN_through_boolean(\@cols, $op, $vals);
}
}
}
# special algorithm if the number of values exceeds the allowed maximum
my $max_members_IN = $self->{max_members_IN};
if ($max_members_IN && does($vals, 'ARRAY')
&& @$vals > $max_members_IN) {
my @vals = @$vals;
my @slices;
while (my @slice = splice(@vals, 0, $max_members_IN)) {
push @slices, \@slice;
}
my @clauses = map {{-$op, $_}} @slices;
my $connector = $op =~ /^not/i ? '-and' : '-or';
unshift @clauses, $connector;
my ($sql, @bind) = $self->where({$k => \@clauses});
$sql =~ s/\s*where\s*\((.*)\)/$1/i;
return ($sql, @bind);
}
# otherwise, call parent method
$vals = [@$vals] if blessed $vals; # because SQLA dies on blessed arrayrefs
return $self->next::method($k, $op, $vals);
}
sub _multicols_IN_through_SQL {
my ($self, $cols, $op, $vals) = @_;
# build initial sql
my $n_cols = @$cols;
my $sql_cols = CORE::join(',', map {$self->_quote($_)} @$cols);
my $sql = "($sql_cols) " . $self->_sqlcase($op);
# dispatch according to structure of $vals
return $self->_SWITCH_refkind($vals, {
ARRAYREF => sub { # list of tuples
# deal with special case of empty list (like the parent class)
my $n_tuples = @$vals;
if (!$n_tuples) {
my $sql = ($op =~ /\bnot\b/i) ? $self->{sqltrue} : $self->{sqlfalse};
return ($sql);
}
# otherwise, build SQL and bind values for the list of tuples
my @bind;
foreach my $val (@$vals) {
does($val, 'ARRAY')
or $val = [split m[$self->{multicols_sep}], $val];
( run in 1.639 second using v1.01-cache-2.11-cpan-71847e10f99 )