X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=t%2F01generate.t;h=7e641f7448f172c41b6623c5d209c10e3d0fc9fe;hb=5eccd8f08ffd024b337650369ba4afadc05bd5bf;hp=5d68e1f0e0ab0ab5155343f5248583389c5b0da7;hpb=970841131ca052eb8d4762dfd7a21205e24013aa;p=dbsrgits%2FSQL-Abstract.git diff --git a/t/01generate.t b/t/01generate.t index 5d68e1f..7e641f7 100644 --- a/t/01generate.t +++ b/t/01generate.t @@ -4,7 +4,7 @@ use Test::More; use Test::Warn; use Test::Exception; -use SQL::Abstract::Test import => ['is_same_sql_bind']; +use SQL::Abstract::Test import => [qw( is_same_sql_bind diag_where dumper )]; use SQL::Abstract; @@ -69,20 +69,6 @@ my @tests = ( }, { func => 'select', - args => [[qw/test1 test2/], '*', { 'test1.a' => { 'In', ['boom', 'bang'] } }], - stmt => 'SELECT * FROM test1, test2 WHERE ( test1.a IN ( ?, ? ) )', - stmt_q => 'SELECT * FROM `test1`, `test2` WHERE ( `test1`.`a` IN ( ?, ? ) )', - bind => ['boom', 'bang'] - }, - { - func => 'select', - args => ['test', '*', { a => { 'between', ['boom', 'bang'] } }], - stmt => 'SELECT * FROM test WHERE ( a BETWEEN ? AND ? )', - stmt_q => 'SELECT * FROM `test` WHERE ( `a` BETWEEN ? AND ? )', - bind => ['boom', 'bang'] - }, - { - func => 'select', args => ['test', '*', { a => { '!=', 'boom' } }], stmt => 'SELECT * FROM test WHERE ( a != ? )', stmt_q => 'SELECT * FROM `test` WHERE ( `a` != ? )', @@ -232,6 +218,8 @@ my @tests = ( tasty => { '!=', [qw(yes YES)] }, -nest => [ face => [ -or => {'=', 'mr.happy'}, {'=', undef} ] ] }, ], + warns => qr/\QA multi-element arrayref as an argument to the inequality op '!=' is technically equivalent to an always-true 1=1/, + stmt => 'UPDATE taco_punches SET one = ?, three = ? WHERE ( ( ( ( ( face = ? ) OR ( face IS NULL ) ) ) )' . ' AND ( ( bland != ? ) AND ( bland != ? ) ) AND ( ( tasty != ? ) OR ( tasty != ? ) ) )', stmt_q => 'UPDATE `taco_punches` SET `one` = ?, `three` = ? WHERE ( ( ( ( ( `face` = ? ) OR ( `face` IS NULL ) ) ) )' @@ -416,6 +404,11 @@ my @tests = ( }, { func => 'select', + args => ['test', '*', { foo => { '>=' => [] }} ], + throws => qr/\Qoperator '>=' applied on an empty array (field 'foo')/, + }, + { + func => 'select', new => {bindtype => 'columns'}, args => ['test', '*', { a => {-in => \["(SELECT d FROM to_date(?, 'MM/DD/YY') AS d)", [dummy => '02/02/02']]}, b => 8 }], stmt => 'SELECT * FROM test WHERE ( a IN (SELECT d FROM to_date(?, \'MM/DD/YY\') AS d) AND b = ? )', @@ -529,53 +522,115 @@ my @tests = ( }, { func => 'select', - args => ['test', '*', { a => { -in => [] }, b => { -not_in => [] }, c => { -in => 42 } }], - stmt => 'SELECT * FROM test WHERE ( 0=1 AND 1=1 AND c IN ( ? ))', - stmt_q => 'SELECT * FROM `test` WHERE ( 0=1 AND 1=1 AND `c` IN ( ? ))', - bind => [ 42 ], + args => ['test', '*', { a => { '=' => undef }, b => { -is => undef }, c => { -like => undef } }], + stmt => 'SELECT * FROM test WHERE ( a IS NULL AND b IS NULL AND c IS NULL )', + stmt_q => 'SELECT * FROM `test` WHERE ( `a` IS NULL AND `b` IS NULL AND `c` IS NULL )', + bind => [], + warns => qr/\QSupplying an undefined argument to 'LIKE' is deprecated/, }, { func => 'select', - args => ['test', '*', { a => { -in => [] }, b => { -not_in => [] } }], - stmt => 'SELECT * FROM test WHERE ( 0=1 AND 1=1 )', - stmt_q => 'SELECT * FROM `test` WHERE ( 0=1 AND 1=1 )', + args => ['test', '*', { a => { '!=' => undef }, b => { -is_not => undef }, c => { -not_like => undef } }], + stmt => 'SELECT * FROM test WHERE ( a IS NOT NULL AND b IS NOT NULL AND c IS NOT NULL )', + stmt_q => 'SELECT * FROM `test` WHERE ( `a` IS NOT NULL AND `b` IS NOT NULL AND `c` IS NOT NULL )', bind => [], + warns => qr/\QSupplying an undefined argument to 'NOT LIKE' is deprecated/, }, { - throws => qr/ - \QSQL::Abstract before v1.75 used to generate incorrect SQL \E - \Qwhen the -IN operator was given an undef-containing list: \E - \Q!!!AUDIT YOUR CODE AND DATA!!! (the upcoming Data::Query-based \E - \Qversion of SQL::Abstract will emit the logically correct SQL \E - \Qinstead of raising this exception)\E - /x, func => 'select', - args => ['test', '*', { a => { -in => [42, undef] }, b => { -not_in => [42, undef] } } ], - stmt => 'SELECT * FROM test WHERE ( ( a IN ( ? ) OR a IS NULL ) AND b NOT IN ( ? ) AND b IS NOT NULL )', - stmt_q => 'SELECT * FROM `test` WHERE ( ( `a` IN ( ? ) OR `a` IS NULL ) AND `b` NOT IN ( ? ) AND `b` IS NOT NULL )', - bind => [ 42, 42 ], - }, - { - throws => qr/ - \QSQL::Abstract before v1.75 used to generate incorrect SQL \E - \Qwhen the -IN operator was given an undef-containing list: \E - \Q!!!AUDIT YOUR CODE AND DATA!!! (the upcoming Data::Query-based \E - \Qversion of SQL::Abstract will emit the logically correct SQL \E - \Qinstead of raising this exception)\E - /x, - func => 'select', - args => ['test', '*', { a => { -in => [undef] }, b => { -not_in => [undef] } } ], - stmt => 'SELECT * FROM test WHERE ( a IS NULL AND b IS NOT NULL )', - stmt_q => 'SELECT * FROM `test` WHERE ( `a` IS NULL AND `b` IS NOT NULL )', + args => ['test', '*', { a => { IS => undef }, b => { LIKE => undef } }], + stmt => 'SELECT * FROM test WHERE ( a IS NULL AND b IS NULL )', + stmt_q => 'SELECT * FROM `test` WHERE ( `a` IS NULL AND `b` IS NULL )', bind => [], + warns => qr/\QSupplying an undefined argument to 'LIKE' is deprecated/, }, { func => 'select', - args => ['test', '*', { a => { -in => undef } }], - throws => qr/Argument passed to the 'IN' operator can not be undefined/, + args => ['test', '*', { a => { 'IS NOT' => undef }, b => { 'NOT LIKE' => undef } }], + stmt => 'SELECT * FROM test WHERE ( a IS NOT NULL AND b IS NOT NULL )', + stmt_q => 'SELECT * FROM `test` WHERE ( `a` IS NOT NULL AND `b` IS NOT NULL )', + bind => [], + warns => qr/\QSupplying an undefined argument to 'NOT LIKE' is deprecated/, }, ); +# check is( not) => undef +for my $op (qw( is is_not), 'is not' ) { + (my $sop = uc $op) =~ s/_/ /gi; + + push @tests, { + func => 'where', + args => [{ a => { "$_$op" => undef } }], + stmt => "WHERE a $sop NULL", + stmt_q => "WHERE `a` $sop NULL", + bind => [], + } for ('', '-'); # with and without - +} + +# check single-element inequality ops for no warnings +for my $op ( qw(!= <>) ) { + for my $val (undef, 42) { + push @tests, { + func => 'where', + args => [ { x => { "$_$op" => [ $val ] } } ], + stmt => "WHERE x " . ($val ? "$op ?" : 'IS NOT NULL'), + stmt_q => "WHERE `x` " . ($val ? "$op ?" : 'IS NOT NULL'), + bind => [ $val || () ], + } for ('', '-'); # with and without - + } +} + +# check single-element not-like ops for no warnings, and NULL exception +# (the last two "is not X" are a weird syntax, but mebbe a dialect...) +for my $op (qw(not_like not_rlike), 'not like', 'not rlike', 'is not like','is not rlike') { + (my $sop = uc $op) =~ s/_/ /gi; + + for my $val (undef, 42) { + push @tests, { + func => 'where', + args => [ { x => { "$_$op" => [ $val ] } } ], + $val ? ( + stmt => "WHERE x $sop ?", + stmt_q => "WHERE `x` $sop ?", + bind => [ $val ], + ) : ( + stmt => "WHERE x IS NOT NULL", + stmt_q => "WHERE `x` IS NOT NULL", + bind => [], + warns => qr/\QSupplying an undefined argument to '$sop' is deprecated/, + ), + } for ('', '-'); # with and without - + } +} + +# check all multi-element inequality/not-like ops for warnings +for my $op ( qw(!= <> not_like not_rlike), 'not like', 'not rlike', 'is not like','is not rlike') { + (my $sop = uc $op) =~ s/_/ /gi; + + push @tests, { + func => 'where', + args => [ { x => { "$_$op" => [ 42, 69 ] } } ], + stmt => "WHERE x $sop ? OR x $sop ?", + stmt_q => "WHERE `x` $sop ? OR `x` $sop ?", + bind => [ 42, 69 ], + warns => qr/\QA multi-element arrayref as an argument to the inequality op '$sop' is technically equivalent to an always-true 1=1/, + } for ('', '-'); # with and without - +} + +# check all like/not-like ops for empty-arrayref warnings +for my $op ( qw(like rlike not_like not_rlike), 'not like', 'not rlike', 'is like', 'is not like', 'is rlike', 'is not rlike') { + (my $sop = uc $op) =~ s/_/ /gi; + + push @tests, { + func => 'where', + args => [ { x => { "$_$op" => [] } } ], + stmt => ( $sop =~ /NOT/ ? "WHERE 1=1" : "WHERE 0=1" ), + stmt_q => ( $sop =~ /NOT/ ? "WHERE 1=1" : "WHERE 0=1" ), + bind => [], + warns => qr/\QSupplying an empty arrayref to '$sop' is deprecated/, + } for ('', '-'); # with and without - +} + for my $t (@tests) { my $new = $t->{new} || {}; @@ -597,13 +652,13 @@ for my $t (@tests) { throws_ok( sub { $cref->() }, $e, - ); + ) || diag dumper ({ args => $t->{args}, result => $stmt }); } else { - warnings_exist( + warnings_like( sub { $cref->() }, $t->{warns} || [], - ); + ) || diag dumper ({ args => $t->{args}, result => $stmt }); is_same_sql_bind( $stmt,