From e7871f47c7f61a211002ef6a15d760a01976a9d5 Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Thu, 7 Feb 2019 17:59:11 +0900 Subject: [PATCH 01/10] Avoid SQL syntax error: column IN () --- lib/Data/ObjectDriver/SQL.pm | 5 ++++- t/11-sql.t | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/Data/ObjectDriver/SQL.pm b/lib/Data/ObjectDriver/SQL.pm index 068d39e..2ba230e 100644 --- a/lib/Data/ObjectDriver/SQL.pm +++ b/lib/Data/ObjectDriver/SQL.pm @@ -245,10 +245,13 @@ sub _mk_term { push @bind, @$bind; } $term = join " $logic ", @terms; - } else { + } elsif (@$val) { $col = $m->($col) if $m = $stmt->column_mutator; $term = "$col IN (".join(',', ('?') x scalar @$val).')'; @bind = @$val; + } else { + # TODO: column NOT IN () + $term = "0 = 1"; # column IN () } } elsif (ref($val) eq 'HASH') { my $c = $val->{column} || $col; diff --git a/t/11-sql.t b/t/11-sql.t index 38c4666..2877142 100644 --- a/t/11-sql.t +++ b/t/11-sql.t @@ -3,7 +3,7 @@ use strict; use Data::ObjectDriver::SQL; -use Test::More tests => 68; +use Test::More tests => 70; my $stmt = ns(); ok($stmt, 'Created SQL object'); @@ -174,6 +174,12 @@ is($stmt->bind->[0], 'foo'); is($stmt->bind->[1], 'bar'); is($stmt->bind->[2], 'baz'); +## 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(); From 9fef4aa47e70414d66a5d7cb9085497b0351202e Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Tue, 19 Feb 2019 11:03:36 +0900 Subject: [PATCH 02/10] Take out a code to handle IN (...) from _mt_term for later reuse --- lib/Data/ObjectDriver/SQL.pm | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/Data/ObjectDriver/SQL.pm b/lib/Data/ObjectDriver/SQL.pm index 2ba230e..de73ed6 100644 --- a/lib/Data/ObjectDriver/SQL.pm +++ b/lib/Data/ObjectDriver/SQL.pm @@ -245,13 +245,10 @@ sub _mk_term { push @bind, @$bind; } $term = join " $logic ", @terms; - } elsif (@$val) { + } 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; - } else { - # TODO: column NOT IN () - $term = "0 = 1"; # column IN () } } elsif (ref($val) eq 'HASH') { my $c = $val->{column} || $col; @@ -269,6 +266,19 @@ sub _mk_term { ($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) = @_; From 1cc13b556318bfeff06bc95e8d07dc671709e202 Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Tue, 19 Feb 2019 11:07:15 +0900 Subject: [PATCH 03/10] Support (foo => { op => IN, value => [...] }) --- lib/Data/ObjectDriver/SQL.pm | 10 ++++++++-- t/11-sql.t | 12 +++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/Data/ObjectDriver/SQL.pm b/lib/Data/ObjectDriver/SQL.pm index de73ed6..171a80c 100644 --- a/lib/Data/ObjectDriver/SQL.pm +++ b/lib/Data/ObjectDriver/SQL.pm @@ -253,8 +253,14 @@ sub _mk_term { } 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}}; + } 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"; diff --git a/t/11-sql.t b/t/11-sql.t index 2877142..e940199 100644 --- a/t/11-sql.t +++ b/t/11-sql.t @@ -3,7 +3,7 @@ use strict; use Data::ObjectDriver::SQL; -use Test::More tests => 70; +use Test::More tests => 76; my $stmt = ns(); ok($stmt, 'Created SQL object'); @@ -128,6 +128,16 @@ 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 => '!=', value => 'bar' }); is($stmt->as_sql_where, "WHERE (foo != ?)\n"); is(scalar @{ $stmt->bind }, 1); From a1088b398ebc0a19d3f9ccaa261cd2fa2db4f03e Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Tue, 19 Feb 2019 11:11:53 +0900 Subject: [PATCH 04/10] Support (foo => { op => "IN", value => \["(SELECT ...)"] }) --- lib/Data/ObjectDriver/SQL.pm | 4 ++++ t/11-sql.t | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/Data/ObjectDriver/SQL.pm b/lib/Data/ObjectDriver/SQL.pm index 171a80c..f2855c0 100644 --- a/lib/Data/ObjectDriver/SQL.pm +++ b/lib/Data/ObjectDriver/SQL.pm @@ -257,6 +257,10 @@ sub _mk_term { 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; } else { $term = "$c $val->{op} ?"; push @bind, $val->{value}; diff --git a/t/11-sql.t b/t/11-sql.t index e940199..dde28c5 100644 --- a/t/11-sql.t +++ b/t/11-sql.t @@ -3,7 +3,7 @@ use strict; use Data::ObjectDriver::SQL; -use Test::More tests => 76; +use Test::More tests => 79; my $stmt = ns(); ok($stmt, 'Created SQL object'); @@ -184,6 +184,12 @@ is($stmt->bind->[0], 'foo'); is($stmt->bind->[1], 'bar'); is($stmt->bind->[2], 'baz'); +$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'); + ## avoid syntax error $stmt = ns(); $stmt->add_where(foo => []); From 77de9d8d1bece3eb1b44ee5aa3c7a49fab2f5ff3 Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Tue, 19 Feb 2019 11:14:06 +0900 Subject: [PATCH 05/10] Support (foo => \["IN (SELECT ...)"]) as well --- lib/Data/ObjectDriver/SQL.pm | 4 ++++ t/11-sql.t | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/Data/ObjectDriver/SQL.pm b/lib/Data/ObjectDriver/SQL.pm index f2855c0..b7bbfa5 100644 --- a/lib/Data/ObjectDriver/SQL.pm +++ b/lib/Data/ObjectDriver/SQL.pm @@ -268,6 +268,10 @@ sub _mk_term { } elsif (ref($val) eq 'SCALAR') { $col = $m->($col) if $m = $stmt->column_mutator; $term = "$col $$val"; + } elsif (ref($val) eq 'REF') { + my @values = @{$$val}; + $term = "$col " . (shift @values); + push @bind, @values; } else { $col = $m->($col) if $m = $stmt->column_mutator; $term = "$col = ?"; diff --git a/t/11-sql.t b/t/11-sql.t index dde28c5..5fe5723 100644 --- a/t/11-sql.t +++ b/t/11-sql.t @@ -3,7 +3,7 @@ use strict; use Data::ObjectDriver::SQL; -use Test::More tests => 79; +use Test::More tests => 82; my $stmt = ns(); ok($stmt, 'Created SQL object'); @@ -184,6 +184,12 @@ 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"); From 3b4ba67db0fa0ea5370c0acedf196d0eceb6a663 Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Tue, 19 Feb 2019 11:18:00 +0900 Subject: [PATCH 06/10] Support (foo => {op => "BETWEEN", value => [$a, $b]}) --- lib/Data/ObjectDriver/SQL.pm | 4 ++++ t/11-sql.t | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/Data/ObjectDriver/SQL.pm b/lib/Data/ObjectDriver/SQL.pm index b7bbfa5..7fd7ce5 100644 --- a/lib/Data/ObjectDriver/SQL.pm +++ b/lib/Data/ObjectDriver/SQL.pm @@ -261,6 +261,10 @@ sub _mk_term { 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 { $term = "$c $val->{op} ?"; push @bind, $val->{value}; diff --git a/t/11-sql.t b/t/11-sql.t index 5fe5723..cabbcab 100644 --- a/t/11-sql.t +++ b/t/11-sql.t @@ -3,7 +3,7 @@ use strict; use Data::ObjectDriver::SQL; -use Test::More tests => 82; +use Test::More tests => 86; my $stmt = ns(); ok($stmt, 'Created SQL object'); @@ -138,6 +138,12 @@ 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 => '!=', value => 'bar' }); is($stmt->as_sql_where, "WHERE (foo != ?)\n"); is(scalar @{ $stmt->bind }, 1); From acc7b17fcdf6c0b435277c4cf7f1cfffed510e43 Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Tue, 19 Feb 2019 11:18:58 +0900 Subject: [PATCH 07/10] Fix (foo = NULL) --- lib/Data/ObjectDriver/SQL.pm | 8 ++++++-- t/11-sql.t | 7 ++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/Data/ObjectDriver/SQL.pm b/lib/Data/ObjectDriver/SQL.pm index 7fd7ce5..2c14e38 100644 --- a/lib/Data/ObjectDriver/SQL.pm +++ b/lib/Data/ObjectDriver/SQL.pm @@ -278,8 +278,12 @@ sub _mk_term { 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); } diff --git a/t/11-sql.t b/t/11-sql.t index cabbcab..5f37496 100644 --- a/t/11-sql.t +++ b/t/11-sql.t @@ -3,7 +3,7 @@ use strict; use Data::ObjectDriver::SQL; -use Test::More tests => 86; +use Test::More tests => 88; my $stmt = ns(); ok($stmt, 'Created SQL object'); @@ -202,6 +202,11 @@ 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 => 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 => []); From 5e87eeb6b556234ee70d222fb010ecc5963ea96a Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Tue, 19 Feb 2019 11:24:05 +0900 Subject: [PATCH 08/10] Support (foo => {op => "IN", value => \"(SELECT ...)"}) --- lib/Data/ObjectDriver/SQL.pm | 8 ++++++-- t/11-sql.t | 7 ++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/Data/ObjectDriver/SQL.pm b/lib/Data/ObjectDriver/SQL.pm index 2c14e38..ac1ad63 100644 --- a/lib/Data/ObjectDriver/SQL.pm +++ b/lib/Data/ObjectDriver/SQL.pm @@ -266,8 +266,12 @@ sub _mk_term { $term = "$c $op ? AND ?"; push @bind, @{$val->{value}}; } else { - $term = "$c $val->{op} ?"; - push @bind, $val->{value}; + 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; diff --git a/t/11-sql.t b/t/11-sql.t index 5f37496..6ffce99 100644 --- a/t/11-sql.t +++ b/t/11-sql.t @@ -3,7 +3,7 @@ use strict; use Data::ObjectDriver::SQL; -use Test::More tests => 88; +use Test::More tests => 90; my $stmt = ns(); ok($stmt, 'Created SQL object'); @@ -202,6 +202,11 @@ 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"); From 5535fc046751bbfd7b549462d77d58b8ae65b9eb Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Tue, 19 Feb 2019 11:24:44 +0900 Subject: [PATCH 09/10] Add a test for (foo => {op => "LIKE", value => "..."}) --- t/11-sql.t | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/t/11-sql.t b/t/11-sql.t index 6ffce99..d82ee2e 100644 --- a/t/11-sql.t +++ b/t/11-sql.t @@ -3,7 +3,7 @@ use strict; use Data::ObjectDriver::SQL; -use Test::More tests => 90; +use Test::More tests => 93; my $stmt = ns(); ok($stmt, 'Created SQL object'); @@ -144,6 +144,11 @@ 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); From 8c3e027bba9fe95d327b373ab46d2a207fc0e093 Mon Sep 17 00:00:00 2001 From: Kenichi Ishigaki Date: Thu, 7 Mar 2019 14:04:54 +0900 Subject: [PATCH 10/10] Apply column_mutator (@usualoma++) --- lib/Data/ObjectDriver/SQL.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Data/ObjectDriver/SQL.pm b/lib/Data/ObjectDriver/SQL.pm index ac1ad63..e6d72b5 100644 --- a/lib/Data/ObjectDriver/SQL.pm +++ b/lib/Data/ObjectDriver/SQL.pm @@ -277,6 +277,7 @@ sub _mk_term { $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;