1--
2-- UNION (also INTERSECT, EXCEPT)
3--
4
5-- Simple UNION constructs
6
7SELECT 1 AS two UNION SELECT 2 ORDER BY 1;
8
9SELECT 1 AS one UNION SELECT 1 ORDER BY 1;
10
11SELECT 1 AS two UNION ALL SELECT 2;
12
13SELECT 1 AS two UNION ALL SELECT 1;
14
15SELECT 1 AS three UNION SELECT 2 UNION SELECT 3 ORDER BY 1;
16
17SELECT 1 AS two UNION SELECT 2 UNION SELECT 2 ORDER BY 1;
18
19SELECT 1 AS three UNION SELECT 2 UNION ALL SELECT 2 ORDER BY 1;
20
21SELECT 1.1 AS two UNION SELECT 2.2 ORDER BY 1;
22
23-- Mixed types
24
25SELECT 1.1 AS two UNION SELECT 2 ORDER BY 1;
26
27SELECT 1 AS two UNION SELECT 2.2 ORDER BY 1;
28
29SELECT 1 AS one UNION SELECT 1.0::float8 ORDER BY 1;
30
31SELECT 1.1 AS two UNION ALL SELECT 2 ORDER BY 1;
32
33SELECT 1.0::float8 AS two UNION ALL SELECT 1 ORDER BY 1;
34
35SELECT 1.1 AS three UNION SELECT 2 UNION SELECT 3 ORDER BY 1;
36
37SELECT 1.1::float8 AS two UNION SELECT 2 UNION SELECT 2.0::float8 ORDER BY 1;
38
39SELECT 1.1 AS three UNION SELECT 2 UNION ALL SELECT 2 ORDER BY 1;
40
41SELECT 1.1 AS two UNION (SELECT 2 UNION ALL SELECT 2) ORDER BY 1;
42
43--
44-- Try testing from tables...
45--
46
47SELECT f1 AS five FROM FLOAT8_TBL
48UNION
49SELECT f1 FROM FLOAT8_TBL
50ORDER BY 1;
51
52SELECT f1 AS ten FROM FLOAT8_TBL
53UNION ALL
54SELECT f1 FROM FLOAT8_TBL;
55
56SELECT f1 AS nine FROM FLOAT8_TBL
57UNION
58SELECT f1 FROM INT4_TBL
59ORDER BY 1;
60
61SELECT f1 AS ten FROM FLOAT8_TBL
62UNION ALL
63SELECT f1 FROM INT4_TBL;
64
65SELECT f1 AS five FROM FLOAT8_TBL
66  WHERE f1 BETWEEN -1e6 AND 1e6
67UNION
68SELECT f1 FROM INT4_TBL
69  WHERE f1 BETWEEN 0 AND 1000000
70ORDER BY 1;
71
72SELECT CAST(f1 AS char(4)) AS three FROM VARCHAR_TBL
73UNION
74SELECT f1 FROM CHAR_TBL
75ORDER BY 1;
76
77SELECT f1 AS three FROM VARCHAR_TBL
78UNION
79SELECT CAST(f1 AS varchar) FROM CHAR_TBL
80ORDER BY 1;
81
82SELECT f1 AS eight FROM VARCHAR_TBL
83UNION ALL
84SELECT f1 FROM CHAR_TBL;
85
86SELECT f1 AS five FROM TEXT_TBL
87UNION
88SELECT f1 FROM VARCHAR_TBL
89UNION
90SELECT TRIM(TRAILING FROM f1) FROM CHAR_TBL
91ORDER BY 1;
92
93--
94-- INTERSECT and EXCEPT
95--
96
97SELECT q2 FROM int8_tbl INTERSECT SELECT q1 FROM int8_tbl ORDER BY 1;
98
99SELECT q2 FROM int8_tbl INTERSECT ALL SELECT q1 FROM int8_tbl ORDER BY 1;
100
101SELECT q2 FROM int8_tbl EXCEPT SELECT q1 FROM int8_tbl ORDER BY 1;
102
103SELECT q2 FROM int8_tbl EXCEPT ALL SELECT q1 FROM int8_tbl ORDER BY 1;
104
105SELECT q2 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q1 FROM int8_tbl ORDER BY 1;
106
107SELECT q1 FROM int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDER BY 1;
108
109SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q2 FROM int8_tbl ORDER BY 1;
110
111SELECT q1 FROM int8_tbl EXCEPT ALL SELECT DISTINCT q2 FROM int8_tbl ORDER BY 1;
112
113SELECT q1 FROM int8_tbl EXCEPT ALL SELECT q1 FROM int8_tbl FOR NO KEY UPDATE;
114
115-- nested cases
116(SELECT 1,2,3 UNION SELECT 4,5,6) INTERSECT SELECT 4,5,6;
117(SELECT 1,2,3 UNION SELECT 4,5,6 ORDER BY 1,2) INTERSECT SELECT 4,5,6;
118(SELECT 1,2,3 UNION SELECT 4,5,6) EXCEPT SELECT 4,5,6;
119(SELECT 1,2,3 UNION SELECT 4,5,6 ORDER BY 1,2) EXCEPT SELECT 4,5,6;
120
121-- exercise both hashed and sorted implementations of INTERSECT/EXCEPT
122
123set enable_hashagg to on;
124
125explain (costs off)
126select count(*) from
127  ( select unique1 from tenk1 intersect select fivethous from tenk1 ) ss;
128select count(*) from
129  ( select unique1 from tenk1 intersect select fivethous from tenk1 ) ss;
130
131explain (costs off)
132select unique1 from tenk1 except select unique2 from tenk1 where unique2 != 10;
133select unique1 from tenk1 except select unique2 from tenk1 where unique2 != 10;
134
135set enable_hashagg to off;
136
137explain (costs off)
138select count(*) from
139  ( select unique1 from tenk1 intersect select fivethous from tenk1 ) ss;
140select count(*) from
141  ( select unique1 from tenk1 intersect select fivethous from tenk1 ) ss;
142
143explain (costs off)
144select unique1 from tenk1 except select unique2 from tenk1 where unique2 != 10;
145select unique1 from tenk1 except select unique2 from tenk1 where unique2 != 10;
146
147reset enable_hashagg;
148
149--
150-- Mixed types
151--
152
153SELECT f1 FROM float8_tbl INTERSECT SELECT f1 FROM int4_tbl ORDER BY 1;
154
155SELECT f1 FROM float8_tbl EXCEPT SELECT f1 FROM int4_tbl ORDER BY 1;
156
157--
158-- Operator precedence and (((((extra))))) parentheses
159--
160
161SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl  ORDER BY 1;
162
163SELECT q1 FROM int8_tbl INTERSECT (((SELECT q2 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl))) ORDER BY 1;
164
165(((SELECT q1 FROM int8_tbl INTERSECT SELECT q2 FROM int8_tbl ORDER BY 1))) UNION ALL SELECT q2 FROM int8_tbl;
166
167SELECT q1 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl EXCEPT SELECT q1 FROM int8_tbl ORDER BY 1;
168
169SELECT q1 FROM int8_tbl UNION ALL (((SELECT q2 FROM int8_tbl EXCEPT SELECT q1 FROM int8_tbl ORDER BY 1)));
170
171(((SELECT q1 FROM int8_tbl UNION ALL SELECT q2 FROM int8_tbl))) EXCEPT SELECT q1 FROM int8_tbl ORDER BY 1;
172
173--
174-- Subqueries with ORDER BY & LIMIT clauses
175--
176
177-- In this syntax, ORDER BY/LIMIT apply to the result of the EXCEPT
178SELECT q1,q2 FROM int8_tbl EXCEPT SELECT q2,q1 FROM int8_tbl
179ORDER BY q2,q1;
180
181-- This should fail, because q2 isn't a name of an EXCEPT output column
182SELECT q1 FROM int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1;
183
184-- But this should work:
185SELECT q1 FROM int8_tbl EXCEPT (((SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1))) ORDER BY 1;
186
187--
188-- New syntaxes (7.1) permit new tests
189--
190
191(((((select * from int8_tbl)))));
192
193--
194-- Check behavior with empty select list (allowed since 9.4)
195--
196
197select union select;
198select intersect select;
199select except select;
200
201-- check hashed implementation
202set enable_hashagg = true;
203set enable_sort = false;
204
205explain (costs off)
206select from generate_series(1,5) union select from generate_series(1,3);
207explain (costs off)
208select from generate_series(1,5) intersect select from generate_series(1,3);
209
210select from generate_series(1,5) union select from generate_series(1,3);
211select from generate_series(1,5) union all select from generate_series(1,3);
212select from generate_series(1,5) intersect select from generate_series(1,3);
213select from generate_series(1,5) intersect all select from generate_series(1,3);
214select from generate_series(1,5) except select from generate_series(1,3);
215select from generate_series(1,5) except all select from generate_series(1,3);
216
217-- check sorted implementation
218set enable_hashagg = false;
219set enable_sort = true;
220
221explain (costs off)
222select from generate_series(1,5) union select from generate_series(1,3);
223explain (costs off)
224select from generate_series(1,5) intersect select from generate_series(1,3);
225
226select from generate_series(1,5) union select from generate_series(1,3);
227select from generate_series(1,5) union all select from generate_series(1,3);
228select from generate_series(1,5) intersect select from generate_series(1,3);
229select from generate_series(1,5) intersect all select from generate_series(1,3);
230select from generate_series(1,5) except select from generate_series(1,3);
231select from generate_series(1,5) except all select from generate_series(1,3);
232
233reset enable_hashagg;
234reset enable_sort;
235
236--
237-- Check handling of a case with unknown constants.  We don't guarantee
238-- an undecorated constant will work in all cases, but historically this
239-- usage has worked, so test we don't break it.
240--
241
242SELECT a.f1 FROM (SELECT 'test' AS f1 FROM varchar_tbl) a
243UNION
244SELECT b.f1 FROM (SELECT f1 FROM varchar_tbl) b
245ORDER BY 1;
246
247-- This should fail, but it should produce an error cursor
248SELECT '3.4'::numeric UNION SELECT 'foo';
249
250--
251-- Test that expression-index constraints can be pushed down through
252-- UNION or UNION ALL
253--
254
255CREATE TEMP TABLE t1 (a text, b text);
256CREATE INDEX t1_ab_idx on t1 ((a || b));
257CREATE TEMP TABLE t2 (ab text primary key);
258INSERT INTO t1 VALUES ('a', 'b'), ('x', 'y');
259INSERT INTO t2 VALUES ('ab'), ('xy');
260
261set enable_seqscan = off;
262set enable_indexscan = on;
263set enable_bitmapscan = off;
264
265explain (costs off)
266 SELECT * FROM
267 (SELECT a || b AS ab FROM t1
268  UNION ALL
269  SELECT * FROM t2) t
270 WHERE ab = 'ab';
271
272explain (costs off)
273 SELECT * FROM
274 (SELECT a || b AS ab FROM t1
275  UNION
276  SELECT * FROM t2) t
277 WHERE ab = 'ab';
278
279--
280-- Test that ORDER BY for UNION ALL can be pushed down to inheritance
281-- children.
282--
283
284CREATE TEMP TABLE t1c (b text, a text);
285ALTER TABLE t1c INHERIT t1;
286CREATE TEMP TABLE t2c (primary key (ab)) INHERITS (t2);
287INSERT INTO t1c VALUES ('v', 'w'), ('c', 'd'), ('m', 'n'), ('e', 'f');
288INSERT INTO t2c VALUES ('vw'), ('cd'), ('mn'), ('ef');
289CREATE INDEX t1c_ab_idx on t1c ((a || b));
290
291set enable_seqscan = on;
292set enable_indexonlyscan = off;
293
294explain (costs off)
295  SELECT * FROM
296  (SELECT a || b AS ab FROM t1
297   UNION ALL
298   SELECT ab FROM t2) t
299  ORDER BY 1 LIMIT 8;
300
301  SELECT * FROM
302  (SELECT a || b AS ab FROM t1
303   UNION ALL
304   SELECT ab FROM t2) t
305  ORDER BY 1 LIMIT 8;
306
307reset enable_seqscan;
308reset enable_indexscan;
309reset enable_bitmapscan;
310
311-- This simpler variant of the above test has been observed to fail differently
312
313create table events (event_id int primary key);
314create table other_events (event_id int primary key);
315create table events_child () inherits (events);
316
317explain (costs off)
318select event_id
319 from (select event_id from events
320       union all
321       select event_id from other_events) ss
322 order by event_id;
323
324drop table events_child, events, other_events;
325
326reset enable_indexonlyscan;
327
328-- Test constraint exclusion of UNION ALL subqueries
329explain (costs off)
330 SELECT * FROM
331  (SELECT 1 AS t, * FROM tenk1 a
332   UNION ALL
333   SELECT 2 AS t, * FROM tenk1 b) c
334 WHERE t = 2;
335
336-- Test that we push quals into UNION sub-selects only when it's safe
337explain (costs off)
338SELECT * FROM
339  (SELECT 1 AS t, 2 AS x
340   UNION
341   SELECT 2 AS t, 4 AS x) ss
342WHERE x < 4
343ORDER BY x;
344
345SELECT * FROM
346  (SELECT 1 AS t, 2 AS x
347   UNION
348   SELECT 2 AS t, 4 AS x) ss
349WHERE x < 4
350ORDER BY x;
351
352explain (costs off)
353SELECT * FROM
354  (SELECT 1 AS t, generate_series(1,10) AS x
355   UNION
356   SELECT 2 AS t, 4 AS x) ss
357WHERE x < 4
358ORDER BY x;
359
360SELECT * FROM
361  (SELECT 1 AS t, generate_series(1,10) AS x
362   UNION
363   SELECT 2 AS t, 4 AS x) ss
364WHERE x < 4
365ORDER BY x;
366
367explain (costs off)
368SELECT * FROM
369  (SELECT 1 AS t, (random()*3)::int AS x
370   UNION
371   SELECT 2 AS t, 4 AS x) ss
372WHERE x > 3
373ORDER BY x;
374
375SELECT * FROM
376  (SELECT 1 AS t, (random()*3)::int AS x
377   UNION
378   SELECT 2 AS t, 4 AS x) ss
379WHERE x > 3
380ORDER BY x;
381
382-- Test cases where the native ordering of a sub-select has more pathkeys
383-- than the outer query cares about
384explain (costs off)
385select distinct q1 from
386  (select distinct * from int8_tbl i81
387   union all
388   select distinct * from int8_tbl i82) ss
389where q2 = q2;
390
391select distinct q1 from
392  (select distinct * from int8_tbl i81
393   union all
394   select distinct * from int8_tbl i82) ss
395where q2 = q2;
396
397explain (costs off)
398select distinct q1 from
399  (select distinct * from int8_tbl i81
400   union all
401   select distinct * from int8_tbl i82) ss
402where -q1 = q2;
403
404select distinct q1 from
405  (select distinct * from int8_tbl i81
406   union all
407   select distinct * from int8_tbl i82) ss
408where -q1 = q2;
409
410-- Test proper handling of parameterized appendrel paths when the
411-- potential join qual is expensive
412create function expensivefunc(int) returns int
413language plpgsql immutable strict cost 10000
414as $$begin return $1; end$$;
415
416create temp table t3 as select generate_series(-1000,1000) as x;
417create index t3i on t3 (expensivefunc(x));
418analyze t3;
419
420explain (costs off)
421select * from
422  (select * from t3 a union all select * from t3 b) ss
423  join int4_tbl on f1 = expensivefunc(x);
424select * from
425  (select * from t3 a union all select * from t3 b) ss
426  join int4_tbl on f1 = expensivefunc(x);
427
428drop table t3;
429drop function expensivefunc(int);
430
431-- Test handling of appendrel quals that const-simplify into an AND
432explain (costs off)
433select * from
434  (select *, 0 as x from int8_tbl a
435   union all
436   select *, 1 as x from int8_tbl b) ss
437where (x = 0) or (q1 >= q2 and q1 <= q2);
438select * from
439  (select *, 0 as x from int8_tbl a
440   union all
441   select *, 1 as x from int8_tbl b) ss
442where (x = 0) or (q1 >= q2 and q1 <= q2);
443