X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=t%2F10test.t;h=2e1e55968d41aee396cc8defc9c3e1533f04dc92;hb=fda0b270e45b2f419edf94e4f7e91d82d31c6f84;hp=af6404d3bf0841aacbe939c91d9d17b0c3bb37b6;hpb=32c343797dddfe975ee1e7b97793c7496e765139;p=scpubgit%2FQ-Branch.git diff --git a/t/10test.t b/t/10test.t index af6404d..2e1e559 100644 --- a/t/10test.t +++ b/t/10test.t @@ -1,12 +1,784 @@ -#!/usr/bin/perl - use strict; use warnings; -use List::Util qw(sum); -use Data::Dumper; use Test::More; +use SQL::Abstract::Test import => [qw( + eq_sql_bind eq_sql eq_bind is_same_sql_bind dumper $sql_differ +)]; + +my @sql_tests = ( + # WHERE condition - equal + { + equal => 1, + statements => [ + q/SELECT foo FROM bar WHERE a = 1/, + q/SELECT foo FROM bar WHERE a=1/, + q/SELECT foo FROM bar WHERE (a = 1)/, + q/SELECT foo FROM bar WHERE (a=1)/, + q/SELECT foo FROM bar WHERE ( a = 1 )/, + q/ + SELECT + foo + FROM + bar + WHERE + a = 1 + /, + q/ + SELECT + foo + FROM + bar + WHERE + (a = 1) + /, + q/ + SELECT + foo + FROM + bar + WHERE + ( a = 1 ) + /, + q/SELECT foo FROM bar WHERE ((a = 1))/, + q/SELECT foo FROM bar WHERE ( (a = 1) )/, + q/SELECT foo FROM bar WHERE ( ( a = 1 ) )/, + ] + }, + { + equal => 1, + statements => [ + q/SELECT foo FROM bar WHERE a = 1 AND b = 1/, + q/SELECT foo FROM bar WHERE (a = 1) AND (b = 1)/, + q/SELECT foo FROM bar WHERE ((a = 1) AND (b = 1))/, + q/SELECT foo FROM bar WHERE (a = 1 AND b = 1)/, + q/SELECT foo FROM bar WHERE ((a = 1 AND b = 1))/, + q/SELECT foo FROM bar WHERE (((a = 1) AND (b = 1)))/, + q/ + SELECT + foo + FROM + bar + WHERE + a = 1 + AND + b = 1 + /, + q/ + SELECT + foo + FROM + bar + WHERE + (a = 1 + AND + b = 1) + /, + q/ + SELECT + foo + FROM + bar + WHERE + (a = 1) + AND + (b = 1) + /, + q/ + SELECT + foo + FROM + bar + WHERE + ((a = 1) + AND + (b = 1)) + /, + ] + }, + { + equal => 1, + statements => [ + q/SELECT foo FROM bar WHERE a = 1 AND b = 1 AND c = 1/, + q/SELECT foo FROM bar WHERE (a = 1 AND b = 1 AND c = 1)/, + q/SELECT foo FROM bar WHERE (a = 1 AND b = 1) AND c = 1/, + q/SELECT foo FROM bar WHERE a = 1 AND (b = 1 AND c = 1)/, + q/SELECT foo FROM bar WHERE ((((a = 1))) AND (b = 1 AND c = 1))/, + ] + }, + { + equal => 1, + statements => [ + q/SELECT foo FROM bar WHERE a = 1 OR b = 1 OR c = 1/, + q/SELECT foo FROM bar WHERE (a = 1 OR b = 1) OR c = 1/, + q/SELECT foo FROM bar WHERE a = 1 OR (b = 1 OR c = 1)/, + q/SELECT foo FROM bar WHERE a = 1 OR ((b = 1 OR (c = 1)))/, + ] + }, + { + equal => 1, + statements => [ + q/SELECT foo FROM bar WHERE (a = 1) AND (b = 1 OR c = 1 OR d = 1) AND (e = 1 AND f = 1)/, + q/SELECT foo FROM bar WHERE a = 1 AND (b = 1 OR c = 1 OR d = 1) AND e = 1 AND (f = 1)/, + q/SELECT foo FROM bar WHERE ( ((a = 1) AND ( b = 1 OR (c = 1 OR d = 1) )) AND ((e = 1)) AND f = 1) /, + ] + }, + { + equal => 1, + statements => [ + q/SELECT foo FROM bar WHERE (a) AND (b = 2)/, + q/SELECT foo FROM bar WHERE (a AND b = 2)/, + q/SELECT foo FROM bar WHERE (a AND (b = 2))/, + q/SELECT foo FROM bar WHERE a AND (b = 2)/, + ] + }, + { + equal => 1, + statements => [ + q/SELECT foo FROM bar WHERE ((NOT a) AND b = 2)/, + q/SELECT foo FROM bar WHERE (NOT a) AND (b = 2)/, + q/SELECT foo FROM bar WHERE (NOT (a)) AND b = 2/, + ], + }, + { + equal => 0, + statements => [ + q/SELECT foo FROM bar WHERE NOT a AND (b = 2)/, + q/SELECT foo FROM bar WHERE (NOT a) AND (b = 2)/, + ] + }, + { + equal => 0, + opts => { parenthesis_significant => 1 }, + statements => [ + q/SELECT foo FROM bar WHERE a = 1 AND b = 1 AND c = 1/, + q/SELECT foo FROM bar WHERE (a = 1 AND b = 1 AND c = 1)/, + q/SELECT foo FROM bar WHERE (a = 1 AND b = 1) AND c = 1/, + q/SELECT foo FROM bar WHERE a = 1 AND (b = 1 AND c = 1)/, + q/SELECT foo FROM bar WHERE ((((a = 1))) AND (b = 1 AND c = 1))/, + ] + }, + { + equal => 0, + opts => { parenthesis_significant => 1 }, + statements => [ + q/SELECT foo FROM bar WHERE a = 1 OR b = 1 OR c = 1/, + q/SELECT foo FROM bar WHERE (a = 1 OR b = 1) OR c = 1/, + q/SELECT foo FROM bar WHERE a = 1 OR (b = 1 OR c = 1)/, + q/SELECT foo FROM bar WHERE a = 1 OR ((b = 1 OR (c = 1)))/, + ] + }, + { + equal => 0, + opts => { parenthesis_significant => 1 }, + statements => [ + q/SELECT foo FROM bar WHERE (a = 1) AND (b = 1 OR c = 1 OR d = 1) AND (e = 1 AND f = 1)/, + q/SELECT foo FROM bar WHERE a = 1 AND (b = 1 OR c = 1 OR d = 1) AND e = 1 AND (f = 1)/, + q/SELECT foo FROM bar WHERE ( ((a = 1) AND ( b = 1 OR (c = 1 OR d = 1) )) AND ((e = 1)) AND f = 1) /, + ] + }, + + # WHERE condition - different + { + equal => 0, + statements => [ + q/SELECT foo FROM bar WHERE a = 1/, + q/SELECT quux FROM bar WHERE a = 1/, + q/SELECT foo FROM quux WHERE a = 1/, + q/FOOBAR foo FROM bar WHERE a = 1/, + + q/SELECT foo FROM bar WHERE a = 2/, + q/SELECT foo FROM bar WHERE a < 1/, + q/SELECT foo FROM bar WHERE b = 1/, + q/SELECT foo FROM bar WHERE (c = 1)/, + q/SELECT foo FROM bar WHERE (d = 1)/, + + q/SELECT foo FROM bar WHERE a = 1 AND quux/, + q/SELECT foo FROM bar WHERE a = 1 GROUP BY foo/, + q/SELECT foo FROM bar WHERE a = 1 ORDER BY foo/, + q/SELECT foo FROM bar WHERE a = 1 LIMIT 1/, + q/SELECT foo FROM bar WHERE a = 1 OFFSET 1/, + q/SELECT foo FROM bar JOIN quux WHERE a = 1/, + q/SELECT foo FROM bar JOIN quux ON a = 1 WHERE a = 1/, + ] + }, + { + equal => 0, + statements => [ + q/SELECT foo FROM bar WHERE a = 1 AND b = 1/, + q/SELECT quux FROM bar WHERE a = 1 AND b = 1/, + q/SELECT foo FROM quux WHERE a = 1 AND b = 1/, + q/FOOBAR foo FROM bar WHERE a = 1 AND b = 1/, + + q/SELECT foo FROM bar WHERE a = 2 AND b = 1/, + q/SELECT foo FROM bar WHERE a = 3 AND (b = 1)/, + q/SELECT foo FROM bar WHERE (a = 4) AND b = 1/, + q/SELECT foo FROM bar WHERE (a = 5) AND (b = 1)/, + q/SELECT foo FROM bar WHERE ((a = 6) AND (b = 1))/, + q/SELECT foo FROM bar WHERE ((a = 7) AND (b = 1))/, + + q/SELECT foo FROM bar WHERE a = 1 AND b = 2/, + q/SELECT foo FROM bar WHERE a = 1 AND (b = 3)/, + q/SELECT foo FROM bar WHERE (a = 1) AND b = 4/, + q/SELECT foo FROM bar WHERE (a = 1) AND (b = 5)/, + q/SELECT foo FROM bar WHERE ((a = 1) AND (b = 6))/, + q/SELECT foo FROM bar WHERE ((a = 1) AND (b = 7))/, + + q/SELECT foo FROM bar WHERE a < 1 AND b = 1/, + q/SELECT foo FROM bar WHERE b = 1 AND b = 1/, + q/SELECT foo FROM bar WHERE (c = 1) AND b = 1/, + q/SELECT foo FROM bar WHERE (d = 1) AND b = 1/, + + q/SELECT foo FROM bar WHERE a = 1 AND b = 1 AND quux/, + q/SELECT foo FROM bar WHERE a = 1 AND b = 1 GROUP BY foo/, + q/SELECT foo FROM bar WHERE a = 1 AND b = 1 ORDER BY foo/, + q/SELECT foo FROM bar WHERE a = 1 AND b = 1 LIMIT 1/, + q/SELECT foo FROM bar WHERE a = 1 AND b = 1 OFFSET 1/, + q/SELECT foo FROM bar JOIN quux WHERE a = 1 AND b = 1/, + q/SELECT foo FROM bar JOIN quux ON a = 1 WHERE a = 1 AND b = 1/, + ] + }, + { + equal => 0, + statements => [ + q/SELECT foo FROM bar WHERE a = 1 AND b = 1 OR c = 1/, + q/SELECT foo FROM bar WHERE (a = 1 AND b = 1) OR c = 1/, + q/SELECT foo FROM bar WHERE a = 1 AND (b = 1 OR c = 1)/, + ] + }, + { + equal => 0, + statements => [ + q/SELECT foo FROM bar WHERE a = 1 OR b = 1 AND c = 1/, + q/SELECT foo FROM bar WHERE (a = 1 OR b = 1) AND c = 1/, + q/SELECT foo FROM bar WHERE a = 1 OR (b = 1 AND c = 1)/, + ] + }, + { + equal => 0, + statements => [ + q/SELECT foo FROM bar WHERE a IN (1,3,2)/, + q/SELECT foo FROM bar WHERE a IN 1,2,3/, + q/SELECT foo FROM bar WHERE a IN (1,2,3)/, + q/SELECT foo FROM bar WHERE a IN ((1,2,3))/, + ] + }, + { + equal => 0, + statements => [ + # BETWEEN with/without parenthesis around itself/RHS is a sticky business + # if I made a mistake here, simply rewrite the special BETWEEN handling in + # _recurse_parse() + # + # by RIBASUSHI + q/SELECT foo FROM bar WHERE ( completion_date BETWEEN ? AND ? AND status = ? )/, + q/SELECT foo FROM bar WHERE completion_date BETWEEN (? AND ?) AND status = ?/, + q/SELECT foo FROM bar WHERE ( (completion_date BETWEEN (? AND ?) ) AND status = ? )/, + q/SELECT foo FROM bar WHERE ( (completion_date BETWEEN (? AND ? AND status = ?) ) )/, + ] + }, + + # IS NULL (special LHS-only op) + { + equal => 1, + statements => [ + q/WHERE a IS NOT NULL AND b IS NULL/, + q/WHERE (a IS NOT NULL) AND b IS NULL/, + q/WHERE a IS NOT NULL AND (b IS NULL)/, + q/WHERE (a IS NOT NULL) AND ((b IS NULL))/, + ], + }, + + # JOIN condition - equal + { + equal => 1, + statements => [ + q/SELECT foo FROM bar JOIN baz ON a = 1 WHERE x = 1/, + q/SELECT foo FROM bar JOIN baz ON a=1 WHERE x = 1/, + q/SELECT foo FROM bar JOIN baz ON (a = 1) WHERE x = 1/, + q/SELECT foo FROM bar JOIN baz ON (a=1) WHERE x = 1/, + q/SELECT foo FROM bar JOIN baz ON ( a = 1 ) WHERE x = 1/, + q/ + SELECT + foo + FROM + bar + JOIN + baz + ON + a = 1 + WHERE + x = 1 + /, + q/ + SELECT + foo + FROM + bar + JOIN + baz + ON + (a = 1) + WHERE + x = 1 + /, + q/ + SELECT + foo + FROM + bar + JOIN + baz + ON + ( a = 1 ) + WHERE + x = 1 + /, + q/SELECT foo FROM bar JOIN baz ON ((a = 1)) WHERE x = 1/, + q/SELECT foo FROM bar JOIN baz ON ( (a = 1) ) WHERE x = 1/, + q/SELECT foo FROM bar JOIN baz ON ( ( a = 1 ) ) WHERE x = 1/, + ] + }, + { + equal => 1, + statements => [ + q/SELECT foo FROM bar JOIN baz ON a = 1 AND b = 1 WHERE x = 1/, + q/SELECT foo FROM bar JOIN baz ON (a = 1) AND (b = 1) WHERE x = 1/, + q/SELECT foo FROM bar JOIN baz ON ((a = 1) AND (b = 1)) WHERE x = 1/, + q/SELECT foo FROM bar JOIN baz ON (a = 1 AND b = 1) WHERE x = 1/, + q/SELECT foo FROM bar JOIN baz ON ((a = 1 AND b = 1)) WHERE x = 1/, + q/SELECT foo FROM bar JOIN baz ON (((a = 1) AND (b = 1))) WHERE x = 1/, + q/ + SELECT + foo + FROM + bar + JOIN + baz + ON + a = 1 + AND + b = 1 + WHERE + x = 1 + /, + q/ + SELECT + foo + FROM + bar + JOIN + baz + ON + (a = 1 + AND + b = 1) + WHERE + x = 1 + /, + q/ + SELECT + foo + FROM + bar + JOIN + baz + ON + (a = 1) + AND + (b = 1) + WHERE + x = 1 + /, + q/ + SELECT + foo + FROM + bar + JOIN + baz + ON + ((a = 1) + AND + (b = 1)) + WHERE + x = 1 + /, + ] + }, + + # JOIN condition - different + { + equal => 0, + statements => [ + q/SELECT foo FROM bar JOIN quux ON a = 1 WHERE quuux/, + q/SELECT quux FROM bar JOIN quux ON a = 1 WHERE quuux/, + q/SELECT foo FROM quux JOIN quux ON a = 1 WHERE quuux/, + q/FOOBAR foo FROM bar JOIN quux ON a = 1 WHERE quuux/, + + q/SELECT foo FROM bar JOIN quux ON a = 2 WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON a < 1 WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON b = 1 WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON (c = 1) WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON (d = 1) WHERE quuux/, + + q/SELECT foo FROM bar JOIN quux ON a = 1 AND quuux/, + q/SELECT foo FROM bar JOIN quux ON a = 1 GROUP BY foo/, + q/SELECT foo FROM bar JOIN quux ON a = 1 ORDER BY foo/, + q/SELECT foo FROM bar JOIN quux ON a = 1 LIMIT 1/, + q/SELECT foo FROM bar JOIN quux ON a = 1 OFFSET 1/, + q/SELECT foo FROM bar JOIN quux ON a = 1 JOIN quuux/, + q/SELECT foo FROM bar JOIN quux ON a = 1 JOIN quuux ON a = 1/, + ] + }, + { + equal => 0, + statements => [ + q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 1 WHERE quuux/, + q/SELECT quux FROM bar JOIN quux ON a = 1 AND b = 1 WHERE quuux/, + q/SELECT foo FROM quux JOIN quux ON a = 1 AND b = 1 WHERE quuux/, + q/FOOBAR foo FROM bar JOIN quux ON a = 1 AND b = 1 WHERE quuux/, + + q/SELECT foo FROM bar JOIN quux ON a = 2 AND b = 1 WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON a = 3 AND (b = 1) WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON (a = 4) AND b = 1 WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON (a = 5) AND (b = 1) WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON ((a = 6) AND (b = 1)) WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON ((a = 7) AND (b = 1)) WHERE quuux/, + + q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 2 WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON a = 1 AND (b = 3) WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON (a = 1) AND b = 4 WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON (a = 1) AND (b = 5) WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON ((a = 1) AND (b = 6)) WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON ((a = 1) AND (b = 7)) WHERE quuux/, + + q/SELECT foo FROM bar JOIN quux ON a < 1 AND b = 1 WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON b = 1 AND b = 1 WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON (c = 1) AND b = 1 WHERE quuux/, + q/SELECT foo FROM bar JOIN quux ON (d = 1) AND b = 1 WHERE quuux/, + + q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 1 AND quuux/, + q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 1 GROUP BY foo/, + q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 1 ORDER BY foo/, + q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 1 LIMIT 1/, + q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 1 OFFSET 1/, + q/SELECT foo FROM bar JOIN quux JOIN quuux ON a = 1 AND b = 1/, + q/SELECT foo FROM bar JOIN quux ON a = 1 JOIN quuux ON a = 1 AND b = 1/, + ] + }, + + # DISTINCT ON (...) not confused with JOIN ON (...) + { + equal => 1, + statements => [ + q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE a = 1/, + q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE a=1/, + q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE (a = 1)/, + q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE (a=1)/, + q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE ( a = 1 )/, + q/ + SELECT DISTINCT ON (foo, quux) + foo, + quux + FROM + bar + WHERE + a = 1 + /, + q/ + SELECT DISTINCT ON (foo, quux) + foo, + quux + FROM + bar + WHERE + (a = 1) + /, + q/ + SELECT DISTINCT ON (foo, quux) + foo, + quux + FROM + bar + WHERE + ( a = 1 ) + /, + q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE ((a = 1))/, + q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE ( (a = 1) )/, + q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE ( ( a = 1 ) )/, + ] + }, + + # subselects - equal + { + equal => 1, + statements => [ + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1) AS foo WHERE a = 1/, + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1) AS foo WHERE (a = 1)/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1)) AS foo WHERE a = 1/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1)) AS foo WHERE (a = 1)/, + ] + }, + { + equal => 1, + statements => [ + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND c = 1) AS foo WHERE a = 1/, + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND (c = 1)) AS foo WHERE a = 1/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND c = 1) AS foo WHERE a = 1/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND (c = 1)) AS foo WHERE a = 1/, + q/SELECT * FROM (SELECT * FROM bar WHERE ((b = 1) AND (c = 1))) AS foo WHERE a = 1/, + + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND c = 1) AS foo WHERE (a = 1)/, + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND (c = 1)) AS foo WHERE (a = 1)/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND c = 1) AS foo WHERE (a = 1)/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND (c = 1)) AS foo WHERE (a = 1)/, + q/SELECT * FROM (SELECT * FROM bar WHERE ((b = 1) AND (c = 1))) AS foo WHERE (a = 1)/, + ] + }, + + # subselects - different + { + equal => 0, + statements => [ + q/DELETE FROM cd WHERE ( cdid IN ( SELECT me.cdid FROM (SELECT * FROM cd me WHERE ( year != ? ) GROUP BY me.cdid) me WHERE ( year != ? ) ) )/, + q/DELETE FROM cd WHERE ( cdid IN ( SELECT me.cdid FROM cd me WHERE ( year != ? ) GROUP BY me.cdid ) )/, + ], + }, + { + equal => 0, + statements => [ + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1) AS foo WHERE a = 1/, + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1) AS foo WHERE a = 2/, + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1) AS foo WHERE (a = 3)/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1)) AS foo WHERE a = 4/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1)) AS foo WHERE (a = 5)/, + q/SELECT * FROM (SELECT * FROM bar WHERE b = 2) AS foo WHERE a = 1/, + q/SELECT * FROM (SELECT * FROM bar WHERE b = 3) AS foo WHERE (a = 1)/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 4)) AS foo WHERE a = 1/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 5)) AS foo WHERE (a = 1)/, + ] + }, + { + equal => 0, + statements => [ + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND c = 1) AS foo WHERE a = 1/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND c = 2) AS foo WHERE a = 1/, + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND (c = 3)) AS foo WHERE a = 1/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND (c = 4)) AS foo WHERE a = 1/, + q/SELECT * FROM (SELECT * FROM bar WHERE ((b = 1) AND (c = 5))) AS foo WHERE a = 1/, + + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND c = 6) AS foo WHERE (a = 1)/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND c = 7) AS foo WHERE (a = 1)/, + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND (c = 8)) AS foo WHERE (a = 1)/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND (c = 9)) AS foo WHERE (a = 1)/, + q/SELECT * FROM (SELECT * FROM bar WHERE ((b = 1) AND (c = 10))) AS foo WHERE (a = 1)/, + + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND c = 1) AS foo WHERE a = 2/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND c = 2) AS foo WHERE a = 2/, + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND (c = 3)) AS foo WHERE a = 2/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND (c = 4)) AS foo WHERE a = 2/, + q/SELECT * FROM (SELECT * FROM bar WHERE ((b = 1) AND (c = 5))) AS foo WHERE a = 2/, + + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND c = 6) AS foo WHERE (a = 2)/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND c = 7) AS foo WHERE (a = 2)/, + q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND (c = 8)) AS foo WHERE (a = 2)/, + q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND (c = 9)) AS foo WHERE (a = 2)/, + q/SELECT * FROM (SELECT * FROM bar WHERE ((b = 1) AND (c = 10))) AS foo WHERE (a = 2)/, + ] + }, + + # order by + { + equal => 1, + statements => [ + q/SELECT * FROM foo ORDER BY bar/, + q/SELECT * FROM foo ORDER BY bar ASC/, + q/SELECT * FROM foo ORDER BY bar asc/, + ], + }, + { + equal => 1, + statements => [ + q/SELECT * FROM foo ORDER BY bar, baz ASC/, + q/SELECT * FROM foo ORDER BY bar ASC, baz/, + q/SELECT * FROM foo ORDER BY bar asc, baz ASC/, + q/SELECT * FROM foo ORDER BY bar, baz/, + ], + }, + { + equal => 1, + statements => [ + q/ORDER BY colA, colB LIKE ? DESC, colC LIKE ?/, + q/ORDER BY colA ASC, colB LIKE ? DESC, colC LIKE ? ASC/, + ], + }, + { + equal => 1, + statements => [ + q/ORDER BY name + ?, [me].[id]/, + q/ORDER BY name + ? ASC, [me].[id]/, + ], + }, + { + equal => 0, + opts => { order_by_asc_significant => 1 }, + statements => [ + q/SELECT * FROM foo ORDER BY bar/, + q/SELECT * FROM foo ORDER BY bar ASC/, + q/SELECT * FROM foo ORDER BY bar desc/, + ], + }, + + # list permutations + { + equal => 0, + statements => [ + 'SELECT a,b,c FROM foo', + 'SELECT a,c,b FROM foo', + 'SELECT b,a,c FROM foo', + 'SELECT b,c,a FROM foo', + 'SELECT c,a,b FROM foo', + 'SELECT c,b,a FROM foo', + ], + }, + { + equal => 0, + statements => [ + 'SELECT * FROM foo WHERE a IN (1,2,3)', + 'SELECT * FROM foo WHERE a IN (1,3,2)', + 'SELECT * FROM foo WHERE a IN (2,1,3)', + 'SELECT * FROM foo WHERE a IN (2,3,1)', + 'SELECT * FROM foo WHERE a IN (3,1,2)', + 'SELECT * FROM foo WHERE a IN (3,2,1)', + ] + }, + + # list consistency + { + equal => 0, + statements => [ + 'SELECT a,b FROM foo', + 'SELECT a,,b FROM foo', + 'SELECT a,b, FROM foo', + 'SELECT ,a,b, FROM foo', + 'SELECT ,a,,b, FROM foo', + ], + }, + + # misc func + { + equal => 0, + statements => [ + 'SELECT count(*) FROM foo', + 'SELECT count(*) AS bar FROM foo', + 'SELECT count(*) AS "bar" FROM foo', + 'SELECT count(a) FROM foo', + 'SELECT count(1) FROM foo', + ] + }, + { + equal => 1, + statements => [ + 'SELECT foo() bar FROM baz', + 'SELECT foo ( )bar FROM baz', + 'SELECT foo (())bar FROM baz', + 'SELECT foo(( ) ) bar FROM baz', + ] + }, + { + equal => 0, + statements => [ + 'SELECT foo() FROM bar', + 'SELECT foo FROM bar', + 'SELECT foo FROM bar ()', + ] + }, + { + equal => 0, + statements => [ + 'SELECT COUNT * FROM foo', + 'SELECT COUNT( * ) FROM foo', + ] + }, + # single ? of unknown funcs do not unroll unless + # explicitly allowed (e.g. Like) + { + equal => 0, + statements => [ + 'SELECT foo FROM bar WHERE bar > foo ?', + 'SELECT foo FROM bar WHERE bar > foo( ? )', + ] + }, + { + equal => 1, + statements => [ + 'SELECT foo FROM bar WHERE bar LIKE ?', + 'SELECT foo FROM bar WHERE bar LiKe (?)', + 'SELECT foo FROM bar WHERE bar lIkE( (?))', + ] + }, + # test multival + { + equal => 0, + statements => [ + 'SELECT foo FROM bar WHERE foo IN (?, ?)', + 'SELECT foo FROM bar WHERE foo IN ?, ?', + ] + }, + # math + { + equal => 0, + statements => [ + 'SELECT * FROM foo WHERE 1 = ( a > b)', + 'SELECT * FROM foo WHERE 1 = a > b', + 'SELECT * FROM foo WHERE (1 = a) > b', + ] + }, + { + equal => 1, + statements => [ + 'SELECT * FROM foo WHERE bar = baz(buzz)', + 'SELECT * FROM foo WHERE bar = (baz( buzz ))', + ] + }, + # oddballs + { + equal => 1, + statements => [ + 'WHERE ( foo GLOB ? )', + 'WHERE foo GLOB ?', + ], + }, + { + equal => 1, + statements => [ + 'SELECT FIRST ? SKIP ? [me].[id], [me].[owner] + FROM [books] [me] + WHERE ( ( (EXISTS ( + SELECT FIRST ? SKIP ? [owner].[id] + FROM [owners] [owner] + WHERE ( [books].[owner] = [owner].[id] ) + )) AND [source] = ? ) )', + 'SELECT FIRST ? SKIP ? [me].[id], [me].[owner] + FROM [books] [me] + WHERE ( ( EXISTS ( + SELECT FIRST ? SKIP ? [owner].[id] + FROM [owners] [owner] + WHERE ( [books].[owner] = [owner].[id] ) + ) AND [source] = ? ) )', + ], + }, + { + equal => 1, + statements => [ + 'WHERE foo = ? FETCH FIRST 1 ROWS ONLY', + 'WHERE ( foo = ? ) FETCH FIRST 1 ROWS ONLY', + 'WHERE (( foo = ? )) FETCH FIRST 1 ROWS ONLY', + ], + }, +); my @bind_tests = ( # scalar - equal @@ -200,13 +972,52 @@ my @bind_tests = ( }, ); +for my $test (@sql_tests) { + + # this does not work on 5.8.8 and earlier :( + #local @{*SQL::Abstract::Test::}{keys %{$test->{opts}}} = map { \$_ } values %{$test->{opts}} + # if $test->{opts}; -plan tests => 1 + sum - map { $_ * ($_ - 1) / 2 } - map { scalar @{$_->{bindvals}} } - @bind_tests; + my %restore_globals; -use_ok('SQL::Abstract::Test', import => [qw(eq_sql eq_bind is_same_sql_bind)]); + for (keys %{$test->{opts} || {} }) { + $restore_globals{$_} = ${${*SQL::Abstract::Test::}{$_}}; + ${*SQL::Abstract::Test::}{$_} = \ do { my $cp = $test->{opts}{$_} }; + } + + my $statements = $test->{statements}; + while (@$statements) { + my $sql1 = shift @$statements; + foreach my $sql2 (@$statements) { + + my $equal = eq_sql($sql1, $sql2); + + TODO: { + local $TODO = $test->{todo} if $test->{todo}; + + if ($test->{equal}) { + ok($equal, "equal SQL expressions should have been considered equal"); + } else { + ok(!$equal, "different SQL expressions should have been considered not equal"); + } + + if ($equal ^ $test->{equal}) { + my ($ast1, $ast2) = map { SQL::Abstract::Test::parse ($_) } ($sql1, $sql2); + $_ = dumper($_) for ($ast1, $ast2); + + diag "sql1: $sql1"; + diag "sql2: $sql2"; + note $sql_differ || 'No differences found'; + note "ast1: $ast1"; + note "ast2: $ast2"; + } + } + } + } + + ${*SQL::Abstract::Test::}{$_} = \$restore_globals{$_} + for keys %restore_globals; +} for my $test (@bind_tests) { my $bindvals = $test->{bindvals}; @@ -221,9 +1032,78 @@ for my $test (@bind_tests) { } if ($equal ^ $test->{equal}) { - diag("bind1: " . Dumper($bind1)); - diag("bind2: " . Dumper($bind2)); + diag("bind1: " . dumper($bind1)); + diag("bind2: " . dumper($bind2)); } } } } + +ok(eq_sql_bind( + "SELECT * FROM foo WHERE id = ?", [42], + "SELECT * FROM foo WHERE (id = ?)", [42], + ), + "eq_sql_bind considers equal SQL expressions and bind values equal" +); + + +ok(!eq_sql_bind( + "SELECT * FROM foo WHERE id = ?", [42], + "SELECT * FROM foo WHERE (id = ?)", [0], + ), + "eq_sql_bind considers equal SQL expressions and different bind values different" +); + +ok(!eq_sql_bind( + "SELECT * FROM foo WHERE id = ?", [42], + "SELECT * FROM bar WHERE (id = ?)", [42], + ), + "eq_sql_bind considers different SQL expressions and equal bind values different" +); + +# test diag string +ok (! eq_sql ( + 'SELECT owner_name FROM books me WHERE ( source = ? )', + 'SELECT owner_name FROM books me WHERE ( sUOrce = ? )', +)); +like( + $sql_differ, + qr/\Q[ source ] != [ sUOrce ]/, + 'expected debug of literal diff', +); + +ok (! eq_sql ( + 'SELECT owner_name FROM books me ORDER BY owner_name', + 'SELECT owner_name FROM books me GROUP BY owner_name', +)); +like( + $sql_differ, + qr/\QOP [ORDER BY] != [GROUP BY]/, + 'expected debug of op diff', +); + +ok (! eq_sql ( + 'SELECT owner_name FROM books WHERE ( source = ? )', + 'SELECT owner_name FROM books' +)); + +like( + $sql_differ, + qr|\Q[WHERE source = ?] != [N/A]|, + 'expected debug of missing branch', +); + + +ok (eq_sql_bind ( + \[ 'SELECT foo FROM bar WHERE baz = ? or buzz = ?', [ {} => 1 ], 2 ], + 'SELECT foo FROM bar WHERE (baz = ?) OR buzz = ?', + [ [ {} => 1 ], 2 ], +), 'arrayrefref unpacks correctly' ); + +is_same_sql_bind( + \[ 'SELECT foo FROM bar WHERE baz = ? or buzz = ?', [ {} => 1 ], 2 ], + \[ 'SELECT foo FROM bar WHERE (( baz = ? OR (buzz = ?) ))', [ {} => 1 ], 2 ], + 'double arrayrefref unpacks correctly' +); + +done_testing;