SQL-Abstract-More
view release on metacpan or search on metacpan
lib/SQL/Abstract/More.pm view on Meta::CPAN
my $regex = qr/' # initial quote
( # begin capturing group
[^']* # any non-quote chars
(?: # begin non-capturing group
'' # pair of quotes
[^']* # any non-quote chars
)* # this non-capturing group 0 or more times
) # end of capturing group
' # ending quote
/x;
my $placeholder = '_?_'; # unlikely to be counfounded with any value
my @constants;
while ($cond_list =~ s/$regex/$placeholder/) {
push @constants, $1;
};
s/''/'/g for @constants; # replace pairs of quotes by single quotes
# accumulate conditions as pairs ($left => \"$op $right")
my @conditions;
my @using;
foreach my $cond (split /,\s*/, $cond_list) {
# parse the condition (left and right operands + comparison operator)
my ($left, $cmp, $right) = split /([<>=!^]{1,2})/, $cond;
if ($cmp && $right) {
# if operands are not qualified by table/alias name, add sprintf hooks
$left = '%1$s.' . $left unless $left =~ /\./;
$right = '%2$s.' . $right unless $right =~ /\./ or $right eq $placeholder;
# add this pair into the list; right operand is either a bind value
# or an identifier within the right table
$right = $right eq $placeholder ? shift @constants : {-ident => $right};
push @conditions, $left, {$cmp => $right};
}
elsif ($cond =~ /^\w+$/) {
push @using, $cond;
}
else {puke "can't parse join condition: $cond"}
}
# build join hashref
my $join_hash = {operator => $op};
$join_hash->{using} = \@using if @using;
$join_hash->{condition}
= $bracket eq '[' ? [@conditions] : {@conditions} if @conditions;
return $join_hash;
}
sub _single_join {
my $self = shift;
# 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);
}
}
( run in 0.461 second using v1.01-cache-2.11-cpan-ff9377addf4 )