23183a9c8ea52614f51ad601f9d389bbe9f20241
[dbsrgits/SQL-Abstract.git] / t / 10test.t
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5 use List::Util qw(sum);
6
7 use Test::More;
8
9 use Data::Dumper;
10 $Data::Dumper::Terse = 1;
11 $Data::Dumper::Sortkeys = 1;
12
13 my @sql_tests = (
14       # WHERE condition - equal
15       {
16         equal => 1,
17         statements => [
18           q/SELECT foo FROM bar WHERE a = 1/,
19           q/SELECT foo FROM bar WHERE a=1/,
20           q/SELECT foo FROM bar WHERE (a = 1)/,
21           q/SELECT foo FROM bar WHERE (a=1)/,
22           q/SELECT foo FROM bar WHERE ( a = 1 )/,
23           q/
24             SELECT
25               foo
26             FROM
27               bar
28             WHERE
29               a = 1
30           /,
31           q/
32             SELECT
33               foo
34             FROM
35               bar
36             WHERE
37               (a = 1)
38           /,
39           q/
40             SELECT
41               foo
42             FROM
43               bar
44             WHERE
45               ( a = 1 )
46           /,
47           q/SELECT foo FROM bar WHERE ((a = 1))/,
48           q/SELECT foo FROM bar WHERE ( (a = 1) )/,
49           q/SELECT foo FROM bar WHERE ( ( a = 1 ) )/,
50         ]
51       },
52       {
53         equal => 1,
54         statements => [
55           q/SELECT foo FROM bar WHERE a = 1 AND b = 1/,
56           q/SELECT foo FROM bar WHERE (a = 1) AND (b = 1)/,
57           q/SELECT foo FROM bar WHERE ((a = 1) AND (b = 1))/,
58           q/SELECT foo FROM bar WHERE (a = 1 AND b = 1)/,
59           q/SELECT foo FROM bar WHERE ((a = 1 AND b = 1))/,
60           q/SELECT foo FROM bar WHERE (((a = 1) AND (b = 1)))/,
61           q/
62             SELECT
63               foo
64             FROM
65               bar
66             WHERE
67               a = 1
68               AND
69               b = 1
70           /,
71           q/
72             SELECT
73               foo
74             FROM
75               bar
76             WHERE
77               (a = 1
78               AND
79               b = 1)
80           /,
81           q/
82             SELECT
83               foo
84             FROM
85               bar
86             WHERE
87               (a = 1)
88               AND
89               (b = 1)
90           /,
91           q/
92             SELECT
93               foo
94             FROM
95               bar
96             WHERE
97               ((a = 1)
98               AND
99               (b = 1))
100           /,
101         ]
102       },
103       {
104         equal => 1,
105         statements => [
106           q/SELECT foo FROM bar WHERE a = 1 AND b = 1 AND c = 1/,
107           q/SELECT foo FROM bar WHERE (a = 1 AND b = 1 AND c = 1)/,
108           q/SELECT foo FROM bar WHERE (a = 1 AND b = 1) AND c = 1/,
109           q/SELECT foo FROM bar WHERE a = 1 AND (b = 1 AND c = 1)/,
110           q/SELECT foo FROM bar WHERE ((((a = 1))) AND (b = 1 AND c = 1))/,
111         ]
112       },
113       {
114         equal => 1,
115         statements => [
116           q/SELECT foo FROM bar WHERE a = 1 OR b = 1 OR c = 1/,
117           q/SELECT foo FROM bar WHERE (a = 1 OR b = 1) OR c = 1/,
118           q/SELECT foo FROM bar WHERE a = 1 OR (b = 1 OR c = 1)/,
119           q/SELECT foo FROM bar WHERE a = 1 OR ((b = 1 OR (c = 1)))/,
120         ]
121       },
122       {
123         equal => 1,
124         statements => [
125           q/SELECT foo FROM bar WHERE (a = 1) AND (b = 1 OR c = 1 OR d = 1) AND (e = 1 AND f = 1)/,
126           q/SELECT foo FROM bar WHERE a = 1 AND (b = 1 OR c = 1 OR d = 1) AND e = 1 AND (f = 1)/,
127           q/SELECT foo FROM bar WHERE ( ((a = 1) AND ( b = 1 OR (c = 1 OR d = 1) )) AND ((e = 1)) AND f = 1) /,
128         ]
129       },
130       {
131         equal => 1,
132         statements => [
133           q/SELECT foo FROM bar WHERE (a) AND (b = 2)/,
134           q/SELECT foo FROM bar WHERE (a AND b = 2)/,
135           q/SELECT foo FROM bar WHERE (a AND (b = 2))/,
136           q/SELECT foo FROM bar WHERE a AND (b = 2)/,
137         ]
138       },
139       {
140         equal => 1,
141         statements => [
142           q/SELECT foo FROM bar WHERE ((NOT a) AND b = 2)/,
143           q/SELECT foo FROM bar WHERE (NOT a) AND (b = 2)/,
144           q/SELECT foo FROM bar WHERE (NOT (a)) AND b = 2/,
145         ],
146       },
147       {
148         equal => 0,
149         statements => [
150           q/SELECT foo FROM bar WHERE NOT a AND (b = 2)/,
151           q/SELECT foo FROM bar WHERE (NOT a) AND (b = 2)/,
152         ]
153       },
154       {
155         equal => 0,
156         opts => { parenthesis_significant => 1 },
157         statements => [
158           q/SELECT foo FROM bar WHERE a = 1 AND b = 1 AND c = 1/,
159           q/SELECT foo FROM bar WHERE (a = 1 AND b = 1 AND c = 1)/,
160           q/SELECT foo FROM bar WHERE (a = 1 AND b = 1) AND c = 1/,
161           q/SELECT foo FROM bar WHERE a = 1 AND (b = 1 AND c = 1)/,
162           q/SELECT foo FROM bar WHERE ((((a = 1))) AND (b = 1 AND c = 1))/,
163         ]
164       },
165       {
166         equal => 0,
167         opts => { parenthesis_significant => 1 },
168         statements => [
169           q/SELECT foo FROM bar WHERE a = 1 OR b = 1 OR c = 1/,
170           q/SELECT foo FROM bar WHERE (a = 1 OR b = 1) OR c = 1/,
171           q/SELECT foo FROM bar WHERE a = 1 OR (b = 1 OR c = 1)/,
172           q/SELECT foo FROM bar WHERE a = 1 OR ((b = 1 OR (c = 1)))/,
173         ]
174       },
175       {
176         equal => 0,
177         opts => { parenthesis_significant => 1 },
178         statements => [
179           q/SELECT foo FROM bar WHERE (a = 1) AND (b = 1 OR c = 1 OR d = 1) AND (e = 1 AND f = 1)/,
180           q/SELECT foo FROM bar WHERE a = 1 AND (b = 1 OR c = 1 OR d = 1) AND e = 1 AND (f = 1)/,
181           q/SELECT foo FROM bar WHERE ( ((a = 1) AND ( b = 1 OR (c = 1 OR d = 1) )) AND ((e = 1)) AND f = 1) /,
182         ]
183       },
184
185       # WHERE condition - different
186       {
187         equal => 0,
188         statements => [
189           q/SELECT foo FROM bar WHERE a = 1/,
190           q/SELECT quux FROM bar WHERE a = 1/,
191           q/SELECT foo FROM quux WHERE a = 1/,
192           q/FOOBAR foo FROM bar WHERE a = 1/,
193
194           q/SELECT foo FROM bar WHERE a = 2/,
195           q/SELECT foo FROM bar WHERE a < 1/,
196           q/SELECT foo FROM bar WHERE b = 1/,
197           q/SELECT foo FROM bar WHERE (c = 1)/,
198           q/SELECT foo FROM bar WHERE (d = 1)/,
199
200           q/SELECT foo FROM bar WHERE a = 1 AND quux/,
201           q/SELECT foo FROM bar WHERE a = 1 GROUP BY foo/,
202           q/SELECT foo FROM bar WHERE a = 1 ORDER BY foo/,
203           q/SELECT foo FROM bar WHERE a = 1 LIMIT 1/,
204           q/SELECT foo FROM bar WHERE a = 1 OFFSET 1/,
205           q/SELECT foo FROM bar JOIN quux WHERE a = 1/,
206           q/SELECT foo FROM bar JOIN quux ON a = 1 WHERE a = 1/,
207         ]
208       },
209       {
210         equal => 0,
211         statements => [
212           q/SELECT foo FROM bar WHERE a = 1 AND b = 1/,
213           q/SELECT quux FROM bar WHERE a = 1 AND b = 1/,
214           q/SELECT foo FROM quux WHERE a = 1 AND b = 1/,
215           q/FOOBAR foo FROM bar WHERE a = 1 AND b = 1/,
216
217           q/SELECT foo FROM bar WHERE a = 2 AND b = 1/,
218           q/SELECT foo FROM bar WHERE a = 3 AND (b = 1)/,
219           q/SELECT foo FROM bar WHERE (a = 4) AND b = 1/,
220           q/SELECT foo FROM bar WHERE (a = 5) AND (b = 1)/,
221           q/SELECT foo FROM bar WHERE ((a = 6) AND (b = 1))/,
222           q/SELECT foo FROM bar WHERE ((a = 7) AND (b = 1))/,
223
224           q/SELECT foo FROM bar WHERE a = 1 AND b = 2/,
225           q/SELECT foo FROM bar WHERE a = 1 AND (b = 3)/,
226           q/SELECT foo FROM bar WHERE (a = 1) AND b = 4/,
227           q/SELECT foo FROM bar WHERE (a = 1) AND (b = 5)/,
228           q/SELECT foo FROM bar WHERE ((a = 1) AND (b = 6))/,
229           q/SELECT foo FROM bar WHERE ((a = 1) AND (b = 7))/,
230
231           q/SELECT foo FROM bar WHERE a < 1 AND b = 1/,
232           q/SELECT foo FROM bar WHERE b = 1 AND b = 1/,
233           q/SELECT foo FROM bar WHERE (c = 1) AND b = 1/,
234           q/SELECT foo FROM bar WHERE (d = 1) AND b = 1/,
235
236           q/SELECT foo FROM bar WHERE a = 1 AND b = 1 AND quux/,
237           q/SELECT foo FROM bar WHERE a = 1 AND b = 1 GROUP BY foo/,
238           q/SELECT foo FROM bar WHERE a = 1 AND b = 1 ORDER BY foo/,
239           q/SELECT foo FROM bar WHERE a = 1 AND b = 1 LIMIT 1/,
240           q/SELECT foo FROM bar WHERE a = 1 AND b = 1 OFFSET 1/,
241           q/SELECT foo FROM bar JOIN quux WHERE a = 1 AND b = 1/,
242           q/SELECT foo FROM bar JOIN quux ON a = 1 WHERE a = 1 AND b = 1/,
243         ]
244       },
245       {
246         equal => 0,
247         statements => [
248           q/SELECT foo FROM bar WHERE a = 1 AND b = 1 OR c = 1/,
249           q/SELECT foo FROM bar WHERE (a = 1 AND b = 1) OR c = 1/,
250           q/SELECT foo FROM bar WHERE a = 1 AND (b = 1 OR c = 1)/,
251         ]
252       },
253       {
254         equal => 0,
255         statements => [
256           q/SELECT foo FROM bar WHERE a = 1 OR b = 1 AND c = 1/,
257           q/SELECT foo FROM bar WHERE (a = 1 OR b = 1) AND c = 1/,
258           q/SELECT foo FROM bar WHERE a = 1 OR (b = 1 AND c = 1)/,
259         ]
260       },
261       {
262         equal => 0,
263         opts => { parenthesis_significant => 1 },
264         statements => [
265           q/SELECT foo FROM bar WHERE a IN (1,2,3)/,
266           q/SELECT foo FROM bar WHERE a IN (1,3,2)/,
267           q/SELECT foo FROM bar WHERE a IN ((1,2,3))/,
268         ]
269       },
270       {
271         equal => 0,
272         statements => [
273           # BETWEEN with/without parenthesis around itself/RHS is a sticky business
274           # if I made a mistake here, simply rewrite the special BETWEEN handling in
275           # _recurse_parse()
276           #
277           # by RIBASUSHI
278           q/SELECT foo FROM bar WHERE ( completion_date BETWEEN ? AND ? AND status = ? )/,
279           q/SELECT foo FROM bar WHERE completion_date BETWEEN (? AND ?) AND status = ?/,
280           q/SELECT foo FROM bar WHERE ( (completion_date BETWEEN (? AND ?) ) AND status = ? )/,
281           q/SELECT foo FROM bar WHERE ( (completion_date BETWEEN (? AND ? AND status = ?) ) )/,
282         ]
283       },
284
285       # IS NULL (special LHS-only op)
286       {
287         equal => 1,
288         statements => [
289           q/WHERE a IS NOT NULL AND b IS NULL/,
290           q/WHERE (a IS NOT NULL) AND b IS NULL/,
291           q/WHERE a IS NOT NULL AND (b IS NULL)/,
292           q/WHERE (a IS NOT NULL) AND ((b IS NULL))/,
293         ],
294       },
295
296       # JOIN condition - equal
297       {
298         equal => 1,
299         statements => [
300           q/SELECT foo FROM bar JOIN baz ON a = 1 WHERE x = 1/,
301           q/SELECT foo FROM bar JOIN baz ON a=1 WHERE x = 1/,
302           q/SELECT foo FROM bar JOIN baz ON (a = 1) WHERE x = 1/,
303           q/SELECT foo FROM bar JOIN baz ON (a=1) WHERE x = 1/,
304           q/SELECT foo FROM bar JOIN baz ON ( a = 1 ) WHERE x = 1/,
305           q/
306             SELECT
307               foo
308             FROM
309               bar
310             JOIN
311               baz
312             ON
313               a = 1
314             WHERE
315               x = 1
316           /,
317           q/
318             SELECT
319               foo
320             FROM
321               bar
322             JOIN
323               baz
324             ON
325               (a = 1)
326             WHERE
327               x = 1
328           /,
329           q/
330             SELECT
331               foo
332             FROM
333               bar
334             JOIN
335               baz
336             ON
337               ( a = 1 )
338             WHERE
339               x = 1
340           /,
341           q/SELECT foo FROM bar JOIN baz ON ((a = 1)) WHERE x = 1/,
342           q/SELECT foo FROM bar JOIN baz ON ( (a = 1) ) WHERE x = 1/,
343           q/SELECT foo FROM bar JOIN baz ON ( ( a = 1 ) ) WHERE x = 1/,
344         ]
345       },
346       {
347         equal => 1,
348         statements => [
349           q/SELECT foo FROM bar JOIN baz ON a = 1 AND b = 1 WHERE x = 1/,
350           q/SELECT foo FROM bar JOIN baz ON (a = 1) AND (b = 1) WHERE x = 1/,
351           q/SELECT foo FROM bar JOIN baz ON ((a = 1) AND (b = 1)) WHERE x = 1/,
352           q/SELECT foo FROM bar JOIN baz ON (a = 1 AND b = 1) WHERE x = 1/,
353           q/SELECT foo FROM bar JOIN baz ON ((a = 1 AND b = 1)) WHERE x = 1/,
354           q/SELECT foo FROM bar JOIN baz ON (((a = 1) AND (b = 1))) WHERE x = 1/,
355           q/
356             SELECT
357               foo
358             FROM
359               bar
360             JOIN
361               baz
362             ON
363               a = 1
364               AND
365               b = 1
366             WHERE
367               x = 1
368           /,
369           q/
370             SELECT
371               foo
372             FROM
373               bar
374             JOIN
375               baz
376             ON
377               (a = 1
378               AND
379               b = 1)
380             WHERE
381               x = 1
382           /,
383           q/
384             SELECT
385               foo
386             FROM
387               bar
388             JOIN
389               baz
390             ON
391               (a = 1)
392               AND
393               (b = 1)
394             WHERE
395               x = 1
396           /,
397           q/
398             SELECT
399               foo
400             FROM
401               bar
402             JOIN
403               baz
404             ON
405               ((a = 1)
406               AND
407               (b = 1))
408             WHERE
409               x = 1
410           /,
411         ]
412       },
413
414       # JOIN condition - different
415       {
416         equal => 0,
417         statements => [
418           q/SELECT foo FROM bar JOIN quux ON a = 1 WHERE quuux/,
419           q/SELECT quux FROM bar JOIN quux ON a = 1 WHERE quuux/,
420           q/SELECT foo FROM quux JOIN quux ON a = 1 WHERE quuux/,
421           q/FOOBAR foo FROM bar JOIN quux ON a = 1 WHERE quuux/,
422
423           q/SELECT foo FROM bar JOIN quux ON a = 2 WHERE quuux/,
424           q/SELECT foo FROM bar JOIN quux ON a < 1 WHERE quuux/,
425           q/SELECT foo FROM bar JOIN quux ON b = 1 WHERE quuux/,
426           q/SELECT foo FROM bar JOIN quux ON (c = 1) WHERE quuux/,
427           q/SELECT foo FROM bar JOIN quux ON (d = 1) WHERE quuux/,
428
429           q/SELECT foo FROM bar JOIN quux ON a = 1 AND quuux/,
430           q/SELECT foo FROM bar JOIN quux ON a = 1 GROUP BY foo/,
431           q/SELECT foo FROM bar JOIN quux ON a = 1 ORDER BY foo/,
432           q/SELECT foo FROM bar JOIN quux ON a = 1 LIMIT 1/,
433           q/SELECT foo FROM bar JOIN quux ON a = 1 OFFSET 1/,
434           q/SELECT foo FROM bar JOIN quux ON a = 1 JOIN quuux/,
435           q/SELECT foo FROM bar JOIN quux ON a = 1 JOIN quuux ON a = 1/,
436         ]
437       },
438       {
439         equal => 0,
440         statements => [
441           q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 1 WHERE quuux/,
442           q/SELECT quux FROM bar JOIN quux ON a = 1 AND b = 1 WHERE quuux/,
443           q/SELECT foo FROM quux JOIN quux ON a = 1 AND b = 1 WHERE quuux/,
444           q/FOOBAR foo FROM bar JOIN quux ON a = 1 AND b = 1 WHERE quuux/,
445
446           q/SELECT foo FROM bar JOIN quux ON a = 2 AND b = 1 WHERE quuux/,
447           q/SELECT foo FROM bar JOIN quux ON a = 3 AND (b = 1) WHERE quuux/,
448           q/SELECT foo FROM bar JOIN quux ON (a = 4) AND b = 1 WHERE quuux/,
449           q/SELECT foo FROM bar JOIN quux ON (a = 5) AND (b = 1) WHERE quuux/,
450           q/SELECT foo FROM bar JOIN quux ON ((a = 6) AND (b = 1)) WHERE quuux/,
451           q/SELECT foo FROM bar JOIN quux ON ((a = 7) AND (b = 1)) WHERE quuux/,
452
453           q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 2 WHERE quuux/,
454           q/SELECT foo FROM bar JOIN quux ON a = 1 AND (b = 3) WHERE quuux/,
455           q/SELECT foo FROM bar JOIN quux ON (a = 1) AND b = 4 WHERE quuux/,
456           q/SELECT foo FROM bar JOIN quux ON (a = 1) AND (b = 5) WHERE quuux/,
457           q/SELECT foo FROM bar JOIN quux ON ((a = 1) AND (b = 6)) WHERE quuux/,
458           q/SELECT foo FROM bar JOIN quux ON ((a = 1) AND (b = 7)) WHERE quuux/,
459
460           q/SELECT foo FROM bar JOIN quux ON a < 1 AND b = 1 WHERE quuux/,
461           q/SELECT foo FROM bar JOIN quux ON b = 1 AND b = 1 WHERE quuux/,
462           q/SELECT foo FROM bar JOIN quux ON (c = 1) AND b = 1 WHERE quuux/,
463           q/SELECT foo FROM bar JOIN quux ON (d = 1) AND b = 1 WHERE quuux/,
464
465           q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 1 AND quuux/,
466           q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 1 GROUP BY foo/,
467           q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 1 ORDER BY foo/,
468           q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 1 LIMIT 1/,
469           q/SELECT foo FROM bar JOIN quux ON a = 1 AND b = 1 OFFSET 1/,
470           q/SELECT foo FROM bar JOIN quux JOIN quuux ON a = 1 AND b = 1/,
471           q/SELECT foo FROM bar JOIN quux ON a = 1 JOIN quuux ON a = 1 AND b = 1/,
472         ]
473       },
474
475       # DISTINCT ON (...) not confused with JOIN ON (...)
476       {
477         equal => 1,
478         statements => [
479           q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE a = 1/,
480           q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE a=1/,
481           q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE (a = 1)/,
482           q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE (a=1)/,
483           q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE ( a = 1 )/,
484           q/
485             SELECT DISTINCT ON (foo, quux)
486               foo,
487               quux
488             FROM
489               bar
490             WHERE
491               a = 1
492           /,
493           q/
494             SELECT DISTINCT ON (foo, quux)
495               foo,
496               quux
497             FROM
498               bar
499             WHERE
500               (a = 1)
501           /,
502           q/
503             SELECT DISTINCT ON (foo, quux)
504               foo,
505               quux
506             FROM
507               bar
508             WHERE
509               ( a = 1 )
510           /,
511           q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE ((a = 1))/,
512           q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE ( (a = 1) )/,
513           q/SELECT DISTINCT ON (foo, quux) foo, quux FROM bar WHERE ( ( a = 1 ) )/,
514         ]
515       },
516
517       # subselects - equal
518       {
519         equal => 1,
520         statements => [
521           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1) AS foo WHERE a = 1/,
522           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1) AS foo WHERE (a = 1)/,
523           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1)) AS foo WHERE a = 1/,
524           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1)) AS foo WHERE (a = 1)/,
525         ]
526       },
527       {
528         equal => 1,
529         statements => [
530           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND c = 1) AS foo WHERE a = 1/,
531           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND (c = 1)) AS foo WHERE a = 1/,
532           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND c = 1) AS foo WHERE a = 1/,
533           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND (c = 1)) AS foo WHERE a = 1/,
534           q/SELECT * FROM (SELECT * FROM bar WHERE ((b = 1) AND (c = 1))) AS foo WHERE a = 1/,
535
536           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND c = 1) AS foo WHERE (a = 1)/,
537           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND (c = 1)) AS foo WHERE (a = 1)/,
538           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND c = 1) AS foo WHERE (a = 1)/,
539           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND (c = 1)) AS foo WHERE (a = 1)/,
540           q/SELECT * FROM (SELECT * FROM bar WHERE ((b = 1) AND (c = 1))) AS foo WHERE (a = 1)/,
541         ]
542       },
543
544       # subselects - different
545       {
546         equal => 0,
547         statements => [
548           q/DELETE FROM cd WHERE ( cdid IN ( SELECT me.cdid FROM (SELECT * FROM cd me WHERE ( year != ? ) GROUP BY me.cdid) me WHERE ( year != ? ) ) )/,
549           q/DELETE FROM cd WHERE ( cdid IN ( SELECT me.cdid FROM cd me WHERE ( year != ? ) GROUP BY me.cdid ) )/,
550         ],
551       },
552       {
553         equal => 0,
554         statements => [
555           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1) AS foo WHERE a = 1/,
556           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1) AS foo WHERE a = 2/,
557           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1) AS foo WHERE (a = 3)/,
558           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1)) AS foo WHERE a = 4/,
559           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1)) AS foo WHERE (a = 5)/,
560           q/SELECT * FROM (SELECT * FROM bar WHERE b = 2) AS foo WHERE a = 1/,
561           q/SELECT * FROM (SELECT * FROM bar WHERE b = 3) AS foo WHERE (a = 1)/,
562           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 4)) AS foo WHERE a = 1/,
563           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 5)) AS foo WHERE (a = 1)/,
564         ]
565       },
566       {
567         equal => 0,
568         statements => [
569           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND c = 1) AS foo WHERE a = 1/,
570           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND c = 2) AS foo WHERE a = 1/,
571           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND (c = 3)) AS foo WHERE a = 1/,
572           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND (c = 4)) AS foo WHERE a = 1/,
573           q/SELECT * FROM (SELECT * FROM bar WHERE ((b = 1) AND (c = 5))) AS foo WHERE a = 1/,
574
575           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND c = 6) AS foo WHERE (a = 1)/,
576           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND c = 7) AS foo WHERE (a = 1)/,
577           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND (c = 8)) AS foo WHERE (a = 1)/,
578           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND (c = 9)) AS foo WHERE (a = 1)/,
579           q/SELECT * FROM (SELECT * FROM bar WHERE ((b = 1) AND (c = 10))) AS foo WHERE (a = 1)/,
580
581           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND c = 1) AS foo WHERE a = 2/,
582           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND c = 2) AS foo WHERE a = 2/,
583           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND (c = 3)) AS foo WHERE a = 2/,
584           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND (c = 4)) AS foo WHERE a = 2/,
585           q/SELECT * FROM (SELECT * FROM bar WHERE ((b = 1) AND (c = 5))) AS foo WHERE a = 2/,
586
587           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND c = 6) AS foo WHERE (a = 2)/,
588           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND c = 7) AS foo WHERE (a = 2)/,
589           q/SELECT * FROM (SELECT * FROM bar WHERE b = 1 AND (c = 8)) AS foo WHERE (a = 2)/,
590           q/SELECT * FROM (SELECT * FROM bar WHERE (b = 1) AND (c = 9)) AS foo WHERE (a = 2)/,
591           q/SELECT * FROM (SELECT * FROM bar WHERE ((b = 1) AND (c = 10))) AS foo WHERE (a = 2)/,
592         ]
593       },
594
595       # order by
596       {
597         equal => 1,
598         statements => [
599           q/SELECT * FROM foo ORDER BY bar/,
600           q/SELECT * FROM foo ORDER BY bar ASC/,
601           q/SELECT * FROM foo ORDER BY bar asc/,
602         ],
603       },
604       {
605         equal => 1,
606         statements => [
607           q/SELECT * FROM foo ORDER BY bar, baz ASC/,
608           q/SELECT * FROM foo ORDER BY bar ASC, baz/,
609           q/SELECT * FROM foo ORDER BY bar asc, baz ASC/,
610           q/SELECT * FROM foo ORDER BY bar, baz/,
611         ],
612       },
613       {
614         equal => 1,
615         statements => [
616           q/ORDER BY colA, colB LIKE ? DESC, colC LIKE ?/,
617           q/ORDER BY colA ASC, colB LIKE ? DESC, colC LIKE ? ASC/,
618         ],
619       },
620       {
621         equal => 1,
622         statements => [
623           q/ORDER BY name + ?, [me].[id]/,
624           q/ORDER BY name + ? ASC, [me].[id]/,
625         ],
626       },
627       {
628         equal => 0,
629         opts => { order_by_asc_significant => 1 },
630         statements => [
631           q/SELECT * FROM foo ORDER BY bar/,
632           q/SELECT * FROM foo ORDER BY bar ASC/,
633           q/SELECT * FROM foo ORDER BY bar desc/,
634         ],
635       },
636
637       # list permutations
638       {
639         equal => 0,
640         statements => [
641           'SELECT a,b,c FROM foo',
642           'SELECT a,c,b FROM foo',
643           'SELECT b,a,c FROM foo',
644           'SELECT b,c,a FROM foo',
645           'SELECT c,a,b FROM foo',
646           'SELECT c,b,a FROM foo',
647         ],
648       },
649       {
650         equal => 0,
651         statements => [
652           'SELECT * FROM foo WHERE a IN (1,2,3)',
653           'SELECT * FROM foo WHERE a IN (1,3,2)',
654           'SELECT * FROM foo WHERE a IN (2,1,3)',
655           'SELECT * FROM foo WHERE a IN (2,3,1)',
656           'SELECT * FROM foo WHERE a IN (3,1,2)',
657           'SELECT * FROM foo WHERE a IN (3,2,1)',
658         ]
659       },
660
661       # list consistency
662       {
663         equal => 0,
664         statements => [
665           'SELECT a,b FROM foo',
666           'SELECT a,,b FROM foo',
667           'SELECT a,b, FROM foo',
668           'SELECT ,a,b, FROM foo',
669           'SELECT ,a,,b, FROM foo',
670         ],
671       },
672
673       # misc func
674       {
675         equal => 0,
676         statements => [
677           'SELECT count(*) FROM foo',
678           'SELECT count(*) AS bar FROM foo',
679           'SELECT count(*) AS "bar" FROM foo',
680           'SELECT count(a) FROM foo',
681           'SELECT count(1) FROM foo',
682         ]
683       },
684       {
685         equal => 1,
686         statements => [
687           'SELECT foo() bar FROM baz',
688           'SELECT foo (  )bar FROM baz',
689           'SELECT foo (())bar FROM baz',
690           'SELECT foo(( ) ) bar FROM baz',
691         ]
692       },
693       {
694         equal => 0,
695         statements => [
696           'SELECT foo() FROM bar',
697           'SELECT foo FROM bar',
698           'SELECT foo FROM bar ()',
699         ]
700       },
701       {
702         equal => 0,
703         statements => [
704           'SELECT COUNT * FROM foo',
705           'SELECT COUNT( * ) FROM foo',
706         ]
707       },
708       # single ? of unknown funcs do not unroll unless
709       # explicitly allowed (e.g. Like)
710       {
711         equal => 0,
712         statements => [
713           'SELECT foo FROM bar WHERE bar > foo ?',
714           'SELECT foo FROM bar WHERE bar > foo( ? )',
715         ]
716       },
717       {
718         equal => 1,
719         statements => [
720           'SELECT foo FROM bar WHERE bar LIKE ?',
721           'SELECT foo FROM bar WHERE bar LiKe (?)',
722           'SELECT foo FROM bar WHERE bar lIkE( (?))',
723         ]
724       },
725       # test multival
726       {
727         equal => 0,
728         statements => [
729           'SELECT foo FROM bar WHERE foo IN (?, ?)',
730           'SELECT foo FROM bar WHERE foo IN ?, ?',
731         ]
732       },
733       # math
734       {
735         equal => 0,
736         statements => [
737           'SELECT * FROM foo WHERE 1 = ( a > b)',
738           'SELECT * FROM foo WHERE 1 = a > b',
739           'SELECT * FROM foo WHERE (1 = a) > b',
740         ]
741       },
742       {
743         equal => 1,
744         statements => [
745           'SELECT * FROM foo WHERE bar = baz(buzz)',
746           'SELECT * FROM foo WHERE bar = (baz( buzz ))',
747         ]
748       },
749       # oddballs
750       {
751         equal => 1,
752         statements => [
753           'WHERE ( foo GLOB ? )',
754           'WHERE foo GLOB ?',
755         ],
756       },
757       {
758         equal => 1,
759         statements => [
760           'SELECT FIRST ? SKIP ? [me].[id], [me].[owner]
761             FROM [books] [me]
762           WHERE ( ( (EXISTS (
763             SELECT FIRST ? SKIP ? [owner].[id]
764               FROM [owners] [owner]
765             WHERE ( [books].[owner] = [owner].[id] )
766           )) AND [source] = ? ) )',
767           'SELECT FIRST ? SKIP ? [me].[id], [me].[owner]
768             FROM [books] [me]
769           WHERE ( ( EXISTS (
770             SELECT FIRST ? SKIP ? [owner].[id]
771               FROM [owners] [owner]
772             WHERE ( [books].[owner] = [owner].[id] )
773           ) AND [source] = ? ) )',
774         ],
775       },
776       {
777         equal => 1,
778         statements => [
779           'WHERE foo = ? FETCH FIRST 1 ROWS ONLY',
780           'WHERE ( foo = ? ) FETCH FIRST 1 ROWS ONLY',
781           'WHERE (( foo = ? )) FETCH FIRST 1 ROWS ONLY',
782         ],
783       },
784 );
785
786 my @bind_tests = (
787   # scalar - equal
788   {
789     equal => 1,
790     bindvals => [
791       undef,
792       undef,
793     ]
794   },
795   {
796     equal => 1,
797     bindvals => [
798       'foo',
799       'foo',
800     ]
801   },
802   {
803     equal => 1,
804     bindvals => [
805       42,
806       42,
807       '42',
808     ]
809   },
810
811   # scalarref - equal
812   {
813     equal => 1,
814     bindvals => [
815       \'foo',
816       \'foo',
817     ]
818   },
819   {
820     equal => 1,
821     bindvals => [
822       \42,
823       \42,
824       \'42',
825     ]
826   },
827
828   # arrayref - equal
829   {
830     equal => 1,
831     bindvals => [
832       [],
833       []
834     ]
835   },
836   {
837     equal => 1,
838     bindvals => [
839       [42],
840       [42],
841       ['42'],
842     ]
843   },
844   {
845     equal => 1,
846     bindvals => [
847       [1, 42],
848       [1, 42],
849       ['1', 42],
850       [1, '42'],
851       ['1', '42'],
852     ]
853   },
854
855   # hashref - equal
856   {
857     equal => 1,
858     bindvals => [
859       { foo => 42 },
860       { foo => 42 },
861       { foo => '42' },
862     ]
863   },
864   {
865     equal => 1,
866     bindvals => [
867       { foo => 42, bar => 1 },
868       { foo => 42, bar => 1 },
869       { foo => '42', bar => 1 },
870     ]
871   },
872
873   # blessed object - equal
874   {
875     equal => 1,
876     bindvals => [
877       bless(\(local $_ = 42), 'Life::Universe::Everything'),
878       bless(\(local $_ = 42), 'Life::Universe::Everything'),
879     ]
880   },
881   {
882     equal => 1,
883     bindvals => [
884       bless([42], 'Life::Universe::Everything'),
885       bless([42], 'Life::Universe::Everything'),
886     ]
887   },
888   {
889     equal => 1,
890     bindvals => [
891       bless({ answer => 42 }, 'Life::Universe::Everything'),
892       bless({ answer => 42 }, 'Life::Universe::Everything'),
893     ]
894   },
895
896   # complex data structure - equal
897   {
898     equal => 1,
899     bindvals => [
900       [42, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
901       [42, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
902     ]
903   },
904
905
906   # scalar - different
907   {
908     equal => 0,
909     bindvals => [
910       undef,
911       'foo',
912       42,
913     ]
914   },
915
916   # scalarref - different
917   {
918     equal => 0,
919     bindvals => [
920       \undef,
921       \'foo',
922       \42,
923     ]
924   },
925
926   # arrayref - different
927   {
928     equal => 0,
929     bindvals => [
930       [undef],
931       ['foo'],
932       [42],
933     ]
934   },
935
936   # hashref - different
937   {
938     equal => 0,
939     bindvals => [
940       { foo => undef },
941       { foo => 'bar' },
942       { foo => 42 },
943     ]
944   },
945
946   # different types
947   {
948     equal => 0,
949     bindvals => [
950       'foo',
951       \'foo',
952       ['foo'],
953       { foo => 'bar' },
954     ]
955   },
956
957   # complex data structure - different
958   {
959     equal => 0,
960     bindvals => [
961       [42, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
962       [43, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
963       [42, { foo => 'baz', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
964       [42, { bar => 'bar', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
965       [42, { foo => 'bar', quuux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
966       [42, { foo => 'bar', quux => [0, 1, 2, \3, { quux => [4, 5] } ] }, 8 ],
967       [42, { foo => 'bar', quux => [1, 2, 3, { quux => [4, 5] } ] }, 8 ],
968       [42, { foo => 'bar', quux => [1, 2, \4, { quux => [4, 5] } ] }, 8 ],
969       [42, { foo => 'bar', quux => [1, 2, \3, { quuux => [4, 5] } ] }, 8 ],
970       [42, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5, 6] } ] }, 8 ],
971       [42, { foo => 'bar', quux => [1, 2, \3, { quux => 4 } ] }, 8 ],
972       [42, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5], quuux => 1 } ] }, 8 ],
973       [42, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8, 9 ],
974     ]
975   },
976 );
977
978 use_ok('SQL::Abstract::Test', import => [qw(
979   eq_sql_bind eq_sql eq_bind is_same_sql_bind
980 )]);
981
982 for my $test ( @sql_tests ) {
983
984   # this does not work on 5.8.8 and earlier :(
985   #local @{*SQL::Abstract::Test::}{keys %{$test->{opts}}} = map { \$_ } values %{$test->{opts}}
986   #  if $test->{opts};
987
988   my %restore_globals;
989
990   for (keys %{$test->{opts} || {} }) {
991     $restore_globals{$_} = ${${*SQL::Abstract::Test::}{$_}};
992     ${*SQL::Abstract::Test::}{$_} = \ do { my $cp = $test->{opts}{$_} };
993   }
994
995   my $statements = $test->{statements};
996   while (@$statements) {
997     my $sql1 = shift @$statements;
998     foreach my $sql2 (@$statements) {
999
1000       my $equal = eq_sql($sql1, $sql2);
1001
1002       TODO: {
1003         local $TODO = $test->{todo} if $test->{todo};
1004
1005         if ($test->{equal}) {
1006           ok($equal, "equal SQL expressions should have been considered equal");
1007         } else {
1008           ok(!$equal, "different SQL expressions should have been considered not equal");
1009         }
1010
1011         if ($equal ^ $test->{equal}) {
1012           my ($ast1, $ast2) = map { SQL::Abstract::Test::parse ($_) } ($sql1, $sql2);
1013           $_ = Dumper $_ for ($ast1, $ast2);
1014
1015           diag "sql1: $sql1";
1016           diag "sql2: $sql2";
1017           note $SQL::Abstract::Test::sql_differ;
1018           note "ast1: $ast1";
1019           note "ast2: $ast2";
1020         }
1021       }
1022     }
1023   }
1024
1025   ${*SQL::Abstract::Test::}{$_} = \$restore_globals{$_}
1026     for keys %restore_globals;
1027 }
1028
1029 for my $test (@bind_tests) {
1030   my $bindvals = $test->{bindvals};
1031   while (@$bindvals) {
1032     my $bind1 = shift @$bindvals;
1033     foreach my $bind2 (@$bindvals) {
1034       my $equal = eq_bind($bind1, $bind2);
1035       if ($test->{equal}) {
1036         ok($equal, "equal bind values considered equal");
1037       } else {
1038         ok(!$equal, "different bind values considered not equal");
1039       }
1040
1041       if ($equal ^ $test->{equal}) {
1042         diag("bind1: " . Dumper($bind1));
1043         diag("bind2: " . Dumper($bind2));
1044       }
1045     }
1046   }
1047 }
1048
1049 ok(eq_sql_bind(
1050     "SELECT * FROM foo WHERE id = ?", [42],
1051     "SELECT * FROM foo WHERE (id = ?)", [42],
1052   ),
1053   "eq_sql_bind considers equal SQL expressions and bind values equal"
1054 );
1055
1056
1057 ok(!eq_sql_bind(
1058     "SELECT * FROM foo WHERE id = ?", [42],
1059     "SELECT * FROM foo WHERE (id = ?)", [0],
1060   ),
1061   "eq_sql_bind considers equal SQL expressions and different bind values different"
1062 );
1063
1064 ok(!eq_sql_bind(
1065     "SELECT * FROM foo WHERE id = ?", [42],
1066     "SELECT * FROM bar WHERE (id = ?)", [42],
1067   ),
1068   "eq_sql_bind considers different SQL expressions and equal bind values different"
1069 );
1070
1071 # test diag string
1072 ok (! eq_sql (
1073   'SELECT owner_name FROM books me WHERE ( source = ? )',
1074   'SELECT owner_name FROM books me WHERE ( sUOrce = ? )',
1075 ));
1076 like(
1077   $SQL::Abstract::Test::sql_differ,
1078   qr/\Q[ source ] != [ sUOrce ]/,
1079   'expected debug of literal diff',
1080 );
1081
1082 ok (! eq_sql (
1083   'SELECT owner_name FROM books me ORDER BY owner_name',
1084   'SELECT owner_name FROM books me GROUP BY owner_name',
1085 ));
1086 like(
1087   $SQL::Abstract::Test::sql_differ,
1088   qr/\QOP [ORDER BY] != [GROUP BY]/,
1089   'expected debug of op diff',
1090 );
1091
1092 ok (! eq_sql (
1093   'SELECT owner_name FROM books WHERE ( source = ? )',
1094   'SELECT owner_name FROM books'
1095 ));
1096
1097 like(
1098   $SQL::Abstract::Test::sql_differ,
1099   qr|\Q[WHERE source = ?] != [N/A]|,
1100   'expected debug of missing branch',
1101 );
1102
1103 done_testing;