use strict;
use warnings;
use List::Util qw(sum);
-use Data::Dumper;
use Test::More;
+use Data::Dumper;
+$Data::Dumper::Terse = 1;
+$Data::Dumper::Sortkeys = 1;
+
+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,
+ 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,
+ 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,
+ 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,
+ parenthesis_significant => 1,
+ statements => [
+ q/SELECT foo FROM bar WHERE a IN (1,2,3)/,
+ q/SELECT foo FROM bar WHERE a IN (1,3,2)/,
+ 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)/,
+ ]
+ },
+
+ # 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 ))',
+ ]
+ },
+);
my @bind_tests = (
# scalar - equal
},
);
+plan tests => 1 +
+ sum(
+ map { $_ * ($_ - 1) / 2 }
+ map { scalar @{$_->{statements}} }
+ @sql_tests
+ ) +
+ sum(
+ map { $_ * ($_ - 1) / 2 }
+ map { scalar @{$_->{bindvals}} }
+ @bind_tests
+ ) +
+ 3;
+
+use_ok('SQL::Abstract::Test', import => [qw(
+ eq_sql_bind eq_sql eq_bind is_same_sql_bind
+)]);
+
+for my $test (@sql_tests) {
+ my $statements = $test->{statements};
+ while (@$statements) {
+ my $sql1 = shift @$statements;
+ foreach my $sql2 (@$statements) {
-plan tests => 1 + sum
- map { $_ * ($_ - 1) / 2 }
- map { scalar @{$_->{bindvals}} }
- @bind_tests;
+ no warnings qw/once/; # perl 5.10 is dumb
+ local $SQL::Abstract::Test::parenthesis_significant = $test->{parenthesis_significant}
+ if $test->{parenthesis_significant};
+ my $equal = eq_sql($sql1, $sql2);
-use_ok('SQL::Abstract::Test', import => [qw(eq_sql eq_bind is_same_sql_bind)]);
+ 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::Abstract::Test::sql_differ;
+ note "ast1: $ast1";
+ note "ast2: $ast2";
+ }
+ }
+ }
+ }
+}
for my $test (@bind_tests) {
my $bindvals = $test->{bindvals};
}
}
}
+
+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"
+);