Skip to content

Commit 6b19220

Browse files
authored
Merge pull request #26 from charsbar/fix/avoid_column_in_empty_list
Avoid SQL syntax error: column IN ()
2 parents eaa8c4c + 8c3e027 commit 6b19220

2 files changed

Lines changed: 95 additions & 6 deletions

File tree

lib/Data/ObjectDriver/SQL.pm

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -247,25 +247,65 @@ sub _mk_term {
247247
$term = join " $logic ", @terms;
248248
} else {
249249
$col = $m->($col) if $m = $stmt->column_mutator;
250-
$term = "$col IN (".join(',', ('?') x scalar @$val).')';
250+
$term = $stmt->_mk_term_arrayref($col, 'IN', $val);
251251
@bind = @$val;
252252
}
253253
} elsif (ref($val) eq 'HASH') {
254254
my $c = $val->{column} || $col;
255255
$c = $m->($c) if $m = $stmt->column_mutator;
256-
$term = "$c $val->{op} ?";
257-
push @bind, $val->{value};
256+
my $op = uc $val->{op};
257+
if (($op eq 'IN' or $op eq 'NOT IN') and ref $val->{value} eq 'ARRAY') {
258+
$term = $stmt->_mk_term_arrayref($c, $op, $val->{value});
259+
push @bind, @{$val->{value}};
260+
} elsif (($op eq 'IN' or $op eq 'NOT IN') and ref $val->{value} eq 'REF') {
261+
my @values = @{${$val->{value}}};
262+
$term = "$c $op (" . (shift @values) . ")";
263+
push @bind, @values;
264+
} elsif ($op eq 'BETWEEN' and ref $val->{value} eq 'ARRAY') {
265+
Carp::croak "USAGE: foo => {op => 'BETWEEN', value => [\$a, \$b]}" if @{$val->{value}} != 2;
266+
$term = "$c $op ? AND ?";
267+
push @bind, @{$val->{value}};
268+
} else {
269+
if (ref $val->{value} eq 'SCALAR') {
270+
$term = "$c $val->{op} " . ${$val->{value}};
271+
} else {
272+
$term = "$c $val->{op} ?";
273+
push @bind, $val->{value};
274+
}
275+
}
258276
} elsif (ref($val) eq 'SCALAR') {
259277
$col = $m->($col) if $m = $stmt->column_mutator;
260278
$term = "$col $$val";
279+
} elsif (ref($val) eq 'REF') {
280+
$col = $m->($col) if $m = $stmt->column_mutator;
281+
my @values = @{$$val};
282+
$term = "$col " . (shift @values);
283+
push @bind, @values;
261284
} else {
262285
$col = $m->($col) if $m = $stmt->column_mutator;
263-
$term = "$col = ?";
264-
push @bind, $val;
286+
if (defined $val) {
287+
$term = "$col = ?";
288+
push @bind, $val;
289+
} else {
290+
$term = "$col IS NULL";
291+
}
265292
}
266293
($term, \@bind, $col);
267294
}
268295

296+
sub _mk_term_arrayref {
297+
my ($stmt, $col, $op, $val) = @_;
298+
if (@$val) {
299+
return "$col $op (".join(',', ('?') x scalar @$val).')';
300+
} else {
301+
if ($op eq 'IN') {
302+
return '0 = 1';
303+
} elsif ($op eq 'NOT IN') {
304+
return '1 = 1';
305+
}
306+
}
307+
}
308+
269309
sub _add_index_hint {
270310
my $stmt = shift;
271311
my ($tbl_name) = @_;

t/11-sql.t

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use strict;
44

55
use Data::ObjectDriver::SQL;
6-
use Test::More tests => 68;
6+
use Test::More tests => 93;
77

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

131+
$stmt = ns(); $stmt->add_where(foo => { op => 'IN', value => ['bar'] });
132+
is($stmt->as_sql_where, "WHERE (foo IN (?))\n");
133+
is(scalar @{ $stmt->bind }, 1);
134+
is($stmt->bind->[0], 'bar');
135+
136+
$stmt = ns(); $stmt->add_where(foo => { op => 'NOT IN', value => ['bar'] });
137+
is($stmt->as_sql_where, "WHERE (foo NOT IN (?))\n");
138+
is(scalar @{ $stmt->bind }, 1);
139+
is($stmt->bind->[0], 'bar');
140+
141+
$stmt = ns(); $stmt->add_where(foo => { op => 'BETWEEN', value => ['bar', 'baz'] });
142+
is($stmt->as_sql_where, "WHERE (foo BETWEEN ? AND ?)\n");
143+
is(scalar @{ $stmt->bind }, 2);
144+
is($stmt->bind->[0], 'bar');
145+
is($stmt->bind->[1], 'baz');
146+
147+
$stmt = ns(); $stmt->add_where(foo => { op => 'LIKE', value => 'bar%' });
148+
is($stmt->as_sql_where, "WHERE (foo LIKE ?)\n");
149+
is(scalar @{ $stmt->bind }, 1);
150+
is($stmt->bind->[0], 'bar%');
151+
131152
$stmt = ns(); $stmt->add_where(foo => { op => '!=', value => 'bar' });
132153
is($stmt->as_sql_where, "WHERE (foo != ?)\n");
133154
is(scalar @{ $stmt->bind }, 1);
@@ -174,6 +195,34 @@ is($stmt->bind->[0], 'foo');
174195
is($stmt->bind->[1], 'bar');
175196
is($stmt->bind->[2], 'baz');
176197

198+
$stmt = ns();
199+
$stmt->add_where(foo => \['IN (SELECT foo FROM bar WHERE t=?)', 'foo']);
200+
is($stmt->as_sql_where, "WHERE (foo IN (SELECT foo FROM bar WHERE t=?))\n");
201+
is(scalar @{ $stmt->bind }, 1);
202+
is($stmt->bind->[0], 'foo');
203+
204+
$stmt = ns();
205+
$stmt->add_where(foo => { op => 'IN', value => \['(SELECT foo FROM bar WHERE t=?)', 'foo']});
206+
is($stmt->as_sql_where, "WHERE (foo IN ((SELECT foo FROM bar WHERE t=?)))\n");
207+
is(scalar @{ $stmt->bind }, 1);
208+
is($stmt->bind->[0], 'foo');
209+
210+
$stmt = ns();
211+
$stmt->add_where(foo => { op => 'IN', value => \'(SELECT foo FROM bar)'});
212+
is($stmt->as_sql_where, "WHERE (foo IN (SELECT foo FROM bar))\n");
213+
is(scalar @{ $stmt->bind }, 0);
214+
215+
$stmt = ns();
216+
$stmt->add_where(foo => undef);
217+
is($stmt->as_sql_where, "WHERE (foo IS NULL)\n");
218+
is(scalar @{ $stmt->bind }, 0);
219+
220+
## avoid syntax error
221+
$stmt = ns();
222+
$stmt->add_where(foo => []);
223+
is($stmt->as_sql_where, "WHERE (0 = 1)\n"); # foo IN ()
224+
is(scalar @{ $stmt->bind }, 0);
225+
177226
## regression bug. modified parameters
178227
my %terms = ( foo => [-and => 'foo', 'bar', 'baz']);
179228
$stmt = ns();

0 commit comments

Comments
 (0)