1 -- ===================================================================
3 -- ===================================================================
5 CREATE EXTENSION postgres_fdw;
7 CREATE SERVER testserver1 FOREIGN DATA WRAPPER postgres_fdw;
10 EXECUTE $$CREATE SERVER loopback FOREIGN DATA WRAPPER postgres_fdw
11 OPTIONS (dbname '$$||current_database()||$$',
12 port '$$||current_setting('port')||$$'
14 EXECUTE $$CREATE SERVER loopback2 FOREIGN DATA WRAPPER postgres_fdw
15 OPTIONS (dbname '$$||current_database()||$$',
16 port '$$||current_setting('port')||$$'
21 CREATE USER MAPPING FOR public SERVER testserver1
22 OPTIONS (user 'value', password 'value');
23 CREATE USER MAPPING FOR CURRENT_USER SERVER loopback;
24 CREATE USER MAPPING FOR CURRENT_USER SERVER loopback2;
26 -- ===================================================================
27 -- create objects used through FDW loopback server
28 -- ===================================================================
29 CREATE TYPE user_enum AS ENUM ('foo', 'bar', 'buz');
31 CREATE TABLE "S 1"."T 1" (
40 CONSTRAINT t1_pkey PRIMARY KEY ("C 1")
42 CREATE TABLE "S 1"."T 2" (
45 CONSTRAINT t2_pkey PRIMARY KEY (c1)
47 CREATE TABLE "S 1"."T 3" (
51 CONSTRAINT t3_pkey PRIMARY KEY (c1)
53 CREATE TABLE "S 1"."T 4" (
57 CONSTRAINT t4_pkey PRIMARY KEY (c1)
60 INSERT INTO "S 1"."T 1"
63 to_char(id, 'FM00000'),
64 '1970-01-01'::timestamptz + ((id % 100) || ' days')::interval,
65 '1970-01-01'::timestamp + ((id % 100) || ' days')::interval,
69 FROM generate_series(1, 1000) id;
70 INSERT INTO "S 1"."T 2"
72 'AAA' || to_char(id, 'FM000')
73 FROM generate_series(1, 100) id;
74 INSERT INTO "S 1"."T 3"
77 'AAA' || to_char(id, 'FM000')
78 FROM generate_series(1, 100) id;
79 DELETE FROM "S 1"."T 3" WHERE c1 % 2 != 0; -- delete for outer join tests
80 INSERT INTO "S 1"."T 4"
83 'AAA' || to_char(id, 'FM000')
84 FROM generate_series(1, 100) id;
85 DELETE FROM "S 1"."T 4" WHERE c1 % 3 != 0; -- delete for outer join tests
92 -- ===================================================================
93 -- create foreign tables
94 -- ===================================================================
95 CREATE FOREIGN TABLE ft1 (
103 c7 char(10) default 'ft1',
106 ALTER FOREIGN TABLE ft1 DROP COLUMN c0;
108 CREATE FOREIGN TABLE ft2 (
116 c7 char(10) default 'ft2',
119 ALTER FOREIGN TABLE ft2 DROP COLUMN cx;
121 CREATE FOREIGN TABLE ft4 (
125 ) SERVER loopback OPTIONS (schema_name 'S 1', table_name 'T 3');
127 CREATE FOREIGN TABLE ft5 (
131 ) SERVER loopback OPTIONS (schema_name 'S 1', table_name 'T 4');
133 CREATE FOREIGN TABLE ft6 (
137 ) SERVER loopback2 OPTIONS (schema_name 'S 1', table_name 'T 4');
139 -- A table with oids. CREATE FOREIGN TABLE doesn't support the
140 -- WITH OIDS option, but ALTER does.
141 CREATE FOREIGN TABLE ft_pg_type (
144 ) SERVER loopback OPTIONS (schema_name 'pg_catalog', table_name 'pg_type');
145 ALTER TABLE ft_pg_type SET WITH OIDS;
147 -- ===================================================================
148 -- tests for validator
149 -- ===================================================================
150 -- requiressl, krbsrvname and gsslib are omitted because they depend on
152 ALTER SERVER testserver1 OPTIONS (
153 use_remote_estimate 'false',
155 fdw_startup_cost '123.456',
156 fdw_tuple_cost '0.123',
158 connect_timeout 'value',
163 --client_encoding 'value',
164 application_name 'value',
165 --fallback_application_name 'value',
167 keepalives_idle 'value',
168 keepalives_interval 'value',
169 -- requiressl 'value',
170 sslcompression 'value',
176 --requirepeer 'value',
177 -- krbsrvname 'value',
179 --replication 'value'
182 -- Error, invalid list syntax
183 ALTER SERVER testserver1 OPTIONS (ADD extensions 'foo; bar');
185 -- OK but gets a warning
186 ALTER SERVER testserver1 OPTIONS (ADD extensions 'foo, bar');
187 ALTER SERVER testserver1 OPTIONS (DROP extensions);
189 ALTER USER MAPPING FOR public SERVER testserver1
190 OPTIONS (DROP user, DROP password);
192 ALTER FOREIGN TABLE ft1 OPTIONS (schema_name 'S 1', table_name 'T 1');
193 ALTER FOREIGN TABLE ft2 OPTIONS (schema_name 'S 1', table_name 'T 1');
194 ALTER FOREIGN TABLE ft1 ALTER COLUMN c1 OPTIONS (column_name 'C 1');
195 ALTER FOREIGN TABLE ft2 ALTER COLUMN c1 OPTIONS (column_name 'C 1');
198 -- Test that alteration of server options causes reconnection
199 -- Remote's errors might be non-English, so hide them to ensure stable results
201 SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1; -- should work
202 ALTER SERVER loopback OPTIONS (SET dbname 'no such database');
203 SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1; -- should fail
206 EXECUTE $$ALTER SERVER loopback
207 OPTIONS (SET dbname '$$||current_database()||$$')$$;
210 SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1; -- should work again
212 -- Test that alteration of user mapping options causes reconnection
213 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback
214 OPTIONS (ADD user 'no such user');
215 SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1; -- should fail
216 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback
218 SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1; -- should work again
219 \set VERBOSITY default
221 -- Now we should be able to run ANALYZE.
222 -- To exercise multiple code paths, we use local stats on ft1
223 -- and remote-estimate mode on ft2.
225 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
227 -- ===================================================================
229 -- ===================================================================
230 -- single table without alias
231 EXPLAIN (COSTS OFF) SELECT * FROM ft1 ORDER BY c3, c1 OFFSET 100 LIMIT 10;
232 SELECT * FROM ft1 ORDER BY c3, c1 OFFSET 100 LIMIT 10;
233 -- single table with alias - also test that tableoid sort is not pushed to remote side
234 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 ORDER BY t1.c3, t1.c1, t1.tableoid OFFSET 100 LIMIT 10;
235 SELECT * FROM ft1 t1 ORDER BY t1.c3, t1.c1, t1.tableoid OFFSET 100 LIMIT 10;
236 -- whole-row reference
237 EXPLAIN (VERBOSE, COSTS OFF) SELECT t1 FROM ft1 t1 ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
238 SELECT t1 FROM ft1 t1 ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
240 SELECT * FROM ft1 WHERE false;
242 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.c1 = 101 AND t1.c6 = '1' AND t1.c7 >= '1';
243 SELECT * FROM ft1 t1 WHERE t1.c1 = 101 AND t1.c6 = '1' AND t1.c7 >= '1';
244 -- with FOR UPDATE/SHARE
245 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = 101 FOR UPDATE;
246 SELECT * FROM ft1 t1 WHERE c1 = 101 FOR UPDATE;
247 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = 102 FOR SHARE;
248 SELECT * FROM ft1 t1 WHERE c1 = 102 FOR SHARE;
250 SELECT COUNT(*) FROM ft1 t1;
252 SELECT * FROM ft1 t1 WHERE t1.c3 IN (SELECT c3 FROM ft2 t2 WHERE c1 <= 10) ORDER BY c1;
254 SELECT * FROM ft1 t1 WHERE t1.c3 = (SELECT MAX(c3) FROM ft2 t2) ORDER BY c1;
256 WITH t1 AS (SELECT * FROM ft1 WHERE c1 <= 10) SELECT t2.c1, t2.c2, t2.c3, t2.c4 FROM t1, ft2 t2 WHERE t1.c1 = t2.c1 ORDER BY t1.c1;
258 SELECT 'fixed', NULL FROM ft1 t1 WHERE c1 = 1;
259 -- Test forcing the remote server to produce sorted data for a merge join.
260 SET enable_hashjoin TO false;
261 SET enable_nestloop TO false;
262 -- inner join; expressions in the clauses appear in the equivalence class list
263 EXPLAIN (VERBOSE, COSTS OFF)
264 SELECT t1.c1, t2."C 1" FROM ft2 t1 JOIN "S 1"."T 1" t2 ON (t1.c1 = t2."C 1") OFFSET 100 LIMIT 10;
265 SELECT t1.c1, t2."C 1" FROM ft2 t1 JOIN "S 1"."T 1" t2 ON (t1.c1 = t2."C 1") OFFSET 100 LIMIT 10;
266 -- outer join; expressions in the clauses do not appear in equivalence class
267 -- list but no output change as compared to the previous query
268 EXPLAIN (VERBOSE, COSTS OFF)
269 SELECT t1.c1, t2."C 1" FROM ft2 t1 LEFT JOIN "S 1"."T 1" t2 ON (t1.c1 = t2."C 1") OFFSET 100 LIMIT 10;
270 SELECT t1.c1, t2."C 1" FROM ft2 t1 LEFT JOIN "S 1"."T 1" t2 ON (t1.c1 = t2."C 1") OFFSET 100 LIMIT 10;
271 -- A join between local table and foreign join. ORDER BY clause is added to the
272 -- foreign join so that the local table can be joined using merge join strategy.
273 EXPLAIN (VERBOSE, COSTS OFF)
274 SELECT t1."C 1" FROM "S 1"."T 1" t1 left join ft1 t2 join ft2 t3 on (t2.c1 = t3.c1) on (t3.c1 = t1."C 1") OFFSET 100 LIMIT 10;
275 SELECT t1."C 1" FROM "S 1"."T 1" t1 left join ft1 t2 join ft2 t3 on (t2.c1 = t3.c1) on (t3.c1 = t1."C 1") OFFSET 100 LIMIT 10;
276 -- Test similar to above, except that the full join prevents any equivalence
277 -- classes from being merged. This produces single relation equivalence classes
278 -- included in join restrictions.
279 EXPLAIN (VERBOSE, COSTS OFF)
280 SELECT t1."C 1", t2.c1, t3.c1 FROM "S 1"."T 1" t1 left join ft1 t2 full join ft2 t3 on (t2.c1 = t3.c1) on (t3.c1 = t1."C 1") OFFSET 100 LIMIT 10;
281 SELECT t1."C 1", t2.c1, t3.c1 FROM "S 1"."T 1" t1 left join ft1 t2 full join ft2 t3 on (t2.c1 = t3.c1) on (t3.c1 = t1."C 1") OFFSET 100 LIMIT 10;
282 -- Test similar to above with all full outer joins
283 EXPLAIN (VERBOSE, COSTS OFF)
284 SELECT t1."C 1", t2.c1, t3.c1 FROM "S 1"."T 1" t1 full join ft1 t2 full join ft2 t3 on (t2.c1 = t3.c1) on (t3.c1 = t1."C 1") OFFSET 100 LIMIT 10;
285 SELECT t1."C 1", t2.c1, t3.c1 FROM "S 1"."T 1" t1 full join ft1 t2 full join ft2 t3 on (t2.c1 = t3.c1) on (t3.c1 = t1."C 1") OFFSET 100 LIMIT 10;
286 RESET enable_hashjoin;
287 RESET enable_nestloop;
289 -- ===================================================================
290 -- WHERE with remotely-executable conditions
291 -- ===================================================================
292 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.c1 = 1; -- Var, OpExpr(b), Const
293 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.c1 = 100 AND t1.c2 = 0; -- BoolExpr
294 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NULL; -- NullTest
295 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 IS NOT NULL; -- NullTest
296 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE round(abs(c1), 0) = 1; -- FuncExpr
297 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1; -- OpExpr(l)
298 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE 1 = c1!; -- OpExpr(r)
299 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
300 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = ANY(ARRAY[c2, 1, c1 + 0]); -- ScalarArrayOpExpr
301 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = (ARRAY[c1,c2,3])[1]; -- ArrayRef
302 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c6 = E'foo''s\\bar'; -- check special chars
303 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c8 = 'foo'; -- can't be sent to remote
304 -- parameterized remote path for foreign table
305 EXPLAIN (VERBOSE, COSTS OFF)
306 SELECT * FROM "S 1"."T 1" a, ft2 b WHERE a."C 1" = 47 AND b.c1 = a.c2;
307 SELECT * FROM ft2 a, ft2 b WHERE a.c1 = 47 AND b.c1 = a.c2;
309 -- check both safe and unsafe join conditions
310 EXPLAIN (VERBOSE, COSTS OFF)
311 SELECT * FROM ft2 a, ft2 b
312 WHERE a.c2 = 6 AND b.c1 = a.c1 AND a.c8 = 'foo' AND b.c7 = upper(a.c7);
313 SELECT * FROM ft2 a, ft2 b
314 WHERE a.c2 = 6 AND b.c1 = a.c1 AND a.c8 = 'foo' AND b.c7 = upper(a.c7);
315 -- bug before 9.3.5 due to sloppy handling of remote-estimate parameters
316 SELECT * FROM ft1 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft2 WHERE c1 < 5));
317 SELECT * FROM ft2 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft1 WHERE c1 < 5));
318 -- we should not push order by clause with volatile expressions or unsafe
320 EXPLAIN (VERBOSE, COSTS OFF)
321 SELECT * FROM ft2 ORDER BY ft2.c1, random();
322 EXPLAIN (VERBOSE, COSTS OFF)
323 SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
325 -- user-defined operator/function
326 CREATE FUNCTION postgres_fdw_abs(int) RETURNS int AS $$
330 $$ LANGUAGE plpgsql IMMUTABLE;
331 CREATE OPERATOR === (
338 -- built-in operators and functions can be shipped for remote execution
339 EXPLAIN (VERBOSE, COSTS OFF)
340 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = abs(t1.c2);
341 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = abs(t1.c2);
342 EXPLAIN (VERBOSE, COSTS OFF)
343 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = t1.c2;
344 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = t1.c2;
346 -- by default, user-defined ones cannot
347 EXPLAIN (VERBOSE, COSTS OFF)
348 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2);
349 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2);
350 EXPLAIN (VERBOSE, COSTS OFF)
351 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2;
352 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2;
354 -- but let's put them in an extension ...
355 ALTER EXTENSION postgres_fdw ADD FUNCTION postgres_fdw_abs(int);
356 ALTER EXTENSION postgres_fdw ADD OPERATOR === (int, int);
357 ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
359 -- ... now they can be shipped
360 EXPLAIN (VERBOSE, COSTS OFF)
361 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2);
362 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2);
363 EXPLAIN (VERBOSE, COSTS OFF)
364 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2;
365 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2;
367 -- ===================================================================
369 -- ===================================================================
370 -- Analyze ft4 and ft5 so that we have better statistics. These tables do not
371 -- have use_remote_estimate set.
376 EXPLAIN (VERBOSE, COSTS OFF)
377 SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
378 SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
380 EXPLAIN (VERBOSE, COSTS OFF)
381 SELECT t1.c1, t2.c2, t3.c3 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) JOIN ft4 t3 ON (t3.c1 = t1.c1) ORDER BY t1.c3, t1.c1 OFFSET 10 LIMIT 10;
382 SELECT t1.c1, t2.c2, t3.c3 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) JOIN ft4 t3 ON (t3.c1 = t1.c1) ORDER BY t1.c3, t1.c1 OFFSET 10 LIMIT 10;
384 EXPLAIN (VERBOSE, COSTS OFF)
385 SELECT t1.c1, t2.c1 FROM ft4 t1 LEFT JOIN ft5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10;
386 SELECT t1.c1, t2.c1 FROM ft4 t1 LEFT JOIN ft5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10;
387 -- left outer join three tables
388 EXPLAIN (VERBOSE, COSTS OFF)
389 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) LEFT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
390 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) LEFT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
391 -- left outer join + placement of clauses.
392 -- clauses within the nullable side are not pulled up, but top level clause on
393 -- non-nullable side is pushed into non-nullable side
394 EXPLAIN (VERBOSE, COSTS OFF)
395 SELECT t1.c1, t1.c2, t2.c1, t2.c2 FROM ft4 t1 LEFT JOIN (SELECT * FROM ft5 WHERE c1 < 10) t2 ON (t1.c1 = t2.c1) WHERE t1.c1 < 10;
396 SELECT t1.c1, t1.c2, t2.c1, t2.c2 FROM ft4 t1 LEFT JOIN (SELECT * FROM ft5 WHERE c1 < 10) t2 ON (t1.c1 = t2.c1) WHERE t1.c1 < 10;
397 -- clauses within the nullable side are not pulled up, but the top level clause
398 -- on nullable side is not pushed down into nullable side
399 EXPLAIN (VERBOSE, COSTS OFF)
400 SELECT t1.c1, t1.c2, t2.c1, t2.c2 FROM ft4 t1 LEFT JOIN (SELECT * FROM ft5 WHERE c1 < 10) t2 ON (t1.c1 = t2.c1)
401 WHERE (t2.c1 < 10 OR t2.c1 IS NULL) AND t1.c1 < 10;
402 SELECT t1.c1, t1.c2, t2.c1, t2.c2 FROM ft4 t1 LEFT JOIN (SELECT * FROM ft5 WHERE c1 < 10) t2 ON (t1.c1 = t2.c1)
403 WHERE (t2.c1 < 10 OR t2.c1 IS NULL) AND t1.c1 < 10;
405 EXPLAIN (VERBOSE, COSTS OFF)
406 SELECT t1.c1, t2.c1 FROM ft5 t1 RIGHT JOIN ft4 t2 ON (t1.c1 = t2.c1) ORDER BY t2.c1, t1.c1 OFFSET 10 LIMIT 10;
407 SELECT t1.c1, t2.c1 FROM ft5 t1 RIGHT JOIN ft4 t2 ON (t1.c1 = t2.c1) ORDER BY t2.c1, t1.c1 OFFSET 10 LIMIT 10;
408 -- right outer join three tables
409 EXPLAIN (VERBOSE, COSTS OFF)
410 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) RIGHT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
411 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) RIGHT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
413 EXPLAIN (VERBOSE, COSTS OFF)
414 SELECT t1.c1, t2.c1 FROM ft4 t1 FULL JOIN ft5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 45 LIMIT 10;
415 SELECT t1.c1, t2.c1 FROM ft4 t1 FULL JOIN ft5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 45 LIMIT 10;
416 -- full outer join with restrictions on the joining relations
417 -- a. the joining relations are both base relations
418 EXPLAIN (VERBOSE, COSTS OFF)
419 SELECT t1.c1, t2.c1 FROM (SELECT c1 FROM ft4 WHERE c1 between 50 and 60) t1 FULL JOIN (SELECT c1 FROM ft5 WHERE c1 between 50 and 60) t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1;
420 SELECT t1.c1, t2.c1 FROM (SELECT c1 FROM ft4 WHERE c1 between 50 and 60) t1 FULL JOIN (SELECT c1 FROM ft5 WHERE c1 between 50 and 60) t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1;
421 EXPLAIN (VERBOSE, COSTS OFF)
422 SELECT 1 FROM (SELECT c1 FROM ft4 WHERE c1 between 50 and 60) t1 FULL JOIN (SELECT c1 FROM ft5 WHERE c1 between 50 and 60) t2 ON (TRUE) OFFSET 10 LIMIT 10;
423 SELECT 1 FROM (SELECT c1 FROM ft4 WHERE c1 between 50 and 60) t1 FULL JOIN (SELECT c1 FROM ft5 WHERE c1 between 50 and 60) t2 ON (TRUE) OFFSET 10 LIMIT 10;
424 -- b. one of the joining relations is a base relation and the other is a join
426 EXPLAIN (VERBOSE, COSTS OFF)
427 SELECT t1.c1, ss.a, ss.b FROM (SELECT c1 FROM ft4 WHERE c1 between 50 and 60) t1 FULL JOIN (SELECT t2.c1, t3.c1 FROM ft4 t2 LEFT JOIN ft5 t3 ON (t2.c1 = t3.c1) WHERE (t2.c1 between 50 and 60)) ss(a, b) ON (t1.c1 = ss.a) ORDER BY t1.c1, ss.a, ss.b;
428 SELECT t1.c1, ss.a, ss.b FROM (SELECT c1 FROM ft4 WHERE c1 between 50 and 60) t1 FULL JOIN (SELECT t2.c1, t3.c1 FROM ft4 t2 LEFT JOIN ft5 t3 ON (t2.c1 = t3.c1) WHERE (t2.c1 between 50 and 60)) ss(a, b) ON (t1.c1 = ss.a) ORDER BY t1.c1, ss.a, ss.b;
429 -- c. test deparsing the remote query as nested subqueries
430 EXPLAIN (VERBOSE, COSTS OFF)
431 SELECT t1.c1, ss.a, ss.b FROM (SELECT c1 FROM ft4 WHERE c1 between 50 and 60) t1 FULL JOIN (SELECT t2.c1, t3.c1 FROM (SELECT c1 FROM ft4 WHERE c1 between 50 and 60) t2 FULL JOIN (SELECT c1 FROM ft5 WHERE c1 between 50 and 60) t3 ON (t2.c1 = t3.c1) WHERE t2.c1 IS NULL OR t2.c1 IS NOT NULL) ss(a, b) ON (t1.c1 = ss.a) ORDER BY t1.c1, ss.a, ss.b;
432 SELECT t1.c1, ss.a, ss.b FROM (SELECT c1 FROM ft4 WHERE c1 between 50 and 60) t1 FULL JOIN (SELECT t2.c1, t3.c1 FROM (SELECT c1 FROM ft4 WHERE c1 between 50 and 60) t2 FULL JOIN (SELECT c1 FROM ft5 WHERE c1 between 50 and 60) t3 ON (t2.c1 = t3.c1) WHERE t2.c1 IS NULL OR t2.c1 IS NOT NULL) ss(a, b) ON (t1.c1 = ss.a) ORDER BY t1.c1, ss.a, ss.b;
433 -- d. test deparsing rowmarked relations as subqueries
434 EXPLAIN (VERBOSE, COSTS OFF)
435 SELECT t1.c1, ss.a, ss.b FROM (SELECT c1 FROM "S 1"."T 3" WHERE c1 = 50) t1 INNER JOIN (SELECT t2.c1, t3.c1 FROM (SELECT c1 FROM ft4 WHERE c1 between 50 and 60) t2 FULL JOIN (SELECT c1 FROM ft5 WHERE c1 between 50 and 60) t3 ON (t2.c1 = t3.c1) WHERE t2.c1 IS NULL OR t2.c1 IS NOT NULL) ss(a, b) ON (TRUE) ORDER BY t1.c1, ss.a, ss.b FOR UPDATE OF t1;
436 SELECT t1.c1, ss.a, ss.b FROM (SELECT c1 FROM "S 1"."T 3" WHERE c1 = 50) t1 INNER JOIN (SELECT t2.c1, t3.c1 FROM (SELECT c1 FROM ft4 WHERE c1 between 50 and 60) t2 FULL JOIN (SELECT c1 FROM ft5 WHERE c1 between 50 and 60) t3 ON (t2.c1 = t3.c1) WHERE t2.c1 IS NULL OR t2.c1 IS NOT NULL) ss(a, b) ON (TRUE) ORDER BY t1.c1, ss.a, ss.b FOR UPDATE OF t1;
437 -- full outer join + inner join
438 EXPLAIN (VERBOSE, COSTS OFF)
439 SELECT t1.c1, t2.c1, t3.c1 FROM ft4 t1 INNER JOIN ft5 t2 ON (t1.c1 = t2.c1 + 1 and t1.c1 between 50 and 60) FULL JOIN ft4 t3 ON (t2.c1 = t3.c1) ORDER BY t1.c1, t2.c1, t3.c1 LIMIT 10;
440 SELECT t1.c1, t2.c1, t3.c1 FROM ft4 t1 INNER JOIN ft5 t2 ON (t1.c1 = t2.c1 + 1 and t1.c1 between 50 and 60) FULL JOIN ft4 t3 ON (t2.c1 = t3.c1) ORDER BY t1.c1, t2.c1, t3.c1 LIMIT 10;
441 -- full outer join three tables
442 EXPLAIN (VERBOSE, COSTS OFF)
443 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 FULL JOIN ft2 t2 ON (t1.c1 = t2.c1) FULL JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
444 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 FULL JOIN ft2 t2 ON (t1.c1 = t2.c1) FULL JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
445 -- full outer join + right outer join
446 EXPLAIN (VERBOSE, COSTS OFF)
447 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 FULL JOIN ft2 t2 ON (t1.c1 = t2.c1) RIGHT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
448 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 FULL JOIN ft2 t2 ON (t1.c1 = t2.c1) RIGHT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
449 -- right outer join + full outer join
450 EXPLAIN (VERBOSE, COSTS OFF)
451 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) FULL JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
452 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) FULL JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
453 -- full outer join + left outer join
454 EXPLAIN (VERBOSE, COSTS OFF)
455 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 FULL JOIN ft2 t2 ON (t1.c1 = t2.c1) LEFT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
456 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 FULL JOIN ft2 t2 ON (t1.c1 = t2.c1) LEFT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
457 -- left outer join + full outer join
458 EXPLAIN (VERBOSE, COSTS OFF)
459 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) FULL JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
460 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) FULL JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
461 -- right outer join + left outer join
462 EXPLAIN (VERBOSE, COSTS OFF)
463 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) LEFT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
464 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 RIGHT JOIN ft2 t2 ON (t1.c1 = t2.c1) LEFT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
465 -- left outer join + right outer join
466 EXPLAIN (VERBOSE, COSTS OFF)
467 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) RIGHT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
468 SELECT t1.c1, t2.c2, t3.c3 FROM ft2 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) RIGHT JOIN ft4 t3 ON (t2.c1 = t3.c1) OFFSET 10 LIMIT 10;
469 -- full outer join + WHERE clause, only matched rows
470 EXPLAIN (VERBOSE, COSTS OFF)
471 SELECT t1.c1, t2.c1 FROM ft4 t1 FULL JOIN ft5 t2 ON (t1.c1 = t2.c1) WHERE (t1.c1 = t2.c1 OR t1.c1 IS NULL) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10;
472 SELECT t1.c1, t2.c1 FROM ft4 t1 FULL JOIN ft5 t2 ON (t1.c1 = t2.c1) WHERE (t1.c1 = t2.c1 OR t1.c1 IS NULL) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10;
473 -- full outer join + WHERE clause with shippable extensions set
474 EXPLAIN (VERBOSE, COSTS OFF)
475 SELECT t1.c1, t2.c2, t1.c3 FROM ft1 t1 FULL JOIN ft2 t2 ON (t1.c1 = t2.c1) WHERE postgres_fdw_abs(t1.c1) > 0 OFFSET 10 LIMIT 10;
476 ALTER SERVER loopback OPTIONS (DROP extensions);
477 -- full outer join + WHERE clause with shippable extensions not set
478 EXPLAIN (VERBOSE, COSTS OFF)
479 SELECT t1.c1, t2.c2, t1.c3 FROM ft1 t1 FULL JOIN ft2 t2 ON (t1.c1 = t2.c1) WHERE postgres_fdw_abs(t1.c1) > 0 OFFSET 10 LIMIT 10;
480 ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
481 -- join two tables with FOR UPDATE clause
482 -- tests whole-row reference for row marks
483 EXPLAIN (VERBOSE, COSTS OFF)
484 SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR UPDATE OF t1;
485 SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR UPDATE OF t1;
486 EXPLAIN (VERBOSE, COSTS OFF)
487 SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR UPDATE;
488 SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR UPDATE;
489 -- join two tables with FOR SHARE clause
490 EXPLAIN (VERBOSE, COSTS OFF)
491 SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR SHARE OF t1;
492 SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR SHARE OF t1;
493 EXPLAIN (VERBOSE, COSTS OFF)
494 SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR SHARE;
495 SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10 FOR SHARE;
497 EXPLAIN (VERBOSE, COSTS OFF)
498 WITH t (c1_1, c1_3, c2_1) AS (SELECT t1.c1, t1.c3, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1)) SELECT c1_1, c2_1 FROM t ORDER BY c1_3, c1_1 OFFSET 100 LIMIT 10;
499 WITH t (c1_1, c1_3, c2_1) AS (SELECT t1.c1, t1.c3, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1)) SELECT c1_1, c2_1 FROM t ORDER BY c1_3, c1_1 OFFSET 100 LIMIT 10;
500 -- ctid with whole-row reference
501 EXPLAIN (VERBOSE, COSTS OFF)
502 SELECT t1.ctid, t1, t2, t1.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
503 -- SEMI JOIN, not pushed down
504 EXPLAIN (VERBOSE, COSTS OFF)
505 SELECT t1.c1 FROM ft1 t1 WHERE EXISTS (SELECT 1 FROM ft2 t2 WHERE t1.c1 = t2.c1) ORDER BY t1.c1 OFFSET 100 LIMIT 10;
506 SELECT t1.c1 FROM ft1 t1 WHERE EXISTS (SELECT 1 FROM ft2 t2 WHERE t1.c1 = t2.c1) ORDER BY t1.c1 OFFSET 100 LIMIT 10;
507 -- ANTI JOIN, not pushed down
508 EXPLAIN (VERBOSE, COSTS OFF)
509 SELECT t1.c1 FROM ft1 t1 WHERE NOT EXISTS (SELECT 1 FROM ft2 t2 WHERE t1.c1 = t2.c2) ORDER BY t1.c1 OFFSET 100 LIMIT 10;
510 SELECT t1.c1 FROM ft1 t1 WHERE NOT EXISTS (SELECT 1 FROM ft2 t2 WHERE t1.c1 = t2.c2) ORDER BY t1.c1 OFFSET 100 LIMIT 10;
511 -- CROSS JOIN, not pushed down
512 EXPLAIN (VERBOSE, COSTS OFF)
513 SELECT t1.c1, t2.c1 FROM ft1 t1 CROSS JOIN ft2 t2 ORDER BY t1.c1, t2.c1 OFFSET 100 LIMIT 10;
514 SELECT t1.c1, t2.c1 FROM ft1 t1 CROSS JOIN ft2 t2 ORDER BY t1.c1, t2.c1 OFFSET 100 LIMIT 10;
515 -- different server, not pushed down. No result expected.
516 EXPLAIN (VERBOSE, COSTS OFF)
517 SELECT t1.c1, t2.c1 FROM ft5 t1 JOIN ft6 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 100 LIMIT 10;
518 SELECT t1.c1, t2.c1 FROM ft5 t1 JOIN ft6 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 100 LIMIT 10;
519 -- unsafe join conditions (c8 has a UDT), not pushed down. Practically a CROSS
520 -- JOIN since c8 in both tables has same value.
521 EXPLAIN (VERBOSE, COSTS OFF)
522 SELECT t1.c1, t2.c1 FROM ft1 t1 LEFT JOIN ft2 t2 ON (t1.c8 = t2.c8) ORDER BY t1.c1, t2.c1 OFFSET 100 LIMIT 10;
523 SELECT t1.c1, t2.c1 FROM ft1 t1 LEFT JOIN ft2 t2 ON (t1.c8 = t2.c8) ORDER BY t1.c1, t2.c1 OFFSET 100 LIMIT 10;
524 -- unsafe conditions on one side (c8 has a UDT), not pushed down.
525 EXPLAIN (VERBOSE, COSTS OFF)
526 SELECT t1.c1, t2.c1 FROM ft1 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) WHERE t1.c8 = 'foo' ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
527 SELECT t1.c1, t2.c1 FROM ft1 t1 LEFT JOIN ft2 t2 ON (t1.c1 = t2.c1) WHERE t1.c8 = 'foo' ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
528 -- join where unsafe to pushdown condition in WHERE clause has a column not
529 -- in the SELECT clause. In this test unsafe clause needs to have column
530 -- references from both joining sides so that the clause is not pushed down
531 -- into one of the joining sides.
532 EXPLAIN (VERBOSE, COSTS OFF)
533 SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) WHERE t1.c8 = t2.c8 ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
534 SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) WHERE t1.c8 = t2.c8 ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
535 -- Aggregate after UNION, for testing setrefs
536 EXPLAIN (VERBOSE, COSTS OFF)
537 SELECT t1c1, avg(t1c1 + t2c1) FROM (SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) UNION SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1)) AS t (t1c1, t2c1) GROUP BY t1c1 ORDER BY t1c1 OFFSET 100 LIMIT 10;
538 SELECT t1c1, avg(t1c1 + t2c1) FROM (SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1) UNION SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1)) AS t (t1c1, t2c1) GROUP BY t1c1 ORDER BY t1c1 OFFSET 100 LIMIT 10;
539 -- join with lateral reference
540 EXPLAIN (VERBOSE, COSTS OFF)
541 SELECT t1."C 1" FROM "S 1"."T 1" t1, LATERAL (SELECT DISTINCT t2.c1, t3.c1 FROM ft1 t2, ft2 t3 WHERE t2.c1 = t3.c1 AND t2.c2 = t1.c2) q ORDER BY t1."C 1" OFFSET 10 LIMIT 10;
542 SELECT t1."C 1" FROM "S 1"."T 1" t1, LATERAL (SELECT DISTINCT t2.c1, t3.c1 FROM ft1 t2, ft2 t3 WHERE t2.c1 = t3.c1 AND t2.c2 = t1.c2) q ORDER BY t1."C 1" OFFSET 10 LIMIT 10;
544 -- non-Var items in targetlist of the nullable rel of a join preventing
545 -- push-down in some cases
546 -- unable to push {ft1, ft2}
547 EXPLAIN (VERBOSE, COSTS OFF)
548 SELECT q.a, ft2.c1 FROM (SELECT 13 FROM ft1 WHERE c1 = 13) q(a) RIGHT JOIN ft2 ON (q.a = ft2.c1) WHERE ft2.c1 BETWEEN 10 AND 15;
549 SELECT q.a, ft2.c1 FROM (SELECT 13 FROM ft1 WHERE c1 = 13) q(a) RIGHT JOIN ft2 ON (q.a = ft2.c1) WHERE ft2.c1 BETWEEN 10 AND 15;
551 -- ok to push {ft1, ft2} but not {ft1, ft2, ft4}
552 EXPLAIN (VERBOSE, COSTS OFF)
553 SELECT ft4.c1, q.* FROM ft4 LEFT JOIN (SELECT 13, ft1.c1, ft2.c1 FROM ft1 RIGHT JOIN ft2 ON (ft1.c1 = ft2.c1) WHERE ft1.c1 = 12) q(a, b, c) ON (ft4.c1 = q.b) WHERE ft4.c1 BETWEEN 10 AND 15;
554 SELECT ft4.c1, q.* FROM ft4 LEFT JOIN (SELECT 13, ft1.c1, ft2.c1 FROM ft1 RIGHT JOIN ft2 ON (ft1.c1 = ft2.c1) WHERE ft1.c1 = 12) q(a, b, c) ON (ft4.c1 = q.b) WHERE ft4.c1 BETWEEN 10 AND 15;
556 -- join with nullable side with some columns with null values
557 UPDATE ft5 SET c3 = null where c1 % 9 = 0;
558 EXPLAIN (VERBOSE, COSTS OFF)
559 SELECT ft5, ft5.c1, ft5.c2, ft5.c3, ft4.c1, ft4.c2 FROM ft5 left join ft4 on ft5.c1 = ft4.c1 WHERE ft4.c1 BETWEEN 10 and 30 ORDER BY ft5.c1, ft4.c1;
560 SELECT ft5, ft5.c1, ft5.c2, ft5.c3, ft4.c1, ft4.c2 FROM ft5 left join ft4 on ft5.c1 = ft4.c1 WHERE ft4.c1 BETWEEN 10 and 30 ORDER BY ft5.c1, ft4.c1;
562 -- check join pushdown in situations where multiple userids are involved
563 CREATE ROLE regress_view_owner;
564 CREATE USER MAPPING FOR regress_view_owner SERVER loopback;
565 GRANT SELECT ON ft4 TO regress_view_owner;
566 GRANT SELECT ON ft5 TO regress_view_owner;
568 CREATE VIEW v4 AS SELECT * FROM ft4;
569 CREATE VIEW v5 AS SELECT * FROM ft5;
570 ALTER VIEW v5 OWNER TO regress_view_owner;
571 EXPLAIN (VERBOSE, COSTS OFF)
572 SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN v5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10; -- can't be pushed down, different view owners
573 SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN v5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10;
574 ALTER VIEW v4 OWNER TO regress_view_owner;
575 EXPLAIN (VERBOSE, COSTS OFF)
576 SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN v5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10; -- can be pushed down
577 SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN v5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10;
579 EXPLAIN (VERBOSE, COSTS OFF)
580 SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN ft5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10; -- can't be pushed down, view owner not current user
581 SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN ft5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10;
582 ALTER VIEW v4 OWNER TO CURRENT_USER;
583 EXPLAIN (VERBOSE, COSTS OFF)
584 SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN ft5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10; -- can be pushed down
585 SELECT t1.c1, t2.c2 FROM v4 t1 LEFT JOIN ft5 t2 ON (t1.c1 = t2.c1) ORDER BY t1.c1, t2.c1 OFFSET 10 LIMIT 10;
586 ALTER VIEW v4 OWNER TO regress_view_owner;
589 DROP OWNED BY regress_view_owner;
590 DROP ROLE regress_view_owner;
593 -- ===================================================================
594 -- Aggregate and grouping queries
595 -- ===================================================================
598 explain (verbose, costs off)
599 select count(c6), sum(c1), avg(c1), min(c2), max(c1), stddev(c2), sum(c1) * (random() <= 1)::int as sum2 from ft1 where c2 < 5 group by c2 order by 1, 2;
600 select count(c6), sum(c1), avg(c1), min(c2), max(c1), stddev(c2), sum(c1) * (random() <= 1)::int as sum2 from ft1 where c2 < 5 group by c2 order by 1, 2;
602 -- Aggregate is not pushed down as aggregation contains random()
603 explain (verbose, costs off)
604 select sum(c1 * (random() <= 1)::int) as sum, avg(c1) from ft1;
606 -- Aggregate over join query
607 explain (verbose, costs off)
608 select count(*), sum(t1.c1), avg(t2.c1) from ft1 t1 inner join ft1 t2 on (t1.c2 = t2.c2) where t1.c2 = 6;
609 select count(*), sum(t1.c1), avg(t2.c1) from ft1 t1 inner join ft1 t2 on (t1.c2 = t2.c2) where t1.c2 = 6;
611 -- Not pushed down due to local conditions present in underneath input rel
612 explain (verbose, costs off)
613 select sum(t1.c1), count(t2.c1) from ft1 t1 inner join ft2 t2 on (t1.c1 = t2.c1) where ((t1.c1 * t2.c1)/(t1.c1 * t2.c1)) * random() <= 1;
615 -- GROUP BY clause having expressions
616 explain (verbose, costs off)
617 select c2/2, sum(c2) * (c2/2) from ft1 group by c2/2 order by c2/2;
618 select c2/2, sum(c2) * (c2/2) from ft1 group by c2/2 order by c2/2;
620 -- Aggregates in subquery are pushed down.
621 explain (verbose, costs off)
622 select count(x.a), sum(x.a) from (select c2 a, sum(c1) b from ft1 group by c2, sqrt(c1) order by 1, 2) x;
623 select count(x.a), sum(x.a) from (select c2 a, sum(c1) b from ft1 group by c2, sqrt(c1) order by 1, 2) x;
625 -- Aggregate is still pushed down by taking unshippable expression out
626 explain (verbose, costs off)
627 select c2 * (random() <= 1)::int as sum1, sum(c1) * c2 as sum2 from ft1 group by c2 order by 1, 2;
628 select c2 * (random() <= 1)::int as sum1, sum(c1) * c2 as sum2 from ft1 group by c2 order by 1, 2;
630 -- Aggregate with unshippable GROUP BY clause are not pushed
631 explain (verbose, costs off)
632 select c2 * (random() <= 1)::int as c2 from ft2 group by c2 * (random() <= 1)::int order by 1;
634 -- GROUP BY clause in various forms, cardinal, alias and constant expression
635 explain (verbose, costs off)
636 select count(c2) w, c2 x, 5 y, 7.0 z from ft1 group by 2, y, 9.0::int order by 2;
637 select count(c2) w, c2 x, 5 y, 7.0 z from ft1 group by 2, y, 9.0::int order by 2;
639 -- Testing HAVING clause shippability
640 explain (verbose, costs off)
641 select c2, sum(c1) from ft2 group by c2 having avg(c1) < 500 and sum(c1) < 49800 order by c2;
642 select c2, sum(c1) from ft2 group by c2 having avg(c1) < 500 and sum(c1) < 49800 order by c2;
644 -- Unshippable HAVING clause will be evaluated locally, and other qual in HAVING clause is pushed down
645 explain (verbose, costs off)
646 select count(*) from (select c5, count(c1) from ft1 group by c5, sqrt(c2) having (avg(c1) / avg(c1)) * random() <= 1 and avg(c1) < 500) x;
647 select count(*) from (select c5, count(c1) from ft1 group by c5, sqrt(c2) having (avg(c1) / avg(c1)) * random() <= 1 and avg(c1) < 500) x;
649 -- Aggregate in HAVING clause is not pushable, and thus aggregation is not pushed down
650 explain (verbose, costs off)
651 select sum(c1) from ft1 group by c2 having avg(c1 * (random() <= 1)::int) > 100 order by 1;
654 -- Testing ORDER BY, DISTINCT, FILTER, Ordered-sets and VARIADIC within aggregates
656 -- ORDER BY within aggregate, same column used to order
657 explain (verbose, costs off)
658 select array_agg(c1 order by c1) from ft1 where c1 < 100 group by c2 order by 1;
659 select array_agg(c1 order by c1) from ft1 where c1 < 100 group by c2 order by 1;
661 -- ORDER BY within aggregate, different column used to order also using DESC
662 explain (verbose, costs off)
663 select array_agg(c5 order by c1 desc) from ft2 where c2 = 6 and c1 < 50;
664 select array_agg(c5 order by c1 desc) from ft2 where c2 = 6 and c1 < 50;
666 -- DISTINCT within aggregate
667 explain (verbose, costs off)
668 select array_agg(distinct (t1.c1)%5) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1;
669 select array_agg(distinct (t1.c1)%5) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1;
671 -- DISTINCT combined with ORDER BY within aggregate
672 explain (verbose, costs off)
673 select array_agg(distinct (t1.c1)%5 order by (t1.c1)%5) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1;
674 select array_agg(distinct (t1.c1)%5 order by (t1.c1)%5) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1;
676 explain (verbose, costs off)
677 select array_agg(distinct (t1.c1)%5 order by (t1.c1)%5 desc nulls last) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1;
678 select array_agg(distinct (t1.c1)%5 order by (t1.c1)%5 desc nulls last) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) where t1.c1 < 20 or (t1.c1 is null and t2.c1 < 5) group by (t2.c1)%3 order by 1;
680 -- FILTER within aggregate
681 explain (verbose, costs off)
682 select sum(c1) filter (where c1 < 100 and c2 > 5) from ft1 group by c2 order by 1 nulls last;
683 select sum(c1) filter (where c1 < 100 and c2 > 5) from ft1 group by c2 order by 1 nulls last;
685 -- DISTINCT, ORDER BY and FILTER within aggregate
686 explain (verbose, costs off)
687 select sum(c1%3), sum(distinct c1%3 order by c1%3) filter (where c1%3 < 2), c2 from ft1 where c2 = 6 group by c2;
688 select sum(c1%3), sum(distinct c1%3 order by c1%3) filter (where c1%3 < 2), c2 from ft1 where c2 = 6 group by c2;
690 -- Outer query is aggregation query
691 explain (verbose, costs off)
692 select distinct (select count(*) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft2 t2 where t2.c2 % 6 = 0 order by 1;
693 select distinct (select count(*) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft2 t2 where t2.c2 % 6 = 0 order by 1;
694 -- Inner query is aggregation query
695 explain (verbose, costs off)
696 select distinct (select count(t1.c1) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft2 t2 where t2.c2 % 6 = 0 order by 1;
697 select distinct (select count(t1.c1) filter (where t2.c2 = 6 and t2.c1 < 10) from ft1 t1 where t1.c1 = 6) from ft2 t2 where t2.c2 % 6 = 0 order by 1;
699 -- Aggregate not pushed down as FILTER condition is not pushable
700 explain (verbose, costs off)
701 select sum(c1) filter (where (c1 / c1) * random() <= 1) from ft1 group by c2 order by 1;
702 explain (verbose, costs off)
703 select sum(c2) filter (where c2 in (select c2 from ft1 where c2 < 5)) from ft1;
705 -- Ordered-sets within aggregate
706 explain (verbose, costs off)
707 select c2, rank('10'::varchar) within group (order by c6), percentile_cont(c2/10::numeric) within group (order by c1) from ft1 where c2 < 10 group by c2 having percentile_cont(c2/10::numeric) within group (order by c1) < 500 order by c2;
708 select c2, rank('10'::varchar) within group (order by c6), percentile_cont(c2/10::numeric) within group (order by c1) from ft1 where c2 < 10 group by c2 having percentile_cont(c2/10::numeric) within group (order by c1) < 500 order by c2;
710 -- Using multiple arguments within aggregates
711 explain (verbose, costs off)
712 select c1, rank(c1, c2) within group (order by c1, c2) from ft1 group by c1, c2 having c1 = 6 order by 1;
713 select c1, rank(c1, c2) within group (order by c1, c2) from ft1 group by c1, c2 having c1 = 6 order by 1;
715 -- User defined function for user defined aggregate, VARIADIC
716 create function least_accum(anyelement, variadic anyarray)
717 returns anyelement language sql as
718 'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)';
719 create aggregate least_agg(variadic items anyarray) (
720 stype = anyelement, sfunc = least_accum
723 -- Disable hash aggregation for plan stability.
724 set enable_hashagg to false;
726 -- Not pushed down due to user defined aggregate
727 explain (verbose, costs off)
728 select c2, least_agg(c1) from ft1 group by c2 order by c2;
730 -- Add function and aggregate into extension
731 alter extension postgres_fdw add function least_accum(anyelement, variadic anyarray);
732 alter extension postgres_fdw add aggregate least_agg(variadic items anyarray);
733 alter server loopback options (set extensions 'postgres_fdw');
735 -- Now aggregate will be pushed. Aggregate will display VARIADIC argument.
736 explain (verbose, costs off)
737 select c2, least_agg(c1) from ft1 where c2 < 100 group by c2 order by c2;
738 select c2, least_agg(c1) from ft1 where c2 < 100 group by c2 order by c2;
740 -- Remove function and aggregate from extension
741 alter extension postgres_fdw drop function least_accum(anyelement, variadic anyarray);
742 alter extension postgres_fdw drop aggregate least_agg(variadic items anyarray);
743 alter server loopback options (set extensions 'postgres_fdw');
745 -- Not pushed down as we have dropped objects from extension.
746 explain (verbose, costs off)
747 select c2, least_agg(c1) from ft1 group by c2 order by c2;
750 reset enable_hashagg;
751 drop aggregate least_agg(variadic items anyarray);
752 drop function least_accum(anyelement, variadic anyarray);
755 -- Testing USING OPERATOR() in ORDER BY within aggregate.
756 -- For this, we need user defined operators along with operator family and
757 -- operator class. Create those and then add them in extension. Note that
758 -- user defined objects are considered unshippable unless they are part of
760 create operator public.<^ (
766 create operator public.=^ (
772 create operator public.>^ (
778 create operator family my_op_family using btree;
780 create function my_op_cmp(a int, b int) returns int as
781 $$begin return btint4cmp(a, b); end $$ language plpgsql;
783 create operator class my_op_class for type int using btree family my_op_family as
784 operator 1 public.<^,
785 operator 3 public.=^,
786 operator 5 public.>^,
787 function 1 my_op_cmp(int, int);
789 -- This will not be pushed as user defined sort operator is not part of the
791 explain (verbose, costs off)
792 select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
794 -- Add into extension
795 alter extension postgres_fdw add operator class my_op_class using btree;
796 alter extension postgres_fdw add function my_op_cmp(a int, b int);
797 alter extension postgres_fdw add operator family my_op_family using btree;
798 alter extension postgres_fdw add operator public.<^(int, int);
799 alter extension postgres_fdw add operator public.=^(int, int);
800 alter extension postgres_fdw add operator public.>^(int, int);
801 alter server loopback options (set extensions 'postgres_fdw');
803 -- Now this will be pushed as sort operator is part of the extension.
804 explain (verbose, costs off)
805 select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
806 select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
808 -- Remove from extension
809 alter extension postgres_fdw drop operator class my_op_class using btree;
810 alter extension postgres_fdw drop function my_op_cmp(a int, b int);
811 alter extension postgres_fdw drop operator family my_op_family using btree;
812 alter extension postgres_fdw drop operator public.<^(int, int);
813 alter extension postgres_fdw drop operator public.=^(int, int);
814 alter extension postgres_fdw drop operator public.>^(int, int);
815 alter server loopback options (set extensions 'postgres_fdw');
817 -- This will not be pushed as sort operator is now removed from the extension.
818 explain (verbose, costs off)
819 select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
822 drop operator class my_op_class using btree;
823 drop function my_op_cmp(a int, b int);
824 drop operator family my_op_family using btree;
825 drop operator public.>^(int, int);
826 drop operator public.=^(int, int);
827 drop operator public.<^(int, int);
829 -- Input relation to aggregate push down hook is not safe to pushdown and thus
830 -- the aggregate cannot be pushed down to foreign server.
831 explain (verbose, costs off)
832 select count(t1.c3) from ft1 t1, ft1 t2 where t1.c1 = postgres_fdw_abs(t1.c2);
834 -- Subquery in FROM clause having aggregate
835 explain (verbose, costs off)
836 select count(*), x.b from ft1, (select c2 a, sum(c1) b from ft1 group by c2) x where ft1.c2 = x.a group by x.b order by 1, 2;
837 select count(*), x.b from ft1, (select c2 a, sum(c1) b from ft1 group by c2) x where ft1.c2 = x.a group by x.b order by 1, 2;
839 -- FULL join with IS NULL check in HAVING
840 explain (verbose, costs off)
841 select avg(t1.c1), sum(t2.c1) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) group by t2.c1 having (avg(t1.c1) is null and sum(t2.c1) < 10) or sum(t2.c1) is null order by 1 nulls last, 2;
842 select avg(t1.c1), sum(t2.c1) from ft4 t1 full join ft5 t2 on (t1.c1 = t2.c1) group by t2.c1 having (avg(t1.c1) is null and sum(t2.c1) < 10) or sum(t2.c1) is null order by 1 nulls last, 2;
844 -- Aggregate over FULL join needing to deparse the joining relations as
846 explain (verbose, costs off)
847 select count(*), sum(t1.c1), avg(t2.c1) from (select c1 from ft4 where c1 between 50 and 60) t1 full join (select c1 from ft5 where c1 between 50 and 60) t2 on (t1.c1 = t2.c1);
848 select count(*), sum(t1.c1), avg(t2.c1) from (select c1 from ft4 where c1 between 50 and 60) t1 full join (select c1 from ft5 where c1 between 50 and 60) t2 on (t1.c1 = t2.c1);
850 -- ORDER BY expression is part of the target list but not pushed down to
852 explain (verbose, costs off)
853 select sum(c2) * (random() <= 1)::int as sum from ft1 order by 1;
854 select sum(c2) * (random() <= 1)::int as sum from ft1 order by 1;
856 -- LATERAL join, with parameterization
857 set enable_hashagg to false;
858 explain (verbose, costs off)
859 select c2, sum from "S 1"."T 1" t1, lateral (select sum(t2.c1 + t1."C 1") sum from ft2 t2 group by t2.c1) qry where t1.c2 * 2 = qry.sum and t1.c2 < 3 and t1."C 1" < 100 order by 1;
860 select c2, sum from "S 1"."T 1" t1, lateral (select sum(t2.c1 + t1."C 1") sum from ft2 t2 group by t2.c1) qry where t1.c2 * 2 = qry.sum and t1.c2 < 3 and t1."C 1" < 100 order by 1;
861 reset enable_hashagg;
863 -- Check with placeHolderVars
864 explain (verbose, costs off)
865 select sum(q.a), count(q.b) from ft4 left join (select 13, avg(ft1.c1), sum(ft2.c1) from ft1 right join ft2 on (ft1.c1 = ft2.c1)) q(a, b, c) on (ft4.c1 <= q.b);
866 select sum(q.a), count(q.b) from ft4 left join (select 13, avg(ft1.c1), sum(ft2.c1) from ft1 right join ft2 on (ft1.c1 = ft2.c1)) q(a, b, c) on (ft4.c1 <= q.b);
869 -- Not supported cases
871 explain (verbose, costs off)
872 select c2, sum(c1) from ft1 where c2 < 3 group by rollup(c2) order by 1 nulls last;
873 select c2, sum(c1) from ft1 where c2 < 3 group by rollup(c2) order by 1 nulls last;
874 explain (verbose, costs off)
875 select c2, sum(c1) from ft1 where c2 < 3 group by cube(c2) order by 1 nulls last;
876 select c2, sum(c1) from ft1 where c2 < 3 group by cube(c2) order by 1 nulls last;
877 explain (verbose, costs off)
878 select c2, c6, sum(c1) from ft1 where c2 < 3 group by grouping sets(c2, c6) order by 1 nulls last, 2 nulls last;
879 select c2, c6, sum(c1) from ft1 where c2 < 3 group by grouping sets(c2, c6) order by 1 nulls last, 2 nulls last;
880 explain (verbose, costs off)
881 select c2, sum(c1), grouping(c2) from ft1 where c2 < 3 group by c2 order by 1 nulls last;
882 select c2, sum(c1), grouping(c2) from ft1 where c2 < 3 group by c2 order by 1 nulls last;
884 -- DISTINCT itself is not pushed down, whereas underneath aggregate is pushed
885 explain (verbose, costs off)
886 select distinct sum(c1)/1000 s from ft2 where c2 < 6 group by c2 order by 1;
887 select distinct sum(c1)/1000 s from ft2 where c2 < 6 group by c2 order by 1;
890 explain (verbose, costs off)
891 select c2, sum(c2), count(c2) over (partition by c2%2) from ft2 where c2 < 10 group by c2 order by 1;
892 select c2, sum(c2), count(c2) over (partition by c2%2) from ft2 where c2 < 10 group by c2 order by 1;
893 explain (verbose, costs off)
894 select c2, array_agg(c2) over (partition by c2%2 order by c2 desc) from ft1 where c2 < 10 group by c2 order by 1;
895 select c2, array_agg(c2) over (partition by c2%2 order by c2 desc) from ft1 where c2 < 10 group by c2 order by 1;
896 explain (verbose, costs off)
897 select c2, array_agg(c2) over (partition by c2%2 order by c2 range between current row and unbounded following) from ft1 where c2 < 10 group by c2 order by 1;
898 select c2, array_agg(c2) over (partition by c2%2 order by c2 range between current row and unbounded following) from ft1 where c2 < 10 group by c2 order by 1;
901 -- ===================================================================
902 -- parameterized queries
903 -- ===================================================================
905 PREPARE st1(int, int) AS SELECT t1.c3, t2.c3 FROM ft1 t1, ft2 t2 WHERE t1.c1 = $1 AND t2.c1 = $2;
906 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st1(1, 2);
908 EXECUTE st1(101, 101);
909 -- subquery using stable function (can't be sent to remote)
910 PREPARE st2(int) AS SELECT * FROM ft1 t1 WHERE t1.c1 < $2 AND t1.c3 IN (SELECT c3 FROM ft2 t2 WHERE c1 > $1 AND date(c4) = '1970-01-17'::date) ORDER BY c1;
911 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st2(10, 20);
913 EXECUTE st2(101, 121);
914 -- subquery using immutable function (can be sent to remote)
915 PREPARE st3(int) AS SELECT * FROM ft1 t1 WHERE t1.c1 < $2 AND t1.c3 IN (SELECT c3 FROM ft2 t2 WHERE c1 > $1 AND date(c5) = '1970-01-17'::date) ORDER BY c1;
916 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st3(10, 20);
919 -- custom plan should be chosen initially
920 PREPARE st4(int) AS SELECT * FROM ft1 t1 WHERE t1.c1 = $1;
921 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
922 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
923 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
924 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
925 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
926 -- once we try it enough times, should switch to generic plan
927 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
928 -- value of $1 should not be sent to remote
929 PREPARE st5(user_enum,int) AS SELECT * FROM ft1 t1 WHERE c8 = $1 and c1 = $2;
930 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
931 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
932 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
933 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
934 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
935 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
936 EXECUTE st5('foo', 1);
938 -- altering FDW options requires replanning
939 PREPARE st6 AS SELECT * FROM ft1 t1 WHERE t1.c1 = t1.c2;
940 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st6;
941 PREPARE st7 AS INSERT INTO ft1 (c1,c2,c3) VALUES (1001,101,'foo');
942 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st7;
943 ALTER TABLE "S 1"."T 1" RENAME TO "T 0";
944 ALTER FOREIGN TABLE ft1 OPTIONS (SET table_name 'T 0');
945 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st6;
947 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st7;
948 ALTER TABLE "S 1"."T 0" RENAME TO "T 1";
949 ALTER FOREIGN TABLE ft1 OPTIONS (SET table_name 'T 1');
951 PREPARE st8 AS SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2;
952 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8;
953 ALTER SERVER loopback OPTIONS (DROP extensions);
954 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8;
956 ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
968 -- System columns, except ctid and oid, should not be sent to remote
969 EXPLAIN (VERBOSE, COSTS OFF)
970 SELECT * FROM ft1 t1 WHERE t1.tableoid = 'pg_class'::regclass LIMIT 1;
971 SELECT * FROM ft1 t1 WHERE t1.tableoid = 'ft1'::regclass LIMIT 1;
972 EXPLAIN (VERBOSE, COSTS OFF)
973 SELECT tableoid::regclass, * FROM ft1 t1 LIMIT 1;
974 SELECT tableoid::regclass, * FROM ft1 t1 LIMIT 1;
975 EXPLAIN (VERBOSE, COSTS OFF)
976 SELECT * FROM ft1 t1 WHERE t1.ctid = '(0,2)';
977 SELECT * FROM ft1 t1 WHERE t1.ctid = '(0,2)';
978 EXPLAIN (VERBOSE, COSTS OFF)
979 SELECT ctid, * FROM ft1 t1 LIMIT 1;
980 SELECT ctid, * FROM ft1 t1 LIMIT 1;
981 EXPLAIN (VERBOSE, COSTS OFF)
982 SELECT oid, * FROM ft_pg_type WHERE typname = 'int4';
983 SELECT oid, * FROM ft_pg_type WHERE typname = 'int4';
985 -- ===================================================================
986 -- used in PL/pgSQL function
987 -- ===================================================================
988 CREATE OR REPLACE FUNCTION f_test(p_c1 int) RETURNS int AS $$
992 SELECT c1 INTO v_c1 FROM ft1 WHERE c1 = p_c1 LIMIT 1;
993 PERFORM c1 FROM ft1 WHERE c1 = p_c1 AND p_c1 = v_c1 LIMIT 1;
998 DROP FUNCTION f_test(int);
1000 -- ===================================================================
1002 -- ===================================================================
1003 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE int;
1004 SELECT * FROM ft1 WHERE c1 = 1; -- ERROR
1005 SELECT ft1.c1, ft2.c2, ft1.c8 FROM ft1, ft2 WHERE ft1.c1 = ft2.c1 AND ft1.c1 = 1; -- ERROR
1006 SELECT ft1.c1, ft2.c2, ft1 FROM ft1, ft2 WHERE ft1.c1 = ft2.c1 AND ft1.c1 = 1; -- ERROR
1007 SELECT sum(c2), array_agg(c8) FROM ft1 GROUP BY c8; -- ERROR
1008 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE user_enum;
1010 -- ===================================================================
1012 -- + local/remote error doesn't break cursor
1013 -- ===================================================================
1015 DECLARE c CURSOR FOR SELECT * FROM ft1 ORDER BY c1;
1022 SELECT * FROM ft1 WHERE 1 / (c1 - 1) > 0; -- ERROR
1025 SELECT * FROM ft1 ORDER BY c1 LIMIT 1;
1028 -- ===================================================================
1029 -- test handling of collations
1030 -- ===================================================================
1031 create table loct3 (f1 text collate "C" unique, f2 text, f3 varchar(10) unique);
1032 create foreign table ft3 (f1 text collate "C", f2 text, f3 varchar(10))
1033 server loopback options (table_name 'loct3', use_remote_estimate 'true');
1035 -- can be sent to remote
1036 explain (verbose, costs off) select * from ft3 where f1 = 'foo';
1037 explain (verbose, costs off) select * from ft3 where f1 COLLATE "C" = 'foo';
1038 explain (verbose, costs off) select * from ft3 where f2 = 'foo';
1039 explain (verbose, costs off) select * from ft3 where f3 = 'foo';
1040 explain (verbose, costs off) select * from ft3 f, loct3 l
1041 where f.f3 = l.f3 and l.f1 = 'foo';
1042 -- can't be sent to remote
1043 explain (verbose, costs off) select * from ft3 where f1 COLLATE "POSIX" = 'foo';
1044 explain (verbose, costs off) select * from ft3 where f1 = 'foo' COLLATE "C";
1045 explain (verbose, costs off) select * from ft3 where f2 COLLATE "C" = 'foo';
1046 explain (verbose, costs off) select * from ft3 where f2 = 'foo' COLLATE "C";
1047 explain (verbose, costs off) select * from ft3 f, loct3 l
1048 where f.f3 = l.f3 COLLATE "POSIX" and l.f1 = 'foo';
1050 -- ===================================================================
1051 -- test writable foreign table stuff
1052 -- ===================================================================
1053 EXPLAIN (verbose, costs off)
1054 INSERT INTO ft2 (c1,c2,c3) SELECT c1+1000,c2+100, c3 || c3 FROM ft2 LIMIT 20;
1055 INSERT INTO ft2 (c1,c2,c3) SELECT c1+1000,c2+100, c3 || c3 FROM ft2 LIMIT 20;
1056 INSERT INTO ft2 (c1,c2,c3)
1057 VALUES (1101,201,'aaa'), (1102,202,'bbb'), (1103,203,'ccc') RETURNING *;
1058 INSERT INTO ft2 (c1,c2,c3) VALUES (1104,204,'ddd'), (1105,205,'eee');
1059 EXPLAIN (verbose, costs off)
1060 UPDATE ft2 SET c2 = c2 + 300, c3 = c3 || '_update3' WHERE c1 % 10 = 3; -- can be pushed down
1061 UPDATE ft2 SET c2 = c2 + 300, c3 = c3 || '_update3' WHERE c1 % 10 = 3;
1062 EXPLAIN (verbose, costs off)
1063 UPDATE ft2 SET c2 = c2 + 400, c3 = c3 || '_update7' WHERE c1 % 10 = 7 RETURNING *; -- can be pushed down
1064 UPDATE ft2 SET c2 = c2 + 400, c3 = c3 || '_update7' WHERE c1 % 10 = 7 RETURNING *;
1065 EXPLAIN (verbose, costs off)
1066 UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT
1067 FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9; -- can't be pushed down
1068 UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT
1069 FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9;
1070 EXPLAIN (verbose, costs off)
1071 DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING c1, c4; -- can be pushed down
1072 DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING c1, c4;
1073 EXPLAIN (verbose, costs off)
1074 DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2; -- can't be pushed down
1075 DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2;
1076 SELECT c1,c2,c3,c4 FROM ft2 ORDER BY c1;
1077 EXPLAIN (verbose, costs off)
1078 INSERT INTO ft2 (c1,c2,c3) VALUES (9999,999,'foo') RETURNING tableoid::regclass;
1079 INSERT INTO ft2 (c1,c2,c3) VALUES (9999,999,'foo') RETURNING tableoid::regclass;
1080 EXPLAIN (verbose, costs off)
1081 UPDATE ft2 SET c3 = 'bar' WHERE c1 = 9999 RETURNING tableoid::regclass; -- can be pushed down
1082 UPDATE ft2 SET c3 = 'bar' WHERE c1 = 9999 RETURNING tableoid::regclass;
1083 EXPLAIN (verbose, costs off)
1084 DELETE FROM ft2 WHERE c1 = 9999 RETURNING tableoid::regclass; -- can be pushed down
1085 DELETE FROM ft2 WHERE c1 = 9999 RETURNING tableoid::regclass;
1087 -- Test that trigger on remote table works as expected
1088 CREATE OR REPLACE FUNCTION "S 1".F_BRTRIG() RETURNS trigger AS $$
1090 NEW.c3 = NEW.c3 || '_trig_update';
1093 $$ LANGUAGE plpgsql;
1094 CREATE TRIGGER t1_br_insert BEFORE INSERT OR UPDATE
1095 ON "S 1"."T 1" FOR EACH ROW EXECUTE PROCEDURE "S 1".F_BRTRIG();
1097 INSERT INTO ft2 (c1,c2,c3) VALUES (1208, 818, 'fff') RETURNING *;
1098 INSERT INTO ft2 (c1,c2,c3,c6) VALUES (1218, 818, 'ggg', '(--;') RETURNING *;
1099 UPDATE ft2 SET c2 = c2 + 600 WHERE c1 % 10 = 8 AND c1 < 1200 RETURNING *;
1101 -- Test errors thrown on remote side during update
1102 ALTER TABLE "S 1"."T 1" ADD CONSTRAINT c2positive CHECK (c2 >= 0);
1104 INSERT INTO ft1(c1, c2) VALUES(11, 12); -- duplicate key
1105 INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT DO NOTHING; -- works
1106 INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT (c1, c2) DO NOTHING; -- unsupported
1107 INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT (c1, c2) DO UPDATE SET c3 = 'ffg'; -- unsupported
1108 INSERT INTO ft1(c1, c2) VALUES(1111, -2); -- c2positive
1109 UPDATE ft1 SET c2 = -c2 WHERE c1 = 1; -- c2positive
1111 -- Test savepoint/rollback behavior
1112 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
1113 select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
1115 update ft2 set c2 = 42 where c2 = 0;
1116 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
1118 update ft2 set c2 = 44 where c2 = 4;
1119 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
1120 release savepoint s1;
1121 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
1123 update ft2 set c2 = 46 where c2 = 6;
1124 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
1125 rollback to savepoint s2;
1126 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
1127 release savepoint s2;
1128 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
1130 update ft2 set c2 = -2 where c2 = 42 and c1 = 10; -- fail on remote side
1131 rollback to savepoint s3;
1132 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
1133 release savepoint s3;
1134 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
1135 -- none of the above is committed yet remotely
1136 select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
1138 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
1139 select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
1141 -- Above DMLs add data with c6 as NULL in ft1, so test ORDER BY NULLS LAST and NULLs
1142 -- FIRST behavior here.
1143 -- ORDER BY DESC NULLS LAST options
1144 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 ORDER BY c6 DESC NULLS LAST, c1 OFFSET 795 LIMIT 10;
1145 SELECT * FROM ft1 ORDER BY c6 DESC NULLS LAST, c1 OFFSET 795 LIMIT 10;
1146 -- ORDER BY DESC NULLS FIRST options
1147 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 ORDER BY c6 DESC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
1148 SELECT * FROM ft1 ORDER BY c6 DESC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
1149 -- ORDER BY ASC NULLS FIRST options
1150 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 ORDER BY c6 ASC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
1151 SELECT * FROM ft1 ORDER BY c6 ASC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
1153 -- ===================================================================
1154 -- test check constraints
1155 -- ===================================================================
1157 -- Consistent check constraints provide consistent results
1158 ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c2positive CHECK (c2 >= 0);
1159 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 < 0;
1160 SELECT count(*) FROM ft1 WHERE c2 < 0;
1161 SET constraint_exclusion = 'on';
1162 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 < 0;
1163 SELECT count(*) FROM ft1 WHERE c2 < 0;
1164 RESET constraint_exclusion;
1165 -- check constraint is enforced on the remote side, not locally
1166 INSERT INTO ft1(c1, c2) VALUES(1111, -2); -- c2positive
1167 UPDATE ft1 SET c2 = -c2 WHERE c1 = 1; -- c2positive
1168 ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2positive;
1170 -- But inconsistent check constraints provide inconsistent results
1171 ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c2negative CHECK (c2 < 0);
1172 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 >= 0;
1173 SELECT count(*) FROM ft1 WHERE c2 >= 0;
1174 SET constraint_exclusion = 'on';
1175 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 >= 0;
1176 SELECT count(*) FROM ft1 WHERE c2 >= 0;
1177 RESET constraint_exclusion;
1178 -- local check constraint is not actually enforced
1179 INSERT INTO ft1(c1, c2) VALUES(1111, 2);
1180 UPDATE ft1 SET c2 = c2 + 1 WHERE c1 = 1;
1181 ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2negative;
1183 -- ===================================================================
1184 -- test WITH CHECK OPTION constraints
1185 -- ===================================================================
1187 CREATE TABLE base_tbl (a int, b int);
1188 CREATE FOREIGN TABLE foreign_tbl (a int, b int)
1189 SERVER loopback OPTIONS(table_name 'base_tbl');
1190 CREATE VIEW rw_view AS SELECT * FROM foreign_tbl
1191 WHERE a < b WITH CHECK OPTION;
1194 INSERT INTO rw_view VALUES (0, 10); -- ok
1195 INSERT INTO rw_view VALUES (10, 0); -- should fail
1196 EXPLAIN (VERBOSE, COSTS OFF)
1197 UPDATE rw_view SET b = 20 WHERE a = 0; -- not pushed down
1198 UPDATE rw_view SET b = 20 WHERE a = 0; -- ok
1199 EXPLAIN (VERBOSE, COSTS OFF)
1200 UPDATE rw_view SET b = -20 WHERE a = 0; -- not pushed down
1201 UPDATE rw_view SET b = -20 WHERE a = 0; -- should fail
1202 SELECT * FROM foreign_tbl;
1204 DROP FOREIGN TABLE foreign_tbl CASCADE;
1205 DROP TABLE base_tbl;
1207 -- ===================================================================
1208 -- test serial columns (ie, sequence-based defaults)
1209 -- ===================================================================
1210 create table loc1 (f1 serial, f2 text);
1211 create foreign table rem1 (f1 serial, f2 text)
1212 server loopback options(table_name 'loc1');
1213 select pg_catalog.setval('rem1_f1_seq', 10, false);
1214 insert into loc1(f2) values('hi');
1215 insert into rem1(f2) values('hi remote');
1216 insert into loc1(f2) values('bye');
1217 insert into rem1(f2) values('bye remote');
1221 -- ===================================================================
1222 -- test local triggers
1223 -- ===================================================================
1225 -- Trigger functions "borrowed" from triggers regress test.
1226 CREATE FUNCTION trigger_func() RETURNS trigger LANGUAGE plpgsql AS $$
1228 RAISE NOTICE 'trigger_func(%) called: action = %, when = %, level = %',
1229 TG_ARGV[0], TG_OP, TG_WHEN, TG_LEVEL;
1233 CREATE TRIGGER trig_stmt_before BEFORE DELETE OR INSERT OR UPDATE ON rem1
1234 FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
1235 CREATE TRIGGER trig_stmt_after AFTER DELETE OR INSERT OR UPDATE ON rem1
1236 FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
1238 CREATE OR REPLACE FUNCTION trigger_data() RETURNS trigger
1239 LANGUAGE plpgsql AS $$
1247 relid := TG_relid::regclass;
1249 for i in 0 .. TG_nargs - 1 loop
1251 argstr := argstr || ', ';
1253 argstr := argstr || TG_argv[i];
1256 RAISE NOTICE '%(%) % % % ON %',
1257 tg_name, argstr, TG_when, TG_level, TG_OP, relid;
1258 oldnew := '{}'::text[];
1259 if TG_OP != 'INSERT' then
1260 oldnew := array_append(oldnew, format('OLD: %s', OLD));
1263 if TG_OP != 'DELETE' then
1264 oldnew := array_append(oldnew, format('NEW: %s', NEW));
1267 RAISE NOTICE '%', array_to_string(oldnew, ',');
1269 if TG_OP = 'DELETE' then
1277 -- Test basic functionality
1278 CREATE TRIGGER trig_row_before
1279 BEFORE INSERT OR UPDATE OR DELETE ON rem1
1280 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
1282 CREATE TRIGGER trig_row_after
1283 AFTER INSERT OR UPDATE OR DELETE ON rem1
1284 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
1287 insert into rem1 values(1,'insert');
1288 update rem1 set f2 = 'update' where f1 = 1;
1289 update rem1 set f2 = f2 || f2;
1293 DROP TRIGGER trig_row_before ON rem1;
1294 DROP TRIGGER trig_row_after ON rem1;
1295 DROP TRIGGER trig_stmt_before ON rem1;
1296 DROP TRIGGER trig_stmt_after ON rem1;
1301 -- Test WHEN conditions
1303 CREATE TRIGGER trig_row_before_insupd
1304 BEFORE INSERT OR UPDATE ON rem1
1306 WHEN (NEW.f2 like '%update%')
1307 EXECUTE PROCEDURE trigger_data(23,'skidoo');
1309 CREATE TRIGGER trig_row_after_insupd
1310 AFTER INSERT OR UPDATE ON rem1
1312 WHEN (NEW.f2 like '%update%')
1313 EXECUTE PROCEDURE trigger_data(23,'skidoo');
1315 -- Insert or update not matching: nothing happens
1316 INSERT INTO rem1 values(1, 'insert');
1317 UPDATE rem1 set f2 = 'test';
1319 -- Insert or update matching: triggers are fired
1320 INSERT INTO rem1 values(2, 'update');
1321 UPDATE rem1 set f2 = 'update update' where f1 = '2';
1323 CREATE TRIGGER trig_row_before_delete
1324 BEFORE DELETE ON rem1
1326 WHEN (OLD.f2 like '%update%')
1327 EXECUTE PROCEDURE trigger_data(23,'skidoo');
1329 CREATE TRIGGER trig_row_after_delete
1330 AFTER DELETE ON rem1
1332 WHEN (OLD.f2 like '%update%')
1333 EXECUTE PROCEDURE trigger_data(23,'skidoo');
1335 -- Trigger is fired for f1=2, not for f1=1
1339 DROP TRIGGER trig_row_before_insupd ON rem1;
1340 DROP TRIGGER trig_row_after_insupd ON rem1;
1341 DROP TRIGGER trig_row_before_delete ON rem1;
1342 DROP TRIGGER trig_row_after_delete ON rem1;
1345 -- Test various RETURN statements in BEFORE triggers.
1347 CREATE FUNCTION trig_row_before_insupdate() RETURNS TRIGGER AS $$
1349 NEW.f2 := NEW.f2 || ' triggered !';
1352 $$ language plpgsql;
1354 CREATE TRIGGER trig_row_before_insupd
1355 BEFORE INSERT OR UPDATE ON rem1
1356 FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate();
1358 -- The new values should have 'triggered' appended
1359 INSERT INTO rem1 values(1, 'insert');
1361 INSERT INTO rem1 values(2, 'insert') RETURNING f2;
1363 UPDATE rem1 set f2 = '';
1365 UPDATE rem1 set f2 = 'skidoo' RETURNING f2;
1370 -- Add a second trigger, to check that the changes are propagated correctly
1371 -- from trigger to trigger
1372 CREATE TRIGGER trig_row_before_insupd2
1373 BEFORE INSERT OR UPDATE ON rem1
1374 FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate();
1376 INSERT INTO rem1 values(1, 'insert');
1378 INSERT INTO rem1 values(2, 'insert') RETURNING f2;
1380 UPDATE rem1 set f2 = '';
1382 UPDATE rem1 set f2 = 'skidoo' RETURNING f2;
1385 DROP TRIGGER trig_row_before_insupd ON rem1;
1386 DROP TRIGGER trig_row_before_insupd2 ON rem1;
1390 INSERT INTO rem1 VALUES (1, 'test');
1392 -- Test with a trigger returning NULL
1393 CREATE FUNCTION trig_null() RETURNS TRIGGER AS $$
1397 $$ language plpgsql;
1399 CREATE TRIGGER trig_null
1400 BEFORE INSERT OR UPDATE OR DELETE ON rem1
1401 FOR EACH ROW EXECUTE PROCEDURE trig_null();
1403 -- Nothing should have changed.
1404 INSERT INTO rem1 VALUES (2, 'test2');
1408 UPDATE rem1 SET f2 = 'test2';
1416 DROP TRIGGER trig_null ON rem1;
1419 -- Test a combination of local and remote triggers
1420 CREATE TRIGGER trig_row_before
1421 BEFORE INSERT OR UPDATE OR DELETE ON rem1
1422 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
1424 CREATE TRIGGER trig_row_after
1425 AFTER INSERT OR UPDATE OR DELETE ON rem1
1426 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
1428 CREATE TRIGGER trig_local_before BEFORE INSERT OR UPDATE ON loc1
1429 FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate();
1431 INSERT INTO rem1(f2) VALUES ('test');
1432 UPDATE rem1 SET f2 = 'testo';
1434 -- Test returning a system attribute
1435 INSERT INTO rem1(f2) VALUES ('test') RETURNING ctid;
1438 DROP TRIGGER trig_row_before ON rem1;
1439 DROP TRIGGER trig_row_after ON rem1;
1440 DROP TRIGGER trig_local_before ON loc1;
1443 -- Test direct foreign table modification functionality
1445 -- Test with statement-level triggers
1446 CREATE TRIGGER trig_stmt_before
1447 BEFORE DELETE OR INSERT OR UPDATE ON rem1
1448 FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
1449 EXPLAIN (verbose, costs off)
1450 UPDATE rem1 set f2 = ''; -- can be pushed down
1451 EXPLAIN (verbose, costs off)
1452 DELETE FROM rem1; -- can be pushed down
1453 DROP TRIGGER trig_stmt_before ON rem1;
1455 CREATE TRIGGER trig_stmt_after
1456 AFTER DELETE OR INSERT OR UPDATE ON rem1
1457 FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
1458 EXPLAIN (verbose, costs off)
1459 UPDATE rem1 set f2 = ''; -- can be pushed down
1460 EXPLAIN (verbose, costs off)
1461 DELETE FROM rem1; -- can be pushed down
1462 DROP TRIGGER trig_stmt_after ON rem1;
1464 -- Test with row-level ON INSERT triggers
1465 CREATE TRIGGER trig_row_before_insert
1466 BEFORE INSERT ON rem1
1467 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
1468 EXPLAIN (verbose, costs off)
1469 UPDATE rem1 set f2 = ''; -- can be pushed down
1470 EXPLAIN (verbose, costs off)
1471 DELETE FROM rem1; -- can be pushed down
1472 DROP TRIGGER trig_row_before_insert ON rem1;
1474 CREATE TRIGGER trig_row_after_insert
1475 AFTER INSERT ON rem1
1476 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
1477 EXPLAIN (verbose, costs off)
1478 UPDATE rem1 set f2 = ''; -- can be pushed down
1479 EXPLAIN (verbose, costs off)
1480 DELETE FROM rem1; -- can be pushed down
1481 DROP TRIGGER trig_row_after_insert ON rem1;
1483 -- Test with row-level ON UPDATE triggers
1484 CREATE TRIGGER trig_row_before_update
1485 BEFORE UPDATE ON rem1
1486 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
1487 EXPLAIN (verbose, costs off)
1488 UPDATE rem1 set f2 = ''; -- can't be pushed down
1489 EXPLAIN (verbose, costs off)
1490 DELETE FROM rem1; -- can be pushed down
1491 DROP TRIGGER trig_row_before_update ON rem1;
1493 CREATE TRIGGER trig_row_after_update
1494 AFTER UPDATE ON rem1
1495 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
1496 EXPLAIN (verbose, costs off)
1497 UPDATE rem1 set f2 = ''; -- can't be pushed down
1498 EXPLAIN (verbose, costs off)
1499 DELETE FROM rem1; -- can be pushed down
1500 DROP TRIGGER trig_row_after_update ON rem1;
1502 -- Test with row-level ON DELETE triggers
1503 CREATE TRIGGER trig_row_before_delete
1504 BEFORE DELETE ON rem1
1505 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
1506 EXPLAIN (verbose, costs off)
1507 UPDATE rem1 set f2 = ''; -- can be pushed down
1508 EXPLAIN (verbose, costs off)
1509 DELETE FROM rem1; -- can't be pushed down
1510 DROP TRIGGER trig_row_before_delete ON rem1;
1512 CREATE TRIGGER trig_row_after_delete
1513 AFTER DELETE ON rem1
1514 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
1515 EXPLAIN (verbose, costs off)
1516 UPDATE rem1 set f2 = ''; -- can be pushed down
1517 EXPLAIN (verbose, costs off)
1518 DELETE FROM rem1; -- can't be pushed down
1519 DROP TRIGGER trig_row_after_delete ON rem1;
1521 -- ===================================================================
1522 -- test inheritance features
1523 -- ===================================================================
1525 CREATE TABLE a (aa TEXT);
1526 CREATE TABLE loct (aa TEXT, bb TEXT);
1527 CREATE FOREIGN TABLE b (bb TEXT) INHERITS (a)
1528 SERVER loopback OPTIONS (table_name 'loct');
1530 INSERT INTO a(aa) VALUES('aaa');
1531 INSERT INTO a(aa) VALUES('aaaa');
1532 INSERT INTO a(aa) VALUES('aaaaa');
1534 INSERT INTO b(aa) VALUES('bbb');
1535 INSERT INTO b(aa) VALUES('bbbb');
1536 INSERT INTO b(aa) VALUES('bbbbb');
1538 SELECT tableoid::regclass, * FROM a;
1539 SELECT tableoid::regclass, * FROM b;
1540 SELECT tableoid::regclass, * FROM ONLY a;
1542 UPDATE a SET aa = 'zzzzzz' WHERE aa LIKE 'aaaa%';
1544 SELECT tableoid::regclass, * FROM a;
1545 SELECT tableoid::regclass, * FROM b;
1546 SELECT tableoid::regclass, * FROM ONLY a;
1548 UPDATE b SET aa = 'new';
1550 SELECT tableoid::regclass, * FROM a;
1551 SELECT tableoid::regclass, * FROM b;
1552 SELECT tableoid::regclass, * FROM ONLY a;
1554 UPDATE a SET aa = 'newtoo';
1556 SELECT tableoid::regclass, * FROM a;
1557 SELECT tableoid::regclass, * FROM b;
1558 SELECT tableoid::regclass, * FROM ONLY a;
1562 SELECT tableoid::regclass, * FROM a;
1563 SELECT tableoid::regclass, * FROM b;
1564 SELECT tableoid::regclass, * FROM ONLY a;
1566 DROP TABLE a CASCADE;
1569 -- Check SELECT FOR UPDATE/SHARE with an inherited source table
1570 create table loct1 (f1 int, f2 int, f3 int);
1571 create table loct2 (f1 int, f2 int, f3 int);
1573 create table foo (f1 int, f2 int);
1574 create foreign table foo2 (f3 int) inherits (foo)
1575 server loopback options (table_name 'loct1');
1576 create table bar (f1 int, f2 int);
1577 create foreign table bar2 (f3 int) inherits (bar)
1578 server loopback options (table_name 'loct2');
1580 insert into foo values(1,1);
1581 insert into foo values(3,3);
1582 insert into foo2 values(2,2,2);
1583 insert into foo2 values(4,4,4);
1584 insert into bar values(1,11);
1585 insert into bar values(2,22);
1586 insert into bar values(6,66);
1587 insert into bar2 values(3,33,33);
1588 insert into bar2 values(4,44,44);
1589 insert into bar2 values(7,77,77);
1591 explain (verbose, costs off)
1592 select * from bar where f1 in (select f1 from foo) for update;
1593 select * from bar where f1 in (select f1 from foo) for update;
1595 explain (verbose, costs off)
1596 select * from bar where f1 in (select f1 from foo) for share;
1597 select * from bar where f1 in (select f1 from foo) for share;
1599 -- Check UPDATE with inherited target and an inherited source table
1600 explain (verbose, costs off)
1601 update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
1602 update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
1604 select tableoid::regclass, * from bar order by 1,2;
1606 -- Check UPDATE with inherited target and an appendrel subquery
1607 explain (verbose, costs off)
1608 update bar set f2 = f2 + 100
1610 ( select f1 from foo union all select f1+3 from foo ) ss
1611 where bar.f1 = ss.f1;
1612 update bar set f2 = f2 + 100
1614 ( select f1 from foo union all select f1+3 from foo ) ss
1615 where bar.f1 = ss.f1;
1617 select tableoid::regclass, * from bar order by 1,2;
1619 -- Test forcing the remote server to produce sorted data for a merge join,
1620 -- but the foreign table is an inheritance child.
1621 truncate table loct1;
1622 truncate table only foo;
1623 \set num_rows_foo 2000
1624 insert into loct1 select generate_series(0, :num_rows_foo, 2), generate_series(0, :num_rows_foo, 2), generate_series(0, :num_rows_foo, 2);
1625 insert into foo select generate_series(1, :num_rows_foo, 2), generate_series(1, :num_rows_foo, 2);
1626 SET enable_hashjoin to false;
1627 SET enable_nestloop to false;
1628 alter foreign table foo2 options (use_remote_estimate 'true');
1629 create index i_loct1_f1 on loct1(f1);
1630 create index i_foo_f1 on foo(f1);
1633 -- inner join; expressions in the clauses appear in the equivalence class list
1634 explain (verbose, costs off)
1635 select foo.f1, loct1.f1 from foo join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
1636 select foo.f1, loct1.f1 from foo join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
1637 -- outer join; expressions in the clauses do not appear in equivalence class
1638 -- list but no output change as compared to the previous query
1639 explain (verbose, costs off)
1640 select foo.f1, loct1.f1 from foo left join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
1641 select foo.f1, loct1.f1 from foo left join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
1642 RESET enable_hashjoin;
1643 RESET enable_nestloop;
1645 -- Test that WHERE CURRENT OF is not supported
1647 declare c cursor for select * from bar where f1 = 7;
1649 update bar set f2 = null where current of c;
1652 explain (verbose, costs off)
1653 delete from foo where f1 < 5 returning *;
1654 delete from foo where f1 < 5 returning *;
1655 explain (verbose, costs off)
1656 update bar set f2 = f2 + 100 returning *;
1657 update bar set f2 = f2 + 100 returning *;
1659 -- Test that UPDATE/DELETE with inherited target works with row-level triggers
1660 CREATE TRIGGER trig_row_before
1661 BEFORE UPDATE OR DELETE ON bar2
1662 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
1664 CREATE TRIGGER trig_row_after
1665 AFTER UPDATE OR DELETE ON bar2
1666 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
1668 explain (verbose, costs off)
1669 update bar set f2 = f2 + 100;
1670 update bar set f2 = f2 + 100;
1672 explain (verbose, costs off)
1673 delete from bar where f2 < 400;
1674 delete from bar where f2 < 400;
1677 drop table foo cascade;
1678 drop table bar cascade;
1682 -- ===================================================================
1683 -- test IMPORT FOREIGN SCHEMA
1684 -- ===================================================================
1686 CREATE SCHEMA import_source;
1687 CREATE TABLE import_source.t1 (c1 int, c2 varchar NOT NULL);
1688 CREATE TABLE import_source.t2 (c1 int default 42, c2 varchar NULL, c3 text collate "POSIX");
1689 CREATE TYPE typ1 AS (m1 int, m2 varchar);
1690 CREATE TABLE import_source.t3 (c1 timestamptz default now(), c2 typ1);
1691 CREATE TABLE import_source."x 4" (c1 float8, "C 2" text, c3 varchar(42));
1692 CREATE TABLE import_source."x 5" (c1 float8);
1693 ALTER TABLE import_source."x 5" DROP COLUMN c1;
1694 CREATE TABLE import_source.t4 (c1 int) PARTITION BY RANGE (c1);
1695 CREATE TABLE import_source.t4_part PARTITION OF import_source.t4
1696 FOR VALUES FROM (1) TO (100);
1698 CREATE SCHEMA import_dest1;
1699 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest1;
1700 \det+ import_dest1.*
1704 CREATE SCHEMA import_dest2;
1705 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest2
1706 OPTIONS (import_default 'true');
1707 \det+ import_dest2.*
1709 CREATE SCHEMA import_dest3;
1710 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest3
1711 OPTIONS (import_collate 'false', import_not_null 'false');
1712 \det+ import_dest3.*
1715 -- Check LIMIT TO and EXCEPT
1716 CREATE SCHEMA import_dest4;
1717 IMPORT FOREIGN SCHEMA import_source LIMIT TO (t1, nonesuch)
1718 FROM SERVER loopback INTO import_dest4;
1719 \det+ import_dest4.*
1720 IMPORT FOREIGN SCHEMA import_source EXCEPT (t1, "x 4", nonesuch)
1721 FROM SERVER loopback INTO import_dest4;
1722 \det+ import_dest4.*
1724 -- Assorted error cases
1725 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest4;
1726 IMPORT FOREIGN SCHEMA nonesuch FROM SERVER loopback INTO import_dest4;
1727 IMPORT FOREIGN SCHEMA nonesuch FROM SERVER loopback INTO notthere;
1728 IMPORT FOREIGN SCHEMA nonesuch FROM SERVER nowhere INTO notthere;
1730 -- Check case of a type present only on the remote server.
1731 -- We can fake this by dropping the type locally in our transaction.
1732 CREATE TYPE "Colors" AS ENUM ('red', 'green', 'blue');
1733 CREATE TABLE import_source.t5 (c1 int, c2 text collate "C", "Col" "Colors");
1735 CREATE SCHEMA import_dest5;
1737 DROP TYPE "Colors" CASCADE;
1738 IMPORT FOREIGN SCHEMA import_source LIMIT TO (t5)
1739 FROM SERVER loopback INTO import_dest5; -- ERROR
1746 CREATE SERVER fetch101 FOREIGN DATA WRAPPER postgres_fdw OPTIONS( fetch_size '101' );
1749 FROM pg_foreign_server
1750 WHERE srvname = 'fetch101'
1751 AND srvoptions @> array['fetch_size=101'];
1753 ALTER SERVER fetch101 OPTIONS( SET fetch_size '202' );
1756 FROM pg_foreign_server
1757 WHERE srvname = 'fetch101'
1758 AND srvoptions @> array['fetch_size=101'];
1761 FROM pg_foreign_server
1762 WHERE srvname = 'fetch101'
1763 AND srvoptions @> array['fetch_size=202'];
1765 CREATE FOREIGN TABLE table30000 ( x int ) SERVER fetch101 OPTIONS ( fetch_size '30000' );
1768 FROM pg_foreign_table
1769 WHERE ftrelid = 'table30000'::regclass
1770 AND ftoptions @> array['fetch_size=30000'];
1772 ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '60000');
1775 FROM pg_foreign_table
1776 WHERE ftrelid = 'table30000'::regclass
1777 AND ftoptions @> array['fetch_size=30000'];
1780 FROM pg_foreign_table
1781 WHERE ftrelid = 'table30000'::regclass
1782 AND ftoptions @> array['fetch_size=60000'];
1786 -- ===================================================================
1787 -- test partition-wise-joins
1788 -- ===================================================================
1789 SET enable_partition_wise_join=on;
1791 CREATE TABLE fprt1 (a int, b int, c varchar) PARTITION BY RANGE(a);
1792 CREATE TABLE fprt1_p1 (LIKE fprt1);
1793 CREATE TABLE fprt1_p2 (LIKE fprt1);
1794 INSERT INTO fprt1_p1 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 249, 2) i;
1795 INSERT INTO fprt1_p2 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(250, 499, 2) i;
1796 CREATE FOREIGN TABLE ftprt1_p1 PARTITION OF fprt1 FOR VALUES FROM (0) TO (250)
1797 SERVER loopback OPTIONS (table_name 'fprt1_p1', use_remote_estimate 'true');
1798 CREATE FOREIGN TABLE ftprt1_p2 PARTITION OF fprt1 FOR VALUES FROM (250) TO (500)
1799 SERVER loopback OPTIONS (TABLE_NAME 'fprt1_p2');
1804 CREATE TABLE fprt2 (a int, b int, c varchar) PARTITION BY RANGE(b);
1805 CREATE TABLE fprt2_p1 (LIKE fprt2);
1806 CREATE TABLE fprt2_p2 (LIKE fprt2);
1807 INSERT INTO fprt2_p1 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 249, 3) i;
1808 INSERT INTO fprt2_p2 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(250, 499, 3) i;
1809 CREATE FOREIGN TABLE ftprt2_p1 PARTITION OF fprt2 FOR VALUES FROM (0) TO (250)
1810 SERVER loopback OPTIONS (table_name 'fprt2_p1', use_remote_estimate 'true');
1811 CREATE FOREIGN TABLE ftprt2_p2 PARTITION OF fprt2 FOR VALUES FROM (250) TO (500)
1812 SERVER loopback OPTIONS (table_name 'fprt2_p2', use_remote_estimate 'true');
1817 -- inner join three tables
1819 SELECT t1.a,t2.b,t3.c FROM fprt1 t1 INNER JOIN fprt2 t2 ON (t1.a = t2.b) INNER JOIN fprt1 t3 ON (t2.b = t3.a) WHERE t1.a % 25 =0 ORDER BY 1,2,3;
1820 SELECT t1.a,t2.b,t3.c FROM fprt1 t1 INNER JOIN fprt2 t2 ON (t1.a = t2.b) INNER JOIN fprt1 t3 ON (t2.b = t3.a) WHERE t1.a % 25 =0 ORDER BY 1,2,3;
1822 -- left outer join + nullable clasue
1824 SELECT t1.a,t2.b,t2.c FROM fprt1 t1 LEFT JOIN (SELECT * FROM fprt2 WHERE a < 10) t2 ON (t1.a = t2.b and t1.b = t2.a) WHERE t1.a < 10 ORDER BY 1,2,3;
1825 SELECT t1.a,t2.b,t2.c FROM fprt1 t1 LEFT JOIN (SELECT * FROM fprt2 WHERE a < 10) t2 ON (t1.a = t2.b and t1.b = t2.a) WHERE t1.a < 10 ORDER BY 1,2,3;
1827 -- with whole-row reference
1829 SELECT t1,t2 FROM fprt1 t1 JOIN fprt2 t2 ON (t1.a = t2.b and t1.b = t2.a) WHERE t1.a % 25 =0 ORDER BY 1,2;
1830 SELECT t1,t2 FROM fprt1 t1 JOIN fprt2 t2 ON (t1.a = t2.b and t1.b = t2.a) WHERE t1.a % 25 =0 ORDER BY 1,2;
1832 -- join with lateral reference
1834 SELECT t1.a,t1.b FROM fprt1 t1, LATERAL (SELECT t2.a, t2.b FROM fprt2 t2 WHERE t1.a = t2.b AND t1.b = t2.a) q WHERE t1.a%25 = 0 ORDER BY 1,2;
1835 SELECT t1.a,t1.b FROM fprt1 t1, LATERAL (SELECT t2.a, t2.b FROM fprt2 t2 WHERE t1.a = t2.b AND t1.b = t2.a) q WHERE t1.a%25 = 0 ORDER BY 1,2;
1837 RESET enable_partition_wise_join;