Skip to content

Commit

Permalink
Merge pull request #26 from charsbar/fix/avoid_column_in_empty_list
Browse files Browse the repository at this point in the history
Avoid SQL syntax error: column IN ()
  • Loading branch information
comewalk authored Mar 7, 2019
2 parents eaa8c4c + 8c3e027 commit 6b19220
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 6 deletions.
50 changes: 45 additions & 5 deletions lib/Data/ObjectDriver/SQL.pm
Original file line number Diff line number Diff line change
Expand Up @@ -247,25 +247,65 @@ sub _mk_term {
$term = join " $logic ", @terms;
} else {
$col = $m->($col) if $m = $stmt->column_mutator;
$term = "$col IN (".join(',', ('?') x scalar @$val).')';
$term = $stmt->_mk_term_arrayref($col, 'IN', $val);
@bind = @$val;
}
} elsif (ref($val) eq 'HASH') {
my $c = $val->{column} || $col;
$c = $m->($c) if $m = $stmt->column_mutator;
$term = "$c $val->{op} ?";
push @bind, $val->{value};
my $op = uc $val->{op};
if (($op eq 'IN' or $op eq 'NOT IN') and ref $val->{value} eq 'ARRAY') {
$term = $stmt->_mk_term_arrayref($c, $op, $val->{value});
push @bind, @{$val->{value}};
} elsif (($op eq 'IN' or $op eq 'NOT IN') and ref $val->{value} eq 'REF') {
my @values = @{${$val->{value}}};
$term = "$c $op (" . (shift @values) . ")";
push @bind, @values;
} elsif ($op eq 'BETWEEN' and ref $val->{value} eq 'ARRAY') {
Carp::croak "USAGE: foo => {op => 'BETWEEN', value => [\$a, \$b]}" if @{$val->{value}} != 2;
$term = "$c $op ? AND ?";
push @bind, @{$val->{value}};
} else {
if (ref $val->{value} eq 'SCALAR') {
$term = "$c $val->{op} " . ${$val->{value}};
} else {
$term = "$c $val->{op} ?";
push @bind, $val->{value};
}
}
} elsif (ref($val) eq 'SCALAR') {
$col = $m->($col) if $m = $stmt->column_mutator;
$term = "$col $$val";
} elsif (ref($val) eq 'REF') {
$col = $m->($col) if $m = $stmt->column_mutator;
my @values = @{$$val};
$term = "$col " . (shift @values);
push @bind, @values;
} else {
$col = $m->($col) if $m = $stmt->column_mutator;
$term = "$col = ?";
push @bind, $val;
if (defined $val) {
$term = "$col = ?";
push @bind, $val;
} else {
$term = "$col IS NULL";
}
}
($term, \@bind, $col);
}

sub _mk_term_arrayref {
my ($stmt, $col, $op, $val) = @_;
if (@$val) {
return "$col $op (".join(',', ('?') x scalar @$val).')';
} else {
if ($op eq 'IN') {
return '0 = 1';
} elsif ($op eq 'NOT IN') {
return '1 = 1';
}
}
}

sub _add_index_hint {
my $stmt = shift;
my ($tbl_name) = @_;
Expand Down
51 changes: 50 additions & 1 deletion t/11-sql.t
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use strict;

use Data::ObjectDriver::SQL;
use Test::More tests => 68;
use Test::More tests => 93;

my $stmt = ns();
ok($stmt, 'Created SQL object');
Expand Down Expand Up @@ -128,6 +128,27 @@ is(scalar @{ $stmt->bind }, 2);
is($stmt->bind->[0], 'bar');
is($stmt->bind->[1], 'baz');

$stmt = ns(); $stmt->add_where(foo => { op => 'IN', value => ['bar'] });
is($stmt->as_sql_where, "WHERE (foo IN (?))\n");
is(scalar @{ $stmt->bind }, 1);
is($stmt->bind->[0], 'bar');

$stmt = ns(); $stmt->add_where(foo => { op => 'NOT IN', value => ['bar'] });
is($stmt->as_sql_where, "WHERE (foo NOT IN (?))\n");
is(scalar @{ $stmt->bind }, 1);
is($stmt->bind->[0], 'bar');

$stmt = ns(); $stmt->add_where(foo => { op => 'BETWEEN', value => ['bar', 'baz'] });
is($stmt->as_sql_where, "WHERE (foo BETWEEN ? AND ?)\n");
is(scalar @{ $stmt->bind }, 2);
is($stmt->bind->[0], 'bar');
is($stmt->bind->[1], 'baz');

$stmt = ns(); $stmt->add_where(foo => { op => 'LIKE', value => 'bar%' });
is($stmt->as_sql_where, "WHERE (foo LIKE ?)\n");
is(scalar @{ $stmt->bind }, 1);
is($stmt->bind->[0], 'bar%');

$stmt = ns(); $stmt->add_where(foo => { op => '!=', value => 'bar' });
is($stmt->as_sql_where, "WHERE (foo != ?)\n");
is(scalar @{ $stmt->bind }, 1);
Expand Down Expand Up @@ -174,6 +195,34 @@ is($stmt->bind->[0], 'foo');
is($stmt->bind->[1], 'bar');
is($stmt->bind->[2], 'baz');

$stmt = ns();
$stmt->add_where(foo => \['IN (SELECT foo FROM bar WHERE t=?)', 'foo']);
is($stmt->as_sql_where, "WHERE (foo IN (SELECT foo FROM bar WHERE t=?))\n");
is(scalar @{ $stmt->bind }, 1);
is($stmt->bind->[0], 'foo');

$stmt = ns();
$stmt->add_where(foo => { op => 'IN', value => \['(SELECT foo FROM bar WHERE t=?)', 'foo']});
is($stmt->as_sql_where, "WHERE (foo IN ((SELECT foo FROM bar WHERE t=?)))\n");
is(scalar @{ $stmt->bind }, 1);
is($stmt->bind->[0], 'foo');

$stmt = ns();
$stmt->add_where(foo => { op => 'IN', value => \'(SELECT foo FROM bar)'});
is($stmt->as_sql_where, "WHERE (foo IN (SELECT foo FROM bar))\n");
is(scalar @{ $stmt->bind }, 0);

$stmt = ns();
$stmt->add_where(foo => undef);
is($stmt->as_sql_where, "WHERE (foo IS NULL)\n");
is(scalar @{ $stmt->bind }, 0);

## avoid syntax error
$stmt = ns();
$stmt->add_where(foo => []);
is($stmt->as_sql_where, "WHERE (0 = 1)\n"); # foo IN ()
is(scalar @{ $stmt->bind }, 0);

## regression bug. modified parameters
my %terms = ( foo => [-and => 'foo', 'bar', 'baz']);
$stmt = ns();
Expand Down

0 comments on commit 6b19220

Please sign in to comment.