Finish a RHS branch before applying ASC/DESC mods
[scpubgit/Q-Branch.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 => 0,
622         opts => { order_by_asc_significant => 1 },
623         statements => [
624           q/SELECT * FROM foo ORDER BY bar/,
625           q/SELECT * FROM foo ORDER BY bar ASC/,
626           q/SELECT * FROM foo ORDER BY bar desc/,
627         ],
628       },
629
630       # list permutations
631       {
632         equal => 0,
633         statements => [
634           'SELECT a,b,c FROM foo',
635           'SELECT a,c,b FROM foo',
636           'SELECT b,a,c FROM foo',
637           'SELECT b,c,a FROM foo',
638           'SELECT c,a,b FROM foo',
639           'SELECT c,b,a FROM foo',
640         ],
641       },
642       {
643         equal => 0,
644         statements => [
645           'SELECT * FROM foo WHERE a IN (1,2,3)',
646           'SELECT * FROM foo WHERE a IN (1,3,2)',
647           'SELECT * FROM foo WHERE a IN (2,1,3)',
648           'SELECT * FROM foo WHERE a IN (2,3,1)',
649           'SELECT * FROM foo WHERE a IN (3,1,2)',
650           'SELECT * FROM foo WHERE a IN (3,2,1)',
651         ]
652       },
653
654       # list consistency
655       {
656         equal => 0,
657         statements => [
658           'SELECT a,b FROM foo',
659           'SELECT a,,b FROM foo',
660           'SELECT a,b, FROM foo',
661           'SELECT ,a,b, FROM foo',
662           'SELECT ,a,,b, FROM foo',
663         ],
664       },
665
666       # misc func
667       {
668         equal => 0,
669         statements => [
670           'SELECT count(*) FROM foo',
671           'SELECT count(*) AS bar FROM foo',
672           'SELECT count(*) AS "bar" FROM foo',
673           'SELECT count(a) FROM foo',
674           'SELECT count(1) FROM foo',
675         ]
676       },
677       {
678         equal => 1,
679         statements => [
680           'SELECT foo() bar FROM baz',
681           'SELECT foo (  )bar FROM baz',
682           'SELECT foo (())bar FROM baz',
683           'SELECT foo(( ) ) bar FROM baz',
684         ]
685       },
686       {
687         equal => 0,
688         statements => [
689           'SELECT foo() FROM bar',
690           'SELECT foo FROM bar',
691           'SELECT foo FROM bar ()',
692         ]
693       },
694       {
695         equal => 0,
696         statements => [
697           'SELECT COUNT * FROM foo',
698           'SELECT COUNT( * ) FROM foo',
699         ]
700       },
701       # single ? of unknown funcs do not unroll unless
702       # explicitly allowed (e.g. Like)
703       {
704         equal => 0,
705         statements => [
706           'SELECT foo FROM bar WHERE bar > foo ?',
707           'SELECT foo FROM bar WHERE bar > foo( ? )',
708         ]
709       },
710       {
711         equal => 1,
712         statements => [
713           'SELECT foo FROM bar WHERE bar LIKE ?',
714           'SELECT foo FROM bar WHERE bar LiKe (?)',
715           'SELECT foo FROM bar WHERE bar lIkE( (?))',
716         ]
717       },
718       # test multival
719       {
720         equal => 0,
721         statements => [
722           'SELECT foo FROM bar WHERE foo IN (?, ?)',
723           'SELECT foo FROM bar WHERE foo IN ?, ?',
724         ]
725       },
726       # math
727       {
728         equal => 0,
729         statements => [
730           'SELECT * FROM foo WHERE 1 = ( a > b)',
731           'SELECT * FROM foo WHERE 1 = a > b',
732           'SELECT * FROM foo WHERE (1 = a) > b',
733         ]
734       },
735       {
736         equal => 1,
737         statements => [
738           'SELECT * FROM foo WHERE bar = baz(buzz)',
739           'SELECT * FROM foo WHERE bar = (baz( buzz ))',
740         ]
741       },
742       # oddballs
743       {
744         equal => 1,
745         statements => [
746           'WHERE ( foo GLOB ? )',
747           'WHERE foo GLOB ?',
748         ],
749       },
750       {
751         equal => 1,
752         statements => [
753           'SELECT FIRST ? SKIP ? [me].[id], [me].[owner]
754             FROM [books] [me]
755           WHERE ( ( (EXISTS (
756             SELECT FIRST ? SKIP ? [owner].[id]
757               FROM [owners] [owner]
758             WHERE ( [books].[owner] = [owner].[id] )
759           )) AND [source] = ? ) )',
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         ],
768       },
769 );
770
771 my @bind_tests = (
772   # scalar - equal
773   {
774     equal => 1,
775     bindvals => [
776       undef,
777       undef,
778     ]
779   },
780   {
781     equal => 1,
782     bindvals => [
783       'foo',
784       'foo',
785     ]
786   },
787   {
788     equal => 1,
789     bindvals => [
790       42,
791       42,
792       '42',
793     ]
794   },
795
796   # scalarref - equal
797   {
798     equal => 1,
799     bindvals => [
800       \'foo',
801       \'foo',
802     ]
803   },
804   {
805     equal => 1,
806     bindvals => [
807       \42,
808       \42,
809       \'42',
810     ]
811   },
812
813   # arrayref - equal
814   {
815     equal => 1,
816     bindvals => [
817       [],
818       []
819     ]
820   },
821   {
822     equal => 1,
823     bindvals => [
824       [42],
825       [42],
826       ['42'],
827     ]
828   },
829   {
830     equal => 1,
831     bindvals => [
832       [1, 42],
833       [1, 42],
834       ['1', 42],
835       [1, '42'],
836       ['1', '42'],
837     ]
838   },
839
840   # hashref - equal
841   {
842     equal => 1,
843     bindvals => [
844       { foo => 42 },
845       { foo => 42 },
846       { foo => '42' },
847     ]
848   },
849   {
850     equal => 1,
851     bindvals => [
852       { foo => 42, bar => 1 },
853       { foo => 42, bar => 1 },
854       { foo => '42', bar => 1 },
855     ]
856   },
857
858   # blessed object - equal
859   {
860     equal => 1,
861     bindvals => [
862       bless(\(local $_ = 42), 'Life::Universe::Everything'),
863       bless(\(local $_ = 42), 'Life::Universe::Everything'),
864     ]
865   },
866   {
867     equal => 1,
868     bindvals => [
869       bless([42], 'Life::Universe::Everything'),
870       bless([42], 'Life::Universe::Everything'),
871     ]
872   },
873   {
874     equal => 1,
875     bindvals => [
876       bless({ answer => 42 }, 'Life::Universe::Everything'),
877       bless({ answer => 42 }, 'Life::Universe::Everything'),
878     ]
879   },
880
881   # complex data structure - equal
882   {
883     equal => 1,
884     bindvals => [
885       [42, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
886       [42, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
887     ]
888   },
889
890
891   # scalar - different
892   {
893     equal => 0,
894     bindvals => [
895       undef,
896       'foo',
897       42,
898     ]
899   },
900
901   # scalarref - different
902   {
903     equal => 0,
904     bindvals => [
905       \undef,
906       \'foo',
907       \42,
908     ]
909   },
910
911   # arrayref - different
912   {
913     equal => 0,
914     bindvals => [
915       [undef],
916       ['foo'],
917       [42],
918     ]
919   },
920
921   # hashref - different
922   {
923     equal => 0,
924     bindvals => [
925       { foo => undef },
926       { foo => 'bar' },
927       { foo => 42 },
928     ]
929   },
930
931   # different types
932   {
933     equal => 0,
934     bindvals => [
935       'foo',
936       \'foo',
937       ['foo'],
938       { foo => 'bar' },
939     ]
940   },
941
942   # complex data structure - different
943   {
944     equal => 0,
945     bindvals => [
946       [42, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
947       [43, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
948       [42, { foo => 'baz', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
949       [42, { bar => 'bar', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
950       [42, { foo => 'bar', quuux => [1, 2, \3, { quux => [4, 5] } ] }, 8 ],
951       [42, { foo => 'bar', quux => [0, 1, 2, \3, { quux => [4, 5] } ] }, 8 ],
952       [42, { foo => 'bar', quux => [1, 2, 3, { quux => [4, 5] } ] }, 8 ],
953       [42, { foo => 'bar', quux => [1, 2, \4, { quux => [4, 5] } ] }, 8 ],
954       [42, { foo => 'bar', quux => [1, 2, \3, { quuux => [4, 5] } ] }, 8 ],
955       [42, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5, 6] } ] }, 8 ],
956       [42, { foo => 'bar', quux => [1, 2, \3, { quux => 4 } ] }, 8 ],
957       [42, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5], quuux => 1 } ] }, 8 ],
958       [42, { foo => 'bar', quux => [1, 2, \3, { quux => [4, 5] } ] }, 8, 9 ],
959     ]
960   },
961 );
962
963 plan tests => 1 +
964   sum(
965     map { $_ * ($_ - 1) / 2 }
966       map { scalar @{$_->{statements}} }
967         @sql_tests
968   ) +
969   sum(
970     map { $_ * ($_ - 1) / 2 }
971       map { scalar @{$_->{bindvals}} }
972         @bind_tests
973   ) +
974   9;
975
976 use_ok('SQL::Abstract::Test', import => [qw(
977   eq_sql_bind eq_sql eq_bind is_same_sql_bind
978 )]);
979
980 for my $test (@sql_tests) {
981
982   # this does not work on 5.8.8 and earlier :(
983   #local @{*SQL::Abstract::Test::}{keys %{$test->{opts}}} = map { \$_ } values %{$test->{opts}}
984   #  if $test->{opts};
985
986   my %restore_globals;
987
988   for (keys %{$test->{opts} || {} }) {
989     $restore_globals{$_} = ${${*SQL::Abstract::Test::}{$_}};
990     ${*SQL::Abstract::Test::}{$_} = \ do { my $cp = $test->{opts}{$_} };
991   }
992
993   my $statements = $test->{statements};
994   while (@$statements) {
995     my $sql1 = shift @$statements;
996     foreach my $sql2 (@$statements) {
997
998       my $equal = eq_sql($sql1, $sql2);
999
1000       TODO: {
1001         local $TODO = $test->{todo} if $test->{todo};
1002
1003         if ($test->{equal}) {
1004           ok($equal, "equal SQL expressions should have been considered equal");
1005         } else {
1006           ok(!$equal, "different SQL expressions should have been considered not equal");
1007         }
1008
1009         if ($equal ^ $test->{equal}) {
1010           my ($ast1, $ast2) = map { SQL::Abstract::Test::parse ($_) } ($sql1, $sql2);
1011           $_ = Dumper $_ for ($ast1, $ast2);
1012
1013           diag "sql1: $sql1";
1014           diag "sql2: $sql2";
1015           note $SQL::Abstract::Test::sql_differ;
1016           note "ast1: $ast1";
1017           note "ast2: $ast2";
1018         }
1019       }
1020     }
1021   }
1022
1023   ${*SQL::Abstract::Test::}{$_} = \$restore_globals{$_}
1024     for keys %restore_globals;
1025 }
1026
1027 for my $test (@bind_tests) {
1028   my $bindvals = $test->{bindvals};
1029   while (@$bindvals) {
1030     my $bind1 = shift @$bindvals;
1031     foreach my $bind2 (@$bindvals) {
1032       my $equal = eq_bind($bind1, $bind2);
1033       if ($test->{equal}) {
1034         ok($equal, "equal bind values considered equal");
1035       } else {
1036         ok(!$equal, "different bind values considered not equal");
1037       }
1038
1039       if ($equal ^ $test->{equal}) {
1040         diag("bind1: " . Dumper($bind1));
1041         diag("bind2: " . Dumper($bind2));
1042       }
1043     }
1044   }
1045 }
1046
1047 ok(eq_sql_bind(
1048     "SELECT * FROM foo WHERE id = ?", [42],
1049     "SELECT * FROM foo WHERE (id = ?)", [42],
1050   ),
1051   "eq_sql_bind considers equal SQL expressions and bind values equal"
1052 );
1053
1054
1055 ok(!eq_sql_bind(
1056     "SELECT * FROM foo WHERE id = ?", [42],
1057     "SELECT * FROM foo WHERE (id = ?)", [0],
1058   ),
1059   "eq_sql_bind considers equal SQL expressions and different bind values different"
1060 );
1061
1062 ok(!eq_sql_bind(
1063     "SELECT * FROM foo WHERE id = ?", [42],
1064     "SELECT * FROM bar WHERE (id = ?)", [42],
1065   ),
1066   "eq_sql_bind considers different SQL expressions and equal bind values different"
1067 );
1068
1069 # test diag string
1070 ok (! eq_sql (
1071   'SELECT owner_name FROM books me WHERE ( source = ? )',
1072   'SELECT owner_name FROM books me WHERE ( sUOrce = ? )',
1073 ));
1074 like(
1075   $SQL::Abstract::Test::sql_differ,
1076   qr/\Q[ source ] != [ sUOrce ]/,
1077   'expected debug of literal diff',
1078 );
1079
1080 ok (! eq_sql (
1081   'SELECT owner_name FROM books me ORDER BY owner_name',
1082   'SELECT owner_name FROM books me GROUP BY owner_name',
1083 ));
1084 like(
1085   $SQL::Abstract::Test::sql_differ,
1086   qr/\QOP [ORDER BY] != [GROUP BY]/,
1087   'expected debug of op diff',
1088 );
1089
1090 ok (! eq_sql (
1091   'SELECT owner_name FROM books WHERE ( source = ? )',
1092   'SELECT owner_name FROM books'
1093 ));
1094
1095 like(
1096   $SQL::Abstract::Test::sql_differ,
1097   qr|\Q[WHERE source = ?] != [N/A]|,
1098   'expected debug of missing branch',
1099 );
1100