Revert commit 66c0185a3 and follow-on patches.
[pgsql.git] / contrib / postgres_fdw / expected / postgres_fdw.out
blob9ae36d3059d16b10dd146e57f7753a414e3728fb
1 -- ===================================================================
2 -- create FDW objects
3 -- ===================================================================
4 CREATE EXTENSION postgres_fdw;
5 CREATE SERVER testserver1 FOREIGN DATA WRAPPER postgres_fdw;
6 DO $d$
7     BEGIN
8         EXECUTE $$CREATE SERVER loopback FOREIGN DATA WRAPPER postgres_fdw
9             OPTIONS (dbname '$$||current_database()||$$',
10                      port '$$||current_setting('port')||$$'
11             )$$;
12         EXECUTE $$CREATE SERVER loopback2 FOREIGN DATA WRAPPER postgres_fdw
13             OPTIONS (dbname '$$||current_database()||$$',
14                      port '$$||current_setting('port')||$$'
15             )$$;
16         EXECUTE $$CREATE SERVER loopback3 FOREIGN DATA WRAPPER postgres_fdw
17             OPTIONS (dbname '$$||current_database()||$$',
18                      port '$$||current_setting('port')||$$'
19             )$$;
20     END;
21 $d$;
22 CREATE USER MAPPING FOR public SERVER testserver1
23         OPTIONS (user 'value', password 'value');
24 CREATE USER MAPPING FOR CURRENT_USER SERVER loopback;
25 CREATE USER MAPPING FOR CURRENT_USER SERVER loopback2;
26 CREATE USER MAPPING FOR public SERVER loopback3;
27 -- ===================================================================
28 -- create objects used through FDW loopback server
29 -- ===================================================================
30 CREATE TYPE user_enum AS ENUM ('foo', 'bar', 'buz');
31 CREATE SCHEMA "S 1";
32 CREATE TABLE "S 1"."T 1" (
33         "C 1" int NOT NULL,
34         c2 int NOT NULL,
35         c3 text,
36         c4 timestamptz,
37         c5 timestamp,
38         c6 varchar(10),
39         c7 char(10),
40         c8 user_enum,
41         CONSTRAINT t1_pkey PRIMARY KEY ("C 1")
43 CREATE TABLE "S 1"."T 2" (
44         c1 int NOT NULL,
45         c2 text,
46         CONSTRAINT t2_pkey PRIMARY KEY (c1)
48 CREATE TABLE "S 1"."T 3" (
49         c1 int NOT NULL,
50         c2 int NOT NULL,
51         c3 text,
52         CONSTRAINT t3_pkey PRIMARY KEY (c1)
54 CREATE TABLE "S 1"."T 4" (
55         c1 int NOT NULL,
56         c2 int NOT NULL,
57         c3 text,
58         CONSTRAINT t4_pkey PRIMARY KEY (c1)
60 -- Disable autovacuum for these tables to avoid unexpected effects of that
61 ALTER TABLE "S 1"."T 1" SET (autovacuum_enabled = 'false');
62 ALTER TABLE "S 1"."T 2" SET (autovacuum_enabled = 'false');
63 ALTER TABLE "S 1"."T 3" SET (autovacuum_enabled = 'false');
64 ALTER TABLE "S 1"."T 4" SET (autovacuum_enabled = 'false');
65 INSERT INTO "S 1"."T 1"
66         SELECT id,
67                id % 10,
68                to_char(id, 'FM00000'),
69                '1970-01-01'::timestamptz + ((id % 100) || ' days')::interval,
70                '1970-01-01'::timestamp + ((id % 100) || ' days')::interval,
71                id % 10,
72                id % 10,
73                'foo'::user_enum
74         FROM generate_series(1, 1000) id;
75 INSERT INTO "S 1"."T 2"
76         SELECT id,
77                'AAA' || to_char(id, 'FM000')
78         FROM generate_series(1, 100) id;
79 INSERT INTO "S 1"."T 3"
80         SELECT id,
81                id + 1,
82                'AAA' || to_char(id, 'FM000')
83         FROM generate_series(1, 100) id;
84 DELETE FROM "S 1"."T 3" WHERE c1 % 2 != 0;      -- delete for outer join tests
85 INSERT INTO "S 1"."T 4"
86         SELECT id,
87                id + 1,
88                'AAA' || to_char(id, 'FM000')
89         FROM generate_series(1, 100) id;
90 DELETE FROM "S 1"."T 4" WHERE c1 % 3 != 0;      -- delete for outer join tests
91 ANALYZE "S 1"."T 1";
92 ANALYZE "S 1"."T 2";
93 ANALYZE "S 1"."T 3";
94 ANALYZE "S 1"."T 4";
95 -- ===================================================================
96 -- create foreign tables
97 -- ===================================================================
98 CREATE FOREIGN TABLE ft1 (
99         c0 int,
100         c1 int NOT NULL,
101         c2 int NOT NULL,
102         c3 text,
103         c4 timestamptz,
104         c5 timestamp,
105         c6 varchar(10),
106         c7 char(10) default 'ft1',
107         c8 user_enum
108 ) SERVER loopback;
109 ALTER FOREIGN TABLE ft1 DROP COLUMN c0;
110 CREATE FOREIGN TABLE ft2 (
111         c1 int NOT NULL,
112         c2 int NOT NULL,
113         cx int,
114         c3 text,
115         c4 timestamptz,
116         c5 timestamp,
117         c6 varchar(10),
118         c7 char(10) default 'ft2',
119         c8 user_enum
120 ) SERVER loopback;
121 ALTER FOREIGN TABLE ft2 DROP COLUMN cx;
122 CREATE FOREIGN TABLE ft4 (
123         c1 int NOT NULL,
124         c2 int NOT NULL,
125         c3 text
126 ) SERVER loopback OPTIONS (schema_name 'S 1', table_name 'T 3');
127 CREATE FOREIGN TABLE ft5 (
128         c1 int NOT NULL,
129         c2 int NOT NULL,
130         c3 text
131 ) SERVER loopback OPTIONS (schema_name 'S 1', table_name 'T 4');
132 CREATE FOREIGN TABLE ft6 (
133         c1 int NOT NULL,
134         c2 int NOT NULL,
135         c3 text
136 ) SERVER loopback2 OPTIONS (schema_name 'S 1', table_name 'T 4');
137 CREATE FOREIGN TABLE ft7 (
138         c1 int NOT NULL,
139         c2 int NOT NULL,
140         c3 text
141 ) SERVER loopback3 OPTIONS (schema_name 'S 1', table_name 'T 4');
142 -- ===================================================================
143 -- tests for validator
144 -- ===================================================================
145 -- requiressl and some other parameters are omitted because
146 -- valid values for them depend on configure options
147 ALTER SERVER testserver1 OPTIONS (
148         use_remote_estimate 'false',
149         updatable 'true',
150         fdw_startup_cost '123.456',
151         fdw_tuple_cost '0.123',
152         service 'value',
153         connect_timeout 'value',
154         dbname 'value',
155         host 'value',
156         hostaddr 'value',
157         port 'value',
158         --client_encoding 'value',
159         application_name 'value',
160         --fallback_application_name 'value',
161         keepalives 'value',
162         keepalives_idle 'value',
163         keepalives_interval 'value',
164         tcp_user_timeout 'value',
165         -- requiressl 'value',
166         sslcompression 'value',
167         sslmode 'value',
168         sslcert 'value',
169         sslkey 'value',
170         sslrootcert 'value',
171         sslcrl 'value',
172         --requirepeer 'value',
173         krbsrvname 'value',
174         gsslib 'value',
175         gssdelegation 'value'
176         --replication 'value'
178 -- Error, invalid list syntax
179 ALTER SERVER testserver1 OPTIONS (ADD extensions 'foo; bar');
180 ERROR:  parameter "extensions" must be a list of extension names
181 -- OK but gets a warning
182 ALTER SERVER testserver1 OPTIONS (ADD extensions 'foo, bar');
183 WARNING:  extension "foo" is not installed
184 WARNING:  extension "bar" is not installed
185 ALTER SERVER testserver1 OPTIONS (DROP extensions);
186 ALTER USER MAPPING FOR public SERVER testserver1
187         OPTIONS (DROP user, DROP password);
188 -- Attempt to add a valid option that's not allowed in a user mapping
189 ALTER USER MAPPING FOR public SERVER testserver1
190         OPTIONS (ADD sslmode 'require');
191 ERROR:  invalid option "sslmode"
192 -- But we can add valid ones fine
193 ALTER USER MAPPING FOR public SERVER testserver1
194         OPTIONS (ADD sslpassword 'dummy');
195 -- Ensure valid options we haven't used in a user mapping yet are
196 -- permitted to check validation.
197 ALTER USER MAPPING FOR public SERVER testserver1
198         OPTIONS (ADD sslkey 'value', ADD sslcert 'value');
199 ALTER FOREIGN TABLE ft1 OPTIONS (schema_name 'S 1', table_name 'T 1');
200 ALTER FOREIGN TABLE ft2 OPTIONS (schema_name 'S 1', table_name 'T 1');
201 ALTER FOREIGN TABLE ft1 ALTER COLUMN c1 OPTIONS (column_name 'C 1');
202 ALTER FOREIGN TABLE ft2 ALTER COLUMN c1 OPTIONS (column_name 'C 1');
203 \det+
204                               List of foreign tables
205  Schema | Table |  Server   |              FDW options              | Description 
206 --------+-------+-----------+---------------------------------------+-------------
207  public | ft1   | loopback  | (schema_name 'S 1', table_name 'T 1') | 
208  public | ft2   | loopback  | (schema_name 'S 1', table_name 'T 1') | 
209  public | ft4   | loopback  | (schema_name 'S 1', table_name 'T 3') | 
210  public | ft5   | loopback  | (schema_name 'S 1', table_name 'T 4') | 
211  public | ft6   | loopback2 | (schema_name 'S 1', table_name 'T 4') | 
212  public | ft7   | loopback3 | (schema_name 'S 1', table_name 'T 4') | 
213 (6 rows)
215 -- Test that alteration of server options causes reconnection
216 -- Remote's errors might be non-English, so hide them to ensure stable results
217 \set VERBOSITY terse
218 SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work
219   c3   |              c4              
220 -------+------------------------------
221  00001 | Fri Jan 02 00:00:00 1970 PST
222 (1 row)
224 ALTER SERVER loopback OPTIONS (SET dbname 'no such database');
225 SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should fail
226 ERROR:  could not connect to server "loopback"
227 DO $d$
228     BEGIN
229         EXECUTE $$ALTER SERVER loopback
230             OPTIONS (SET dbname '$$||current_database()||$$')$$;
231     END;
232 $d$;
233 SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
234   c3   |              c4              
235 -------+------------------------------
236  00001 | Fri Jan 02 00:00:00 1970 PST
237 (1 row)
239 -- Test that alteration of user mapping options causes reconnection
240 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback
241   OPTIONS (ADD user 'no such user');
242 SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should fail
243 ERROR:  could not connect to server "loopback"
244 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback
245   OPTIONS (DROP user);
246 SELECT c3, c4 FROM ft1 ORDER BY c3, c1 LIMIT 1;  -- should work again
247   c3   |              c4              
248 -------+------------------------------
249  00001 | Fri Jan 02 00:00:00 1970 PST
250 (1 row)
252 \set VERBOSITY default
253 -- Now we should be able to run ANALYZE.
254 -- To exercise multiple code paths, we use local stats on ft1
255 -- and remote-estimate mode on ft2.
256 ANALYZE ft1;
257 ALTER FOREIGN TABLE ft2 OPTIONS (use_remote_estimate 'true');
258 -- ===================================================================
259 -- test error case for create publication on foreign table
260 -- ===================================================================
261 CREATE PUBLICATION testpub_ftbl FOR TABLE ft1;  -- should fail
262 ERROR:  cannot add relation "ft1" to publication
263 DETAIL:  This operation is not supported for foreign tables.
264 -- ===================================================================
265 -- simple queries
266 -- ===================================================================
267 -- single table without alias
268 EXPLAIN (COSTS OFF) SELECT * FROM ft1 ORDER BY c3, c1 OFFSET 100 LIMIT 10;
269      QUERY PLAN      
270 ---------------------
271  Foreign Scan on ft1
272 (1 row)
274 SELECT * FROM ft1 ORDER BY c3, c1 OFFSET 100 LIMIT 10;
275  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
276 -----+----+-------+------------------------------+--------------------------+----+------------+-----
277  101 |  1 | 00101 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
278  102 |  2 | 00102 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo
279  103 |  3 | 00103 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo
280  104 |  4 | 00104 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4  | 4          | foo
281  105 |  5 | 00105 | Tue Jan 06 00:00:00 1970 PST | Tue Jan 06 00:00:00 1970 | 5  | 5          | foo
282  106 |  6 | 00106 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
283  107 |  7 | 00107 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
284  108 |  8 | 00108 | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
285  109 |  9 | 00109 | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9  | 9          | foo
286  110 |  0 | 00110 | Sun Jan 11 00:00:00 1970 PST | Sun Jan 11 00:00:00 1970 | 0  | 0          | foo
287 (10 rows)
289 -- single table with alias - also test that tableoid sort is not pushed to remote side
290 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 ORDER BY t1.c3, t1.c1, t1.tableoid OFFSET 100 LIMIT 10;
291                                      QUERY PLAN                                      
292 -------------------------------------------------------------------------------------
293  Limit
294    Output: c1, c2, c3, c4, c5, c6, c7, c8, tableoid
295    ->  Sort
296          Output: c1, c2, c3, c4, c5, c6, c7, c8, tableoid
297          Sort Key: t1.c3, t1.c1, t1.tableoid
298          ->  Foreign Scan on public.ft1 t1
299                Output: c1, c2, c3, c4, c5, c6, c7, c8, tableoid
300                Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
301 (8 rows)
303 SELECT * FROM ft1 t1 ORDER BY t1.c3, t1.c1, t1.tableoid OFFSET 100 LIMIT 10;
304  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
305 -----+----+-------+------------------------------+--------------------------+----+------------+-----
306  101 |  1 | 00101 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
307  102 |  2 | 00102 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo
308  103 |  3 | 00103 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo
309  104 |  4 | 00104 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4  | 4          | foo
310  105 |  5 | 00105 | Tue Jan 06 00:00:00 1970 PST | Tue Jan 06 00:00:00 1970 | 5  | 5          | foo
311  106 |  6 | 00106 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
312  107 |  7 | 00107 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
313  108 |  8 | 00108 | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
314  109 |  9 | 00109 | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9  | 9          | foo
315  110 |  0 | 00110 | Sun Jan 11 00:00:00 1970 PST | Sun Jan 11 00:00:00 1970 | 0  | 0          | foo
316 (10 rows)
318 -- whole-row reference
319 EXPLAIN (VERBOSE, COSTS OFF) SELECT t1 FROM ft1 t1 ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
320                                                                           QUERY PLAN                                                                          
321 --------------------------------------------------------------------------------------------------------------------------------------------------------------
322  Foreign Scan on public.ft1 t1
323    Output: t1.*, c3, c1
324    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY c3 ASC NULLS LAST, "C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 100::bigint
325 (3 rows)
327 SELECT t1 FROM ft1 t1 ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
328                                              t1                                             
329 --------------------------------------------------------------------------------------------
330  (101,1,00101,"Fri Jan 02 00:00:00 1970 PST","Fri Jan 02 00:00:00 1970",1,"1         ",foo)
331  (102,2,00102,"Sat Jan 03 00:00:00 1970 PST","Sat Jan 03 00:00:00 1970",2,"2         ",foo)
332  (103,3,00103,"Sun Jan 04 00:00:00 1970 PST","Sun Jan 04 00:00:00 1970",3,"3         ",foo)
333  (104,4,00104,"Mon Jan 05 00:00:00 1970 PST","Mon Jan 05 00:00:00 1970",4,"4         ",foo)
334  (105,5,00105,"Tue Jan 06 00:00:00 1970 PST","Tue Jan 06 00:00:00 1970",5,"5         ",foo)
335  (106,6,00106,"Wed Jan 07 00:00:00 1970 PST","Wed Jan 07 00:00:00 1970",6,"6         ",foo)
336  (107,7,00107,"Thu Jan 08 00:00:00 1970 PST","Thu Jan 08 00:00:00 1970",7,"7         ",foo)
337  (108,8,00108,"Fri Jan 09 00:00:00 1970 PST","Fri Jan 09 00:00:00 1970",8,"8         ",foo)
338  (109,9,00109,"Sat Jan 10 00:00:00 1970 PST","Sat Jan 10 00:00:00 1970",9,"9         ",foo)
339  (110,0,00110,"Sun Jan 11 00:00:00 1970 PST","Sun Jan 11 00:00:00 1970",0,"0         ",foo)
340 (10 rows)
342 -- empty result
343 SELECT * FROM ft1 WHERE false;
344  c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 
345 ----+----+----+----+----+----+----+----
346 (0 rows)
348 -- with WHERE clause
349 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.c1 = 101 AND t1.c6 = '1' AND t1.c7 >= '1';
350                                                             QUERY PLAN                                                            
351 ----------------------------------------------------------------------------------------------------------------------------------
352  Foreign Scan on public.ft1 t1
353    Output: c1, c2, c3, c4, c5, c6, c7, c8
354    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c7 >= '1')) AND (("C 1" = 101)) AND ((c6 = '1'))
355 (3 rows)
357 SELECT * FROM ft1 t1 WHERE t1.c1 = 101 AND t1.c6 = '1' AND t1.c7 >= '1';
358  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
359 -----+----+-------+------------------------------+--------------------------+----+------------+-----
360  101 |  1 | 00101 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
361 (1 row)
363 -- with FOR UPDATE/SHARE
364 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = 101 FOR UPDATE;
365                                                 QUERY PLAN                                                
366 ----------------------------------------------------------------------------------------------------------
367  Foreign Scan on public.ft1 t1
368    Output: c1, c2, c3, c4, c5, c6, c7, c8, t1.*
369    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 101)) FOR UPDATE
370 (3 rows)
372 SELECT * FROM ft1 t1 WHERE c1 = 101 FOR UPDATE;
373  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
374 -----+----+-------+------------------------------+--------------------------+----+------------+-----
375  101 |  1 | 00101 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
376 (1 row)
378 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = 102 FOR SHARE;
379                                                QUERY PLAN                                                
380 ---------------------------------------------------------------------------------------------------------
381  Foreign Scan on public.ft1 t1
382    Output: c1, c2, c3, c4, c5, c6, c7, c8, t1.*
383    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 102)) FOR SHARE
384 (3 rows)
386 SELECT * FROM ft1 t1 WHERE c1 = 102 FOR SHARE;
387  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
388 -----+----+-------+------------------------------+--------------------------+----+------------+-----
389  102 |  2 | 00102 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo
390 (1 row)
392 -- aggregate
393 SELECT COUNT(*) FROM ft1 t1;
394  count 
395 -------
396   1000
397 (1 row)
399 -- subquery
400 SELECT * FROM ft1 t1 WHERE t1.c3 IN (SELECT c3 FROM ft2 t2 WHERE c1 <= 10) ORDER BY c1;
401  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
402 ----+----+-------+------------------------------+--------------------------+----+------------+-----
403   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
404   2 |  2 | 00002 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo
405   3 |  3 | 00003 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo
406   4 |  4 | 00004 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4  | 4          | foo
407   5 |  5 | 00005 | Tue Jan 06 00:00:00 1970 PST | Tue Jan 06 00:00:00 1970 | 5  | 5          | foo
408   6 |  6 | 00006 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
409   7 |  7 | 00007 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
410   8 |  8 | 00008 | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
411   9 |  9 | 00009 | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9  | 9          | foo
412  10 |  0 | 00010 | Sun Jan 11 00:00:00 1970 PST | Sun Jan 11 00:00:00 1970 | 0  | 0          | foo
413 (10 rows)
415 -- subquery+MAX
416 SELECT * FROM ft1 t1 WHERE t1.c3 = (SELECT MAX(c3) FROM ft2 t2) ORDER BY c1;
417   c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
418 ------+----+-------+------------------------------+--------------------------+----+------------+-----
419  1000 |  0 | 01000 | Thu Jan 01 00:00:00 1970 PST | Thu Jan 01 00:00:00 1970 | 0  | 0          | foo
420 (1 row)
422 -- used in CTE
423 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;
424  c1 | c2 |  c3   |              c4              
425 ----+----+-------+------------------------------
426   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST
427   2 |  2 | 00002 | Sat Jan 03 00:00:00 1970 PST
428   3 |  3 | 00003 | Sun Jan 04 00:00:00 1970 PST
429   4 |  4 | 00004 | Mon Jan 05 00:00:00 1970 PST
430   5 |  5 | 00005 | Tue Jan 06 00:00:00 1970 PST
431   6 |  6 | 00006 | Wed Jan 07 00:00:00 1970 PST
432   7 |  7 | 00007 | Thu Jan 08 00:00:00 1970 PST
433   8 |  8 | 00008 | Fri Jan 09 00:00:00 1970 PST
434   9 |  9 | 00009 | Sat Jan 10 00:00:00 1970 PST
435  10 |  0 | 00010 | Sun Jan 11 00:00:00 1970 PST
436 (10 rows)
438 -- fixed values
439 SELECT 'fixed', NULL FROM ft1 t1 WHERE c1 = 1;
440  ?column? | ?column? 
441 ----------+----------
442  fixed    | 
443 (1 row)
445 -- Test forcing the remote server to produce sorted data for a merge join.
446 SET enable_hashjoin TO false;
447 SET enable_nestloop TO false;
448 -- inner join; expressions in the clauses appear in the equivalence class list
449 EXPLAIN (VERBOSE, COSTS OFF)
450         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;
451                                       QUERY PLAN                                       
452 ---------------------------------------------------------------------------------------
453  Limit
454    Output: t1.c1, t2."C 1"
455    ->  Merge Join
456          Output: t1.c1, t2."C 1"
457          Inner Unique: true
458          Merge Cond: (t1.c1 = t2."C 1")
459          ->  Foreign Scan on public.ft2 t1
460                Output: t1.c1
461                Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
462          ->  Index Only Scan using t1_pkey on "S 1"."T 1" t2
463                Output: t2."C 1"
464 (11 rows)
466 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;
467  c1  | C 1 
468 -----+-----
469  101 | 101
470  102 | 102
471  103 | 103
472  104 | 104
473  105 | 105
474  106 | 106
475  107 | 107
476  108 | 108
477  109 | 109
478  110 | 110
479 (10 rows)
481 -- outer join; expressions in the clauses do not appear in equivalence class
482 -- list but no output change as compared to the previous query
483 EXPLAIN (VERBOSE, COSTS OFF)
484         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;
485                                       QUERY PLAN                                       
486 ---------------------------------------------------------------------------------------
487  Limit
488    Output: t1.c1, t2."C 1"
489    ->  Merge Left Join
490          Output: t1.c1, t2."C 1"
491          Inner Unique: true
492          Merge Cond: (t1.c1 = t2."C 1")
493          ->  Foreign Scan on public.ft2 t1
494                Output: t1.c1
495                Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
496          ->  Index Only Scan using t1_pkey on "S 1"."T 1" t2
497                Output: t2."C 1"
498 (11 rows)
500 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;
501  c1  | C 1 
502 -----+-----
503  101 | 101
504  102 | 102
505  103 | 103
506  104 | 104
507  105 | 105
508  106 | 106
509  107 | 107
510  108 | 108
511  109 | 109
512  110 | 110
513 (10 rows)
515 -- A join between local table and foreign join. ORDER BY clause is added to the
516 -- foreign join so that the local table can be joined using merge join strategy.
517 EXPLAIN (VERBOSE, COSTS OFF)
518         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;
519                                                                        QUERY PLAN                                                                        
520 ---------------------------------------------------------------------------------------------------------------------------------------------------------
521  Limit
522    Output: t1."C 1"
523    ->  Merge Right Join
524          Output: t1."C 1"
525          Inner Unique: true
526          Merge Cond: (t3.c1 = t1."C 1")
527          ->  Foreign Scan
528                Output: t3.c1
529                Relations: (public.ft1 t2) INNER JOIN (public.ft2 t3)
530                Remote SQL: SELECT r3."C 1" FROM ("S 1"."T 1" r2 INNER JOIN "S 1"."T 1" r3 ON (((r3."C 1" = r2."C 1")))) ORDER BY r2."C 1" ASC NULLS LAST
531          ->  Index Only Scan using t1_pkey on "S 1"."T 1" t1
532                Output: t1."C 1"
533 (12 rows)
535 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;
536  C 1 
537 -----
538  101
539  102
540  103
541  104
542  105
543  106
544  107
545  108
546  109
547  110
548 (10 rows)
550 -- Test similar to above, except that the full join prevents any equivalence
551 -- classes from being merged. This produces single relation equivalence classes
552 -- included in join restrictions.
553 EXPLAIN (VERBOSE, COSTS OFF)
554         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;
555                                                                             QUERY PLAN                                                                            
556 ------------------------------------------------------------------------------------------------------------------------------------------------------------------
557  Limit
558    Output: t1."C 1", t2.c1, t3.c1
559    ->  Merge Right Join
560          Output: t1."C 1", t2.c1, t3.c1
561          Inner Unique: true
562          Merge Cond: (t3.c1 = t1."C 1")
563          ->  Foreign Scan
564                Output: t3.c1, t2.c1
565                Relations: (public.ft2 t3) LEFT JOIN (public.ft1 t2)
566                Remote SQL: SELECT r3."C 1", r2."C 1" FROM ("S 1"."T 1" r3 LEFT JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r3."C 1")))) ORDER BY r3."C 1" ASC NULLS LAST
567          ->  Index Only Scan using t1_pkey on "S 1"."T 1" t1
568                Output: t1."C 1"
569 (12 rows)
571 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;
572  C 1 | c1  | c1  
573 -----+-----+-----
574  101 | 101 | 101
575  102 | 102 | 102
576  103 | 103 | 103
577  104 | 104 | 104
578  105 | 105 | 105
579  106 | 106 | 106
580  107 | 107 | 107
581  108 | 108 | 108
582  109 | 109 | 109
583  110 | 110 | 110
584 (10 rows)
586 -- Test similar to above with all full outer joins
587 EXPLAIN (VERBOSE, COSTS OFF)
588         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;
589                                                                             QUERY PLAN                                                                            
590 ------------------------------------------------------------------------------------------------------------------------------------------------------------------
591  Limit
592    Output: t1."C 1", t2.c1, t3.c1
593    ->  Merge Full Join
594          Output: t1."C 1", t2.c1, t3.c1
595          Inner Unique: true
596          Merge Cond: (t3.c1 = t1."C 1")
597          ->  Foreign Scan
598                Output: t2.c1, t3.c1
599                Relations: (public.ft1 t2) FULL JOIN (public.ft2 t3)
600                Remote SQL: SELECT r2."C 1", r3."C 1" FROM ("S 1"."T 1" r2 FULL JOIN "S 1"."T 1" r3 ON (((r2."C 1" = r3."C 1")))) ORDER BY r3."C 1" ASC NULLS LAST
601          ->  Index Only Scan using t1_pkey on "S 1"."T 1" t1
602                Output: t1."C 1"
603 (12 rows)
605 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;
606  C 1 | c1  | c1  
607 -----+-----+-----
608  101 | 101 | 101
609  102 | 102 | 102
610  103 | 103 | 103
611  104 | 104 | 104
612  105 | 105 | 105
613  106 | 106 | 106
614  107 | 107 | 107
615  108 | 108 | 108
616  109 | 109 | 109
617  110 | 110 | 110
618 (10 rows)
620 RESET enable_hashjoin;
621 RESET enable_nestloop;
622 -- Test executing assertion in estimate_path_cost_size() that makes sure that
623 -- retrieved_rows for foreign rel re-used to cost pre-sorted foreign paths is
624 -- a sensible value even when the rel has tuples=0
625 CREATE TABLE loct_empty (c1 int NOT NULL, c2 text);
626 CREATE FOREIGN TABLE ft_empty (c1 int NOT NULL, c2 text)
627   SERVER loopback OPTIONS (table_name 'loct_empty');
628 INSERT INTO loct_empty
629   SELECT id, 'AAA' || to_char(id, 'FM000') FROM generate_series(1, 100) id;
630 DELETE FROM loct_empty;
631 ANALYZE ft_empty;
632 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft_empty ORDER BY c1;
633                                   QUERY PLAN                                   
634 -------------------------------------------------------------------------------
635  Foreign Scan on public.ft_empty
636    Output: c1, c2
637    Remote SQL: SELECT c1, c2 FROM public.loct_empty ORDER BY c1 ASC NULLS LAST
638 (3 rows)
640 -- ===================================================================
641 -- WHERE with remotely-executable conditions
642 -- ===================================================================
643 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.c1 = 1;         -- Var, OpExpr(b), Const
644                                          QUERY PLAN                                          
645 ---------------------------------------------------------------------------------------------
646  Foreign Scan on public.ft1 t1
647    Output: c1, c2, c3, c4, c5, c6, c7, c8
648    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
649 (3 rows)
651 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE t1.c1 = 100 AND t1.c2 = 0; -- BoolExpr
652                                                   QUERY PLAN                                                  
653 --------------------------------------------------------------------------------------------------------------
654  Foreign Scan on public.ft1 t1
655    Output: c1, c2, c3, c4, c5, c6, c7, c8
656    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 100)) AND ((c2 = 0))
657 (3 rows)
659 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c3 IS NULL;        -- NullTest
660                                           QUERY PLAN                                          
661 ----------------------------------------------------------------------------------------------
662  Foreign Scan on public.ft1 t1
663    Output: c1, c2, c3, c4, c5, c6, c7, c8
664    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c3 IS NULL))
665 (3 rows)
667 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c3 IS NOT NULL;    -- NullTest
668                                             QUERY PLAN                                            
669 --------------------------------------------------------------------------------------------------
670  Foreign Scan on public.ft1 t1
671    Output: c1, c2, c3, c4, c5, c6, c7, c8
672    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c3 IS NOT NULL))
673 (3 rows)
675 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE round(abs(c1), 0) = 1; -- FuncExpr
676                                                      QUERY PLAN                                                      
677 ---------------------------------------------------------------------------------------------------------------------
678  Foreign Scan on public.ft1 t1
679    Output: c1, c2, c3, c4, c5, c6, c7, c8
680    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((round(abs("C 1"), 0) = 1::numeric))
681 (3 rows)
683 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = -c1;          -- OpExpr(l)
684                                              QUERY PLAN                                              
685 -----------------------------------------------------------------------------------------------------
686  Foreign Scan on public.ft1 t1
687    Output: c1, c2, c3, c4, c5, c6, c7, c8
688    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = (- "C 1")))
689 (3 rows)
691 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE (c1 IS NOT NULL) IS DISTINCT FROM (c1 IS NOT NULL); -- DistinctExpr
692                                                                  QUERY PLAN                                                                 
693 --------------------------------------------------------------------------------------------------------------------------------------------
694  Foreign Scan on public.ft1 t1
695    Output: c1, c2, c3, c4, c5, c6, c7, c8
696    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((("C 1" IS NOT NULL) IS DISTINCT FROM ("C 1" IS NOT NULL)))
697 (3 rows)
699 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = ANY(ARRAY[c2, 1, c1 + 0]); -- ScalarArrayOpExpr
700                                                         QUERY PLAN                                                         
701 ---------------------------------------------------------------------------------------------------------------------------
702  Foreign Scan on public.ft1 t1
703    Output: c1, c2, c3, c4, c5, c6, c7, c8
704    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = ANY (ARRAY[c2, 1, ("C 1" + 0)])))
705 (3 rows)
707 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c1 = (ARRAY[c1,c2,3])[1]; -- SubscriptingRef
708                                                       QUERY PLAN                                                      
709 ----------------------------------------------------------------------------------------------------------------------
710  Foreign Scan on public.ft1 t1
711    Output: c1, c2, c3, c4, c5, c6, c7, c8
712    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = ((ARRAY["C 1", c2, 3])[1])))
713 (3 rows)
715 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c6 = E'foo''s\\bar';  -- check special chars
716                                               QUERY PLAN                                               
717 -------------------------------------------------------------------------------------------------------
718  Foreign Scan on public.ft1 t1
719    Output: c1, c2, c3, c4, c5, c6, c7, c8
720    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c6 = E'foo''s\\bar'))
721 (3 rows)
723 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 t1 WHERE c8 = 'foo';  -- can't be sent to remote
724                                QUERY PLAN                                
725 -------------------------------------------------------------------------
726  Foreign Scan on public.ft1 t1
727    Output: c1, c2, c3, c4, c5, c6, c7, c8
728    Filter: (t1.c8 = 'foo'::user_enum)
729    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
730 (4 rows)
732 -- parameterized remote path for foreign table
733 EXPLAIN (VERBOSE, COSTS OFF)
734   SELECT * FROM "S 1"."T 1" a, ft2 b WHERE a."C 1" = 47 AND b.c1 = a.c2;
735                                                  QUERY PLAN                                                  
736 -------------------------------------------------------------------------------------------------------------
737  Nested Loop
738    Output: a."C 1", a.c2, a.c3, a.c4, a.c5, a.c6, a.c7, a.c8, b.c1, b.c2, b.c3, b.c4, b.c5, b.c6, b.c7, b.c8
739    ->  Index Scan using t1_pkey on "S 1"."T 1" a
740          Output: a."C 1", a.c2, a.c3, a.c4, a.c5, a.c6, a.c7, a.c8
741          Index Cond: (a."C 1" = 47)
742    ->  Foreign Scan on public.ft2 b
743          Output: b.c1, b.c2, b.c3, b.c4, b.c5, b.c6, b.c7, b.c8
744          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = $1::integer))
745 (8 rows)
747 SELECT * FROM "S 1"."T 1" a, ft2 b WHERE a."C 1" = 47 AND b.c1 = a.c2;
748  C 1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  | c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
749 -----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+-------+------------------------------+--------------------------+----+------------+-----
750   47 |  7 | 00047 | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo |  7 |  7 | 00007 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
751 (1 row)
753 -- check both safe and unsafe join conditions
754 EXPLAIN (VERBOSE, COSTS OFF)
755   SELECT * FROM ft2 a, ft2 b
756   WHERE a.c2 = 6 AND b.c1 = a.c1 AND a.c8 = 'foo' AND b.c7 = upper(a.c7);
757                                                  QUERY PLAN                                                  
758 -------------------------------------------------------------------------------------------------------------
759  Nested Loop
760    Output: a.c1, a.c2, a.c3, a.c4, a.c5, a.c6, a.c7, a.c8, b.c1, b.c2, b.c3, b.c4, b.c5, b.c6, b.c7, b.c8
761    ->  Foreign Scan on public.ft2 a
762          Output: a.c1, a.c2, a.c3, a.c4, a.c5, a.c6, a.c7, a.c8
763          Filter: (a.c8 = 'foo'::user_enum)
764          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c2 = 6))
765    ->  Foreign Scan on public.ft2 b
766          Output: b.c1, b.c2, b.c3, b.c4, b.c5, b.c6, b.c7, b.c8
767          Filter: ((b.c7)::text = upper((a.c7)::text))
768          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (($1::integer = "C 1"))
769 (10 rows)
771 SELECT * FROM ft2 a, ft2 b
772 WHERE a.c2 = 6 AND b.c1 = a.c1 AND a.c8 = 'foo' AND b.c7 = upper(a.c7);
773  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  | c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
774 -----+----+-------+------------------------------+--------------------------+----+------------+-----+-----+----+-------+------------------------------+--------------------------+----+------------+-----
775    6 |  6 | 00006 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |   6 |  6 | 00006 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
776   16 |  6 | 00016 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo |  16 |  6 | 00016 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
777   26 |  6 | 00026 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo |  26 |  6 | 00026 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo
778   36 |  6 | 00036 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo |  36 |  6 | 00036 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo
779   46 |  6 | 00046 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo |  46 |  6 | 00046 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo
780   56 |  6 | 00056 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo |  56 |  6 | 00056 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo
781   66 |  6 | 00066 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo |  66 |  6 | 00066 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo
782   76 |  6 | 00076 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo |  76 |  6 | 00076 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo
783   86 |  6 | 00086 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo |  86 |  6 | 00086 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo
784   96 |  6 | 00096 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo |  96 |  6 | 00096 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo
785  106 |  6 | 00106 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo | 106 |  6 | 00106 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
786  116 |  6 | 00116 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo | 116 |  6 | 00116 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
787  126 |  6 | 00126 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo | 126 |  6 | 00126 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo
788  136 |  6 | 00136 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo | 136 |  6 | 00136 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo
789  146 |  6 | 00146 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo | 146 |  6 | 00146 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo
790  156 |  6 | 00156 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo | 156 |  6 | 00156 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo
791  166 |  6 | 00166 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo | 166 |  6 | 00166 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo
792  176 |  6 | 00176 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo | 176 |  6 | 00176 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo
793  186 |  6 | 00186 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo | 186 |  6 | 00186 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo
794  196 |  6 | 00196 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo | 196 |  6 | 00196 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo
795  206 |  6 | 00206 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo | 206 |  6 | 00206 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
796  216 |  6 | 00216 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo | 216 |  6 | 00216 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
797  226 |  6 | 00226 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo | 226 |  6 | 00226 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo
798  236 |  6 | 00236 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo | 236 |  6 | 00236 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo
799  246 |  6 | 00246 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo | 246 |  6 | 00246 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo
800  256 |  6 | 00256 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo | 256 |  6 | 00256 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo
801  266 |  6 | 00266 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo | 266 |  6 | 00266 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo
802  276 |  6 | 00276 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo | 276 |  6 | 00276 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo
803  286 |  6 | 00286 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo | 286 |  6 | 00286 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo
804  296 |  6 | 00296 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo | 296 |  6 | 00296 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo
805  306 |  6 | 00306 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo | 306 |  6 | 00306 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
806  316 |  6 | 00316 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo | 316 |  6 | 00316 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
807  326 |  6 | 00326 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo | 326 |  6 | 00326 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo
808  336 |  6 | 00336 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo | 336 |  6 | 00336 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo
809  346 |  6 | 00346 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo | 346 |  6 | 00346 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo
810  356 |  6 | 00356 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo | 356 |  6 | 00356 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo
811  366 |  6 | 00366 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo | 366 |  6 | 00366 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo
812  376 |  6 | 00376 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo | 376 |  6 | 00376 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo
813  386 |  6 | 00386 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo | 386 |  6 | 00386 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo
814  396 |  6 | 00396 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo | 396 |  6 | 00396 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo
815  406 |  6 | 00406 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo | 406 |  6 | 00406 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
816  416 |  6 | 00416 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo | 416 |  6 | 00416 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
817  426 |  6 | 00426 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo | 426 |  6 | 00426 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo
818  436 |  6 | 00436 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo | 436 |  6 | 00436 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo
819  446 |  6 | 00446 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo | 446 |  6 | 00446 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo
820  456 |  6 | 00456 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo | 456 |  6 | 00456 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo
821  466 |  6 | 00466 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo | 466 |  6 | 00466 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo
822  476 |  6 | 00476 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo | 476 |  6 | 00476 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo
823  486 |  6 | 00486 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo | 486 |  6 | 00486 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo
824  496 |  6 | 00496 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo | 496 |  6 | 00496 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo
825  506 |  6 | 00506 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo | 506 |  6 | 00506 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
826  516 |  6 | 00516 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo | 516 |  6 | 00516 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
827  526 |  6 | 00526 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo | 526 |  6 | 00526 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo
828  536 |  6 | 00536 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo | 536 |  6 | 00536 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo
829  546 |  6 | 00546 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo | 546 |  6 | 00546 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo
830  556 |  6 | 00556 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo | 556 |  6 | 00556 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo
831  566 |  6 | 00566 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo | 566 |  6 | 00566 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo
832  576 |  6 | 00576 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo | 576 |  6 | 00576 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo
833  586 |  6 | 00586 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo | 586 |  6 | 00586 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo
834  596 |  6 | 00596 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo | 596 |  6 | 00596 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo
835  606 |  6 | 00606 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo | 606 |  6 | 00606 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
836  616 |  6 | 00616 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo | 616 |  6 | 00616 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
837  626 |  6 | 00626 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo | 626 |  6 | 00626 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo
838  636 |  6 | 00636 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo | 636 |  6 | 00636 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo
839  646 |  6 | 00646 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo | 646 |  6 | 00646 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo
840  656 |  6 | 00656 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo | 656 |  6 | 00656 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo
841  666 |  6 | 00666 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo | 666 |  6 | 00666 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo
842  676 |  6 | 00676 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo | 676 |  6 | 00676 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo
843  686 |  6 | 00686 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo | 686 |  6 | 00686 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo
844  696 |  6 | 00696 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo | 696 |  6 | 00696 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo
845  706 |  6 | 00706 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo | 706 |  6 | 00706 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
846  716 |  6 | 00716 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo | 716 |  6 | 00716 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
847  726 |  6 | 00726 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo | 726 |  6 | 00726 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo
848  736 |  6 | 00736 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo | 736 |  6 | 00736 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo
849  746 |  6 | 00746 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo | 746 |  6 | 00746 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo
850  756 |  6 | 00756 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo | 756 |  6 | 00756 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo
851  766 |  6 | 00766 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo | 766 |  6 | 00766 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo
852  776 |  6 | 00776 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo | 776 |  6 | 00776 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo
853  786 |  6 | 00786 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo | 786 |  6 | 00786 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo
854  796 |  6 | 00796 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo | 796 |  6 | 00796 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo
855  806 |  6 | 00806 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo | 806 |  6 | 00806 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
856  816 |  6 | 00816 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo | 816 |  6 | 00816 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
857  826 |  6 | 00826 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo | 826 |  6 | 00826 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo
858  836 |  6 | 00836 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo | 836 |  6 | 00836 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo
859  846 |  6 | 00846 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo | 846 |  6 | 00846 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo
860  856 |  6 | 00856 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo | 856 |  6 | 00856 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo
861  866 |  6 | 00866 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo | 866 |  6 | 00866 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo
862  876 |  6 | 00876 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo | 876 |  6 | 00876 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo
863  886 |  6 | 00886 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo | 886 |  6 | 00886 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo
864  896 |  6 | 00896 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo | 896 |  6 | 00896 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo
865  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo | 906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
866  916 |  6 | 00916 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo | 916 |  6 | 00916 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
867  926 |  6 | 00926 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo | 926 |  6 | 00926 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo
868  936 |  6 | 00936 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo | 936 |  6 | 00936 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo
869  946 |  6 | 00946 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo | 946 |  6 | 00946 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo
870  956 |  6 | 00956 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo | 956 |  6 | 00956 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo
871  966 |  6 | 00966 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo | 966 |  6 | 00966 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo
872  976 |  6 | 00976 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo | 976 |  6 | 00976 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo
873  986 |  6 | 00986 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo | 986 |  6 | 00986 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo
874  996 |  6 | 00996 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo | 996 |  6 | 00996 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo
875 (100 rows)
877 -- bug before 9.3.5 due to sloppy handling of remote-estimate parameters
878 SELECT * FROM ft1 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft2 WHERE c1 < 5));
879  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
880 ----+----+-------+------------------------------+--------------------------+----+------------+-----
881   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
882   2 |  2 | 00002 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo
883   3 |  3 | 00003 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo
884   4 |  4 | 00004 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4  | 4          | foo
885 (4 rows)
887 SELECT * FROM ft2 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft1 WHERE c1 < 5));
888  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
889 ----+----+-------+------------------------------+--------------------------+----+------------+-----
890   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
891   2 |  2 | 00002 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo
892   3 |  3 | 00003 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo
893   4 |  4 | 00004 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4  | 4          | foo
894 (4 rows)
896 -- user-defined operator/function
897 CREATE FUNCTION postgres_fdw_abs(int) RETURNS int AS $$
898 BEGIN
899 RETURN abs($1);
901 $$ LANGUAGE plpgsql IMMUTABLE;
902 CREATE OPERATOR === (
903     LEFTARG = int,
904     RIGHTARG = int,
905     PROCEDURE = int4eq,
906     COMMUTATOR = ===
908 -- built-in operators and functions can be shipped for remote execution
909 EXPLAIN (VERBOSE, COSTS OFF)
910   SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = abs(t1.c2);
911                                 QUERY PLAN                                 
912 ---------------------------------------------------------------------------
913  Foreign Scan
914    Output: (count(c3))
915    Relations: Aggregate on (public.ft1 t1)
916    Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" = abs(c2)))
917 (4 rows)
919 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = abs(t1.c2);
920  count 
921 -------
922      9
923 (1 row)
925 EXPLAIN (VERBOSE, COSTS OFF)
926   SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = t1.c2;
927                               QUERY PLAN                              
928 ----------------------------------------------------------------------
929  Foreign Scan
930    Output: (count(c3))
931    Relations: Aggregate on (public.ft1 t1)
932    Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" = c2))
933 (4 rows)
935 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = t1.c2;
936  count 
937 -------
938      9
939 (1 row)
941 -- by default, user-defined ones cannot
942 EXPLAIN (VERBOSE, COSTS OFF)
943   SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2);
944                         QUERY PLAN                         
945 -----------------------------------------------------------
946  Aggregate
947    Output: count(c3)
948    ->  Foreign Scan on public.ft1 t1
949          Output: c3
950          Filter: (t1.c1 = postgres_fdw_abs(t1.c2))
951          Remote SQL: SELECT "C 1", c2, c3 FROM "S 1"."T 1"
952 (6 rows)
954 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2);
955  count 
956 -------
957      9
958 (1 row)
960 EXPLAIN (VERBOSE, COSTS OFF)
961   SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2;
962                         QUERY PLAN                         
963 -----------------------------------------------------------
964  Aggregate
965    Output: count(c3)
966    ->  Foreign Scan on public.ft1 t1
967          Output: c3
968          Filter: (t1.c1 === t1.c2)
969          Remote SQL: SELECT "C 1", c2, c3 FROM "S 1"."T 1"
970 (6 rows)
972 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2;
973  count 
974 -------
975      9
976 (1 row)
978 -- ORDER BY can be shipped, though
979 EXPLAIN (VERBOSE, COSTS OFF)
980   SELECT * FROM ft1 t1 WHERE t1.c1 === t1.c2 order by t1.c2 limit 1;
981                                                 QUERY PLAN                                                
982 ----------------------------------------------------------------------------------------------------------
983  Limit
984    Output: c1, c2, c3, c4, c5, c6, c7, c8
985    ->  Foreign Scan on public.ft1 t1
986          Output: c1, c2, c3, c4, c5, c6, c7, c8
987          Filter: (t1.c1 === t1.c2)
988          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY c2 ASC NULLS LAST
989 (6 rows)
991 SELECT * FROM ft1 t1 WHERE t1.c1 === t1.c2 order by t1.c2 limit 1;
992  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
993 ----+----+-------+------------------------------+--------------------------+----+------------+-----
994   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
995 (1 row)
997 -- but let's put them in an extension ...
998 ALTER EXTENSION postgres_fdw ADD FUNCTION postgres_fdw_abs(int);
999 ALTER EXTENSION postgres_fdw ADD OPERATOR === (int, int);
1000 ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
1001 -- ... now they can be shipped
1002 EXPLAIN (VERBOSE, COSTS OFF)
1003   SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2);
1004                                           QUERY PLAN                                           
1005 -----------------------------------------------------------------------------------------------
1006  Foreign Scan
1007    Output: (count(c3))
1008    Relations: Aggregate on (public.ft1 t1)
1009    Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" = public.postgres_fdw_abs(c2)))
1010 (4 rows)
1012 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 = postgres_fdw_abs(t1.c2);
1013  count 
1014 -------
1015      9
1016 (1 row)
1018 EXPLAIN (VERBOSE, COSTS OFF)
1019   SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2;
1020                                        QUERY PLAN                                        
1021 -----------------------------------------------------------------------------------------
1022  Foreign Scan
1023    Output: (count(c3))
1024    Relations: Aggregate on (public.ft1 t1)
1025    Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" OPERATOR(public.===) c2))
1026 (4 rows)
1028 SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2;
1029  count 
1030 -------
1031      9
1032 (1 row)
1034 -- and both ORDER BY and LIMIT can be shipped
1035 EXPLAIN (VERBOSE, COSTS OFF)
1036   SELECT * FROM ft1 t1 WHERE t1.c1 === t1.c2 order by t1.c2 limit 1;
1037                                                                          QUERY PLAN                                                                         
1038 ------------------------------------------------------------------------------------------------------------------------------------------------------------
1039  Foreign Scan on public.ft1 t1
1040    Output: c1, c2, c3, c4, c5, c6, c7, c8
1041    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" OPERATOR(public.===) c2)) ORDER BY c2 ASC NULLS LAST LIMIT 1::bigint
1042 (3 rows)
1044 SELECT * FROM ft1 t1 WHERE t1.c1 === t1.c2 order by t1.c2 limit 1;
1045  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
1046 ----+----+-------+------------------------------+--------------------------+----+------------+-----
1047   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
1048 (1 row)
1050 -- Test CASE pushdown
1051 EXPLAIN (VERBOSE, COSTS OFF)
1052 SELECT c1,c2,c3 FROM ft2 WHERE CASE WHEN c1 > 990 THEN c1 END < 1000 ORDER BY c1;
1053                                                                            QUERY PLAN                                                                           
1054 ----------------------------------------------------------------------------------------------------------------------------------------------------------------
1055  Foreign Scan on public.ft2
1056    Output: c1, c2, c3
1057    Remote SQL: SELECT "C 1", c2, c3 FROM "S 1"."T 1" WHERE (((CASE WHEN ("C 1" > 990) THEN "C 1" ELSE NULL::integer END) < 1000)) ORDER BY "C 1" ASC NULLS LAST
1058 (3 rows)
1060 SELECT c1,c2,c3 FROM ft2 WHERE CASE WHEN c1 > 990 THEN c1 END < 1000 ORDER BY c1;
1061  c1  | c2 |  c3   
1062 -----+----+-------
1063  991 |  1 | 00991
1064  992 |  2 | 00992
1065  993 |  3 | 00993
1066  994 |  4 | 00994
1067  995 |  5 | 00995
1068  996 |  6 | 00996
1069  997 |  7 | 00997
1070  998 |  8 | 00998
1071  999 |  9 | 00999
1072 (9 rows)
1074 -- Nested CASE
1075 EXPLAIN (VERBOSE, COSTS OFF)
1076 SELECT c1,c2,c3 FROM ft2 WHERE CASE CASE WHEN c2 > 0 THEN c2 END WHEN 100 THEN 601 WHEN c2 THEN c2 ELSE 0 END > 600 ORDER BY c1;
1077                                                                                                 QUERY PLAN                                                                                                 
1078 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1079  Foreign Scan on public.ft2
1080    Output: c1, c2, c3
1081    Remote SQL: SELECT "C 1", c2, c3 FROM "S 1"."T 1" WHERE (((CASE (CASE WHEN (c2 > 0) THEN c2 ELSE NULL::integer END) WHEN 100 THEN 601 WHEN c2 THEN c2 ELSE 0 END) > 600)) ORDER BY "C 1" ASC NULLS LAST
1082 (3 rows)
1084 SELECT c1,c2,c3 FROM ft2 WHERE CASE CASE WHEN c2 > 0 THEN c2 END WHEN 100 THEN 601 WHEN c2 THEN c2 ELSE 0 END > 600 ORDER BY c1;
1085  c1 | c2 | c3 
1086 ----+----+----
1087 (0 rows)
1089 -- CASE arg WHEN
1090 EXPLAIN (VERBOSE, COSTS OFF)
1091 SELECT * FROM ft1 WHERE c1 > (CASE mod(c1, 4) WHEN 0 THEN 1 WHEN 2 THEN 50 ELSE 100 END);
1092                                                                         QUERY PLAN                                                                        
1093 ----------------------------------------------------------------------------------------------------------------------------------------------------------
1094  Foreign Scan on public.ft1
1095    Output: c1, c2, c3, c4, c5, c6, c7, c8
1096    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" > (CASE mod("C 1", 4) WHEN 0 THEN 1 WHEN 2 THEN 50 ELSE 100 END)))
1097 (3 rows)
1099 -- CASE cannot be pushed down because of unshippable arg clause
1100 EXPLAIN (VERBOSE, COSTS OFF)
1101 SELECT * FROM ft1 WHERE c1 > (CASE random()::integer WHEN 0 THEN 1 WHEN 2 THEN 50 ELSE 100 END);
1102                                        QUERY PLAN                                        
1103 -----------------------------------------------------------------------------------------
1104  Foreign Scan on public.ft1
1105    Output: c1, c2, c3, c4, c5, c6, c7, c8
1106    Filter: (ft1.c1 > CASE (random())::integer WHEN 0 THEN 1 WHEN 2 THEN 50 ELSE 100 END)
1107    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1108 (4 rows)
1110 -- these are shippable
1111 EXPLAIN (VERBOSE, COSTS OFF)
1112 SELECT * FROM ft1 WHERE CASE c6 WHEN 'foo' THEN true ELSE c3 < 'bar' END;
1113                                                                  QUERY PLAN                                                                 
1114 --------------------------------------------------------------------------------------------------------------------------------------------
1115  Foreign Scan on public.ft1
1116    Output: c1, c2, c3, c4, c5, c6, c7, c8
1117    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((CASE c6 WHEN 'foo'::text THEN true ELSE (c3 < 'bar') END))
1118 (3 rows)
1120 EXPLAIN (VERBOSE, COSTS OFF)
1121 SELECT * FROM ft1 WHERE CASE c3 WHEN c6 THEN true ELSE c3 < 'bar' END;
1122                                                             QUERY PLAN                                                             
1123 -----------------------------------------------------------------------------------------------------------------------------------
1124  Foreign Scan on public.ft1
1125    Output: c1, c2, c3, c4, c5, c6, c7, c8
1126    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((CASE c3 WHEN c6 THEN true ELSE (c3 < 'bar') END))
1127 (3 rows)
1129 -- but this is not because of collation
1130 EXPLAIN (VERBOSE, COSTS OFF)
1131 SELECT * FROM ft1 WHERE CASE c3 COLLATE "C" WHEN c6 THEN true ELSE c3 < 'bar' END;
1132                                      QUERY PLAN                                      
1133 -------------------------------------------------------------------------------------
1134  Foreign Scan on public.ft1
1135    Output: c1, c2, c3, c4, c5, c6, c7, c8
1136    Filter: CASE (ft1.c3)::text WHEN ft1.c6 THEN true ELSE (ft1.c3 < 'bar'::text) END
1137    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1138 (4 rows)
1140 -- a regconfig constant referring to this text search configuration
1141 -- is initially unshippable
1142 CREATE TEXT SEARCH CONFIGURATION public.custom_search
1143   (COPY = pg_catalog.english);
1144 EXPLAIN (VERBOSE, COSTS OFF)
1145 SELECT c1, to_tsvector('custom_search'::regconfig, c3) FROM ft1
1146 WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
1147                                QUERY PLAN                                
1148 -------------------------------------------------------------------------
1149  Foreign Scan on public.ft1
1150    Output: c1, to_tsvector('custom_search'::regconfig, c3)
1151    Filter: (length(to_tsvector('custom_search'::regconfig, ft1.c3)) > 0)
1152    Remote SQL: SELECT "C 1", c3 FROM "S 1"."T 1" WHERE (("C 1" = 642))
1153 (4 rows)
1155 SELECT c1, to_tsvector('custom_search'::regconfig, c3) FROM ft1
1156 WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
1157  c1  | to_tsvector 
1158 -----+-------------
1159  642 | '00642':1
1160 (1 row)
1162 -- but if it's in a shippable extension, it can be shipped
1163 ALTER EXTENSION postgres_fdw ADD TEXT SEARCH CONFIGURATION public.custom_search;
1164 -- however, that doesn't flush the shippability cache, so do a quick reconnect
1165 \c -
1166 EXPLAIN (VERBOSE, COSTS OFF)
1167 SELECT c1, to_tsvector('custom_search'::regconfig, c3) FROM ft1
1168 WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
1169                                                                   QUERY PLAN                                                                  
1170 ----------------------------------------------------------------------------------------------------------------------------------------------
1171  Foreign Scan on public.ft1
1172    Output: c1, to_tsvector('custom_search'::regconfig, c3)
1173    Remote SQL: SELECT "C 1", c3 FROM "S 1"."T 1" WHERE (("C 1" = 642)) AND ((length(to_tsvector('public.custom_search'::regconfig, c3)) > 0))
1174 (3 rows)
1176 SELECT c1, to_tsvector('custom_search'::regconfig, c3) FROM ft1
1177 WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
1178  c1  | to_tsvector 
1179 -----+-------------
1180  642 | '00642':1
1181 (1 row)
1183 -- ===================================================================
1184 -- ORDER BY queries
1185 -- ===================================================================
1186 -- we should not push order by clause with volatile expressions or unsafe
1187 -- collations
1188 EXPLAIN (VERBOSE, COSTS OFF)
1189         SELECT * FROM ft2 ORDER BY ft2.c1, random();
1190                                   QUERY PLAN                                   
1191 -------------------------------------------------------------------------------
1192  Sort
1193    Output: c1, c2, c3, c4, c5, c6, c7, c8, (random())
1194    Sort Key: ft2.c1, (random())
1195    ->  Foreign Scan on public.ft2
1196          Output: c1, c2, c3, c4, c5, c6, c7, c8, random()
1197          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1198 (6 rows)
1200 EXPLAIN (VERBOSE, COSTS OFF)
1201         SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
1202                                   QUERY PLAN                                   
1203 -------------------------------------------------------------------------------
1204  Sort
1205    Output: c1, c2, c3, c4, c5, c6, c7, c8, ((c3)::text)
1206    Sort Key: ft2.c1, ft2.c3 COLLATE "C"
1207    ->  Foreign Scan on public.ft2
1208          Output: c1, c2, c3, c4, c5, c6, c7, c8, c3
1209          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1210 (6 rows)
1212 -- Ensure we don't push ORDER BY expressions which are Consts at the UNION
1213 -- child level to the foreign server.
1214 EXPLAIN (VERBOSE, COSTS OFF)
1215 SELECT * FROM (
1216     SELECT 1 AS type,c1 FROM ft1
1217     UNION ALL
1218     SELECT 2 AS type,c1 FROM ft2
1219 ) a ORDER BY type,c1;
1220                                    QUERY PLAN                                    
1221 ---------------------------------------------------------------------------------
1222  Merge Append
1223    Sort Key: (1), ft1.c1
1224    ->  Foreign Scan on public.ft1
1225          Output: 1, ft1.c1
1226          Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
1227    ->  Foreign Scan on public.ft2
1228          Output: 2, ft2.c1
1229          Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
1230 (8 rows)
1232 EXPLAIN (VERBOSE, COSTS OFF)
1233 SELECT * FROM (
1234     SELECT 1 AS type,c1 FROM ft1
1235     UNION ALL
1236     SELECT 2 AS type,c1 FROM ft2
1237 ) a ORDER BY type;
1238                     QUERY PLAN                     
1239 ---------------------------------------------------
1240  Merge Append
1241    Sort Key: (1)
1242    ->  Foreign Scan on public.ft1
1243          Output: 1, ft1.c1
1244          Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
1245    ->  Foreign Scan on public.ft2
1246          Output: 2, ft2.c1
1247          Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
1248 (8 rows)
1250 -- ===================================================================
1251 -- JOIN queries
1252 -- ===================================================================
1253 -- Analyze ft4 and ft5 so that we have better statistics. These tables do not
1254 -- have use_remote_estimate set.
1255 ANALYZE ft4;
1256 ANALYZE ft5;
1257 -- join two tables
1258 EXPLAIN (VERBOSE, COSTS OFF)
1259 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;
1260                                                                                                        QUERY PLAN                                                                                                       
1261 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1262  Foreign Scan
1263    Output: t1.c1, t2.c1, t1.c3
1264    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
1265    Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3 FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 100::bigint
1266 (4 rows)
1268 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;
1269  c1  | c1  
1270 -----+-----
1271  101 | 101
1272  102 | 102
1273  103 | 103
1274  104 | 104
1275  105 | 105
1276  106 | 106
1277  107 | 107
1278  108 | 108
1279  109 | 109
1280  110 | 110
1281 (10 rows)
1283 -- join three tables
1284 EXPLAIN (VERBOSE, COSTS OFF)
1285 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;
1286                                                                                                                                    QUERY PLAN                                                                                                                                    
1287 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1288  Foreign Scan
1289    Output: t1.c1, t2.c2, t3.c3, t1.c3
1290    Relations: ((public.ft1 t1) INNER JOIN (public.ft2 t2)) INNER JOIN (public.ft4 t3)
1291    Remote SQL: SELECT r1."C 1", r2.c2, r4.c3, r1.c3 FROM (("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1")))) INNER JOIN "S 1"."T 3" r4 ON (((r1."C 1" = r4.c1)))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 10::bigint
1292 (4 rows)
1294 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;
1295  c1 | c2 |   c3   
1296 ----+----+--------
1297  22 |  2 | AAA022
1298  24 |  4 | AAA024
1299  26 |  6 | AAA026
1300  28 |  8 | AAA028
1301  30 |  0 | AAA030
1302  32 |  2 | AAA032
1303  34 |  4 | AAA034
1304  36 |  6 | AAA036
1305  38 |  8 | AAA038
1306  40 |  0 | AAA040
1307 (10 rows)
1309 -- left outer join
1310 EXPLAIN (VERBOSE, COSTS OFF)
1311 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;
1312                                                                                            QUERY PLAN                                                                                           
1313 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1314  Foreign Scan
1315    Output: t1.c1, t2.c1
1316    Relations: (public.ft4 t1) LEFT JOIN (public.ft5 t2)
1317    Remote SQL: SELECT r1.c1, r2.c1 FROM ("S 1"."T 3" r1 LEFT JOIN "S 1"."T 4" r2 ON (((r1.c1 = r2.c1)))) ORDER BY r1.c1 ASC NULLS LAST, r2.c1 ASC NULLS LAST LIMIT 10::bigint OFFSET 10::bigint
1318 (4 rows)
1320 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;
1321  c1 | c1 
1322 ----+----
1323  22 |   
1324  24 | 24
1325  26 |   
1326  28 |   
1327  30 | 30
1328  32 |   
1329  34 |   
1330  36 | 36
1331  38 |   
1332  40 |   
1333 (10 rows)
1335 -- left outer join three tables
1336 EXPLAIN (VERBOSE, COSTS OFF)
1337 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;
1338                                                                                                    QUERY PLAN                                                                                                    
1339 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1340  Foreign Scan
1341    Output: t1.c1, t2.c2, t3.c3
1342    Relations: ((public.ft2 t1) LEFT JOIN (public.ft2 t2)) LEFT JOIN (public.ft4 t3)
1343    Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM (("S 1"."T 1" r1 LEFT JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) LEFT JOIN "S 1"."T 3" r4 ON (((r2."C 1" = r4.c1)))) LIMIT 10::bigint OFFSET 10::bigint
1344 (4 rows)
1346 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;
1347  c1 | c2 |   c3   
1348 ----+----+--------
1349  11 |  1 | 
1350  12 |  2 | AAA012
1351  13 |  3 | 
1352  14 |  4 | AAA014
1353  15 |  5 | 
1354  16 |  6 | AAA016
1355  17 |  7 | 
1356  18 |  8 | AAA018
1357  19 |  9 | 
1358  20 |  0 | AAA020
1359 (10 rows)
1361 -- left outer join + placement of clauses.
1362 -- clauses within the nullable side are not pulled up, but top level clause on
1363 -- non-nullable side is pushed into non-nullable side
1364 EXPLAIN (VERBOSE, COSTS OFF)
1365 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;
1366                                                                           QUERY PLAN                                                                           
1367 ---------------------------------------------------------------------------------------------------------------------------------------------------------------
1368  Foreign Scan
1369    Output: t1.c1, t1.c2, ft5.c1, ft5.c2
1370    Relations: (public.ft4 t1) LEFT JOIN (public.ft5)
1371    Remote SQL: SELECT r1.c1, r1.c2, r4.c1, r4.c2 FROM ("S 1"."T 3" r1 LEFT JOIN "S 1"."T 4" r4 ON (((r1.c1 = r4.c1)) AND ((r4.c1 < 10)))) WHERE ((r1.c1 < 10))
1372 (4 rows)
1374 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;
1375  c1 | c2 | c1 | c2 
1376 ----+----+----+----
1377   2 |  3 |    |   
1378   4 |  5 |    |   
1379   6 |  7 |  6 |  7
1380   8 |  9 |    |   
1381 (4 rows)
1383 -- clauses within the nullable side are not pulled up, but the top level clause
1384 -- on nullable side is not pushed down into nullable side
1385 EXPLAIN (VERBOSE, COSTS OFF)
1386 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)
1387                         WHERE (t2.c1 < 10 OR t2.c1 IS NULL) AND t1.c1 < 10;
1388                                                                                               QUERY PLAN                                                                                               
1389 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1390  Foreign Scan
1391    Output: t1.c1, t1.c2, ft5.c1, ft5.c2
1392    Relations: (public.ft4 t1) LEFT JOIN (public.ft5)
1393    Remote SQL: SELECT r1.c1, r1.c2, r4.c1, r4.c2 FROM ("S 1"."T 3" r1 LEFT JOIN "S 1"."T 4" r4 ON (((r1.c1 = r4.c1)) AND ((r4.c1 < 10)))) WHERE (((r4.c1 < 10) OR (r4.c1 IS NULL))) AND ((r1.c1 < 10))
1394 (4 rows)
1396 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)
1397                         WHERE (t2.c1 < 10 OR t2.c1 IS NULL) AND t1.c1 < 10;
1398  c1 | c2 | c1 | c2 
1399 ----+----+----+----
1400   2 |  3 |    |   
1401   4 |  5 |    |   
1402   6 |  7 |  6 |  7
1403   8 |  9 |    |   
1404 (4 rows)
1406 -- right outer join
1407 EXPLAIN (VERBOSE, COSTS OFF)
1408 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;
1409                                                                                            QUERY PLAN                                                                                           
1410 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1411  Foreign Scan
1412    Output: t1.c1, t2.c1
1413    Relations: (public.ft4 t2) LEFT JOIN (public.ft5 t1)
1414    Remote SQL: SELECT r1.c1, r2.c1 FROM ("S 1"."T 3" r2 LEFT JOIN "S 1"."T 4" r1 ON (((r1.c1 = r2.c1)))) ORDER BY r2.c1 ASC NULLS LAST, r1.c1 ASC NULLS LAST LIMIT 10::bigint OFFSET 10::bigint
1415 (4 rows)
1417 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;
1418  c1 | c1 
1419 ----+----
1420     | 22
1421  24 | 24
1422     | 26
1423     | 28
1424  30 | 30
1425     | 32
1426     | 34
1427  36 | 36
1428     | 38
1429     | 40
1430 (10 rows)
1432 -- right outer join three tables
1433 EXPLAIN (VERBOSE, COSTS OFF)
1434 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;
1435                                                                                                    QUERY PLAN                                                                                                    
1436 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1437  Foreign Scan
1438    Output: t1.c1, t2.c2, t3.c3
1439    Relations: ((public.ft4 t3) LEFT JOIN (public.ft2 t2)) LEFT JOIN (public.ft2 t1)
1440    Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM (("S 1"."T 3" r4 LEFT JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r4.c1)))) LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1")))) LIMIT 10::bigint OFFSET 10::bigint
1441 (4 rows)
1443 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;
1444  c1 | c2 |   c3   
1445 ----+----+--------
1446  22 |  2 | AAA022
1447  24 |  4 | AAA024
1448  26 |  6 | AAA026
1449  28 |  8 | AAA028
1450  30 |  0 | AAA030
1451  32 |  2 | AAA032
1452  34 |  4 | AAA034
1453  36 |  6 | AAA036
1454  38 |  8 | AAA038
1455  40 |  0 | AAA040
1456 (10 rows)
1458 -- full outer join
1459 EXPLAIN (VERBOSE, COSTS OFF)
1460 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;
1461                                                                                            QUERY PLAN                                                                                           
1462 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1463  Foreign Scan
1464    Output: t1.c1, t2.c1
1465    Relations: (public.ft4 t1) FULL JOIN (public.ft5 t2)
1466    Remote SQL: SELECT r1.c1, r2.c1 FROM ("S 1"."T 3" r1 FULL JOIN "S 1"."T 4" r2 ON (((r1.c1 = r2.c1)))) ORDER BY r1.c1 ASC NULLS LAST, r2.c1 ASC NULLS LAST LIMIT 10::bigint OFFSET 45::bigint
1467 (4 rows)
1469 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;
1470  c1  | c1 
1471 -----+----
1472   92 |   
1473   94 |   
1474   96 | 96
1475   98 |   
1476  100 |   
1477      |  3
1478      |  9
1479      | 15
1480      | 21
1481      | 27
1482 (10 rows)
1484 -- full outer join with restrictions on the joining relations
1485 -- a. the joining relations are both base relations
1486 EXPLAIN (VERBOSE, COSTS OFF)
1487 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;
1488                                                                                                                                   QUERY PLAN                                                                                                                                   
1489 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1490  Foreign Scan
1491    Output: ft4.c1, ft5.c1
1492    Relations: (public.ft4) FULL JOIN (public.ft5)
1493    Remote SQL: SELECT s4.c1, s5.c1 FROM ((SELECT c1 FROM "S 1"."T 3" WHERE ((c1 >= 50)) AND ((c1 <= 60))) s4(c1) FULL JOIN (SELECT c1 FROM "S 1"."T 4" WHERE ((c1 >= 50)) AND ((c1 <= 60))) s5(c1) ON (((s4.c1 = s5.c1)))) ORDER BY s4.c1 ASC NULLS LAST, s5.c1 ASC NULLS LAST
1494 (4 rows)
1496 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;
1497  c1 | c1 
1498 ----+----
1499  50 |   
1500  52 |   
1501  54 | 54
1502  56 |   
1503  58 |   
1504  60 | 60
1505     | 51
1506     | 57
1507 (8 rows)
1509 EXPLAIN (VERBOSE, COSTS OFF)
1510 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;
1511                                                                                                              QUERY PLAN                                                                                                              
1512 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1513  Foreign Scan
1514    Output: 1
1515    Relations: (public.ft4) FULL JOIN (public.ft5)
1516    Remote SQL: SELECT NULL FROM ((SELECT NULL FROM "S 1"."T 3" WHERE ((c1 >= 50)) AND ((c1 <= 60))) s4 FULL JOIN (SELECT NULL FROM "S 1"."T 4" WHERE ((c1 >= 50)) AND ((c1 <= 60))) s5 ON (TRUE)) LIMIT 10::bigint OFFSET 10::bigint
1517 (4 rows)
1519 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;
1520  ?column? 
1521 ----------
1522         1
1523         1
1524         1
1525         1
1526         1
1527         1
1528         1
1529         1
1530         1
1531         1
1532 (10 rows)
1534 -- b. one of the joining relations is a base relation and the other is a join
1535 -- relation
1536 EXPLAIN (VERBOSE, COSTS OFF)
1537 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;
1538                                                                                                                                                                                      QUERY PLAN                                                                                                                                                                                      
1539 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1540  Foreign Scan
1541    Output: ft4.c1, t2.c1, t3.c1
1542    Relations: (public.ft4) FULL JOIN ((public.ft4 t2) LEFT JOIN (public.ft5 t3))
1543    Remote SQL: SELECT s4.c1, s8.c1, s8.c2 FROM ((SELECT c1 FROM "S 1"."T 3" WHERE ((c1 >= 50)) AND ((c1 <= 60))) s4(c1) FULL JOIN (SELECT r5.c1, r6.c1 FROM ("S 1"."T 3" r5 LEFT JOIN "S 1"."T 4" r6 ON (((r5.c1 = r6.c1)))) WHERE ((r5.c1 >= 50)) AND ((r5.c1 <= 60))) s8(c1, c2) ON (((s4.c1 = s8.c1)))) ORDER BY s4.c1 ASC NULLS LAST, s8.c1 ASC NULLS LAST, s8.c2 ASC NULLS LAST
1544 (4 rows)
1546 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;
1547  c1 | a  | b  
1548 ----+----+----
1549  50 | 50 |   
1550  52 | 52 |   
1551  54 | 54 | 54
1552  56 | 56 |   
1553  58 | 58 |   
1554  60 | 60 | 60
1555 (6 rows)
1557 -- c. test deparsing the remote query as nested subqueries
1558 EXPLAIN (VERBOSE, COSTS OFF)
1559 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;
1560                                                                                                                                                                                                                                                      QUERY PLAN                                                                                                                                                                                                                                                     
1561 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1562  Foreign Scan
1563    Output: ft4.c1, ft4_1.c1, ft5.c1
1564    Relations: (public.ft4) FULL JOIN ((public.ft4 ft4_1) FULL JOIN (public.ft5))
1565    Remote SQL: SELECT s4.c1, s10.c1, s10.c2 FROM ((SELECT c1 FROM "S 1"."T 3" WHERE ((c1 >= 50)) AND ((c1 <= 60))) s4(c1) FULL JOIN (SELECT s8.c1, s9.c1 FROM ((SELECT c1 FROM "S 1"."T 3" WHERE ((c1 >= 50)) AND ((c1 <= 60))) s8(c1) FULL JOIN (SELECT c1 FROM "S 1"."T 4" WHERE ((c1 >= 50)) AND ((c1 <= 60))) s9(c1) ON (((s8.c1 = s9.c1)))) WHERE (((s8.c1 IS NULL) OR (s8.c1 IS NOT NULL)))) s10(c1, c2) ON (((s4.c1 = s10.c1)))) ORDER BY s4.c1 ASC NULLS LAST, s10.c1 ASC NULLS LAST, s10.c2 ASC NULLS LAST
1566 (4 rows)
1568 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;
1569  c1 | a  | b  
1570 ----+----+----
1571  50 | 50 |   
1572  52 | 52 |   
1573  54 | 54 | 54
1574  56 | 56 |   
1575  58 | 58 |   
1576  60 | 60 | 60
1577     |    | 51
1578     |    | 57
1579 (8 rows)
1581 -- d. test deparsing rowmarked relations as subqueries
1582 EXPLAIN (VERBOSE, COSTS OFF)
1583 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;
1584                                                                                                                                                                                              QUERY PLAN                                                                                                                                                                                             
1585 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1586  LockRows
1587    Output: "T 3".c1, ft4.c1, ft5.c1, "T 3".ctid, ft4.*, ft5.*
1588    ->  Nested Loop
1589          Output: "T 3".c1, ft4.c1, ft5.c1, "T 3".ctid, ft4.*, ft5.*
1590          ->  Foreign Scan
1591                Output: ft4.c1, ft4.*, ft5.c1, ft5.*
1592                Relations: (public.ft4) FULL JOIN (public.ft5)
1593                Remote SQL: SELECT s8.c1, s8.c2, s9.c1, s9.c2 FROM ((SELECT c1, ROW(c1, c2, c3) FROM "S 1"."T 3" WHERE ((c1 >= 50)) AND ((c1 <= 60))) s8(c1, c2) FULL JOIN (SELECT c1, ROW(c1, c2, c3) FROM "S 1"."T 4" WHERE ((c1 >= 50)) AND ((c1 <= 60))) s9(c1, c2) ON (((s8.c1 = s9.c1)))) WHERE (((s8.c1 IS NULL) OR (s8.c1 IS NOT NULL))) ORDER BY s8.c1 ASC NULLS LAST, s9.c1 ASC NULLS LAST
1594                ->  Sort
1595                      Output: ft4.c1, ft4.*, ft5.c1, ft5.*
1596                      Sort Key: ft4.c1, ft5.c1
1597                      ->  Hash Full Join
1598                            Output: ft4.c1, ft4.*, ft5.c1, ft5.*
1599                            Hash Cond: (ft4.c1 = ft5.c1)
1600                            Filter: ((ft4.c1 IS NULL) OR (ft4.c1 IS NOT NULL))
1601                            ->  Foreign Scan on public.ft4
1602                                  Output: ft4.c1, ft4.*
1603                                  Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3" WHERE ((c1 >= 50)) AND ((c1 <= 60))
1604                            ->  Hash
1605                                  Output: ft5.c1, ft5.*
1606                                  ->  Foreign Scan on public.ft5
1607                                        Output: ft5.c1, ft5.*
1608                                        Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 4" WHERE ((c1 >= 50)) AND ((c1 <= 60))
1609          ->  Materialize
1610                Output: "T 3".c1, "T 3".ctid
1611                ->  Seq Scan on "S 1"."T 3"
1612                      Output: "T 3".c1, "T 3".ctid
1613                      Filter: ("T 3".c1 = 50)
1614 (28 rows)
1616 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;
1617  c1 | a  | b  
1618 ----+----+----
1619  50 | 50 |   
1620  50 | 52 |   
1621  50 | 54 | 54
1622  50 | 56 |   
1623  50 | 58 |   
1624  50 | 60 | 60
1625  50 |    | 51
1626  50 |    | 57
1627 (8 rows)
1629 -- full outer join + inner join
1630 EXPLAIN (VERBOSE, COSTS OFF)
1631 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;
1632                                                                                                                                                  QUERY PLAN                                                                                                                                                 
1633 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1634  Foreign Scan
1635    Output: t1.c1, t2.c1, t3.c1
1636    Relations: ((public.ft4 t1) INNER JOIN (public.ft5 t2)) FULL JOIN (public.ft4 t3)
1637    Remote SQL: SELECT r1.c1, r2.c1, r4.c1 FROM (("S 1"."T 3" r1 INNER JOIN "S 1"."T 4" r2 ON (((r1.c1 = (r2.c1 + 1))) AND ((r1.c1 >= 50)) AND ((r1.c1 <= 60)))) FULL JOIN "S 1"."T 3" r4 ON (((r2.c1 = r4.c1)))) ORDER BY r1.c1 ASC NULLS LAST, r2.c1 ASC NULLS LAST, r4.c1 ASC NULLS LAST LIMIT 10::bigint
1638 (4 rows)
1640 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;
1641  c1 | c1 | c1 
1642 ----+----+----
1643  52 | 51 |   
1644  58 | 57 |   
1645     |    |  2
1646     |    |  4
1647     |    |  6
1648     |    |  8
1649     |    | 10
1650     |    | 12
1651     |    | 14
1652     |    | 16
1653 (10 rows)
1655 -- full outer join three tables
1656 EXPLAIN (VERBOSE, COSTS OFF)
1657 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;
1658                                                                                                    QUERY PLAN                                                                                                    
1659 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1660  Foreign Scan
1661    Output: t1.c1, t2.c2, t3.c3
1662    Relations: ((public.ft2 t1) FULL JOIN (public.ft2 t2)) FULL JOIN (public.ft4 t3)
1663    Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM (("S 1"."T 1" r1 FULL JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) FULL JOIN "S 1"."T 3" r4 ON (((r2."C 1" = r4.c1)))) LIMIT 10::bigint OFFSET 10::bigint
1664 (4 rows)
1666 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;
1667  c1 | c2 |   c3   
1668 ----+----+--------
1669  11 |  1 | 
1670  12 |  2 | AAA012
1671  13 |  3 | 
1672  14 |  4 | AAA014
1673  15 |  5 | 
1674  16 |  6 | AAA016
1675  17 |  7 | 
1676  18 |  8 | AAA018
1677  19 |  9 | 
1678  20 |  0 | AAA020
1679 (10 rows)
1681 -- full outer join + right outer join
1682 EXPLAIN (VERBOSE, COSTS OFF)
1683 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;
1684                                                                                                    QUERY PLAN                                                                                                    
1685 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1686  Foreign Scan
1687    Output: t1.c1, t2.c2, t3.c3
1688    Relations: ((public.ft4 t3) LEFT JOIN (public.ft2 t2)) LEFT JOIN (public.ft2 t1)
1689    Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM (("S 1"."T 3" r4 LEFT JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r4.c1)))) LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1")))) LIMIT 10::bigint OFFSET 10::bigint
1690 (4 rows)
1692 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;
1693  c1 | c2 |   c3   
1694 ----+----+--------
1695  22 |  2 | AAA022
1696  24 |  4 | AAA024
1697  26 |  6 | AAA026
1698  28 |  8 | AAA028
1699  30 |  0 | AAA030
1700  32 |  2 | AAA032
1701  34 |  4 | AAA034
1702  36 |  6 | AAA036
1703  38 |  8 | AAA038
1704  40 |  0 | AAA040
1705 (10 rows)
1707 -- right outer join + full outer join
1708 EXPLAIN (VERBOSE, COSTS OFF)
1709 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;
1710                                                                                                    QUERY PLAN                                                                                                    
1711 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1712  Foreign Scan
1713    Output: t1.c1, t2.c2, t3.c3
1714    Relations: ((public.ft2 t2) LEFT JOIN (public.ft2 t1)) FULL JOIN (public.ft4 t3)
1715    Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM (("S 1"."T 1" r2 LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1")))) FULL JOIN "S 1"."T 3" r4 ON (((r2."C 1" = r4.c1)))) LIMIT 10::bigint OFFSET 10::bigint
1716 (4 rows)
1718 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;
1719  c1 | c2 |   c3   
1720 ----+----+--------
1721  11 |  1 | 
1722  12 |  2 | AAA012
1723  13 |  3 | 
1724  14 |  4 | AAA014
1725  15 |  5 | 
1726  16 |  6 | AAA016
1727  17 |  7 | 
1728  18 |  8 | AAA018
1729  19 |  9 | 
1730  20 |  0 | AAA020
1731 (10 rows)
1733 -- full outer join + left outer join
1734 EXPLAIN (VERBOSE, COSTS OFF)
1735 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;
1736                                                                                                    QUERY PLAN                                                                                                    
1737 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1738  Foreign Scan
1739    Output: t1.c1, t2.c2, t3.c3
1740    Relations: ((public.ft2 t1) FULL JOIN (public.ft2 t2)) LEFT JOIN (public.ft4 t3)
1741    Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM (("S 1"."T 1" r1 FULL JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) LEFT JOIN "S 1"."T 3" r4 ON (((r2."C 1" = r4.c1)))) LIMIT 10::bigint OFFSET 10::bigint
1742 (4 rows)
1744 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;
1745  c1 | c2 |   c3   
1746 ----+----+--------
1747  11 |  1 | 
1748  12 |  2 | AAA012
1749  13 |  3 | 
1750  14 |  4 | AAA014
1751  15 |  5 | 
1752  16 |  6 | AAA016
1753  17 |  7 | 
1754  18 |  8 | AAA018
1755  19 |  9 | 
1756  20 |  0 | AAA020
1757 (10 rows)
1759 -- left outer join + full outer join
1760 EXPLAIN (VERBOSE, COSTS OFF)
1761 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;
1762                                                                                                    QUERY PLAN                                                                                                    
1763 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1764  Foreign Scan
1765    Output: t1.c1, t2.c2, t3.c3
1766    Relations: ((public.ft2 t1) LEFT JOIN (public.ft2 t2)) FULL JOIN (public.ft4 t3)
1767    Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM (("S 1"."T 1" r1 LEFT JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) FULL JOIN "S 1"."T 3" r4 ON (((r2."C 1" = r4.c1)))) LIMIT 10::bigint OFFSET 10::bigint
1768 (4 rows)
1770 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;
1771  c1 | c2 |   c3   
1772 ----+----+--------
1773  11 |  1 | 
1774  12 |  2 | AAA012
1775  13 |  3 | 
1776  14 |  4 | AAA014
1777  15 |  5 | 
1778  16 |  6 | AAA016
1779  17 |  7 | 
1780  18 |  8 | AAA018
1781  19 |  9 | 
1782  20 |  0 | AAA020
1783 (10 rows)
1785 SET enable_memoize TO off;
1786 -- right outer join + left outer join
1787 EXPLAIN (VERBOSE, COSTS OFF)
1788 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;
1789                                                                                                    QUERY PLAN                                                                                                    
1790 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1791  Foreign Scan
1792    Output: t1.c1, t2.c2, t3.c3
1793    Relations: ((public.ft2 t2) LEFT JOIN (public.ft2 t1)) LEFT JOIN (public.ft4 t3)
1794    Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM (("S 1"."T 1" r2 LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1")))) LEFT JOIN "S 1"."T 3" r4 ON (((r2."C 1" = r4.c1)))) LIMIT 10::bigint OFFSET 10::bigint
1795 (4 rows)
1797 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;
1798  c1 | c2 |   c3   
1799 ----+----+--------
1800  11 |  1 | 
1801  12 |  2 | AAA012
1802  13 |  3 | 
1803  14 |  4 | AAA014
1804  15 |  5 | 
1805  16 |  6 | AAA016
1806  17 |  7 | 
1807  18 |  8 | AAA018
1808  19 |  9 | 
1809  20 |  0 | AAA020
1810 (10 rows)
1812 RESET enable_memoize;
1813 -- left outer join + right outer join
1814 EXPLAIN (VERBOSE, COSTS OFF)
1815 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;
1816                                                                                                     QUERY PLAN                                                                                                    
1817 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1818  Foreign Scan
1819    Output: t1.c1, t2.c2, t3.c3
1820    Relations: (public.ft4 t3) LEFT JOIN ((public.ft2 t1) INNER JOIN (public.ft2 t2))
1821    Remote SQL: SELECT r1."C 1", r2.c2, r4.c3 FROM ("S 1"."T 3" r4 LEFT JOIN ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) ON (((r2."C 1" = r4.c1)))) LIMIT 10::bigint OFFSET 10::bigint
1822 (4 rows)
1824 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;
1825  c1 | c2 |   c3   
1826 ----+----+--------
1827  22 |  2 | AAA022
1828  24 |  4 | AAA024
1829  26 |  6 | AAA026
1830  28 |  8 | AAA028
1831  30 |  0 | AAA030
1832  32 |  2 | AAA032
1833  34 |  4 | AAA034
1834  36 |  6 | AAA036
1835  38 |  8 | AAA038
1836  40 |  0 | AAA040
1837 (10 rows)
1839 -- full outer join + WHERE clause, only matched rows
1840 EXPLAIN (VERBOSE, COSTS OFF)
1841 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;
1842                                                                             QUERY PLAN                                                                            
1843 ------------------------------------------------------------------------------------------------------------------------------------------------------------------
1844  Limit
1845    Output: t1.c1, t2.c1
1846    ->  Sort
1847          Output: t1.c1, t2.c1
1848          Sort Key: t1.c1, t2.c1
1849          ->  Foreign Scan
1850                Output: t1.c1, t2.c1
1851                Relations: (public.ft4 t1) FULL JOIN (public.ft5 t2)
1852                Remote SQL: SELECT r1.c1, r2.c1 FROM ("S 1"."T 3" r1 FULL JOIN "S 1"."T 4" r2 ON (((r1.c1 = r2.c1)))) WHERE (((r1.c1 = r2.c1) OR (r1.c1 IS NULL)))
1853 (9 rows)
1855 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;
1856  c1 | c1 
1857 ----+----
1858  66 | 66
1859  72 | 72
1860  78 | 78
1861  84 | 84
1862  90 | 90
1863  96 | 96
1864     |  3
1865     |  9
1866     | 15
1867     | 21
1868 (10 rows)
1870 -- full outer join + WHERE clause with shippable extensions set
1871 EXPLAIN (VERBOSE, COSTS OFF)
1872 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;
1873                                                                                                  QUERY PLAN                                                                                                 
1874 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1875  Foreign Scan
1876    Output: t1.c1, t2.c2, t1.c3
1877    Relations: (public.ft1 t1) FULL JOIN (public.ft2 t2)
1878    Remote SQL: SELECT r1."C 1", r2.c2, r1.c3 FROM ("S 1"."T 1" r1 FULL JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")))) WHERE ((public.postgres_fdw_abs(r1."C 1") > 0)) LIMIT 10::bigint OFFSET 10::bigint
1879 (4 rows)
1881 ALTER SERVER loopback OPTIONS (DROP extensions);
1882 -- full outer join + WHERE clause with shippable extensions not set
1883 EXPLAIN (VERBOSE, COSTS OFF)
1884 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;
1885                                                           QUERY PLAN                                                           
1886 -------------------------------------------------------------------------------------------------------------------------------
1887  Limit
1888    Output: t1.c1, t2.c2, t1.c3
1889    ->  Foreign Scan
1890          Output: t1.c1, t2.c2, t1.c3
1891          Filter: (postgres_fdw_abs(t1.c1) > 0)
1892          Relations: (public.ft1 t1) FULL JOIN (public.ft2 t2)
1893          Remote SQL: SELECT r1."C 1", r2.c2, r1.c3 FROM ("S 1"."T 1" r1 FULL JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1"))))
1894 (7 rows)
1896 ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
1897 -- join two tables with FOR UPDATE clause
1898 -- tests whole-row reference for row marks
1899 EXPLAIN (VERBOSE, COSTS OFF)
1900 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;
1901                                                                                                                                                                                                                            QUERY PLAN                                                                                                                                                                                                                            
1902 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1903  Foreign Scan
1904    Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
1905    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
1906    Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 100::bigint FOR UPDATE OF r1
1907 (4 rows)
1909 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;
1910  c1  | c1  
1911 -----+-----
1912  101 | 101
1913  102 | 102
1914  103 | 103
1915  104 | 104
1916  105 | 105
1917  106 | 106
1918  107 | 107
1919  108 | 108
1920  109 | 109
1921  110 | 110
1922 (10 rows)
1924 EXPLAIN (VERBOSE, COSTS OFF)
1925 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;
1926                                                                                                                                                                                                                                     QUERY PLAN                                                                                                                                                                                                                                    
1927 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1928  Foreign Scan
1929    Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
1930    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
1931    Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 100::bigint FOR UPDATE OF r1 FOR UPDATE OF r2
1932 (4 rows)
1934 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;
1935  c1  | c1  
1936 -----+-----
1937  101 | 101
1938  102 | 102
1939  103 | 103
1940  104 | 104
1941  105 | 105
1942  106 | 106
1943  107 | 107
1944  108 | 108
1945  109 | 109
1946  110 | 110
1947 (10 rows)
1949 -- join two tables with FOR SHARE clause
1950 EXPLAIN (VERBOSE, COSTS OFF)
1951 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;
1952                                                                                                                                                                                                                            QUERY PLAN                                                                                                                                                                                                                           
1953 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1954  Foreign Scan
1955    Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
1956    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
1957    Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 100::bigint FOR SHARE OF r1
1958 (4 rows)
1960 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;
1961  c1  | c1  
1962 -----+-----
1963  101 | 101
1964  102 | 102
1965  103 | 103
1966  104 | 104
1967  105 | 105
1968  106 | 106
1969  107 | 107
1970  108 | 108
1971  109 | 109
1972  110 | 110
1973 (10 rows)
1975 EXPLAIN (VERBOSE, COSTS OFF)
1976 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;
1977                                                                                                                                                                                                                                    QUERY PLAN                                                                                                                                                                                                                                   
1978 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1979  Foreign Scan
1980    Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
1981    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
1982    Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 100::bigint FOR SHARE OF r1 FOR SHARE OF r2
1983 (4 rows)
1985 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;
1986  c1  | c1  
1987 -----+-----
1988  101 | 101
1989  102 | 102
1990  103 | 103
1991  104 | 104
1992  105 | 105
1993  106 | 106
1994  107 | 107
1995  108 | 108
1996  109 | 109
1997  110 | 110
1998 (10 rows)
2000 -- join in CTE
2001 EXPLAIN (VERBOSE, COSTS OFF)
2002 WITH t (c1_1, c1_3, c2_1) AS MATERIALIZED (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;
2003                                                              QUERY PLAN                                                              
2004 -------------------------------------------------------------------------------------------------------------------------------------
2005  Limit
2006    Output: t.c1_1, t.c2_1, t.c1_3
2007    CTE t
2008      ->  Foreign Scan
2009            Output: t1.c1, t1.c3, t2.c1
2010            Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2011            Remote SQL: SELECT r1."C 1", r1.c3, r2."C 1" FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1"))))
2012    ->  Sort
2013          Output: t.c1_1, t.c2_1, t.c1_3
2014          Sort Key: t.c1_3, t.c1_1
2015          ->  CTE Scan on t
2016                Output: t.c1_1, t.c2_1, t.c1_3
2017 (12 rows)
2019 WITH t (c1_1, c1_3, c2_1) AS MATERIALIZED (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;
2020  c1_1 | c2_1 
2021 ------+------
2022   101 |  101
2023   102 |  102
2024   103 |  103
2025   104 |  104
2026   105 |  105
2027   106 |  106
2028   107 |  107
2029   108 |  108
2030   109 |  109
2031   110 |  110
2032 (10 rows)
2034 -- ctid with whole-row reference
2035 EXPLAIN (VERBOSE, COSTS OFF)
2036 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;
2037                                                                                                                                                                                                                   QUERY PLAN                                                                                                                                                                                                                   
2038 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2039  Foreign Scan
2040    Output: t1.ctid, t1.*, t2.*, t1.c1, t1.c3
2041    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2042    Remote SQL: SELECT r1.ctid, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END, r1."C 1", r1.c3 FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 100::bigint
2043 (4 rows)
2045 -- SEMI JOIN
2046 EXPLAIN (VERBOSE, COSTS OFF)
2047 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;
2048                                                                                              QUERY PLAN                                                                                              
2049 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2050  Foreign Scan
2051    Output: t1.c1
2052    Relations: (public.ft1 t1) SEMI JOIN (public.ft2 t2)
2053    Remote SQL: SELECT r1."C 1" FROM "S 1"."T 1" r1 WHERE EXISTS (SELECT NULL FROM "S 1"."T 1" r2 WHERE ((r2."C 1" = r1."C 1"))) ORDER BY r1."C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 100::bigint
2054 (4 rows)
2056 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;
2057  c1  
2058 -----
2059  101
2060  102
2061  103
2062  104
2063  105
2064  106
2065  107
2066  108
2067  109
2068  110
2069 (10 rows)
2071 -- ANTI JOIN, not pushed down
2072 EXPLAIN (VERBOSE, COSTS OFF)
2073 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;
2074                                       QUERY PLAN                                       
2075 ---------------------------------------------------------------------------------------
2076  Limit
2077    Output: t1.c1
2078    ->  Merge Anti Join
2079          Output: t1.c1
2080          Merge Cond: (t1.c1 = t2.c2)
2081          ->  Foreign Scan on public.ft1 t1
2082                Output: t1.c1
2083                Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
2084          ->  Foreign Scan on public.ft2 t2
2085                Output: t2.c2
2086                Remote SQL: SELECT c2 FROM "S 1"."T 1" ORDER BY c2 ASC NULLS LAST
2087 (11 rows)
2089 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;
2090  c1  
2091 -----
2092  110
2093  111
2094  112
2095  113
2096  114
2097  115
2098  116
2099  117
2100  118
2101  119
2102 (10 rows)
2104 -- CROSS JOIN can be pushed down
2105 EXPLAIN (VERBOSE, COSTS OFF)
2106 SELECT t1.c1, t2.c1 FROM ft1 t1 CROSS JOIN ft2 t2 ORDER BY t1.c1, t2.c1 OFFSET 100 LIMIT 10;
2107                                                                                            QUERY PLAN                                                                                            
2108 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2109  Foreign Scan
2110    Output: t1.c1, t2.c1
2111    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2112    Remote SQL: SELECT r1."C 1", r2."C 1" FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (TRUE)) ORDER BY r1."C 1" ASC NULLS LAST, r2."C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 100::bigint
2113 (4 rows)
2115 SELECT t1.c1, t2.c1 FROM ft1 t1 CROSS JOIN ft2 t2 ORDER BY t1.c1, t2.c1 OFFSET 100 LIMIT 10;
2116  c1 | c1  
2117 ----+-----
2118   1 | 101
2119   1 | 102
2120   1 | 103
2121   1 | 104
2122   1 | 105
2123   1 | 106
2124   1 | 107
2125   1 | 108
2126   1 | 109
2127   1 | 110
2128 (10 rows)
2130 -- different server, not pushed down. No result expected.
2131 EXPLAIN (VERBOSE, COSTS OFF)
2132 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;
2133                                       QUERY PLAN                                       
2134 ---------------------------------------------------------------------------------------
2135  Limit
2136    Output: t1.c1, t2.c1
2137    ->  Merge Join
2138          Output: t1.c1, t2.c1
2139          Merge Cond: (t2.c1 = t1.c1)
2140          ->  Foreign Scan on public.ft6 t2
2141                Output: t2.c1, t2.c2, t2.c3
2142                Remote SQL: SELECT c1 FROM "S 1"."T 4" ORDER BY c1 ASC NULLS LAST
2143          ->  Materialize
2144                Output: t1.c1, t1.c2, t1.c3
2145                ->  Foreign Scan on public.ft5 t1
2146                      Output: t1.c1, t1.c2, t1.c3
2147                      Remote SQL: SELECT c1 FROM "S 1"."T 4" ORDER BY c1 ASC NULLS LAST
2148 (13 rows)
2150 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;
2151  c1 | c1 
2152 ----+----
2153 (0 rows)
2155 -- unsafe join conditions (c8 has a UDT), not pushed down. Practically a CROSS
2156 -- JOIN since c8 in both tables has same value.
2157 EXPLAIN (VERBOSE, COSTS OFF)
2158 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;
2159                                QUERY PLAN                                
2160 -------------------------------------------------------------------------
2161  Limit
2162    Output: t1.c1, t2.c1
2163    ->  Sort
2164          Output: t1.c1, t2.c1
2165          Sort Key: t1.c1, t2.c1
2166          ->  Merge Left Join
2167                Output: t1.c1, t2.c1
2168                Merge Cond: (t1.c8 = t2.c8)
2169                ->  Sort
2170                      Output: t1.c1, t1.c8
2171                      Sort Key: t1.c8
2172                      ->  Foreign Scan on public.ft1 t1
2173                            Output: t1.c1, t1.c8
2174                            Remote SQL: SELECT "C 1", c8 FROM "S 1"."T 1"
2175                ->  Sort
2176                      Output: t2.c1, t2.c8
2177                      Sort Key: t2.c8
2178                      ->  Foreign Scan on public.ft2 t2
2179                            Output: t2.c1, t2.c8
2180                            Remote SQL: SELECT "C 1", c8 FROM "S 1"."T 1"
2181 (20 rows)
2183 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;
2184  c1 | c1  
2185 ----+-----
2186   1 | 101
2187   1 | 102
2188   1 | 103
2189   1 | 104
2190   1 | 105
2191   1 | 106
2192   1 | 107
2193   1 | 108
2194   1 | 109
2195   1 | 110
2196 (10 rows)
2198 -- unsafe conditions on one side (c8 has a UDT), not pushed down.
2199 EXPLAIN (VERBOSE, COSTS OFF)
2200 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;
2201                                  QUERY PLAN                                  
2202 -----------------------------------------------------------------------------
2203  Limit
2204    Output: t1.c1, t2.c1, t1.c3
2205    ->  Sort
2206          Output: t1.c1, t2.c1, t1.c3
2207          Sort Key: t1.c3, t1.c1
2208          ->  Hash Right Join
2209                Output: t1.c1, t2.c1, t1.c3
2210                Hash Cond: (t2.c1 = t1.c1)
2211                ->  Foreign Scan on public.ft2 t2
2212                      Output: t2.c1
2213                      Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
2214                ->  Hash
2215                      Output: t1.c1, t1.c3
2216                      ->  Foreign Scan on public.ft1 t1
2217                            Output: t1.c1, t1.c3
2218                            Filter: (t1.c8 = 'foo'::user_enum)
2219                            Remote SQL: SELECT "C 1", c3, c8 FROM "S 1"."T 1"
2220 (17 rows)
2222 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;
2223  c1  | c1  
2224 -----+-----
2225  101 | 101
2226  102 | 102
2227  103 | 103
2228  104 | 104
2229  105 | 105
2230  106 | 106
2231  107 | 107
2232  108 | 108
2233  109 | 109
2234  110 | 110
2235 (10 rows)
2237 -- join where unsafe to pushdown condition in WHERE clause has a column not
2238 -- in the SELECT clause. In this test unsafe clause needs to have column
2239 -- references from both joining sides so that the clause is not pushed down
2240 -- into one of the joining sides.
2241 EXPLAIN (VERBOSE, COSTS OFF)
2242 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;
2243                                                                       QUERY PLAN                                                                       
2244 -------------------------------------------------------------------------------------------------------------------------------------------------------
2245  Limit
2246    Output: t1.c1, t2.c1, t1.c3
2247    ->  Sort
2248          Output: t1.c1, t2.c1, t1.c3
2249          Sort Key: t1.c3, t1.c1
2250          ->  Foreign Scan
2251                Output: t1.c1, t2.c1, t1.c3
2252                Filter: (t1.c8 = t2.c8)
2253                Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2254                Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3, r1.c8, r2.c8 FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1"))))
2255 (10 rows)
2257 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;
2258  c1  | c1  
2259 -----+-----
2260  101 | 101
2261  102 | 102
2262  103 | 103
2263  104 | 104
2264  105 | 105
2265  106 | 106
2266  107 | 107
2267  108 | 108
2268  109 | 109
2269  110 | 110
2270 (10 rows)
2272 -- Aggregate after UNION, for testing setrefs
2273 EXPLAIN (VERBOSE, COSTS OFF)
2274 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;
2275                                                                      QUERY PLAN                                                                     
2276 ----------------------------------------------------------------------------------------------------------------------------------------------------
2277  Limit
2278    Output: t1.c1, (avg((t1.c1 + t2.c1)))
2279    ->  Sort
2280          Output: t1.c1, (avg((t1.c1 + t2.c1)))
2281          Sort Key: t1.c1
2282          ->  HashAggregate
2283                Output: t1.c1, avg((t1.c1 + t2.c1))
2284                Group Key: t1.c1
2285                ->  HashAggregate
2286                      Output: t1.c1, t2.c1
2287                      Group Key: t1.c1, t2.c1
2288                      ->  Append
2289                            ->  Foreign Scan
2290                                  Output: t1.c1, t2.c1
2291                                  Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2292                                  Remote SQL: SELECT r1."C 1", r2."C 1" FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1"))))
2293                            ->  Foreign Scan
2294                                  Output: t1_1.c1, t2_1.c1
2295                                  Relations: (public.ft1 t1_1) INNER JOIN (public.ft2 t2_1)
2296                                  Remote SQL: SELECT r1."C 1", r2."C 1" FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1"))))
2297 (20 rows)
2299 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;
2300  t1c1 |         avg          
2301 ------+----------------------
2302   101 | 202.0000000000000000
2303   102 | 204.0000000000000000
2304   103 | 206.0000000000000000
2305   104 | 208.0000000000000000
2306   105 | 210.0000000000000000
2307   106 | 212.0000000000000000
2308   107 | 214.0000000000000000
2309   108 | 216.0000000000000000
2310   109 | 218.0000000000000000
2311   110 | 220.0000000000000000
2312 (10 rows)
2314 -- join with lateral reference
2315 EXPLAIN (VERBOSE, COSTS OFF)
2316 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;
2317                                                                                    QUERY PLAN                                                                                   
2318 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2319  Limit
2320    Output: t1."C 1"
2321    ->  Nested Loop
2322          Output: t1."C 1"
2323          ->  Index Scan using t1_pkey on "S 1"."T 1" t1
2324                Output: t1."C 1", t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8
2325          ->  Memoize
2326                Cache Key: t1.c2
2327                Cache Mode: binary
2328                ->  Subquery Scan on q
2329                      ->  HashAggregate
2330                            Output: t2.c1, t3.c1
2331                            Group Key: t2.c1
2332                            ->  Foreign Scan
2333                                  Output: t2.c1, t3.c1
2334                                  Relations: (public.ft1 t2) INNER JOIN (public.ft2 t3)
2335                                  Remote SQL: SELECT r1."C 1", r2."C 1" FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1")) AND ((r1.c2 = $1::integer))))
2336 (17 rows)
2338 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;
2339  C 1 
2340 -----
2341    1
2342    1
2343    1
2344    1
2345    1
2346    1
2347    1
2348    1
2349    1
2350    1
2351 (10 rows)
2353 -- join with pseudoconstant quals
2354 EXPLAIN (VERBOSE, COSTS OFF)
2355 SELECT t1.c1, t2.c1 FROM ft1 t1 JOIN ft2 t2 ON (t1.c1 = t2.c1 AND CURRENT_USER = SESSION_USER) ORDER BY t1.c3, t1.c1 OFFSET 100 LIMIT 10;
2356                                                                                            QUERY PLAN                                                                                           
2357 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2358  Limit
2359    Output: t1.c1, t2.c1, t1.c3
2360    ->  Result
2361          Output: t1.c1, t2.c1, t1.c3
2362          One-Time Filter: (CURRENT_USER = SESSION_USER)
2363          ->  Foreign Scan
2364                Output: t1.c1, t1.c3, t2.c1
2365                Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2366                Remote SQL: SELECT r1."C 1", r2."C 1", r1.c3 FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1")))) ORDER BY r1.c3 ASC NULLS LAST, r1."C 1" ASC NULLS LAST
2367 (9 rows)
2369 -- non-Var items in targetlist of the nullable rel of a join preventing
2370 -- push-down in some cases
2371 -- unable to push {ft1, ft2}
2372 EXPLAIN (VERBOSE, COSTS OFF)
2373 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;
2374                                                         QUERY PLAN                                                         
2375 ---------------------------------------------------------------------------------------------------------------------------
2376  Nested Loop Left Join
2377    Output: (13), ft2.c1
2378    Join Filter: (13 = ft2.c1)
2379    ->  Foreign Scan on public.ft2
2380          Output: ft2.c1
2381          Remote SQL: SELECT "C 1" FROM "S 1"."T 1" WHERE (("C 1" >= 10)) AND (("C 1" <= 15)) ORDER BY "C 1" ASC NULLS LAST
2382    ->  Materialize
2383          Output: (13)
2384          ->  Foreign Scan on public.ft1
2385                Output: 13
2386                Remote SQL: SELECT NULL FROM "S 1"."T 1" WHERE (("C 1" = 13))
2387 (11 rows)
2389 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;
2390  a  | c1 
2391 ----+----
2392     | 10
2393     | 11
2394     | 12
2395  13 | 13
2396     | 14
2397     | 15
2398 (6 rows)
2400 -- ok to push {ft1, ft2} but not {ft1, ft2, ft4}
2401 EXPLAIN (VERBOSE, COSTS OFF)
2402 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;
2403                                                                                     QUERY PLAN                                                                                     
2404 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2405  Nested Loop Left Join
2406    Output: ft4.c1, (13), ft1.c1, ft2.c1
2407    Join Filter: (ft4.c1 = ft1.c1)
2408    ->  Foreign Scan on public.ft4
2409          Output: ft4.c1, ft4.c2, ft4.c3
2410          Remote SQL: SELECT c1 FROM "S 1"."T 3" WHERE ((c1 >= 10)) AND ((c1 <= 15))
2411    ->  Materialize
2412          Output: ft1.c1, ft2.c1, (13)
2413          ->  Foreign Scan
2414                Output: ft1.c1, ft2.c1, 13
2415                Relations: (public.ft1) INNER JOIN (public.ft2)
2416                Remote SQL: SELECT r4."C 1", r5."C 1" FROM ("S 1"."T 1" r4 INNER JOIN "S 1"."T 1" r5 ON (((r5."C 1" = 12)) AND ((r4."C 1" = 12)))) ORDER BY r4."C 1" ASC NULLS LAST
2417 (12 rows)
2419 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;
2420  c1 | a  | b  | c  
2421 ----+----+----+----
2422  10 |    |    |   
2423  12 | 13 | 12 | 12
2424  14 |    |    |   
2425 (3 rows)
2427 -- join with nullable side with some columns with null values
2428 UPDATE ft5 SET c3 = null where c1 % 9 = 0;
2429 EXPLAIN (VERBOSE, COSTS OFF)
2430 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;
2431                                                                                                                                 QUERY PLAN                                                                                                                                 
2432 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2433  Foreign Scan
2434    Output: ft5.*, ft5.c1, ft5.c2, ft5.c3, ft4.c1, ft4.c2
2435    Relations: (public.ft5) INNER JOIN (public.ft4)
2436    Remote SQL: SELECT CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1.c1, r1.c2, r1.c3) END, r1.c1, r1.c2, r1.c3, r2.c1, r2.c2 FROM ("S 1"."T 4" r1 INNER JOIN "S 1"."T 3" r2 ON (((r1.c1 = r2.c1)) AND ((r2.c1 >= 10)) AND ((r2.c1 <= 30)))) ORDER BY r1.c1 ASC NULLS LAST
2437 (4 rows)
2439 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;
2440       ft5       | c1 | c2 |   c3   | c1 | c2 
2441 ----------------+----+----+--------+----+----
2442  (12,13,AAA012) | 12 | 13 | AAA012 | 12 | 13
2443  (18,19,)       | 18 | 19 |        | 18 | 19
2444  (24,25,AAA024) | 24 | 25 | AAA024 | 24 | 25
2445  (30,31,AAA030) | 30 | 31 | AAA030 | 30 | 31
2446 (4 rows)
2448 -- multi-way join involving multiple merge joins
2449 -- (this case used to have EPQ-related planning problems)
2450 CREATE TABLE local_tbl (c1 int NOT NULL, c2 int NOT NULL, c3 text, CONSTRAINT local_tbl_pkey PRIMARY KEY (c1));
2451 INSERT INTO local_tbl SELECT id, id % 10, to_char(id, 'FM0000') FROM generate_series(1, 1000) id;
2452 ANALYZE local_tbl;
2453 SET enable_nestloop TO false;
2454 SET enable_hashjoin TO false;
2455 EXPLAIN (VERBOSE, COSTS OFF)
2456 SELECT * FROM ft1, ft2, ft4, ft5, local_tbl WHERE ft1.c1 = ft2.c1 AND ft1.c2 = ft4.c1
2457     AND ft1.c2 = ft5.c1 AND ft1.c2 = local_tbl.c1 AND ft1.c1 < 100 AND ft2.c1 < 100 FOR UPDATE;
2458                                                                                                                                                                                                                                                                                                                                                                                                                                                QUERY PLAN                                                                                                                                                                                                                                                                                                                                                                                                                                               
2459 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2460  LockRows
2461    Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3, ft5.c1, ft5.c2, ft5.c3, local_tbl.c1, local_tbl.c2, local_tbl.c3, ft1.*, ft2.*, ft4.*, ft5.*, local_tbl.ctid
2462    ->  Merge Join
2463          Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3, ft5.c1, ft5.c2, ft5.c3, local_tbl.c1, local_tbl.c2, local_tbl.c3, ft1.*, ft2.*, ft4.*, ft5.*, local_tbl.ctid
2464          Inner Unique: true
2465          Merge Cond: (ft1.c2 = local_tbl.c1)
2466          ->  Foreign Scan
2467                Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.*, ft4.c1, ft4.c2, ft4.c3, ft4.*, ft5.c1, ft5.c2, ft5.c3, ft5.*
2468                Relations: (((public.ft1) INNER JOIN (public.ft2)) INNER JOIN (public.ft4)) INNER JOIN (public.ft5)
2469                Remote SQL: SELECT r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END, r3.c1, r3.c2, r3.c3, CASE WHEN (r3.*)::text IS NOT NULL THEN ROW(r3.c1, r3.c2, r3.c3) END, r4.c1, r4.c2, r4.c3, CASE WHEN (r4.*)::text IS NOT NULL THEN ROW(r4.c1, r4.c2, r4.c3) END FROM ((("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1")) AND ((r2."C 1" < 100)) AND ((r1."C 1" < 100)))) INNER JOIN "S 1"."T 3" r3 ON (((r1.c2 = r3.c1)))) INNER JOIN "S 1"."T 4" r4 ON (((r1.c2 = r4.c1)))) ORDER BY r1.c2 ASC NULLS LAST FOR UPDATE OF r1 FOR UPDATE OF r2 FOR UPDATE OF r3 FOR UPDATE OF r4
2470                ->  Merge Join
2471                      Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.*, ft4.c1, ft4.c2, ft4.c3, ft4.*, ft5.c1, ft5.c2, ft5.c3, ft5.*
2472                      Merge Cond: (ft1.c2 = ft5.c1)
2473                      ->  Merge Join
2474                            Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.*, ft4.c1, ft4.c2, ft4.c3, ft4.*
2475                            Merge Cond: (ft1.c2 = ft4.c1)
2476                            ->  Sort
2477                                  Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.*
2478                                  Sort Key: ft1.c2
2479                                  ->  Merge Join
2480                                        Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.*
2481                                        Merge Cond: (ft1.c1 = ft2.c1)
2482                                        ->  Sort
2483                                              Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*
2484                                              Sort Key: ft1.c1
2485                                              ->  Foreign Scan on public.ft1
2486                                                    Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*
2487                                                    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" < 100)) FOR UPDATE
2488                                        ->  Materialize
2489                                              Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.*
2490                                              ->  Foreign Scan on public.ft2
2491                                                    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.*
2492                                                    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" < 100)) ORDER BY "C 1" ASC NULLS LAST FOR UPDATE
2493                            ->  Sort
2494                                  Output: ft4.c1, ft4.c2, ft4.c3, ft4.*
2495                                  Sort Key: ft4.c1
2496                                  ->  Foreign Scan on public.ft4
2497                                        Output: ft4.c1, ft4.c2, ft4.c3, ft4.*
2498                                        Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3" FOR UPDATE
2499                      ->  Sort
2500                            Output: ft5.c1, ft5.c2, ft5.c3, ft5.*
2501                            Sort Key: ft5.c1
2502                            ->  Foreign Scan on public.ft5
2503                                  Output: ft5.c1, ft5.c2, ft5.c3, ft5.*
2504                                  Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 4" FOR UPDATE
2505          ->  Index Scan using local_tbl_pkey on public.local_tbl
2506                Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, local_tbl.ctid
2507 (47 rows)
2509 SELECT * FROM ft1, ft2, ft4, ft5, local_tbl WHERE ft1.c1 = ft2.c1 AND ft1.c2 = ft4.c1
2510     AND ft1.c2 = ft5.c1 AND ft1.c2 = local_tbl.c1 AND ft1.c1 < 100 AND ft2.c1 < 100 FOR UPDATE;
2511  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  | c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  | c1 | c2 |   c3   | c1 | c2 |   c3   | c1 | c2 |  c3  
2512 ----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+--------+----+----+--------+----+----+------
2513   6 |  6 | 00006 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  6 | 00006 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006 |  6 |  7 | AAA006 |  6 |  6 | 0006
2514  16 |  6 | 00016 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo | 16 |  6 | 00016 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006 |  6 |  7 | AAA006 |  6 |  6 | 0006
2515  26 |  6 | 00026 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo | 26 |  6 | 00026 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006 |  6 |  7 | AAA006 |  6 |  6 | 0006
2516  36 |  6 | 00036 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo | 36 |  6 | 00036 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006 |  6 |  7 | AAA006 |  6 |  6 | 0006
2517  46 |  6 | 00046 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo | 46 |  6 | 00046 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006 |  6 |  7 | AAA006 |  6 |  6 | 0006
2518  56 |  6 | 00056 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo | 56 |  6 | 00056 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006 |  6 |  7 | AAA006 |  6 |  6 | 0006
2519  66 |  6 | 00066 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo | 66 |  6 | 00066 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006 |  6 |  7 | AAA006 |  6 |  6 | 0006
2520  76 |  6 | 00076 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo | 76 |  6 | 00076 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006 |  6 |  7 | AAA006 |  6 |  6 | 0006
2521  86 |  6 | 00086 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo | 86 |  6 | 00086 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006 |  6 |  7 | AAA006 |  6 |  6 | 0006
2522  96 |  6 | 00096 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo | 96 |  6 | 00096 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006 |  6 |  7 | AAA006 |  6 |  6 | 0006
2523 (10 rows)
2525 RESET enable_nestloop;
2526 RESET enable_hashjoin;
2527 -- test that add_paths_with_pathkeys_for_rel() arranges for the epq_path to
2528 -- return columns needed by the parent ForeignScan node
2529 EXPLAIN (VERBOSE, COSTS OFF)
2530 SELECT * FROM local_tbl LEFT JOIN (SELECT ft1.*, COALESCE(ft1.c3 || ft2.c3, 'foobar') FROM ft1 INNER JOIN ft2 ON (ft1.c1 = ft2.c1 AND ft1.c1 < 100)) ss ON (local_tbl.c1 = ss.c1) ORDER BY local_tbl.c1 FOR UPDATE OF local_tbl;
2531                                                                                                                                                                                                                               QUERY PLAN                                                                                                                                                                                                                              
2532 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2533  LockRows
2534    Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, (COALESCE((ft1.c3 || ft2.c3), 'foobar'::text)), local_tbl.ctid, ft1.*, ft2.*
2535    ->  Merge Left Join
2536          Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, (COALESCE((ft1.c3 || ft2.c3), 'foobar'::text)), local_tbl.ctid, ft1.*, ft2.*
2537          Merge Cond: (local_tbl.c1 = ft1.c1)
2538          ->  Index Scan using local_tbl_pkey on public.local_tbl
2539                Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, local_tbl.ctid
2540          ->  Materialize
2541                Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, (COALESCE((ft1.c3 || ft2.c3), 'foobar'::text))
2542                ->  Foreign Scan
2543                      Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, COALESCE((ft1.c3 || ft2.c3), 'foobar'::text)
2544                      Relations: (public.ft1) INNER JOIN (public.ft2)
2545                      Remote SQL: SELECT r4."C 1", r4.c2, r4.c3, r4.c4, r4.c5, r4.c6, r4.c7, r4.c8, CASE WHEN (r4.*)::text IS NOT NULL THEN ROW(r4."C 1", r4.c2, r4.c3, r4.c4, r4.c5, r4.c6, r4.c7, r4.c8) END, CASE WHEN (r5.*)::text IS NOT NULL THEN ROW(r5."C 1", r5.c2, r5.c3, r5.c4, r5.c5, r5.c6, r5.c7, r5.c8) END, r5.c3 FROM ("S 1"."T 1" r4 INNER JOIN "S 1"."T 1" r5 ON (((r5."C 1" = r4."C 1")) AND ((r4."C 1" < 100)))) ORDER BY r4."C 1" ASC NULLS LAST
2546                      ->  Result
2547                            Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, ft2.c3
2548                            ->  Sort
2549                                  Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, (COALESCE((ft1.c3 || ft2.c3), 'foobar'::text)), ft2.c3
2550                                  Sort Key: ft1.c1
2551                                  ->  Hash Join
2552                                        Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, COALESCE((ft1.c3 || ft2.c3), 'foobar'::text), ft2.c3
2553                                        Hash Cond: (ft1.c1 = ft2.c1)
2554                                        ->  Foreign Scan on public.ft1
2555                                              Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*
2556                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" < 100))
2557                                        ->  Hash
2558                                              Output: ft2.*, ft2.c1, ft2.c3
2559                                              ->  Foreign Scan on public.ft2
2560                                                    Output: ft2.*, ft2.c1, ft2.c3
2561                                                    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
2562 (29 rows)
2564 ALTER SERVER loopback OPTIONS (DROP extensions);
2565 ALTER SERVER loopback OPTIONS (ADD fdw_startup_cost '10000.0');
2566 EXPLAIN (VERBOSE, COSTS OFF)
2567 SELECT * FROM local_tbl LEFT JOIN (SELECT ft1.* FROM ft1 INNER JOIN ft2 ON (ft1.c1 = ft2.c1 AND ft1.c1 < 100 AND (ft1.c1 - postgres_fdw_abs(ft2.c2)) = 0)) ss ON (local_tbl.c3 = ss.c3) ORDER BY local_tbl.c1 FOR UPDATE OF local_tbl;
2568                                                                                                                                                                                                                             QUERY PLAN                                                                                                                                                                                                                             
2569 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2570  LockRows
2571    Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, local_tbl.ctid, ft1.*, ft2.*
2572    ->  Nested Loop Left Join
2573          Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, local_tbl.ctid, ft1.*, ft2.*
2574          Join Filter: (local_tbl.c3 = ft1.c3)
2575          ->  Index Scan using local_tbl_pkey on public.local_tbl
2576                Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, local_tbl.ctid
2577          ->  Materialize
2578                Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*
2579                ->  Foreign Scan
2580                      Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*
2581                      Filter: ((ft1.c1 - postgres_fdw_abs(ft2.c2)) = 0)
2582                      Relations: (public.ft1) INNER JOIN (public.ft2)
2583                      Remote SQL: SELECT r4."C 1", r4.c2, r4.c3, r4.c4, r4.c5, r4.c6, r4.c7, r4.c8, CASE WHEN (r4.*)::text IS NOT NULL THEN ROW(r4."C 1", r4.c2, r4.c3, r4.c4, r4.c5, r4.c6, r4.c7, r4.c8) END, CASE WHEN (r5.*)::text IS NOT NULL THEN ROW(r5."C 1", r5.c2, r5.c3, r5.c4, r5.c5, r5.c6, r5.c7, r5.c8) END, r5.c2 FROM ("S 1"."T 1" r4 INNER JOIN "S 1"."T 1" r5 ON (((r5."C 1" = r4."C 1")) AND ((r4."C 1" < 100)))) ORDER BY r4.c3 ASC NULLS LAST
2584                      ->  Sort
2585                            Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, ft2.c2
2586                            Sort Key: ft1.c3
2587                            ->  Merge Join
2588                                  Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, ft2.c2
2589                                  Merge Cond: (ft1.c1 = ft2.c1)
2590                                  Join Filter: ((ft1.c1 - postgres_fdw_abs(ft2.c2)) = 0)
2591                                  ->  Sort
2592                                        Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*
2593                                        Sort Key: ft1.c1
2594                                        ->  Foreign Scan on public.ft1
2595                                              Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*
2596                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" < 100))
2597                                  ->  Materialize
2598                                        Output: ft2.*, ft2.c1, ft2.c2
2599                                        ->  Foreign Scan on public.ft2
2600                                              Output: ft2.*, ft2.c1, ft2.c2
2601                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
2602 (32 rows)
2604 ALTER SERVER loopback OPTIONS (DROP fdw_startup_cost);
2605 ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
2606 DROP TABLE local_tbl;
2607 -- check join pushdown in situations where multiple userids are involved
2608 CREATE ROLE regress_view_owner SUPERUSER;
2609 CREATE USER MAPPING FOR regress_view_owner SERVER loopback;
2610 GRANT SELECT ON ft4 TO regress_view_owner;
2611 GRANT SELECT ON ft5 TO regress_view_owner;
2612 CREATE VIEW v4 AS SELECT * FROM ft4;
2613 CREATE VIEW v5 AS SELECT * FROM ft5;
2614 ALTER VIEW v5 OWNER TO regress_view_owner;
2615 EXPLAIN (VERBOSE, COSTS OFF)
2616 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
2617                               QUERY PLAN                              
2618 ----------------------------------------------------------------------
2619  Limit
2620    Output: ft4.c1, ft5.c2, ft5.c1
2621    ->  Sort
2622          Output: ft4.c1, ft5.c2, ft5.c1
2623          Sort Key: ft4.c1, ft5.c1
2624          ->  Hash Left Join
2625                Output: ft4.c1, ft5.c2, ft5.c1
2626                Hash Cond: (ft4.c1 = ft5.c1)
2627                ->  Foreign Scan on public.ft4
2628                      Output: ft4.c1, ft4.c2, ft4.c3
2629                      Remote SQL: SELECT c1 FROM "S 1"."T 3"
2630                ->  Hash
2631                      Output: ft5.c2, ft5.c1
2632                      ->  Foreign Scan on public.ft5
2633                            Output: ft5.c2, ft5.c1
2634                            Remote SQL: SELECT c1, c2 FROM "S 1"."T 4"
2635 (16 rows)
2637 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;
2638  c1 | c2 
2639 ----+----
2640  22 |   
2641  24 | 25
2642  26 |   
2643  28 |   
2644  30 | 31
2645  32 |   
2646  34 |   
2647  36 | 37
2648  38 |   
2649  40 |   
2650 (10 rows)
2652 ALTER VIEW v4 OWNER TO regress_view_owner;
2653 EXPLAIN (VERBOSE, COSTS OFF)
2654 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
2655                                                                                               QUERY PLAN                                                                                               
2656 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2657  Foreign Scan
2658    Output: ft4.c1, ft5.c2, ft5.c1
2659    Relations: (public.ft4) LEFT JOIN (public.ft5)
2660    Remote SQL: SELECT r4.c1, r5.c2, r5.c1 FROM ("S 1"."T 3" r4 LEFT JOIN "S 1"."T 4" r5 ON (((r4.c1 = r5.c1)))) ORDER BY r4.c1 ASC NULLS LAST, r5.c1 ASC NULLS LAST LIMIT 10::bigint OFFSET 10::bigint
2661 (4 rows)
2663 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;
2664  c1 | c2 
2665 ----+----
2666  22 |   
2667  24 | 25
2668  26 |   
2669  28 |   
2670  30 | 31
2671  32 |   
2672  34 |   
2673  36 | 37
2674  38 |   
2675  40 |   
2676 (10 rows)
2678 EXPLAIN (VERBOSE, COSTS OFF)
2679 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
2680                               QUERY PLAN                              
2681 ----------------------------------------------------------------------
2682  Limit
2683    Output: ft4.c1, t2.c2, t2.c1
2684    ->  Sort
2685          Output: ft4.c1, t2.c2, t2.c1
2686          Sort Key: ft4.c1, t2.c1
2687          ->  Hash Left Join
2688                Output: ft4.c1, t2.c2, t2.c1
2689                Hash Cond: (ft4.c1 = t2.c1)
2690                ->  Foreign Scan on public.ft4
2691                      Output: ft4.c1, ft4.c2, ft4.c3
2692                      Remote SQL: SELECT c1 FROM "S 1"."T 3"
2693                ->  Hash
2694                      Output: t2.c2, t2.c1
2695                      ->  Foreign Scan on public.ft5 t2
2696                            Output: t2.c2, t2.c1
2697                            Remote SQL: SELECT c1, c2 FROM "S 1"."T 4"
2698 (16 rows)
2700 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;
2701  c1 | c2 
2702 ----+----
2703  22 |   
2704  24 | 25
2705  26 |   
2706  28 |   
2707  30 | 31
2708  32 |   
2709  34 |   
2710  36 | 37
2711  38 |   
2712  40 |   
2713 (10 rows)
2715 ALTER VIEW v4 OWNER TO CURRENT_USER;
2716 EXPLAIN (VERBOSE, COSTS OFF)
2717 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
2718                                                                                               QUERY PLAN                                                                                               
2719 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2720  Foreign Scan
2721    Output: ft4.c1, t2.c2, t2.c1
2722    Relations: (public.ft4) LEFT JOIN (public.ft5 t2)
2723    Remote SQL: SELECT r4.c1, r2.c2, r2.c1 FROM ("S 1"."T 3" r4 LEFT JOIN "S 1"."T 4" r2 ON (((r4.c1 = r2.c1)))) ORDER BY r4.c1 ASC NULLS LAST, r2.c1 ASC NULLS LAST LIMIT 10::bigint OFFSET 10::bigint
2724 (4 rows)
2726 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;
2727  c1 | c2 
2728 ----+----
2729  22 |   
2730  24 | 25
2731  26 |   
2732  28 |   
2733  30 | 31
2734  32 |   
2735  34 |   
2736  36 | 37
2737  38 |   
2738  40 |   
2739 (10 rows)
2741 ALTER VIEW v4 OWNER TO regress_view_owner;
2742 -- Make sure this big CROSS JOIN query is pushed down
2743 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 CROSS JOIN ft2 CROSS JOIN ft4 CROSS JOIN ft5;
2744                                                                              QUERY PLAN                                                                              
2745 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
2746  Foreign Scan
2747    Output: (count(*))
2748    Relations: Aggregate on ((((public.ft1) INNER JOIN (public.ft2)) INNER JOIN (public.ft4)) INNER JOIN (public.ft5))
2749    Remote SQL: SELECT count(*) FROM ((("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (TRUE)) INNER JOIN "S 1"."T 3" r4 ON (TRUE)) INNER JOIN "S 1"."T 4" r6 ON (TRUE))
2750 (4 rows)
2752 -- Make sure query cancellation works
2753 BEGIN;
2754 SET LOCAL statement_timeout = '10ms';
2755 select count(*) from ft1 CROSS JOIN ft2 CROSS JOIN ft4 CROSS JOIN ft5; -- this takes very long
2756 ERROR:  canceling statement due to statement timeout
2757 COMMIT;
2758 -- ====================================================================
2759 -- Check that userid to use when querying the remote table is correctly
2760 -- propagated into foreign rels present in subqueries under an UNION ALL
2761 -- ====================================================================
2762 CREATE ROLE regress_view_owner_another;
2763 ALTER VIEW v4 OWNER TO regress_view_owner_another;
2764 GRANT SELECT ON ft4 TO regress_view_owner_another;
2765 ALTER FOREIGN TABLE ft4 OPTIONS (ADD use_remote_estimate 'true');
2766 -- The following should query the remote backing table of ft4 as user
2767 -- regress_view_owner_another, the view owner, though it fails as expected
2768 -- due to the lack of a user mapping for that user.
2769 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM v4;
2770 ERROR:  user mapping not found for user "regress_view_owner_another", server "loopback"
2771 -- Likewise, but with the query under an UNION ALL
2772 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM (SELECT * FROM v4 UNION ALL SELECT * FROM v4);
2773 ERROR:  user mapping not found for user "regress_view_owner_another", server "loopback"
2774 -- Should not get that error once a user mapping is created
2775 CREATE USER MAPPING FOR regress_view_owner_another SERVER loopback OPTIONS (password_required 'false');
2776 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM v4;
2777                     QUERY PLAN                    
2778 --------------------------------------------------
2779  Foreign Scan on public.ft4
2780    Output: ft4.c1, ft4.c2, ft4.c3
2781    Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3"
2782 (3 rows)
2784 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM (SELECT * FROM v4 UNION ALL SELECT * FROM v4);
2785                        QUERY PLAN                       
2786 --------------------------------------------------------
2787  Append
2788    ->  Foreign Scan on public.ft4
2789          Output: ft4.c1, ft4.c2, ft4.c3
2790          Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3"
2791    ->  Foreign Scan on public.ft4 ft4_1
2792          Output: ft4_1.c1, ft4_1.c2, ft4_1.c3
2793          Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3"
2794 (7 rows)
2796 DROP USER MAPPING FOR regress_view_owner_another SERVER loopback;
2797 DROP OWNED BY regress_view_owner_another;
2798 DROP ROLE regress_view_owner_another;
2799 ALTER FOREIGN TABLE ft4 OPTIONS (SET use_remote_estimate 'false');
2800 -- cleanup
2801 DROP OWNED BY regress_view_owner;
2802 DROP ROLE regress_view_owner;
2803 -- ===================================================================
2804 -- Aggregate and grouping queries
2805 -- ===================================================================
2806 -- Simple aggregates
2807 explain (verbose, costs off)
2808 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;
2809                                                                                               QUERY PLAN                                                                                               
2810 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2811  Foreign Scan
2812    Output: (count(c6)), (sum(c1)), (avg(c1)), (min(c2)), (max(c1)), (stddev(c2)), ((sum(c1)) * ((random() <= '1'::double precision))::integer), c2
2813    Relations: Aggregate on (public.ft1)
2814    Remote SQL: SELECT count(c6), sum("C 1"), avg("C 1"), min(c2), max("C 1"), stddev(c2), c2 FROM "S 1"."T 1" WHERE ((c2 < 5)) GROUP BY 7 ORDER BY count(c6) ASC NULLS LAST, sum("C 1") ASC NULLS LAST
2815 (4 rows)
2817 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;
2818  count |  sum  |         avg          | min | max  | stddev | sum2  
2819 -------+-------+----------------------+-----+------+--------+-------
2820    100 | 49600 | 496.0000000000000000 |   1 |  991 |      0 | 49600
2821    100 | 49700 | 497.0000000000000000 |   2 |  992 |      0 | 49700
2822    100 | 49800 | 498.0000000000000000 |   3 |  993 |      0 | 49800
2823    100 | 49900 | 499.0000000000000000 |   4 |  994 |      0 | 49900
2824    100 | 50500 | 505.0000000000000000 |   0 | 1000 |      0 | 50500
2825 (5 rows)
2827 explain (verbose, costs off)
2828 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 limit 1;
2829                                                                                                       QUERY PLAN                                                                                                       
2830 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2831  Foreign Scan
2832    Output: (count(c6)), (sum(c1)), (avg(c1)), (min(c2)), (max(c1)), (stddev(c2)), ((sum(c1)) * ((random() <= '1'::double precision))::integer), c2
2833    Relations: Aggregate on (public.ft1)
2834    Remote SQL: SELECT count(c6), sum("C 1"), avg("C 1"), min(c2), max("C 1"), stddev(c2), c2 FROM "S 1"."T 1" WHERE ((c2 < 5)) GROUP BY 7 ORDER BY count(c6) ASC NULLS LAST, sum("C 1") ASC NULLS LAST LIMIT 1::bigint
2835 (4 rows)
2837 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 limit 1;
2838  count |  sum  |         avg          | min | max | stddev | sum2  
2839 -------+-------+----------------------+-----+-----+--------+-------
2840    100 | 49600 | 496.0000000000000000 |   1 | 991 |      0 | 49600
2841 (1 row)
2843 -- Aggregate is not pushed down as aggregation contains random()
2844 explain (verbose, costs off)
2845 select sum(c1 * (random() <= 1)::int) as sum, avg(c1) from ft1;
2846                                   QUERY PLAN                                   
2847 -------------------------------------------------------------------------------
2848  Aggregate
2849    Output: sum((c1 * ((random() <= '1'::double precision))::integer)), avg(c1)
2850    ->  Foreign Scan on public.ft1
2851          Output: c1
2852          Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
2853 (5 rows)
2855 -- Aggregate over join query
2856 explain (verbose, costs off)
2857 select count(*), sum(t1.c1), avg(t2.c1) from ft1 t1 inner join ft1 t2 on (t1.c2 = t2.c2) where t1.c2 = 6;
2858                                                                     QUERY PLAN                                                                    
2859 --------------------------------------------------------------------------------------------------------------------------------------------------
2860  Foreign Scan
2861    Output: (count(*)), (sum(t1.c1)), (avg(t2.c1))
2862    Relations: Aggregate on ((public.ft1 t1) INNER JOIN (public.ft1 t2))
2863    Remote SQL: SELECT count(*), sum(r1."C 1"), avg(r2."C 1") FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2.c2 = 6)) AND ((r1.c2 = 6))))
2864 (4 rows)
2866 select count(*), sum(t1.c1), avg(t2.c1) from ft1 t1 inner join ft1 t2 on (t1.c2 = t2.c2) where t1.c2 = 6;
2867  count |   sum   |         avg          
2868 -------+---------+----------------------
2869  10000 | 5010000 | 501.0000000000000000
2870 (1 row)
2872 -- Not pushed down due to local conditions present in underneath input rel
2873 explain (verbose, costs off)
2874 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;
2875                                                          QUERY PLAN                                                         
2876 ----------------------------------------------------------------------------------------------------------------------------
2877  Aggregate
2878    Output: sum(t1.c1), count(t2.c1)
2879    ->  Foreign Scan
2880          Output: t1.c1, t2.c1
2881          Filter: (((((t1.c1 * t2.c1) / (t1.c1 * t2.c1)))::double precision * random()) <= '1'::double precision)
2882          Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2883          Remote SQL: SELECT r1."C 1", r2."C 1" FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1"))))
2884 (7 rows)
2886 -- GROUP BY clause having expressions
2887 explain (verbose, costs off)
2888 select c2/2, sum(c2) * (c2/2) from ft1 group by c2/2 order by c2/2;
2889                                                     QUERY PLAN                                                    
2890 ------------------------------------------------------------------------------------------------------------------
2891  Foreign Scan
2892    Output: ((c2 / 2)), ((sum(c2) * (c2 / 2)))
2893    Relations: Aggregate on (public.ft1)
2894    Remote SQL: SELECT (c2 / 2), (sum(c2) * (c2 / 2)) FROM "S 1"."T 1" GROUP BY 1 ORDER BY (c2 / 2) ASC NULLS LAST
2895 (4 rows)
2897 select c2/2, sum(c2) * (c2/2) from ft1 group by c2/2 order by c2/2;
2898  ?column? | ?column? 
2899 ----------+----------
2900         0 |        0
2901         1 |      500
2902         2 |     1800
2903         3 |     3900
2904         4 |     6800
2905 (5 rows)
2907 -- Aggregates in subquery are pushed down.
2908 set enable_incremental_sort = off;
2909 explain (verbose, costs off)
2910 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;
2911                                                                  QUERY PLAN                                                                  
2912 ---------------------------------------------------------------------------------------------------------------------------------------------
2913  Aggregate
2914    Output: count(ft1.c2), sum(ft1.c2)
2915    ->  Foreign Scan
2916          Output: ft1.c2, (sum(ft1.c1)), (sqrt((ft1.c1)::double precision))
2917          Relations: Aggregate on (public.ft1)
2918          Remote SQL: SELECT c2, sum("C 1"), sqrt("C 1") FROM "S 1"."T 1" GROUP BY 1, 3 ORDER BY c2 ASC NULLS LAST, sum("C 1") ASC NULLS LAST
2919 (6 rows)
2921 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;
2922  count | sum  
2923 -------+------
2924   1000 | 4500
2925 (1 row)
2927 reset enable_incremental_sort;
2928 -- Aggregate is still pushed down by taking unshippable expression out
2929 explain (verbose, costs off)
2930 select c2 * (random() <= 1)::int as sum1, sum(c1) * c2 as sum2 from ft1 group by c2 order by 1, 2;
2931                                             QUERY PLAN                                             
2932 ---------------------------------------------------------------------------------------------------
2933  Sort
2934    Output: ((c2 * ((random() <= '1'::double precision))::integer)), ((sum(c1) * c2)), c2
2935    Sort Key: ((ft1.c2 * ((random() <= '1'::double precision))::integer)), ((sum(ft1.c1) * ft1.c2))
2936    ->  Foreign Scan
2937          Output: (c2 * ((random() <= '1'::double precision))::integer), ((sum(c1) * c2)), c2
2938          Relations: Aggregate on (public.ft1)
2939          Remote SQL: SELECT (sum("C 1") * c2), c2 FROM "S 1"."T 1" GROUP BY 2
2940 (7 rows)
2942 select c2 * (random() <= 1)::int as sum1, sum(c1) * c2 as sum2 from ft1 group by c2 order by 1, 2;
2943  sum1 |  sum2  
2944 ------+--------
2945     0 |      0
2946     1 |  49600
2947     2 |  99400
2948     3 | 149400
2949     4 | 199600
2950     5 | 250000
2951     6 | 300600
2952     7 | 351400
2953     8 | 402400
2954     9 | 453600
2955 (10 rows)
2957 -- Aggregate with unshippable GROUP BY clause are not pushed
2958 explain (verbose, costs off)
2959 select c2 * (random() <= 1)::int as c2 from ft2 group by c2 * (random() <= 1)::int order by 1;
2960                                   QUERY PLAN                                  
2961 ------------------------------------------------------------------------------
2962  Sort
2963    Output: ((c2 * ((random() <= '1'::double precision))::integer))
2964    Sort Key: ((ft2.c2 * ((random() <= '1'::double precision))::integer))
2965    ->  HashAggregate
2966          Output: ((c2 * ((random() <= '1'::double precision))::integer))
2967          Group Key: (ft2.c2 * ((random() <= '1'::double precision))::integer)
2968          ->  Foreign Scan on public.ft2
2969                Output: (c2 * ((random() <= '1'::double precision))::integer)
2970                Remote SQL: SELECT c2 FROM "S 1"."T 1"
2971 (9 rows)
2973 -- GROUP BY clause in various forms, cardinal, alias and constant expression
2974 explain (verbose, costs off)
2975 select count(c2) w, c2 x, 5 y, 7.0 z from ft1 group by 2, y, 9.0::int order by 2;
2976                                                  QUERY PLAN                                                 
2977 ------------------------------------------------------------------------------------------------------------
2978  Foreign Scan
2979    Output: (count(c2)), c2, 5, 7.0, 9
2980    Relations: Aggregate on (public.ft1)
2981    Remote SQL: SELECT count(c2), c2, 5, 7.0, 9 FROM "S 1"."T 1" GROUP BY 2, 3, 5 ORDER BY c2 ASC NULLS LAST
2982 (4 rows)
2984 select count(c2) w, c2 x, 5 y, 7.0 z from ft1 group by 2, y, 9.0::int order by 2;
2985   w  | x | y |  z  
2986 -----+---+---+-----
2987  100 | 0 | 5 | 7.0
2988  100 | 1 | 5 | 7.0
2989  100 | 2 | 5 | 7.0
2990  100 | 3 | 5 | 7.0
2991  100 | 4 | 5 | 7.0
2992  100 | 5 | 5 | 7.0
2993  100 | 6 | 5 | 7.0
2994  100 | 7 | 5 | 7.0
2995  100 | 8 | 5 | 7.0
2996  100 | 9 | 5 | 7.0
2997 (10 rows)
2999 -- GROUP BY clause referring to same column multiple times
3000 -- Also, ORDER BY contains an aggregate function
3001 explain (verbose, costs off)
3002 select c2, c2 from ft1 where c2 > 6 group by 1, 2 order by sum(c1);
3003                                                          QUERY PLAN                                                         
3004 ----------------------------------------------------------------------------------------------------------------------------
3005  Foreign Scan
3006    Output: c2, c2, (sum(c1))
3007    Relations: Aggregate on (public.ft1)
3008    Remote SQL: SELECT c2, c2, sum("C 1") FROM "S 1"."T 1" WHERE ((c2 > 6)) GROUP BY 1, 2 ORDER BY sum("C 1") ASC NULLS LAST
3009 (4 rows)
3011 select c2, c2 from ft1 where c2 > 6 group by 1, 2 order by sum(c1);
3012  c2 | c2 
3013 ----+----
3014   7 |  7
3015   8 |  8
3016   9 |  9
3017 (3 rows)
3019 -- Testing HAVING clause shippability
3020 explain (verbose, costs off)
3021 select c2, sum(c1) from ft2 group by c2 having avg(c1) < 500 and sum(c1) < 49800 order by c2;
3022                                                                          QUERY PLAN                                                                         
3023 ------------------------------------------------------------------------------------------------------------------------------------------------------------
3024  Foreign Scan
3025    Output: c2, (sum(c1))
3026    Relations: Aggregate on (public.ft2)
3027    Remote SQL: SELECT c2, sum("C 1") FROM "S 1"."T 1" GROUP BY 1 HAVING ((avg("C 1") < 500::numeric)) AND ((sum("C 1") < 49800)) ORDER BY c2 ASC NULLS LAST
3028 (4 rows)
3030 select c2, sum(c1) from ft2 group by c2 having avg(c1) < 500 and sum(c1) < 49800 order by c2;
3031  c2 |  sum  
3032 ----+-------
3033   1 | 49600
3034   2 | 49700
3035 (2 rows)
3037 -- Unshippable HAVING clause will be evaluated locally, and other qual in HAVING clause is pushed down
3038 explain (verbose, costs off)
3039 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;
3040                                                               QUERY PLAN                                                               
3041 ---------------------------------------------------------------------------------------------------------------------------------------
3042  Aggregate
3043    Output: count(*)
3044    ->  Foreign Scan
3045          Output: ft1.c5, NULL::bigint, (sqrt((ft1.c2)::double precision))
3046          Filter: (((((avg(ft1.c1)) / (avg(ft1.c1))))::double precision * random()) <= '1'::double precision)
3047          Relations: Aggregate on (public.ft1)
3048          Remote SQL: SELECT c5, NULL::bigint, sqrt(c2), avg("C 1") FROM "S 1"."T 1" GROUP BY 1, 3 HAVING ((avg("C 1") < 500::numeric))
3049 (7 rows)
3051 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;
3052  count 
3053 -------
3054     49
3055 (1 row)
3057 -- Aggregate in HAVING clause is not pushable, and thus aggregation is not pushed down
3058 explain (verbose, costs off)
3059 select sum(c1) from ft1 group by c2 having avg(c1 * (random() <= 1)::int) > 100 order by 1;
3060                                             QUERY PLAN                                             
3061 ---------------------------------------------------------------------------------------------------
3062  Sort
3063    Output: (sum(c1)), c2
3064    Sort Key: (sum(ft1.c1))
3065    ->  HashAggregate
3066          Output: sum(c1), c2
3067          Group Key: ft1.c2
3068          Filter: (avg((ft1.c1 * ((random() <= '1'::double precision))::integer)) > '100'::numeric)
3069          ->  Foreign Scan on public.ft1
3070                Output: c1, c2
3071                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1"
3072 (10 rows)
3074 -- Remote aggregate in combination with a local Param (for the output
3075 -- of an initplan) can be trouble, per bug #15781
3076 explain (verbose, costs off)
3077 select exists(select 1 from pg_enum), sum(c1) from ft1;
3078                     QUERY PLAN                    
3079 --------------------------------------------------
3080  Foreign Scan
3081    Output: (InitPlan 1).col1, (sum(ft1.c1))
3082    Relations: Aggregate on (public.ft1)
3083    Remote SQL: SELECT sum("C 1") FROM "S 1"."T 1"
3084    InitPlan 1
3085      ->  Seq Scan on pg_catalog.pg_enum
3086 (6 rows)
3088 select exists(select 1 from pg_enum), sum(c1) from ft1;
3089  exists |  sum   
3090 --------+--------
3091  t      | 500500
3092 (1 row)
3094 explain (verbose, costs off)
3095 select exists(select 1 from pg_enum), sum(c1) from ft1 group by 1;
3096                     QUERY PLAN                     
3097 ---------------------------------------------------
3098  GroupAggregate
3099    Output: (InitPlan 1).col1, sum(ft1.c1)
3100    InitPlan 1
3101      ->  Seq Scan on pg_catalog.pg_enum
3102    ->  Foreign Scan on public.ft1
3103          Output: ft1.c1
3104          Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
3105 (7 rows)
3107 select exists(select 1 from pg_enum), sum(c1) from ft1 group by 1;
3108  exists |  sum   
3109 --------+--------
3110  t      | 500500
3111 (1 row)
3113 -- Testing ORDER BY, DISTINCT, FILTER, Ordered-sets and VARIADIC within aggregates
3114 -- ORDER BY within aggregate, same column used to order
3115 explain (verbose, costs off)
3116 select array_agg(c1 order by c1) from ft1 where c1 < 100 group by c2 order by 1;
3117                                                                                             QUERY PLAN                                                                                            
3118 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3119  Foreign Scan
3120    Output: (array_agg(c1 ORDER BY c1)), c2
3121    Relations: Aggregate on (public.ft1)
3122    Remote SQL: SELECT array_agg("C 1" ORDER BY "C 1" ASC NULLS LAST), c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) GROUP BY 2 ORDER BY array_agg("C 1" ORDER BY "C 1" ASC NULLS LAST) ASC NULLS LAST
3123 (4 rows)
3125 select array_agg(c1 order by c1) from ft1 where c1 < 100 group by c2 order by 1;
3126            array_agg            
3127 --------------------------------
3128  {1,11,21,31,41,51,61,71,81,91}
3129  {2,12,22,32,42,52,62,72,82,92}
3130  {3,13,23,33,43,53,63,73,83,93}
3131  {4,14,24,34,44,54,64,74,84,94}
3132  {5,15,25,35,45,55,65,75,85,95}
3133  {6,16,26,36,46,56,66,76,86,96}
3134  {7,17,27,37,47,57,67,77,87,97}
3135  {8,18,28,38,48,58,68,78,88,98}
3136  {9,19,29,39,49,59,69,79,89,99}
3137  {10,20,30,40,50,60,70,80,90}
3138 (10 rows)
3140 -- ORDER BY within aggregate, different column used to order also using DESC
3141 explain (verbose, costs off)
3142 select array_agg(c5 order by c1 desc) from ft2 where c2 = 6 and c1 < 50;
3143                                                        QUERY PLAN                                                        
3144 -------------------------------------------------------------------------------------------------------------------------
3145  Foreign Scan
3146    Output: (array_agg(c5 ORDER BY c1 DESC))
3147    Relations: Aggregate on (public.ft2)
3148    Remote SQL: SELECT array_agg(c5 ORDER BY "C 1" DESC NULLS FIRST) FROM "S 1"."T 1" WHERE (("C 1" < 50)) AND ((c2 = 6))
3149 (4 rows)
3151 select array_agg(c5 order by c1 desc) from ft2 where c2 = 6 and c1 < 50;
3152                                                                 array_agg                                                                 
3153 ------------------------------------------------------------------------------------------------------------------------------------------
3154  {"Mon Feb 16 00:00:00 1970","Fri Feb 06 00:00:00 1970","Tue Jan 27 00:00:00 1970","Sat Jan 17 00:00:00 1970","Wed Jan 07 00:00:00 1970"}
3155 (1 row)
3157 -- DISTINCT within aggregate
3158 explain (verbose, costs off)
3159 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;
3160                                                                                                                                QUERY PLAN                                                                                                                               
3161 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3162  Foreign Scan
3163    Output: (array_agg(DISTINCT (t1.c1 % 5))), ((t2.c1 % 3))
3164    Relations: Aggregate on ((public.ft4 t1) FULL JOIN (public.ft5 t2))
3165    Remote SQL: SELECT array_agg(DISTINCT (r1.c1 % 5)), (r2.c1 % 3) FROM ("S 1"."T 3" r1 FULL JOIN "S 1"."T 4" r2 ON (((r1.c1 = r2.c1)))) WHERE (((r1.c1 < 20) OR ((r1.c1 IS NULL) AND (r2.c1 < 5)))) GROUP BY 2 ORDER BY array_agg(DISTINCT (r1.c1 % 5)) ASC NULLS LAST
3166 (4 rows)
3168 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;
3169   array_agg   
3170 --------------
3171  {0,1,2,3,4}
3172  {1,2,3,NULL}
3173 (2 rows)
3175 -- DISTINCT combined with ORDER BY within aggregate
3176 explain (verbose, costs off)
3177 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;
3178                                                                                                                                                                      QUERY PLAN                                                                                                                                                                     
3179 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3180  Foreign Scan
3181    Output: (array_agg(DISTINCT (t1.c1 % 5) ORDER BY (t1.c1 % 5))), ((t2.c1 % 3))
3182    Relations: Aggregate on ((public.ft4 t1) FULL JOIN (public.ft5 t2))
3183    Remote SQL: SELECT array_agg(DISTINCT (r1.c1 % 5) ORDER BY ((r1.c1 % 5)) ASC NULLS LAST), (r2.c1 % 3) FROM ("S 1"."T 3" r1 FULL JOIN "S 1"."T 4" r2 ON (((r1.c1 = r2.c1)))) WHERE (((r1.c1 < 20) OR ((r1.c1 IS NULL) AND (r2.c1 < 5)))) GROUP BY 2 ORDER BY array_agg(DISTINCT (r1.c1 % 5) ORDER BY ((r1.c1 % 5)) ASC NULLS LAST) ASC NULLS LAST
3184 (4 rows)
3186 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;
3187   array_agg   
3188 --------------
3189  {0,1,2,3,4}
3190  {1,2,3,NULL}
3191 (2 rows)
3193 explain (verbose, costs off)
3194 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;
3195                                                                                                                                                                       QUERY PLAN                                                                                                                                                                      
3196 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3197  Foreign Scan
3198    Output: (array_agg(DISTINCT (t1.c1 % 5) ORDER BY (t1.c1 % 5) DESC NULLS LAST)), ((t2.c1 % 3))
3199    Relations: Aggregate on ((public.ft4 t1) FULL JOIN (public.ft5 t2))
3200    Remote SQL: SELECT array_agg(DISTINCT (r1.c1 % 5) ORDER BY ((r1.c1 % 5)) DESC NULLS LAST), (r2.c1 % 3) FROM ("S 1"."T 3" r1 FULL JOIN "S 1"."T 4" r2 ON (((r1.c1 = r2.c1)))) WHERE (((r1.c1 < 20) OR ((r1.c1 IS NULL) AND (r2.c1 < 5)))) GROUP BY 2 ORDER BY array_agg(DISTINCT (r1.c1 % 5) ORDER BY ((r1.c1 % 5)) DESC NULLS LAST) ASC NULLS LAST
3201 (4 rows)
3203 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;
3204   array_agg   
3205 --------------
3206  {3,2,1,NULL}
3207  {4,3,2,1,0}
3208 (2 rows)
3210 -- FILTER within aggregate
3211 explain (verbose, costs off)
3212 select sum(c1) filter (where c1 < 100 and c2 > 5) from ft1 group by c2 order by 1 nulls last;
3213                                                                                          QUERY PLAN                                                                                         
3214 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3215  Foreign Scan
3216    Output: (sum(c1) FILTER (WHERE ((c1 < 100) AND (c2 > 5)))), c2
3217    Relations: Aggregate on (public.ft1)
3218    Remote SQL: SELECT sum("C 1") FILTER (WHERE (("C 1" < 100) AND (c2 > 5))), c2 FROM "S 1"."T 1" GROUP BY 2 ORDER BY sum("C 1") FILTER (WHERE (("C 1" < 100) AND (c2 > 5))) ASC NULLS LAST
3219 (4 rows)
3221 select sum(c1) filter (where c1 < 100 and c2 > 5) from ft1 group by c2 order by 1 nulls last;
3222  sum 
3223 -----
3224  510
3225  520
3226  530
3227  540
3228     
3229     
3230     
3231     
3232     
3233     
3234 (10 rows)
3236 -- DISTINCT, ORDER BY and FILTER within aggregate
3237 explain (verbose, costs off)
3238 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;
3239                                                                                         QUERY PLAN                                                                                        
3240 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3241  Foreign Scan
3242    Output: (sum((c1 % 3))), (sum(DISTINCT (c1 % 3) ORDER BY (c1 % 3)) FILTER (WHERE ((c1 % 3) < 2))), c2
3243    Relations: Aggregate on (public.ft1)
3244    Remote SQL: SELECT sum(("C 1" % 3)), sum(DISTINCT ("C 1" % 3) ORDER BY (("C 1" % 3)) ASC NULLS LAST) FILTER (WHERE (("C 1" % 3) < 2)), c2 FROM "S 1"."T 1" WHERE ((c2 = 6)) GROUP BY 3
3245 (4 rows)
3247 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;
3248  sum | sum | c2 
3249 -----+-----+----
3250   99 |   1 |  6
3251 (1 row)
3253 -- Outer query is aggregation query
3254 explain (verbose, costs off)
3255 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;
3256                                                           QUERY PLAN                                                          
3257 ------------------------------------------------------------------------------------------------------------------------------
3258  Unique
3259    Output: ((SubPlan 1))
3260    ->  Sort
3261          Output: ((SubPlan 1))
3262          Sort Key: ((SubPlan 1))
3263          ->  Foreign Scan
3264                Output: (SubPlan 1)
3265                Relations: Aggregate on (public.ft2 t2)
3266                Remote SQL: SELECT count(*) FILTER (WHERE ((c2 = 6) AND ("C 1" < 10))) FROM "S 1"."T 1" WHERE (((c2 % 6) = 0))
3267                SubPlan 1
3268                  ->  Foreign Scan on public.ft1 t1
3269                        Output: (count(*) FILTER (WHERE ((t2.c2 = 6) AND (t2.c1 < 10))))
3270                        Remote SQL: SELECT NULL FROM "S 1"."T 1" WHERE (("C 1" = 6))
3271 (13 rows)
3273 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;
3274  count 
3275 -------
3276      1
3277 (1 row)
3279 -- Inner query is aggregation query
3280 explain (verbose, costs off)
3281 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;
3282                                                                       QUERY PLAN                                                                      
3283 ------------------------------------------------------------------------------------------------------------------------------------------------------
3284  Unique
3285    Output: ((SubPlan 1))
3286    ->  Sort
3287          Output: ((SubPlan 1))
3288          Sort Key: ((SubPlan 1))
3289          ->  Foreign Scan on public.ft2 t2
3290                Output: (SubPlan 1)
3291                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (((c2 % 6) = 0))
3292                SubPlan 1
3293                  ->  Foreign Scan
3294                        Output: (count(t1.c1) FILTER (WHERE ((t2.c2 = 6) AND (t2.c1 < 10))))
3295                        Relations: Aggregate on (public.ft1 t1)
3296                        Remote SQL: SELECT count("C 1") FILTER (WHERE (($1::integer = 6) AND ($2::integer < 10))) FROM "S 1"."T 1" WHERE (("C 1" = 6))
3297 (13 rows)
3299 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;
3300  count 
3301 -------
3302      0
3303      1
3304 (2 rows)
3306 -- Aggregate not pushed down as FILTER condition is not pushable
3307 explain (verbose, costs off)
3308 select sum(c1) filter (where (c1 / c1) * random() <= 1) from ft1 group by c2 order by 1;
3309                                                        QUERY PLAN                                                       
3310 ------------------------------------------------------------------------------------------------------------------------
3311  Sort
3312    Output: (sum(c1) FILTER (WHERE ((((c1 / c1))::double precision * random()) <= '1'::double precision))), c2
3313    Sort Key: (sum(ft1.c1) FILTER (WHERE ((((ft1.c1 / ft1.c1))::double precision * random()) <= '1'::double precision)))
3314    ->  HashAggregate
3315          Output: sum(c1) FILTER (WHERE ((((c1 / c1))::double precision * random()) <= '1'::double precision)), c2
3316          Group Key: ft1.c2
3317          ->  Foreign Scan on public.ft1
3318                Output: c1, c2
3319                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1"
3320 (9 rows)
3322 explain (verbose, costs off)
3323 select sum(c2) filter (where c2 in (select c2 from ft1 where c2 < 5)) from ft1;
3324                                   QUERY PLAN                                   
3325 -------------------------------------------------------------------------------
3326  Aggregate
3327    Output: sum(ft1.c2) FILTER (WHERE (ANY (ft1.c2 = (hashed SubPlan 1).col1)))
3328    ->  Foreign Scan on public.ft1
3329          Output: ft1.c2
3330          Remote SQL: SELECT c2 FROM "S 1"."T 1"
3331    SubPlan 1
3332      ->  Foreign Scan on public.ft1 ft1_1
3333            Output: ft1_1.c2
3334            Remote SQL: SELECT c2 FROM "S 1"."T 1" WHERE ((c2 < 5))
3335 (9 rows)
3337 -- Ordered-sets within aggregate
3338 explain (verbose, costs off)
3339 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;
3340                                                                                                                                                                            QUERY PLAN                                                                                                                                                                           
3341 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3342  Sort
3343    Output: c2, (rank('10'::character varying) WITHIN GROUP (ORDER BY c6)), (percentile_cont((((c2)::numeric / '10'::numeric))::double precision) WITHIN GROUP (ORDER BY ((c1)::double precision)))
3344    Sort Key: ft1.c2
3345    ->  Foreign Scan
3346          Output: c2, (rank('10'::character varying) WITHIN GROUP (ORDER BY c6)), (percentile_cont((((c2)::numeric / '10'::numeric))::double precision) WITHIN GROUP (ORDER BY ((c1)::double precision)))
3347          Relations: Aggregate on (public.ft1)
3348          Remote SQL: SELECT c2, rank('10'::character varying) WITHIN GROUP (ORDER BY c6 ASC NULLS LAST), percentile_cont((c2 / 10::numeric)) WITHIN GROUP (ORDER BY ("C 1") ASC NULLS LAST) FROM "S 1"."T 1" WHERE ((c2 < 10)) GROUP BY 1 HAVING ((percentile_cont((c2 / 10::numeric)) WITHIN GROUP (ORDER BY ("C 1") ASC NULLS LAST) < 500::double precision))
3349 (7 rows)
3351 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;
3352  c2 | rank | percentile_cont 
3353 ----+------+-----------------
3354   0 |  101 |              10
3355   1 |  101 |             100
3356   2 |    1 |             200
3357   3 |    1 |             300
3358   4 |    1 |             400
3359 (5 rows)
3361 -- Using multiple arguments within aggregates
3362 explain (verbose, costs off)
3363 select c1, rank(c1, c2) within group (order by c1, c2) from ft1 group by c1, c2 having c1 = 6 order by 1;
3364                                                                              QUERY PLAN                                                                             
3365 --------------------------------------------------------------------------------------------------------------------------------------------------------------------
3366  Foreign Scan
3367    Output: c1, (rank(c1, c2) WITHIN GROUP (ORDER BY c1, c2)), c2
3368    Relations: Aggregate on (public.ft1)
3369    Remote SQL: SELECT "C 1", rank("C 1", c2) WITHIN GROUP (ORDER BY "C 1" ASC NULLS LAST, c2 ASC NULLS LAST), c2 FROM "S 1"."T 1" WHERE (("C 1" = 6)) GROUP BY 1, 3
3370 (4 rows)
3372 select c1, rank(c1, c2) within group (order by c1, c2) from ft1 group by c1, c2 having c1 = 6 order by 1;
3373  c1 | rank 
3374 ----+------
3375   6 |    1
3376 (1 row)
3378 -- User defined function for user defined aggregate, VARIADIC
3379 create function least_accum(anyelement, variadic anyarray)
3380 returns anyelement language sql as
3381   'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)';
3382 create aggregate least_agg(variadic items anyarray) (
3383   stype = anyelement, sfunc = least_accum
3385 -- Disable hash aggregation for plan stability.
3386 set enable_hashagg to false;
3387 -- Not pushed down due to user defined aggregate
3388 explain (verbose, costs off)
3389 select c2, least_agg(c1) from ft1 group by c2 order by c2;
3390                                     QUERY PLAN                                    
3391 ----------------------------------------------------------------------------------
3392  GroupAggregate
3393    Output: c2, least_agg(VARIADIC ARRAY[c1])
3394    Group Key: ft1.c2
3395    ->  Foreign Scan on public.ft1
3396          Output: c2, c1
3397          Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" ORDER BY c2 ASC NULLS LAST
3398 (6 rows)
3400 -- Add function and aggregate into extension
3401 alter extension postgres_fdw add function least_accum(anyelement, variadic anyarray);
3402 alter extension postgres_fdw add aggregate least_agg(variadic items anyarray);
3403 alter server loopback options (set extensions 'postgres_fdw');
3404 -- Now aggregate will be pushed.  Aggregate will display VARIADIC argument.
3405 explain (verbose, costs off)
3406 select c2, least_agg(c1) from ft1 where c2 < 100 group by c2 order by c2;
3407                                                       QUERY PLAN                                                       
3408 -----------------------------------------------------------------------------------------------------------------------
3409  Sort
3410    Output: c2, (least_agg(VARIADIC ARRAY[c1]))
3411    Sort Key: ft1.c2
3412    ->  Foreign Scan
3413          Output: c2, (least_agg(VARIADIC ARRAY[c1]))
3414          Relations: Aggregate on (public.ft1)
3415          Remote SQL: SELECT c2, public.least_agg(VARIADIC ARRAY["C 1"]) FROM "S 1"."T 1" WHERE ((c2 < 100)) GROUP BY 1
3416 (7 rows)
3418 select c2, least_agg(c1) from ft1 where c2 < 100 group by c2 order by c2;
3419  c2 | least_agg 
3420 ----+-----------
3421   0 |        10
3422   1 |         1
3423   2 |         2
3424   3 |         3
3425   4 |         4
3426   5 |         5
3427   6 |         6
3428   7 |         7
3429   8 |         8
3430   9 |         9
3431 (10 rows)
3433 -- Remove function and aggregate from extension
3434 alter extension postgres_fdw drop function least_accum(anyelement, variadic anyarray);
3435 alter extension postgres_fdw drop aggregate least_agg(variadic items anyarray);
3436 alter server loopback options (set extensions 'postgres_fdw');
3437 -- Not pushed down as we have dropped objects from extension.
3438 explain (verbose, costs off)
3439 select c2, least_agg(c1) from ft1 group by c2 order by c2;
3440                                     QUERY PLAN                                    
3441 ----------------------------------------------------------------------------------
3442  GroupAggregate
3443    Output: c2, least_agg(VARIADIC ARRAY[c1])
3444    Group Key: ft1.c2
3445    ->  Foreign Scan on public.ft1
3446          Output: c2, c1
3447          Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" ORDER BY c2 ASC NULLS LAST
3448 (6 rows)
3450 -- Cleanup
3451 reset enable_hashagg;
3452 drop aggregate least_agg(variadic items anyarray);
3453 drop function least_accum(anyelement, variadic anyarray);
3454 -- Testing USING OPERATOR() in ORDER BY within aggregate.
3455 -- For this, we need user defined operators along with operator family and
3456 -- operator class.  Create those and then add them in extension.  Note that
3457 -- user defined objects are considered unshippable unless they are part of
3458 -- the extension.
3459 create operator public.<^ (
3460  leftarg = int4,
3461  rightarg = int4,
3462  procedure = int4eq
3464 create operator public.=^ (
3465  leftarg = int4,
3466  rightarg = int4,
3467  procedure = int4lt
3469 create operator public.>^ (
3470  leftarg = int4,
3471  rightarg = int4,
3472  procedure = int4gt
3474 create operator family my_op_family using btree;
3475 create function my_op_cmp(a int, b int) returns int as
3476   $$begin return btint4cmp(a, b); end $$ language plpgsql;
3477 create operator class my_op_class for type int using btree family my_op_family as
3478  operator 1 public.<^,
3479  operator 3 public.=^,
3480  operator 5 public.>^,
3481  function 1 my_op_cmp(int, int);
3482 -- This will not be pushed as user defined sort operator is not part of the
3483 -- extension yet.
3484 explain (verbose, costs off)
3485 select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
3486                                             QUERY PLAN                                            
3487 --------------------------------------------------------------------------------------------------
3488  GroupAggregate
3489    Output: array_agg(c1 ORDER BY c1 USING <^ NULLS LAST), c2
3490    ->  Sort
3491          Output: c1, c2
3492          Sort Key: ft2.c1 USING <^
3493          ->  Foreign Scan on public.ft2
3494                Output: c1, c2
3495                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6))
3496 (8 rows)
3498 -- This should not be pushed either.
3499 explain (verbose, costs off)
3500 select * from ft2 order by c1 using operator(public.<^);
3501                                   QUERY PLAN                                   
3502 -------------------------------------------------------------------------------
3503  Sort
3504    Output: c1, c2, c3, c4, c5, c6, c7, c8
3505    Sort Key: ft2.c1 USING <^
3506    ->  Foreign Scan on public.ft2
3507          Output: c1, c2, c3, c4, c5, c6, c7, c8
3508          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
3509 (6 rows)
3511 -- Update local stats on ft2
3512 ANALYZE ft2;
3513 -- Add into extension
3514 alter extension postgres_fdw add operator class my_op_class using btree;
3515 alter extension postgres_fdw add function my_op_cmp(a int, b int);
3516 alter extension postgres_fdw add operator family my_op_family using btree;
3517 alter extension postgres_fdw add operator public.<^(int, int);
3518 alter extension postgres_fdw add operator public.=^(int, int);
3519 alter extension postgres_fdw add operator public.>^(int, int);
3520 alter server loopback options (set extensions 'postgres_fdw');
3521 -- Now this will be pushed as sort operator is part of the extension.
3522 alter server loopback options (add fdw_tuple_cost '0.5');
3523 explain (verbose, costs off)
3524 select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
3525                                                                            QUERY PLAN                                                                           
3526 ----------------------------------------------------------------------------------------------------------------------------------------------------------------
3527  Foreign Scan
3528    Output: (array_agg(c1 ORDER BY c1 USING <^ NULLS LAST)), c2
3529    Relations: Aggregate on (public.ft2)
3530    Remote SQL: SELECT array_agg("C 1" ORDER BY "C 1" USING OPERATOR(public.<^) NULLS LAST), c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6)) GROUP BY 2
3531 (4 rows)
3533 select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
3534            array_agg            
3535 --------------------------------
3536  {6,16,26,36,46,56,66,76,86,96}
3537 (1 row)
3539 alter server loopback options (drop fdw_tuple_cost);
3540 -- This should be pushed too.
3541 explain (verbose, costs off)
3542 select * from ft2 order by c1 using operator(public.<^);
3543                                                          QUERY PLAN                                                          
3544 -----------------------------------------------------------------------------------------------------------------------------
3545  Foreign Scan on public.ft2
3546    Output: c1, c2, c3, c4, c5, c6, c7, c8
3547    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY "C 1" USING OPERATOR(public.<^) NULLS LAST
3548 (3 rows)
3550 -- Remove from extension
3551 alter extension postgres_fdw drop operator class my_op_class using btree;
3552 alter extension postgres_fdw drop function my_op_cmp(a int, b int);
3553 alter extension postgres_fdw drop operator family my_op_family using btree;
3554 alter extension postgres_fdw drop operator public.<^(int, int);
3555 alter extension postgres_fdw drop operator public.=^(int, int);
3556 alter extension postgres_fdw drop operator public.>^(int, int);
3557 alter server loopback options (set extensions 'postgres_fdw');
3558 -- This will not be pushed as sort operator is now removed from the extension.
3559 explain (verbose, costs off)
3560 select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
3561                                             QUERY PLAN                                            
3562 --------------------------------------------------------------------------------------------------
3563  GroupAggregate
3564    Output: array_agg(c1 ORDER BY c1 USING <^ NULLS LAST), c2
3565    ->  Sort
3566          Output: c1, c2
3567          Sort Key: ft2.c1 USING <^
3568          ->  Foreign Scan on public.ft2
3569                Output: c1, c2
3570                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6))
3571 (8 rows)
3573 -- Cleanup
3574 drop operator class my_op_class using btree;
3575 drop function my_op_cmp(a int, b int);
3576 drop operator family my_op_family using btree;
3577 drop operator public.>^(int, int);
3578 drop operator public.=^(int, int);
3579 drop operator public.<^(int, int);
3580 -- Input relation to aggregate push down hook is not safe to pushdown and thus
3581 -- the aggregate cannot be pushed down to foreign server.
3582 explain (verbose, costs off)
3583 select count(t1.c3) from ft2 t1 left join ft2 t2 on (t1.c1 = random() * t2.c2);
3584                                         QUERY PLAN                                         
3585 -------------------------------------------------------------------------------------------
3586  Aggregate
3587    Output: count(t1.c3)
3588    ->  Nested Loop Left Join
3589          Output: t1.c3
3590          Join Filter: ((t1.c1)::double precision = (random() * (t2.c2)::double precision))
3591          ->  Foreign Scan on public.ft2 t1
3592                Output: t1.c3, t1.c1
3593                Remote SQL: SELECT "C 1", c3 FROM "S 1"."T 1"
3594          ->  Materialize
3595                Output: t2.c2
3596                ->  Foreign Scan on public.ft2 t2
3597                      Output: t2.c2
3598                      Remote SQL: SELECT c2 FROM "S 1"."T 1"
3599 (13 rows)
3601 -- Subquery in FROM clause having aggregate
3602 explain (verbose, costs off)
3603 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;
3604                                           QUERY PLAN                                           
3605 -----------------------------------------------------------------------------------------------
3606  Sort
3607    Output: (count(*)), x.b
3608    Sort Key: (count(*)), x.b
3609    ->  HashAggregate
3610          Output: count(*), x.b
3611          Group Key: x.b
3612          ->  Hash Join
3613                Output: x.b
3614                Inner Unique: true
3615                Hash Cond: (ft1.c2 = x.a)
3616                ->  Foreign Scan on public.ft1
3617                      Output: ft1.c2
3618                      Remote SQL: SELECT c2 FROM "S 1"."T 1"
3619                ->  Hash
3620                      Output: x.b, x.a
3621                      ->  Subquery Scan on x
3622                            Output: x.b, x.a
3623                            ->  Foreign Scan
3624                                  Output: ft1_1.c2, (sum(ft1_1.c1))
3625                                  Relations: Aggregate on (public.ft1 ft1_1)
3626                                  Remote SQL: SELECT c2, sum("C 1") FROM "S 1"."T 1" GROUP BY 1
3627 (21 rows)
3629 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;
3630  count |   b   
3631 -------+-------
3632    100 | 49600
3633    100 | 49700
3634    100 | 49800
3635    100 | 49900
3636    100 | 50000
3637    100 | 50100
3638    100 | 50200
3639    100 | 50300
3640    100 | 50400
3641    100 | 50500
3642 (10 rows)
3644 -- FULL join with IS NULL check in HAVING
3645 explain (verbose, costs off)
3646 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;
3647                                                                                                                                     QUERY PLAN                                                                                                                                     
3648 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3649  Foreign Scan
3650    Output: (avg(t1.c1)), (sum(t2.c1)), t2.c1
3651    Relations: Aggregate on ((public.ft4 t1) FULL JOIN (public.ft5 t2))
3652    Remote SQL: SELECT avg(r1.c1), sum(r2.c1), r2.c1 FROM ("S 1"."T 3" r1 FULL JOIN "S 1"."T 4" r2 ON (((r1.c1 = r2.c1)))) GROUP BY 3 HAVING ((((avg(r1.c1) IS NULL) AND (sum(r2.c1) < 10)) OR (sum(r2.c1) IS NULL))) ORDER BY avg(r1.c1) ASC NULLS LAST, sum(r2.c1) ASC NULLS LAST
3653 (4 rows)
3655 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;
3656          avg         | sum 
3657 ---------------------+-----
3658  51.0000000000000000 |    
3659                      |   3
3660                      |   9
3661 (3 rows)
3663 -- Aggregate over FULL join needing to deparse the joining relations as
3664 -- subqueries.
3665 explain (verbose, costs off)
3666 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);
3667                                                                                                                   QUERY PLAN                                                                                                                   
3668 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3669  Foreign Scan
3670    Output: (count(*)), (sum(ft4.c1)), (avg(ft5.c1))
3671    Relations: Aggregate on ((public.ft4) FULL JOIN (public.ft5))
3672    Remote SQL: SELECT count(*), sum(s4.c1), avg(s5.c1) FROM ((SELECT c1 FROM "S 1"."T 3" WHERE ((c1 >= 50)) AND ((c1 <= 60))) s4(c1) FULL JOIN (SELECT c1 FROM "S 1"."T 4" WHERE ((c1 >= 50)) AND ((c1 <= 60))) s5(c1) ON (((s4.c1 = s5.c1))))
3673 (4 rows)
3675 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);
3676  count | sum |         avg         
3677 -------+-----+---------------------
3678      8 | 330 | 55.5000000000000000
3679 (1 row)
3681 -- ORDER BY expression is part of the target list but not pushed down to
3682 -- foreign server.
3683 explain (verbose, costs off)
3684 select sum(c2) * (random() <= 1)::int as sum from ft1 order by 1;
3685                                    QUERY PLAN                                   
3686 --------------------------------------------------------------------------------
3687  Sort
3688    Output: (((sum(c2)) * ((random() <= '1'::double precision))::integer))
3689    Sort Key: (((sum(ft1.c2)) * ((random() <= '1'::double precision))::integer))
3690    ->  Foreign Scan
3691          Output: ((sum(c2)) * ((random() <= '1'::double precision))::integer)
3692          Relations: Aggregate on (public.ft1)
3693          Remote SQL: SELECT sum(c2) FROM "S 1"."T 1"
3694 (7 rows)
3696 select sum(c2) * (random() <= 1)::int as sum from ft1 order by 1;
3697  sum  
3698 ------
3699  4500
3700 (1 row)
3702 -- LATERAL join, with parameterization
3703 set enable_hashagg to false;
3704 explain (verbose, costs off)
3705 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;
3706                                               QUERY PLAN                                              
3707 ------------------------------------------------------------------------------------------------------
3708  Sort
3709    Output: t1.c2, qry.sum
3710    Sort Key: t1.c2
3711    ->  Nested Loop
3712          Output: t1.c2, qry.sum
3713          ->  Index Scan using t1_pkey on "S 1"."T 1" t1
3714                Output: t1."C 1", t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8
3715                Index Cond: (t1."C 1" < 100)
3716                Filter: (t1.c2 < 3)
3717          ->  Subquery Scan on qry
3718                Output: qry.sum, t2.c1
3719                Filter: ((t1.c2 * 2) = qry.sum)
3720                ->  Foreign Scan
3721                      Output: (sum((t2.c1 + t1."C 1"))), t2.c1
3722                      Relations: Aggregate on (public.ft2 t2)
3723                      Remote SQL: SELECT sum(("C 1" + $1::integer)), "C 1" FROM "S 1"."T 1" GROUP BY 2
3724 (16 rows)
3726 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;
3727  c2 | sum 
3728 ----+-----
3729   1 |   2
3730   2 |   4
3731 (2 rows)
3733 reset enable_hashagg;
3734 -- bug #15613: bad plan for foreign table scan with lateral reference
3735 EXPLAIN (VERBOSE, COSTS OFF)
3736 SELECT ref_0.c2, subq_1.*
3737 FROM
3738     "S 1"."T 1" AS ref_0,
3739     LATERAL (
3740         SELECT ref_0."C 1" c1, subq_0.*
3741         FROM (SELECT ref_0.c2, ref_1.c3
3742               FROM ft1 AS ref_1) AS subq_0
3743              RIGHT JOIN ft2 AS ref_3 ON (subq_0.c3 = ref_3.c3)
3744     ) AS subq_1
3745 WHERE ref_0."C 1" < 10 AND subq_1.c3 = '00001'
3746 ORDER BY ref_0."C 1";
3747                                                QUERY PLAN                                                
3748 ---------------------------------------------------------------------------------------------------------
3749  Nested Loop
3750    Output: ref_0.c2, ref_0."C 1", (ref_0.c2), ref_1.c3, ref_0."C 1"
3751    ->  Nested Loop
3752          Output: ref_0.c2, ref_0."C 1", ref_1.c3, (ref_0.c2)
3753          ->  Index Scan using t1_pkey on "S 1"."T 1" ref_0
3754                Output: ref_0."C 1", ref_0.c2, ref_0.c3, ref_0.c4, ref_0.c5, ref_0.c6, ref_0.c7, ref_0.c8
3755                Index Cond: (ref_0."C 1" < 10)
3756          ->  Foreign Scan on public.ft1 ref_1
3757                Output: ref_1.c3, ref_0.c2
3758                Remote SQL: SELECT c3 FROM "S 1"."T 1" WHERE ((c3 = '00001'))
3759    ->  Materialize
3760          Output: ref_3.c3
3761          ->  Foreign Scan on public.ft2 ref_3
3762                Output: ref_3.c3
3763                Remote SQL: SELECT c3 FROM "S 1"."T 1" WHERE ((c3 = '00001'))
3764 (15 rows)
3766 SELECT ref_0.c2, subq_1.*
3767 FROM
3768     "S 1"."T 1" AS ref_0,
3769     LATERAL (
3770         SELECT ref_0."C 1" c1, subq_0.*
3771         FROM (SELECT ref_0.c2, ref_1.c3
3772               FROM ft1 AS ref_1) AS subq_0
3773              RIGHT JOIN ft2 AS ref_3 ON (subq_0.c3 = ref_3.c3)
3774     ) AS subq_1
3775 WHERE ref_0."C 1" < 10 AND subq_1.c3 = '00001'
3776 ORDER BY ref_0."C 1";
3777  c2 | c1 | c2 |  c3   
3778 ----+----+----+-------
3779   1 |  1 |  1 | 00001
3780   2 |  2 |  2 | 00001
3781   3 |  3 |  3 | 00001
3782   4 |  4 |  4 | 00001
3783   5 |  5 |  5 | 00001
3784   6 |  6 |  6 | 00001
3785   7 |  7 |  7 | 00001
3786   8 |  8 |  8 | 00001
3787   9 |  9 |  9 | 00001
3788 (9 rows)
3790 -- Check with placeHolderVars
3791 explain (verbose, costs off)
3792 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);
3793                                                                         QUERY PLAN                                                                        
3794 ----------------------------------------------------------------------------------------------------------------------------------------------------------
3795  Aggregate
3796    Output: sum(q.a), count(q.b)
3797    ->  Nested Loop Left Join
3798          Output: q.a, q.b
3799          Inner Unique: true
3800          Join Filter: ((ft4.c1)::numeric <= q.b)
3801          ->  Foreign Scan on public.ft4
3802                Output: ft4.c1, ft4.c2, ft4.c3
3803                Remote SQL: SELECT c1 FROM "S 1"."T 3"
3804          ->  Materialize
3805                Output: q.a, q.b
3806                ->  Subquery Scan on q
3807                      Output: q.a, q.b
3808                      ->  Foreign Scan
3809                            Output: 13, (avg(ft1.c1)), NULL::bigint
3810                            Relations: Aggregate on ((public.ft2) LEFT JOIN (public.ft1))
3811                            Remote SQL: SELECT 13, avg(r1."C 1"), NULL::bigint FROM ("S 1"."T 1" r2 LEFT JOIN "S 1"."T 1" r1 ON (((r1."C 1" = r2."C 1"))))
3812 (17 rows)
3814 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);
3815  sum | count 
3816 -----+-------
3817  650 |    50
3818 (1 row)
3820 -- Not supported cases
3821 -- Grouping sets
3822 explain (verbose, costs off)
3823 select c2, sum(c1) from ft1 where c2 < 3 group by rollup(c2) order by 1 nulls last;
3824                                   QUERY PLAN                                  
3825 ------------------------------------------------------------------------------
3826  Sort
3827    Output: c2, (sum(c1))
3828    Sort Key: ft1.c2
3829    ->  MixedAggregate
3830          Output: c2, sum(c1)
3831          Hash Key: ft1.c2
3832          Group Key: ()
3833          ->  Foreign Scan on public.ft1
3834                Output: c2, c1
3835                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE ((c2 < 3))
3836 (10 rows)
3838 select c2, sum(c1) from ft1 where c2 < 3 group by rollup(c2) order by 1 nulls last;
3839  c2 |  sum   
3840 ----+--------
3841   0 |  50500
3842   1 |  49600
3843   2 |  49700
3844     | 149800
3845 (4 rows)
3847 explain (verbose, costs off)
3848 select c2, sum(c1) from ft1 where c2 < 3 group by cube(c2) order by 1 nulls last;
3849                                   QUERY PLAN                                  
3850 ------------------------------------------------------------------------------
3851  Sort
3852    Output: c2, (sum(c1))
3853    Sort Key: ft1.c2
3854    ->  MixedAggregate
3855          Output: c2, sum(c1)
3856          Hash Key: ft1.c2
3857          Group Key: ()
3858          ->  Foreign Scan on public.ft1
3859                Output: c2, c1
3860                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE ((c2 < 3))
3861 (10 rows)
3863 select c2, sum(c1) from ft1 where c2 < 3 group by cube(c2) order by 1 nulls last;
3864  c2 |  sum   
3865 ----+--------
3866   0 |  50500
3867   1 |  49600
3868   2 |  49700
3869     | 149800
3870 (4 rows)
3872 explain (verbose, costs off)
3873 select c2, c6, sum(c1) from ft1 where c2 < 3 group by grouping sets(c2, c6) order by 1 nulls last, 2 nulls last;
3874                                     QUERY PLAN                                    
3875 ----------------------------------------------------------------------------------
3876  Sort
3877    Output: c2, c6, (sum(c1))
3878    Sort Key: ft1.c2, ft1.c6
3879    ->  HashAggregate
3880          Output: c2, c6, sum(c1)
3881          Hash Key: ft1.c2
3882          Hash Key: ft1.c6
3883          ->  Foreign Scan on public.ft1
3884                Output: c2, c6, c1
3885                Remote SQL: SELECT "C 1", c2, c6 FROM "S 1"."T 1" WHERE ((c2 < 3))
3886 (10 rows)
3888 select c2, c6, sum(c1) from ft1 where c2 < 3 group by grouping sets(c2, c6) order by 1 nulls last, 2 nulls last;
3889  c2 | c6 |  sum  
3890 ----+----+-------
3891   0 |    | 50500
3892   1 |    | 49600
3893   2 |    | 49700
3894     | 0  | 50500
3895     | 1  | 49600
3896     | 2  | 49700
3897 (6 rows)
3899 explain (verbose, costs off)
3900 select c2, sum(c1), grouping(c2) from ft1 where c2 < 3 group by c2 order by 1 nulls last;
3901                                   QUERY PLAN                                  
3902 ------------------------------------------------------------------------------
3903  Sort
3904    Output: c2, (sum(c1)), (GROUPING(c2))
3905    Sort Key: ft1.c2
3906    ->  HashAggregate
3907          Output: c2, sum(c1), GROUPING(c2)
3908          Group Key: ft1.c2
3909          ->  Foreign Scan on public.ft1
3910                Output: c2, c1
3911                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE ((c2 < 3))
3912 (9 rows)
3914 select c2, sum(c1), grouping(c2) from ft1 where c2 < 3 group by c2 order by 1 nulls last;
3915  c2 |  sum  | grouping 
3916 ----+-------+----------
3917   0 | 50500 |        0
3918   1 | 49600 |        0
3919   2 | 49700 |        0
3920 (3 rows)
3922 -- DISTINCT itself is not pushed down, whereas underneath aggregate is pushed
3923 explain (verbose, costs off)
3924 select distinct sum(c1)/1000 s from ft2 where c2 < 6 group by c2 order by 1;
3925                                               QUERY PLAN                                               
3926 -------------------------------------------------------------------------------------------------------
3927  Unique
3928    Output: ((sum(c1) / 1000)), c2
3929    ->  Sort
3930          Output: ((sum(c1) / 1000)), c2
3931          Sort Key: ((sum(ft2.c1) / 1000))
3932          ->  Foreign Scan
3933                Output: ((sum(c1) / 1000)), c2
3934                Relations: Aggregate on (public.ft2)
3935                Remote SQL: SELECT (sum("C 1") / 1000), c2 FROM "S 1"."T 1" WHERE ((c2 < 6)) GROUP BY 2
3936 (9 rows)
3938 select distinct sum(c1)/1000 s from ft2 where c2 < 6 group by c2 order by 1;
3939  s  
3940 ----
3941  49
3942  50
3943 (2 rows)
3945 -- WindowAgg
3946 explain (verbose, costs off)
3947 select c2, sum(c2), count(c2) over (partition by c2%2) from ft2 where c2 < 10 group by c2 order by 1;
3948                                                  QUERY PLAN                                                 
3949 ------------------------------------------------------------------------------------------------------------
3950  Sort
3951    Output: c2, (sum(c2)), (count(c2) OVER (?)), ((c2 % 2))
3952    Sort Key: ft2.c2
3953    ->  WindowAgg
3954          Output: c2, (sum(c2)), count(c2) OVER (?), ((c2 % 2))
3955          ->  Sort
3956                Output: c2, ((c2 % 2)), (sum(c2))
3957                Sort Key: ((ft2.c2 % 2))
3958                ->  Foreign Scan
3959                      Output: c2, ((c2 % 2)), (sum(c2))
3960                      Relations: Aggregate on (public.ft2)
3961                      Remote SQL: SELECT c2, (c2 % 2), sum(c2) FROM "S 1"."T 1" WHERE ((c2 < 10)) GROUP BY 1
3962 (12 rows)
3964 select c2, sum(c2), count(c2) over (partition by c2%2) from ft2 where c2 < 10 group by c2 order by 1;
3965  c2 | sum | count 
3966 ----+-----+-------
3967   0 |   0 |     5
3968   1 | 100 |     5
3969   2 | 200 |     5
3970   3 | 300 |     5
3971   4 | 400 |     5
3972   5 | 500 |     5
3973   6 | 600 |     5
3974   7 | 700 |     5
3975   8 | 800 |     5
3976   9 | 900 |     5
3977 (10 rows)
3979 explain (verbose, costs off)
3980 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;
3981                                             QUERY PLAN                                             
3982 ---------------------------------------------------------------------------------------------------
3983  Sort
3984    Output: c2, (array_agg(c2) OVER (?)), ((c2 % 2))
3985    Sort Key: ft1.c2
3986    ->  WindowAgg
3987          Output: c2, array_agg(c2) OVER (?), ((c2 % 2))
3988          ->  Sort
3989                Output: c2, ((c2 % 2))
3990                Sort Key: ((ft1.c2 % 2)), ft1.c2 DESC
3991                ->  Foreign Scan
3992                      Output: c2, ((c2 % 2))
3993                      Relations: Aggregate on (public.ft1)
3994                      Remote SQL: SELECT c2, (c2 % 2) FROM "S 1"."T 1" WHERE ((c2 < 10)) GROUP BY 1
3995 (12 rows)
3997 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;
3998  c2 |  array_agg  
3999 ----+-------------
4000   0 | {8,6,4,2,0}
4001   1 | {9,7,5,3,1}
4002   2 | {8,6,4,2}
4003   3 | {9,7,5,3}
4004   4 | {8,6,4}
4005   5 | {9,7,5}
4006   6 | {8,6}
4007   7 | {9,7}
4008   8 | {8}
4009   9 | {9}
4010 (10 rows)
4012 explain (verbose, costs off)
4013 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;
4014                                             QUERY PLAN                                             
4015 ---------------------------------------------------------------------------------------------------
4016  Sort
4017    Output: c2, (array_agg(c2) OVER (?)), ((c2 % 2))
4018    Sort Key: ft1.c2
4019    ->  WindowAgg
4020          Output: c2, array_agg(c2) OVER (?), ((c2 % 2))
4021          ->  Sort
4022                Output: c2, ((c2 % 2))
4023                Sort Key: ((ft1.c2 % 2)), ft1.c2
4024                ->  Foreign Scan
4025                      Output: c2, ((c2 % 2))
4026                      Relations: Aggregate on (public.ft1)
4027                      Remote SQL: SELECT c2, (c2 % 2) FROM "S 1"."T 1" WHERE ((c2 < 10)) GROUP BY 1
4028 (12 rows)
4030 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;
4031  c2 |  array_agg  
4032 ----+-------------
4033   0 | {0,2,4,6,8}
4034   1 | {1,3,5,7,9}
4035   2 | {2,4,6,8}
4036   3 | {3,5,7,9}
4037   4 | {4,6,8}
4038   5 | {5,7,9}
4039   6 | {6,8}
4040   7 | {7,9}
4041   8 | {8}
4042   9 | {9}
4043 (10 rows)
4045 -- ===================================================================
4046 -- parameterized queries
4047 -- ===================================================================
4048 -- simple join
4049 PREPARE st1(int, int) AS SELECT t1.c3, t2.c3 FROM ft1 t1, ft2 t2 WHERE t1.c1 = $1 AND t2.c1 = $2;
4050 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st1(1, 2);
4051                                                           QUERY PLAN                                                          
4052 ------------------------------------------------------------------------------------------------------------------------------
4053  Foreign Scan
4054    Output: t1.c3, t2.c3
4055    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
4056    Remote SQL: SELECT r1.c3, r2.c3 FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = 2)) AND ((r1."C 1" = 1))))
4057 (4 rows)
4059 EXECUTE st1(1, 1);
4060   c3   |  c3   
4061 -------+-------
4062  00001 | 00001
4063 (1 row)
4065 EXECUTE st1(101, 101);
4066   c3   |  c3   
4067 -------+-------
4068  00101 | 00101
4069 (1 row)
4071 SET enable_hashjoin TO off;
4072 SET enable_sort TO off;
4073 -- subquery using stable function (can't be sent to remote)
4074 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;
4075 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st2(10, 20);
4076                                                             QUERY PLAN                                                            
4077 ----------------------------------------------------------------------------------------------------------------------------------
4078  Nested Loop Semi Join
4079    Output: t1.c1, t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8
4080    Join Filter: (t2.c3 = t1.c3)
4081    ->  Foreign Scan on public.ft1 t1
4082          Output: t1.c1, t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8
4083          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" < 20)) ORDER BY "C 1" ASC NULLS LAST
4084    ->  Materialize
4085          Output: t2.c3
4086          ->  Foreign Scan on public.ft2 t2
4087                Output: t2.c3
4088                Filter: (date(t2.c4) = '01-17-1970'::date)
4089                Remote SQL: SELECT c3, c4 FROM "S 1"."T 1" WHERE (("C 1" > 10))
4090 (12 rows)
4092 EXECUTE st2(10, 20);
4093  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4094 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4095  16 |  6 | 00016 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
4096 (1 row)
4098 EXECUTE st2(101, 121);
4099  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4100 -----+----+-------+------------------------------+--------------------------+----+------------+-----
4101  116 |  6 | 00116 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
4102 (1 row)
4104 RESET enable_hashjoin;
4105 RESET enable_sort;
4106 -- subquery using immutable function (can be sent to remote)
4107 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;
4108 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st3(10, 20);
4109                                                                                                                                            QUERY PLAN                                                                                                                                            
4110 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4111  Foreign Scan
4112    Output: t1.c1, t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8
4113    Relations: (public.ft1 t1) SEMI JOIN (public.ft2 t2)
4114    Remote SQL: SELECT r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM "S 1"."T 1" r1 WHERE ((r1."C 1" < 20)) AND EXISTS (SELECT NULL FROM "S 1"."T 1" r3 WHERE ((r3."C 1" > 10)) AND ((date(r3.c5) = '1970-01-17'::date)) AND ((r3.c3 = r1.c3))) ORDER BY r1."C 1" ASC NULLS LAST
4115 (4 rows)
4117 EXECUTE st3(10, 20);
4118  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4119 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4120  16 |  6 | 00016 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
4121 (1 row)
4123 EXECUTE st3(20, 30);
4124  c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 
4125 ----+----+----+----+----+----+----+----
4126 (0 rows)
4128 -- custom plan should be chosen initially
4129 PREPARE st4(int) AS SELECT * FROM ft1 t1 WHERE t1.c1 = $1;
4130 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
4131                                          QUERY PLAN                                          
4132 ---------------------------------------------------------------------------------------------
4133  Foreign Scan on public.ft1 t1
4134    Output: c1, c2, c3, c4, c5, c6, c7, c8
4135    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4136 (3 rows)
4138 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
4139                                          QUERY PLAN                                          
4140 ---------------------------------------------------------------------------------------------
4141  Foreign Scan on public.ft1 t1
4142    Output: c1, c2, c3, c4, c5, c6, c7, c8
4143    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4144 (3 rows)
4146 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
4147                                          QUERY PLAN                                          
4148 ---------------------------------------------------------------------------------------------
4149  Foreign Scan on public.ft1 t1
4150    Output: c1, c2, c3, c4, c5, c6, c7, c8
4151    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4152 (3 rows)
4154 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
4155                                          QUERY PLAN                                          
4156 ---------------------------------------------------------------------------------------------
4157  Foreign Scan on public.ft1 t1
4158    Output: c1, c2, c3, c4, c5, c6, c7, c8
4159    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4160 (3 rows)
4162 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
4163                                          QUERY PLAN                                          
4164 ---------------------------------------------------------------------------------------------
4165  Foreign Scan on public.ft1 t1
4166    Output: c1, c2, c3, c4, c5, c6, c7, c8
4167    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4168 (3 rows)
4170 -- once we try it enough times, should switch to generic plan
4171 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
4172                                               QUERY PLAN                                               
4173 -------------------------------------------------------------------------------------------------------
4174  Foreign Scan on public.ft1 t1
4175    Output: c1, c2, c3, c4, c5, c6, c7, c8
4176    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = $1::integer))
4177 (3 rows)
4179 -- value of $1 should not be sent to remote
4180 PREPARE st5(user_enum,int) AS SELECT * FROM ft1 t1 WHERE c8 = $1 and c1 = $2;
4181 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
4182                                          QUERY PLAN                                          
4183 ---------------------------------------------------------------------------------------------
4184  Foreign Scan on public.ft1 t1
4185    Output: c1, c2, c3, c4, c5, c6, c7, c8
4186    Filter: (t1.c8 = 'foo'::user_enum)
4187    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4188 (4 rows)
4190 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
4191                                          QUERY PLAN                                          
4192 ---------------------------------------------------------------------------------------------
4193  Foreign Scan on public.ft1 t1
4194    Output: c1, c2, c3, c4, c5, c6, c7, c8
4195    Filter: (t1.c8 = 'foo'::user_enum)
4196    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4197 (4 rows)
4199 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
4200                                          QUERY PLAN                                          
4201 ---------------------------------------------------------------------------------------------
4202  Foreign Scan on public.ft1 t1
4203    Output: c1, c2, c3, c4, c5, c6, c7, c8
4204    Filter: (t1.c8 = 'foo'::user_enum)
4205    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4206 (4 rows)
4208 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
4209                                          QUERY PLAN                                          
4210 ---------------------------------------------------------------------------------------------
4211  Foreign Scan on public.ft1 t1
4212    Output: c1, c2, c3, c4, c5, c6, c7, c8
4213    Filter: (t1.c8 = 'foo'::user_enum)
4214    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4215 (4 rows)
4217 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
4218                                          QUERY PLAN                                          
4219 ---------------------------------------------------------------------------------------------
4220  Foreign Scan on public.ft1 t1
4221    Output: c1, c2, c3, c4, c5, c6, c7, c8
4222    Filter: (t1.c8 = 'foo'::user_enum)
4223    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4224 (4 rows)
4226 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
4227                                               QUERY PLAN                                               
4228 -------------------------------------------------------------------------------------------------------
4229  Foreign Scan on public.ft1 t1
4230    Output: c1, c2, c3, c4, c5, c6, c7, c8
4231    Filter: (t1.c8 = $1)
4232    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = $1::integer))
4233 (4 rows)
4235 EXECUTE st5('foo', 1);
4236  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4237 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4238   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4239 (1 row)
4241 -- altering FDW options requires replanning
4242 PREPARE st6 AS SELECT * FROM ft1 t1 WHERE t1.c1 = t1.c2;
4243 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st6;
4244                                           QUERY PLAN                                          
4245 ----------------------------------------------------------------------------------------------
4246  Foreign Scan on public.ft1 t1
4247    Output: c1, c2, c3, c4, c5, c6, c7, c8
4248    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = c2))
4249 (3 rows)
4251 PREPARE st7 AS INSERT INTO ft1 (c1,c2,c3) VALUES (1001,101,'foo');
4252 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st7;
4253                                                                                            QUERY PLAN                                                                                            
4254 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4255  Insert on public.ft1
4256    Remote SQL: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
4257    Batch Size: 1
4258    ->  Result
4259          Output: NULL::integer, 1001, 101, 'foo'::text, NULL::timestamp with time zone, NULL::timestamp without time zone, NULL::character varying, 'ft1       '::character(10), NULL::user_enum
4260 (5 rows)
4262 ALTER TABLE "S 1"."T 1" RENAME TO "T 0";
4263 ALTER FOREIGN TABLE ft1 OPTIONS (SET table_name 'T 0');
4264 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st6;
4265                                           QUERY PLAN                                          
4266 ----------------------------------------------------------------------------------------------
4267  Foreign Scan on public.ft1 t1
4268    Output: c1, c2, c3, c4, c5, c6, c7, c8
4269    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 0" WHERE (("C 1" = c2))
4270 (3 rows)
4272 EXECUTE st6;
4273  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4274 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4275   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4276   2 |  2 | 00002 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo
4277   3 |  3 | 00003 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo
4278   4 |  4 | 00004 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4  | 4          | foo
4279   5 |  5 | 00005 | Tue Jan 06 00:00:00 1970 PST | Tue Jan 06 00:00:00 1970 | 5  | 5          | foo
4280   6 |  6 | 00006 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
4281   7 |  7 | 00007 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
4282   8 |  8 | 00008 | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
4283   9 |  9 | 00009 | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9  | 9          | foo
4284 (9 rows)
4286 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st7;
4287                                                                                            QUERY PLAN                                                                                            
4288 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4289  Insert on public.ft1
4290    Remote SQL: INSERT INTO "S 1"."T 0"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
4291    Batch Size: 1
4292    ->  Result
4293          Output: NULL::integer, 1001, 101, 'foo'::text, NULL::timestamp with time zone, NULL::timestamp without time zone, NULL::character varying, 'ft1       '::character(10), NULL::user_enum
4294 (5 rows)
4296 ALTER TABLE "S 1"."T 0" RENAME TO "T 1";
4297 ALTER FOREIGN TABLE ft1 OPTIONS (SET table_name 'T 1');
4298 PREPARE st8 AS SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2;
4299 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8;
4300                                        QUERY PLAN                                        
4301 -----------------------------------------------------------------------------------------
4302  Foreign Scan
4303    Output: (count(c3))
4304    Relations: Aggregate on (public.ft1 t1)
4305    Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" OPERATOR(public.===) c2))
4306 (4 rows)
4308 ALTER SERVER loopback OPTIONS (DROP extensions);
4309 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8;
4310                         QUERY PLAN                         
4311 -----------------------------------------------------------
4312  Aggregate
4313    Output: count(c3)
4314    ->  Foreign Scan on public.ft1 t1
4315          Output: c3
4316          Filter: (t1.c1 === t1.c2)
4317          Remote SQL: SELECT "C 1", c2, c3 FROM "S 1"."T 1"
4318 (6 rows)
4320 EXECUTE st8;
4321  count 
4322 -------
4323      9
4324 (1 row)
4326 ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
4327 -- cleanup
4328 DEALLOCATE st1;
4329 DEALLOCATE st2;
4330 DEALLOCATE st3;
4331 DEALLOCATE st4;
4332 DEALLOCATE st5;
4333 DEALLOCATE st6;
4334 DEALLOCATE st7;
4335 DEALLOCATE st8;
4336 -- System columns, except ctid and oid, should not be sent to remote
4337 EXPLAIN (VERBOSE, COSTS OFF)
4338 SELECT * FROM ft1 t1 WHERE t1.tableoid = 'pg_class'::regclass LIMIT 1;
4339                                   QUERY PLAN                                   
4340 -------------------------------------------------------------------------------
4341  Limit
4342    Output: c1, c2, c3, c4, c5, c6, c7, c8
4343    ->  Foreign Scan on public.ft1 t1
4344          Output: c1, c2, c3, c4, c5, c6, c7, c8
4345          Filter: (t1.tableoid = '1259'::oid)
4346          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
4347 (6 rows)
4349 SELECT * FROM ft1 t1 WHERE t1.tableoid = 'ft1'::regclass LIMIT 1;
4350  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4351 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4352   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4353 (1 row)
4355 EXPLAIN (VERBOSE, COSTS OFF)
4356 SELECT tableoid::regclass, * FROM ft1 t1 LIMIT 1;
4357                                        QUERY PLAN                                        
4358 -----------------------------------------------------------------------------------------
4359  Foreign Scan on public.ft1 t1
4360    Output: (tableoid)::regclass, c1, c2, c3, c4, c5, c6, c7, c8
4361    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" LIMIT 1::bigint
4362 (3 rows)
4364 SELECT tableoid::regclass, * FROM ft1 t1 LIMIT 1;
4365  tableoid | c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4366 ----------+----+----+-------+------------------------------+--------------------------+----+------------+-----
4367  ft1      |  1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4368 (1 row)
4370 EXPLAIN (VERBOSE, COSTS OFF)
4371 SELECT * FROM ft1 t1 WHERE t1.ctid = '(0,2)';
4372                                             QUERY PLAN                                            
4373 --------------------------------------------------------------------------------------------------
4374  Foreign Scan on public.ft1 t1
4375    Output: c1, c2, c3, c4, c5, c6, c7, c8
4376    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((ctid = '(0,2)'))
4377 (3 rows)
4379 SELECT * FROM ft1 t1 WHERE t1.ctid = '(0,2)';
4380  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4381 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4382   2 |  2 | 00002 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo
4383 (1 row)
4385 EXPLAIN (VERBOSE, COSTS OFF)
4386 SELECT ctid, * FROM ft1 t1 LIMIT 1;
4387                                           QUERY PLAN                                           
4388 -----------------------------------------------------------------------------------------------
4389  Foreign Scan on public.ft1 t1
4390    Output: ctid, c1, c2, c3, c4, c5, c6, c7, c8
4391    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8, ctid FROM "S 1"."T 1" LIMIT 1::bigint
4392 (3 rows)
4394 SELECT ctid, * FROM ft1 t1 LIMIT 1;
4395  ctid  | c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4396 -------+----+----+-------+------------------------------+--------------------------+----+------------+-----
4397  (0,1) |  1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4398 (1 row)
4400 -- ===================================================================
4401 -- used in PL/pgSQL function
4402 -- ===================================================================
4403 CREATE OR REPLACE FUNCTION f_test(p_c1 int) RETURNS int AS $$
4404 DECLARE
4405         v_c1 int;
4406 BEGIN
4407     SELECT c1 INTO v_c1 FROM ft1 WHERE c1 = p_c1 LIMIT 1;
4408     PERFORM c1 FROM ft1 WHERE c1 = p_c1 AND p_c1 = v_c1 LIMIT 1;
4409     RETURN v_c1;
4410 END;
4411 $$ LANGUAGE plpgsql;
4412 SELECT f_test(100);
4413  f_test 
4414 --------
4415     100
4416 (1 row)
4418 DROP FUNCTION f_test(int);
4419 -- ===================================================================
4420 -- REINDEX
4421 -- ===================================================================
4422 -- remote table is not created here
4423 CREATE FOREIGN TABLE reindex_foreign (c1 int, c2 int)
4424   SERVER loopback2 OPTIONS (table_name 'reindex_local');
4425 REINDEX TABLE reindex_foreign; -- error
4426 ERROR:  "reindex_foreign" is not a table or materialized view
4427 REINDEX TABLE CONCURRENTLY reindex_foreign; -- error
4428 ERROR:  "reindex_foreign" is not a table or materialized view
4429 DROP FOREIGN TABLE reindex_foreign;
4430 -- partitions and foreign tables
4431 CREATE TABLE reind_fdw_parent (c1 int) PARTITION BY RANGE (c1);
4432 CREATE TABLE reind_fdw_0_10 PARTITION OF reind_fdw_parent
4433   FOR VALUES FROM (0) TO (10);
4434 CREATE FOREIGN TABLE reind_fdw_10_20 PARTITION OF reind_fdw_parent
4435   FOR VALUES FROM (10) TO (20)
4436   SERVER loopback OPTIONS (table_name 'reind_local_10_20');
4437 REINDEX TABLE reind_fdw_parent; -- ok
4438 REINDEX TABLE CONCURRENTLY reind_fdw_parent; -- ok
4439 DROP TABLE reind_fdw_parent;
4440 -- ===================================================================
4441 -- conversion error
4442 -- ===================================================================
4443 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE int;
4444 SELECT * FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8) WHERE x1 = 1;  -- ERROR
4445 ERROR:  invalid input syntax for type integer: "foo"
4446 CONTEXT:  column "x8" of foreign table "ftx"
4447 SELECT ftx.x1, ft2.c2, ftx.x8 FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8), ft2
4448   WHERE ftx.x1 = ft2.c1 AND ftx.x1 = 1; -- ERROR
4449 ERROR:  invalid input syntax for type integer: "foo"
4450 CONTEXT:  column "x8" of foreign table "ftx"
4451 SELECT ftx.x1, ft2.c2, ftx FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8), ft2
4452   WHERE ftx.x1 = ft2.c1 AND ftx.x1 = 1; -- ERROR
4453 ERROR:  invalid input syntax for type integer: "foo"
4454 CONTEXT:  whole-row reference to foreign table "ftx"
4455 SELECT sum(c2), array_agg(c8) FROM ft1 GROUP BY c8; -- ERROR
4456 ERROR:  invalid input syntax for type integer: "foo"
4457 CONTEXT:  processing expression at position 2 in select list
4458 ANALYZE ft1; -- ERROR
4459 ERROR:  invalid input syntax for type integer: "foo"
4460 CONTEXT:  column "c8" of foreign table "ft1"
4461 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE user_enum;
4462 -- ===================================================================
4463 -- local type can be different from remote type in some cases,
4464 -- in particular if similarly-named operators do equivalent things
4465 -- ===================================================================
4466 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE text;
4467 EXPLAIN (VERBOSE, COSTS OFF)
4468 SELECT * FROM ft1 WHERE c8 = 'foo' LIMIT 1;
4469                                                   QUERY PLAN                                                  
4470 --------------------------------------------------------------------------------------------------------------
4471  Foreign Scan on public.ft1
4472    Output: c1, c2, c3, c4, c5, c6, c7, c8
4473    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c8 = 'foo')) LIMIT 1::bigint
4474 (3 rows)
4476 SELECT * FROM ft1 WHERE c8 = 'foo' LIMIT 1;
4477  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4478 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4479   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4480 (1 row)
4482 EXPLAIN (VERBOSE, COSTS OFF)
4483 SELECT * FROM ft1 WHERE 'foo' = c8 LIMIT 1;
4484                                                   QUERY PLAN                                                  
4485 --------------------------------------------------------------------------------------------------------------
4486  Foreign Scan on public.ft1
4487    Output: c1, c2, c3, c4, c5, c6, c7, c8
4488    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (('foo' = c8)) LIMIT 1::bigint
4489 (3 rows)
4491 SELECT * FROM ft1 WHERE 'foo' = c8 LIMIT 1;
4492  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4493 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4494   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4495 (1 row)
4497 -- we declared c8 to be text locally, but it's still the same type on
4498 -- the remote which will balk if we try to do anything incompatible
4499 -- with that remote type
4500 SELECT * FROM ft1 WHERE c8 LIKE 'foo' LIMIT 1; -- ERROR
4501 ERROR:  operator does not exist: public.user_enum ~~ unknown
4502 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
4503 CONTEXT:  remote SQL command: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c8 ~~ 'foo')) LIMIT 1::bigint
4504 SELECT * FROM ft1 WHERE c8::text LIKE 'foo' LIMIT 1; -- ERROR; cast not pushed down
4505 ERROR:  operator does not exist: public.user_enum ~~ unknown
4506 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
4507 CONTEXT:  remote SQL command: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c8 ~~ 'foo')) LIMIT 1::bigint
4508 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE user_enum;
4509 -- ===================================================================
4510 -- subtransaction
4511 --  + local/remote error doesn't break cursor
4512 -- ===================================================================
4513 BEGIN;
4514 DECLARE c CURSOR FOR SELECT * FROM ft1 ORDER BY c1;
4515 FETCH c;
4516  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4517 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4518   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4519 (1 row)
4521 SAVEPOINT s;
4522 ERROR OUT;          -- ERROR
4523 ERROR:  syntax error at or near "ERROR"
4524 LINE 1: ERROR OUT;
4525         ^
4526 ROLLBACK TO s;
4527 FETCH c;
4528  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4529 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4530   2 |  2 | 00002 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo
4531 (1 row)
4533 SAVEPOINT s;
4534 SELECT * FROM ft1 WHERE 1 / (c1 - 1) > 0;  -- ERROR
4535 ERROR:  division by zero
4536 CONTEXT:  remote SQL command: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (((1 / ("C 1" - 1)) > 0))
4537 ROLLBACK TO s;
4538 FETCH c;
4539  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4540 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4541   3 |  3 | 00003 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo
4542 (1 row)
4544 SELECT * FROM ft1 ORDER BY c1 LIMIT 1;
4545  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4546 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4547   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4548 (1 row)
4550 COMMIT;
4551 -- ===================================================================
4552 -- test handling of collations
4553 -- ===================================================================
4554 create table loct3 (f1 text collate "C" unique, f2 text, f3 varchar(10) unique);
4555 create foreign table ft3 (f1 text collate "C", f2 text, f3 varchar(10))
4556   server loopback options (table_name 'loct3', use_remote_estimate 'true');
4557 -- can be sent to remote
4558 explain (verbose, costs off) select * from ft3 where f1 = 'foo';
4559                                QUERY PLAN                               
4560 ------------------------------------------------------------------------
4561  Foreign Scan on public.ft3
4562    Output: f1, f2, f3
4563    Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE ((f1 = 'foo'))
4564 (3 rows)
4566 explain (verbose, costs off) select * from ft3 where f1 COLLATE "C" = 'foo';
4567                                QUERY PLAN                               
4568 ------------------------------------------------------------------------
4569  Foreign Scan on public.ft3
4570    Output: f1, f2, f3
4571    Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE ((f1 = 'foo'))
4572 (3 rows)
4574 explain (verbose, costs off) select * from ft3 where f2 = 'foo';
4575                                QUERY PLAN                               
4576 ------------------------------------------------------------------------
4577  Foreign Scan on public.ft3
4578    Output: f1, f2, f3
4579    Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE ((f2 = 'foo'))
4580 (3 rows)
4582 explain (verbose, costs off) select * from ft3 where f3 = 'foo';
4583                                QUERY PLAN                               
4584 ------------------------------------------------------------------------
4585  Foreign Scan on public.ft3
4586    Output: f1, f2, f3
4587    Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE ((f3 = 'foo'))
4588 (3 rows)
4590 explain (verbose, costs off) select * from ft3 f, loct3 l
4591   where f.f3 = l.f3 and l.f1 = 'foo';
4592                                             QUERY PLAN                                            
4593 --------------------------------------------------------------------------------------------------
4594  Nested Loop
4595    Output: f.f1, f.f2, f.f3, l.f1, l.f2, l.f3
4596    ->  Index Scan using loct3_f1_key on public.loct3 l
4597          Output: l.f1, l.f2, l.f3
4598          Index Cond: (l.f1 = 'foo'::text)
4599    ->  Foreign Scan on public.ft3 f
4600          Output: f.f1, f.f2, f.f3
4601          Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE ((f3 = $1::character varying(10)))
4602 (8 rows)
4604 -- can't be sent to remote
4605 explain (verbose, costs off) select * from ft3 where f1 COLLATE "POSIX" = 'foo';
4606                     QUERY PLAN                     
4607 ---------------------------------------------------
4608  Foreign Scan on public.ft3
4609    Output: f1, f2, f3
4610    Filter: ((ft3.f1)::text = 'foo'::text)
4611    Remote SQL: SELECT f1, f2, f3 FROM public.loct3
4612 (4 rows)
4614 explain (verbose, costs off) select * from ft3 where f1 = 'foo' COLLATE "C";
4615                     QUERY PLAN                     
4616 ---------------------------------------------------
4617  Foreign Scan on public.ft3
4618    Output: f1, f2, f3
4619    Filter: (ft3.f1 = 'foo'::text COLLATE "C")
4620    Remote SQL: SELECT f1, f2, f3 FROM public.loct3
4621 (4 rows)
4623 explain (verbose, costs off) select * from ft3 where f2 COLLATE "C" = 'foo';
4624                     QUERY PLAN                     
4625 ---------------------------------------------------
4626  Foreign Scan on public.ft3
4627    Output: f1, f2, f3
4628    Filter: ((ft3.f2)::text = 'foo'::text)
4629    Remote SQL: SELECT f1, f2, f3 FROM public.loct3
4630 (4 rows)
4632 explain (verbose, costs off) select * from ft3 where f2 = 'foo' COLLATE "C";
4633                     QUERY PLAN                     
4634 ---------------------------------------------------
4635  Foreign Scan on public.ft3
4636    Output: f1, f2, f3
4637    Filter: (ft3.f2 = 'foo'::text COLLATE "C")
4638    Remote SQL: SELECT f1, f2, f3 FROM public.loct3
4639 (4 rows)
4641 explain (verbose, costs off) select * from ft3 f, loct3 l
4642   where f.f3 = l.f3 COLLATE "POSIX" and l.f1 = 'foo';
4643                          QUERY PLAN                          
4644 -------------------------------------------------------------
4645  Hash Join
4646    Output: f.f1, f.f2, f.f3, l.f1, l.f2, l.f3
4647    Inner Unique: true
4648    Hash Cond: ((f.f3)::text = (l.f3)::text)
4649    ->  Foreign Scan on public.ft3 f
4650          Output: f.f1, f.f2, f.f3
4651          Remote SQL: SELECT f1, f2, f3 FROM public.loct3
4652    ->  Hash
4653          Output: l.f1, l.f2, l.f3
4654          ->  Index Scan using loct3_f1_key on public.loct3 l
4655                Output: l.f1, l.f2, l.f3
4656                Index Cond: (l.f1 = 'foo'::text)
4657 (12 rows)
4659 -- ===================================================================
4660 -- test SEMI-JOIN pushdown
4661 -- ===================================================================
4662 EXPLAIN (verbose, costs off)
4663 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN ft4 ON ft2.c2 = ft4.c1
4664   WHERE ft2.c1 > 900
4665   AND EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)
4666   ORDER BY ft2.c1;
4667                                                                                                                                                 QUERY PLAN                                                                                                                                                 
4668 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4669  Foreign Scan
4670    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3
4671    Relations: ((public.ft2) INNER JOIN (public.ft4)) SEMI JOIN (public.ft5)
4672    Remote SQL: SELECT r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8, r2.c1, r2.c2, r2.c3 FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 3" r2 ON (((r1.c2 = r2.c1)) AND ((r1."C 1" > 900)))) WHERE EXISTS (SELECT NULL FROM "S 1"."T 4" r4 WHERE ((r1.c2 = r4.c1))) ORDER BY r1."C 1" ASC NULLS LAST
4673 (4 rows)
4675 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN ft4 ON ft2.c2 = ft4.c1
4676   WHERE ft2.c1 > 900
4677   AND EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)
4678   ORDER BY ft2.c1;
4679  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  | c1 | c2 |   c3   
4680 -----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+--------
4681  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4682  916 |  6 | 00916 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4683  926 |  6 | 00926 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4684  936 |  6 | 00936 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4685  946 |  6 | 00946 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4686  956 |  6 | 00956 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4687  966 |  6 | 00966 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4688  976 |  6 | 00976 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4689  986 |  6 | 00986 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4690  996 |  6 | 00996 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4691 (10 rows)
4693 -- The same query, different join order
4694 EXPLAIN (verbose, costs off)
4695 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN
4696   (SELECT * FROM ft4 WHERE
4697   EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)) ft4
4698   ON ft2.c2 = ft4.c1
4699   WHERE ft2.c1 > 900
4700   ORDER BY ft2.c1;
4701                                                                                                                                                 QUERY PLAN                                                                                                                                                 
4702 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4703  Foreign Scan
4704    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3
4705    Relations: ((public.ft2) INNER JOIN (public.ft4)) SEMI JOIN (public.ft5)
4706    Remote SQL: SELECT r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8, r4.c1, r4.c2, r4.c3 FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 3" r4 ON (((r1.c2 = r4.c1)) AND ((r1."C 1" > 900)))) WHERE EXISTS (SELECT NULL FROM "S 1"."T 4" r5 WHERE ((r4.c1 = r5.c1))) ORDER BY r1."C 1" ASC NULLS LAST
4707 (4 rows)
4709 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN
4710   (SELECT * FROM ft4 WHERE
4711   EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)) ft4
4712   ON ft2.c2 = ft4.c1
4713   WHERE ft2.c1 > 900
4714   ORDER BY ft2.c1;
4715  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  | c1 | c2 |   c3   
4716 -----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+--------
4717  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4718  916 |  6 | 00916 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4719  926 |  6 | 00926 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4720  936 |  6 | 00936 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4721  946 |  6 | 00946 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4722  956 |  6 | 00956 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4723  966 |  6 | 00966 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4724  976 |  6 | 00976 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4725  986 |  6 | 00986 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4726  996 |  6 | 00996 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4727 (10 rows)
4729 -- Left join
4730 EXPLAIN (verbose, costs off)
4731 SELECT ft2.*, ft4.* FROM ft2 LEFT JOIN
4732   (SELECT * FROM ft4 WHERE
4733   EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)) ft4
4734   ON ft2.c2 = ft4.c1
4735   WHERE ft2.c1 > 900
4736   ORDER BY ft2.c1 LIMIT 10;
4737                                                                                                                                                                                   QUERY PLAN                                                                                                                                                                                  
4738 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4739  Foreign Scan
4740    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3
4741    Relations: (public.ft2) LEFT JOIN ((public.ft4) SEMI JOIN (public.ft5))
4742    Remote SQL: SELECT r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8, s6.c1, s6.c2, s6.c3 FROM ("S 1"."T 1" r1 LEFT JOIN (SELECT r4.c1, r4.c2, r4.c3 FROM "S 1"."T 3" r4 WHERE EXISTS (SELECT NULL FROM "S 1"."T 4" r5 WHERE ((r4.c1 = r5.c1)))) s6(c1, c2, c3) ON (((r1.c2 = s6.c1)))) WHERE ((r1."C 1" > 900)) ORDER BY r1."C 1" ASC NULLS LAST LIMIT 10::bigint
4743 (4 rows)
4745 SELECT ft2.*, ft4.* FROM ft2 LEFT JOIN
4746   (SELECT * FROM ft4 WHERE
4747   EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)) ft4
4748   ON ft2.c2 = ft4.c1
4749   WHERE ft2.c1 > 900
4750   ORDER BY ft2.c1 LIMIT 10;
4751  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  | c1 | c2 |   c3   
4752 -----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+--------
4753  901 |  1 | 00901 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo |    |    | 
4754  902 |  2 | 00902 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo |    |    | 
4755  903 |  3 | 00903 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo |    |    | 
4756  904 |  4 | 00904 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4  | 4          | foo |    |    | 
4757  905 |  5 | 00905 | Tue Jan 06 00:00:00 1970 PST | Tue Jan 06 00:00:00 1970 | 5  | 5          | foo |    |    | 
4758  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4759  907 |  7 | 00907 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo |    |    | 
4760  908 |  8 | 00908 | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo |    |    | 
4761  909 |  9 | 00909 | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9  | 9          | foo |    |    | 
4762  910 |  0 | 00910 | Sun Jan 11 00:00:00 1970 PST | Sun Jan 11 00:00:00 1970 | 0  | 0          | foo |    |    | 
4763 (10 rows)
4765 -- Several semi-joins per upper level join
4766 EXPLAIN (verbose, costs off)
4767 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN
4768   (SELECT * FROM ft4 WHERE
4769   EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)) ft4
4770   ON ft2.c2 = ft4.c1
4771   INNER JOIN (SELECT * FROM ft5 WHERE
4772   EXISTS (SELECT 1 FROM ft4 WHERE ft4.c1 = ft5.c1)) ft5
4773   ON ft2.c2 <= ft5.c1
4774   WHERE ft2.c1 > 900
4775   ORDER BY ft2.c1 LIMIT 10;
4776                                                                                                                                                                                                                      QUERY PLAN                                                                                                                                                                                                                      
4777 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4778  Foreign Scan
4779    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3
4780    Relations: ((((public.ft2) INNER JOIN (public.ft4)) SEMI JOIN (public.ft5)) INNER JOIN (public.ft5 ft5_1)) SEMI JOIN (public.ft4 ft4_1)
4781    Remote SQL: SELECT r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8, r6.c1, r6.c2, r6.c3 FROM (("S 1"."T 1" r1 INNER JOIN "S 1"."T 3" r6 ON (((r1.c2 = r6.c1)) AND ((r1."C 1" > 900)))) INNER JOIN "S 1"."T 4" r8 ON (((r1.c2 <= r8.c1)))) WHERE EXISTS (SELECT NULL FROM "S 1"."T 3" r9 WHERE ((r8.c1 = r9.c1))) AND EXISTS (SELECT NULL FROM "S 1"."T 4" r7 WHERE ((r6.c1 = r7.c1))) ORDER BY r1."C 1" ASC NULLS LAST LIMIT 10::bigint
4782 (4 rows)
4784 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN
4785   (SELECT * FROM ft4 WHERE
4786   EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)) ft4
4787   ON ft2.c2 = ft4.c1
4788   INNER JOIN (SELECT * FROM ft5 WHERE
4789   EXISTS (SELECT 1 FROM ft4 WHERE ft4.c1 = ft5.c1)) ft5
4790   ON ft2.c2 <= ft5.c1
4791   WHERE ft2.c1 > 900
4792   ORDER BY ft2.c1 LIMIT 10;
4793  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  | c1 | c2 |   c3   
4794 -----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+--------
4795  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4796  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4797  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4798  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4799  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4800  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4801  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4802  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4803  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4804  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4805 (10 rows)
4807 -- Semi-join below Semi-join
4808 EXPLAIN (verbose, costs off)
4809 SELECT ft2.* FROM ft2 WHERE
4810   c1 = ANY (
4811         SELECT c1 FROM ft2 WHERE
4812           EXISTS (SELECT 1 FROM ft4 WHERE ft4.c2 = ft2.c2))
4813   AND ft2.c1 > 900
4814   ORDER BY ft2.c1 LIMIT 10;
4815                                                                                                                                                           QUERY PLAN                                                                                                                                                           
4816 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4817  Foreign Scan
4818    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8
4819    Relations: (public.ft2) SEMI JOIN ((public.ft2 ft2_1) SEMI JOIN (public.ft4))
4820    Remote SQL: SELECT r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM "S 1"."T 1" r1 WHERE ((r1."C 1" > 900)) AND EXISTS (SELECT NULL FROM "S 1"."T 1" r3 WHERE ((r1."C 1" = r3."C 1")) AND EXISTS (SELECT NULL FROM "S 1"."T 3" r4 WHERE ((r3.c2 = r4.c2)))) ORDER BY r1."C 1" ASC NULLS LAST LIMIT 10::bigint
4821 (4 rows)
4823 SELECT ft2.* FROM ft2 WHERE
4824   c1 = ANY (
4825         SELECT c1 FROM ft2 WHERE
4826           EXISTS (SELECT 1 FROM ft4 WHERE ft4.c2 = ft2.c2))
4827   AND ft2.c1 > 900
4828   ORDER BY ft2.c1 LIMIT 10;
4829  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4830 -----+----+-------+------------------------------+--------------------------+----+------------+-----
4831  903 |  3 | 00903 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo
4832  905 |  5 | 00905 | Tue Jan 06 00:00:00 1970 PST | Tue Jan 06 00:00:00 1970 | 5  | 5          | foo
4833  907 |  7 | 00907 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
4834  909 |  9 | 00909 | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9  | 9          | foo
4835  913 |  3 | 00913 | Wed Jan 14 00:00:00 1970 PST | Wed Jan 14 00:00:00 1970 | 3  | 3          | foo
4836  915 |  5 | 00915 | Fri Jan 16 00:00:00 1970 PST | Fri Jan 16 00:00:00 1970 | 5  | 5          | foo
4837  917 |  7 | 00917 | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
4838  919 |  9 | 00919 | Tue Jan 20 00:00:00 1970 PST | Tue Jan 20 00:00:00 1970 | 9  | 9          | foo
4839  923 |  3 | 00923 | Sat Jan 24 00:00:00 1970 PST | Sat Jan 24 00:00:00 1970 | 3  | 3          | foo
4840  925 |  5 | 00925 | Mon Jan 26 00:00:00 1970 PST | Mon Jan 26 00:00:00 1970 | 5  | 5          | foo
4841 (10 rows)
4843 -- Upper level relations shouldn't refer EXISTS() subqueries
4844 EXPLAIN (verbose, costs off)
4845 SELECT * FROM ft2 ftupper WHERE
4846    EXISTS (
4847         SELECT c1 FROM ft2 WHERE
4848           EXISTS (SELECT 1 FROM ft4 WHERE ft4.c2 = ft2.c2) AND c1 = ftupper.c1 )
4849   AND ftupper.c1 > 900
4850   ORDER BY ftupper.c1 LIMIT 10;
4851                                                                                                                                                           QUERY PLAN                                                                                                                                                           
4852 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4853  Foreign Scan
4854    Output: ftupper.c1, ftupper.c2, ftupper.c3, ftupper.c4, ftupper.c5, ftupper.c6, ftupper.c7, ftupper.c8
4855    Relations: (public.ft2 ftupper) SEMI JOIN ((public.ft2) SEMI JOIN (public.ft4))
4856    Remote SQL: SELECT r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8 FROM "S 1"."T 1" r1 WHERE ((r1."C 1" > 900)) AND EXISTS (SELECT NULL FROM "S 1"."T 1" r2 WHERE ((r1."C 1" = r2."C 1")) AND EXISTS (SELECT NULL FROM "S 1"."T 3" r3 WHERE ((r2.c2 = r3.c2)))) ORDER BY r1."C 1" ASC NULLS LAST LIMIT 10::bigint
4857 (4 rows)
4859 SELECT * FROM ft2 ftupper WHERE
4860    EXISTS (
4861         SELECT c1 FROM ft2 WHERE
4862           EXISTS (SELECT 1 FROM ft4 WHERE ft4.c2 = ft2.c2) AND c1 = ftupper.c1 )
4863   AND ftupper.c1 > 900
4864   ORDER BY ftupper.c1 LIMIT 10;
4865  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4866 -----+----+-------+------------------------------+--------------------------+----+------------+-----
4867  903 |  3 | 00903 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo
4868  905 |  5 | 00905 | Tue Jan 06 00:00:00 1970 PST | Tue Jan 06 00:00:00 1970 | 5  | 5          | foo
4869  907 |  7 | 00907 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
4870  909 |  9 | 00909 | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9  | 9          | foo
4871  913 |  3 | 00913 | Wed Jan 14 00:00:00 1970 PST | Wed Jan 14 00:00:00 1970 | 3  | 3          | foo
4872  915 |  5 | 00915 | Fri Jan 16 00:00:00 1970 PST | Fri Jan 16 00:00:00 1970 | 5  | 5          | foo
4873  917 |  7 | 00917 | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
4874  919 |  9 | 00919 | Tue Jan 20 00:00:00 1970 PST | Tue Jan 20 00:00:00 1970 | 9  | 9          | foo
4875  923 |  3 | 00923 | Sat Jan 24 00:00:00 1970 PST | Sat Jan 24 00:00:00 1970 | 3  | 3          | foo
4876  925 |  5 | 00925 | Mon Jan 26 00:00:00 1970 PST | Mon Jan 26 00:00:00 1970 | 5  | 5          | foo
4877 (10 rows)
4879 -- EXISTS should be propagated to the highest upper inner join
4880 EXPLAIN (verbose, costs off)
4881         SELECT ft2.*, ft4.* FROM ft2 INNER JOIN
4882         (SELECT * FROM ft4 WHERE EXISTS (
4883                 SELECT 1 FROM ft2 WHERE ft2.c2 = ft4.c2)) ft4
4884         ON ft2.c2 = ft4.c1
4885         INNER JOIN
4886         (SELECT * FROM ft2 WHERE EXISTS (
4887                 SELECT 1 FROM ft4 WHERE ft2.c2 = ft4.c2)) ft21
4888         ON ft2.c2 = ft21.c2
4889         WHERE ft2.c1 > 900
4890         ORDER BY ft2.c1 LIMIT 10;
4891                                                                                                                                                                                                                      QUERY PLAN                                                                                                                                                                                                                     
4892 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4893  Foreign Scan
4894    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3
4895    Relations: ((((public.ft2) INNER JOIN (public.ft4)) SEMI JOIN (public.ft2 ft2_1)) INNER JOIN (public.ft2 ft2_2)) SEMI JOIN (public.ft4 ft4_1)
4896    Remote SQL: SELECT r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8, r6.c1, r6.c2, r6.c3 FROM (("S 1"."T 1" r1 INNER JOIN "S 1"."T 3" r6 ON (((r1.c2 = r6.c1)) AND ((r1."C 1" > 900)))) INNER JOIN "S 1"."T 1" r8 ON (((r1.c2 = r8.c2)))) WHERE EXISTS (SELECT NULL FROM "S 1"."T 3" r9 WHERE ((r1.c2 = r9.c2))) AND EXISTS (SELECT NULL FROM "S 1"."T 1" r7 WHERE ((r7.c2 = r6.c2))) ORDER BY r1."C 1" ASC NULLS LAST LIMIT 10::bigint
4897 (4 rows)
4899 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN
4900         (SELECT * FROM ft4 WHERE EXISTS (
4901                 SELECT 1 FROM ft2 WHERE ft2.c2 = ft4.c2)) ft4
4902         ON ft2.c2 = ft4.c1
4903         INNER JOIN
4904         (SELECT * FROM ft2 WHERE EXISTS (
4905                 SELECT 1 FROM ft4 WHERE ft2.c2 = ft4.c2)) ft21
4906         ON ft2.c2 = ft21.c2
4907         WHERE ft2.c1 > 900
4908         ORDER BY ft2.c1 LIMIT 10;
4909  c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c1 | c2 | c3 
4910 ----+----+----+----+----+----+----+----+----+----+----
4911 (0 rows)
4913 -- Can't push down semi-join with inner rel vars in targetlist
4914 EXPLAIN (verbose, costs off)
4915 SELECT ft1.c1 FROM ft1 JOIN ft2 on ft1.c1 = ft2.c1 WHERE
4916         ft1.c1 IN (
4917                 SELECT ft2.c1 FROM ft2 JOIN ft4 ON ft2.c1 = ft4.c1)
4918         ORDER BY ft1.c1 LIMIT 5;
4919                                                                             QUERY PLAN                                                                             
4920 -------------------------------------------------------------------------------------------------------------------------------------------------------------------
4921  Limit
4922    Output: ft1.c1
4923    ->  Merge Semi Join
4924          Output: ft1.c1
4925          Merge Cond: (ft1.c1 = ft2_1.c1)
4926          ->  Foreign Scan
4927                Output: ft1.c1, ft2.c1
4928                Relations: (public.ft1) INNER JOIN (public.ft2)
4929                Remote SQL: SELECT r1."C 1", r2."C 1" FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r2."C 1" = r1."C 1")))) ORDER BY r1."C 1" ASC NULLS LAST
4930          ->  Foreign Scan
4931                Output: ft2_1.c1, ft4.c1
4932                Relations: (public.ft2 ft2_1) INNER JOIN (public.ft4)
4933                Remote SQL: SELECT r5."C 1", r6.c1 FROM ("S 1"."T 1" r5 INNER JOIN "S 1"."T 3" r6 ON (((r5."C 1" = r6.c1)))) ORDER BY r5."C 1" ASC NULLS LAST
4934 (13 rows)
4936 -- ===================================================================
4937 -- test writable foreign table stuff
4938 -- ===================================================================
4939 EXPLAIN (verbose, costs off)
4940 INSERT INTO ft2 (c1,c2,c3) SELECT c1+1000,c2+100, c3 || c3 FROM ft2 LIMIT 20;
4941                                                                                                                     QUERY PLAN                                                                                                                    
4942 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4943  Insert on public.ft2
4944    Remote SQL: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
4945    Batch Size: 1
4946    ->  Subquery Scan on "*SELECT*"
4947          Output: "*SELECT*"."?column?", "*SELECT*"."?column?_1", NULL::integer, "*SELECT*"."?column?_2", NULL::timestamp with time zone, NULL::timestamp without time zone, NULL::character varying, 'ft2       '::character(10), NULL::user_enum
4948          ->  Foreign Scan on public.ft2 ft2_1
4949                Output: (ft2_1.c1 + 1000), (ft2_1.c2 + 100), (ft2_1.c3 || ft2_1.c3)
4950                Remote SQL: SELECT "C 1", c2, c3 FROM "S 1"."T 1" LIMIT 20::bigint
4951 (8 rows)
4953 INSERT INTO ft2 (c1,c2,c3) SELECT c1+1000,c2+100, c3 || c3 FROM ft2 LIMIT 20;
4954 INSERT INTO ft2 (c1,c2,c3)
4955   VALUES (1101,201,'aaa'), (1102,202,'bbb'), (1103,203,'ccc') RETURNING *;
4956   c1  | c2  | c3  | c4 | c5 | c6 |     c7     | c8 
4957 ------+-----+-----+----+----+----+------------+----
4958  1101 | 201 | aaa |    |    |    | ft2        | 
4959  1102 | 202 | bbb |    |    |    | ft2        | 
4960  1103 | 203 | ccc |    |    |    | ft2        | 
4961 (3 rows)
4963 INSERT INTO ft2 (c1,c2,c3) VALUES (1104,204,'ddd'), (1105,205,'eee');
4964 EXPLAIN (verbose, costs off)
4965 UPDATE ft2 SET c2 = c2 + 300, c3 = c3 || '_update3' WHERE c1 % 10 = 3;              -- can be pushed down
4966                                                    QUERY PLAN                                                   
4967 ----------------------------------------------------------------------------------------------------------------
4968  Update on public.ft2
4969    ->  Foreign Update on public.ft2
4970          Remote SQL: UPDATE "S 1"."T 1" SET c2 = (c2 + 300), c3 = (c3 || '_update3') WHERE ((("C 1" % 10) = 3))
4971 (3 rows)
4973 UPDATE ft2 SET c2 = c2 + 300, c3 = c3 || '_update3' WHERE c1 % 10 = 3;
4974 EXPLAIN (verbose, costs off)
4975 UPDATE ft2 SET c2 = c2 + 400, c3 = c3 || '_update7' WHERE c1 % 10 = 7 RETURNING *;  -- can be pushed down
4976                                                                          QUERY PLAN                                                                         
4977 ------------------------------------------------------------------------------------------------------------------------------------------------------------
4978  Update on public.ft2
4979    Output: c1, c2, c3, c4, c5, c6, c7, c8
4980    ->  Foreign Update on public.ft2
4981          Remote SQL: UPDATE "S 1"."T 1" SET c2 = (c2 + 400), c3 = (c3 || '_update7') WHERE ((("C 1" % 10) = 7)) RETURNING "C 1", c2, c3, c4, c5, c6, c7, c8
4982 (4 rows)
4984 UPDATE ft2 SET c2 = c2 + 400, c3 = c3 || '_update7' WHERE c1 % 10 = 7 RETURNING *;
4985   c1  | c2  |         c3         |              c4              |            c5            | c6 |     c7     | c8  
4986 ------+-----+--------------------+------------------------------+--------------------------+----+------------+-----
4987     7 | 407 | 00007_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
4988    17 | 407 | 00017_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
4989    27 | 407 | 00027_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
4990    37 | 407 | 00037_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
4991    47 | 407 | 00047_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
4992    57 | 407 | 00057_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
4993    67 | 407 | 00067_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
4994    77 | 407 | 00077_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
4995    87 | 407 | 00087_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
4996    97 | 407 | 00097_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
4997   107 | 407 | 00107_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
4998   117 | 407 | 00117_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
4999   127 | 407 | 00127_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5000   137 | 407 | 00137_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5001   147 | 407 | 00147_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5002   157 | 407 | 00157_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5003   167 | 407 | 00167_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5004   177 | 407 | 00177_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5005   187 | 407 | 00187_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5006   197 | 407 | 00197_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5007   207 | 407 | 00207_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5008   217 | 407 | 00217_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5009   227 | 407 | 00227_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5010   237 | 407 | 00237_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5011   247 | 407 | 00247_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5012   257 | 407 | 00257_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5013   267 | 407 | 00267_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5014   277 | 407 | 00277_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5015   287 | 407 | 00287_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5016   297 | 407 | 00297_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5017   307 | 407 | 00307_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5018   317 | 407 | 00317_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5019   327 | 407 | 00327_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5020   337 | 407 | 00337_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5021   347 | 407 | 00347_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5022   357 | 407 | 00357_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5023   367 | 407 | 00367_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5024   377 | 407 | 00377_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5025   387 | 407 | 00387_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5026   397 | 407 | 00397_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5027   407 | 407 | 00407_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5028   417 | 407 | 00417_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5029   427 | 407 | 00427_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5030   437 | 407 | 00437_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5031   447 | 407 | 00447_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5032   457 | 407 | 00457_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5033   467 | 407 | 00467_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5034   477 | 407 | 00477_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5035   487 | 407 | 00487_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5036   497 | 407 | 00497_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5037   507 | 407 | 00507_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5038   517 | 407 | 00517_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5039   527 | 407 | 00527_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5040   537 | 407 | 00537_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5041   547 | 407 | 00547_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5042   557 | 407 | 00557_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5043   567 | 407 | 00567_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5044   577 | 407 | 00577_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5045   587 | 407 | 00587_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5046   597 | 407 | 00597_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5047   607 | 407 | 00607_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5048   617 | 407 | 00617_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5049   627 | 407 | 00627_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5050   637 | 407 | 00637_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5051   647 | 407 | 00647_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5052   657 | 407 | 00657_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5053   667 | 407 | 00667_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5054   677 | 407 | 00677_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5055   687 | 407 | 00687_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5056   697 | 407 | 00697_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5057   707 | 407 | 00707_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5058   717 | 407 | 00717_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5059   727 | 407 | 00727_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5060   737 | 407 | 00737_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5061   747 | 407 | 00747_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5062   757 | 407 | 00757_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5063   767 | 407 | 00767_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5064   777 | 407 | 00777_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5065   787 | 407 | 00787_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5066   797 | 407 | 00797_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5067   807 | 407 | 00807_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5068   817 | 407 | 00817_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5069   827 | 407 | 00827_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5070   837 | 407 | 00837_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5071   847 | 407 | 00847_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5072   857 | 407 | 00857_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5073   867 | 407 | 00867_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5074   877 | 407 | 00877_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5075   887 | 407 | 00887_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5076   897 | 407 | 00897_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5077   907 | 407 | 00907_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5078   917 | 407 | 00917_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5079   927 | 407 | 00927_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5080   937 | 407 | 00937_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5081   947 | 407 | 00947_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5082   957 | 407 | 00957_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5083   967 | 407 | 00967_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5084   977 | 407 | 00977_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5085   987 | 407 | 00987_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5086   997 | 407 | 00997_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5087  1007 | 507 | 0000700007_update7 |                              |                          |    | ft2        | 
5088  1017 | 507 | 0001700017_update7 |                              |                          |    | ft2        | 
5089 (102 rows)
5091 EXPLAIN (verbose, costs off)
5092 UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT
5093   FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9;                               -- can be pushed down
5094                                                                                                 QUERY PLAN                                                                                                 
5095 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
5096  Update on public.ft2
5097    ->  Foreign Update
5098          Remote SQL: UPDATE "S 1"."T 1" r1 SET c2 = (r1.c2 + 500), c3 = (r1.c3 || '_update9'), c7 = 'ft2       '::character(10) FROM "S 1"."T 1" r2 WHERE ((r1.c2 = r2."C 1")) AND (((r2."C 1" % 10) = 9))
5099 (3 rows)
5101 UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT
5102   FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9;
5103 EXPLAIN (verbose, costs off)
5104   DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING c1, c4;                               -- can be pushed down
5105                                          QUERY PLAN                                         
5106 --------------------------------------------------------------------------------------------
5107  Delete on public.ft2
5108    Output: c1, c4
5109    ->  Foreign Delete on public.ft2
5110          Remote SQL: DELETE FROM "S 1"."T 1" WHERE ((("C 1" % 10) = 5)) RETURNING "C 1", c4
5111 (4 rows)
5113 DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING c1, c4;
5114   c1  |              c4              
5115 ------+------------------------------
5116     5 | Tue Jan 06 00:00:00 1970 PST
5117    15 | Fri Jan 16 00:00:00 1970 PST
5118    25 | Mon Jan 26 00:00:00 1970 PST
5119    35 | Thu Feb 05 00:00:00 1970 PST
5120    45 | Sun Feb 15 00:00:00 1970 PST
5121    55 | Wed Feb 25 00:00:00 1970 PST
5122    65 | Sat Mar 07 00:00:00 1970 PST
5123    75 | Tue Mar 17 00:00:00 1970 PST
5124    85 | Fri Mar 27 00:00:00 1970 PST
5125    95 | Mon Apr 06 00:00:00 1970 PST
5126   105 | Tue Jan 06 00:00:00 1970 PST
5127   115 | Fri Jan 16 00:00:00 1970 PST
5128   125 | Mon Jan 26 00:00:00 1970 PST
5129   135 | Thu Feb 05 00:00:00 1970 PST
5130   145 | Sun Feb 15 00:00:00 1970 PST
5131   155 | Wed Feb 25 00:00:00 1970 PST
5132   165 | Sat Mar 07 00:00:00 1970 PST
5133   175 | Tue Mar 17 00:00:00 1970 PST
5134   185 | Fri Mar 27 00:00:00 1970 PST
5135   195 | Mon Apr 06 00:00:00 1970 PST
5136   205 | Tue Jan 06 00:00:00 1970 PST
5137   215 | Fri Jan 16 00:00:00 1970 PST
5138   225 | Mon Jan 26 00:00:00 1970 PST
5139   235 | Thu Feb 05 00:00:00 1970 PST
5140   245 | Sun Feb 15 00:00:00 1970 PST
5141   255 | Wed Feb 25 00:00:00 1970 PST
5142   265 | Sat Mar 07 00:00:00 1970 PST
5143   275 | Tue Mar 17 00:00:00 1970 PST
5144   285 | Fri Mar 27 00:00:00 1970 PST
5145   295 | Mon Apr 06 00:00:00 1970 PST
5146   305 | Tue Jan 06 00:00:00 1970 PST
5147   315 | Fri Jan 16 00:00:00 1970 PST
5148   325 | Mon Jan 26 00:00:00 1970 PST
5149   335 | Thu Feb 05 00:00:00 1970 PST
5150   345 | Sun Feb 15 00:00:00 1970 PST
5151   355 | Wed Feb 25 00:00:00 1970 PST
5152   365 | Sat Mar 07 00:00:00 1970 PST
5153   375 | Tue Mar 17 00:00:00 1970 PST
5154   385 | Fri Mar 27 00:00:00 1970 PST
5155   395 | Mon Apr 06 00:00:00 1970 PST
5156   405 | Tue Jan 06 00:00:00 1970 PST
5157   415 | Fri Jan 16 00:00:00 1970 PST
5158   425 | Mon Jan 26 00:00:00 1970 PST
5159   435 | Thu Feb 05 00:00:00 1970 PST
5160   445 | Sun Feb 15 00:00:00 1970 PST
5161   455 | Wed Feb 25 00:00:00 1970 PST
5162   465 | Sat Mar 07 00:00:00 1970 PST
5163   475 | Tue Mar 17 00:00:00 1970 PST
5164   485 | Fri Mar 27 00:00:00 1970 PST
5165   495 | Mon Apr 06 00:00:00 1970 PST
5166   505 | Tue Jan 06 00:00:00 1970 PST
5167   515 | Fri Jan 16 00:00:00 1970 PST
5168   525 | Mon Jan 26 00:00:00 1970 PST
5169   535 | Thu Feb 05 00:00:00 1970 PST
5170   545 | Sun Feb 15 00:00:00 1970 PST
5171   555 | Wed Feb 25 00:00:00 1970 PST
5172   565 | Sat Mar 07 00:00:00 1970 PST
5173   575 | Tue Mar 17 00:00:00 1970 PST
5174   585 | Fri Mar 27 00:00:00 1970 PST
5175   595 | Mon Apr 06 00:00:00 1970 PST
5176   605 | Tue Jan 06 00:00:00 1970 PST
5177   615 | Fri Jan 16 00:00:00 1970 PST
5178   625 | Mon Jan 26 00:00:00 1970 PST
5179   635 | Thu Feb 05 00:00:00 1970 PST
5180   645 | Sun Feb 15 00:00:00 1970 PST
5181   655 | Wed Feb 25 00:00:00 1970 PST
5182   665 | Sat Mar 07 00:00:00 1970 PST
5183   675 | Tue Mar 17 00:00:00 1970 PST
5184   685 | Fri Mar 27 00:00:00 1970 PST
5185   695 | Mon Apr 06 00:00:00 1970 PST
5186   705 | Tue Jan 06 00:00:00 1970 PST
5187   715 | Fri Jan 16 00:00:00 1970 PST
5188   725 | Mon Jan 26 00:00:00 1970 PST
5189   735 | Thu Feb 05 00:00:00 1970 PST
5190   745 | Sun Feb 15 00:00:00 1970 PST
5191   755 | Wed Feb 25 00:00:00 1970 PST
5192   765 | Sat Mar 07 00:00:00 1970 PST
5193   775 | Tue Mar 17 00:00:00 1970 PST
5194   785 | Fri Mar 27 00:00:00 1970 PST
5195   795 | Mon Apr 06 00:00:00 1970 PST
5196   805 | Tue Jan 06 00:00:00 1970 PST
5197   815 | Fri Jan 16 00:00:00 1970 PST
5198   825 | Mon Jan 26 00:00:00 1970 PST
5199   835 | Thu Feb 05 00:00:00 1970 PST
5200   845 | Sun Feb 15 00:00:00 1970 PST
5201   855 | Wed Feb 25 00:00:00 1970 PST
5202   865 | Sat Mar 07 00:00:00 1970 PST
5203   875 | Tue Mar 17 00:00:00 1970 PST
5204   885 | Fri Mar 27 00:00:00 1970 PST
5205   895 | Mon Apr 06 00:00:00 1970 PST
5206   905 | Tue Jan 06 00:00:00 1970 PST
5207   915 | Fri Jan 16 00:00:00 1970 PST
5208   925 | Mon Jan 26 00:00:00 1970 PST
5209   935 | Thu Feb 05 00:00:00 1970 PST
5210   945 | Sun Feb 15 00:00:00 1970 PST
5211   955 | Wed Feb 25 00:00:00 1970 PST
5212   965 | Sat Mar 07 00:00:00 1970 PST
5213   975 | Tue Mar 17 00:00:00 1970 PST
5214   985 | Fri Mar 27 00:00:00 1970 PST
5215   995 | Mon Apr 06 00:00:00 1970 PST
5216  1005 | 
5217  1015 | 
5218  1105 | 
5219 (103 rows)
5221 EXPLAIN (verbose, costs off)
5222 DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2;                -- can be pushed down
5223                                                          QUERY PLAN                                                         
5224 ----------------------------------------------------------------------------------------------------------------------------
5225  Delete on public.ft2
5226    ->  Foreign Delete
5227          Remote SQL: DELETE FROM "S 1"."T 1" r1 USING "S 1"."T 1" r2 WHERE ((r1.c2 = r2."C 1")) AND (((r2."C 1" % 10) = 2))
5228 (3 rows)
5230 DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2;
5231 SELECT c1,c2,c3,c4 FROM ft2 ORDER BY c1;
5232   c1  | c2  |         c3         |              c4              
5233 ------+-----+--------------------+------------------------------
5234     1 |   1 | 00001              | Fri Jan 02 00:00:00 1970 PST
5235     3 | 303 | 00003_update3      | Sun Jan 04 00:00:00 1970 PST
5236     4 |   4 | 00004              | Mon Jan 05 00:00:00 1970 PST
5237     6 |   6 | 00006              | Wed Jan 07 00:00:00 1970 PST
5238     7 | 407 | 00007_update7      | Thu Jan 08 00:00:00 1970 PST
5239     8 |   8 | 00008              | Fri Jan 09 00:00:00 1970 PST
5240     9 | 509 | 00009_update9      | Sat Jan 10 00:00:00 1970 PST
5241    10 |   0 | 00010              | Sun Jan 11 00:00:00 1970 PST
5242    11 |   1 | 00011              | Mon Jan 12 00:00:00 1970 PST
5243    13 | 303 | 00013_update3      | Wed Jan 14 00:00:00 1970 PST
5244    14 |   4 | 00014              | Thu Jan 15 00:00:00 1970 PST
5245    16 |   6 | 00016              | Sat Jan 17 00:00:00 1970 PST
5246    17 | 407 | 00017_update7      | Sun Jan 18 00:00:00 1970 PST
5247    18 |   8 | 00018              | Mon Jan 19 00:00:00 1970 PST
5248    19 | 509 | 00019_update9      | Tue Jan 20 00:00:00 1970 PST
5249    20 |   0 | 00020              | Wed Jan 21 00:00:00 1970 PST
5250    21 |   1 | 00021              | Thu Jan 22 00:00:00 1970 PST
5251    23 | 303 | 00023_update3      | Sat Jan 24 00:00:00 1970 PST
5252    24 |   4 | 00024              | Sun Jan 25 00:00:00 1970 PST
5253    26 |   6 | 00026              | Tue Jan 27 00:00:00 1970 PST
5254    27 | 407 | 00027_update7      | Wed Jan 28 00:00:00 1970 PST
5255    28 |   8 | 00028              | Thu Jan 29 00:00:00 1970 PST
5256    29 | 509 | 00029_update9      | Fri Jan 30 00:00:00 1970 PST
5257    30 |   0 | 00030              | Sat Jan 31 00:00:00 1970 PST
5258    31 |   1 | 00031              | Sun Feb 01 00:00:00 1970 PST
5259    33 | 303 | 00033_update3      | Tue Feb 03 00:00:00 1970 PST
5260    34 |   4 | 00034              | Wed Feb 04 00:00:00 1970 PST
5261    36 |   6 | 00036              | Fri Feb 06 00:00:00 1970 PST
5262    37 | 407 | 00037_update7      | Sat Feb 07 00:00:00 1970 PST
5263    38 |   8 | 00038              | Sun Feb 08 00:00:00 1970 PST
5264    39 | 509 | 00039_update9      | Mon Feb 09 00:00:00 1970 PST
5265    40 |   0 | 00040              | Tue Feb 10 00:00:00 1970 PST
5266    41 |   1 | 00041              | Wed Feb 11 00:00:00 1970 PST
5267    43 | 303 | 00043_update3      | Fri Feb 13 00:00:00 1970 PST
5268    44 |   4 | 00044              | Sat Feb 14 00:00:00 1970 PST
5269    46 |   6 | 00046              | Mon Feb 16 00:00:00 1970 PST
5270    47 | 407 | 00047_update7      | Tue Feb 17 00:00:00 1970 PST
5271    48 |   8 | 00048              | Wed Feb 18 00:00:00 1970 PST
5272    49 | 509 | 00049_update9      | Thu Feb 19 00:00:00 1970 PST
5273    50 |   0 | 00050              | Fri Feb 20 00:00:00 1970 PST
5274    51 |   1 | 00051              | Sat Feb 21 00:00:00 1970 PST
5275    53 | 303 | 00053_update3      | Mon Feb 23 00:00:00 1970 PST
5276    54 |   4 | 00054              | Tue Feb 24 00:00:00 1970 PST
5277    56 |   6 | 00056              | Thu Feb 26 00:00:00 1970 PST
5278    57 | 407 | 00057_update7      | Fri Feb 27 00:00:00 1970 PST
5279    58 |   8 | 00058              | Sat Feb 28 00:00:00 1970 PST
5280    59 | 509 | 00059_update9      | Sun Mar 01 00:00:00 1970 PST
5281    60 |   0 | 00060              | Mon Mar 02 00:00:00 1970 PST
5282    61 |   1 | 00061              | Tue Mar 03 00:00:00 1970 PST
5283    63 | 303 | 00063_update3      | Thu Mar 05 00:00:00 1970 PST
5284    64 |   4 | 00064              | Fri Mar 06 00:00:00 1970 PST
5285    66 |   6 | 00066              | Sun Mar 08 00:00:00 1970 PST
5286    67 | 407 | 00067_update7      | Mon Mar 09 00:00:00 1970 PST
5287    68 |   8 | 00068              | Tue Mar 10 00:00:00 1970 PST
5288    69 | 509 | 00069_update9      | Wed Mar 11 00:00:00 1970 PST
5289    70 |   0 | 00070              | Thu Mar 12 00:00:00 1970 PST
5290    71 |   1 | 00071              | Fri Mar 13 00:00:00 1970 PST
5291    73 | 303 | 00073_update3      | Sun Mar 15 00:00:00 1970 PST
5292    74 |   4 | 00074              | Mon Mar 16 00:00:00 1970 PST
5293    76 |   6 | 00076              | Wed Mar 18 00:00:00 1970 PST
5294    77 | 407 | 00077_update7      | Thu Mar 19 00:00:00 1970 PST
5295    78 |   8 | 00078              | Fri Mar 20 00:00:00 1970 PST
5296    79 | 509 | 00079_update9      | Sat Mar 21 00:00:00 1970 PST
5297    80 |   0 | 00080              | Sun Mar 22 00:00:00 1970 PST
5298    81 |   1 | 00081              | Mon Mar 23 00:00:00 1970 PST
5299    83 | 303 | 00083_update3      | Wed Mar 25 00:00:00 1970 PST
5300    84 |   4 | 00084              | Thu Mar 26 00:00:00 1970 PST
5301    86 |   6 | 00086              | Sat Mar 28 00:00:00 1970 PST
5302    87 | 407 | 00087_update7      | Sun Mar 29 00:00:00 1970 PST
5303    88 |   8 | 00088              | Mon Mar 30 00:00:00 1970 PST
5304    89 | 509 | 00089_update9      | Tue Mar 31 00:00:00 1970 PST
5305    90 |   0 | 00090              | Wed Apr 01 00:00:00 1970 PST
5306    91 |   1 | 00091              | Thu Apr 02 00:00:00 1970 PST
5307    93 | 303 | 00093_update3      | Sat Apr 04 00:00:00 1970 PST
5308    94 |   4 | 00094              | Sun Apr 05 00:00:00 1970 PST
5309    96 |   6 | 00096              | Tue Apr 07 00:00:00 1970 PST
5310    97 | 407 | 00097_update7      | Wed Apr 08 00:00:00 1970 PST
5311    98 |   8 | 00098              | Thu Apr 09 00:00:00 1970 PST
5312    99 | 509 | 00099_update9      | Fri Apr 10 00:00:00 1970 PST
5313   100 |   0 | 00100              | Thu Jan 01 00:00:00 1970 PST
5314   101 |   1 | 00101              | Fri Jan 02 00:00:00 1970 PST
5315   103 | 303 | 00103_update3      | Sun Jan 04 00:00:00 1970 PST
5316   104 |   4 | 00104              | Mon Jan 05 00:00:00 1970 PST
5317   106 |   6 | 00106              | Wed Jan 07 00:00:00 1970 PST
5318   107 | 407 | 00107_update7      | Thu Jan 08 00:00:00 1970 PST
5319   108 |   8 | 00108              | Fri Jan 09 00:00:00 1970 PST
5320   109 | 509 | 00109_update9      | Sat Jan 10 00:00:00 1970 PST
5321   110 |   0 | 00110              | Sun Jan 11 00:00:00 1970 PST
5322   111 |   1 | 00111              | Mon Jan 12 00:00:00 1970 PST
5323   113 | 303 | 00113_update3      | Wed Jan 14 00:00:00 1970 PST
5324   114 |   4 | 00114              | Thu Jan 15 00:00:00 1970 PST
5325   116 |   6 | 00116              | Sat Jan 17 00:00:00 1970 PST
5326   117 | 407 | 00117_update7      | Sun Jan 18 00:00:00 1970 PST
5327   118 |   8 | 00118              | Mon Jan 19 00:00:00 1970 PST
5328   119 | 509 | 00119_update9      | Tue Jan 20 00:00:00 1970 PST
5329   120 |   0 | 00120              | Wed Jan 21 00:00:00 1970 PST
5330   121 |   1 | 00121              | Thu Jan 22 00:00:00 1970 PST
5331   123 | 303 | 00123_update3      | Sat Jan 24 00:00:00 1970 PST
5332   124 |   4 | 00124              | Sun Jan 25 00:00:00 1970 PST
5333   126 |   6 | 00126              | Tue Jan 27 00:00:00 1970 PST
5334   127 | 407 | 00127_update7      | Wed Jan 28 00:00:00 1970 PST
5335   128 |   8 | 00128              | Thu Jan 29 00:00:00 1970 PST
5336   129 | 509 | 00129_update9      | Fri Jan 30 00:00:00 1970 PST
5337   130 |   0 | 00130              | Sat Jan 31 00:00:00 1970 PST
5338   131 |   1 | 00131              | Sun Feb 01 00:00:00 1970 PST
5339   133 | 303 | 00133_update3      | Tue Feb 03 00:00:00 1970 PST
5340   134 |   4 | 00134              | Wed Feb 04 00:00:00 1970 PST
5341   136 |   6 | 00136              | Fri Feb 06 00:00:00 1970 PST
5342   137 | 407 | 00137_update7      | Sat Feb 07 00:00:00 1970 PST
5343   138 |   8 | 00138              | Sun Feb 08 00:00:00 1970 PST
5344   139 | 509 | 00139_update9      | Mon Feb 09 00:00:00 1970 PST
5345   140 |   0 | 00140              | Tue Feb 10 00:00:00 1970 PST
5346   141 |   1 | 00141              | Wed Feb 11 00:00:00 1970 PST
5347   143 | 303 | 00143_update3      | Fri Feb 13 00:00:00 1970 PST
5348   144 |   4 | 00144              | Sat Feb 14 00:00:00 1970 PST
5349   146 |   6 | 00146              | Mon Feb 16 00:00:00 1970 PST
5350   147 | 407 | 00147_update7      | Tue Feb 17 00:00:00 1970 PST
5351   148 |   8 | 00148              | Wed Feb 18 00:00:00 1970 PST
5352   149 | 509 | 00149_update9      | Thu Feb 19 00:00:00 1970 PST
5353   150 |   0 | 00150              | Fri Feb 20 00:00:00 1970 PST
5354   151 |   1 | 00151              | Sat Feb 21 00:00:00 1970 PST
5355   153 | 303 | 00153_update3      | Mon Feb 23 00:00:00 1970 PST
5356   154 |   4 | 00154              | Tue Feb 24 00:00:00 1970 PST
5357   156 |   6 | 00156              | Thu Feb 26 00:00:00 1970 PST
5358   157 | 407 | 00157_update7      | Fri Feb 27 00:00:00 1970 PST
5359   158 |   8 | 00158              | Sat Feb 28 00:00:00 1970 PST
5360   159 | 509 | 00159_update9      | Sun Mar 01 00:00:00 1970 PST
5361   160 |   0 | 00160              | Mon Mar 02 00:00:00 1970 PST
5362   161 |   1 | 00161              | Tue Mar 03 00:00:00 1970 PST
5363   163 | 303 | 00163_update3      | Thu Mar 05 00:00:00 1970 PST
5364   164 |   4 | 00164              | Fri Mar 06 00:00:00 1970 PST
5365   166 |   6 | 00166              | Sun Mar 08 00:00:00 1970 PST
5366   167 | 407 | 00167_update7      | Mon Mar 09 00:00:00 1970 PST
5367   168 |   8 | 00168              | Tue Mar 10 00:00:00 1970 PST
5368   169 | 509 | 00169_update9      | Wed Mar 11 00:00:00 1970 PST
5369   170 |   0 | 00170              | Thu Mar 12 00:00:00 1970 PST
5370   171 |   1 | 00171              | Fri Mar 13 00:00:00 1970 PST
5371   173 | 303 | 00173_update3      | Sun Mar 15 00:00:00 1970 PST
5372   174 |   4 | 00174              | Mon Mar 16 00:00:00 1970 PST
5373   176 |   6 | 00176              | Wed Mar 18 00:00:00 1970 PST
5374   177 | 407 | 00177_update7      | Thu Mar 19 00:00:00 1970 PST
5375   178 |   8 | 00178              | Fri Mar 20 00:00:00 1970 PST
5376   179 | 509 | 00179_update9      | Sat Mar 21 00:00:00 1970 PST
5377   180 |   0 | 00180              | Sun Mar 22 00:00:00 1970 PST
5378   181 |   1 | 00181              | Mon Mar 23 00:00:00 1970 PST
5379   183 | 303 | 00183_update3      | Wed Mar 25 00:00:00 1970 PST
5380   184 |   4 | 00184              | Thu Mar 26 00:00:00 1970 PST
5381   186 |   6 | 00186              | Sat Mar 28 00:00:00 1970 PST
5382   187 | 407 | 00187_update7      | Sun Mar 29 00:00:00 1970 PST
5383   188 |   8 | 00188              | Mon Mar 30 00:00:00 1970 PST
5384   189 | 509 | 00189_update9      | Tue Mar 31 00:00:00 1970 PST
5385   190 |   0 | 00190              | Wed Apr 01 00:00:00 1970 PST
5386   191 |   1 | 00191              | Thu Apr 02 00:00:00 1970 PST
5387   193 | 303 | 00193_update3      | Sat Apr 04 00:00:00 1970 PST
5388   194 |   4 | 00194              | Sun Apr 05 00:00:00 1970 PST
5389   196 |   6 | 00196              | Tue Apr 07 00:00:00 1970 PST
5390   197 | 407 | 00197_update7      | Wed Apr 08 00:00:00 1970 PST
5391   198 |   8 | 00198              | Thu Apr 09 00:00:00 1970 PST
5392   199 | 509 | 00199_update9      | Fri Apr 10 00:00:00 1970 PST
5393   200 |   0 | 00200              | Thu Jan 01 00:00:00 1970 PST
5394   201 |   1 | 00201              | Fri Jan 02 00:00:00 1970 PST
5395   203 | 303 | 00203_update3      | Sun Jan 04 00:00:00 1970 PST
5396   204 |   4 | 00204              | Mon Jan 05 00:00:00 1970 PST
5397   206 |   6 | 00206              | Wed Jan 07 00:00:00 1970 PST
5398   207 | 407 | 00207_update7      | Thu Jan 08 00:00:00 1970 PST
5399   208 |   8 | 00208              | Fri Jan 09 00:00:00 1970 PST
5400   209 | 509 | 00209_update9      | Sat Jan 10 00:00:00 1970 PST
5401   210 |   0 | 00210              | Sun Jan 11 00:00:00 1970 PST
5402   211 |   1 | 00211              | Mon Jan 12 00:00:00 1970 PST
5403   213 | 303 | 00213_update3      | Wed Jan 14 00:00:00 1970 PST
5404   214 |   4 | 00214              | Thu Jan 15 00:00:00 1970 PST
5405   216 |   6 | 00216              | Sat Jan 17 00:00:00 1970 PST
5406   217 | 407 | 00217_update7      | Sun Jan 18 00:00:00 1970 PST
5407   218 |   8 | 00218              | Mon Jan 19 00:00:00 1970 PST
5408   219 | 509 | 00219_update9      | Tue Jan 20 00:00:00 1970 PST
5409   220 |   0 | 00220              | Wed Jan 21 00:00:00 1970 PST
5410   221 |   1 | 00221              | Thu Jan 22 00:00:00 1970 PST
5411   223 | 303 | 00223_update3      | Sat Jan 24 00:00:00 1970 PST
5412   224 |   4 | 00224              | Sun Jan 25 00:00:00 1970 PST
5413   226 |   6 | 00226              | Tue Jan 27 00:00:00 1970 PST
5414   227 | 407 | 00227_update7      | Wed Jan 28 00:00:00 1970 PST
5415   228 |   8 | 00228              | Thu Jan 29 00:00:00 1970 PST
5416   229 | 509 | 00229_update9      | Fri Jan 30 00:00:00 1970 PST
5417   230 |   0 | 00230              | Sat Jan 31 00:00:00 1970 PST
5418   231 |   1 | 00231              | Sun Feb 01 00:00:00 1970 PST
5419   233 | 303 | 00233_update3      | Tue Feb 03 00:00:00 1970 PST
5420   234 |   4 | 00234              | Wed Feb 04 00:00:00 1970 PST
5421   236 |   6 | 00236              | Fri Feb 06 00:00:00 1970 PST
5422   237 | 407 | 00237_update7      | Sat Feb 07 00:00:00 1970 PST
5423   238 |   8 | 00238              | Sun Feb 08 00:00:00 1970 PST
5424   239 | 509 | 00239_update9      | Mon Feb 09 00:00:00 1970 PST
5425   240 |   0 | 00240              | Tue Feb 10 00:00:00 1970 PST
5426   241 |   1 | 00241              | Wed Feb 11 00:00:00 1970 PST
5427   243 | 303 | 00243_update3      | Fri Feb 13 00:00:00 1970 PST
5428   244 |   4 | 00244              | Sat Feb 14 00:00:00 1970 PST
5429   246 |   6 | 00246              | Mon Feb 16 00:00:00 1970 PST
5430   247 | 407 | 00247_update7      | Tue Feb 17 00:00:00 1970 PST
5431   248 |   8 | 00248              | Wed Feb 18 00:00:00 1970 PST
5432   249 | 509 | 00249_update9      | Thu Feb 19 00:00:00 1970 PST
5433   250 |   0 | 00250              | Fri Feb 20 00:00:00 1970 PST
5434   251 |   1 | 00251              | Sat Feb 21 00:00:00 1970 PST
5435   253 | 303 | 00253_update3      | Mon Feb 23 00:00:00 1970 PST
5436   254 |   4 | 00254              | Tue Feb 24 00:00:00 1970 PST
5437   256 |   6 | 00256              | Thu Feb 26 00:00:00 1970 PST
5438   257 | 407 | 00257_update7      | Fri Feb 27 00:00:00 1970 PST
5439   258 |   8 | 00258              | Sat Feb 28 00:00:00 1970 PST
5440   259 | 509 | 00259_update9      | Sun Mar 01 00:00:00 1970 PST
5441   260 |   0 | 00260              | Mon Mar 02 00:00:00 1970 PST
5442   261 |   1 | 00261              | Tue Mar 03 00:00:00 1970 PST
5443   263 | 303 | 00263_update3      | Thu Mar 05 00:00:00 1970 PST
5444   264 |   4 | 00264              | Fri Mar 06 00:00:00 1970 PST
5445   266 |   6 | 00266              | Sun Mar 08 00:00:00 1970 PST
5446   267 | 407 | 00267_update7      | Mon Mar 09 00:00:00 1970 PST
5447   268 |   8 | 00268              | Tue Mar 10 00:00:00 1970 PST
5448   269 | 509 | 00269_update9      | Wed Mar 11 00:00:00 1970 PST
5449   270 |   0 | 00270              | Thu Mar 12 00:00:00 1970 PST
5450   271 |   1 | 00271              | Fri Mar 13 00:00:00 1970 PST
5451   273 | 303 | 00273_update3      | Sun Mar 15 00:00:00 1970 PST
5452   274 |   4 | 00274              | Mon Mar 16 00:00:00 1970 PST
5453   276 |   6 | 00276              | Wed Mar 18 00:00:00 1970 PST
5454   277 | 407 | 00277_update7      | Thu Mar 19 00:00:00 1970 PST
5455   278 |   8 | 00278              | Fri Mar 20 00:00:00 1970 PST
5456   279 | 509 | 00279_update9      | Sat Mar 21 00:00:00 1970 PST
5457   280 |   0 | 00280              | Sun Mar 22 00:00:00 1970 PST
5458   281 |   1 | 00281              | Mon Mar 23 00:00:00 1970 PST
5459   283 | 303 | 00283_update3      | Wed Mar 25 00:00:00 1970 PST
5460   284 |   4 | 00284              | Thu Mar 26 00:00:00 1970 PST
5461   286 |   6 | 00286              | Sat Mar 28 00:00:00 1970 PST
5462   287 | 407 | 00287_update7      | Sun Mar 29 00:00:00 1970 PST
5463   288 |   8 | 00288              | Mon Mar 30 00:00:00 1970 PST
5464   289 | 509 | 00289_update9      | Tue Mar 31 00:00:00 1970 PST
5465   290 |   0 | 00290              | Wed Apr 01 00:00:00 1970 PST
5466   291 |   1 | 00291              | Thu Apr 02 00:00:00 1970 PST
5467   293 | 303 | 00293_update3      | Sat Apr 04 00:00:00 1970 PST
5468   294 |   4 | 00294              | Sun Apr 05 00:00:00 1970 PST
5469   296 |   6 | 00296              | Tue Apr 07 00:00:00 1970 PST
5470   297 | 407 | 00297_update7      | Wed Apr 08 00:00:00 1970 PST
5471   298 |   8 | 00298              | Thu Apr 09 00:00:00 1970 PST
5472   299 | 509 | 00299_update9      | Fri Apr 10 00:00:00 1970 PST
5473   300 |   0 | 00300              | Thu Jan 01 00:00:00 1970 PST
5474   301 |   1 | 00301              | Fri Jan 02 00:00:00 1970 PST
5475   303 | 303 | 00303_update3      | Sun Jan 04 00:00:00 1970 PST
5476   304 |   4 | 00304              | Mon Jan 05 00:00:00 1970 PST
5477   306 |   6 | 00306              | Wed Jan 07 00:00:00 1970 PST
5478   307 | 407 | 00307_update7      | Thu Jan 08 00:00:00 1970 PST
5479   308 |   8 | 00308              | Fri Jan 09 00:00:00 1970 PST
5480   309 | 509 | 00309_update9      | Sat Jan 10 00:00:00 1970 PST
5481   310 |   0 | 00310              | Sun Jan 11 00:00:00 1970 PST
5482   311 |   1 | 00311              | Mon Jan 12 00:00:00 1970 PST
5483   313 | 303 | 00313_update3      | Wed Jan 14 00:00:00 1970 PST
5484   314 |   4 | 00314              | Thu Jan 15 00:00:00 1970 PST
5485   316 |   6 | 00316              | Sat Jan 17 00:00:00 1970 PST
5486   317 | 407 | 00317_update7      | Sun Jan 18 00:00:00 1970 PST
5487   318 |   8 | 00318              | Mon Jan 19 00:00:00 1970 PST
5488   319 | 509 | 00319_update9      | Tue Jan 20 00:00:00 1970 PST
5489   320 |   0 | 00320              | Wed Jan 21 00:00:00 1970 PST
5490   321 |   1 | 00321              | Thu Jan 22 00:00:00 1970 PST
5491   323 | 303 | 00323_update3      | Sat Jan 24 00:00:00 1970 PST
5492   324 |   4 | 00324              | Sun Jan 25 00:00:00 1970 PST
5493   326 |   6 | 00326              | Tue Jan 27 00:00:00 1970 PST
5494   327 | 407 | 00327_update7      | Wed Jan 28 00:00:00 1970 PST
5495   328 |   8 | 00328              | Thu Jan 29 00:00:00 1970 PST
5496   329 | 509 | 00329_update9      | Fri Jan 30 00:00:00 1970 PST
5497   330 |   0 | 00330              | Sat Jan 31 00:00:00 1970 PST
5498   331 |   1 | 00331              | Sun Feb 01 00:00:00 1970 PST
5499   333 | 303 | 00333_update3      | Tue Feb 03 00:00:00 1970 PST
5500   334 |   4 | 00334              | Wed Feb 04 00:00:00 1970 PST
5501   336 |   6 | 00336              | Fri Feb 06 00:00:00 1970 PST
5502   337 | 407 | 00337_update7      | Sat Feb 07 00:00:00 1970 PST
5503   338 |   8 | 00338              | Sun Feb 08 00:00:00 1970 PST
5504   339 | 509 | 00339_update9      | Mon Feb 09 00:00:00 1970 PST
5505   340 |   0 | 00340              | Tue Feb 10 00:00:00 1970 PST
5506   341 |   1 | 00341              | Wed Feb 11 00:00:00 1970 PST
5507   343 | 303 | 00343_update3      | Fri Feb 13 00:00:00 1970 PST
5508   344 |   4 | 00344              | Sat Feb 14 00:00:00 1970 PST
5509   346 |   6 | 00346              | Mon Feb 16 00:00:00 1970 PST
5510   347 | 407 | 00347_update7      | Tue Feb 17 00:00:00 1970 PST
5511   348 |   8 | 00348              | Wed Feb 18 00:00:00 1970 PST
5512   349 | 509 | 00349_update9      | Thu Feb 19 00:00:00 1970 PST
5513   350 |   0 | 00350              | Fri Feb 20 00:00:00 1970 PST
5514   351 |   1 | 00351              | Sat Feb 21 00:00:00 1970 PST
5515   353 | 303 | 00353_update3      | Mon Feb 23 00:00:00 1970 PST
5516   354 |   4 | 00354              | Tue Feb 24 00:00:00 1970 PST
5517   356 |   6 | 00356              | Thu Feb 26 00:00:00 1970 PST
5518   357 | 407 | 00357_update7      | Fri Feb 27 00:00:00 1970 PST
5519   358 |   8 | 00358              | Sat Feb 28 00:00:00 1970 PST
5520   359 | 509 | 00359_update9      | Sun Mar 01 00:00:00 1970 PST
5521   360 |   0 | 00360              | Mon Mar 02 00:00:00 1970 PST
5522   361 |   1 | 00361              | Tue Mar 03 00:00:00 1970 PST
5523   363 | 303 | 00363_update3      | Thu Mar 05 00:00:00 1970 PST
5524   364 |   4 | 00364              | Fri Mar 06 00:00:00 1970 PST
5525   366 |   6 | 00366              | Sun Mar 08 00:00:00 1970 PST
5526   367 | 407 | 00367_update7      | Mon Mar 09 00:00:00 1970 PST
5527   368 |   8 | 00368              | Tue Mar 10 00:00:00 1970 PST
5528   369 | 509 | 00369_update9      | Wed Mar 11 00:00:00 1970 PST
5529   370 |   0 | 00370              | Thu Mar 12 00:00:00 1970 PST
5530   371 |   1 | 00371              | Fri Mar 13 00:00:00 1970 PST
5531   373 | 303 | 00373_update3      | Sun Mar 15 00:00:00 1970 PST
5532   374 |   4 | 00374              | Mon Mar 16 00:00:00 1970 PST
5533   376 |   6 | 00376              | Wed Mar 18 00:00:00 1970 PST
5534   377 | 407 | 00377_update7      | Thu Mar 19 00:00:00 1970 PST
5535   378 |   8 | 00378              | Fri Mar 20 00:00:00 1970 PST
5536   379 | 509 | 00379_update9      | Sat Mar 21 00:00:00 1970 PST
5537   380 |   0 | 00380              | Sun Mar 22 00:00:00 1970 PST
5538   381 |   1 | 00381              | Mon Mar 23 00:00:00 1970 PST
5539   383 | 303 | 00383_update3      | Wed Mar 25 00:00:00 1970 PST
5540   384 |   4 | 00384              | Thu Mar 26 00:00:00 1970 PST
5541   386 |   6 | 00386              | Sat Mar 28 00:00:00 1970 PST
5542   387 | 407 | 00387_update7      | Sun Mar 29 00:00:00 1970 PST
5543   388 |   8 | 00388              | Mon Mar 30 00:00:00 1970 PST
5544   389 | 509 | 00389_update9      | Tue Mar 31 00:00:00 1970 PST
5545   390 |   0 | 00390              | Wed Apr 01 00:00:00 1970 PST
5546   391 |   1 | 00391              | Thu Apr 02 00:00:00 1970 PST
5547   393 | 303 | 00393_update3      | Sat Apr 04 00:00:00 1970 PST
5548   394 |   4 | 00394              | Sun Apr 05 00:00:00 1970 PST
5549   396 |   6 | 00396              | Tue Apr 07 00:00:00 1970 PST
5550   397 | 407 | 00397_update7      | Wed Apr 08 00:00:00 1970 PST
5551   398 |   8 | 00398              | Thu Apr 09 00:00:00 1970 PST
5552   399 | 509 | 00399_update9      | Fri Apr 10 00:00:00 1970 PST
5553   400 |   0 | 00400              | Thu Jan 01 00:00:00 1970 PST
5554   401 |   1 | 00401              | Fri Jan 02 00:00:00 1970 PST
5555   403 | 303 | 00403_update3      | Sun Jan 04 00:00:00 1970 PST
5556   404 |   4 | 00404              | Mon Jan 05 00:00:00 1970 PST
5557   406 |   6 | 00406              | Wed Jan 07 00:00:00 1970 PST
5558   407 | 407 | 00407_update7      | Thu Jan 08 00:00:00 1970 PST
5559   408 |   8 | 00408              | Fri Jan 09 00:00:00 1970 PST
5560   409 | 509 | 00409_update9      | Sat Jan 10 00:00:00 1970 PST
5561   410 |   0 | 00410              | Sun Jan 11 00:00:00 1970 PST
5562   411 |   1 | 00411              | Mon Jan 12 00:00:00 1970 PST
5563   413 | 303 | 00413_update3      | Wed Jan 14 00:00:00 1970 PST
5564   414 |   4 | 00414              | Thu Jan 15 00:00:00 1970 PST
5565   416 |   6 | 00416              | Sat Jan 17 00:00:00 1970 PST
5566   417 | 407 | 00417_update7      | Sun Jan 18 00:00:00 1970 PST
5567   418 |   8 | 00418              | Mon Jan 19 00:00:00 1970 PST
5568   419 | 509 | 00419_update9      | Tue Jan 20 00:00:00 1970 PST
5569   420 |   0 | 00420              | Wed Jan 21 00:00:00 1970 PST
5570   421 |   1 | 00421              | Thu Jan 22 00:00:00 1970 PST
5571   423 | 303 | 00423_update3      | Sat Jan 24 00:00:00 1970 PST
5572   424 |   4 | 00424              | Sun Jan 25 00:00:00 1970 PST
5573   426 |   6 | 00426              | Tue Jan 27 00:00:00 1970 PST
5574   427 | 407 | 00427_update7      | Wed Jan 28 00:00:00 1970 PST
5575   428 |   8 | 00428              | Thu Jan 29 00:00:00 1970 PST
5576   429 | 509 | 00429_update9      | Fri Jan 30 00:00:00 1970 PST
5577   430 |   0 | 00430              | Sat Jan 31 00:00:00 1970 PST
5578   431 |   1 | 00431              | Sun Feb 01 00:00:00 1970 PST
5579   433 | 303 | 00433_update3      | Tue Feb 03 00:00:00 1970 PST
5580   434 |   4 | 00434              | Wed Feb 04 00:00:00 1970 PST
5581   436 |   6 | 00436              | Fri Feb 06 00:00:00 1970 PST
5582   437 | 407 | 00437_update7      | Sat Feb 07 00:00:00 1970 PST
5583   438 |   8 | 00438              | Sun Feb 08 00:00:00 1970 PST
5584   439 | 509 | 00439_update9      | Mon Feb 09 00:00:00 1970 PST
5585   440 |   0 | 00440              | Tue Feb 10 00:00:00 1970 PST
5586   441 |   1 | 00441              | Wed Feb 11 00:00:00 1970 PST
5587   443 | 303 | 00443_update3      | Fri Feb 13 00:00:00 1970 PST
5588   444 |   4 | 00444              | Sat Feb 14 00:00:00 1970 PST
5589   446 |   6 | 00446              | Mon Feb 16 00:00:00 1970 PST
5590   447 | 407 | 00447_update7      | Tue Feb 17 00:00:00 1970 PST
5591   448 |   8 | 00448              | Wed Feb 18 00:00:00 1970 PST
5592   449 | 509 | 00449_update9      | Thu Feb 19 00:00:00 1970 PST
5593   450 |   0 | 00450              | Fri Feb 20 00:00:00 1970 PST
5594   451 |   1 | 00451              | Sat Feb 21 00:00:00 1970 PST
5595   453 | 303 | 00453_update3      | Mon Feb 23 00:00:00 1970 PST
5596   454 |   4 | 00454              | Tue Feb 24 00:00:00 1970 PST
5597   456 |   6 | 00456              | Thu Feb 26 00:00:00 1970 PST
5598   457 | 407 | 00457_update7      | Fri Feb 27 00:00:00 1970 PST
5599   458 |   8 | 00458              | Sat Feb 28 00:00:00 1970 PST
5600   459 | 509 | 00459_update9      | Sun Mar 01 00:00:00 1970 PST
5601   460 |   0 | 00460              | Mon Mar 02 00:00:00 1970 PST
5602   461 |   1 | 00461              | Tue Mar 03 00:00:00 1970 PST
5603   463 | 303 | 00463_update3      | Thu Mar 05 00:00:00 1970 PST
5604   464 |   4 | 00464              | Fri Mar 06 00:00:00 1970 PST
5605   466 |   6 | 00466              | Sun Mar 08 00:00:00 1970 PST
5606   467 | 407 | 00467_update7      | Mon Mar 09 00:00:00 1970 PST
5607   468 |   8 | 00468              | Tue Mar 10 00:00:00 1970 PST
5608   469 | 509 | 00469_update9      | Wed Mar 11 00:00:00 1970 PST
5609   470 |   0 | 00470              | Thu Mar 12 00:00:00 1970 PST
5610   471 |   1 | 00471              | Fri Mar 13 00:00:00 1970 PST
5611   473 | 303 | 00473_update3      | Sun Mar 15 00:00:00 1970 PST
5612   474 |   4 | 00474              | Mon Mar 16 00:00:00 1970 PST
5613   476 |   6 | 00476              | Wed Mar 18 00:00:00 1970 PST
5614   477 | 407 | 00477_update7      | Thu Mar 19 00:00:00 1970 PST
5615   478 |   8 | 00478              | Fri Mar 20 00:00:00 1970 PST
5616   479 | 509 | 00479_update9      | Sat Mar 21 00:00:00 1970 PST
5617   480 |   0 | 00480              | Sun Mar 22 00:00:00 1970 PST
5618   481 |   1 | 00481              | Mon Mar 23 00:00:00 1970 PST
5619   483 | 303 | 00483_update3      | Wed Mar 25 00:00:00 1970 PST
5620   484 |   4 | 00484              | Thu Mar 26 00:00:00 1970 PST
5621   486 |   6 | 00486              | Sat Mar 28 00:00:00 1970 PST
5622   487 | 407 | 00487_update7      | Sun Mar 29 00:00:00 1970 PST
5623   488 |   8 | 00488              | Mon Mar 30 00:00:00 1970 PST
5624   489 | 509 | 00489_update9      | Tue Mar 31 00:00:00 1970 PST
5625   490 |   0 | 00490              | Wed Apr 01 00:00:00 1970 PST
5626   491 |   1 | 00491              | Thu Apr 02 00:00:00 1970 PST
5627   493 | 303 | 00493_update3      | Sat Apr 04 00:00:00 1970 PST
5628   494 |   4 | 00494              | Sun Apr 05 00:00:00 1970 PST
5629   496 |   6 | 00496              | Tue Apr 07 00:00:00 1970 PST
5630   497 | 407 | 00497_update7      | Wed Apr 08 00:00:00 1970 PST
5631   498 |   8 | 00498              | Thu Apr 09 00:00:00 1970 PST
5632   499 | 509 | 00499_update9      | Fri Apr 10 00:00:00 1970 PST
5633   500 |   0 | 00500              | Thu Jan 01 00:00:00 1970 PST
5634   501 |   1 | 00501              | Fri Jan 02 00:00:00 1970 PST
5635   503 | 303 | 00503_update3      | Sun Jan 04 00:00:00 1970 PST
5636   504 |   4 | 00504              | Mon Jan 05 00:00:00 1970 PST
5637   506 |   6 | 00506              | Wed Jan 07 00:00:00 1970 PST
5638   507 | 407 | 00507_update7      | Thu Jan 08 00:00:00 1970 PST
5639   508 |   8 | 00508              | Fri Jan 09 00:00:00 1970 PST
5640   509 | 509 | 00509_update9      | Sat Jan 10 00:00:00 1970 PST
5641   510 |   0 | 00510              | Sun Jan 11 00:00:00 1970 PST
5642   511 |   1 | 00511              | Mon Jan 12 00:00:00 1970 PST
5643   513 | 303 | 00513_update3      | Wed Jan 14 00:00:00 1970 PST
5644   514 |   4 | 00514              | Thu Jan 15 00:00:00 1970 PST
5645   516 |   6 | 00516              | Sat Jan 17 00:00:00 1970 PST
5646   517 | 407 | 00517_update7      | Sun Jan 18 00:00:00 1970 PST
5647   518 |   8 | 00518              | Mon Jan 19 00:00:00 1970 PST
5648   519 | 509 | 00519_update9      | Tue Jan 20 00:00:00 1970 PST
5649   520 |   0 | 00520              | Wed Jan 21 00:00:00 1970 PST
5650   521 |   1 | 00521              | Thu Jan 22 00:00:00 1970 PST
5651   523 | 303 | 00523_update3      | Sat Jan 24 00:00:00 1970 PST
5652   524 |   4 | 00524              | Sun Jan 25 00:00:00 1970 PST
5653   526 |   6 | 00526              | Tue Jan 27 00:00:00 1970 PST
5654   527 | 407 | 00527_update7      | Wed Jan 28 00:00:00 1970 PST
5655   528 |   8 | 00528              | Thu Jan 29 00:00:00 1970 PST
5656   529 | 509 | 00529_update9      | Fri Jan 30 00:00:00 1970 PST
5657   530 |   0 | 00530              | Sat Jan 31 00:00:00 1970 PST
5658   531 |   1 | 00531              | Sun Feb 01 00:00:00 1970 PST
5659   533 | 303 | 00533_update3      | Tue Feb 03 00:00:00 1970 PST
5660   534 |   4 | 00534              | Wed Feb 04 00:00:00 1970 PST
5661   536 |   6 | 00536              | Fri Feb 06 00:00:00 1970 PST
5662   537 | 407 | 00537_update7      | Sat Feb 07 00:00:00 1970 PST
5663   538 |   8 | 00538              | Sun Feb 08 00:00:00 1970 PST
5664   539 | 509 | 00539_update9      | Mon Feb 09 00:00:00 1970 PST
5665   540 |   0 | 00540              | Tue Feb 10 00:00:00 1970 PST
5666   541 |   1 | 00541              | Wed Feb 11 00:00:00 1970 PST
5667   543 | 303 | 00543_update3      | Fri Feb 13 00:00:00 1970 PST
5668   544 |   4 | 00544              | Sat Feb 14 00:00:00 1970 PST
5669   546 |   6 | 00546              | Mon Feb 16 00:00:00 1970 PST
5670   547 | 407 | 00547_update7      | Tue Feb 17 00:00:00 1970 PST
5671   548 |   8 | 00548              | Wed Feb 18 00:00:00 1970 PST
5672   549 | 509 | 00549_update9      | Thu Feb 19 00:00:00 1970 PST
5673   550 |   0 | 00550              | Fri Feb 20 00:00:00 1970 PST
5674   551 |   1 | 00551              | Sat Feb 21 00:00:00 1970 PST
5675   553 | 303 | 00553_update3      | Mon Feb 23 00:00:00 1970 PST
5676   554 |   4 | 00554              | Tue Feb 24 00:00:00 1970 PST
5677   556 |   6 | 00556              | Thu Feb 26 00:00:00 1970 PST
5678   557 | 407 | 00557_update7      | Fri Feb 27 00:00:00 1970 PST
5679   558 |   8 | 00558              | Sat Feb 28 00:00:00 1970 PST
5680   559 | 509 | 00559_update9      | Sun Mar 01 00:00:00 1970 PST
5681   560 |   0 | 00560              | Mon Mar 02 00:00:00 1970 PST
5682   561 |   1 | 00561              | Tue Mar 03 00:00:00 1970 PST
5683   563 | 303 | 00563_update3      | Thu Mar 05 00:00:00 1970 PST
5684   564 |   4 | 00564              | Fri Mar 06 00:00:00 1970 PST
5685   566 |   6 | 00566              | Sun Mar 08 00:00:00 1970 PST
5686   567 | 407 | 00567_update7      | Mon Mar 09 00:00:00 1970 PST
5687   568 |   8 | 00568              | Tue Mar 10 00:00:00 1970 PST
5688   569 | 509 | 00569_update9      | Wed Mar 11 00:00:00 1970 PST
5689   570 |   0 | 00570              | Thu Mar 12 00:00:00 1970 PST
5690   571 |   1 | 00571              | Fri Mar 13 00:00:00 1970 PST
5691   573 | 303 | 00573_update3      | Sun Mar 15 00:00:00 1970 PST
5692   574 |   4 | 00574              | Mon Mar 16 00:00:00 1970 PST
5693   576 |   6 | 00576              | Wed Mar 18 00:00:00 1970 PST
5694   577 | 407 | 00577_update7      | Thu Mar 19 00:00:00 1970 PST
5695   578 |   8 | 00578              | Fri Mar 20 00:00:00 1970 PST
5696   579 | 509 | 00579_update9      | Sat Mar 21 00:00:00 1970 PST
5697   580 |   0 | 00580              | Sun Mar 22 00:00:00 1970 PST
5698   581 |   1 | 00581              | Mon Mar 23 00:00:00 1970 PST
5699   583 | 303 | 00583_update3      | Wed Mar 25 00:00:00 1970 PST
5700   584 |   4 | 00584              | Thu Mar 26 00:00:00 1970 PST
5701   586 |   6 | 00586              | Sat Mar 28 00:00:00 1970 PST
5702   587 | 407 | 00587_update7      | Sun Mar 29 00:00:00 1970 PST
5703   588 |   8 | 00588              | Mon Mar 30 00:00:00 1970 PST
5704   589 | 509 | 00589_update9      | Tue Mar 31 00:00:00 1970 PST
5705   590 |   0 | 00590              | Wed Apr 01 00:00:00 1970 PST
5706   591 |   1 | 00591              | Thu Apr 02 00:00:00 1970 PST
5707   593 | 303 | 00593_update3      | Sat Apr 04 00:00:00 1970 PST
5708   594 |   4 | 00594              | Sun Apr 05 00:00:00 1970 PST
5709   596 |   6 | 00596              | Tue Apr 07 00:00:00 1970 PST
5710   597 | 407 | 00597_update7      | Wed Apr 08 00:00:00 1970 PST
5711   598 |   8 | 00598              | Thu Apr 09 00:00:00 1970 PST
5712   599 | 509 | 00599_update9      | Fri Apr 10 00:00:00 1970 PST
5713   600 |   0 | 00600              | Thu Jan 01 00:00:00 1970 PST
5714   601 |   1 | 00601              | Fri Jan 02 00:00:00 1970 PST
5715   603 | 303 | 00603_update3      | Sun Jan 04 00:00:00 1970 PST
5716   604 |   4 | 00604              | Mon Jan 05 00:00:00 1970 PST
5717   606 |   6 | 00606              | Wed Jan 07 00:00:00 1970 PST
5718   607 | 407 | 00607_update7      | Thu Jan 08 00:00:00 1970 PST
5719   608 |   8 | 00608              | Fri Jan 09 00:00:00 1970 PST
5720   609 | 509 | 00609_update9      | Sat Jan 10 00:00:00 1970 PST
5721   610 |   0 | 00610              | Sun Jan 11 00:00:00 1970 PST
5722   611 |   1 | 00611              | Mon Jan 12 00:00:00 1970 PST
5723   613 | 303 | 00613_update3      | Wed Jan 14 00:00:00 1970 PST
5724   614 |   4 | 00614              | Thu Jan 15 00:00:00 1970 PST
5725   616 |   6 | 00616              | Sat Jan 17 00:00:00 1970 PST
5726   617 | 407 | 00617_update7      | Sun Jan 18 00:00:00 1970 PST
5727   618 |   8 | 00618              | Mon Jan 19 00:00:00 1970 PST
5728   619 | 509 | 00619_update9      | Tue Jan 20 00:00:00 1970 PST
5729   620 |   0 | 00620              | Wed Jan 21 00:00:00 1970 PST
5730   621 |   1 | 00621              | Thu Jan 22 00:00:00 1970 PST
5731   623 | 303 | 00623_update3      | Sat Jan 24 00:00:00 1970 PST
5732   624 |   4 | 00624              | Sun Jan 25 00:00:00 1970 PST
5733   626 |   6 | 00626              | Tue Jan 27 00:00:00 1970 PST
5734   627 | 407 | 00627_update7      | Wed Jan 28 00:00:00 1970 PST
5735   628 |   8 | 00628              | Thu Jan 29 00:00:00 1970 PST
5736   629 | 509 | 00629_update9      | Fri Jan 30 00:00:00 1970 PST
5737   630 |   0 | 00630              | Sat Jan 31 00:00:00 1970 PST
5738   631 |   1 | 00631              | Sun Feb 01 00:00:00 1970 PST
5739   633 | 303 | 00633_update3      | Tue Feb 03 00:00:00 1970 PST
5740   634 |   4 | 00634              | Wed Feb 04 00:00:00 1970 PST
5741   636 |   6 | 00636              | Fri Feb 06 00:00:00 1970 PST
5742   637 | 407 | 00637_update7      | Sat Feb 07 00:00:00 1970 PST
5743   638 |   8 | 00638              | Sun Feb 08 00:00:00 1970 PST
5744   639 | 509 | 00639_update9      | Mon Feb 09 00:00:00 1970 PST
5745   640 |   0 | 00640              | Tue Feb 10 00:00:00 1970 PST
5746   641 |   1 | 00641              | Wed Feb 11 00:00:00 1970 PST
5747   643 | 303 | 00643_update3      | Fri Feb 13 00:00:00 1970 PST
5748   644 |   4 | 00644              | Sat Feb 14 00:00:00 1970 PST
5749   646 |   6 | 00646              | Mon Feb 16 00:00:00 1970 PST
5750   647 | 407 | 00647_update7      | Tue Feb 17 00:00:00 1970 PST
5751   648 |   8 | 00648              | Wed Feb 18 00:00:00 1970 PST
5752   649 | 509 | 00649_update9      | Thu Feb 19 00:00:00 1970 PST
5753   650 |   0 | 00650              | Fri Feb 20 00:00:00 1970 PST
5754   651 |   1 | 00651              | Sat Feb 21 00:00:00 1970 PST
5755   653 | 303 | 00653_update3      | Mon Feb 23 00:00:00 1970 PST
5756   654 |   4 | 00654              | Tue Feb 24 00:00:00 1970 PST
5757   656 |   6 | 00656              | Thu Feb 26 00:00:00 1970 PST
5758   657 | 407 | 00657_update7      | Fri Feb 27 00:00:00 1970 PST
5759   658 |   8 | 00658              | Sat Feb 28 00:00:00 1970 PST
5760   659 | 509 | 00659_update9      | Sun Mar 01 00:00:00 1970 PST
5761   660 |   0 | 00660              | Mon Mar 02 00:00:00 1970 PST
5762   661 |   1 | 00661              | Tue Mar 03 00:00:00 1970 PST
5763   663 | 303 | 00663_update3      | Thu Mar 05 00:00:00 1970 PST
5764   664 |   4 | 00664              | Fri Mar 06 00:00:00 1970 PST
5765   666 |   6 | 00666              | Sun Mar 08 00:00:00 1970 PST
5766   667 | 407 | 00667_update7      | Mon Mar 09 00:00:00 1970 PST
5767   668 |   8 | 00668              | Tue Mar 10 00:00:00 1970 PST
5768   669 | 509 | 00669_update9      | Wed Mar 11 00:00:00 1970 PST
5769   670 |   0 | 00670              | Thu Mar 12 00:00:00 1970 PST
5770   671 |   1 | 00671              | Fri Mar 13 00:00:00 1970 PST
5771   673 | 303 | 00673_update3      | Sun Mar 15 00:00:00 1970 PST
5772   674 |   4 | 00674              | Mon Mar 16 00:00:00 1970 PST
5773   676 |   6 | 00676              | Wed Mar 18 00:00:00 1970 PST
5774   677 | 407 | 00677_update7      | Thu Mar 19 00:00:00 1970 PST
5775   678 |   8 | 00678              | Fri Mar 20 00:00:00 1970 PST
5776   679 | 509 | 00679_update9      | Sat Mar 21 00:00:00 1970 PST
5777   680 |   0 | 00680              | Sun Mar 22 00:00:00 1970 PST
5778   681 |   1 | 00681              | Mon Mar 23 00:00:00 1970 PST
5779   683 | 303 | 00683_update3      | Wed Mar 25 00:00:00 1970 PST
5780   684 |   4 | 00684              | Thu Mar 26 00:00:00 1970 PST
5781   686 |   6 | 00686              | Sat Mar 28 00:00:00 1970 PST
5782   687 | 407 | 00687_update7      | Sun Mar 29 00:00:00 1970 PST
5783   688 |   8 | 00688              | Mon Mar 30 00:00:00 1970 PST
5784   689 | 509 | 00689_update9      | Tue Mar 31 00:00:00 1970 PST
5785   690 |   0 | 00690              | Wed Apr 01 00:00:00 1970 PST
5786   691 |   1 | 00691              | Thu Apr 02 00:00:00 1970 PST
5787   693 | 303 | 00693_update3      | Sat Apr 04 00:00:00 1970 PST
5788   694 |   4 | 00694              | Sun Apr 05 00:00:00 1970 PST
5789   696 |   6 | 00696              | Tue Apr 07 00:00:00 1970 PST
5790   697 | 407 | 00697_update7      | Wed Apr 08 00:00:00 1970 PST
5791   698 |   8 | 00698              | Thu Apr 09 00:00:00 1970 PST
5792   699 | 509 | 00699_update9      | Fri Apr 10 00:00:00 1970 PST
5793   700 |   0 | 00700              | Thu Jan 01 00:00:00 1970 PST
5794   701 |   1 | 00701              | Fri Jan 02 00:00:00 1970 PST
5795   703 | 303 | 00703_update3      | Sun Jan 04 00:00:00 1970 PST
5796   704 |   4 | 00704              | Mon Jan 05 00:00:00 1970 PST
5797   706 |   6 | 00706              | Wed Jan 07 00:00:00 1970 PST
5798   707 | 407 | 00707_update7      | Thu Jan 08 00:00:00 1970 PST
5799   708 |   8 | 00708              | Fri Jan 09 00:00:00 1970 PST
5800   709 | 509 | 00709_update9      | Sat Jan 10 00:00:00 1970 PST
5801   710 |   0 | 00710              | Sun Jan 11 00:00:00 1970 PST
5802   711 |   1 | 00711              | Mon Jan 12 00:00:00 1970 PST
5803   713 | 303 | 00713_update3      | Wed Jan 14 00:00:00 1970 PST
5804   714 |   4 | 00714              | Thu Jan 15 00:00:00 1970 PST
5805   716 |   6 | 00716              | Sat Jan 17 00:00:00 1970 PST
5806   717 | 407 | 00717_update7      | Sun Jan 18 00:00:00 1970 PST
5807   718 |   8 | 00718              | Mon Jan 19 00:00:00 1970 PST
5808   719 | 509 | 00719_update9      | Tue Jan 20 00:00:00 1970 PST
5809   720 |   0 | 00720              | Wed Jan 21 00:00:00 1970 PST
5810   721 |   1 | 00721              | Thu Jan 22 00:00:00 1970 PST
5811   723 | 303 | 00723_update3      | Sat Jan 24 00:00:00 1970 PST
5812   724 |   4 | 00724              | Sun Jan 25 00:00:00 1970 PST
5813   726 |   6 | 00726              | Tue Jan 27 00:00:00 1970 PST
5814   727 | 407 | 00727_update7      | Wed Jan 28 00:00:00 1970 PST
5815   728 |   8 | 00728              | Thu Jan 29 00:00:00 1970 PST
5816   729 | 509 | 00729_update9      | Fri Jan 30 00:00:00 1970 PST
5817   730 |   0 | 00730              | Sat Jan 31 00:00:00 1970 PST
5818   731 |   1 | 00731              | Sun Feb 01 00:00:00 1970 PST
5819   733 | 303 | 00733_update3      | Tue Feb 03 00:00:00 1970 PST
5820   734 |   4 | 00734              | Wed Feb 04 00:00:00 1970 PST
5821   736 |   6 | 00736              | Fri Feb 06 00:00:00 1970 PST
5822   737 | 407 | 00737_update7      | Sat Feb 07 00:00:00 1970 PST
5823   738 |   8 | 00738              | Sun Feb 08 00:00:00 1970 PST
5824   739 | 509 | 00739_update9      | Mon Feb 09 00:00:00 1970 PST
5825   740 |   0 | 00740              | Tue Feb 10 00:00:00 1970 PST
5826   741 |   1 | 00741              | Wed Feb 11 00:00:00 1970 PST
5827   743 | 303 | 00743_update3      | Fri Feb 13 00:00:00 1970 PST
5828   744 |   4 | 00744              | Sat Feb 14 00:00:00 1970 PST
5829   746 |   6 | 00746              | Mon Feb 16 00:00:00 1970 PST
5830   747 | 407 | 00747_update7      | Tue Feb 17 00:00:00 1970 PST
5831   748 |   8 | 00748              | Wed Feb 18 00:00:00 1970 PST
5832   749 | 509 | 00749_update9      | Thu Feb 19 00:00:00 1970 PST
5833   750 |   0 | 00750              | Fri Feb 20 00:00:00 1970 PST
5834   751 |   1 | 00751              | Sat Feb 21 00:00:00 1970 PST
5835   753 | 303 | 00753_update3      | Mon Feb 23 00:00:00 1970 PST
5836   754 |   4 | 00754              | Tue Feb 24 00:00:00 1970 PST
5837   756 |   6 | 00756              | Thu Feb 26 00:00:00 1970 PST
5838   757 | 407 | 00757_update7      | Fri Feb 27 00:00:00 1970 PST
5839   758 |   8 | 00758              | Sat Feb 28 00:00:00 1970 PST
5840   759 | 509 | 00759_update9      | Sun Mar 01 00:00:00 1970 PST
5841   760 |   0 | 00760              | Mon Mar 02 00:00:00 1970 PST
5842   761 |   1 | 00761              | Tue Mar 03 00:00:00 1970 PST
5843   763 | 303 | 00763_update3      | Thu Mar 05 00:00:00 1970 PST
5844   764 |   4 | 00764              | Fri Mar 06 00:00:00 1970 PST
5845   766 |   6 | 00766              | Sun Mar 08 00:00:00 1970 PST
5846   767 | 407 | 00767_update7      | Mon Mar 09 00:00:00 1970 PST
5847   768 |   8 | 00768              | Tue Mar 10 00:00:00 1970 PST
5848   769 | 509 | 00769_update9      | Wed Mar 11 00:00:00 1970 PST
5849   770 |   0 | 00770              | Thu Mar 12 00:00:00 1970 PST
5850   771 |   1 | 00771              | Fri Mar 13 00:00:00 1970 PST
5851   773 | 303 | 00773_update3      | Sun Mar 15 00:00:00 1970 PST
5852   774 |   4 | 00774              | Mon Mar 16 00:00:00 1970 PST
5853   776 |   6 | 00776              | Wed Mar 18 00:00:00 1970 PST
5854   777 | 407 | 00777_update7      | Thu Mar 19 00:00:00 1970 PST
5855   778 |   8 | 00778              | Fri Mar 20 00:00:00 1970 PST
5856   779 | 509 | 00779_update9      | Sat Mar 21 00:00:00 1970 PST
5857   780 |   0 | 00780              | Sun Mar 22 00:00:00 1970 PST
5858   781 |   1 | 00781              | Mon Mar 23 00:00:00 1970 PST
5859   783 | 303 | 00783_update3      | Wed Mar 25 00:00:00 1970 PST
5860   784 |   4 | 00784              | Thu Mar 26 00:00:00 1970 PST
5861   786 |   6 | 00786              | Sat Mar 28 00:00:00 1970 PST
5862   787 | 407 | 00787_update7      | Sun Mar 29 00:00:00 1970 PST
5863   788 |   8 | 00788              | Mon Mar 30 00:00:00 1970 PST
5864   789 | 509 | 00789_update9      | Tue Mar 31 00:00:00 1970 PST
5865   790 |   0 | 00790              | Wed Apr 01 00:00:00 1970 PST
5866   791 |   1 | 00791              | Thu Apr 02 00:00:00 1970 PST
5867   793 | 303 | 00793_update3      | Sat Apr 04 00:00:00 1970 PST
5868   794 |   4 | 00794              | Sun Apr 05 00:00:00 1970 PST
5869   796 |   6 | 00796              | Tue Apr 07 00:00:00 1970 PST
5870   797 | 407 | 00797_update7      | Wed Apr 08 00:00:00 1970 PST
5871   798 |   8 | 00798              | Thu Apr 09 00:00:00 1970 PST
5872   799 | 509 | 00799_update9      | Fri Apr 10 00:00:00 1970 PST
5873   800 |   0 | 00800              | Thu Jan 01 00:00:00 1970 PST
5874   801 |   1 | 00801              | Fri Jan 02 00:00:00 1970 PST
5875   803 | 303 | 00803_update3      | Sun Jan 04 00:00:00 1970 PST
5876   804 |   4 | 00804              | Mon Jan 05 00:00:00 1970 PST
5877   806 |   6 | 00806              | Wed Jan 07 00:00:00 1970 PST
5878   807 | 407 | 00807_update7      | Thu Jan 08 00:00:00 1970 PST
5879   808 |   8 | 00808              | Fri Jan 09 00:00:00 1970 PST
5880   809 | 509 | 00809_update9      | Sat Jan 10 00:00:00 1970 PST
5881   810 |   0 | 00810              | Sun Jan 11 00:00:00 1970 PST
5882   811 |   1 | 00811              | Mon Jan 12 00:00:00 1970 PST
5883   813 | 303 | 00813_update3      | Wed Jan 14 00:00:00 1970 PST
5884   814 |   4 | 00814              | Thu Jan 15 00:00:00 1970 PST
5885   816 |   6 | 00816              | Sat Jan 17 00:00:00 1970 PST
5886   817 | 407 | 00817_update7      | Sun Jan 18 00:00:00 1970 PST
5887   818 |   8 | 00818              | Mon Jan 19 00:00:00 1970 PST
5888   819 | 509 | 00819_update9      | Tue Jan 20 00:00:00 1970 PST
5889   820 |   0 | 00820              | Wed Jan 21 00:00:00 1970 PST
5890   821 |   1 | 00821              | Thu Jan 22 00:00:00 1970 PST
5891   823 | 303 | 00823_update3      | Sat Jan 24 00:00:00 1970 PST
5892   824 |   4 | 00824              | Sun Jan 25 00:00:00 1970 PST
5893   826 |   6 | 00826              | Tue Jan 27 00:00:00 1970 PST
5894   827 | 407 | 00827_update7      | Wed Jan 28 00:00:00 1970 PST
5895   828 |   8 | 00828              | Thu Jan 29 00:00:00 1970 PST
5896   829 | 509 | 00829_update9      | Fri Jan 30 00:00:00 1970 PST
5897   830 |   0 | 00830              | Sat Jan 31 00:00:00 1970 PST
5898   831 |   1 | 00831              | Sun Feb 01 00:00:00 1970 PST
5899   833 | 303 | 00833_update3      | Tue Feb 03 00:00:00 1970 PST
5900   834 |   4 | 00834              | Wed Feb 04 00:00:00 1970 PST
5901   836 |   6 | 00836              | Fri Feb 06 00:00:00 1970 PST
5902   837 | 407 | 00837_update7      | Sat Feb 07 00:00:00 1970 PST
5903   838 |   8 | 00838              | Sun Feb 08 00:00:00 1970 PST
5904   839 | 509 | 00839_update9      | Mon Feb 09 00:00:00 1970 PST
5905   840 |   0 | 00840              | Tue Feb 10 00:00:00 1970 PST
5906   841 |   1 | 00841              | Wed Feb 11 00:00:00 1970 PST
5907   843 | 303 | 00843_update3      | Fri Feb 13 00:00:00 1970 PST
5908   844 |   4 | 00844              | Sat Feb 14 00:00:00 1970 PST
5909   846 |   6 | 00846              | Mon Feb 16 00:00:00 1970 PST
5910   847 | 407 | 00847_update7      | Tue Feb 17 00:00:00 1970 PST
5911   848 |   8 | 00848              | Wed Feb 18 00:00:00 1970 PST
5912   849 | 509 | 00849_update9      | Thu Feb 19 00:00:00 1970 PST
5913   850 |   0 | 00850              | Fri Feb 20 00:00:00 1970 PST
5914   851 |   1 | 00851              | Sat Feb 21 00:00:00 1970 PST
5915   853 | 303 | 00853_update3      | Mon Feb 23 00:00:00 1970 PST
5916   854 |   4 | 00854              | Tue Feb 24 00:00:00 1970 PST
5917   856 |   6 | 00856              | Thu Feb 26 00:00:00 1970 PST
5918   857 | 407 | 00857_update7      | Fri Feb 27 00:00:00 1970 PST
5919   858 |   8 | 00858              | Sat Feb 28 00:00:00 1970 PST
5920   859 | 509 | 00859_update9      | Sun Mar 01 00:00:00 1970 PST
5921   860 |   0 | 00860              | Mon Mar 02 00:00:00 1970 PST
5922   861 |   1 | 00861              | Tue Mar 03 00:00:00 1970 PST
5923   863 | 303 | 00863_update3      | Thu Mar 05 00:00:00 1970 PST
5924   864 |   4 | 00864              | Fri Mar 06 00:00:00 1970 PST
5925   866 |   6 | 00866              | Sun Mar 08 00:00:00 1970 PST
5926   867 | 407 | 00867_update7      | Mon Mar 09 00:00:00 1970 PST
5927   868 |   8 | 00868              | Tue Mar 10 00:00:00 1970 PST
5928   869 | 509 | 00869_update9      | Wed Mar 11 00:00:00 1970 PST
5929   870 |   0 | 00870              | Thu Mar 12 00:00:00 1970 PST
5930   871 |   1 | 00871              | Fri Mar 13 00:00:00 1970 PST
5931   873 | 303 | 00873_update3      | Sun Mar 15 00:00:00 1970 PST
5932   874 |   4 | 00874              | Mon Mar 16 00:00:00 1970 PST
5933   876 |   6 | 00876              | Wed Mar 18 00:00:00 1970 PST
5934   877 | 407 | 00877_update7      | Thu Mar 19 00:00:00 1970 PST
5935   878 |   8 | 00878              | Fri Mar 20 00:00:00 1970 PST
5936   879 | 509 | 00879_update9      | Sat Mar 21 00:00:00 1970 PST
5937   880 |   0 | 00880              | Sun Mar 22 00:00:00 1970 PST
5938   881 |   1 | 00881              | Mon Mar 23 00:00:00 1970 PST
5939   883 | 303 | 00883_update3      | Wed Mar 25 00:00:00 1970 PST
5940   884 |   4 | 00884              | Thu Mar 26 00:00:00 1970 PST
5941   886 |   6 | 00886              | Sat Mar 28 00:00:00 1970 PST
5942   887 | 407 | 00887_update7      | Sun Mar 29 00:00:00 1970 PST
5943   888 |   8 | 00888              | Mon Mar 30 00:00:00 1970 PST
5944   889 | 509 | 00889_update9      | Tue Mar 31 00:00:00 1970 PST
5945   890 |   0 | 00890              | Wed Apr 01 00:00:00 1970 PST
5946   891 |   1 | 00891              | Thu Apr 02 00:00:00 1970 PST
5947   893 | 303 | 00893_update3      | Sat Apr 04 00:00:00 1970 PST
5948   894 |   4 | 00894              | Sun Apr 05 00:00:00 1970 PST
5949   896 |   6 | 00896              | Tue Apr 07 00:00:00 1970 PST
5950   897 | 407 | 00897_update7      | Wed Apr 08 00:00:00 1970 PST
5951   898 |   8 | 00898              | Thu Apr 09 00:00:00 1970 PST
5952   899 | 509 | 00899_update9      | Fri Apr 10 00:00:00 1970 PST
5953   900 |   0 | 00900              | Thu Jan 01 00:00:00 1970 PST
5954   901 |   1 | 00901              | Fri Jan 02 00:00:00 1970 PST
5955   903 | 303 | 00903_update3      | Sun Jan 04 00:00:00 1970 PST
5956   904 |   4 | 00904              | Mon Jan 05 00:00:00 1970 PST
5957   906 |   6 | 00906              | Wed Jan 07 00:00:00 1970 PST
5958   907 | 407 | 00907_update7      | Thu Jan 08 00:00:00 1970 PST
5959   908 |   8 | 00908              | Fri Jan 09 00:00:00 1970 PST
5960   909 | 509 | 00909_update9      | Sat Jan 10 00:00:00 1970 PST
5961   910 |   0 | 00910              | Sun Jan 11 00:00:00 1970 PST
5962   911 |   1 | 00911              | Mon Jan 12 00:00:00 1970 PST
5963   913 | 303 | 00913_update3      | Wed Jan 14 00:00:00 1970 PST
5964   914 |   4 | 00914              | Thu Jan 15 00:00:00 1970 PST
5965   916 |   6 | 00916              | Sat Jan 17 00:00:00 1970 PST
5966   917 | 407 | 00917_update7      | Sun Jan 18 00:00:00 1970 PST
5967   918 |   8 | 00918              | Mon Jan 19 00:00:00 1970 PST
5968   919 | 509 | 00919_update9      | Tue Jan 20 00:00:00 1970 PST
5969   920 |   0 | 00920              | Wed Jan 21 00:00:00 1970 PST
5970   921 |   1 | 00921              | Thu Jan 22 00:00:00 1970 PST
5971   923 | 303 | 00923_update3      | Sat Jan 24 00:00:00 1970 PST
5972   924 |   4 | 00924              | Sun Jan 25 00:00:00 1970 PST
5973   926 |   6 | 00926              | Tue Jan 27 00:00:00 1970 PST
5974   927 | 407 | 00927_update7      | Wed Jan 28 00:00:00 1970 PST
5975   928 |   8 | 00928              | Thu Jan 29 00:00:00 1970 PST
5976   929 | 509 | 00929_update9      | Fri Jan 30 00:00:00 1970 PST
5977   930 |   0 | 00930              | Sat Jan 31 00:00:00 1970 PST
5978   931 |   1 | 00931              | Sun Feb 01 00:00:00 1970 PST
5979   933 | 303 | 00933_update3      | Tue Feb 03 00:00:00 1970 PST
5980   934 |   4 | 00934              | Wed Feb 04 00:00:00 1970 PST
5981   936 |   6 | 00936              | Fri Feb 06 00:00:00 1970 PST
5982   937 | 407 | 00937_update7      | Sat Feb 07 00:00:00 1970 PST
5983   938 |   8 | 00938              | Sun Feb 08 00:00:00 1970 PST
5984   939 | 509 | 00939_update9      | Mon Feb 09 00:00:00 1970 PST
5985   940 |   0 | 00940              | Tue Feb 10 00:00:00 1970 PST
5986   941 |   1 | 00941              | Wed Feb 11 00:00:00 1970 PST
5987   943 | 303 | 00943_update3      | Fri Feb 13 00:00:00 1970 PST
5988   944 |   4 | 00944              | Sat Feb 14 00:00:00 1970 PST
5989   946 |   6 | 00946              | Mon Feb 16 00:00:00 1970 PST
5990   947 | 407 | 00947_update7      | Tue Feb 17 00:00:00 1970 PST
5991   948 |   8 | 00948              | Wed Feb 18 00:00:00 1970 PST
5992   949 | 509 | 00949_update9      | Thu Feb 19 00:00:00 1970 PST
5993   950 |   0 | 00950              | Fri Feb 20 00:00:00 1970 PST
5994   951 |   1 | 00951              | Sat Feb 21 00:00:00 1970 PST
5995   953 | 303 | 00953_update3      | Mon Feb 23 00:00:00 1970 PST
5996   954 |   4 | 00954              | Tue Feb 24 00:00:00 1970 PST
5997   956 |   6 | 00956              | Thu Feb 26 00:00:00 1970 PST
5998   957 | 407 | 00957_update7      | Fri Feb 27 00:00:00 1970 PST
5999   958 |   8 | 00958              | Sat Feb 28 00:00:00 1970 PST
6000   959 | 509 | 00959_update9      | Sun Mar 01 00:00:00 1970 PST
6001   960 |   0 | 00960              | Mon Mar 02 00:00:00 1970 PST
6002   961 |   1 | 00961              | Tue Mar 03 00:00:00 1970 PST
6003   963 | 303 | 00963_update3      | Thu Mar 05 00:00:00 1970 PST
6004   964 |   4 | 00964              | Fri Mar 06 00:00:00 1970 PST
6005   966 |   6 | 00966              | Sun Mar 08 00:00:00 1970 PST
6006   967 | 407 | 00967_update7      | Mon Mar 09 00:00:00 1970 PST
6007   968 |   8 | 00968              | Tue Mar 10 00:00:00 1970 PST
6008   969 | 509 | 00969_update9      | Wed Mar 11 00:00:00 1970 PST
6009   970 |   0 | 00970              | Thu Mar 12 00:00:00 1970 PST
6010   971 |   1 | 00971              | Fri Mar 13 00:00:00 1970 PST
6011   973 | 303 | 00973_update3      | Sun Mar 15 00:00:00 1970 PST
6012   974 |   4 | 00974              | Mon Mar 16 00:00:00 1970 PST
6013   976 |   6 | 00976              | Wed Mar 18 00:00:00 1970 PST
6014   977 | 407 | 00977_update7      | Thu Mar 19 00:00:00 1970 PST
6015   978 |   8 | 00978              | Fri Mar 20 00:00:00 1970 PST
6016   979 | 509 | 00979_update9      | Sat Mar 21 00:00:00 1970 PST
6017   980 |   0 | 00980              | Sun Mar 22 00:00:00 1970 PST
6018   981 |   1 | 00981              | Mon Mar 23 00:00:00 1970 PST
6019   983 | 303 | 00983_update3      | Wed Mar 25 00:00:00 1970 PST
6020   984 |   4 | 00984              | Thu Mar 26 00:00:00 1970 PST
6021   986 |   6 | 00986              | Sat Mar 28 00:00:00 1970 PST
6022   987 | 407 | 00987_update7      | Sun Mar 29 00:00:00 1970 PST
6023   988 |   8 | 00988              | Mon Mar 30 00:00:00 1970 PST
6024   989 | 509 | 00989_update9      | Tue Mar 31 00:00:00 1970 PST
6025   990 |   0 | 00990              | Wed Apr 01 00:00:00 1970 PST
6026   991 |   1 | 00991              | Thu Apr 02 00:00:00 1970 PST
6027   993 | 303 | 00993_update3      | Sat Apr 04 00:00:00 1970 PST
6028   994 |   4 | 00994              | Sun Apr 05 00:00:00 1970 PST
6029   996 |   6 | 00996              | Tue Apr 07 00:00:00 1970 PST
6030   997 | 407 | 00997_update7      | Wed Apr 08 00:00:00 1970 PST
6031   998 |   8 | 00998              | Thu Apr 09 00:00:00 1970 PST
6032   999 | 509 | 00999_update9      | Fri Apr 10 00:00:00 1970 PST
6033  1000 |   0 | 01000              | Thu Jan 01 00:00:00 1970 PST
6034  1001 | 101 | 0000100001         | 
6035  1003 | 403 | 0000300003_update3 | 
6036  1004 | 104 | 0000400004         | 
6037  1006 | 106 | 0000600006         | 
6038  1007 | 507 | 0000700007_update7 | 
6039  1008 | 108 | 0000800008         | 
6040  1009 | 609 | 0000900009_update9 | 
6041  1010 | 100 | 0001000010         | 
6042  1011 | 101 | 0001100011         | 
6043  1013 | 403 | 0001300013_update3 | 
6044  1014 | 104 | 0001400014         | 
6045  1016 | 106 | 0001600016         | 
6046  1017 | 507 | 0001700017_update7 | 
6047  1018 | 108 | 0001800018         | 
6048  1019 | 609 | 0001900019_update9 | 
6049  1020 | 100 | 0002000020         | 
6050  1101 | 201 | aaa                | 
6051  1103 | 503 | ccc_update3        | 
6052  1104 | 204 | ddd                | 
6053 (819 rows)
6055 EXPLAIN (verbose, costs off)
6056 INSERT INTO ft2 (c1,c2,c3) VALUES (1200,999,'foo') RETURNING tableoid::regclass;
6057                                                                                            QUERY PLAN                                                                                            
6058 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6059  Insert on public.ft2
6060    Output: (ft2.tableoid)::regclass
6061    Remote SQL: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
6062    Batch Size: 1
6063    ->  Result
6064          Output: 1200, 999, NULL::integer, 'foo'::text, NULL::timestamp with time zone, NULL::timestamp without time zone, NULL::character varying, 'ft2       '::character(10), NULL::user_enum
6065 (6 rows)
6067 INSERT INTO ft2 (c1,c2,c3) VALUES (1200,999,'foo') RETURNING tableoid::regclass;
6068  tableoid 
6069 ----------
6070  ft2
6071 (1 row)
6073 EXPLAIN (verbose, costs off)
6074 UPDATE ft2 SET c3 = 'bar' WHERE c1 = 1200 RETURNING tableoid::regclass;             -- can be pushed down
6075                                      QUERY PLAN                                     
6076 ------------------------------------------------------------------------------------
6077  Update on public.ft2
6078    Output: (tableoid)::regclass
6079    ->  Foreign Update on public.ft2
6080          Remote SQL: UPDATE "S 1"."T 1" SET c3 = 'bar'::text WHERE (("C 1" = 1200))
6081 (4 rows)
6083 UPDATE ft2 SET c3 = 'bar' WHERE c1 = 1200 RETURNING tableoid::regclass;
6084  tableoid 
6085 ----------
6086  ft2
6087 (1 row)
6089 EXPLAIN (verbose, costs off)
6090 DELETE FROM ft2 WHERE c1 = 1200 RETURNING tableoid::regclass;                       -- can be pushed down
6091                              QUERY PLAN                             
6092 --------------------------------------------------------------------
6093  Delete on public.ft2
6094    Output: (tableoid)::regclass
6095    ->  Foreign Delete on public.ft2
6096          Remote SQL: DELETE FROM "S 1"."T 1" WHERE (("C 1" = 1200))
6097 (4 rows)
6099 DELETE FROM ft2 WHERE c1 = 1200 RETURNING tableoid::regclass;
6100  tableoid 
6101 ----------
6102  ft2
6103 (1 row)
6105 -- Test UPDATE/DELETE with RETURNING on a three-table join
6106 INSERT INTO ft2 (c1,c2,c3)
6107   SELECT id, id - 1200, to_char(id, 'FM00000') FROM generate_series(1201, 1300) id;
6108 EXPLAIN (verbose, costs off)
6109 UPDATE ft2 SET c3 = 'foo'
6110   FROM ft4 INNER JOIN ft5 ON (ft4.c1 = ft5.c1)
6111   WHERE ft2.c1 > 1200 AND ft2.c2 = ft4.c1
6112   RETURNING ft2, ft2.*, ft4, ft4.*;       -- can be pushed down
6113                                                                                                                                                                           QUERY PLAN                                                                                                                                                                           
6114 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6115  Update on public.ft2
6116    Output: ft2.*, ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.*, ft4.c1, ft4.c2, ft4.c3
6117    ->  Foreign Update
6118          Remote SQL: UPDATE "S 1"."T 1" r1 SET c3 = 'foo'::text FROM ("S 1"."T 3" r2 INNER JOIN "S 1"."T 4" r3 ON (TRUE)) WHERE ((r2.c1 = r3.c1)) AND ((r1.c2 = r2.c1)) AND ((r1."C 1" > 1200)) RETURNING r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2.c1, r2.c2, r2.c3) END, r2.c1, r2.c2, r2.c3
6119 (4 rows)
6121 UPDATE ft2 SET c3 = 'foo'
6122   FROM ft4 INNER JOIN ft5 ON (ft4.c1 = ft5.c1)
6123   WHERE ft2.c1 > 1200 AND ft2.c2 = ft4.c1
6124   RETURNING ft2, ft2.*, ft4, ft4.*;
6125               ft2               |  c1  | c2 | c3  | c4 | c5 | c6 |     c7     | c8 |      ft4       | c1 | c2 |   c3   
6126 --------------------------------+------+----+-----+----+----+----+------------+----+----------------+----+----+--------
6127  (1206,6,foo,,,,"ft2       ",)  | 1206 |  6 | foo |    |    |    | ft2        |    | (6,7,AAA006)   |  6 |  7 | AAA006
6128  (1212,12,foo,,,,"ft2       ",) | 1212 | 12 | foo |    |    |    | ft2        |    | (12,13,AAA012) | 12 | 13 | AAA012
6129  (1218,18,foo,,,,"ft2       ",) | 1218 | 18 | foo |    |    |    | ft2        |    | (18,19,AAA018) | 18 | 19 | AAA018
6130  (1224,24,foo,,,,"ft2       ",) | 1224 | 24 | foo |    |    |    | ft2        |    | (24,25,AAA024) | 24 | 25 | AAA024
6131  (1230,30,foo,,,,"ft2       ",) | 1230 | 30 | foo |    |    |    | ft2        |    | (30,31,AAA030) | 30 | 31 | AAA030
6132  (1236,36,foo,,,,"ft2       ",) | 1236 | 36 | foo |    |    |    | ft2        |    | (36,37,AAA036) | 36 | 37 | AAA036
6133  (1242,42,foo,,,,"ft2       ",) | 1242 | 42 | foo |    |    |    | ft2        |    | (42,43,AAA042) | 42 | 43 | AAA042
6134  (1248,48,foo,,,,"ft2       ",) | 1248 | 48 | foo |    |    |    | ft2        |    | (48,49,AAA048) | 48 | 49 | AAA048
6135  (1254,54,foo,,,,"ft2       ",) | 1254 | 54 | foo |    |    |    | ft2        |    | (54,55,AAA054) | 54 | 55 | AAA054
6136  (1260,60,foo,,,,"ft2       ",) | 1260 | 60 | foo |    |    |    | ft2        |    | (60,61,AAA060) | 60 | 61 | AAA060
6137  (1266,66,foo,,,,"ft2       ",) | 1266 | 66 | foo |    |    |    | ft2        |    | (66,67,AAA066) | 66 | 67 | AAA066
6138  (1272,72,foo,,,,"ft2       ",) | 1272 | 72 | foo |    |    |    | ft2        |    | (72,73,AAA072) | 72 | 73 | AAA072
6139  (1278,78,foo,,,,"ft2       ",) | 1278 | 78 | foo |    |    |    | ft2        |    | (78,79,AAA078) | 78 | 79 | AAA078
6140  (1284,84,foo,,,,"ft2       ",) | 1284 | 84 | foo |    |    |    | ft2        |    | (84,85,AAA084) | 84 | 85 | AAA084
6141  (1290,90,foo,,,,"ft2       ",) | 1290 | 90 | foo |    |    |    | ft2        |    | (90,91,AAA090) | 90 | 91 | AAA090
6142  (1296,96,foo,,,,"ft2       ",) | 1296 | 96 | foo |    |    |    | ft2        |    | (96,97,AAA096) | 96 | 97 | AAA096
6143 (16 rows)
6145 EXPLAIN (verbose, costs off)
6146 DELETE FROM ft2
6147   USING ft4 LEFT JOIN ft5 ON (ft4.c1 = ft5.c1)
6148   WHERE ft2.c1 > 1200 AND ft2.c1 % 10 = 0 AND ft2.c2 = ft4.c1
6149   RETURNING 100;                          -- can be pushed down
6150                                                                                             QUERY PLAN                                                                                             
6151 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6152  Delete on public.ft2
6153    Output: 100
6154    ->  Foreign Delete
6155          Remote SQL: DELETE FROM "S 1"."T 1" r1 USING ("S 1"."T 3" r2 LEFT JOIN "S 1"."T 4" r3 ON (((r2.c1 = r3.c1)))) WHERE ((r1.c2 = r2.c1)) AND ((r1."C 1" > 1200)) AND (((r1."C 1" % 10) = 0))
6156 (4 rows)
6158 DELETE FROM ft2
6159   USING ft4 LEFT JOIN ft5 ON (ft4.c1 = ft5.c1)
6160   WHERE ft2.c1 > 1200 AND ft2.c1 % 10 = 0 AND ft2.c2 = ft4.c1
6161   RETURNING 100;
6162  ?column? 
6163 ----------
6164       100
6165       100
6166       100
6167       100
6168       100
6169       100
6170       100
6171       100
6172       100
6173       100
6174 (10 rows)
6176 DELETE FROM ft2 WHERE ft2.c1 > 1200;
6177 -- Test UPDATE with a MULTIEXPR sub-select
6178 -- (maybe someday this'll be remotely executable, but not today)
6179 EXPLAIN (verbose, costs off)
6180 UPDATE ft2 AS target SET (c2, c7) = (
6181     SELECT c2 * 10, c7
6182         FROM ft2 AS src
6183         WHERE target.c1 = src.c1
6184 ) WHERE c1 > 1100;
6185                                                       QUERY PLAN                                                       
6186 -----------------------------------------------------------------------------------------------------------------------
6187  Update on public.ft2 target
6188    Remote SQL: UPDATE "S 1"."T 1" SET c2 = $2, c7 = $3 WHERE ctid = $1
6189    ->  Foreign Scan on public.ft2 target
6190          Output: (SubPlan 1).col1, (SubPlan 1).col2, (rescan SubPlan 1), target.ctid, target.*
6191          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8, ctid FROM "S 1"."T 1" WHERE (("C 1" > 1100)) FOR UPDATE
6192          SubPlan 1
6193            ->  Foreign Scan on public.ft2 src
6194                  Output: (src.c2 * 10), src.c7
6195                  Remote SQL: SELECT c2, c7 FROM "S 1"."T 1" WHERE (($1::integer = "C 1"))
6196 (9 rows)
6198 UPDATE ft2 AS target SET (c2, c7) = (
6199     SELECT c2 * 10, c7
6200         FROM ft2 AS src
6201         WHERE target.c1 = src.c1
6202 ) WHERE c1 > 1100;
6203 UPDATE ft2 AS target SET (c2) = (
6204     SELECT c2 / 10
6205         FROM ft2 AS src
6206         WHERE target.c1 = src.c1
6207 ) WHERE c1 > 1100;
6208 -- Test UPDATE involving a join that can be pushed down,
6209 -- but a SET clause that can't be
6210 EXPLAIN (VERBOSE, COSTS OFF)
6211 UPDATE ft2 d SET c2 = CASE WHEN random() >= 0 THEN d.c2 ELSE 0 END
6212   FROM ft2 AS t WHERE d.c1 = t.c1 AND d.c1 > 1000;
6213                                                                                                                                                                                        QUERY PLAN                                                                                                                                                                                        
6214 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6215  Update on public.ft2 d
6216    Remote SQL: UPDATE "S 1"."T 1" SET c2 = $2 WHERE ctid = $1
6217    ->  Foreign Scan
6218          Output: CASE WHEN (random() >= '0'::double precision) THEN d.c2 ELSE 0 END, d.ctid, d.*, t.*
6219          Relations: (public.ft2 d) INNER JOIN (public.ft2 t)
6220          Remote SQL: SELECT r1.c2, r1.ctid, CASE WHEN (r1.*)::text IS NOT NULL THEN ROW(r1."C 1", r1.c2, r1.c3, r1.c4, r1.c5, r1.c6, r1.c7, r1.c8) END, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2."C 1", r2.c2, r2.c3, r2.c4, r2.c5, r2.c6, r2.c7, r2.c8) END FROM ("S 1"."T 1" r1 INNER JOIN "S 1"."T 1" r2 ON (((r1."C 1" = r2."C 1")) AND ((r1."C 1" > 1000)))) FOR UPDATE OF r1
6221          ->  Hash Join
6222                Output: d.c2, d.ctid, d.*, t.*
6223                Hash Cond: (d.c1 = t.c1)
6224                ->  Foreign Scan on public.ft2 d
6225                      Output: d.c2, d.ctid, d.*, d.c1
6226                      Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8, ctid FROM "S 1"."T 1" WHERE (("C 1" > 1000)) ORDER BY "C 1" ASC NULLS LAST FOR UPDATE
6227                ->  Hash
6228                      Output: t.*, t.c1
6229                      ->  Foreign Scan on public.ft2 t
6230                            Output: t.*, t.c1
6231                            Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
6232 (17 rows)
6234 UPDATE ft2 d SET c2 = CASE WHEN random() >= 0 THEN d.c2 ELSE 0 END
6235   FROM ft2 AS t WHERE d.c1 = t.c1 AND d.c1 > 1000;
6236 -- Test UPDATE/DELETE with WHERE or JOIN/ON conditions containing
6237 -- user-defined operators/functions
6238 ALTER SERVER loopback OPTIONS (DROP extensions);
6239 INSERT INTO ft2 (c1,c2,c3)
6240   SELECT id, id % 10, to_char(id, 'FM00000') FROM generate_series(2001, 2010) id;
6241 EXPLAIN (verbose, costs off)
6242 UPDATE ft2 SET c3 = 'bar' WHERE postgres_fdw_abs(c1) > 2000 RETURNING *;            -- can't be pushed down
6243                                                 QUERY PLAN                                                
6244 ----------------------------------------------------------------------------------------------------------
6245  Update on public.ft2
6246    Output: c1, c2, c3, c4, c5, c6, c7, c8
6247    Remote SQL: UPDATE "S 1"."T 1" SET c3 = $2 WHERE ctid = $1 RETURNING "C 1", c2, c3, c4, c5, c6, c7, c8
6248    ->  Foreign Scan on public.ft2
6249          Output: 'bar'::text, ctid, ft2.*
6250          Filter: (postgres_fdw_abs(ft2.c1) > 2000)
6251          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8, ctid FROM "S 1"."T 1" FOR UPDATE
6252 (7 rows)
6254 UPDATE ft2 SET c3 = 'bar' WHERE postgres_fdw_abs(c1) > 2000 RETURNING *;
6255   c1  | c2 | c3  | c4 | c5 | c6 |     c7     | c8 
6256 ------+----+-----+----+----+----+------------+----
6257  2001 |  1 | bar |    |    |    | ft2        | 
6258  2002 |  2 | bar |    |    |    | ft2        | 
6259  2003 |  3 | bar |    |    |    | ft2        | 
6260  2004 |  4 | bar |    |    |    | ft2        | 
6261  2005 |  5 | bar |    |    |    | ft2        | 
6262  2006 |  6 | bar |    |    |    | ft2        | 
6263  2007 |  7 | bar |    |    |    | ft2        | 
6264  2008 |  8 | bar |    |    |    | ft2        | 
6265  2009 |  9 | bar |    |    |    | ft2        | 
6266  2010 |  0 | bar |    |    |    | ft2        | 
6267 (10 rows)
6269 EXPLAIN (verbose, costs off)
6270 UPDATE ft2 SET c3 = 'baz'
6271   FROM ft4 INNER JOIN ft5 ON (ft4.c1 = ft5.c1)
6272   WHERE ft2.c1 > 2000 AND ft2.c2 === ft4.c1
6273   RETURNING ft2.*, ft4.*, ft5.*;                                                    -- can't be pushed down
6274                                                                                                                                           QUERY PLAN                                                                                                                                          
6275 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6276  Update on public.ft2
6277    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3, ft5.c1, ft5.c2, ft5.c3
6278    Remote SQL: UPDATE "S 1"."T 1" SET c3 = $2 WHERE ctid = $1 RETURNING "C 1", c2, c3, c4, c5, c6, c7, c8
6279    ->  Nested Loop
6280          Output: 'baz'::text, ft2.ctid, ft2.*, ft4.*, ft5.*, ft4.c1, ft4.c2, ft4.c3, ft5.c1, ft5.c2, ft5.c3
6281          Join Filter: (ft2.c2 === ft4.c1)
6282          ->  Foreign Scan on public.ft2
6283                Output: ft2.ctid, ft2.*, ft2.c2
6284                Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8, ctid FROM "S 1"."T 1" WHERE (("C 1" > 2000)) FOR UPDATE
6285          ->  Foreign Scan
6286                Output: ft4.*, ft4.c1, ft4.c2, ft4.c3, ft5.*, ft5.c1, ft5.c2, ft5.c3
6287                Relations: (public.ft4) INNER JOIN (public.ft5)
6288                Remote SQL: SELECT CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2.c1, r2.c2, r2.c3) END, r2.c1, r2.c2, r2.c3, CASE WHEN (r3.*)::text IS NOT NULL THEN ROW(r3.c1, r3.c2, r3.c3) END, r3.c1, r3.c2, r3.c3 FROM ("S 1"."T 3" r2 INNER JOIN "S 1"."T 4" r3 ON (((r2.c1 = r3.c1))))
6289                ->  Hash Join
6290                      Output: ft4.*, ft4.c1, ft4.c2, ft4.c3, ft5.*, ft5.c1, ft5.c2, ft5.c3
6291                      Hash Cond: (ft4.c1 = ft5.c1)
6292                      ->  Foreign Scan on public.ft4
6293                            Output: ft4.*, ft4.c1, ft4.c2, ft4.c3
6294                            Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3"
6295                      ->  Hash
6296                            Output: ft5.*, ft5.c1, ft5.c2, ft5.c3
6297                            ->  Foreign Scan on public.ft5
6298                                  Output: ft5.*, ft5.c1, ft5.c2, ft5.c3
6299                                  Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 4"
6300 (24 rows)
6302 UPDATE ft2 SET c3 = 'baz'
6303   FROM ft4 INNER JOIN ft5 ON (ft4.c1 = ft5.c1)
6304   WHERE ft2.c1 > 2000 AND ft2.c2 === ft4.c1
6305   RETURNING ft2.*, ft4.*, ft5.*;
6306   c1  | c2 | c3  | c4 | c5 | c6 |     c7     | c8 | c1 | c2 |   c3   | c1 | c2 |   c3   
6307 ------+----+-----+----+----+----+------------+----+----+----+--------+----+----+--------
6308  2006 |  6 | baz |    |    |    | ft2        |    |  6 |  7 | AAA006 |  6 |  7 | AAA006
6309 (1 row)
6311 EXPLAIN (verbose, costs off)
6312 DELETE FROM ft2
6313   USING ft4 INNER JOIN ft5 ON (ft4.c1 === ft5.c1)
6314   WHERE ft2.c1 > 2000 AND ft2.c2 = ft4.c1
6315   RETURNING ft2.c1, ft2.c2, ft2.c3;       -- can't be pushed down
6316                                                                                                                                                                      QUERY PLAN                                                                                                                                                                     
6317 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6318  Delete on public.ft2
6319    Output: ft2.c1, ft2.c2, ft2.c3
6320    Remote SQL: DELETE FROM "S 1"."T 1" WHERE ctid = $1 RETURNING "C 1", c2, c3
6321    ->  Foreign Scan
6322          Output: ft2.ctid, ft4.*, ft5.*
6323          Filter: (ft4.c1 === ft5.c1)
6324          Relations: ((public.ft2) INNER JOIN (public.ft4)) INNER JOIN (public.ft5)
6325          Remote SQL: SELECT r1.ctid, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2.c1, r2.c2, r2.c3) END, CASE WHEN (r3.*)::text IS NOT NULL THEN ROW(r3.c1, r3.c2, r3.c3) END, r2.c1, r3.c1 FROM (("S 1"."T 1" r1 INNER JOIN "S 1"."T 3" r2 ON (((r1.c2 = r2.c1)) AND ((r1."C 1" > 2000)))) INNER JOIN "S 1"."T 4" r3 ON (TRUE)) FOR UPDATE OF r1
6326          ->  Nested Loop
6327                Output: ft2.ctid, ft4.*, ft5.*, ft4.c1, ft5.c1
6328                ->  Nested Loop
6329                      Output: ft2.ctid, ft4.*, ft4.c1
6330                      Join Filter: (ft2.c2 = ft4.c1)
6331                      ->  Foreign Scan on public.ft2
6332                            Output: ft2.ctid, ft2.c2
6333                            Remote SQL: SELECT c2, ctid FROM "S 1"."T 1" WHERE (("C 1" > 2000)) FOR UPDATE
6334                      ->  Foreign Scan on public.ft4
6335                            Output: ft4.*, ft4.c1
6336                            Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3"
6337                ->  Foreign Scan on public.ft5
6338                      Output: ft5.*, ft5.c1
6339                      Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 4"
6340 (22 rows)
6342 DELETE FROM ft2
6343   USING ft4 INNER JOIN ft5 ON (ft4.c1 === ft5.c1)
6344   WHERE ft2.c1 > 2000 AND ft2.c2 = ft4.c1
6345   RETURNING ft2.c1, ft2.c2, ft2.c3;
6346   c1  | c2 | c3  
6347 ------+----+-----
6348  2006 |  6 | baz
6349 (1 row)
6351 DELETE FROM ft2 WHERE ft2.c1 > 2000;
6352 ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
6353 -- Test that trigger on remote table works as expected
6354 CREATE OR REPLACE FUNCTION "S 1".F_BRTRIG() RETURNS trigger AS $$
6355 BEGIN
6356     NEW.c3 = NEW.c3 || '_trig_update';
6357     RETURN NEW;
6358 END;
6359 $$ LANGUAGE plpgsql;
6360 CREATE TRIGGER t1_br_insert BEFORE INSERT OR UPDATE
6361     ON "S 1"."T 1" FOR EACH ROW EXECUTE PROCEDURE "S 1".F_BRTRIG();
6362 INSERT INTO ft2 (c1,c2,c3) VALUES (1208, 818, 'fff') RETURNING *;
6363   c1  | c2  |       c3        | c4 | c5 | c6 |     c7     | c8 
6364 ------+-----+-----------------+----+----+----+------------+----
6365  1208 | 818 | fff_trig_update |    |    |    | ft2        | 
6366 (1 row)
6368 INSERT INTO ft2 (c1,c2,c3,c6) VALUES (1218, 818, 'ggg', '(--;') RETURNING *;
6369   c1  | c2  |       c3        | c4 | c5 |  c6  |     c7     | c8 
6370 ------+-----+-----------------+----+----+------+------------+----
6371  1218 | 818 | ggg_trig_update |    |    | (--; | ft2        | 
6372 (1 row)
6374 UPDATE ft2 SET c2 = c2 + 600 WHERE c1 % 10 = 8 AND c1 < 1200 RETURNING *;
6375   c1  | c2  |           c3           |              c4              |            c5            | c6 |     c7     | c8  
6376 ------+-----+------------------------+------------------------------+--------------------------+----+------------+-----
6377     8 | 608 | 00008_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6378    18 | 608 | 00018_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6379    28 | 608 | 00028_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6380    38 | 608 | 00038_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6381    48 | 608 | 00048_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6382    58 | 608 | 00058_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6383    68 | 608 | 00068_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6384    78 | 608 | 00078_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6385    88 | 608 | 00088_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6386    98 | 608 | 00098_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6387   108 | 608 | 00108_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6388   118 | 608 | 00118_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6389   128 | 608 | 00128_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6390   138 | 608 | 00138_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6391   148 | 608 | 00148_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6392   158 | 608 | 00158_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6393   168 | 608 | 00168_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6394   178 | 608 | 00178_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6395   188 | 608 | 00188_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6396   198 | 608 | 00198_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6397   208 | 608 | 00208_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6398   218 | 608 | 00218_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6399   228 | 608 | 00228_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6400   238 | 608 | 00238_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6401   248 | 608 | 00248_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6402   258 | 608 | 00258_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6403   268 | 608 | 00268_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6404   278 | 608 | 00278_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6405   288 | 608 | 00288_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6406   298 | 608 | 00298_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6407   308 | 608 | 00308_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6408   318 | 608 | 00318_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6409   328 | 608 | 00328_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6410   338 | 608 | 00338_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6411   348 | 608 | 00348_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6412   358 | 608 | 00358_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6413   368 | 608 | 00368_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6414   378 | 608 | 00378_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6415   388 | 608 | 00388_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6416   398 | 608 | 00398_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6417   408 | 608 | 00408_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6418   418 | 608 | 00418_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6419   428 | 608 | 00428_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6420   438 | 608 | 00438_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6421   448 | 608 | 00448_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6422   458 | 608 | 00458_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6423   468 | 608 | 00468_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6424   478 | 608 | 00478_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6425   488 | 608 | 00488_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6426   498 | 608 | 00498_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6427   508 | 608 | 00508_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6428   518 | 608 | 00518_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6429   528 | 608 | 00528_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6430   538 | 608 | 00538_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6431   548 | 608 | 00548_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6432   558 | 608 | 00558_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6433   568 | 608 | 00568_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6434   578 | 608 | 00578_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6435   588 | 608 | 00588_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6436   598 | 608 | 00598_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6437   608 | 608 | 00608_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6438   618 | 608 | 00618_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6439   628 | 608 | 00628_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6440   638 | 608 | 00638_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6441   648 | 608 | 00648_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6442   658 | 608 | 00658_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6443   668 | 608 | 00668_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6444   678 | 608 | 00678_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6445   688 | 608 | 00688_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6446   698 | 608 | 00698_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6447   708 | 608 | 00708_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6448   718 | 608 | 00718_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6449   728 | 608 | 00728_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6450   738 | 608 | 00738_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6451   748 | 608 | 00748_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6452   758 | 608 | 00758_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6453   768 | 608 | 00768_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6454   778 | 608 | 00778_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6455   788 | 608 | 00788_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6456   798 | 608 | 00798_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6457   808 | 608 | 00808_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6458   818 | 608 | 00818_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6459   828 | 608 | 00828_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6460   838 | 608 | 00838_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6461   848 | 608 | 00848_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6462   858 | 608 | 00858_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6463   868 | 608 | 00868_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6464   878 | 608 | 00878_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6465   888 | 608 | 00888_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6466   898 | 608 | 00898_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6467   908 | 608 | 00908_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6468   918 | 608 | 00918_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6469   928 | 608 | 00928_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6470   938 | 608 | 00938_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6471   948 | 608 | 00948_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6472   958 | 608 | 00958_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6473   968 | 608 | 00968_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6474   978 | 608 | 00978_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6475   988 | 608 | 00988_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6476   998 | 608 | 00998_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6477  1008 | 708 | 0000800008_trig_update |                              |                          |    | ft2        | 
6478  1018 | 708 | 0001800018_trig_update |                              |                          |    | ft2        | 
6479 (102 rows)
6481 -- Test errors thrown on remote side during update
6482 ALTER TABLE "S 1"."T 1" ADD CONSTRAINT c2positive CHECK (c2 >= 0);
6483 INSERT INTO ft1(c1, c2) VALUES(11, 12);  -- duplicate key
6484 ERROR:  duplicate key value violates unique constraint "t1_pkey"
6485 DETAIL:  Key ("C 1")=(11) already exists.
6486 CONTEXT:  remote SQL command: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
6487 INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT DO NOTHING; -- works
6488 INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT (c1, c2) DO NOTHING; -- unsupported
6489 ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification
6490 INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT (c1, c2) DO UPDATE SET c3 = 'ffg'; -- unsupported
6491 ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification
6492 INSERT INTO ft1(c1, c2) VALUES(1111, -2);  -- c2positive
6493 ERROR:  new row for relation "T 1" violates check constraint "c2positive"
6494 DETAIL:  Failing row contains (1111, -2, null, null, null, null, ft1       , null).
6495 CONTEXT:  remote SQL command: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
6496 UPDATE ft1 SET c2 = -c2 WHERE c1 = 1;  -- c2positive
6497 ERROR:  new row for relation "T 1" violates check constraint "c2positive"
6498 DETAIL:  Failing row contains (1, -1, 00001_trig_update, 1970-01-02 08:00:00+00, 1970-01-02 00:00:00, 1, 1         , foo).
6499 CONTEXT:  remote SQL command: UPDATE "S 1"."T 1" SET c2 = (- c2) WHERE (("C 1" = 1))
6500 -- Test savepoint/rollback behavior
6501 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6502  c2  | count 
6503 -----+-------
6504    0 |   100
6505    1 |   100
6506    4 |   100
6507    6 |   100
6508  100 |     2
6509  101 |     2
6510  104 |     2
6511  106 |     2
6512  201 |     1
6513  204 |     1
6514  303 |   100
6515  403 |     2
6516  407 |   100
6517 (13 rows)
6519 select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
6520  c2  | count 
6521 -----+-------
6522    0 |   100
6523    1 |   100
6524    4 |   100
6525    6 |   100
6526  100 |     2
6527  101 |     2
6528  104 |     2
6529  106 |     2
6530  201 |     1
6531  204 |     1
6532  303 |   100
6533  403 |     2
6534  407 |   100
6535 (13 rows)
6537 begin;
6538 update ft2 set c2 = 42 where c2 = 0;
6539 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6540  c2  | count 
6541 -----+-------
6542    1 |   100
6543    4 |   100
6544    6 |   100
6545   42 |   100
6546  100 |     2
6547  101 |     2
6548  104 |     2
6549  106 |     2
6550  201 |     1
6551  204 |     1
6552  303 |   100
6553  403 |     2
6554  407 |   100
6555 (13 rows)
6557 savepoint s1;
6558 update ft2 set c2 = 44 where c2 = 4;
6559 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6560  c2  | count 
6561 -----+-------
6562    1 |   100
6563    6 |   100
6564   42 |   100
6565   44 |   100
6566  100 |     2
6567  101 |     2
6568  104 |     2
6569  106 |     2
6570  201 |     1
6571  204 |     1
6572  303 |   100
6573  403 |     2
6574  407 |   100
6575 (13 rows)
6577 release savepoint s1;
6578 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6579  c2  | count 
6580 -----+-------
6581    1 |   100
6582    6 |   100
6583   42 |   100
6584   44 |   100
6585  100 |     2
6586  101 |     2
6587  104 |     2
6588  106 |     2
6589  201 |     1
6590  204 |     1
6591  303 |   100
6592  403 |     2
6593  407 |   100
6594 (13 rows)
6596 savepoint s2;
6597 update ft2 set c2 = 46 where c2 = 6;
6598 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6599  c2  | count 
6600 -----+-------
6601    1 |   100
6602   42 |   100
6603   44 |   100
6604   46 |   100
6605  100 |     2
6606  101 |     2
6607  104 |     2
6608  106 |     2
6609  201 |     1
6610  204 |     1
6611  303 |   100
6612  403 |     2
6613  407 |   100
6614 (13 rows)
6616 rollback to savepoint s2;
6617 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6618  c2  | count 
6619 -----+-------
6620    1 |   100
6621    6 |   100
6622   42 |   100
6623   44 |   100
6624  100 |     2
6625  101 |     2
6626  104 |     2
6627  106 |     2
6628  201 |     1
6629  204 |     1
6630  303 |   100
6631  403 |     2
6632  407 |   100
6633 (13 rows)
6635 release savepoint s2;
6636 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6637  c2  | count 
6638 -----+-------
6639    1 |   100
6640    6 |   100
6641   42 |   100
6642   44 |   100
6643  100 |     2
6644  101 |     2
6645  104 |     2
6646  106 |     2
6647  201 |     1
6648  204 |     1
6649  303 |   100
6650  403 |     2
6651  407 |   100
6652 (13 rows)
6654 savepoint s3;
6655 update ft2 set c2 = -2 where c2 = 42 and c1 = 10; -- fail on remote side
6656 ERROR:  new row for relation "T 1" violates check constraint "c2positive"
6657 DETAIL:  Failing row contains (10, -2, 00010_trig_update_trig_update, 1970-01-11 08:00:00+00, 1970-01-11 00:00:00, 0, 0         , foo).
6658 CONTEXT:  remote SQL command: UPDATE "S 1"."T 1" SET c2 = (-2) WHERE ((c2 = 42)) AND (("C 1" = 10))
6659 rollback to savepoint s3;
6660 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6661  c2  | count 
6662 -----+-------
6663    1 |   100
6664    6 |   100
6665   42 |   100
6666   44 |   100
6667  100 |     2
6668  101 |     2
6669  104 |     2
6670  106 |     2
6671  201 |     1
6672  204 |     1
6673  303 |   100
6674  403 |     2
6675  407 |   100
6676 (13 rows)
6678 release savepoint s3;
6679 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6680  c2  | count 
6681 -----+-------
6682    1 |   100
6683    6 |   100
6684   42 |   100
6685   44 |   100
6686  100 |     2
6687  101 |     2
6688  104 |     2
6689  106 |     2
6690  201 |     1
6691  204 |     1
6692  303 |   100
6693  403 |     2
6694  407 |   100
6695 (13 rows)
6697 -- none of the above is committed yet remotely
6698 select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
6699  c2  | count 
6700 -----+-------
6701    0 |   100
6702    1 |   100
6703    4 |   100
6704    6 |   100
6705  100 |     2
6706  101 |     2
6707  104 |     2
6708  106 |     2
6709  201 |     1
6710  204 |     1
6711  303 |   100
6712  403 |     2
6713  407 |   100
6714 (13 rows)
6716 commit;
6717 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6718  c2  | count 
6719 -----+-------
6720    1 |   100
6721    6 |   100
6722   42 |   100
6723   44 |   100
6724  100 |     2
6725  101 |     2
6726  104 |     2
6727  106 |     2
6728  201 |     1
6729  204 |     1
6730  303 |   100
6731  403 |     2
6732  407 |   100
6733 (13 rows)
6735 select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
6736  c2  | count 
6737 -----+-------
6738    1 |   100
6739    6 |   100
6740   42 |   100
6741   44 |   100
6742  100 |     2
6743  101 |     2
6744  104 |     2
6745  106 |     2
6746  201 |     1
6747  204 |     1
6748  303 |   100
6749  403 |     2
6750  407 |   100
6751 (13 rows)
6753 VACUUM ANALYZE "S 1"."T 1";
6754 -- Above DMLs add data with c6 as NULL in ft1, so test ORDER BY NULLS LAST and NULLs
6755 -- FIRST behavior here.
6756 -- ORDER BY DESC NULLS LAST options
6757 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 ORDER BY c6 DESC NULLS LAST, c1 OFFSET 795 LIMIT 10;
6758                                                                           QUERY PLAN                                                                           
6759 ---------------------------------------------------------------------------------------------------------------------------------------------------------------
6760  Foreign Scan on public.ft1
6761    Output: c1, c2, c3, c4, c5, c6, c7, c8
6762    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY c6 DESC NULLS LAST, "C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 795::bigint
6763 (3 rows)
6765 SELECT * FROM ft1 ORDER BY c6 DESC NULLS LAST, c1 OFFSET 795  LIMIT 10;
6766   c1  | c2  |         c3         |              c4              |            c5            |  c6  |     c7     | c8  
6767 ------+-----+--------------------+------------------------------+--------------------------+------+------------+-----
6768   960 |  42 | 00960_trig_update  | Mon Mar 02 00:00:00 1970 PST | Mon Mar 02 00:00:00 1970 | 0    | 0          | foo
6769   970 |  42 | 00970_trig_update  | Thu Mar 12 00:00:00 1970 PST | Thu Mar 12 00:00:00 1970 | 0    | 0          | foo
6770   980 |  42 | 00980_trig_update  | Sun Mar 22 00:00:00 1970 PST | Sun Mar 22 00:00:00 1970 | 0    | 0          | foo
6771   990 |  42 | 00990_trig_update  | Wed Apr 01 00:00:00 1970 PST | Wed Apr 01 00:00:00 1970 | 0    | 0          | foo
6772  1000 |  42 | 01000_trig_update  | Thu Jan 01 00:00:00 1970 PST | Thu Jan 01 00:00:00 1970 | 0    | 0          | foo
6773  1218 | 818 | ggg_trig_update    |                              |                          | (--; | ft2        | 
6774  1001 | 101 | 0000100001         |                              |                          |      | ft2        | 
6775  1003 | 403 | 0000300003_update3 |                              |                          |      | ft2        | 
6776  1004 | 104 | 0000400004         |                              |                          |      | ft2        | 
6777  1006 | 106 | 0000600006         |                              |                          |      | ft2        | 
6778 (10 rows)
6780 -- ORDER BY DESC NULLS FIRST options
6781 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 ORDER BY c6 DESC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
6782                                                                           QUERY PLAN                                                                           
6783 ---------------------------------------------------------------------------------------------------------------------------------------------------------------
6784  Foreign Scan on public.ft1
6785    Output: c1, c2, c3, c4, c5, c6, c7, c8
6786    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY c6 DESC NULLS FIRST, "C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 15::bigint
6787 (3 rows)
6789 SELECT * FROM ft1 ORDER BY c6 DESC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
6790   c1  | c2  |       c3        |              c4              |            c5            | c6 |     c7     | c8  
6791 ------+-----+-----------------+------------------------------+--------------------------+----+------------+-----
6792  1020 | 100 | 0002000020      |                              |                          |    | ft2        | 
6793  1101 | 201 | aaa             |                              |                          |    | ft2        | 
6794  1103 | 503 | ccc_update3     |                              |                          |    | ft2        | 
6795  1104 | 204 | ddd             |                              |                          |    | ft2        | 
6796  1208 | 818 | fff_trig_update |                              |                          |    | ft2        | 
6797     9 | 509 | 00009_update9   | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9  | ft2        | foo
6798    19 | 509 | 00019_update9   | Tue Jan 20 00:00:00 1970 PST | Tue Jan 20 00:00:00 1970 | 9  | ft2        | foo
6799    29 | 509 | 00029_update9   | Fri Jan 30 00:00:00 1970 PST | Fri Jan 30 00:00:00 1970 | 9  | ft2        | foo
6800    39 | 509 | 00039_update9   | Mon Feb 09 00:00:00 1970 PST | Mon Feb 09 00:00:00 1970 | 9  | ft2        | foo
6801    49 | 509 | 00049_update9   | Thu Feb 19 00:00:00 1970 PST | Thu Feb 19 00:00:00 1970 | 9  | ft2        | foo
6802 (10 rows)
6804 -- ORDER BY ASC NULLS FIRST options
6805 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 ORDER BY c6 ASC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
6806                                                                           QUERY PLAN                                                                          
6807 --------------------------------------------------------------------------------------------------------------------------------------------------------------
6808  Foreign Scan on public.ft1
6809    Output: c1, c2, c3, c4, c5, c6, c7, c8
6810    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY c6 ASC NULLS FIRST, "C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 15::bigint
6811 (3 rows)
6813 SELECT * FROM ft1 ORDER BY c6 ASC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
6814   c1  | c2  |        c3         |              c4              |            c5            |  c6  |     c7     | c8  
6815 ------+-----+-------------------+------------------------------+--------------------------+------+------------+-----
6816  1020 | 100 | 0002000020        |                              |                          |      | ft2        | 
6817  1101 | 201 | aaa               |                              |                          |      | ft2        | 
6818  1103 | 503 | ccc_update3       |                              |                          |      | ft2        | 
6819  1104 | 204 | ddd               |                              |                          |      | ft2        | 
6820  1208 | 818 | fff_trig_update   |                              |                          |      | ft2        | 
6821  1218 | 818 | ggg_trig_update   |                              |                          | (--; | ft2        | 
6822    10 |  42 | 00010_trig_update | Sun Jan 11 00:00:00 1970 PST | Sun Jan 11 00:00:00 1970 | 0    | 0          | foo
6823    20 |  42 | 00020_trig_update | Wed Jan 21 00:00:00 1970 PST | Wed Jan 21 00:00:00 1970 | 0    | 0          | foo
6824    30 |  42 | 00030_trig_update | Sat Jan 31 00:00:00 1970 PST | Sat Jan 31 00:00:00 1970 | 0    | 0          | foo
6825    40 |  42 | 00040_trig_update | Tue Feb 10 00:00:00 1970 PST | Tue Feb 10 00:00:00 1970 | 0    | 0          | foo
6826 (10 rows)
6828 -- ===================================================================
6829 -- test check constraints
6830 -- ===================================================================
6831 -- Consistent check constraints provide consistent results
6832 ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c2positive CHECK (c2 >= 0);
6833 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 < 0;
6834                            QUERY PLAN                            
6835 -----------------------------------------------------------------
6836  Foreign Scan
6837    Output: (count(*))
6838    Relations: Aggregate on (public.ft1)
6839    Remote SQL: SELECT count(*) FROM "S 1"."T 1" WHERE ((c2 < 0))
6840 (4 rows)
6842 SELECT count(*) FROM ft1 WHERE c2 < 0;
6843  count 
6844 -------
6845      0
6846 (1 row)
6848 SET constraint_exclusion = 'on';
6849 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 < 0;
6850            QUERY PLAN           
6851 --------------------------------
6852  Aggregate
6853    Output: count(*)
6854    ->  Result
6855          One-Time Filter: false
6856 (4 rows)
6858 SELECT count(*) FROM ft1 WHERE c2 < 0;
6859  count 
6860 -------
6861      0
6862 (1 row)
6864 RESET constraint_exclusion;
6865 -- check constraint is enforced on the remote side, not locally
6866 INSERT INTO ft1(c1, c2) VALUES(1111, -2);  -- c2positive
6867 ERROR:  new row for relation "T 1" violates check constraint "c2positive"
6868 DETAIL:  Failing row contains (1111, -2, null, null, null, null, ft1       , null).
6869 CONTEXT:  remote SQL command: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
6870 UPDATE ft1 SET c2 = -c2 WHERE c1 = 1;  -- c2positive
6871 ERROR:  new row for relation "T 1" violates check constraint "c2positive"
6872 DETAIL:  Failing row contains (1, -1, 00001_trig_update, 1970-01-02 08:00:00+00, 1970-01-02 00:00:00, 1, 1         , foo).
6873 CONTEXT:  remote SQL command: UPDATE "S 1"."T 1" SET c2 = (- c2) WHERE (("C 1" = 1))
6874 ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2positive;
6875 -- But inconsistent check constraints provide inconsistent results
6876 ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c2negative CHECK (c2 < 0);
6877 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 >= 0;
6878                             QUERY PLAN                            
6879 ------------------------------------------------------------------
6880  Foreign Scan
6881    Output: (count(*))
6882    Relations: Aggregate on (public.ft1)
6883    Remote SQL: SELECT count(*) FROM "S 1"."T 1" WHERE ((c2 >= 0))
6884 (4 rows)
6886 SELECT count(*) FROM ft1 WHERE c2 >= 0;
6887  count 
6888 -------
6889    821
6890 (1 row)
6892 SET constraint_exclusion = 'on';
6893 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 >= 0;
6894            QUERY PLAN           
6895 --------------------------------
6896  Aggregate
6897    Output: count(*)
6898    ->  Result
6899          One-Time Filter: false
6900 (4 rows)
6902 SELECT count(*) FROM ft1 WHERE c2 >= 0;
6903  count 
6904 -------
6905      0
6906 (1 row)
6908 RESET constraint_exclusion;
6909 -- local check constraint is not actually enforced
6910 INSERT INTO ft1(c1, c2) VALUES(1111, 2);
6911 UPDATE ft1 SET c2 = c2 + 1 WHERE c1 = 1;
6912 ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2negative;
6913 -- ===================================================================
6914 -- test WITH CHECK OPTION constraints
6915 -- ===================================================================
6916 CREATE FUNCTION row_before_insupd_trigfunc() RETURNS trigger AS $$BEGIN NEW.a := NEW.a + 10; RETURN NEW; END$$ LANGUAGE plpgsql;
6917 CREATE TABLE base_tbl (a int, b int);
6918 ALTER TABLE base_tbl SET (autovacuum_enabled = 'false');
6919 CREATE TRIGGER row_before_insupd_trigger BEFORE INSERT OR UPDATE ON base_tbl FOR EACH ROW EXECUTE PROCEDURE row_before_insupd_trigfunc();
6920 CREATE FOREIGN TABLE foreign_tbl (a int, b int)
6921   SERVER loopback OPTIONS (table_name 'base_tbl');
6922 CREATE VIEW rw_view AS SELECT * FROM foreign_tbl
6923   WHERE a < b WITH CHECK OPTION;
6924 \d+ rw_view
6925                            View "public.rw_view"
6926  Column |  Type   | Collation | Nullable | Default | Storage | Description 
6927 --------+---------+-----------+----------+---------+---------+-------------
6928  a      | integer |           |          |         | plain   | 
6929  b      | integer |           |          |         | plain   | 
6930 View definition:
6931  SELECT a,
6932     b
6933    FROM foreign_tbl
6934   WHERE a < b;
6935 Options: check_option=cascaded
6937 EXPLAIN (VERBOSE, COSTS OFF)
6938 INSERT INTO rw_view VALUES (0, 5);
6939                                    QUERY PLAN                                   
6940 --------------------------------------------------------------------------------
6941  Insert on public.foreign_tbl
6942    Remote SQL: INSERT INTO public.base_tbl(a, b) VALUES ($1, $2) RETURNING a, b
6943    Batch Size: 1
6944    ->  Result
6945          Output: 0, 5
6946 (5 rows)
6948 INSERT INTO rw_view VALUES (0, 5); -- should fail
6949 ERROR:  new row violates check option for view "rw_view"
6950 DETAIL:  Failing row contains (10, 5).
6951 EXPLAIN (VERBOSE, COSTS OFF)
6952 INSERT INTO rw_view VALUES (0, 15);
6953                                    QUERY PLAN                                   
6954 --------------------------------------------------------------------------------
6955  Insert on public.foreign_tbl
6956    Remote SQL: INSERT INTO public.base_tbl(a, b) VALUES ($1, $2) RETURNING a, b
6957    Batch Size: 1
6958    ->  Result
6959          Output: 0, 15
6960 (5 rows)
6962 INSERT INTO rw_view VALUES (0, 15); -- ok
6963 SELECT * FROM foreign_tbl;
6964  a  | b  
6965 ----+----
6966  10 | 15
6967 (1 row)
6969 EXPLAIN (VERBOSE, COSTS OFF)
6970 UPDATE rw_view SET b = b + 5;
6971                                       QUERY PLAN                                       
6972 ---------------------------------------------------------------------------------------
6973  Update on public.foreign_tbl
6974    Remote SQL: UPDATE public.base_tbl SET b = $2 WHERE ctid = $1 RETURNING a, b
6975    ->  Foreign Scan on public.foreign_tbl
6976          Output: (foreign_tbl.b + 5), foreign_tbl.ctid, foreign_tbl.*
6977          Remote SQL: SELECT a, b, ctid FROM public.base_tbl WHERE ((a < b)) FOR UPDATE
6978 (5 rows)
6980 UPDATE rw_view SET b = b + 5; -- should fail
6981 ERROR:  new row violates check option for view "rw_view"
6982 DETAIL:  Failing row contains (20, 20).
6983 EXPLAIN (VERBOSE, COSTS OFF)
6984 UPDATE rw_view SET b = b + 15;
6985                                       QUERY PLAN                                       
6986 ---------------------------------------------------------------------------------------
6987  Update on public.foreign_tbl
6988    Remote SQL: UPDATE public.base_tbl SET b = $2 WHERE ctid = $1 RETURNING a, b
6989    ->  Foreign Scan on public.foreign_tbl
6990          Output: (foreign_tbl.b + 15), foreign_tbl.ctid, foreign_tbl.*
6991          Remote SQL: SELECT a, b, ctid FROM public.base_tbl WHERE ((a < b)) FOR UPDATE
6992 (5 rows)
6994 UPDATE rw_view SET b = b + 15; -- ok
6995 SELECT * FROM foreign_tbl;
6996  a  | b  
6997 ----+----
6998  20 | 30
6999 (1 row)
7001 -- We don't allow batch insert when there are any WCO constraints
7002 ALTER SERVER loopback OPTIONS (ADD batch_size '10');
7003 EXPLAIN (VERBOSE, COSTS OFF)
7004 INSERT INTO rw_view VALUES (0, 15), (0, 5);
7005                                    QUERY PLAN                                   
7006 --------------------------------------------------------------------------------
7007  Insert on public.foreign_tbl
7008    Remote SQL: INSERT INTO public.base_tbl(a, b) VALUES ($1, $2) RETURNING a, b
7009    Batch Size: 1
7010    ->  Values Scan on "*VALUES*"
7011          Output: "*VALUES*".column1, "*VALUES*".column2
7012 (5 rows)
7014 INSERT INTO rw_view VALUES (0, 15), (0, 5); -- should fail
7015 ERROR:  new row violates check option for view "rw_view"
7016 DETAIL:  Failing row contains (10, 5).
7017 SELECT * FROM foreign_tbl;
7018  a  | b  
7019 ----+----
7020  20 | 30
7021 (1 row)
7023 ALTER SERVER loopback OPTIONS (DROP batch_size);
7024 DROP FOREIGN TABLE foreign_tbl CASCADE;
7025 NOTICE:  drop cascades to view rw_view
7026 DROP TRIGGER row_before_insupd_trigger ON base_tbl;
7027 DROP TABLE base_tbl;
7028 -- test WCO for partitions
7029 CREATE TABLE child_tbl (a int, b int);
7030 ALTER TABLE child_tbl SET (autovacuum_enabled = 'false');
7031 CREATE TRIGGER row_before_insupd_trigger BEFORE INSERT OR UPDATE ON child_tbl FOR EACH ROW EXECUTE PROCEDURE row_before_insupd_trigfunc();
7032 CREATE FOREIGN TABLE foreign_tbl (a int, b int)
7033   SERVER loopback OPTIONS (table_name 'child_tbl');
7034 CREATE TABLE parent_tbl (a int, b int) PARTITION BY RANGE(a);
7035 ALTER TABLE parent_tbl ATTACH PARTITION foreign_tbl FOR VALUES FROM (0) TO (100);
7036 -- Detach and re-attach once, to stress the concurrent detach case.
7037 ALTER TABLE parent_tbl DETACH PARTITION foreign_tbl CONCURRENTLY;
7038 ALTER TABLE parent_tbl ATTACH PARTITION foreign_tbl FOR VALUES FROM (0) TO (100);
7039 CREATE VIEW rw_view AS SELECT * FROM parent_tbl
7040   WHERE a < b WITH CHECK OPTION;
7041 \d+ rw_view
7042                            View "public.rw_view"
7043  Column |  Type   | Collation | Nullable | Default | Storage | Description 
7044 --------+---------+-----------+----------+---------+---------+-------------
7045  a      | integer |           |          |         | plain   | 
7046  b      | integer |           |          |         | plain   | 
7047 View definition:
7048  SELECT a,
7049     b
7050    FROM parent_tbl
7051   WHERE a < b;
7052 Options: check_option=cascaded
7054 EXPLAIN (VERBOSE, COSTS OFF)
7055 INSERT INTO rw_view VALUES (0, 5);
7056          QUERY PLAN          
7057 -----------------------------
7058  Insert on public.parent_tbl
7059    ->  Result
7060          Output: 0, 5
7061 (3 rows)
7063 INSERT INTO rw_view VALUES (0, 5); -- should fail
7064 ERROR:  new row violates check option for view "rw_view"
7065 DETAIL:  Failing row contains (10, 5).
7066 EXPLAIN (VERBOSE, COSTS OFF)
7067 INSERT INTO rw_view VALUES (0, 15);
7068          QUERY PLAN          
7069 -----------------------------
7070  Insert on public.parent_tbl
7071    ->  Result
7072          Output: 0, 15
7073 (3 rows)
7075 INSERT INTO rw_view VALUES (0, 15); -- ok
7076 SELECT * FROM foreign_tbl;
7077  a  | b  
7078 ----+----
7079  10 | 15
7080 (1 row)
7082 EXPLAIN (VERBOSE, COSTS OFF)
7083 UPDATE rw_view SET b = b + 5;
7084                                            QUERY PLAN                                           
7085 ------------------------------------------------------------------------------------------------
7086  Update on public.parent_tbl
7087    Foreign Update on public.foreign_tbl parent_tbl_1
7088      Remote SQL: UPDATE public.child_tbl SET b = $2 WHERE ctid = $1 RETURNING a, b
7089    ->  Foreign Scan on public.foreign_tbl parent_tbl_1
7090          Output: (parent_tbl_1.b + 5), parent_tbl_1.tableoid, parent_tbl_1.ctid, parent_tbl_1.*
7091          Remote SQL: SELECT a, b, ctid FROM public.child_tbl WHERE ((a < b)) FOR UPDATE
7092 (6 rows)
7094 UPDATE rw_view SET b = b + 5; -- should fail
7095 ERROR:  new row violates check option for view "rw_view"
7096 DETAIL:  Failing row contains (20, 20).
7097 EXPLAIN (VERBOSE, COSTS OFF)
7098 UPDATE rw_view SET b = b + 15;
7099                                            QUERY PLAN                                            
7100 -------------------------------------------------------------------------------------------------
7101  Update on public.parent_tbl
7102    Foreign Update on public.foreign_tbl parent_tbl_1
7103      Remote SQL: UPDATE public.child_tbl SET b = $2 WHERE ctid = $1 RETURNING a, b
7104    ->  Foreign Scan on public.foreign_tbl parent_tbl_1
7105          Output: (parent_tbl_1.b + 15), parent_tbl_1.tableoid, parent_tbl_1.ctid, parent_tbl_1.*
7106          Remote SQL: SELECT a, b, ctid FROM public.child_tbl WHERE ((a < b)) FOR UPDATE
7107 (6 rows)
7109 UPDATE rw_view SET b = b + 15; -- ok
7110 SELECT * FROM foreign_tbl;
7111  a  | b  
7112 ----+----
7113  20 | 30
7114 (1 row)
7116 -- We don't allow batch insert when there are any WCO constraints
7117 ALTER SERVER loopback OPTIONS (ADD batch_size '10');
7118 EXPLAIN (VERBOSE, COSTS OFF)
7119 INSERT INTO rw_view VALUES (0, 15), (0, 5);
7120                        QUERY PLAN                       
7121 --------------------------------------------------------
7122  Insert on public.parent_tbl
7123    ->  Values Scan on "*VALUES*"
7124          Output: "*VALUES*".column1, "*VALUES*".column2
7125 (3 rows)
7127 INSERT INTO rw_view VALUES (0, 15), (0, 5); -- should fail
7128 ERROR:  new row violates check option for view "rw_view"
7129 DETAIL:  Failing row contains (10, 5).
7130 SELECT * FROM foreign_tbl;
7131  a  | b  
7132 ----+----
7133  20 | 30
7134 (1 row)
7136 ALTER SERVER loopback OPTIONS (DROP batch_size);
7137 DROP FOREIGN TABLE foreign_tbl CASCADE;
7138 DROP TRIGGER row_before_insupd_trigger ON child_tbl;
7139 DROP TABLE parent_tbl CASCADE;
7140 NOTICE:  drop cascades to view rw_view
7141 DROP FUNCTION row_before_insupd_trigfunc;
7142 -- Try a more complex permutation of WCO where there are multiple levels of
7143 -- partitioned tables with columns not all in the same order
7144 CREATE TABLE parent_tbl (a int, b text, c numeric) PARTITION BY RANGE(a);
7145 CREATE TABLE sub_parent (c numeric, a int, b text) PARTITION BY RANGE(a);
7146 ALTER TABLE parent_tbl ATTACH PARTITION sub_parent FOR VALUES FROM (1) TO (10);
7147 CREATE TABLE child_local (b text, c numeric, a int);
7148 CREATE FOREIGN TABLE child_foreign (b text, c numeric, a int)
7149   SERVER loopback OPTIONS (table_name 'child_local');
7150 ALTER TABLE sub_parent ATTACH PARTITION child_foreign FOR VALUES FROM (1) TO (10);
7151 CREATE VIEW rw_view AS SELECT * FROM parent_tbl WHERE a < 5 WITH CHECK OPTION;
7152 INSERT INTO parent_tbl (a) VALUES(1),(5);
7153 EXPLAIN (VERBOSE, COSTS OFF)
7154 UPDATE rw_view SET b = 'text', c = 123.456;
7155                                            QUERY PLAN                                            
7156 -------------------------------------------------------------------------------------------------
7157  Update on public.parent_tbl
7158    Foreign Update on public.child_foreign parent_tbl_1
7159      Remote SQL: UPDATE public.child_local SET b = $2, c = $3 WHERE ctid = $1 RETURNING a
7160    ->  Foreign Scan on public.child_foreign parent_tbl_1
7161          Output: 'text'::text, 123.456, parent_tbl_1.tableoid, parent_tbl_1.ctid, parent_tbl_1.*
7162          Remote SQL: SELECT b, c, a, ctid FROM public.child_local WHERE ((a < 5)) FOR UPDATE
7163 (6 rows)
7165 UPDATE rw_view SET b = 'text', c = 123.456;
7166 SELECT * FROM parent_tbl ORDER BY a;
7167  a |  b   |    c    
7168 ---+------+---------
7169  1 | text | 123.456
7170  5 |      |        
7171 (2 rows)
7173 DROP VIEW rw_view;
7174 DROP TABLE child_local;
7175 DROP FOREIGN TABLE child_foreign;
7176 DROP TABLE sub_parent;
7177 DROP TABLE parent_tbl;
7178 -- ===================================================================
7179 -- test serial columns (ie, sequence-based defaults)
7180 -- ===================================================================
7181 create table loc1 (f1 serial, f2 text);
7182 alter table loc1 set (autovacuum_enabled = 'false');
7183 create foreign table rem1 (f1 serial, f2 text)
7184   server loopback options(table_name 'loc1');
7185 select pg_catalog.setval('rem1_f1_seq', 10, false);
7186  setval 
7187 --------
7188      10
7189 (1 row)
7191 insert into loc1(f2) values('hi');
7192 insert into rem1(f2) values('hi remote');
7193 insert into loc1(f2) values('bye');
7194 insert into rem1(f2) values('bye remote');
7195 select * from loc1;
7196  f1 |     f2     
7197 ----+------------
7198   1 | hi
7199  10 | hi remote
7200   2 | bye
7201  11 | bye remote
7202 (4 rows)
7204 select * from rem1;
7205  f1 |     f2     
7206 ----+------------
7207   1 | hi
7208  10 | hi remote
7209   2 | bye
7210  11 | bye remote
7211 (4 rows)
7213 -- ===================================================================
7214 -- test generated columns
7215 -- ===================================================================
7216 create table gloc1 (
7217   a int,
7218   b int generated always as (a * 2) stored);
7219 alter table gloc1 set (autovacuum_enabled = 'false');
7220 create foreign table grem1 (
7221   a int,
7222   b int generated always as (a * 2) stored)
7223   server loopback options(table_name 'gloc1');
7224 explain (verbose, costs off)
7225 insert into grem1 (a) values (1), (2);
7226                             QUERY PLAN                             
7227 -------------------------------------------------------------------
7228  Insert on public.grem1
7229    Remote SQL: INSERT INTO public.gloc1(a, b) VALUES ($1, DEFAULT)
7230    Batch Size: 1
7231    ->  Values Scan on "*VALUES*"
7232          Output: "*VALUES*".column1, NULL::integer
7233 (5 rows)
7235 insert into grem1 (a) values (1), (2);
7236 explain (verbose, costs off)
7237 update grem1 set a = 22 where a = 2;
7238                                      QUERY PLAN                                     
7239 ------------------------------------------------------------------------------------
7240  Update on public.grem1
7241    Remote SQL: UPDATE public.gloc1 SET a = $2, b = DEFAULT WHERE ctid = $1
7242    ->  Foreign Scan on public.grem1
7243          Output: 22, ctid, grem1.*
7244          Remote SQL: SELECT a, b, ctid FROM public.gloc1 WHERE ((a = 2)) FOR UPDATE
7245 (5 rows)
7247 update grem1 set a = 22 where a = 2;
7248 select * from gloc1;
7249  a  | b  
7250 ----+----
7251   1 |  2
7252  22 | 44
7253 (2 rows)
7255 select * from grem1;
7256  a  | b  
7257 ----+----
7258   1 |  2
7259  22 | 44
7260 (2 rows)
7262 delete from grem1;
7263 -- test copy from
7264 copy grem1 from stdin;
7265 select * from gloc1;
7266  a | b 
7267 ---+---
7268  1 | 2
7269  2 | 4
7270 (2 rows)
7272 select * from grem1;
7273  a | b 
7274 ---+---
7275  1 | 2
7276  2 | 4
7277 (2 rows)
7279 delete from grem1;
7280 -- test batch insert
7281 alter server loopback options (add batch_size '10');
7282 explain (verbose, costs off)
7283 insert into grem1 (a) values (1), (2);
7284                             QUERY PLAN                             
7285 -------------------------------------------------------------------
7286  Insert on public.grem1
7287    Remote SQL: INSERT INTO public.gloc1(a, b) VALUES ($1, DEFAULT)
7288    Batch Size: 10
7289    ->  Values Scan on "*VALUES*"
7290          Output: "*VALUES*".column1, NULL::integer
7291 (5 rows)
7293 insert into grem1 (a) values (1), (2);
7294 select * from gloc1;
7295  a | b 
7296 ---+---
7297  1 | 2
7298  2 | 4
7299 (2 rows)
7301 select * from grem1;
7302  a | b 
7303 ---+---
7304  1 | 2
7305  2 | 4
7306 (2 rows)
7308 delete from grem1;
7309 -- batch insert with foreign partitions.
7310 -- This schema uses two partitions, one local and one remote with a modulo
7311 -- to loop across all of them in batches.
7312 create table tab_batch_local (id int, data text);
7313 insert into tab_batch_local select i, 'test'|| i from generate_series(1, 45) i;
7314 create table tab_batch_sharded (id int, data text) partition by hash(id);
7315 create table tab_batch_sharded_p0 partition of tab_batch_sharded
7316   for values with (modulus 2, remainder 0);
7317 create table tab_batch_sharded_p1_remote (id int, data text);
7318 create foreign table tab_batch_sharded_p1 partition of tab_batch_sharded
7319   for values with (modulus 2, remainder 1)
7320   server loopback options (table_name 'tab_batch_sharded_p1_remote');
7321 insert into tab_batch_sharded select * from tab_batch_local;
7322 select count(*) from tab_batch_sharded;
7323  count 
7324 -------
7325     45
7326 (1 row)
7328 drop table tab_batch_local;
7329 drop table tab_batch_sharded;
7330 drop table tab_batch_sharded_p1_remote;
7331 alter server loopback options (drop batch_size);
7332 -- ===================================================================
7333 -- test local triggers
7334 -- ===================================================================
7335 -- Trigger functions "borrowed" from triggers regress test.
7336 CREATE FUNCTION trigger_func() RETURNS trigger LANGUAGE plpgsql AS $$
7337 BEGIN
7338         RAISE NOTICE 'trigger_func(%) called: action = %, when = %, level = %',
7339                 TG_ARGV[0], TG_OP, TG_WHEN, TG_LEVEL;
7340         RETURN NULL;
7341 END;$$;
7342 CREATE TRIGGER trig_stmt_before BEFORE DELETE OR INSERT OR UPDATE OR TRUNCATE ON rem1
7343         FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
7344 CREATE TRIGGER trig_stmt_after AFTER DELETE OR INSERT OR UPDATE OR TRUNCATE ON rem1
7345         FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
7346 CREATE OR REPLACE FUNCTION trigger_data()  RETURNS trigger
7347 LANGUAGE plpgsql AS $$
7349 declare
7350         oldnew text[];
7351         relid text;
7352     argstr text;
7353 begin
7355         relid := TG_relid::regclass;
7356         argstr := '';
7357         for i in 0 .. TG_nargs - 1 loop
7358                 if i > 0 then
7359                         argstr := argstr || ', ';
7360                 end if;
7361                 argstr := argstr || TG_argv[i];
7362         end loop;
7364     RAISE NOTICE '%(%) % % % ON %',
7365                 tg_name, argstr, TG_when, TG_level, TG_OP, relid;
7366     oldnew := '{}'::text[];
7367         if TG_OP != 'INSERT' then
7368                 oldnew := array_append(oldnew, format('OLD: %s', OLD));
7369         end if;
7371         if TG_OP != 'DELETE' then
7372                 oldnew := array_append(oldnew, format('NEW: %s', NEW));
7373         end if;
7375     RAISE NOTICE '%', array_to_string(oldnew, ',');
7377         if TG_OP = 'DELETE' then
7378                 return OLD;
7379         else
7380                 return NEW;
7381         end if;
7382 end;
7384 -- Test basic functionality
7385 CREATE TRIGGER trig_row_before
7386 BEFORE INSERT OR UPDATE OR DELETE ON rem1
7387 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7388 CREATE TRIGGER trig_row_after
7389 AFTER INSERT OR UPDATE OR DELETE ON rem1
7390 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7391 delete from rem1;
7392 NOTICE:  trigger_func(<NULL>) called: action = DELETE, when = BEFORE, level = STATEMENT
7393 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW DELETE ON rem1
7394 NOTICE:  OLD: (1,hi)
7395 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW DELETE ON rem1
7396 NOTICE:  OLD: (10,"hi remote")
7397 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW DELETE ON rem1
7398 NOTICE:  OLD: (2,bye)
7399 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW DELETE ON rem1
7400 NOTICE:  OLD: (11,"bye remote")
7401 NOTICE:  trig_row_after(23, skidoo) AFTER ROW DELETE ON rem1
7402 NOTICE:  OLD: (1,hi)
7403 NOTICE:  trig_row_after(23, skidoo) AFTER ROW DELETE ON rem1
7404 NOTICE:  OLD: (10,"hi remote")
7405 NOTICE:  trig_row_after(23, skidoo) AFTER ROW DELETE ON rem1
7406 NOTICE:  OLD: (2,bye)
7407 NOTICE:  trig_row_after(23, skidoo) AFTER ROW DELETE ON rem1
7408 NOTICE:  OLD: (11,"bye remote")
7409 NOTICE:  trigger_func(<NULL>) called: action = DELETE, when = AFTER, level = STATEMENT
7410 insert into rem1 values(1,'insert');
7411 NOTICE:  trigger_func(<NULL>) called: action = INSERT, when = BEFORE, level = STATEMENT
7412 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem1
7413 NOTICE:  NEW: (1,insert)
7414 NOTICE:  trig_row_after(23, skidoo) AFTER ROW INSERT ON rem1
7415 NOTICE:  NEW: (1,insert)
7416 NOTICE:  trigger_func(<NULL>) called: action = INSERT, when = AFTER, level = STATEMENT
7417 update rem1 set f2  = 'update' where f1 = 1;
7418 NOTICE:  trigger_func(<NULL>) called: action = UPDATE, when = BEFORE, level = STATEMENT
7419 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON rem1
7420 NOTICE:  OLD: (1,insert),NEW: (1,update)
7421 NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON rem1
7422 NOTICE:  OLD: (1,insert),NEW: (1,update)
7423 NOTICE:  trigger_func(<NULL>) called: action = UPDATE, when = AFTER, level = STATEMENT
7424 update rem1 set f2 = f2 || f2;
7425 NOTICE:  trigger_func(<NULL>) called: action = UPDATE, when = BEFORE, level = STATEMENT
7426 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON rem1
7427 NOTICE:  OLD: (1,update),NEW: (1,updateupdate)
7428 NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON rem1
7429 NOTICE:  OLD: (1,update),NEW: (1,updateupdate)
7430 NOTICE:  trigger_func(<NULL>) called: action = UPDATE, when = AFTER, level = STATEMENT
7431 truncate rem1;
7432 NOTICE:  trigger_func(<NULL>) called: action = TRUNCATE, when = BEFORE, level = STATEMENT
7433 NOTICE:  trigger_func(<NULL>) called: action = TRUNCATE, when = AFTER, level = STATEMENT
7434 -- cleanup
7435 DROP TRIGGER trig_row_before ON rem1;
7436 DROP TRIGGER trig_row_after ON rem1;
7437 DROP TRIGGER trig_stmt_before ON rem1;
7438 DROP TRIGGER trig_stmt_after ON rem1;
7439 DELETE from rem1;
7440 -- Test multiple AFTER ROW triggers on a foreign table
7441 CREATE TRIGGER trig_row_after1
7442 AFTER INSERT OR UPDATE OR DELETE ON rem1
7443 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7444 CREATE TRIGGER trig_row_after2
7445 AFTER INSERT OR UPDATE OR DELETE ON rem1
7446 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7447 insert into rem1 values(1,'insert');
7448 NOTICE:  trig_row_after1(23, skidoo) AFTER ROW INSERT ON rem1
7449 NOTICE:  NEW: (1,insert)
7450 NOTICE:  trig_row_after2(23, skidoo) AFTER ROW INSERT ON rem1
7451 NOTICE:  NEW: (1,insert)
7452 update rem1 set f2  = 'update' where f1 = 1;
7453 NOTICE:  trig_row_after1(23, skidoo) AFTER ROW UPDATE ON rem1
7454 NOTICE:  OLD: (1,insert),NEW: (1,update)
7455 NOTICE:  trig_row_after2(23, skidoo) AFTER ROW UPDATE ON rem1
7456 NOTICE:  OLD: (1,insert),NEW: (1,update)
7457 update rem1 set f2 = f2 || f2;
7458 NOTICE:  trig_row_after1(23, skidoo) AFTER ROW UPDATE ON rem1
7459 NOTICE:  OLD: (1,update),NEW: (1,updateupdate)
7460 NOTICE:  trig_row_after2(23, skidoo) AFTER ROW UPDATE ON rem1
7461 NOTICE:  OLD: (1,update),NEW: (1,updateupdate)
7462 delete from rem1;
7463 NOTICE:  trig_row_after1(23, skidoo) AFTER ROW DELETE ON rem1
7464 NOTICE:  OLD: (1,updateupdate)
7465 NOTICE:  trig_row_after2(23, skidoo) AFTER ROW DELETE ON rem1
7466 NOTICE:  OLD: (1,updateupdate)
7467 -- cleanup
7468 DROP TRIGGER trig_row_after1 ON rem1;
7469 DROP TRIGGER trig_row_after2 ON rem1;
7470 -- Test WHEN conditions
7471 CREATE TRIGGER trig_row_before_insupd
7472 BEFORE INSERT OR UPDATE ON rem1
7473 FOR EACH ROW
7474 WHEN (NEW.f2 like '%update%')
7475 EXECUTE PROCEDURE trigger_data(23,'skidoo');
7476 CREATE TRIGGER trig_row_after_insupd
7477 AFTER INSERT OR UPDATE ON rem1
7478 FOR EACH ROW
7479 WHEN (NEW.f2 like '%update%')
7480 EXECUTE PROCEDURE trigger_data(23,'skidoo');
7481 -- Insert or update not matching: nothing happens
7482 INSERT INTO rem1 values(1, 'insert');
7483 UPDATE rem1 set f2 = 'test';
7484 -- Insert or update matching: triggers are fired
7485 INSERT INTO rem1 values(2, 'update');
7486 NOTICE:  trig_row_before_insupd(23, skidoo) BEFORE ROW INSERT ON rem1
7487 NOTICE:  NEW: (2,update)
7488 NOTICE:  trig_row_after_insupd(23, skidoo) AFTER ROW INSERT ON rem1
7489 NOTICE:  NEW: (2,update)
7490 UPDATE rem1 set f2 = 'update update' where f1 = '2';
7491 NOTICE:  trig_row_before_insupd(23, skidoo) BEFORE ROW UPDATE ON rem1
7492 NOTICE:  OLD: (2,update),NEW: (2,"update update")
7493 NOTICE:  trig_row_after_insupd(23, skidoo) AFTER ROW UPDATE ON rem1
7494 NOTICE:  OLD: (2,update),NEW: (2,"update update")
7495 CREATE TRIGGER trig_row_before_delete
7496 BEFORE DELETE ON rem1
7497 FOR EACH ROW
7498 WHEN (OLD.f2 like '%update%')
7499 EXECUTE PROCEDURE trigger_data(23,'skidoo');
7500 CREATE TRIGGER trig_row_after_delete
7501 AFTER DELETE ON rem1
7502 FOR EACH ROW
7503 WHEN (OLD.f2 like '%update%')
7504 EXECUTE PROCEDURE trigger_data(23,'skidoo');
7505 -- Trigger is fired for f1=2, not for f1=1
7506 DELETE FROM rem1;
7507 NOTICE:  trig_row_before_delete(23, skidoo) BEFORE ROW DELETE ON rem1
7508 NOTICE:  OLD: (2,"update update")
7509 NOTICE:  trig_row_after_delete(23, skidoo) AFTER ROW DELETE ON rem1
7510 NOTICE:  OLD: (2,"update update")
7511 -- cleanup
7512 DROP TRIGGER trig_row_before_insupd ON rem1;
7513 DROP TRIGGER trig_row_after_insupd ON rem1;
7514 DROP TRIGGER trig_row_before_delete ON rem1;
7515 DROP TRIGGER trig_row_after_delete ON rem1;
7516 -- Test various RETURN statements in BEFORE triggers.
7517 CREATE FUNCTION trig_row_before_insupdate() RETURNS TRIGGER AS $$
7518   BEGIN
7519     NEW.f2 := NEW.f2 || ' triggered !';
7520     RETURN NEW;
7521   END
7522 $$ language plpgsql;
7523 CREATE TRIGGER trig_row_before_insupd
7524 BEFORE INSERT OR UPDATE ON rem1
7525 FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate();
7526 -- The new values should have 'triggered' appended
7527 INSERT INTO rem1 values(1, 'insert');
7528 SELECT * from loc1;
7529  f1 |         f2         
7530 ----+--------------------
7531   1 | insert triggered !
7532 (1 row)
7534 INSERT INTO rem1 values(2, 'insert') RETURNING f2;
7535          f2         
7536 --------------------
7537  insert triggered !
7538 (1 row)
7540 SELECT * from loc1;
7541  f1 |         f2         
7542 ----+--------------------
7543   1 | insert triggered !
7544   2 | insert triggered !
7545 (2 rows)
7547 UPDATE rem1 set f2 = '';
7548 SELECT * from loc1;
7549  f1 |      f2      
7550 ----+--------------
7551   1 |  triggered !
7552   2 |  triggered !
7553 (2 rows)
7555 UPDATE rem1 set f2 = 'skidoo' RETURNING f2;
7556          f2         
7557 --------------------
7558  skidoo triggered !
7559  skidoo triggered !
7560 (2 rows)
7562 SELECT * from loc1;
7563  f1 |         f2         
7564 ----+--------------------
7565   1 | skidoo triggered !
7566   2 | skidoo triggered !
7567 (2 rows)
7569 EXPLAIN (verbose, costs off)
7570 UPDATE rem1 set f1 = 10;          -- all columns should be transmitted
7571                               QUERY PLAN                               
7572 -----------------------------------------------------------------------
7573  Update on public.rem1
7574    Remote SQL: UPDATE public.loc1 SET f1 = $2, f2 = $3 WHERE ctid = $1
7575    ->  Foreign Scan on public.rem1
7576          Output: 10, ctid, rem1.*
7577          Remote SQL: SELECT f1, f2, ctid FROM public.loc1 FOR UPDATE
7578 (5 rows)
7580 UPDATE rem1 set f1 = 10;
7581 SELECT * from loc1;
7582  f1 |               f2               
7583 ----+--------------------------------
7584  10 | skidoo triggered ! triggered !
7585  10 | skidoo triggered ! triggered !
7586 (2 rows)
7588 DELETE FROM rem1;
7589 -- Add a second trigger, to check that the changes are propagated correctly
7590 -- from trigger to trigger
7591 CREATE TRIGGER trig_row_before_insupd2
7592 BEFORE INSERT OR UPDATE ON rem1
7593 FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate();
7594 INSERT INTO rem1 values(1, 'insert');
7595 SELECT * from loc1;
7596  f1 |               f2               
7597 ----+--------------------------------
7598   1 | insert triggered ! triggered !
7599 (1 row)
7601 INSERT INTO rem1 values(2, 'insert') RETURNING f2;
7602                f2               
7603 --------------------------------
7604  insert triggered ! triggered !
7605 (1 row)
7607 SELECT * from loc1;
7608  f1 |               f2               
7609 ----+--------------------------------
7610   1 | insert triggered ! triggered !
7611   2 | insert triggered ! triggered !
7612 (2 rows)
7614 UPDATE rem1 set f2 = '';
7615 SELECT * from loc1;
7616  f1 |            f2            
7617 ----+--------------------------
7618   1 |  triggered ! triggered !
7619   2 |  triggered ! triggered !
7620 (2 rows)
7622 UPDATE rem1 set f2 = 'skidoo' RETURNING f2;
7623                f2               
7624 --------------------------------
7625  skidoo triggered ! triggered !
7626  skidoo triggered ! triggered !
7627 (2 rows)
7629 SELECT * from loc1;
7630  f1 |               f2               
7631 ----+--------------------------------
7632   1 | skidoo triggered ! triggered !
7633   2 | skidoo triggered ! triggered !
7634 (2 rows)
7636 DROP TRIGGER trig_row_before_insupd ON rem1;
7637 DROP TRIGGER trig_row_before_insupd2 ON rem1;
7638 DELETE from rem1;
7639 INSERT INTO rem1 VALUES (1, 'test');
7640 -- Test with a trigger returning NULL
7641 CREATE FUNCTION trig_null() RETURNS TRIGGER AS $$
7642   BEGIN
7643     RETURN NULL;
7644   END
7645 $$ language plpgsql;
7646 CREATE TRIGGER trig_null
7647 BEFORE INSERT OR UPDATE OR DELETE ON rem1
7648 FOR EACH ROW EXECUTE PROCEDURE trig_null();
7649 -- Nothing should have changed.
7650 INSERT INTO rem1 VALUES (2, 'test2');
7651 SELECT * from loc1;
7652  f1 |  f2  
7653 ----+------
7654   1 | test
7655 (1 row)
7657 UPDATE rem1 SET f2 = 'test2';
7658 SELECT * from loc1;
7659  f1 |  f2  
7660 ----+------
7661   1 | test
7662 (1 row)
7664 DELETE from rem1;
7665 SELECT * from loc1;
7666  f1 |  f2  
7667 ----+------
7668   1 | test
7669 (1 row)
7671 DROP TRIGGER trig_null ON rem1;
7672 DELETE from rem1;
7673 -- Test a combination of local and remote triggers
7674 CREATE TRIGGER trig_row_before
7675 BEFORE INSERT OR UPDATE OR DELETE ON rem1
7676 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7677 CREATE TRIGGER trig_row_after
7678 AFTER INSERT OR UPDATE OR DELETE ON rem1
7679 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7680 CREATE TRIGGER trig_local_before BEFORE INSERT OR UPDATE ON loc1
7681 FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate();
7682 INSERT INTO rem1(f2) VALUES ('test');
7683 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem1
7684 NOTICE:  NEW: (12,test)
7685 NOTICE:  trig_row_after(23, skidoo) AFTER ROW INSERT ON rem1
7686 NOTICE:  NEW: (12,"test triggered !")
7687 UPDATE rem1 SET f2 = 'testo';
7688 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON rem1
7689 NOTICE:  OLD: (12,"test triggered !"),NEW: (12,testo)
7690 NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON rem1
7691 NOTICE:  OLD: (12,"test triggered !"),NEW: (12,"testo triggered !")
7692 -- Test returning a system attribute
7693 INSERT INTO rem1(f2) VALUES ('test') RETURNING ctid;
7694 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem1
7695 NOTICE:  NEW: (13,test)
7696 NOTICE:  trig_row_after(23, skidoo) AFTER ROW INSERT ON rem1
7697 NOTICE:  NEW: (13,"test triggered !")
7698   ctid  
7699 --------
7700  (0,25)
7701 (1 row)
7703 -- cleanup
7704 DROP TRIGGER trig_row_before ON rem1;
7705 DROP TRIGGER trig_row_after ON rem1;
7706 DROP TRIGGER trig_local_before ON loc1;
7707 -- Test direct foreign table modification functionality
7708 EXPLAIN (verbose, costs off)
7709 DELETE FROM rem1;                 -- can be pushed down
7710                  QUERY PLAN                  
7711 ---------------------------------------------
7712  Delete on public.rem1
7713    ->  Foreign Delete on public.rem1
7714          Remote SQL: DELETE FROM public.loc1
7715 (3 rows)
7717 EXPLAIN (verbose, costs off)
7718 DELETE FROM rem1 WHERE false;     -- currently can't be pushed down
7719                       QUERY PLAN                       
7720 -------------------------------------------------------
7721  Delete on public.rem1
7722    Remote SQL: DELETE FROM public.loc1 WHERE ctid = $1
7723    ->  Result
7724          Output: ctid
7725          One-Time Filter: false
7726 (5 rows)
7728 -- Test with statement-level triggers
7729 CREATE TRIGGER trig_stmt_before
7730         BEFORE DELETE OR INSERT OR UPDATE ON rem1
7731         FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
7732 EXPLAIN (verbose, costs off)
7733 UPDATE rem1 set f2 = '';          -- can be pushed down
7734                         QUERY PLAN                        
7735 ----------------------------------------------------------
7736  Update on public.rem1
7737    ->  Foreign Update on public.rem1
7738          Remote SQL: UPDATE public.loc1 SET f2 = ''::text
7739 (3 rows)
7741 EXPLAIN (verbose, costs off)
7742 DELETE FROM rem1;                 -- can be pushed down
7743                  QUERY PLAN                  
7744 ---------------------------------------------
7745  Delete on public.rem1
7746    ->  Foreign Delete on public.rem1
7747          Remote SQL: DELETE FROM public.loc1
7748 (3 rows)
7750 DROP TRIGGER trig_stmt_before ON rem1;
7751 CREATE TRIGGER trig_stmt_after
7752         AFTER DELETE OR INSERT OR UPDATE ON rem1
7753         FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
7754 EXPLAIN (verbose, costs off)
7755 UPDATE rem1 set f2 = '';          -- can be pushed down
7756                         QUERY PLAN                        
7757 ----------------------------------------------------------
7758  Update on public.rem1
7759    ->  Foreign Update on public.rem1
7760          Remote SQL: UPDATE public.loc1 SET f2 = ''::text
7761 (3 rows)
7763 EXPLAIN (verbose, costs off)
7764 DELETE FROM rem1;                 -- can be pushed down
7765                  QUERY PLAN                  
7766 ---------------------------------------------
7767  Delete on public.rem1
7768    ->  Foreign Delete on public.rem1
7769          Remote SQL: DELETE FROM public.loc1
7770 (3 rows)
7772 DROP TRIGGER trig_stmt_after ON rem1;
7773 -- Test with row-level ON INSERT triggers
7774 CREATE TRIGGER trig_row_before_insert
7775 BEFORE INSERT ON rem1
7776 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7777 EXPLAIN (verbose, costs off)
7778 UPDATE rem1 set f2 = '';          -- can be pushed down
7779                         QUERY PLAN                        
7780 ----------------------------------------------------------
7781  Update on public.rem1
7782    ->  Foreign Update on public.rem1
7783          Remote SQL: UPDATE public.loc1 SET f2 = ''::text
7784 (3 rows)
7786 EXPLAIN (verbose, costs off)
7787 DELETE FROM rem1;                 -- can be pushed down
7788                  QUERY PLAN                  
7789 ---------------------------------------------
7790  Delete on public.rem1
7791    ->  Foreign Delete on public.rem1
7792          Remote SQL: DELETE FROM public.loc1
7793 (3 rows)
7795 DROP TRIGGER trig_row_before_insert ON rem1;
7796 CREATE TRIGGER trig_row_after_insert
7797 AFTER INSERT ON rem1
7798 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7799 EXPLAIN (verbose, costs off)
7800 UPDATE rem1 set f2 = '';          -- can be pushed down
7801                         QUERY PLAN                        
7802 ----------------------------------------------------------
7803  Update on public.rem1
7804    ->  Foreign Update on public.rem1
7805          Remote SQL: UPDATE public.loc1 SET f2 = ''::text
7806 (3 rows)
7808 EXPLAIN (verbose, costs off)
7809 DELETE FROM rem1;                 -- can be pushed down
7810                  QUERY PLAN                  
7811 ---------------------------------------------
7812  Delete on public.rem1
7813    ->  Foreign Delete on public.rem1
7814          Remote SQL: DELETE FROM public.loc1
7815 (3 rows)
7817 DROP TRIGGER trig_row_after_insert ON rem1;
7818 -- Test with row-level ON UPDATE triggers
7819 CREATE TRIGGER trig_row_before_update
7820 BEFORE UPDATE ON rem1
7821 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7822 EXPLAIN (verbose, costs off)
7823 UPDATE rem1 set f2 = '';          -- can't be pushed down
7824                               QUERY PLAN                               
7825 -----------------------------------------------------------------------
7826  Update on public.rem1
7827    Remote SQL: UPDATE public.loc1 SET f1 = $2, f2 = $3 WHERE ctid = $1
7828    ->  Foreign Scan on public.rem1
7829          Output: ''::text, ctid, rem1.*
7830          Remote SQL: SELECT f1, f2, ctid FROM public.loc1 FOR UPDATE
7831 (5 rows)
7833 EXPLAIN (verbose, costs off)
7834 DELETE FROM rem1;                 -- can be pushed down
7835                  QUERY PLAN                  
7836 ---------------------------------------------
7837  Delete on public.rem1
7838    ->  Foreign Delete on public.rem1
7839          Remote SQL: DELETE FROM public.loc1
7840 (3 rows)
7842 DROP TRIGGER trig_row_before_update ON rem1;
7843 CREATE TRIGGER trig_row_after_update
7844 AFTER UPDATE ON rem1
7845 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7846 EXPLAIN (verbose, costs off)
7847 UPDATE rem1 set f2 = '';          -- can't be pushed down
7848                                   QUERY PLAN                                   
7849 -------------------------------------------------------------------------------
7850  Update on public.rem1
7851    Remote SQL: UPDATE public.loc1 SET f2 = $2 WHERE ctid = $1 RETURNING f1, f2
7852    ->  Foreign Scan on public.rem1
7853          Output: ''::text, ctid, rem1.*
7854          Remote SQL: SELECT f1, f2, ctid FROM public.loc1 FOR UPDATE
7855 (5 rows)
7857 EXPLAIN (verbose, costs off)
7858 DELETE FROM rem1;                 -- can be pushed down
7859                  QUERY PLAN                  
7860 ---------------------------------------------
7861  Delete on public.rem1
7862    ->  Foreign Delete on public.rem1
7863          Remote SQL: DELETE FROM public.loc1
7864 (3 rows)
7866 DROP TRIGGER trig_row_after_update ON rem1;
7867 -- Test with row-level ON DELETE triggers
7868 CREATE TRIGGER trig_row_before_delete
7869 BEFORE DELETE ON rem1
7870 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7871 EXPLAIN (verbose, costs off)
7872 UPDATE rem1 set f2 = '';          -- can be pushed down
7873                         QUERY PLAN                        
7874 ----------------------------------------------------------
7875  Update on public.rem1
7876    ->  Foreign Update on public.rem1
7877          Remote SQL: UPDATE public.loc1 SET f2 = ''::text
7878 (3 rows)
7880 EXPLAIN (verbose, costs off)
7881 DELETE FROM rem1;                 -- can't be pushed down
7882                              QUERY PLAN                              
7883 ---------------------------------------------------------------------
7884  Delete on public.rem1
7885    Remote SQL: DELETE FROM public.loc1 WHERE ctid = $1
7886    ->  Foreign Scan on public.rem1
7887          Output: ctid, rem1.*
7888          Remote SQL: SELECT f1, f2, ctid FROM public.loc1 FOR UPDATE
7889 (5 rows)
7891 DROP TRIGGER trig_row_before_delete ON rem1;
7892 CREATE TRIGGER trig_row_after_delete
7893 AFTER DELETE ON rem1
7894 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7895 EXPLAIN (verbose, costs off)
7896 UPDATE rem1 set f2 = '';          -- can be pushed down
7897                         QUERY PLAN                        
7898 ----------------------------------------------------------
7899  Update on public.rem1
7900    ->  Foreign Update on public.rem1
7901          Remote SQL: UPDATE public.loc1 SET f2 = ''::text
7902 (3 rows)
7904 EXPLAIN (verbose, costs off)
7905 DELETE FROM rem1;                 -- can't be pushed down
7906                                QUERY PLAN                               
7907 ------------------------------------------------------------------------
7908  Delete on public.rem1
7909    Remote SQL: DELETE FROM public.loc1 WHERE ctid = $1 RETURNING f1, f2
7910    ->  Foreign Scan on public.rem1
7911          Output: ctid, rem1.*
7912          Remote SQL: SELECT f1, f2, ctid FROM public.loc1 FOR UPDATE
7913 (5 rows)
7915 DROP TRIGGER trig_row_after_delete ON rem1;
7916 -- ===================================================================
7917 -- test inheritance features
7918 -- ===================================================================
7919 CREATE TABLE a (aa TEXT);
7920 CREATE TABLE loct (aa TEXT, bb TEXT);
7921 ALTER TABLE a SET (autovacuum_enabled = 'false');
7922 ALTER TABLE loct SET (autovacuum_enabled = 'false');
7923 CREATE FOREIGN TABLE b (bb TEXT) INHERITS (a)
7924   SERVER loopback OPTIONS (table_name 'loct');
7925 INSERT INTO a(aa) VALUES('aaa');
7926 INSERT INTO a(aa) VALUES('aaaa');
7927 INSERT INTO a(aa) VALUES('aaaaa');
7928 INSERT INTO b(aa) VALUES('bbb');
7929 INSERT INTO b(aa) VALUES('bbbb');
7930 INSERT INTO b(aa) VALUES('bbbbb');
7931 SELECT tableoid::regclass, * FROM a;
7932  tableoid |  aa   
7933 ----------+-------
7934  a        | aaa
7935  a        | aaaa
7936  a        | aaaaa
7937  b        | bbb
7938  b        | bbbb
7939  b        | bbbbb
7940 (6 rows)
7942 SELECT tableoid::regclass, * FROM b;
7943  tableoid |  aa   | bb 
7944 ----------+-------+----
7945  b        | bbb   | 
7946  b        | bbbb  | 
7947  b        | bbbbb | 
7948 (3 rows)
7950 SELECT tableoid::regclass, * FROM ONLY a;
7951  tableoid |  aa   
7952 ----------+-------
7953  a        | aaa
7954  a        | aaaa
7955  a        | aaaaa
7956 (3 rows)
7958 UPDATE a SET aa = 'zzzzzz' WHERE aa LIKE 'aaaa%';
7959 SELECT tableoid::regclass, * FROM a;
7960  tableoid |   aa   
7961 ----------+--------
7962  a        | aaa
7963  a        | zzzzzz
7964  a        | zzzzzz
7965  b        | bbb
7966  b        | bbbb
7967  b        | bbbbb
7968 (6 rows)
7970 SELECT tableoid::regclass, * FROM b;
7971  tableoid |  aa   | bb 
7972 ----------+-------+----
7973  b        | bbb   | 
7974  b        | bbbb  | 
7975  b        | bbbbb | 
7976 (3 rows)
7978 SELECT tableoid::regclass, * FROM ONLY a;
7979  tableoid |   aa   
7980 ----------+--------
7981  a        | aaa
7982  a        | zzzzzz
7983  a        | zzzzzz
7984 (3 rows)
7986 UPDATE b SET aa = 'new';
7987 SELECT tableoid::regclass, * FROM a;
7988  tableoid |   aa   
7989 ----------+--------
7990  a        | aaa
7991  a        | zzzzzz
7992  a        | zzzzzz
7993  b        | new
7994  b        | new
7995  b        | new
7996 (6 rows)
7998 SELECT tableoid::regclass, * FROM b;
7999  tableoid | aa  | bb 
8000 ----------+-----+----
8001  b        | new | 
8002  b        | new | 
8003  b        | new | 
8004 (3 rows)
8006 SELECT tableoid::regclass, * FROM ONLY a;
8007  tableoid |   aa   
8008 ----------+--------
8009  a        | aaa
8010  a        | zzzzzz
8011  a        | zzzzzz
8012 (3 rows)
8014 UPDATE a SET aa = 'newtoo';
8015 SELECT tableoid::regclass, * FROM a;
8016  tableoid |   aa   
8017 ----------+--------
8018  a        | newtoo
8019  a        | newtoo
8020  a        | newtoo
8021  b        | newtoo
8022  b        | newtoo
8023  b        | newtoo
8024 (6 rows)
8026 SELECT tableoid::regclass, * FROM b;
8027  tableoid |   aa   | bb 
8028 ----------+--------+----
8029  b        | newtoo | 
8030  b        | newtoo | 
8031  b        | newtoo | 
8032 (3 rows)
8034 SELECT tableoid::regclass, * FROM ONLY a;
8035  tableoid |   aa   
8036 ----------+--------
8037  a        | newtoo
8038  a        | newtoo
8039  a        | newtoo
8040 (3 rows)
8042 DELETE FROM a;
8043 SELECT tableoid::regclass, * FROM a;
8044  tableoid | aa 
8045 ----------+----
8046 (0 rows)
8048 SELECT tableoid::regclass, * FROM b;
8049  tableoid | aa | bb 
8050 ----------+----+----
8051 (0 rows)
8053 SELECT tableoid::regclass, * FROM ONLY a;
8054  tableoid | aa 
8055 ----------+----
8056 (0 rows)
8058 DROP TABLE a CASCADE;
8059 NOTICE:  drop cascades to foreign table b
8060 DROP TABLE loct;
8061 -- Check SELECT FOR UPDATE/SHARE with an inherited source table
8062 create table loct1 (f1 int, f2 int, f3 int);
8063 create table loct2 (f1 int, f2 int, f3 int);
8064 alter table loct1 set (autovacuum_enabled = 'false');
8065 alter table loct2 set (autovacuum_enabled = 'false');
8066 create table foo (f1 int, f2 int);
8067 create foreign table foo2 (f3 int) inherits (foo)
8068   server loopback options (table_name 'loct1');
8069 create table bar (f1 int, f2 int);
8070 create foreign table bar2 (f3 int) inherits (bar)
8071   server loopback options (table_name 'loct2');
8072 alter table foo set (autovacuum_enabled = 'false');
8073 alter table bar set (autovacuum_enabled = 'false');
8074 insert into foo values(1,1);
8075 insert into foo values(3,3);
8076 insert into foo2 values(2,2,2);
8077 insert into foo2 values(4,4,4);
8078 insert into bar values(1,11);
8079 insert into bar values(2,22);
8080 insert into bar values(6,66);
8081 insert into bar2 values(3,33,33);
8082 insert into bar2 values(4,44,44);
8083 insert into bar2 values(7,77,77);
8084 explain (verbose, costs off)
8085 select * from bar where f1 in (select f1 from foo) for update;
8086                                           QUERY PLAN                                          
8087 ----------------------------------------------------------------------------------------------
8088  LockRows
8089    Output: bar.f1, bar.f2, bar.ctid, foo.ctid, bar.*, bar.tableoid, foo.*, foo.tableoid
8090    ->  Hash Join
8091          Output: bar.f1, bar.f2, bar.ctid, foo.ctid, bar.*, bar.tableoid, foo.*, foo.tableoid
8092          Inner Unique: true
8093          Hash Cond: (bar.f1 = foo.f1)
8094          ->  Append
8095                ->  Seq Scan on public.bar bar_1
8096                      Output: bar_1.f1, bar_1.f2, bar_1.ctid, bar_1.*, bar_1.tableoid
8097                ->  Foreign Scan on public.bar2 bar_2
8098                      Output: bar_2.f1, bar_2.f2, bar_2.ctid, bar_2.*, bar_2.tableoid
8099                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
8100          ->  Hash
8101                Output: foo.ctid, foo.f1, foo.*, foo.tableoid
8102                ->  HashAggregate
8103                      Output: foo.ctid, foo.f1, foo.*, foo.tableoid
8104                      Group Key: foo.f1
8105                      ->  Append
8106                            ->  Seq Scan on public.foo foo_1
8107                                  Output: foo_1.ctid, foo_1.f1, foo_1.*, foo_1.tableoid
8108                            ->  Foreign Scan on public.foo2 foo_2
8109                                  Output: foo_2.ctid, foo_2.f1, foo_2.*, foo_2.tableoid
8110                                  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
8111 (23 rows)
8113 select * from bar where f1 in (select f1 from foo) for update;
8114  f1 | f2 
8115 ----+----
8116   1 | 11
8117   2 | 22
8118   3 | 33
8119   4 | 44
8120 (4 rows)
8122 explain (verbose, costs off)
8123 select * from bar where f1 in (select f1 from foo) for share;
8124                                           QUERY PLAN                                          
8125 ----------------------------------------------------------------------------------------------
8126  LockRows
8127    Output: bar.f1, bar.f2, bar.ctid, foo.ctid, bar.*, bar.tableoid, foo.*, foo.tableoid
8128    ->  Hash Join
8129          Output: bar.f1, bar.f2, bar.ctid, foo.ctid, bar.*, bar.tableoid, foo.*, foo.tableoid
8130          Inner Unique: true
8131          Hash Cond: (bar.f1 = foo.f1)
8132          ->  Append
8133                ->  Seq Scan on public.bar bar_1
8134                      Output: bar_1.f1, bar_1.f2, bar_1.ctid, bar_1.*, bar_1.tableoid
8135                ->  Foreign Scan on public.bar2 bar_2
8136                      Output: bar_2.f1, bar_2.f2, bar_2.ctid, bar_2.*, bar_2.tableoid
8137                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR SHARE
8138          ->  Hash
8139                Output: foo.ctid, foo.f1, foo.*, foo.tableoid
8140                ->  HashAggregate
8141                      Output: foo.ctid, foo.f1, foo.*, foo.tableoid
8142                      Group Key: foo.f1
8143                      ->  Append
8144                            ->  Seq Scan on public.foo foo_1
8145                                  Output: foo_1.ctid, foo_1.f1, foo_1.*, foo_1.tableoid
8146                            ->  Foreign Scan on public.foo2 foo_2
8147                                  Output: foo_2.ctid, foo_2.f1, foo_2.*, foo_2.tableoid
8148                                  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
8149 (23 rows)
8151 select * from bar where f1 in (select f1 from foo) for share;
8152  f1 | f2 
8153 ----+----
8154   1 | 11
8155   2 | 22
8156   3 | 33
8157   4 | 44
8158 (4 rows)
8160 -- Now check SELECT FOR UPDATE/SHARE with an inherited source table,
8161 -- where the parent is itself a foreign table
8162 create table loct4 (f1 int, f2 int, f3 int);
8163 create foreign table foo2child (f3 int) inherits (foo2)
8164   server loopback options (table_name 'loct4');
8165 NOTICE:  moving and merging column "f3" with inherited definition
8166 DETAIL:  User-specified column moved to the position of the inherited column.
8167 explain (verbose, costs off)
8168 select * from bar where f1 in (select f1 from foo2) for share;
8169                                       QUERY PLAN                                      
8170 --------------------------------------------------------------------------------------
8171  LockRows
8172    Output: bar.f1, bar.f2, bar.ctid, foo2.*, bar.*, bar.tableoid, foo2.tableoid
8173    ->  Hash Join
8174          Output: bar.f1, bar.f2, bar.ctid, foo2.*, bar.*, bar.tableoid, foo2.tableoid
8175          Inner Unique: true
8176          Hash Cond: (bar.f1 = foo2.f1)
8177          ->  Append
8178                ->  Seq Scan on public.bar bar_1
8179                      Output: bar_1.f1, bar_1.f2, bar_1.ctid, bar_1.*, bar_1.tableoid
8180                ->  Foreign Scan on public.bar2 bar_2
8181                      Output: bar_2.f1, bar_2.f2, bar_2.ctid, bar_2.*, bar_2.tableoid
8182                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR SHARE
8183          ->  Hash
8184                Output: foo2.*, foo2.f1, foo2.tableoid
8185                ->  HashAggregate
8186                      Output: foo2.*, foo2.f1, foo2.tableoid
8187                      Group Key: foo2.f1
8188                      ->  Append
8189                            ->  Foreign Scan on public.foo2 foo2_1
8190                                  Output: foo2_1.*, foo2_1.f1, foo2_1.tableoid
8191                                  Remote SQL: SELECT f1, f2, f3 FROM public.loct1
8192                            ->  Foreign Scan on public.foo2child foo2_2
8193                                  Output: foo2_2.*, foo2_2.f1, foo2_2.tableoid
8194                                  Remote SQL: SELECT f1, f2, f3 FROM public.loct4
8195 (24 rows)
8197 select * from bar where f1 in (select f1 from foo2) for share;
8198  f1 | f2 
8199 ----+----
8200   2 | 22
8201   4 | 44
8202 (2 rows)
8204 drop foreign table foo2child;
8205 -- And with a local child relation of the foreign table parent
8206 create table foo2child (f3 int) inherits (foo2);
8207 NOTICE:  moving and merging column "f3" with inherited definition
8208 DETAIL:  User-specified column moved to the position of the inherited column.
8209 explain (verbose, costs off)
8210 select * from bar where f1 in (select f1 from foo2) for share;
8211                                            QUERY PLAN                                            
8212 -------------------------------------------------------------------------------------------------
8213  LockRows
8214    Output: bar.f1, bar.f2, bar.ctid, foo2.*, bar.*, bar.tableoid, foo2.ctid, foo2.tableoid
8215    ->  Hash Join
8216          Output: bar.f1, bar.f2, bar.ctid, foo2.*, bar.*, bar.tableoid, foo2.ctid, foo2.tableoid
8217          Inner Unique: true
8218          Hash Cond: (bar.f1 = foo2.f1)
8219          ->  Append
8220                ->  Seq Scan on public.bar bar_1
8221                      Output: bar_1.f1, bar_1.f2, bar_1.ctid, bar_1.*, bar_1.tableoid
8222                ->  Foreign Scan on public.bar2 bar_2
8223                      Output: bar_2.f1, bar_2.f2, bar_2.ctid, bar_2.*, bar_2.tableoid
8224                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR SHARE
8225          ->  Hash
8226                Output: foo2.*, foo2.f1, foo2.ctid, foo2.tableoid
8227                ->  HashAggregate
8228                      Output: foo2.*, foo2.f1, foo2.ctid, foo2.tableoid
8229                      Group Key: foo2.f1
8230                      ->  Append
8231                            ->  Foreign Scan on public.foo2 foo2_1
8232                                  Output: foo2_1.*, foo2_1.f1, foo2_1.ctid, foo2_1.tableoid
8233                                  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
8234                            ->  Seq Scan on public.foo2child foo2_2
8235                                  Output: foo2_2.*, foo2_2.f1, foo2_2.ctid, foo2_2.tableoid
8236 (23 rows)
8238 select * from bar where f1 in (select f1 from foo2) for share;
8239  f1 | f2 
8240 ----+----
8241   2 | 22
8242   4 | 44
8243 (2 rows)
8245 drop table foo2child;
8246 -- Check UPDATE with inherited target and an inherited source table
8247 explain (verbose, costs off)
8248 update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
8249                                               QUERY PLAN                                               
8250 -------------------------------------------------------------------------------------------------------
8251  Update on public.bar
8252    Update on public.bar bar_1
8253    Foreign Update on public.bar2 bar_2
8254      Remote SQL: UPDATE public.loct2 SET f2 = $2 WHERE ctid = $1
8255    ->  Hash Join
8256          Output: (bar.f2 + 100), foo.ctid, bar.tableoid, bar.ctid, (NULL::record), foo.*, foo.tableoid
8257          Inner Unique: true
8258          Hash Cond: (bar.f1 = foo.f1)
8259          ->  Append
8260                ->  Seq Scan on public.bar bar_1
8261                      Output: bar_1.f2, bar_1.f1, bar_1.tableoid, bar_1.ctid, NULL::record
8262                ->  Foreign Scan on public.bar2 bar_2
8263                      Output: bar_2.f2, bar_2.f1, bar_2.tableoid, bar_2.ctid, bar_2.*
8264                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
8265          ->  Hash
8266                Output: foo.ctid, foo.f1, foo.*, foo.tableoid
8267                ->  HashAggregate
8268                      Output: foo.ctid, foo.f1, foo.*, foo.tableoid
8269                      Group Key: foo.f1
8270                      ->  Append
8271                            ->  Seq Scan on public.foo foo_1
8272                                  Output: foo_1.ctid, foo_1.f1, foo_1.*, foo_1.tableoid
8273                            ->  Foreign Scan on public.foo2 foo_2
8274                                  Output: foo_2.ctid, foo_2.f1, foo_2.*, foo_2.tableoid
8275                                  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
8276 (25 rows)
8278 update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
8279 select tableoid::regclass, * from bar order by 1,2;
8280  tableoid | f1 | f2  
8281 ----------+----+-----
8282  bar      |  1 | 111
8283  bar      |  2 | 122
8284  bar      |  6 |  66
8285  bar2     |  3 | 133
8286  bar2     |  4 | 144
8287  bar2     |  7 |  77
8288 (6 rows)
8290 -- Check UPDATE with inherited target and an appendrel subquery
8291 explain (verbose, costs off)
8292 update bar set f2 = f2 + 100
8293 from
8294   ( select f1 from foo union all select f1+3 from foo ) ss
8295 where bar.f1 = ss.f1;
8296                                            QUERY PLAN                                           
8297 ------------------------------------------------------------------------------------------------
8298  Update on public.bar
8299    Update on public.bar bar_1
8300    Foreign Update on public.bar2 bar_2
8301      Remote SQL: UPDATE public.loct2 SET f2 = $2 WHERE ctid = $1
8302    ->  Merge Join
8303          Output: (bar.f2 + 100), (ROW(foo.f1)), bar.tableoid, bar.ctid, (NULL::record)
8304          Merge Cond: (bar.f1 = foo.f1)
8305          ->  Sort
8306                Output: bar.f2, bar.f1, bar.tableoid, bar.ctid, (NULL::record)
8307                Sort Key: bar.f1
8308                ->  Append
8309                      ->  Seq Scan on public.bar bar_1
8310                            Output: bar_1.f2, bar_1.f1, bar_1.tableoid, bar_1.ctid, NULL::record
8311                      ->  Foreign Scan on public.bar2 bar_2
8312                            Output: bar_2.f2, bar_2.f1, bar_2.tableoid, bar_2.ctid, bar_2.*
8313                            Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
8314          ->  Sort
8315                Output: (ROW(foo.f1)), foo.f1
8316                Sort Key: foo.f1
8317                ->  Append
8318                      ->  Seq Scan on public.foo
8319                            Output: ROW(foo.f1), foo.f1
8320                      ->  Foreign Scan on public.foo2 foo_1
8321                            Output: ROW(foo_1.f1), foo_1.f1
8322                            Remote SQL: SELECT f1 FROM public.loct1
8323                      ->  Seq Scan on public.foo foo_2
8324                            Output: ROW((foo_2.f1 + 3)), (foo_2.f1 + 3)
8325                      ->  Foreign Scan on public.foo2 foo_3
8326                            Output: ROW((foo_3.f1 + 3)), (foo_3.f1 + 3)
8327                            Remote SQL: SELECT f1 FROM public.loct1
8328 (30 rows)
8330 update bar set f2 = f2 + 100
8331 from
8332   ( select f1 from foo union all select f1+3 from foo ) ss
8333 where bar.f1 = ss.f1;
8334 select tableoid::regclass, * from bar order by 1,2;
8335  tableoid | f1 | f2  
8336 ----------+----+-----
8337  bar      |  1 | 211
8338  bar      |  2 | 222
8339  bar      |  6 | 166
8340  bar2     |  3 | 233
8341  bar2     |  4 | 244
8342  bar2     |  7 | 177
8343 (6 rows)
8345 -- Test forcing the remote server to produce sorted data for a merge join,
8346 -- but the foreign table is an inheritance child.
8347 truncate table loct1;
8348 truncate table only foo;
8349 \set num_rows_foo 2000
8350 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);
8351 insert into foo select generate_series(1, :num_rows_foo, 2), generate_series(1, :num_rows_foo, 2);
8352 SET enable_hashjoin to false;
8353 SET enable_nestloop to false;
8354 alter foreign table foo2 options (use_remote_estimate 'true');
8355 create index i_loct1_f1 on loct1(f1);
8356 create index i_foo_f1 on foo(f1);
8357 analyze foo;
8358 analyze loct1;
8359 -- inner join; expressions in the clauses appear in the equivalence class list
8360 explain (verbose, costs off)
8361         select foo.f1, loct1.f1 from foo join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
8362                                             QUERY PLAN                                            
8363 --------------------------------------------------------------------------------------------------
8364  Limit
8365    Output: foo.f1, loct1.f1, foo.f2
8366    ->  Sort
8367          Output: foo.f1, loct1.f1, foo.f2
8368          Sort Key: foo.f2
8369          ->  Merge Join
8370                Output: foo.f1, loct1.f1, foo.f2
8371                Merge Cond: (foo.f1 = loct1.f1)
8372                ->  Merge Append
8373                      Sort Key: foo.f1
8374                      ->  Index Scan using i_foo_f1 on public.foo foo_1
8375                            Output: foo_1.f1, foo_1.f2
8376                      ->  Foreign Scan on public.foo2 foo_2
8377                            Output: foo_2.f1, foo_2.f2
8378                            Remote SQL: SELECT f1, f2 FROM public.loct1 ORDER BY f1 ASC NULLS LAST
8379                ->  Index Only Scan using i_loct1_f1 on public.loct1
8380                      Output: loct1.f1
8381 (17 rows)
8383 select foo.f1, loct1.f1 from foo join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
8384  f1 | f1 
8385 ----+----
8386  20 | 20
8387  22 | 22
8388  24 | 24
8389  26 | 26
8390  28 | 28
8391  30 | 30
8392  32 | 32
8393  34 | 34
8394  36 | 36
8395  38 | 38
8396 (10 rows)
8398 -- outer join; expressions in the clauses do not appear in equivalence class
8399 -- list but no output change as compared to the previous query
8400 explain (verbose, costs off)
8401         select foo.f1, loct1.f1 from foo left join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
8402                                             QUERY PLAN                                            
8403 --------------------------------------------------------------------------------------------------
8404  Limit
8405    Output: foo.f1, loct1.f1, foo.f2
8406    ->  Sort
8407          Output: foo.f1, loct1.f1, foo.f2
8408          Sort Key: foo.f2
8409          ->  Merge Left Join
8410                Output: foo.f1, loct1.f1, foo.f2
8411                Merge Cond: (foo.f1 = loct1.f1)
8412                ->  Merge Append
8413                      Sort Key: foo.f1
8414                      ->  Index Scan using i_foo_f1 on public.foo foo_1
8415                            Output: foo_1.f1, foo_1.f2
8416                      ->  Foreign Scan on public.foo2 foo_2
8417                            Output: foo_2.f1, foo_2.f2
8418                            Remote SQL: SELECT f1, f2 FROM public.loct1 ORDER BY f1 ASC NULLS LAST
8419                ->  Index Only Scan using i_loct1_f1 on public.loct1
8420                      Output: loct1.f1
8421 (17 rows)
8423 select foo.f1, loct1.f1 from foo left join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
8424  f1 | f1 
8425 ----+----
8426  10 | 10
8427  11 |   
8428  12 | 12
8429  13 |   
8430  14 | 14
8431  15 |   
8432  16 | 16
8433  17 |   
8434  18 | 18
8435  19 |   
8436 (10 rows)
8438 RESET enable_hashjoin;
8439 RESET enable_nestloop;
8440 -- Test that WHERE CURRENT OF is not supported
8441 begin;
8442 declare c cursor for select * from bar where f1 = 7;
8443 fetch from c;
8444  f1 | f2  
8445 ----+-----
8446   7 | 177
8447 (1 row)
8449 update bar set f2 = null where current of c;
8450 ERROR:  WHERE CURRENT OF is not supported for this table type
8451 rollback;
8452 explain (verbose, costs off)
8453 delete from foo where f1 < 5 returning *;
8454                                       QUERY PLAN                                      
8455 --------------------------------------------------------------------------------------
8456  Delete on public.foo
8457    Output: foo_1.f1, foo_1.f2
8458    Delete on public.foo foo_1
8459    Foreign Delete on public.foo2 foo_2
8460    ->  Append
8461          ->  Index Scan using i_foo_f1 on public.foo foo_1
8462                Output: foo_1.tableoid, foo_1.ctid
8463                Index Cond: (foo_1.f1 < 5)
8464          ->  Foreign Delete on public.foo2 foo_2
8465                Remote SQL: DELETE FROM public.loct1 WHERE ((f1 < 5)) RETURNING f1, f2
8466 (10 rows)
8468 delete from foo where f1 < 5 returning *;
8469  f1 | f2 
8470 ----+----
8471   1 |  1
8472   3 |  3
8473   0 |  0
8474   2 |  2
8475   4 |  4
8476 (5 rows)
8478 explain (verbose, costs off)
8479 update bar set f2 = f2 + 100 returning *;
8480                                         QUERY PLAN                                        
8481 ------------------------------------------------------------------------------------------
8482  Update on public.bar
8483    Output: bar_1.f1, bar_1.f2
8484    Update on public.bar bar_1
8485    Foreign Update on public.bar2 bar_2
8486    ->  Result
8487          Output: (bar.f2 + 100), bar.tableoid, bar.ctid, (NULL::record)
8488          ->  Append
8489                ->  Seq Scan on public.bar bar_1
8490                      Output: bar_1.f2, bar_1.tableoid, bar_1.ctid, NULL::record
8491                ->  Foreign Update on public.bar2 bar_2
8492                      Remote SQL: UPDATE public.loct2 SET f2 = (f2 + 100) RETURNING f1, f2
8493 (11 rows)
8495 update bar set f2 = f2 + 100 returning *;
8496  f1 | f2  
8497 ----+-----
8498   1 | 311
8499   2 | 322
8500   6 | 266
8501   3 | 333
8502   4 | 344
8503   7 | 277
8504 (6 rows)
8506 -- Test that UPDATE/DELETE with inherited target works with row-level triggers
8507 CREATE TRIGGER trig_row_before
8508 BEFORE UPDATE OR DELETE ON bar2
8509 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
8510 CREATE TRIGGER trig_row_after
8511 AFTER UPDATE OR DELETE ON bar2
8512 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
8513 explain (verbose, costs off)
8514 update bar set f2 = f2 + 100;
8515                                                QUERY PLAN                                               
8516 --------------------------------------------------------------------------------------------------------
8517  Update on public.bar
8518    Update on public.bar bar_1
8519    Foreign Update on public.bar2 bar_2
8520      Remote SQL: UPDATE public.loct2 SET f1 = $2, f2 = $3, f3 = $4 WHERE ctid = $1 RETURNING f1, f2, f3
8521    ->  Result
8522          Output: (bar.f2 + 100), bar.tableoid, bar.ctid, (NULL::record)
8523          ->  Append
8524                ->  Seq Scan on public.bar bar_1
8525                      Output: bar_1.f2, bar_1.tableoid, bar_1.ctid, NULL::record
8526                ->  Foreign Scan on public.bar2 bar_2
8527                      Output: bar_2.f2, bar_2.tableoid, bar_2.ctid, bar_2.*
8528                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
8529 (12 rows)
8531 update bar set f2 = f2 + 100;
8532 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
8533 NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
8534 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
8535 NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
8536 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
8537 NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
8538 NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
8539 NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
8540 NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
8541 NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
8542 NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
8543 NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
8544 explain (verbose, costs off)
8545 delete from bar where f2 < 400;
8546                                             QUERY PLAN                                             
8547 ---------------------------------------------------------------------------------------------------
8548  Delete on public.bar
8549    Delete on public.bar bar_1
8550    Foreign Delete on public.bar2 bar_2
8551      Remote SQL: DELETE FROM public.loct2 WHERE ctid = $1 RETURNING f1, f2, f3
8552    ->  Append
8553          ->  Seq Scan on public.bar bar_1
8554                Output: bar_1.tableoid, bar_1.ctid, NULL::record
8555                Filter: (bar_1.f2 < 400)
8556          ->  Foreign Scan on public.bar2 bar_2
8557                Output: bar_2.tableoid, bar_2.ctid, bar_2.*
8558                Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 WHERE ((f2 < 400)) FOR UPDATE
8559 (11 rows)
8561 delete from bar where f2 < 400;
8562 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW DELETE ON bar2
8563 NOTICE:  OLD: (7,377,77)
8564 NOTICE:  trig_row_after(23, skidoo) AFTER ROW DELETE ON bar2
8565 NOTICE:  OLD: (7,377,77)
8566 -- cleanup
8567 drop table foo cascade;
8568 NOTICE:  drop cascades to foreign table foo2
8569 drop table bar cascade;
8570 NOTICE:  drop cascades to foreign table bar2
8571 drop table loct1;
8572 drop table loct2;
8573 -- Test pushing down UPDATE/DELETE joins to the remote server
8574 create table parent (a int, b text);
8575 create table loct1 (a int, b text);
8576 create table loct2 (a int, b text);
8577 create foreign table remt1 (a int, b text)
8578   server loopback options (table_name 'loct1');
8579 create foreign table remt2 (a int, b text)
8580   server loopback options (table_name 'loct2');
8581 alter foreign table remt1 inherit parent;
8582 insert into remt1 values (1, 'foo');
8583 insert into remt1 values (2, 'bar');
8584 insert into remt2 values (1, 'foo');
8585 insert into remt2 values (2, 'bar');
8586 analyze remt1;
8587 analyze remt2;
8588 explain (verbose, costs off)
8589 update parent set b = parent.b || remt2.b from remt2 where parent.a = remt2.a returning *;
8590                                                    QUERY PLAN                                                   
8591 ----------------------------------------------------------------------------------------------------------------
8592  Update on public.parent
8593    Output: parent_1.a, parent_1.b, remt2.a, remt2.b
8594    Update on public.parent parent_1
8595    Foreign Update on public.remt1 parent_2
8596      Remote SQL: UPDATE public.loct1 SET b = $2 WHERE ctid = $1 RETURNING a, b
8597    ->  Nested Loop
8598          Output: (parent.b || remt2.b), remt2.*, remt2.a, remt2.b, parent.tableoid, parent.ctid, (NULL::record)
8599          Join Filter: (parent.a = remt2.a)
8600          ->  Append
8601                ->  Seq Scan on public.parent parent_1
8602                      Output: parent_1.b, parent_1.a, parent_1.tableoid, parent_1.ctid, NULL::record
8603                ->  Foreign Scan on public.remt1 parent_2
8604                      Output: parent_2.b, parent_2.a, parent_2.tableoid, parent_2.ctid, parent_2.*
8605                      Remote SQL: SELECT a, b, ctid FROM public.loct1 FOR UPDATE
8606          ->  Materialize
8607                Output: remt2.b, remt2.*, remt2.a
8608                ->  Foreign Scan on public.remt2
8609                      Output: remt2.b, remt2.*, remt2.a
8610                      Remote SQL: SELECT a, b FROM public.loct2
8611 (19 rows)
8613 update parent set b = parent.b || remt2.b from remt2 where parent.a = remt2.a returning *;
8614  a |   b    | a |  b  
8615 ---+--------+---+-----
8616  1 | foofoo | 1 | foo
8617  2 | barbar | 2 | bar
8618 (2 rows)
8620 explain (verbose, costs off)
8621 delete from parent using remt2 where parent.a = remt2.a returning parent;
8622                                  QUERY PLAN                                  
8623 -----------------------------------------------------------------------------
8624  Delete on public.parent
8625    Output: parent_1.*
8626    Delete on public.parent parent_1
8627    Foreign Delete on public.remt1 parent_2
8628      Remote SQL: DELETE FROM public.loct1 WHERE ctid = $1 RETURNING a, b
8629    ->  Nested Loop
8630          Output: remt2.*, parent.tableoid, parent.ctid
8631          Join Filter: (parent.a = remt2.a)
8632          ->  Append
8633                ->  Seq Scan on public.parent parent_1
8634                      Output: parent_1.a, parent_1.tableoid, parent_1.ctid
8635                ->  Foreign Scan on public.remt1 parent_2
8636                      Output: parent_2.a, parent_2.tableoid, parent_2.ctid
8637                      Remote SQL: SELECT a, ctid FROM public.loct1 FOR UPDATE
8638          ->  Materialize
8639                Output: remt2.*, remt2.a
8640                ->  Foreign Scan on public.remt2
8641                      Output: remt2.*, remt2.a
8642                      Remote SQL: SELECT a, b FROM public.loct2
8643 (19 rows)
8645 delete from parent using remt2 where parent.a = remt2.a returning parent;
8646    parent   
8647 ------------
8648  (1,foofoo)
8649  (2,barbar)
8650 (2 rows)
8652 -- cleanup
8653 drop foreign table remt1;
8654 drop foreign table remt2;
8655 drop table loct1;
8656 drop table loct2;
8657 drop table parent;
8658 -- ===================================================================
8659 -- test tuple routing for foreign-table partitions
8660 -- ===================================================================
8661 -- Test insert tuple routing
8662 create table itrtest (a int, b text) partition by list (a);
8663 create table loct1 (a int check (a in (1)), b text);
8664 create foreign table remp1 (a int check (a in (1)), b text) server loopback options (table_name 'loct1');
8665 create table loct2 (a int check (a in (2)), b text);
8666 create foreign table remp2 (b text, a int check (a in (2))) server loopback options (table_name 'loct2');
8667 alter table itrtest attach partition remp1 for values in (1);
8668 alter table itrtest attach partition remp2 for values in (2);
8669 insert into itrtest values (1, 'foo');
8670 insert into itrtest values (1, 'bar') returning *;
8671  a |  b  
8672 ---+-----
8673  1 | bar
8674 (1 row)
8676 insert into itrtest values (2, 'baz');
8677 insert into itrtest values (2, 'qux') returning *;
8678  a |  b  
8679 ---+-----
8680  2 | qux
8681 (1 row)
8683 insert into itrtest values (1, 'test1'), (2, 'test2') returning *;
8684  a |   b   
8685 ---+-------
8686  1 | test1
8687  2 | test2
8688 (2 rows)
8690 select tableoid::regclass, * FROM itrtest;
8691  tableoid | a |   b   
8692 ----------+---+-------
8693  remp1    | 1 | foo
8694  remp1    | 1 | bar
8695  remp1    | 1 | test1
8696  remp2    | 2 | baz
8697  remp2    | 2 | qux
8698  remp2    | 2 | test2
8699 (6 rows)
8701 select tableoid::regclass, * FROM remp1;
8702  tableoid | a |   b   
8703 ----------+---+-------
8704  remp1    | 1 | foo
8705  remp1    | 1 | bar
8706  remp1    | 1 | test1
8707 (3 rows)
8709 select tableoid::regclass, * FROM remp2;
8710  tableoid |   b   | a 
8711 ----------+-------+---
8712  remp2    | baz   | 2
8713  remp2    | qux   | 2
8714  remp2    | test2 | 2
8715 (3 rows)
8717 delete from itrtest;
8718 -- MERGE ought to fail cleanly
8719 merge into itrtest using (select 1, 'foo') as source on (true)
8720   when matched then do nothing;
8721 ERROR:  cannot execute MERGE on relation "remp1"
8722 DETAIL:  This operation is not supported for foreign tables.
8723 create unique index loct1_idx on loct1 (a);
8724 -- DO NOTHING without an inference specification is supported
8725 insert into itrtest values (1, 'foo') on conflict do nothing returning *;
8726  a |  b  
8727 ---+-----
8728  1 | foo
8729 (1 row)
8731 insert into itrtest values (1, 'foo') on conflict do nothing returning *;
8732  a | b 
8733 ---+---
8734 (0 rows)
8736 -- But other cases are not supported
8737 insert into itrtest values (1, 'bar') on conflict (a) do nothing;
8738 ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification
8739 insert into itrtest values (1, 'bar') on conflict (a) do update set b = excluded.b;
8740 ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification
8741 select tableoid::regclass, * FROM itrtest;
8742  tableoid | a |  b  
8743 ----------+---+-----
8744  remp1    | 1 | foo
8745 (1 row)
8747 delete from itrtest;
8748 drop index loct1_idx;
8749 -- Test that remote triggers work with insert tuple routing
8750 create function br_insert_trigfunc() returns trigger as $$
8751 begin
8752         new.b := new.b || ' triggered !';
8753         return new;
8755 $$ language plpgsql;
8756 create trigger loct1_br_insert_trigger before insert on loct1
8757         for each row execute procedure br_insert_trigfunc();
8758 create trigger loct2_br_insert_trigger before insert on loct2
8759         for each row execute procedure br_insert_trigfunc();
8760 -- The new values are concatenated with ' triggered !'
8761 insert into itrtest values (1, 'foo') returning *;
8762  a |        b        
8763 ---+-----------------
8764  1 | foo triggered !
8765 (1 row)
8767 insert into itrtest values (2, 'qux') returning *;
8768  a |        b        
8769 ---+-----------------
8770  2 | qux triggered !
8771 (1 row)
8773 insert into itrtest values (1, 'test1'), (2, 'test2') returning *;
8774  a |         b         
8775 ---+-------------------
8776  1 | test1 triggered !
8777  2 | test2 triggered !
8778 (2 rows)
8780 with result as (insert into itrtest values (1, 'test1'), (2, 'test2') returning *) select * from result;
8781  a |         b         
8782 ---+-------------------
8783  1 | test1 triggered !
8784  2 | test2 triggered !
8785 (2 rows)
8787 drop trigger loct1_br_insert_trigger on loct1;
8788 drop trigger loct2_br_insert_trigger on loct2;
8789 drop table itrtest;
8790 drop table loct1;
8791 drop table loct2;
8792 -- Test update tuple routing
8793 create table utrtest (a int, b text) partition by list (a);
8794 create table loct (a int check (a in (1)), b text);
8795 create foreign table remp (a int check (a in (1)), b text) server loopback options (table_name 'loct');
8796 create table locp (a int check (a in (2)), b text);
8797 alter table utrtest attach partition remp for values in (1);
8798 alter table utrtest attach partition locp for values in (2);
8799 insert into utrtest values (1, 'foo');
8800 insert into utrtest values (2, 'qux');
8801 select tableoid::regclass, * FROM utrtest;
8802  tableoid | a |  b  
8803 ----------+---+-----
8804  remp     | 1 | foo
8805  locp     | 2 | qux
8806 (2 rows)
8808 select tableoid::regclass, * FROM remp;
8809  tableoid | a |  b  
8810 ----------+---+-----
8811  remp     | 1 | foo
8812 (1 row)
8814 select tableoid::regclass, * FROM locp;
8815  tableoid | a |  b  
8816 ----------+---+-----
8817  locp     | 2 | qux
8818 (1 row)
8820 -- It's not allowed to move a row from a partition that is foreign to another
8821 update utrtest set a = 2 where b = 'foo' returning *;
8822 ERROR:  new row for relation "loct" violates check constraint "loct_a_check"
8823 DETAIL:  Failing row contains (2, foo).
8824 CONTEXT:  remote SQL command: UPDATE public.loct SET a = 2 WHERE ((b = 'foo')) RETURNING a, b
8825 -- But the reverse is allowed
8826 update utrtest set a = 1 where b = 'qux' returning *;
8827 ERROR:  cannot route tuples into foreign table to be updated "remp"
8828 select tableoid::regclass, * FROM utrtest;
8829  tableoid | a |  b  
8830 ----------+---+-----
8831  remp     | 1 | foo
8832  locp     | 2 | qux
8833 (2 rows)
8835 select tableoid::regclass, * FROM remp;
8836  tableoid | a |  b  
8837 ----------+---+-----
8838  remp     | 1 | foo
8839 (1 row)
8841 select tableoid::regclass, * FROM locp;
8842  tableoid | a |  b  
8843 ----------+---+-----
8844  locp     | 2 | qux
8845 (1 row)
8847 -- The executor should not let unexercised FDWs shut down
8848 update utrtest set a = 1 where b = 'foo';
8849 -- Test that remote triggers work with update tuple routing
8850 create trigger loct_br_insert_trigger before insert on loct
8851         for each row execute procedure br_insert_trigfunc();
8852 delete from utrtest;
8853 insert into utrtest values (2, 'qux');
8854 -- Check case where the foreign partition is a subplan target rel
8855 explain (verbose, costs off)
8856 update utrtest set a = 1 where a = 1 or a = 2 returning *;
8857                                              QUERY PLAN                                             
8858 ----------------------------------------------------------------------------------------------------
8859  Update on public.utrtest
8860    Output: utrtest_1.a, utrtest_1.b
8861    Foreign Update on public.remp utrtest_1
8862    Update on public.locp utrtest_2
8863    ->  Append
8864          ->  Foreign Update on public.remp utrtest_1
8865                Remote SQL: UPDATE public.loct SET a = 1 WHERE (((a = 1) OR (a = 2))) RETURNING a, b
8866          ->  Seq Scan on public.locp utrtest_2
8867                Output: 1, utrtest_2.tableoid, utrtest_2.ctid, NULL::record
8868                Filter: ((utrtest_2.a = 1) OR (utrtest_2.a = 2))
8869 (10 rows)
8871 -- The new values are concatenated with ' triggered !'
8872 update utrtest set a = 1 where a = 1 or a = 2 returning *;
8873 ERROR:  cannot route tuples into foreign table to be updated "remp"
8874 delete from utrtest;
8875 insert into utrtest values (2, 'qux');
8876 -- Check case where the foreign partition isn't a subplan target rel
8877 explain (verbose, costs off)
8878 update utrtest set a = 1 where a = 2 returning *;
8879                       QUERY PLAN                       
8880 -------------------------------------------------------
8881  Update on public.utrtest
8882    Output: utrtest_1.a, utrtest_1.b
8883    Update on public.locp utrtest_1
8884    ->  Seq Scan on public.locp utrtest_1
8885          Output: 1, utrtest_1.tableoid, utrtest_1.ctid
8886          Filter: (utrtest_1.a = 2)
8887 (6 rows)
8889 -- The new values are concatenated with ' triggered !'
8890 update utrtest set a = 1 where a = 2 returning *;
8891  a |        b        
8892 ---+-----------------
8893  1 | qux triggered !
8894 (1 row)
8896 drop trigger loct_br_insert_trigger on loct;
8897 -- We can move rows to a foreign partition that has been updated already,
8898 -- but can't move rows to a foreign partition that hasn't been updated yet
8899 delete from utrtest;
8900 insert into utrtest values (1, 'foo');
8901 insert into utrtest values (2, 'qux');
8902 -- Test the former case:
8903 -- with a direct modification plan
8904 explain (verbose, costs off)
8905 update utrtest set a = 1 returning *;
8906                                 QUERY PLAN                                 
8907 ---------------------------------------------------------------------------
8908  Update on public.utrtest
8909    Output: utrtest_1.a, utrtest_1.b
8910    Foreign Update on public.remp utrtest_1
8911    Update on public.locp utrtest_2
8912    ->  Append
8913          ->  Foreign Update on public.remp utrtest_1
8914                Remote SQL: UPDATE public.loct SET a = 1 RETURNING a, b
8915          ->  Seq Scan on public.locp utrtest_2
8916                Output: 1, utrtest_2.tableoid, utrtest_2.ctid, NULL::record
8917 (9 rows)
8919 update utrtest set a = 1 returning *;
8920 ERROR:  cannot route tuples into foreign table to be updated "remp"
8921 delete from utrtest;
8922 insert into utrtest values (1, 'foo');
8923 insert into utrtest values (2, 'qux');
8924 -- with a non-direct modification plan
8925 explain (verbose, costs off)
8926 update utrtest set a = 1 from (values (1), (2)) s(x) where a = s.x returning *;
8927                                            QUERY PLAN                                           
8928 ------------------------------------------------------------------------------------------------
8929  Update on public.utrtest
8930    Output: utrtest_1.a, utrtest_1.b, "*VALUES*".column1
8931    Foreign Update on public.remp utrtest_1
8932      Remote SQL: UPDATE public.loct SET a = $2 WHERE ctid = $1 RETURNING a, b
8933    Update on public.locp utrtest_2
8934    ->  Hash Join
8935          Output: 1, "*VALUES*".*, "*VALUES*".column1, utrtest.tableoid, utrtest.ctid, utrtest.*
8936          Hash Cond: (utrtest.a = "*VALUES*".column1)
8937          ->  Append
8938                ->  Foreign Scan on public.remp utrtest_1
8939                      Output: utrtest_1.a, utrtest_1.tableoid, utrtest_1.ctid, utrtest_1.*
8940                      Remote SQL: SELECT a, b, ctid FROM public.loct FOR UPDATE
8941                ->  Seq Scan on public.locp utrtest_2
8942                      Output: utrtest_2.a, utrtest_2.tableoid, utrtest_2.ctid, NULL::record
8943          ->  Hash
8944                Output: "*VALUES*".*, "*VALUES*".column1
8945                ->  Values Scan on "*VALUES*"
8946                      Output: "*VALUES*".*, "*VALUES*".column1
8947 (18 rows)
8949 update utrtest set a = 1 from (values (1), (2)) s(x) where a = s.x returning *;
8950 ERROR:  cannot route tuples into foreign table to be updated "remp"
8951 -- Change the definition of utrtest so that the foreign partition get updated
8952 -- after the local partition
8953 delete from utrtest;
8954 alter table utrtest detach partition remp;
8955 drop foreign table remp;
8956 alter table loct drop constraint loct_a_check;
8957 alter table loct add check (a in (3));
8958 create foreign table remp (a int check (a in (3)), b text) server loopback options (table_name 'loct');
8959 alter table utrtest attach partition remp for values in (3);
8960 insert into utrtest values (2, 'qux');
8961 insert into utrtest values (3, 'xyzzy');
8962 -- Test the latter case:
8963 -- with a direct modification plan
8964 explain (verbose, costs off)
8965 update utrtest set a = 3 returning *;
8966                                 QUERY PLAN                                 
8967 ---------------------------------------------------------------------------
8968  Update on public.utrtest
8969    Output: utrtest_1.a, utrtest_1.b
8970    Update on public.locp utrtest_1
8971    Foreign Update on public.remp utrtest_2
8972    ->  Append
8973          ->  Seq Scan on public.locp utrtest_1
8974                Output: 3, utrtest_1.tableoid, utrtest_1.ctid, NULL::record
8975          ->  Foreign Update on public.remp utrtest_2
8976                Remote SQL: UPDATE public.loct SET a = 3 RETURNING a, b
8977 (9 rows)
8979 update utrtest set a = 3 returning *; -- ERROR
8980 ERROR:  cannot route tuples into foreign table to be updated "remp"
8981 -- with a non-direct modification plan
8982 explain (verbose, costs off)
8983 update utrtest set a = 3 from (values (2), (3)) s(x) where a = s.x returning *;
8984                                              QUERY PLAN                                              
8985 -----------------------------------------------------------------------------------------------------
8986  Update on public.utrtest
8987    Output: utrtest_1.a, utrtest_1.b, "*VALUES*".column1
8988    Update on public.locp utrtest_1
8989    Foreign Update on public.remp utrtest_2
8990      Remote SQL: UPDATE public.loct SET a = $2 WHERE ctid = $1 RETURNING a, b
8991    ->  Hash Join
8992          Output: 3, "*VALUES*".*, "*VALUES*".column1, utrtest.tableoid, utrtest.ctid, (NULL::record)
8993          Hash Cond: (utrtest.a = "*VALUES*".column1)
8994          ->  Append
8995                ->  Seq Scan on public.locp utrtest_1
8996                      Output: utrtest_1.a, utrtest_1.tableoid, utrtest_1.ctid, NULL::record
8997                ->  Foreign Scan on public.remp utrtest_2
8998                      Output: utrtest_2.a, utrtest_2.tableoid, utrtest_2.ctid, utrtest_2.*
8999                      Remote SQL: SELECT a, b, ctid FROM public.loct FOR UPDATE
9000          ->  Hash
9001                Output: "*VALUES*".*, "*VALUES*".column1
9002                ->  Values Scan on "*VALUES*"
9003                      Output: "*VALUES*".*, "*VALUES*".column1
9004 (18 rows)
9006 update utrtest set a = 3 from (values (2), (3)) s(x) where a = s.x returning *; -- ERROR
9007 ERROR:  cannot route tuples into foreign table to be updated "remp"
9008 drop table utrtest;
9009 drop table loct;
9010 -- Test copy tuple routing
9011 create table ctrtest (a int, b text) partition by list (a);
9012 create table loct1 (a int check (a in (1)), b text);
9013 create foreign table remp1 (a int check (a in (1)), b text) server loopback options (table_name 'loct1');
9014 create table loct2 (a int check (a in (2)), b text);
9015 create foreign table remp2 (b text, a int check (a in (2))) server loopback options (table_name 'loct2');
9016 alter table ctrtest attach partition remp1 for values in (1);
9017 alter table ctrtest attach partition remp2 for values in (2);
9018 copy ctrtest from stdin;
9019 select tableoid::regclass, * FROM ctrtest;
9020  tableoid | a |  b  
9021 ----------+---+-----
9022  remp1    | 1 | foo
9023  remp2    | 2 | qux
9024 (2 rows)
9026 select tableoid::regclass, * FROM remp1;
9027  tableoid | a |  b  
9028 ----------+---+-----
9029  remp1    | 1 | foo
9030 (1 row)
9032 select tableoid::regclass, * FROM remp2;
9033  tableoid |  b  | a 
9034 ----------+-----+---
9035  remp2    | qux | 2
9036 (1 row)
9038 -- Copying into foreign partitions directly should work as well
9039 copy remp1 from stdin;
9040 select tableoid::regclass, * FROM remp1;
9041  tableoid | a |  b  
9042 ----------+---+-----
9043  remp1    | 1 | foo
9044  remp1    | 1 | bar
9045 (2 rows)
9047 delete from ctrtest;
9048 -- Test copy tuple routing with the batch_size option enabled
9049 alter server loopback options (add batch_size '2');
9050 copy ctrtest from stdin;
9051 select tableoid::regclass, * FROM ctrtest;
9052  tableoid | a |   b   
9053 ----------+---+-------
9054  remp1    | 1 | foo
9055  remp1    | 1 | bar
9056  remp1    | 1 | test1
9057  remp2    | 2 | baz
9058  remp2    | 2 | qux
9059  remp2    | 2 | test2
9060 (6 rows)
9062 select tableoid::regclass, * FROM remp1;
9063  tableoid | a |   b   
9064 ----------+---+-------
9065  remp1    | 1 | foo
9066  remp1    | 1 | bar
9067  remp1    | 1 | test1
9068 (3 rows)
9070 select tableoid::regclass, * FROM remp2;
9071  tableoid |   b   | a 
9072 ----------+-------+---
9073  remp2    | baz   | 2
9074  remp2    | qux   | 2
9075  remp2    | test2 | 2
9076 (3 rows)
9078 delete from ctrtest;
9079 alter server loopback options (drop batch_size);
9080 drop table ctrtest;
9081 drop table loct1;
9082 drop table loct2;
9083 -- ===================================================================
9084 -- test COPY FROM
9085 -- ===================================================================
9086 create table loc2 (f1 int, f2 text);
9087 alter table loc2 set (autovacuum_enabled = 'false');
9088 create foreign table rem2 (f1 int, f2 text) server loopback options(table_name 'loc2');
9089 -- Test basic functionality
9090 copy rem2 from stdin;
9091 select * from rem2;
9092  f1 | f2  
9093 ----+-----
9094   1 | foo
9095   2 | bar
9096 (2 rows)
9098 delete from rem2;
9099 -- Test check constraints
9100 alter table loc2 add constraint loc2_f1positive check (f1 >= 0);
9101 alter foreign table rem2 add constraint rem2_f1positive check (f1 >= 0);
9102 -- check constraint is enforced on the remote side, not locally
9103 copy rem2 from stdin;
9104 copy rem2 from stdin; -- ERROR
9105 ERROR:  new row for relation "loc2" violates check constraint "loc2_f1positive"
9106 DETAIL:  Failing row contains (-1, xyzzy).
9107 CONTEXT:  remote SQL command: INSERT INTO public.loc2(f1, f2) VALUES ($1, $2)
9108 COPY rem2, line 1: "-1  xyzzy"
9109 select * from rem2;
9110  f1 | f2  
9111 ----+-----
9112   1 | foo
9113   2 | bar
9114 (2 rows)
9116 alter foreign table rem2 drop constraint rem2_f1positive;
9117 alter table loc2 drop constraint loc2_f1positive;
9118 delete from rem2;
9119 -- Test local triggers
9120 create trigger trig_stmt_before before insert on rem2
9121         for each statement execute procedure trigger_func();
9122 create trigger trig_stmt_after after insert on rem2
9123         for each statement execute procedure trigger_func();
9124 create trigger trig_row_before before insert on rem2
9125         for each row execute procedure trigger_data(23,'skidoo');
9126 create trigger trig_row_after after insert on rem2
9127         for each row execute procedure trigger_data(23,'skidoo');
9128 copy rem2 from stdin;
9129 NOTICE:  trigger_func(<NULL>) called: action = INSERT, when = BEFORE, level = STATEMENT
9130 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem2
9131 NOTICE:  NEW: (1,foo)
9132 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem2
9133 NOTICE:  NEW: (2,bar)
9134 NOTICE:  trig_row_after(23, skidoo) AFTER ROW INSERT ON rem2
9135 NOTICE:  NEW: (1,foo)
9136 NOTICE:  trig_row_after(23, skidoo) AFTER ROW INSERT ON rem2
9137 NOTICE:  NEW: (2,bar)
9138 NOTICE:  trigger_func(<NULL>) called: action = INSERT, when = AFTER, level = STATEMENT
9139 select * from rem2;
9140  f1 | f2  
9141 ----+-----
9142   1 | foo
9143   2 | bar
9144 (2 rows)
9146 drop trigger trig_row_before on rem2;
9147 drop trigger trig_row_after on rem2;
9148 drop trigger trig_stmt_before on rem2;
9149 drop trigger trig_stmt_after on rem2;
9150 delete from rem2;
9151 create trigger trig_row_before_insert before insert on rem2
9152         for each row execute procedure trig_row_before_insupdate();
9153 -- The new values are concatenated with ' triggered !'
9154 copy rem2 from stdin;
9155 select * from rem2;
9156  f1 |       f2        
9157 ----+-----------------
9158   1 | foo triggered !
9159   2 | bar triggered !
9160 (2 rows)
9162 drop trigger trig_row_before_insert on rem2;
9163 delete from rem2;
9164 create trigger trig_null before insert on rem2
9165         for each row execute procedure trig_null();
9166 -- Nothing happens
9167 copy rem2 from stdin;
9168 select * from rem2;
9169  f1 | f2 
9170 ----+----
9171 (0 rows)
9173 drop trigger trig_null on rem2;
9174 delete from rem2;
9175 -- Test remote triggers
9176 create trigger trig_row_before_insert before insert on loc2
9177         for each row execute procedure trig_row_before_insupdate();
9178 -- The new values are concatenated with ' triggered !'
9179 copy rem2 from stdin;
9180 select * from rem2;
9181  f1 |       f2        
9182 ----+-----------------
9183   1 | foo triggered !
9184   2 | bar triggered !
9185 (2 rows)
9187 drop trigger trig_row_before_insert on loc2;
9188 delete from rem2;
9189 create trigger trig_null before insert on loc2
9190         for each row execute procedure trig_null();
9191 -- Nothing happens
9192 copy rem2 from stdin;
9193 select * from rem2;
9194  f1 | f2 
9195 ----+----
9196 (0 rows)
9198 drop trigger trig_null on loc2;
9199 delete from rem2;
9200 -- Test a combination of local and remote triggers
9201 create trigger rem2_trig_row_before before insert on rem2
9202         for each row execute procedure trigger_data(23,'skidoo');
9203 create trigger rem2_trig_row_after after insert on rem2
9204         for each row execute procedure trigger_data(23,'skidoo');
9205 create trigger loc2_trig_row_before_insert before insert on loc2
9206         for each row execute procedure trig_row_before_insupdate();
9207 copy rem2 from stdin;
9208 NOTICE:  rem2_trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem2
9209 NOTICE:  NEW: (1,foo)
9210 NOTICE:  rem2_trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem2
9211 NOTICE:  NEW: (2,bar)
9212 NOTICE:  rem2_trig_row_after(23, skidoo) AFTER ROW INSERT ON rem2
9213 NOTICE:  NEW: (1,"foo triggered !")
9214 NOTICE:  rem2_trig_row_after(23, skidoo) AFTER ROW INSERT ON rem2
9215 NOTICE:  NEW: (2,"bar triggered !")
9216 select * from rem2;
9217  f1 |       f2        
9218 ----+-----------------
9219   1 | foo triggered !
9220   2 | bar triggered !
9221 (2 rows)
9223 drop trigger rem2_trig_row_before on rem2;
9224 drop trigger rem2_trig_row_after on rem2;
9225 drop trigger loc2_trig_row_before_insert on loc2;
9226 delete from rem2;
9227 -- test COPY FROM with foreign table created in the same transaction
9228 create table loc3 (f1 int, f2 text);
9229 begin;
9230 create foreign table rem3 (f1 int, f2 text)
9231         server loopback options(table_name 'loc3');
9232 copy rem3 from stdin;
9233 commit;
9234 select * from rem3;
9235  f1 | f2  
9236 ----+-----
9237   1 | foo
9238   2 | bar
9239 (2 rows)
9241 drop foreign table rem3;
9242 drop table loc3;
9243 -- Test COPY FROM with the batch_size option enabled
9244 alter server loopback options (add batch_size '2');
9245 -- Test basic functionality
9246 copy rem2 from stdin;
9247 select * from rem2;
9248  f1 | f2  
9249 ----+-----
9250   1 | foo
9251   2 | bar
9252   3 | baz
9253 (3 rows)
9255 delete from rem2;
9256 -- Test check constraints
9257 alter table loc2 add constraint loc2_f1positive check (f1 >= 0);
9258 alter foreign table rem2 add constraint rem2_f1positive check (f1 >= 0);
9259 -- check constraint is enforced on the remote side, not locally
9260 copy rem2 from stdin;
9261 copy rem2 from stdin; -- ERROR
9262 ERROR:  new row for relation "loc2" violates check constraint "loc2_f1positive"
9263 DETAIL:  Failing row contains (-1, xyzzy).
9264 CONTEXT:  remote SQL command: INSERT INTO public.loc2(f1, f2) VALUES ($1, $2)
9265 COPY rem2
9266 select * from rem2;
9267  f1 | f2  
9268 ----+-----
9269   1 | foo
9270   2 | bar
9271   3 | baz
9272 (3 rows)
9274 alter foreign table rem2 drop constraint rem2_f1positive;
9275 alter table loc2 drop constraint loc2_f1positive;
9276 delete from rem2;
9277 -- Test remote triggers
9278 create trigger trig_row_before_insert before insert on loc2
9279         for each row execute procedure trig_row_before_insupdate();
9280 -- The new values are concatenated with ' triggered !'
9281 copy rem2 from stdin;
9282 select * from rem2;
9283  f1 |       f2        
9284 ----+-----------------
9285   1 | foo triggered !
9286   2 | bar triggered !
9287   3 | baz triggered !
9288 (3 rows)
9290 drop trigger trig_row_before_insert on loc2;
9291 delete from rem2;
9292 create trigger trig_null before insert on loc2
9293         for each row execute procedure trig_null();
9294 -- Nothing happens
9295 copy rem2 from stdin;
9296 select * from rem2;
9297  f1 | f2 
9298 ----+----
9299 (0 rows)
9301 drop trigger trig_null on loc2;
9302 delete from rem2;
9303 -- Check with zero-column foreign table; batch insert will be disabled
9304 alter table loc2 drop column f1;
9305 alter table loc2 drop column f2;
9306 alter table rem2 drop column f1;
9307 alter table rem2 drop column f2;
9308 copy rem2 from stdin;
9309 select * from rem2;
9311 (3 rows)
9313 delete from rem2;
9314 alter server loopback options (drop batch_size);
9315 -- ===================================================================
9316 -- test for TRUNCATE
9317 -- ===================================================================
9318 CREATE TABLE tru_rtable0 (id int primary key);
9319 CREATE FOREIGN TABLE tru_ftable (id int)
9320        SERVER loopback OPTIONS (table_name 'tru_rtable0');
9321 INSERT INTO tru_rtable0 (SELECT x FROM generate_series(1,10) x);
9322 CREATE TABLE tru_ptable (id int) PARTITION BY HASH(id);
9323 CREATE TABLE tru_ptable__p0 PARTITION OF tru_ptable
9324                             FOR VALUES WITH (MODULUS 2, REMAINDER 0);
9325 CREATE TABLE tru_rtable1 (id int primary key);
9326 CREATE FOREIGN TABLE tru_ftable__p1 PARTITION OF tru_ptable
9327                                     FOR VALUES WITH (MODULUS 2, REMAINDER 1)
9328        SERVER loopback OPTIONS (table_name 'tru_rtable1');
9329 INSERT INTO tru_ptable (SELECT x FROM generate_series(11,20) x);
9330 CREATE TABLE tru_pk_table(id int primary key);
9331 CREATE TABLE tru_fk_table(fkey int references tru_pk_table(id));
9332 INSERT INTO tru_pk_table (SELECT x FROM generate_series(1,10) x);
9333 INSERT INTO tru_fk_table (SELECT x % 10 + 1 FROM generate_series(5,25) x);
9334 CREATE FOREIGN TABLE tru_pk_ftable (id int)
9335        SERVER loopback OPTIONS (table_name 'tru_pk_table');
9336 CREATE TABLE tru_rtable_parent (id int);
9337 CREATE TABLE tru_rtable_child (id int);
9338 CREATE FOREIGN TABLE tru_ftable_parent (id int)
9339        SERVER loopback OPTIONS (table_name 'tru_rtable_parent');
9340 CREATE FOREIGN TABLE tru_ftable_child () INHERITS (tru_ftable_parent)
9341        SERVER loopback OPTIONS (table_name 'tru_rtable_child');
9342 INSERT INTO tru_rtable_parent (SELECT x FROM generate_series(1,8) x);
9343 INSERT INTO tru_rtable_child  (SELECT x FROM generate_series(10, 18) x);
9344 -- normal truncate
9345 SELECT sum(id) FROM tru_ftable;        -- 55
9346  sum 
9347 -----
9348   55
9349 (1 row)
9351 TRUNCATE tru_ftable;
9352 SELECT count(*) FROM tru_rtable0;               -- 0
9353  count 
9354 -------
9355      0
9356 (1 row)
9358 SELECT count(*) FROM tru_ftable;                -- 0
9359  count 
9360 -------
9361      0
9362 (1 row)
9364 -- 'truncatable' option
9365 ALTER SERVER loopback OPTIONS (ADD truncatable 'false');
9366 TRUNCATE tru_ftable;                    -- error
9367 ERROR:  foreign table "tru_ftable" does not allow truncates
9368 ALTER FOREIGN TABLE tru_ftable OPTIONS (ADD truncatable 'true');
9369 TRUNCATE tru_ftable;                    -- accepted
9370 ALTER FOREIGN TABLE tru_ftable OPTIONS (SET truncatable 'false');
9371 TRUNCATE tru_ftable;                    -- error
9372 ERROR:  foreign table "tru_ftable" does not allow truncates
9373 ALTER SERVER loopback OPTIONS (DROP truncatable);
9374 ALTER FOREIGN TABLE tru_ftable OPTIONS (SET truncatable 'false');
9375 TRUNCATE tru_ftable;                    -- error
9376 ERROR:  foreign table "tru_ftable" does not allow truncates
9377 ALTER FOREIGN TABLE tru_ftable OPTIONS (SET truncatable 'true');
9378 TRUNCATE tru_ftable;                    -- accepted
9379 -- partitioned table with both local and foreign tables as partitions
9380 SELECT sum(id) FROM tru_ptable;        -- 155
9381  sum 
9382 -----
9383  155
9384 (1 row)
9386 TRUNCATE tru_ptable;
9387 SELECT count(*) FROM tru_ptable;                -- 0
9388  count 
9389 -------
9390      0
9391 (1 row)
9393 SELECT count(*) FROM tru_ptable__p0;    -- 0
9394  count 
9395 -------
9396      0
9397 (1 row)
9399 SELECT count(*) FROM tru_ftable__p1;    -- 0
9400  count 
9401 -------
9402      0
9403 (1 row)
9405 SELECT count(*) FROM tru_rtable1;               -- 0
9406  count 
9407 -------
9408      0
9409 (1 row)
9411 -- 'CASCADE' option
9412 SELECT sum(id) FROM tru_pk_ftable;      -- 55
9413  sum 
9414 -----
9415   55
9416 (1 row)
9418 TRUNCATE tru_pk_ftable; -- failed by FK reference
9419 ERROR:  cannot truncate a table referenced in a foreign key constraint
9420 DETAIL:  Table "tru_fk_table" references "tru_pk_table".
9421 HINT:  Truncate table "tru_fk_table" at the same time, or use TRUNCATE ... CASCADE.
9422 CONTEXT:  remote SQL command: TRUNCATE public.tru_pk_table CONTINUE IDENTITY RESTRICT
9423 TRUNCATE tru_pk_ftable CASCADE;
9424 SELECT count(*) FROM tru_pk_ftable;    -- 0
9425  count 
9426 -------
9427      0
9428 (1 row)
9430 SELECT count(*) FROM tru_fk_table;              -- also truncated,0
9431  count 
9432 -------
9433      0
9434 (1 row)
9436 -- truncate two tables at a command
9437 INSERT INTO tru_ftable (SELECT x FROM generate_series(1,8) x);
9438 INSERT INTO tru_pk_ftable (SELECT x FROM generate_series(3,10) x);
9439 SELECT count(*) from tru_ftable; -- 8
9440  count 
9441 -------
9442      8
9443 (1 row)
9445 SELECT count(*) from tru_pk_ftable; -- 8
9446  count 
9447 -------
9448      8
9449 (1 row)
9451 TRUNCATE tru_ftable, tru_pk_ftable CASCADE;
9452 SELECT count(*) from tru_ftable; -- 0
9453  count 
9454 -------
9455      0
9456 (1 row)
9458 SELECT count(*) from tru_pk_ftable; -- 0
9459  count 
9460 -------
9461      0
9462 (1 row)
9464 -- truncate with ONLY clause
9465 -- Since ONLY is specified, the table tru_ftable_child that inherits
9466 -- tru_ftable_parent locally is not truncated.
9467 TRUNCATE ONLY tru_ftable_parent;
9468 SELECT sum(id) FROM tru_ftable_parent;  -- 126
9469  sum 
9470 -----
9471  126
9472 (1 row)
9474 TRUNCATE tru_ftable_parent;
9475 SELECT count(*) FROM tru_ftable_parent; -- 0
9476  count 
9477 -------
9478      0
9479 (1 row)
9481 -- in case when remote table has inherited children
9482 CREATE TABLE tru_rtable0_child () INHERITS (tru_rtable0);
9483 INSERT INTO tru_rtable0 (SELECT x FROM generate_series(5,9) x);
9484 INSERT INTO tru_rtable0_child (SELECT x FROM generate_series(10,14) x);
9485 SELECT sum(id) FROM tru_ftable;   -- 95
9486  sum 
9487 -----
9488   95
9489 (1 row)
9491 -- Both parent and child tables in the foreign server are truncated
9492 -- even though ONLY is specified because ONLY has no effect
9493 -- when truncating a foreign table.
9494 TRUNCATE ONLY tru_ftable;
9495 SELECT count(*) FROM tru_ftable;   -- 0
9496  count 
9497 -------
9498      0
9499 (1 row)
9501 INSERT INTO tru_rtable0 (SELECT x FROM generate_series(21,25) x);
9502 INSERT INTO tru_rtable0_child (SELECT x FROM generate_series(26,30) x);
9503 SELECT sum(id) FROM tru_ftable;         -- 255
9504  sum 
9505 -----
9506  255
9507 (1 row)
9509 TRUNCATE tru_ftable;                    -- truncate both of parent and child
9510 SELECT count(*) FROM tru_ftable;    -- 0
9511  count 
9512 -------
9513      0
9514 (1 row)
9516 -- cleanup
9517 DROP FOREIGN TABLE tru_ftable_parent, tru_ftable_child, tru_pk_ftable,tru_ftable__p1,tru_ftable;
9518 DROP TABLE tru_rtable0, tru_rtable1, tru_ptable, tru_ptable__p0, tru_pk_table, tru_fk_table,
9519 tru_rtable_parent,tru_rtable_child, tru_rtable0_child;
9520 -- ===================================================================
9521 -- test IMPORT FOREIGN SCHEMA
9522 -- ===================================================================
9523 CREATE SCHEMA import_source;
9524 CREATE TABLE import_source.t1 (c1 int, c2 varchar NOT NULL);
9525 CREATE TABLE import_source.t2 (c1 int default 42, c2 varchar NULL, c3 text collate "POSIX");
9526 CREATE TYPE typ1 AS (m1 int, m2 varchar);
9527 CREATE TABLE import_source.t3 (c1 timestamptz default now(), c2 typ1);
9528 CREATE TABLE import_source."x 4" (c1 float8, "C 2" text, c3 varchar(42));
9529 CREATE TABLE import_source."x 5" (c1 float8);
9530 ALTER TABLE import_source."x 5" DROP COLUMN c1;
9531 CREATE TABLE import_source."x 6" (c1 int, c2 int generated always as (c1 * 2) stored);
9532 CREATE TABLE import_source.t4 (c1 int) PARTITION BY RANGE (c1);
9533 CREATE TABLE import_source.t4_part PARTITION OF import_source.t4
9534   FOR VALUES FROM (1) TO (100);
9535 CREATE TABLE import_source.t4_part2 PARTITION OF import_source.t4
9536   FOR VALUES FROM (100) TO (200);
9537 CREATE SCHEMA import_dest1;
9538 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest1;
9539 \det+ import_dest1.*
9540                                      List of foreign tables
9541     Schema    | Table |  Server  |                   FDW options                   | Description 
9542 --------------+-------+----------+-------------------------------------------------+-------------
9543  import_dest1 | t1    | loopback | (schema_name 'import_source', table_name 't1')  | 
9544  import_dest1 | t2    | loopback | (schema_name 'import_source', table_name 't2')  | 
9545  import_dest1 | t3    | loopback | (schema_name 'import_source', table_name 't3')  | 
9546  import_dest1 | t4    | loopback | (schema_name 'import_source', table_name 't4')  | 
9547  import_dest1 | x 4   | loopback | (schema_name 'import_source', table_name 'x 4') | 
9548  import_dest1 | x 5   | loopback | (schema_name 'import_source', table_name 'x 5') | 
9549  import_dest1 | x 6   | loopback | (schema_name 'import_source', table_name 'x 6') | 
9550 (7 rows)
9552 \d import_dest1.*
9553                          Foreign table "import_dest1.t1"
9554  Column |       Type        | Collation | Nullable | Default |    FDW options     
9555 --------+-------------------+-----------+----------+---------+--------------------
9556  c1     | integer           |           |          |         | (column_name 'c1')
9557  c2     | character varying |           | not null |         | (column_name 'c2')
9558 Server: loopback
9559 FDW options: (schema_name 'import_source', table_name 't1')
9561                          Foreign table "import_dest1.t2"
9562  Column |       Type        | Collation | Nullable | Default |    FDW options     
9563 --------+-------------------+-----------+----------+---------+--------------------
9564  c1     | integer           |           |          |         | (column_name 'c1')
9565  c2     | character varying |           |          |         | (column_name 'c2')
9566  c3     | text              | POSIX     |          |         | (column_name 'c3')
9567 Server: loopback
9568 FDW options: (schema_name 'import_source', table_name 't2')
9570                              Foreign table "import_dest1.t3"
9571  Column |           Type           | Collation | Nullable | Default |    FDW options     
9572 --------+--------------------------+-----------+----------+---------+--------------------
9573  c1     | timestamp with time zone |           |          |         | (column_name 'c1')
9574  c2     | typ1                     |           |          |         | (column_name 'c2')
9575 Server: loopback
9576 FDW options: (schema_name 'import_source', table_name 't3')
9578                     Foreign table "import_dest1.t4"
9579  Column |  Type   | Collation | Nullable | Default |    FDW options     
9580 --------+---------+-----------+----------+---------+--------------------
9581  c1     | integer |           |          |         | (column_name 'c1')
9582 Server: loopback
9583 FDW options: (schema_name 'import_source', table_name 't4')
9585                            Foreign table "import_dest1.x 4"
9586  Column |         Type          | Collation | Nullable | Default |     FDW options     
9587 --------+-----------------------+-----------+----------+---------+---------------------
9588  c1     | double precision      |           |          |         | (column_name 'c1')
9589  C 2    | text                  |           |          |         | (column_name 'C 2')
9590  c3     | character varying(42) |           |          |         | (column_name 'c3')
9591 Server: loopback
9592 FDW options: (schema_name 'import_source', table_name 'x 4')
9594                Foreign table "import_dest1.x 5"
9595  Column | Type | Collation | Nullable | Default | FDW options 
9596 --------+------+-----------+----------+---------+-------------
9597 Server: loopback
9598 FDW options: (schema_name 'import_source', table_name 'x 5')
9600                                   Foreign table "import_dest1.x 6"
9601  Column |  Type   | Collation | Nullable |               Default               |    FDW options     
9602 --------+---------+-----------+----------+-------------------------------------+--------------------
9603  c1     | integer |           |          |                                     | (column_name 'c1')
9604  c2     | integer |           |          | generated always as (c1 * 2) stored | (column_name 'c2')
9605 Server: loopback
9606 FDW options: (schema_name 'import_source', table_name 'x 6')
9608 -- Options
9609 CREATE SCHEMA import_dest2;
9610 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest2
9611   OPTIONS (import_default 'true');
9612 \det+ import_dest2.*
9613                                      List of foreign tables
9614     Schema    | Table |  Server  |                   FDW options                   | Description 
9615 --------------+-------+----------+-------------------------------------------------+-------------
9616  import_dest2 | t1    | loopback | (schema_name 'import_source', table_name 't1')  | 
9617  import_dest2 | t2    | loopback | (schema_name 'import_source', table_name 't2')  | 
9618  import_dest2 | t3    | loopback | (schema_name 'import_source', table_name 't3')  | 
9619  import_dest2 | t4    | loopback | (schema_name 'import_source', table_name 't4')  | 
9620  import_dest2 | x 4   | loopback | (schema_name 'import_source', table_name 'x 4') | 
9621  import_dest2 | x 5   | loopback | (schema_name 'import_source', table_name 'x 5') | 
9622  import_dest2 | x 6   | loopback | (schema_name 'import_source', table_name 'x 6') | 
9623 (7 rows)
9625 \d import_dest2.*
9626                          Foreign table "import_dest2.t1"
9627  Column |       Type        | Collation | Nullable | Default |    FDW options     
9628 --------+-------------------+-----------+----------+---------+--------------------
9629  c1     | integer           |           |          |         | (column_name 'c1')
9630  c2     | character varying |           | not null |         | (column_name 'c2')
9631 Server: loopback
9632 FDW options: (schema_name 'import_source', table_name 't1')
9634                          Foreign table "import_dest2.t2"
9635  Column |       Type        | Collation | Nullable | Default |    FDW options     
9636 --------+-------------------+-----------+----------+---------+--------------------
9637  c1     | integer           |           |          | 42      | (column_name 'c1')
9638  c2     | character varying |           |          |         | (column_name 'c2')
9639  c3     | text              | POSIX     |          |         | (column_name 'c3')
9640 Server: loopback
9641 FDW options: (schema_name 'import_source', table_name 't2')
9643                              Foreign table "import_dest2.t3"
9644  Column |           Type           | Collation | Nullable | Default |    FDW options     
9645 --------+--------------------------+-----------+----------+---------+--------------------
9646  c1     | timestamp with time zone |           |          | now()   | (column_name 'c1')
9647  c2     | typ1                     |           |          |         | (column_name 'c2')
9648 Server: loopback
9649 FDW options: (schema_name 'import_source', table_name 't3')
9651                     Foreign table "import_dest2.t4"
9652  Column |  Type   | Collation | Nullable | Default |    FDW options     
9653 --------+---------+-----------+----------+---------+--------------------
9654  c1     | integer |           |          |         | (column_name 'c1')
9655 Server: loopback
9656 FDW options: (schema_name 'import_source', table_name 't4')
9658                            Foreign table "import_dest2.x 4"
9659  Column |         Type          | Collation | Nullable | Default |     FDW options     
9660 --------+-----------------------+-----------+----------+---------+---------------------
9661  c1     | double precision      |           |          |         | (column_name 'c1')
9662  C 2    | text                  |           |          |         | (column_name 'C 2')
9663  c3     | character varying(42) |           |          |         | (column_name 'c3')
9664 Server: loopback
9665 FDW options: (schema_name 'import_source', table_name 'x 4')
9667                Foreign table "import_dest2.x 5"
9668  Column | Type | Collation | Nullable | Default | FDW options 
9669 --------+------+-----------+----------+---------+-------------
9670 Server: loopback
9671 FDW options: (schema_name 'import_source', table_name 'x 5')
9673                                   Foreign table "import_dest2.x 6"
9674  Column |  Type   | Collation | Nullable |               Default               |    FDW options     
9675 --------+---------+-----------+----------+-------------------------------------+--------------------
9676  c1     | integer |           |          |                                     | (column_name 'c1')
9677  c2     | integer |           |          | generated always as (c1 * 2) stored | (column_name 'c2')
9678 Server: loopback
9679 FDW options: (schema_name 'import_source', table_name 'x 6')
9681 CREATE SCHEMA import_dest3;
9682 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest3
9683   OPTIONS (import_collate 'false', import_generated 'false', import_not_null 'false');
9684 \det+ import_dest3.*
9685                                      List of foreign tables
9686     Schema    | Table |  Server  |                   FDW options                   | Description 
9687 --------------+-------+----------+-------------------------------------------------+-------------
9688  import_dest3 | t1    | loopback | (schema_name 'import_source', table_name 't1')  | 
9689  import_dest3 | t2    | loopback | (schema_name 'import_source', table_name 't2')  | 
9690  import_dest3 | t3    | loopback | (schema_name 'import_source', table_name 't3')  | 
9691  import_dest3 | t4    | loopback | (schema_name 'import_source', table_name 't4')  | 
9692  import_dest3 | x 4   | loopback | (schema_name 'import_source', table_name 'x 4') | 
9693  import_dest3 | x 5   | loopback | (schema_name 'import_source', table_name 'x 5') | 
9694  import_dest3 | x 6   | loopback | (schema_name 'import_source', table_name 'x 6') | 
9695 (7 rows)
9697 \d import_dest3.*
9698                          Foreign table "import_dest3.t1"
9699  Column |       Type        | Collation | Nullable | Default |    FDW options     
9700 --------+-------------------+-----------+----------+---------+--------------------
9701  c1     | integer           |           |          |         | (column_name 'c1')
9702  c2     | character varying |           |          |         | (column_name 'c2')
9703 Server: loopback
9704 FDW options: (schema_name 'import_source', table_name 't1')
9706                          Foreign table "import_dest3.t2"
9707  Column |       Type        | Collation | Nullable | Default |    FDW options     
9708 --------+-------------------+-----------+----------+---------+--------------------
9709  c1     | integer           |           |          |         | (column_name 'c1')
9710  c2     | character varying |           |          |         | (column_name 'c2')
9711  c3     | text              |           |          |         | (column_name 'c3')
9712 Server: loopback
9713 FDW options: (schema_name 'import_source', table_name 't2')
9715                              Foreign table "import_dest3.t3"
9716  Column |           Type           | Collation | Nullable | Default |    FDW options     
9717 --------+--------------------------+-----------+----------+---------+--------------------
9718  c1     | timestamp with time zone |           |          |         | (column_name 'c1')
9719  c2     | typ1                     |           |          |         | (column_name 'c2')
9720 Server: loopback
9721 FDW options: (schema_name 'import_source', table_name 't3')
9723                     Foreign table "import_dest3.t4"
9724  Column |  Type   | Collation | Nullable | Default |    FDW options     
9725 --------+---------+-----------+----------+---------+--------------------
9726  c1     | integer |           |          |         | (column_name 'c1')
9727 Server: loopback
9728 FDW options: (schema_name 'import_source', table_name 't4')
9730                            Foreign table "import_dest3.x 4"
9731  Column |         Type          | Collation | Nullable | Default |     FDW options     
9732 --------+-----------------------+-----------+----------+---------+---------------------
9733  c1     | double precision      |           |          |         | (column_name 'c1')
9734  C 2    | text                  |           |          |         | (column_name 'C 2')
9735  c3     | character varying(42) |           |          |         | (column_name 'c3')
9736 Server: loopback
9737 FDW options: (schema_name 'import_source', table_name 'x 4')
9739                Foreign table "import_dest3.x 5"
9740  Column | Type | Collation | Nullable | Default | FDW options 
9741 --------+------+-----------+----------+---------+-------------
9742 Server: loopback
9743 FDW options: (schema_name 'import_source', table_name 'x 5')
9745                     Foreign table "import_dest3.x 6"
9746  Column |  Type   | Collation | Nullable | Default |    FDW options     
9747 --------+---------+-----------+----------+---------+--------------------
9748  c1     | integer |           |          |         | (column_name 'c1')
9749  c2     | integer |           |          |         | (column_name 'c2')
9750 Server: loopback
9751 FDW options: (schema_name 'import_source', table_name 'x 6')
9753 -- Check LIMIT TO and EXCEPT
9754 CREATE SCHEMA import_dest4;
9755 IMPORT FOREIGN SCHEMA import_source LIMIT TO (t1, nonesuch, t4_part)
9756   FROM SERVER loopback INTO import_dest4;
9757 \det+ import_dest4.*
9758                                         List of foreign tables
9759     Schema    |  Table  |  Server  |                     FDW options                     | Description 
9760 --------------+---------+----------+-----------------------------------------------------+-------------
9761  import_dest4 | t1      | loopback | (schema_name 'import_source', table_name 't1')      | 
9762  import_dest4 | t4_part | loopback | (schema_name 'import_source', table_name 't4_part') | 
9763 (2 rows)
9765 IMPORT FOREIGN SCHEMA import_source EXCEPT (t1, "x 4", nonesuch, t4_part)
9766   FROM SERVER loopback INTO import_dest4;
9767 \det+ import_dest4.*
9768                                         List of foreign tables
9769     Schema    |  Table  |  Server  |                     FDW options                     | Description 
9770 --------------+---------+----------+-----------------------------------------------------+-------------
9771  import_dest4 | t1      | loopback | (schema_name 'import_source', table_name 't1')      | 
9772  import_dest4 | t2      | loopback | (schema_name 'import_source', table_name 't2')      | 
9773  import_dest4 | t3      | loopback | (schema_name 'import_source', table_name 't3')      | 
9774  import_dest4 | t4      | loopback | (schema_name 'import_source', table_name 't4')      | 
9775  import_dest4 | t4_part | loopback | (schema_name 'import_source', table_name 't4_part') | 
9776  import_dest4 | x 5     | loopback | (schema_name 'import_source', table_name 'x 5')     | 
9777  import_dest4 | x 6     | loopback | (schema_name 'import_source', table_name 'x 6')     | 
9778 (7 rows)
9780 -- Assorted error cases
9781 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest4;
9782 ERROR:  relation "t1" already exists
9783 CONTEXT:  importing foreign table "t1"
9784 IMPORT FOREIGN SCHEMA nonesuch FROM SERVER loopback INTO import_dest4;
9785 ERROR:  schema "nonesuch" is not present on foreign server "loopback"
9786 IMPORT FOREIGN SCHEMA nonesuch FROM SERVER loopback INTO notthere;
9787 ERROR:  schema "notthere" does not exist
9788 IMPORT FOREIGN SCHEMA nonesuch FROM SERVER nowhere INTO notthere;
9789 ERROR:  server "nowhere" does not exist
9790 -- Check case of a type present only on the remote server.
9791 -- We can fake this by dropping the type locally in our transaction.
9792 CREATE TYPE "Colors" AS ENUM ('red', 'green', 'blue');
9793 CREATE TABLE import_source.t5 (c1 int, c2 text collate "C", "Col" "Colors");
9794 CREATE SCHEMA import_dest5;
9795 BEGIN;
9796 DROP TYPE "Colors" CASCADE;
9797 NOTICE:  drop cascades to column Col of table import_source.t5
9798 IMPORT FOREIGN SCHEMA import_source LIMIT TO (t5)
9799   FROM SERVER loopback INTO import_dest5;  -- ERROR
9800 ERROR:  type "public.Colors" does not exist
9801 LINE 4:   "Col" public."Colors" OPTIONS (column_name 'Col')
9802                 ^
9803 QUERY:  CREATE FOREIGN TABLE t5 (
9804   c1 integer OPTIONS (column_name 'c1'),
9805   c2 text OPTIONS (column_name 'c2') COLLATE pg_catalog."C",
9806   "Col" public."Colors" OPTIONS (column_name 'Col')
9807 ) SERVER loopback
9808 OPTIONS (schema_name 'import_source', table_name 't5');
9809 CONTEXT:  importing foreign table "t5"
9810 ROLLBACK;
9811 BEGIN;
9812 CREATE SERVER fetch101 FOREIGN DATA WRAPPER postgres_fdw OPTIONS( fetch_size '101' );
9813 SELECT count(*)
9814 FROM pg_foreign_server
9815 WHERE srvname = 'fetch101'
9816 AND srvoptions @> array['fetch_size=101'];
9817  count 
9818 -------
9819      1
9820 (1 row)
9822 ALTER SERVER fetch101 OPTIONS( SET fetch_size '202' );
9823 SELECT count(*)
9824 FROM pg_foreign_server
9825 WHERE srvname = 'fetch101'
9826 AND srvoptions @> array['fetch_size=101'];
9827  count 
9828 -------
9829      0
9830 (1 row)
9832 SELECT count(*)
9833 FROM pg_foreign_server
9834 WHERE srvname = 'fetch101'
9835 AND srvoptions @> array['fetch_size=202'];
9836  count 
9837 -------
9838      1
9839 (1 row)
9841 CREATE FOREIGN TABLE table30000 ( x int ) SERVER fetch101 OPTIONS ( fetch_size '30000' );
9842 SELECT COUNT(*)
9843 FROM pg_foreign_table
9844 WHERE ftrelid = 'table30000'::regclass
9845 AND ftoptions @> array['fetch_size=30000'];
9846  count 
9847 -------
9848      1
9849 (1 row)
9851 ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '60000');
9852 SELECT COUNT(*)
9853 FROM pg_foreign_table
9854 WHERE ftrelid = 'table30000'::regclass
9855 AND ftoptions @> array['fetch_size=30000'];
9856  count 
9857 -------
9858      0
9859 (1 row)
9861 SELECT COUNT(*)
9862 FROM pg_foreign_table
9863 WHERE ftrelid = 'table30000'::regclass
9864 AND ftoptions @> array['fetch_size=60000'];
9865  count 
9866 -------
9867      1
9868 (1 row)
9870 ROLLBACK;
9871 -- ===================================================================
9872 -- test partitionwise joins
9873 -- ===================================================================
9874 SET enable_partitionwise_join=on;
9875 CREATE TABLE fprt1 (a int, b int, c varchar) PARTITION BY RANGE(a);
9876 CREATE TABLE fprt1_p1 (LIKE fprt1);
9877 CREATE TABLE fprt1_p2 (LIKE fprt1);
9878 ALTER TABLE fprt1_p1 SET (autovacuum_enabled = 'false');
9879 ALTER TABLE fprt1_p2 SET (autovacuum_enabled = 'false');
9880 INSERT INTO fprt1_p1 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 249, 2) i;
9881 INSERT INTO fprt1_p2 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(250, 499, 2) i;
9882 CREATE FOREIGN TABLE ftprt1_p1 PARTITION OF fprt1 FOR VALUES FROM (0) TO (250)
9883         SERVER loopback OPTIONS (table_name 'fprt1_p1', use_remote_estimate 'true');
9884 CREATE FOREIGN TABLE ftprt1_p2 PARTITION OF fprt1 FOR VALUES FROM (250) TO (500)
9885         SERVER loopback OPTIONS (TABLE_NAME 'fprt1_p2');
9886 ANALYZE fprt1;
9887 ANALYZE fprt1_p1;
9888 ANALYZE fprt1_p2;
9889 CREATE TABLE fprt2 (a int, b int, c varchar) PARTITION BY RANGE(b);
9890 CREATE TABLE fprt2_p1 (LIKE fprt2);
9891 CREATE TABLE fprt2_p2 (LIKE fprt2);
9892 ALTER TABLE fprt2_p1 SET (autovacuum_enabled = 'false');
9893 ALTER TABLE fprt2_p2 SET (autovacuum_enabled = 'false');
9894 INSERT INTO fprt2_p1 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 249, 3) i;
9895 INSERT INTO fprt2_p2 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(250, 499, 3) i;
9896 CREATE FOREIGN TABLE ftprt2_p1 (b int, c varchar, a int)
9897         SERVER loopback OPTIONS (table_name 'fprt2_p1', use_remote_estimate 'true');
9898 ALTER TABLE fprt2 ATTACH PARTITION ftprt2_p1 FOR VALUES FROM (0) TO (250);
9899 CREATE FOREIGN TABLE ftprt2_p2 PARTITION OF fprt2 FOR VALUES FROM (250) TO (500)
9900         SERVER loopback OPTIONS (table_name 'fprt2_p2', use_remote_estimate 'true');
9901 ANALYZE fprt2;
9902 ANALYZE fprt2_p1;
9903 ANALYZE fprt2_p2;
9904 -- inner join three tables
9905 EXPLAIN (COSTS OFF)
9906 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;
9907                                              QUERY PLAN                                              
9908 -----------------------------------------------------------------------------------------------------
9909  Sort
9910    Sort Key: t1.a, t3.c
9911    ->  Append
9912          ->  Foreign Scan
9913                Relations: ((ftprt1_p1 t1_1) INNER JOIN (ftprt2_p1 t2_1)) INNER JOIN (ftprt1_p1 t3_1)
9914          ->  Foreign Scan
9915                Relations: ((ftprt1_p2 t1_2) INNER JOIN (ftprt2_p2 t2_2)) INNER JOIN (ftprt1_p2 t3_2)
9916 (7 rows)
9918 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;
9919   a  |  b  |  c   
9920 -----+-----+------
9921    0 |   0 | 0000
9922  150 | 150 | 0003
9923  250 | 250 | 0005
9924  400 | 400 | 0008
9925 (4 rows)
9927 -- left outer join + nullable clause
9928 EXPLAIN (VERBOSE, COSTS OFF)
9929 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;
9930                                                                                                                      QUERY PLAN                                                                                                                     
9931 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
9932  Foreign Scan
9933    Output: t1.a, fprt2.b, fprt2.c
9934    Relations: (public.ftprt1_p1 t1) LEFT JOIN (public.ftprt2_p1 fprt2)
9935    Remote SQL: SELECT r5.a, r6.b, r6.c FROM (public.fprt1_p1 r5 LEFT JOIN public.fprt2_p1 r6 ON (((r5.a = r6.b)) AND ((r5.b = r6.a)) AND ((r6.a < 10)))) WHERE ((r5.a < 10)) ORDER BY r5.a ASC NULLS LAST, r6.b ASC NULLS LAST, r6.c ASC NULLS LAST
9936 (4 rows)
9938 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;
9939  a | b |  c   
9940 ---+---+------
9941  0 | 0 | 0000
9942  2 |   | 
9943  4 |   | 
9944  6 | 6 | 0000
9945  8 |   | 
9946 (5 rows)
9948 -- with whole-row reference; partitionwise join does not apply
9949 EXPLAIN (COSTS OFF)
9950 SELECT t1.wr, t2.wr FROM (SELECT t1 wr, a FROM fprt1 t1 WHERE t1.a % 25 = 0) t1 FULL JOIN (SELECT t2 wr, b FROM fprt2 t2 WHERE t2.b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY 1,2;
9951                        QUERY PLAN                       
9952 --------------------------------------------------------
9953  Sort
9954    Sort Key: ((t1.*)::fprt1), ((t2.*)::fprt2)
9955    ->  Hash Full Join
9956          Hash Cond: (t1.a = t2.b)
9957          ->  Append
9958                ->  Foreign Scan on ftprt1_p1 t1_1
9959                ->  Foreign Scan on ftprt1_p2 t1_2
9960          ->  Hash
9961                ->  Append
9962                      ->  Foreign Scan on ftprt2_p1 t2_1
9963                      ->  Foreign Scan on ftprt2_p2 t2_2
9964 (11 rows)
9966 SELECT t1.wr, t2.wr FROM (SELECT t1 wr, a FROM fprt1 t1 WHERE t1.a % 25 = 0) t1 FULL JOIN (SELECT t2 wr, b FROM fprt2 t2 WHERE t2.b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY 1,2;
9967        wr       |       wr       
9968 ----------------+----------------
9969  (0,0,0000)     | (0,0,0000)
9970  (50,50,0001)   | 
9971  (100,100,0002) | 
9972  (150,150,0003) | (150,150,0003)
9973  (200,200,0004) | 
9974  (250,250,0005) | (250,250,0005)
9975  (300,300,0006) | 
9976  (350,350,0007) | 
9977  (400,400,0008) | (400,400,0008)
9978  (450,450,0009) | 
9979                 | (75,75,0001)
9980                 | (225,225,0004)
9981                 | (325,325,0006)
9982                 | (475,475,0009)
9983 (14 rows)
9985 -- join with lateral reference
9986 EXPLAIN (COSTS OFF)
9987 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;
9988                               QUERY PLAN                               
9989 -----------------------------------------------------------------------
9990  Sort
9991    Sort Key: t1.a, t1.b
9992    ->  Append
9993          ->  Foreign Scan
9994                Relations: (ftprt1_p1 t1_1) INNER JOIN (ftprt2_p1 t2_1)
9995          ->  Foreign Scan
9996                Relations: (ftprt1_p2 t1_2) INNER JOIN (ftprt2_p2 t2_2)
9997 (7 rows)
9999 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;
10000   a  |  b  
10001 -----+-----
10002    0 |   0
10003  150 | 150
10004  250 | 250
10005  400 | 400
10006 (4 rows)
10008 -- with PHVs, partitionwise join selected but no join pushdown
10009 EXPLAIN (COSTS OFF)
10010 SELECT t1.a, t1.phv, t2.b, t2.phv FROM (SELECT 't1_phv' phv, * FROM fprt1 WHERE a % 25 = 0) t1 FULL JOIN (SELECT 't2_phv' phv, * FROM fprt2 WHERE b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
10011                         QUERY PLAN                         
10012 -----------------------------------------------------------
10013  Sort
10014    Sort Key: fprt1.a, fprt2.b
10015    ->  Append
10016          ->  Hash Full Join
10017                Hash Cond: (fprt1_1.a = fprt2_1.b)
10018                ->  Foreign Scan on ftprt1_p1 fprt1_1
10019                ->  Hash
10020                      ->  Foreign Scan on ftprt2_p1 fprt2_1
10021          ->  Hash Full Join
10022                Hash Cond: (fprt1_2.a = fprt2_2.b)
10023                ->  Foreign Scan on ftprt1_p2 fprt1_2
10024                ->  Hash
10025                      ->  Foreign Scan on ftprt2_p2 fprt2_2
10026 (13 rows)
10028 SELECT t1.a, t1.phv, t2.b, t2.phv FROM (SELECT 't1_phv' phv, * FROM fprt1 WHERE a % 25 = 0) t1 FULL JOIN (SELECT 't2_phv' phv, * FROM fprt2 WHERE b % 25 = 0) t2 ON (t1.a = t2.b) ORDER BY t1.a, t2.b;
10029   a  |  phv   |  b  |  phv   
10030 -----+--------+-----+--------
10031    0 | t1_phv |   0 | t2_phv
10032   50 | t1_phv |     | 
10033  100 | t1_phv |     | 
10034  150 | t1_phv | 150 | t2_phv
10035  200 | t1_phv |     | 
10036  250 | t1_phv | 250 | t2_phv
10037  300 | t1_phv |     | 
10038  350 | t1_phv |     | 
10039  400 | t1_phv | 400 | t2_phv
10040  450 | t1_phv |     | 
10041      |        |  75 | t2_phv
10042      |        | 225 | t2_phv
10043      |        | 325 | t2_phv
10044      |        | 475 | t2_phv
10045 (14 rows)
10047 -- test FOR UPDATE; partitionwise join does not apply
10048 EXPLAIN (COSTS OFF)
10049 SELECT t1.a, t2.b FROM fprt1 t1 INNER JOIN fprt2 t2 ON (t1.a = t2.b) WHERE t1.a % 25 = 0 ORDER BY 1,2 FOR UPDATE OF t1;
10050                        QUERY PLAN                       
10051 --------------------------------------------------------
10052  LockRows
10053    ->  Nested Loop
10054          Join Filter: (t1.a = t2.b)
10055          ->  Append
10056                ->  Foreign Scan on ftprt1_p1 t1_1
10057                ->  Foreign Scan on ftprt1_p2 t1_2
10058          ->  Materialize
10059                ->  Append
10060                      ->  Foreign Scan on ftprt2_p1 t2_1
10061                      ->  Foreign Scan on ftprt2_p2 t2_2
10062 (10 rows)
10064 SELECT t1.a, t2.b FROM fprt1 t1 INNER JOIN fprt2 t2 ON (t1.a = t2.b) WHERE t1.a % 25 = 0 ORDER BY 1,2 FOR UPDATE OF t1;
10065   a  |  b  
10066 -----+-----
10067    0 |   0
10068  150 | 150
10069  250 | 250
10070  400 | 400
10071 (4 rows)
10073 RESET enable_partitionwise_join;
10074 -- ===================================================================
10075 -- test partitionwise aggregates
10076 -- ===================================================================
10077 CREATE TABLE pagg_tab (a int, b int, c text) PARTITION BY RANGE(a);
10078 CREATE TABLE pagg_tab_p1 (LIKE pagg_tab);
10079 CREATE TABLE pagg_tab_p2 (LIKE pagg_tab);
10080 CREATE TABLE pagg_tab_p3 (LIKE pagg_tab);
10081 INSERT INTO pagg_tab_p1 SELECT i % 30, i % 50, to_char(i/30, 'FM0000') FROM generate_series(1, 3000) i WHERE (i % 30) < 10;
10082 INSERT INTO pagg_tab_p2 SELECT i % 30, i % 50, to_char(i/30, 'FM0000') FROM generate_series(1, 3000) i WHERE (i % 30) < 20 and (i % 30) >= 10;
10083 INSERT INTO pagg_tab_p3 SELECT i % 30, i % 50, to_char(i/30, 'FM0000') FROM generate_series(1, 3000) i WHERE (i % 30) < 30 and (i % 30) >= 20;
10084 -- Create foreign partitions
10085 CREATE FOREIGN TABLE fpagg_tab_p1 PARTITION OF pagg_tab FOR VALUES FROM (0) TO (10) SERVER loopback OPTIONS (table_name 'pagg_tab_p1');
10086 CREATE FOREIGN TABLE fpagg_tab_p2 PARTITION OF pagg_tab FOR VALUES FROM (10) TO (20) SERVER loopback OPTIONS (table_name 'pagg_tab_p2');
10087 CREATE FOREIGN TABLE fpagg_tab_p3 PARTITION OF pagg_tab FOR VALUES FROM (20) TO (30) SERVER loopback OPTIONS (table_name 'pagg_tab_p3');
10088 ANALYZE pagg_tab;
10089 ANALYZE fpagg_tab_p1;
10090 ANALYZE fpagg_tab_p2;
10091 ANALYZE fpagg_tab_p3;
10092 -- When GROUP BY clause matches with PARTITION KEY.
10093 -- Plan with partitionwise aggregates is disabled
10094 SET enable_partitionwise_aggregate TO false;
10095 EXPLAIN (COSTS OFF)
10096 SELECT a, sum(b), min(b), count(*) FROM pagg_tab GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
10097                      QUERY PLAN                      
10098 -----------------------------------------------------
10099  GroupAggregate
10100    Group Key: pagg_tab.a
10101    Filter: (avg(pagg_tab.b) < '22'::numeric)
10102    ->  Append
10103          ->  Foreign Scan on fpagg_tab_p1 pagg_tab_1
10104          ->  Foreign Scan on fpagg_tab_p2 pagg_tab_2
10105          ->  Foreign Scan on fpagg_tab_p3 pagg_tab_3
10106 (7 rows)
10108 -- Plan with partitionwise aggregates is enabled
10109 SET enable_partitionwise_aggregate TO true;
10110 EXPLAIN (COSTS OFF)
10111 SELECT a, sum(b), min(b), count(*) FROM pagg_tab GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
10112                            QUERY PLAN                            
10113 -----------------------------------------------------------------
10114  Sort
10115    Sort Key: pagg_tab.a
10116    ->  Append
10117          ->  Foreign Scan
10118                Relations: Aggregate on (fpagg_tab_p1 pagg_tab)
10119          ->  Foreign Scan
10120                Relations: Aggregate on (fpagg_tab_p2 pagg_tab_1)
10121          ->  Foreign Scan
10122                Relations: Aggregate on (fpagg_tab_p3 pagg_tab_2)
10123 (9 rows)
10125 SELECT a, sum(b), min(b), count(*) FROM pagg_tab GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
10126  a  | sum  | min | count 
10127 ----+------+-----+-------
10128   0 | 2000 |   0 |   100
10129   1 | 2100 |   1 |   100
10130  10 | 2000 |   0 |   100
10131  11 | 2100 |   1 |   100
10132  20 | 2000 |   0 |   100
10133  21 | 2100 |   1 |   100
10134 (6 rows)
10136 -- Check with whole-row reference
10137 -- Should have all the columns in the target list for the given relation
10138 EXPLAIN (VERBOSE, COSTS OFF)
10139 SELECT a, count(t1) FROM pagg_tab t1 GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
10140                                          QUERY PLAN                                         
10141 --------------------------------------------------------------------------------------------
10142  Merge Append
10143    Sort Key: t1.a
10144    ->  GroupAggregate
10145          Output: t1.a, count(((t1.*)::pagg_tab))
10146          Group Key: t1.a
10147          Filter: (avg(t1.b) < '22'::numeric)
10148          ->  Foreign Scan on public.fpagg_tab_p1 t1
10149                Output: t1.a, t1.*, t1.b
10150                Remote SQL: SELECT a, b, c FROM public.pagg_tab_p1 ORDER BY a ASC NULLS LAST
10151    ->  GroupAggregate
10152          Output: t1_1.a, count(((t1_1.*)::pagg_tab))
10153          Group Key: t1_1.a
10154          Filter: (avg(t1_1.b) < '22'::numeric)
10155          ->  Foreign Scan on public.fpagg_tab_p2 t1_1
10156                Output: t1_1.a, t1_1.*, t1_1.b
10157                Remote SQL: SELECT a, b, c FROM public.pagg_tab_p2 ORDER BY a ASC NULLS LAST
10158    ->  GroupAggregate
10159          Output: t1_2.a, count(((t1_2.*)::pagg_tab))
10160          Group Key: t1_2.a
10161          Filter: (avg(t1_2.b) < '22'::numeric)
10162          ->  Foreign Scan on public.fpagg_tab_p3 t1_2
10163                Output: t1_2.a, t1_2.*, t1_2.b
10164                Remote SQL: SELECT a, b, c FROM public.pagg_tab_p3 ORDER BY a ASC NULLS LAST
10165 (23 rows)
10167 SELECT a, count(t1) FROM pagg_tab t1 GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
10168  a  | count 
10169 ----+-------
10170   0 |   100
10171   1 |   100
10172  10 |   100
10173  11 |   100
10174  20 |   100
10175  21 |   100
10176 (6 rows)
10178 -- When GROUP BY clause does not match with PARTITION KEY.
10179 EXPLAIN (COSTS OFF)
10180 SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b HAVING sum(a) < 700 ORDER BY 1;
10181                         QUERY PLAN                         
10182 -----------------------------------------------------------
10183  Finalize GroupAggregate
10184    Group Key: pagg_tab.b
10185    Filter: (sum(pagg_tab.a) < 700)
10186    ->  Merge Append
10187          Sort Key: pagg_tab.b
10188          ->  Partial GroupAggregate
10189                Group Key: pagg_tab.b
10190                ->  Foreign Scan on fpagg_tab_p1 pagg_tab
10191          ->  Partial GroupAggregate
10192                Group Key: pagg_tab_1.b
10193                ->  Foreign Scan on fpagg_tab_p2 pagg_tab_1
10194          ->  Partial GroupAggregate
10195                Group Key: pagg_tab_2.b
10196                ->  Foreign Scan on fpagg_tab_p3 pagg_tab_2
10197 (14 rows)
10199 -- ===================================================================
10200 -- access rights and superuser
10201 -- ===================================================================
10202 -- Non-superuser cannot create a FDW without a password in the connstr
10203 CREATE ROLE regress_nosuper NOSUPERUSER;
10204 GRANT USAGE ON FOREIGN DATA WRAPPER postgres_fdw TO regress_nosuper;
10205 SET ROLE regress_nosuper;
10206 SHOW is_superuser;
10207  is_superuser 
10208 --------------
10209  off
10210 (1 row)
10212 -- This will be OK, we can create the FDW
10213 DO $d$
10214     BEGIN
10215         EXECUTE $$CREATE SERVER loopback_nopw FOREIGN DATA WRAPPER postgres_fdw
10216             OPTIONS (dbname '$$||current_database()||$$',
10217                      port '$$||current_setting('port')||$$'
10218             )$$;
10219     END;
10220 $d$;
10221 -- But creation of user mappings for non-superusers should fail
10222 CREATE USER MAPPING FOR public SERVER loopback_nopw;
10223 CREATE USER MAPPING FOR CURRENT_USER SERVER loopback_nopw;
10224 CREATE FOREIGN TABLE pg_temp.ft1_nopw (
10225         c1 int NOT NULL,
10226         c2 int NOT NULL,
10227         c3 text,
10228         c4 timestamptz,
10229         c5 timestamp,
10230         c6 varchar(10),
10231         c7 char(10) default 'ft1',
10232         c8 user_enum
10233 ) SERVER loopback_nopw OPTIONS (schema_name 'public', table_name 'ft1');
10234 SELECT 1 FROM ft1_nopw LIMIT 1;
10235 ERROR:  password or GSSAPI delegated credentials required
10236 DETAIL:  Non-superusers must delegate GSSAPI credentials or provide a password in the user mapping.
10237 -- If we add a password to the connstr it'll fail, because we don't allow passwords
10238 -- in connstrs only in user mappings.
10239 ALTER SERVER loopback_nopw OPTIONS (ADD password 'dummypw');
10240 ERROR:  invalid option "password"
10241 HINT:  Perhaps you meant the option "passfile".
10242 -- If we add a password for our user mapping instead, we should get a different
10243 -- error because the password wasn't actually *used* when we run with trust auth.
10245 -- This won't work with installcheck, but neither will most of the FDW checks.
10246 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback_nopw OPTIONS (ADD password 'dummypw');
10247 SELECT 1 FROM ft1_nopw LIMIT 1;
10248 ERROR:  password or GSSAPI delegated credentials required
10249 DETAIL:  Non-superuser cannot connect if the server does not request a password or use GSSAPI with delegated credentials.
10250 HINT:  Target server's authentication method must be changed or password_required=false set in the user mapping attributes.
10251 -- Unpriv user cannot make the mapping passwordless
10252 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback_nopw OPTIONS (ADD password_required 'false');
10253 ERROR:  password_required=false is superuser-only
10254 HINT:  User mappings with the password_required option set to false may only be created or modified by the superuser.
10255 SELECT 1 FROM ft1_nopw LIMIT 1;
10256 ERROR:  password or GSSAPI delegated credentials required
10257 DETAIL:  Non-superuser cannot connect if the server does not request a password or use GSSAPI with delegated credentials.
10258 HINT:  Target server's authentication method must be changed or password_required=false set in the user mapping attributes.
10259 RESET ROLE;
10260 -- But the superuser can
10261 ALTER USER MAPPING FOR regress_nosuper SERVER loopback_nopw OPTIONS (ADD password_required 'false');
10262 SET ROLE regress_nosuper;
10263 -- Should finally work now
10264 SELECT 1 FROM ft1_nopw LIMIT 1;
10265  ?column? 
10266 ----------
10267         1
10268 (1 row)
10270 -- unpriv user also cannot set sslcert / sslkey on the user mapping
10271 -- first set password_required so we see the right error messages
10272 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback_nopw OPTIONS (SET password_required 'true');
10273 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback_nopw OPTIONS (ADD sslcert 'foo.crt');
10274 ERROR:  sslcert and sslkey are superuser-only
10275 HINT:  User mappings with the sslcert or sslkey options set may only be created or modified by the superuser.
10276 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback_nopw OPTIONS (ADD sslkey 'foo.key');
10277 ERROR:  sslcert and sslkey are superuser-only
10278 HINT:  User mappings with the sslcert or sslkey options set may only be created or modified by the superuser.
10279 -- We're done with the role named after a specific user and need to check the
10280 -- changes to the public mapping.
10281 DROP USER MAPPING FOR CURRENT_USER SERVER loopback_nopw;
10282 -- This will fail again as it'll resolve the user mapping for public, which
10283 -- lacks password_required=false
10284 SELECT 1 FROM ft1_nopw LIMIT 1;
10285 ERROR:  password or GSSAPI delegated credentials required
10286 DETAIL:  Non-superusers must delegate GSSAPI credentials or provide a password in the user mapping.
10287 RESET ROLE;
10288 -- The user mapping for public is passwordless and lacks the password_required=false
10289 -- mapping option, but will work because the current user is a superuser.
10290 SELECT 1 FROM ft1_nopw LIMIT 1;
10291  ?column? 
10292 ----------
10293         1
10294 (1 row)
10296 -- cleanup
10297 DROP USER MAPPING FOR public SERVER loopback_nopw;
10298 DROP OWNED BY regress_nosuper;
10299 DROP ROLE regress_nosuper;
10300 -- Clean-up
10301 RESET enable_partitionwise_aggregate;
10302 -- Two-phase transactions are not supported.
10303 BEGIN;
10304 SELECT count(*) FROM ft1;
10305  count 
10306 -------
10307    822
10308 (1 row)
10310 -- error here
10311 PREPARE TRANSACTION 'fdw_tpc';
10312 ERROR:  cannot PREPARE a transaction that has operated on postgres_fdw foreign tables
10313 ROLLBACK;
10314 WARNING:  there is no transaction in progress
10315 -- ===================================================================
10316 -- reestablish new connection
10317 -- ===================================================================
10318 -- Change application_name of remote connection to special one
10319 -- so that we can easily terminate the connection later.
10320 ALTER SERVER loopback OPTIONS (application_name 'fdw_retry_check');
10321 -- Make sure we have a remote connection.
10322 SELECT 1 FROM ft1 LIMIT 1;
10323  ?column? 
10324 ----------
10325         1
10326 (1 row)
10328 -- Terminate the remote connection and wait for the termination to complete.
10329 -- (If a cache flush happens, the remote connection might have already been
10330 -- dropped; so code this step in a way that doesn't fail if no connection.)
10331 DO $$ BEGIN
10332 PERFORM pg_terminate_backend(pid, 180000) FROM pg_stat_activity
10333         WHERE application_name = 'fdw_retry_check';
10334 END $$;
10335 -- This query should detect the broken connection when starting new remote
10336 -- transaction, reestablish new connection, and then succeed.
10337 BEGIN;
10338 SELECT 1 FROM ft1 LIMIT 1;
10339  ?column? 
10340 ----------
10341         1
10342 (1 row)
10344 -- If we detect the broken connection when starting a new remote
10345 -- subtransaction, we should fail instead of establishing a new connection.
10346 -- Terminate the remote connection and wait for the termination to complete.
10347 DO $$ BEGIN
10348 PERFORM pg_terminate_backend(pid, 180000) FROM pg_stat_activity
10349         WHERE application_name = 'fdw_retry_check';
10350 END $$;
10351 SAVEPOINT s;
10352 -- The text of the error might vary across platforms, so only show SQLSTATE.
10353 \set VERBOSITY sqlstate
10354 SELECT 1 FROM ft1 LIMIT 1;    -- should fail
10355 ERROR:  08006
10356 \set VERBOSITY default
10357 COMMIT;
10358 -- =============================================================================
10359 -- test connection invalidation cases and postgres_fdw_get_connections function
10360 -- =============================================================================
10361 -- Let's ensure to close all the existing cached connections.
10362 SELECT 1 FROM postgres_fdw_disconnect_all();
10363  ?column? 
10364 ----------
10365         1
10366 (1 row)
10368 -- No cached connections, so no records should be output.
10369 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10370  server_name 
10371 -------------
10372 (0 rows)
10374 -- This test case is for closing the connection in pgfdw_xact_callback
10375 BEGIN;
10376 -- Connection xact depth becomes 1 i.e. the connection is in midst of the xact.
10377 SELECT 1 FROM ft1 LIMIT 1;
10378  ?column? 
10379 ----------
10380         1
10381 (1 row)
10383 SELECT 1 FROM ft7 LIMIT 1;
10384  ?column? 
10385 ----------
10386         1
10387 (1 row)
10389 -- List all the existing cached connections. loopback and loopback3 should be
10390 -- output.
10391 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10392  server_name 
10393 -------------
10394  loopback
10395  loopback3
10396 (2 rows)
10398 -- Connections are not closed at the end of the alter and drop statements.
10399 -- That's because the connections are in midst of this xact,
10400 -- they are just marked as invalid in pgfdw_inval_callback.
10401 ALTER SERVER loopback OPTIONS (ADD use_remote_estimate 'off');
10402 DROP SERVER loopback3 CASCADE;
10403 NOTICE:  drop cascades to 2 other objects
10404 DETAIL:  drop cascades to user mapping for public on server loopback3
10405 drop cascades to foreign table ft7
10406 -- List all the existing cached connections. loopback and loopback3
10407 -- should be output as invalid connections. Also the server name for
10408 -- loopback3 should be NULL because the server was dropped.
10409 SELECT * FROM postgres_fdw_get_connections() ORDER BY 1;
10410  server_name | valid 
10411 -------------+-------
10412  loopback    | f
10413              | f
10414 (2 rows)
10416 -- The invalid connections get closed in pgfdw_xact_callback during commit.
10417 COMMIT;
10418 -- All cached connections were closed while committing above xact, so no
10419 -- records should be output.
10420 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10421  server_name 
10422 -------------
10423 (0 rows)
10425 -- =======================================================================
10426 -- test postgres_fdw_disconnect and postgres_fdw_disconnect_all functions
10427 -- =======================================================================
10428 BEGIN;
10429 -- Ensure to cache loopback connection.
10430 SELECT 1 FROM ft1 LIMIT 1;
10431  ?column? 
10432 ----------
10433         1
10434 (1 row)
10436 -- Ensure to cache loopback2 connection.
10437 SELECT 1 FROM ft6 LIMIT 1;
10438  ?column? 
10439 ----------
10440         1
10441 (1 row)
10443 -- List all the existing cached connections. loopback and loopback2 should be
10444 -- output.
10445 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10446  server_name 
10447 -------------
10448  loopback
10449  loopback2
10450 (2 rows)
10452 -- Issue a warning and return false as loopback connection is still in use and
10453 -- can not be closed.
10454 SELECT postgres_fdw_disconnect('loopback');
10455 WARNING:  cannot close connection for server "loopback" because it is still in use
10456  postgres_fdw_disconnect 
10457 -------------------------
10459 (1 row)
10461 -- List all the existing cached connections. loopback and loopback2 should be
10462 -- output.
10463 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10464  server_name 
10465 -------------
10466  loopback
10467  loopback2
10468 (2 rows)
10470 -- Return false as connections are still in use, warnings are issued.
10471 -- But disable warnings temporarily because the order of them is not stable.
10472 SET client_min_messages = 'ERROR';
10473 SELECT postgres_fdw_disconnect_all();
10474  postgres_fdw_disconnect_all 
10475 -----------------------------
10477 (1 row)
10479 RESET client_min_messages;
10480 COMMIT;
10481 -- Ensure that loopback2 connection is closed.
10482 SELECT 1 FROM postgres_fdw_disconnect('loopback2');
10483  ?column? 
10484 ----------
10485         1
10486 (1 row)
10488 SELECT server_name FROM postgres_fdw_get_connections() WHERE server_name = 'loopback2';
10489  server_name 
10490 -------------
10491 (0 rows)
10493 -- Return false as loopback2 connection is closed already.
10494 SELECT postgres_fdw_disconnect('loopback2');
10495  postgres_fdw_disconnect 
10496 -------------------------
10498 (1 row)
10500 -- Return an error as there is no foreign server with given name.
10501 SELECT postgres_fdw_disconnect('unknownserver');
10502 ERROR:  server "unknownserver" does not exist
10503 -- Let's ensure to close all the existing cached connections.
10504 SELECT 1 FROM postgres_fdw_disconnect_all();
10505  ?column? 
10506 ----------
10507         1
10508 (1 row)
10510 -- No cached connections, so no records should be output.
10511 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10512  server_name 
10513 -------------
10514 (0 rows)
10516 -- =============================================================================
10517 -- test case for having multiple cached connections for a foreign server
10518 -- =============================================================================
10519 CREATE ROLE regress_multi_conn_user1 SUPERUSER;
10520 CREATE ROLE regress_multi_conn_user2 SUPERUSER;
10521 CREATE USER MAPPING FOR regress_multi_conn_user1 SERVER loopback;
10522 CREATE USER MAPPING FOR regress_multi_conn_user2 SERVER loopback;
10523 BEGIN;
10524 -- Will cache loopback connection with user mapping for regress_multi_conn_user1
10525 SET ROLE regress_multi_conn_user1;
10526 SELECT 1 FROM ft1 LIMIT 1;
10527  ?column? 
10528 ----------
10529         1
10530 (1 row)
10532 RESET ROLE;
10533 -- Will cache loopback connection with user mapping for regress_multi_conn_user2
10534 SET ROLE regress_multi_conn_user2;
10535 SELECT 1 FROM ft1 LIMIT 1;
10536  ?column? 
10537 ----------
10538         1
10539 (1 row)
10541 RESET ROLE;
10542 -- Should output two connections for loopback server
10543 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10544  server_name 
10545 -------------
10546  loopback
10547  loopback
10548 (2 rows)
10550 COMMIT;
10551 -- Let's ensure to close all the existing cached connections.
10552 SELECT 1 FROM postgres_fdw_disconnect_all();
10553  ?column? 
10554 ----------
10555         1
10556 (1 row)
10558 -- No cached connections, so no records should be output.
10559 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10560  server_name 
10561 -------------
10562 (0 rows)
10564 -- Clean up
10565 DROP USER MAPPING FOR regress_multi_conn_user1 SERVER loopback;
10566 DROP USER MAPPING FOR regress_multi_conn_user2 SERVER loopback;
10567 DROP ROLE regress_multi_conn_user1;
10568 DROP ROLE regress_multi_conn_user2;
10569 -- ===================================================================
10570 -- Test foreign server level option keep_connections
10571 -- ===================================================================
10572 -- By default, the connections associated with foreign server are cached i.e.
10573 -- keep_connections option is on. Set it to off.
10574 ALTER SERVER loopback OPTIONS (keep_connections 'off');
10575 -- connection to loopback server is closed at the end of xact
10576 -- as keep_connections was set to off.
10577 SELECT 1 FROM ft1 LIMIT 1;
10578  ?column? 
10579 ----------
10580         1
10581 (1 row)
10583 -- No cached connections, so no records should be output.
10584 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10585  server_name 
10586 -------------
10587 (0 rows)
10589 ALTER SERVER loopback OPTIONS (SET keep_connections 'on');
10590 -- ===================================================================
10591 -- batch insert
10592 -- ===================================================================
10593 BEGIN;
10594 CREATE SERVER batch10 FOREIGN DATA WRAPPER postgres_fdw OPTIONS( batch_size '10' );
10595 SELECT count(*)
10596 FROM pg_foreign_server
10597 WHERE srvname = 'batch10'
10598 AND srvoptions @> array['batch_size=10'];
10599  count 
10600 -------
10601      1
10602 (1 row)
10604 ALTER SERVER batch10 OPTIONS( SET batch_size '20' );
10605 SELECT count(*)
10606 FROM pg_foreign_server
10607 WHERE srvname = 'batch10'
10608 AND srvoptions @> array['batch_size=10'];
10609  count 
10610 -------
10611      0
10612 (1 row)
10614 SELECT count(*)
10615 FROM pg_foreign_server
10616 WHERE srvname = 'batch10'
10617 AND srvoptions @> array['batch_size=20'];
10618  count 
10619 -------
10620      1
10621 (1 row)
10623 CREATE FOREIGN TABLE table30 ( x int ) SERVER batch10 OPTIONS ( batch_size '30' );
10624 SELECT COUNT(*)
10625 FROM pg_foreign_table
10626 WHERE ftrelid = 'table30'::regclass
10627 AND ftoptions @> array['batch_size=30'];
10628  count 
10629 -------
10630      1
10631 (1 row)
10633 ALTER FOREIGN TABLE table30 OPTIONS ( SET batch_size '40');
10634 SELECT COUNT(*)
10635 FROM pg_foreign_table
10636 WHERE ftrelid = 'table30'::regclass
10637 AND ftoptions @> array['batch_size=30'];
10638  count 
10639 -------
10640      0
10641 (1 row)
10643 SELECT COUNT(*)
10644 FROM pg_foreign_table
10645 WHERE ftrelid = 'table30'::regclass
10646 AND ftoptions @> array['batch_size=40'];
10647  count 
10648 -------
10649      1
10650 (1 row)
10652 ROLLBACK;
10653 CREATE TABLE batch_table ( x int );
10654 CREATE FOREIGN TABLE ftable ( x int ) SERVER loopback OPTIONS ( table_name 'batch_table', batch_size '10' );
10655 EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable SELECT * FROM generate_series(1, 10) i;
10656                          QUERY PLAN                          
10657 -------------------------------------------------------------
10658  Insert on public.ftable
10659    Remote SQL: INSERT INTO public.batch_table(x) VALUES ($1)
10660    Batch Size: 10
10661    ->  Function Scan on pg_catalog.generate_series i
10662          Output: i.i
10663          Function Call: generate_series(1, 10)
10664 (6 rows)
10666 INSERT INTO ftable SELECT * FROM generate_series(1, 10) i;
10667 INSERT INTO ftable SELECT * FROM generate_series(11, 31) i;
10668 INSERT INTO ftable VALUES (32);
10669 INSERT INTO ftable VALUES (33), (34);
10670 SELECT COUNT(*) FROM ftable;
10671  count 
10672 -------
10673     34
10674 (1 row)
10676 TRUNCATE batch_table;
10677 DROP FOREIGN TABLE ftable;
10678 -- Disable batch insert
10679 CREATE FOREIGN TABLE ftable ( x int ) SERVER loopback OPTIONS ( table_name 'batch_table', batch_size '1' );
10680 EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable VALUES (1), (2);
10681                          QUERY PLAN                          
10682 -------------------------------------------------------------
10683  Insert on public.ftable
10684    Remote SQL: INSERT INTO public.batch_table(x) VALUES ($1)
10685    Batch Size: 1
10686    ->  Values Scan on "*VALUES*"
10687          Output: "*VALUES*".column1
10688 (5 rows)
10690 INSERT INTO ftable VALUES (1), (2);
10691 SELECT COUNT(*) FROM ftable;
10692  count 
10693 -------
10694      2
10695 (1 row)
10697 -- Disable batch inserting into foreign tables with BEFORE ROW INSERT triggers
10698 -- even if the batch_size option is enabled.
10699 ALTER FOREIGN TABLE ftable OPTIONS ( SET batch_size '10' );
10700 CREATE TRIGGER trig_row_before BEFORE INSERT ON ftable
10701 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
10702 EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable VALUES (3), (4);
10703                          QUERY PLAN                          
10704 -------------------------------------------------------------
10705  Insert on public.ftable
10706    Remote SQL: INSERT INTO public.batch_table(x) VALUES ($1)
10707    Batch Size: 1
10708    ->  Values Scan on "*VALUES*"
10709          Output: "*VALUES*".column1
10710 (5 rows)
10712 INSERT INTO ftable VALUES (3), (4);
10713 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON ftable
10714 NOTICE:  NEW: (3)
10715 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON ftable
10716 NOTICE:  NEW: (4)
10717 SELECT COUNT(*) FROM ftable;
10718  count 
10719 -------
10720      4
10721 (1 row)
10723 -- Clean up
10724 DROP TRIGGER trig_row_before ON ftable;
10725 DROP FOREIGN TABLE ftable;
10726 DROP TABLE batch_table;
10727 -- Use partitioning
10728 CREATE TABLE batch_table ( x int ) PARTITION BY HASH (x);
10729 CREATE TABLE batch_table_p0 (LIKE batch_table);
10730 CREATE FOREIGN TABLE batch_table_p0f
10731         PARTITION OF batch_table
10732         FOR VALUES WITH (MODULUS 3, REMAINDER 0)
10733         SERVER loopback
10734         OPTIONS (table_name 'batch_table_p0', batch_size '10');
10735 CREATE TABLE batch_table_p1 (LIKE batch_table);
10736 CREATE FOREIGN TABLE batch_table_p1f
10737         PARTITION OF batch_table
10738         FOR VALUES WITH (MODULUS 3, REMAINDER 1)
10739         SERVER loopback
10740         OPTIONS (table_name 'batch_table_p1', batch_size '1');
10741 CREATE TABLE batch_table_p2
10742         PARTITION OF batch_table
10743         FOR VALUES WITH (MODULUS 3, REMAINDER 2);
10744 INSERT INTO batch_table SELECT * FROM generate_series(1, 66) i;
10745 SELECT COUNT(*) FROM batch_table;
10746  count 
10747 -------
10748     66
10749 (1 row)
10751 -- Clean up
10752 DROP TABLE batch_table;
10753 DROP TABLE batch_table_p0;
10754 DROP TABLE batch_table_p1;
10755 -- Check that batched mode also works for some inserts made during
10756 -- cross-partition updates
10757 CREATE TABLE batch_cp_upd_test (a int) PARTITION BY LIST (a);
10758 CREATE TABLE batch_cp_upd_test1 (LIKE batch_cp_upd_test);
10759 CREATE FOREIGN TABLE batch_cp_upd_test1_f
10760         PARTITION OF batch_cp_upd_test
10761         FOR VALUES IN (1)
10762         SERVER loopback
10763         OPTIONS (table_name 'batch_cp_upd_test1', batch_size '10');
10764 CREATE TABLE batch_cp_upd_test2 PARTITION OF batch_cp_upd_test
10765         FOR VALUES IN (2);
10766 CREATE TABLE batch_cp_upd_test3 (LIKE batch_cp_upd_test);
10767 CREATE FOREIGN TABLE batch_cp_upd_test3_f
10768         PARTITION OF batch_cp_upd_test
10769         FOR VALUES IN (3)
10770         SERVER loopback
10771         OPTIONS (table_name 'batch_cp_upd_test3', batch_size '1');
10772 -- Create statement triggers on remote tables that "log" any INSERTs
10773 -- performed on them.
10774 CREATE TABLE cmdlog (cmd text);
10775 CREATE FUNCTION log_stmt() RETURNS TRIGGER LANGUAGE plpgsql AS $$
10776         BEGIN INSERT INTO public.cmdlog VALUES (TG_OP || ' on ' || TG_RELNAME); RETURN NULL; END;
10778 CREATE TRIGGER stmt_trig AFTER INSERT ON batch_cp_upd_test1
10779         FOR EACH STATEMENT EXECUTE FUNCTION log_stmt();
10780 CREATE TRIGGER stmt_trig AFTER INSERT ON batch_cp_upd_test3
10781         FOR EACH STATEMENT EXECUTE FUNCTION log_stmt();
10782 -- This update moves rows from the local partition 'batch_cp_upd_test2' to the
10783 -- foreign partition 'batch_cp_upd_test1', one that has insert batching
10784 -- enabled, so a single INSERT for both rows.
10785 INSERT INTO batch_cp_upd_test VALUES (2), (2);
10786 UPDATE batch_cp_upd_test t SET a = 1 FROM (VALUES (1), (2)) s(a) WHERE t.a = s.a AND s.a = 2;
10787 -- This one moves rows from the local partition 'batch_cp_upd_test2' to the
10788 -- foreign partition 'batch_cp_upd_test2', one that has insert batching
10789 -- disabled, so separate INSERTs for the two rows.
10790 INSERT INTO batch_cp_upd_test VALUES (2), (2);
10791 UPDATE batch_cp_upd_test t SET a = 3 FROM (VALUES (1), (2)) s(a) WHERE t.a = s.a AND s.a = 2;
10792 SELECT tableoid::regclass, * FROM batch_cp_upd_test ORDER BY 1;
10793        tableoid       | a 
10794 ----------------------+---
10795  batch_cp_upd_test1_f | 1
10796  batch_cp_upd_test1_f | 1
10797  batch_cp_upd_test3_f | 3
10798  batch_cp_upd_test3_f | 3
10799 (4 rows)
10801 -- Should see 1 INSERT on batch_cp_upd_test1 and 2 on batch_cp_upd_test3 as
10802 -- described above.
10803 SELECT * FROM cmdlog ORDER BY 1;
10804              cmd              
10805 ------------------------------
10806  INSERT on batch_cp_upd_test1
10807  INSERT on batch_cp_upd_test3
10808  INSERT on batch_cp_upd_test3
10809 (3 rows)
10811 -- Clean up
10812 DROP TABLE batch_cp_upd_test;
10813 DROP TABLE batch_cp_upd_test1;
10814 DROP TABLE batch_cp_upd_test3;
10815 DROP TABLE cmdlog;
10816 DROP FUNCTION log_stmt();
10817 -- Use partitioning
10818 ALTER SERVER loopback OPTIONS (ADD batch_size '10');
10819 CREATE TABLE batch_table ( x int, field1 text, field2 text) PARTITION BY HASH (x);
10820 CREATE TABLE batch_table_p0 (LIKE batch_table);
10821 ALTER TABLE batch_table_p0 ADD CONSTRAINT p0_pkey PRIMARY KEY (x);
10822 CREATE FOREIGN TABLE batch_table_p0f
10823         PARTITION OF batch_table
10824         FOR VALUES WITH (MODULUS 2, REMAINDER 0)
10825         SERVER loopback
10826         OPTIONS (table_name 'batch_table_p0');
10827 CREATE TABLE batch_table_p1 (LIKE batch_table);
10828 ALTER TABLE batch_table_p1 ADD CONSTRAINT p1_pkey PRIMARY KEY (x);
10829 CREATE FOREIGN TABLE batch_table_p1f
10830         PARTITION OF batch_table
10831         FOR VALUES WITH (MODULUS 2, REMAINDER 1)
10832         SERVER loopback
10833         OPTIONS (table_name 'batch_table_p1');
10834 INSERT INTO batch_table SELECT i, 'test'||i, 'test'|| i FROM generate_series(1, 50) i;
10835 SELECT COUNT(*) FROM batch_table;
10836  count 
10837 -------
10838     50
10839 (1 row)
10841 SELECT * FROM batch_table ORDER BY x;
10842  x  | field1 | field2 
10843 ----+--------+--------
10844   1 | test1  | test1
10845   2 | test2  | test2
10846   3 | test3  | test3
10847   4 | test4  | test4
10848   5 | test5  | test5
10849   6 | test6  | test6
10850   7 | test7  | test7
10851   8 | test8  | test8
10852   9 | test9  | test9
10853  10 | test10 | test10
10854  11 | test11 | test11
10855  12 | test12 | test12
10856  13 | test13 | test13
10857  14 | test14 | test14
10858  15 | test15 | test15
10859  16 | test16 | test16
10860  17 | test17 | test17
10861  18 | test18 | test18
10862  19 | test19 | test19
10863  20 | test20 | test20
10864  21 | test21 | test21
10865  22 | test22 | test22
10866  23 | test23 | test23
10867  24 | test24 | test24
10868  25 | test25 | test25
10869  26 | test26 | test26
10870  27 | test27 | test27
10871  28 | test28 | test28
10872  29 | test29 | test29
10873  30 | test30 | test30
10874  31 | test31 | test31
10875  32 | test32 | test32
10876  33 | test33 | test33
10877  34 | test34 | test34
10878  35 | test35 | test35
10879  36 | test36 | test36
10880  37 | test37 | test37
10881  38 | test38 | test38
10882  39 | test39 | test39
10883  40 | test40 | test40
10884  41 | test41 | test41
10885  42 | test42 | test42
10886  43 | test43 | test43
10887  44 | test44 | test44
10888  45 | test45 | test45
10889  46 | test46 | test46
10890  47 | test47 | test47
10891  48 | test48 | test48
10892  49 | test49 | test49
10893  50 | test50 | test50
10894 (50 rows)
10896 -- Clean up
10897 DROP TABLE batch_table;
10898 DROP TABLE batch_table_p0;
10899 DROP TABLE batch_table_p1;
10900 ALTER SERVER loopback OPTIONS (DROP batch_size);
10901 -- Test that pending inserts are handled properly when needed
10902 CREATE TABLE batch_table (a text, b int);
10903 CREATE FOREIGN TABLE ftable (a text, b int)
10904         SERVER loopback
10905         OPTIONS (table_name 'batch_table', batch_size '2');
10906 CREATE TABLE ltable (a text, b int);
10907 CREATE FUNCTION ftable_rowcount_trigf() RETURNS trigger LANGUAGE plpgsql AS
10909 begin
10910         raise notice '%: there are % rows in ftable',
10911                 TG_NAME, (SELECT count(*) FROM ftable);
10912         if TG_OP = 'DELETE' then
10913                 return OLD;
10914         else
10915                 return NEW;
10916         end if;
10917 end;
10919 CREATE TRIGGER ftable_rowcount_trigger
10920 BEFORE INSERT OR UPDATE OR DELETE ON ltable
10921 FOR EACH ROW EXECUTE PROCEDURE ftable_rowcount_trigf();
10922 WITH t AS (
10923         INSERT INTO ltable VALUES ('AAA', 42), ('BBB', 42) RETURNING *
10925 INSERT INTO ftable SELECT * FROM t;
10926 NOTICE:  ftable_rowcount_trigger: there are 0 rows in ftable
10927 NOTICE:  ftable_rowcount_trigger: there are 1 rows in ftable
10928 SELECT * FROM ltable;
10929   a  | b  
10930 -----+----
10931  AAA | 42
10932  BBB | 42
10933 (2 rows)
10935 SELECT * FROM ftable;
10936   a  | b  
10937 -----+----
10938  AAA | 42
10939  BBB | 42
10940 (2 rows)
10942 DELETE FROM ftable;
10943 WITH t AS (
10944         UPDATE ltable SET b = b + 100 RETURNING *
10946 INSERT INTO ftable SELECT * FROM t;
10947 NOTICE:  ftable_rowcount_trigger: there are 0 rows in ftable
10948 NOTICE:  ftable_rowcount_trigger: there are 1 rows in ftable
10949 SELECT * FROM ltable;
10950   a  |  b  
10951 -----+-----
10952  AAA | 142
10953  BBB | 142
10954 (2 rows)
10956 SELECT * FROM ftable;
10957   a  |  b  
10958 -----+-----
10959  AAA | 142
10960  BBB | 142
10961 (2 rows)
10963 DELETE FROM ftable;
10964 WITH t AS (
10965         DELETE FROM ltable RETURNING *
10967 INSERT INTO ftable SELECT * FROM t;
10968 NOTICE:  ftable_rowcount_trigger: there are 0 rows in ftable
10969 NOTICE:  ftable_rowcount_trigger: there are 1 rows in ftable
10970 SELECT * FROM ltable;
10971  a | b 
10972 ---+---
10973 (0 rows)
10975 SELECT * FROM ftable;
10976   a  |  b  
10977 -----+-----
10978  AAA | 142
10979  BBB | 142
10980 (2 rows)
10982 DELETE FROM ftable;
10983 -- Clean up
10984 DROP FOREIGN TABLE ftable;
10985 DROP TABLE batch_table;
10986 DROP TRIGGER ftable_rowcount_trigger ON ltable;
10987 DROP TABLE ltable;
10988 CREATE TABLE parent (a text, b int) PARTITION BY LIST (a);
10989 CREATE TABLE batch_table (a text, b int);
10990 CREATE FOREIGN TABLE ftable
10991         PARTITION OF parent
10992         FOR VALUES IN ('AAA')
10993         SERVER loopback
10994         OPTIONS (table_name 'batch_table', batch_size '2');
10995 CREATE TABLE ltable
10996         PARTITION OF parent
10997         FOR VALUES IN ('BBB');
10998 CREATE TRIGGER ftable_rowcount_trigger
10999 BEFORE INSERT ON ltable
11000 FOR EACH ROW EXECUTE PROCEDURE ftable_rowcount_trigf();
11001 INSERT INTO parent VALUES ('AAA', 42), ('BBB', 42), ('AAA', 42), ('BBB', 42);
11002 NOTICE:  ftable_rowcount_trigger: there are 1 rows in ftable
11003 NOTICE:  ftable_rowcount_trigger: there are 2 rows in ftable
11004 SELECT tableoid::regclass, * FROM parent;
11005  tableoid |  a  | b  
11006 ----------+-----+----
11007  ftable   | AAA | 42
11008  ftable   | AAA | 42
11009  ltable   | BBB | 42
11010  ltable   | BBB | 42
11011 (4 rows)
11013 -- Clean up
11014 DROP FOREIGN TABLE ftable;
11015 DROP TABLE batch_table;
11016 DROP TRIGGER ftable_rowcount_trigger ON ltable;
11017 DROP TABLE ltable;
11018 DROP TABLE parent;
11019 DROP FUNCTION ftable_rowcount_trigf;
11020 -- ===================================================================
11021 -- test asynchronous execution
11022 -- ===================================================================
11023 ALTER SERVER loopback OPTIONS (DROP extensions);
11024 ALTER SERVER loopback OPTIONS (ADD async_capable 'true');
11025 ALTER SERVER loopback2 OPTIONS (ADD async_capable 'true');
11026 CREATE TABLE async_pt (a int, b int, c text) PARTITION BY RANGE (a);
11027 CREATE TABLE base_tbl1 (a int, b int, c text);
11028 CREATE TABLE base_tbl2 (a int, b int, c text);
11029 CREATE FOREIGN TABLE async_p1 PARTITION OF async_pt FOR VALUES FROM (1000) TO (2000)
11030   SERVER loopback OPTIONS (table_name 'base_tbl1');
11031 CREATE FOREIGN TABLE async_p2 PARTITION OF async_pt FOR VALUES FROM (2000) TO (3000)
11032   SERVER loopback2 OPTIONS (table_name 'base_tbl2');
11033 INSERT INTO async_p1 SELECT 1000 + i, i, to_char(i, 'FM0000') FROM generate_series(0, 999, 5) i;
11034 INSERT INTO async_p2 SELECT 2000 + i, i, to_char(i, 'FM0000') FROM generate_series(0, 999, 5) i;
11035 ANALYZE async_pt;
11036 -- simple queries
11037 CREATE TABLE result_tbl (a int, b int, c text);
11038 EXPLAIN (VERBOSE, COSTS OFF)
11039 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b % 100 = 0;
11040                                        QUERY PLAN                                       
11041 ----------------------------------------------------------------------------------------
11042  Insert on public.result_tbl
11043    ->  Append
11044          ->  Async Foreign Scan on public.async_p1 async_pt_1
11045                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11046                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE (((b % 100) = 0))
11047          ->  Async Foreign Scan on public.async_p2 async_pt_2
11048                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11049                Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE (((b % 100) = 0))
11050 (8 rows)
11052 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b % 100 = 0;
11053 SELECT * FROM result_tbl ORDER BY a;
11054   a   |  b  |  c   
11055 ------+-----+------
11056  1000 |   0 | 0000
11057  1100 | 100 | 0100
11058  1200 | 200 | 0200
11059  1300 | 300 | 0300
11060  1400 | 400 | 0400
11061  1500 | 500 | 0500
11062  1600 | 600 | 0600
11063  1700 | 700 | 0700
11064  1800 | 800 | 0800
11065  1900 | 900 | 0900
11066  2000 |   0 | 0000
11067  2100 | 100 | 0100
11068  2200 | 200 | 0200
11069  2300 | 300 | 0300
11070  2400 | 400 | 0400
11071  2500 | 500 | 0500
11072  2600 | 600 | 0600
11073  2700 | 700 | 0700
11074  2800 | 800 | 0800
11075  2900 | 900 | 0900
11076 (20 rows)
11078 DELETE FROM result_tbl;
11079 EXPLAIN (VERBOSE, COSTS OFF)
11080 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b === 505;
11081                            QUERY PLAN                           
11082 ----------------------------------------------------------------
11083  Insert on public.result_tbl
11084    ->  Append
11085          ->  Async Foreign Scan on public.async_p1 async_pt_1
11086                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11087                Filter: (async_pt_1.b === 505)
11088                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11089          ->  Async Foreign Scan on public.async_p2 async_pt_2
11090                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11091                Filter: (async_pt_2.b === 505)
11092                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11093 (10 rows)
11095 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b === 505;
11096 SELECT * FROM result_tbl ORDER BY a;
11097   a   |  b  |  c   
11098 ------+-----+------
11099  1505 | 505 | 0505
11100  2505 | 505 | 0505
11101 (2 rows)
11103 DELETE FROM result_tbl;
11104 EXPLAIN (VERBOSE, COSTS OFF)
11105 INSERT INTO result_tbl SELECT a, b, 'AAA' || c FROM async_pt WHERE b === 505;
11106                                    QUERY PLAN                                    
11107 ---------------------------------------------------------------------------------
11108  Insert on public.result_tbl
11109    ->  Append
11110          ->  Async Foreign Scan on public.async_p1 async_pt_1
11111                Output: async_pt_1.a, async_pt_1.b, ('AAA'::text || async_pt_1.c)
11112                Filter: (async_pt_1.b === 505)
11113                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11114          ->  Async Foreign Scan on public.async_p2 async_pt_2
11115                Output: async_pt_2.a, async_pt_2.b, ('AAA'::text || async_pt_2.c)
11116                Filter: (async_pt_2.b === 505)
11117                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11118 (10 rows)
11120 INSERT INTO result_tbl SELECT a, b, 'AAA' || c FROM async_pt WHERE b === 505;
11121 SELECT * FROM result_tbl ORDER BY a;
11122   a   |  b  |    c    
11123 ------+-----+---------
11124  1505 | 505 | AAA0505
11125  2505 | 505 | AAA0505
11126 (2 rows)
11128 DELETE FROM result_tbl;
11129 -- Test error handling, if accessing one of the foreign partitions errors out
11130 CREATE FOREIGN TABLE async_p_broken PARTITION OF async_pt FOR VALUES FROM (10000) TO (10001)
11131   SERVER loopback OPTIONS (table_name 'non_existent_table');
11132 SELECT * FROM async_pt;
11133 ERROR:  relation "public.non_existent_table" does not exist
11134 CONTEXT:  remote SQL command: SELECT a, b, c FROM public.non_existent_table
11135 DROP FOREIGN TABLE async_p_broken;
11136 -- Check case where multiple partitions use the same connection
11137 CREATE TABLE base_tbl3 (a int, b int, c text);
11138 CREATE FOREIGN TABLE async_p3 PARTITION OF async_pt FOR VALUES FROM (3000) TO (4000)
11139   SERVER loopback2 OPTIONS (table_name 'base_tbl3');
11140 INSERT INTO async_p3 SELECT 3000 + i, i, to_char(i, 'FM0000') FROM generate_series(0, 999, 5) i;
11141 ANALYZE async_pt;
11142 EXPLAIN (VERBOSE, COSTS OFF)
11143 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b === 505;
11144                            QUERY PLAN                           
11145 ----------------------------------------------------------------
11146  Insert on public.result_tbl
11147    ->  Append
11148          ->  Async Foreign Scan on public.async_p1 async_pt_1
11149                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11150                Filter: (async_pt_1.b === 505)
11151                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11152          ->  Async Foreign Scan on public.async_p2 async_pt_2
11153                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11154                Filter: (async_pt_2.b === 505)
11155                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11156          ->  Async Foreign Scan on public.async_p3 async_pt_3
11157                Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
11158                Filter: (async_pt_3.b === 505)
11159                Remote SQL: SELECT a, b, c FROM public.base_tbl3
11160 (14 rows)
11162 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b === 505;
11163 SELECT * FROM result_tbl ORDER BY a;
11164   a   |  b  |  c   
11165 ------+-----+------
11166  1505 | 505 | 0505
11167  2505 | 505 | 0505
11168  3505 | 505 | 0505
11169 (3 rows)
11171 DELETE FROM result_tbl;
11172 DROP FOREIGN TABLE async_p3;
11173 DROP TABLE base_tbl3;
11174 -- Check case where the partitioned table has local/remote partitions
11175 CREATE TABLE async_p3 PARTITION OF async_pt FOR VALUES FROM (3000) TO (4000);
11176 INSERT INTO async_p3 SELECT 3000 + i, i, to_char(i, 'FM0000') FROM generate_series(0, 999, 5) i;
11177 ANALYZE async_pt;
11178 EXPLAIN (VERBOSE, COSTS OFF)
11179 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b === 505;
11180                            QUERY PLAN                           
11181 ----------------------------------------------------------------
11182  Insert on public.result_tbl
11183    ->  Append
11184          ->  Async Foreign Scan on public.async_p1 async_pt_1
11185                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11186                Filter: (async_pt_1.b === 505)
11187                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11188          ->  Async Foreign Scan on public.async_p2 async_pt_2
11189                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11190                Filter: (async_pt_2.b === 505)
11191                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11192          ->  Seq Scan on public.async_p3 async_pt_3
11193                Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
11194                Filter: (async_pt_3.b === 505)
11195 (13 rows)
11197 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b === 505;
11198 SELECT * FROM result_tbl ORDER BY a;
11199   a   |  b  |  c   
11200 ------+-----+------
11201  1505 | 505 | 0505
11202  2505 | 505 | 0505
11203  3505 | 505 | 0505
11204 (3 rows)
11206 DELETE FROM result_tbl;
11207 -- partitionwise joins
11208 SET enable_partitionwise_join TO true;
11209 CREATE TABLE join_tbl (a1 int, b1 int, c1 text, a2 int, b2 int, c2 text);
11210 EXPLAIN (VERBOSE, COSTS OFF)
11211 INSERT INTO join_tbl SELECT * FROM async_pt t1, async_pt t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.b % 100 = 0;
11212                                                                                            QUERY PLAN                                                                                            
11213 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
11214  Insert on public.join_tbl
11215    ->  Append
11216          ->  Async Foreign Scan
11217                Output: t1_1.a, t1_1.b, t1_1.c, t2_1.a, t2_1.b, t2_1.c
11218                Relations: (public.async_p1 t1_1) INNER JOIN (public.async_p1 t2_1)
11219                Remote SQL: SELECT r5.a, r5.b, r5.c, r8.a, r8.b, r8.c FROM (public.base_tbl1 r5 INNER JOIN public.base_tbl1 r8 ON (((r5.a = r8.a)) AND ((r5.b = r8.b)) AND (((r5.b % 100) = 0))))
11220          ->  Async Foreign Scan
11221                Output: t1_2.a, t1_2.b, t1_2.c, t2_2.a, t2_2.b, t2_2.c
11222                Relations: (public.async_p2 t1_2) INNER JOIN (public.async_p2 t2_2)
11223                Remote SQL: SELECT r6.a, r6.b, r6.c, r9.a, r9.b, r9.c FROM (public.base_tbl2 r6 INNER JOIN public.base_tbl2 r9 ON (((r6.a = r9.a)) AND ((r6.b = r9.b)) AND (((r6.b % 100) = 0))))
11224          ->  Hash Join
11225                Output: t1_3.a, t1_3.b, t1_3.c, t2_3.a, t2_3.b, t2_3.c
11226                Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.b = t1_3.b))
11227                ->  Seq Scan on public.async_p3 t2_3
11228                      Output: t2_3.a, t2_3.b, t2_3.c
11229                ->  Hash
11230                      Output: t1_3.a, t1_3.b, t1_3.c
11231                      ->  Seq Scan on public.async_p3 t1_3
11232                            Output: t1_3.a, t1_3.b, t1_3.c
11233                            Filter: ((t1_3.b % 100) = 0)
11234 (20 rows)
11236 INSERT INTO join_tbl SELECT * FROM async_pt t1, async_pt t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.b % 100 = 0;
11237 SELECT * FROM join_tbl ORDER BY a1;
11238   a1  | b1  |  c1  |  a2  | b2  |  c2  
11239 ------+-----+------+------+-----+------
11240  1000 |   0 | 0000 | 1000 |   0 | 0000
11241  1100 | 100 | 0100 | 1100 | 100 | 0100
11242  1200 | 200 | 0200 | 1200 | 200 | 0200
11243  1300 | 300 | 0300 | 1300 | 300 | 0300
11244  1400 | 400 | 0400 | 1400 | 400 | 0400
11245  1500 | 500 | 0500 | 1500 | 500 | 0500
11246  1600 | 600 | 0600 | 1600 | 600 | 0600
11247  1700 | 700 | 0700 | 1700 | 700 | 0700
11248  1800 | 800 | 0800 | 1800 | 800 | 0800
11249  1900 | 900 | 0900 | 1900 | 900 | 0900
11250  2000 |   0 | 0000 | 2000 |   0 | 0000
11251  2100 | 100 | 0100 | 2100 | 100 | 0100
11252  2200 | 200 | 0200 | 2200 | 200 | 0200
11253  2300 | 300 | 0300 | 2300 | 300 | 0300
11254  2400 | 400 | 0400 | 2400 | 400 | 0400
11255  2500 | 500 | 0500 | 2500 | 500 | 0500
11256  2600 | 600 | 0600 | 2600 | 600 | 0600
11257  2700 | 700 | 0700 | 2700 | 700 | 0700
11258  2800 | 800 | 0800 | 2800 | 800 | 0800
11259  2900 | 900 | 0900 | 2900 | 900 | 0900
11260  3000 |   0 | 0000 | 3000 |   0 | 0000
11261  3100 | 100 | 0100 | 3100 | 100 | 0100
11262  3200 | 200 | 0200 | 3200 | 200 | 0200
11263  3300 | 300 | 0300 | 3300 | 300 | 0300
11264  3400 | 400 | 0400 | 3400 | 400 | 0400
11265  3500 | 500 | 0500 | 3500 | 500 | 0500
11266  3600 | 600 | 0600 | 3600 | 600 | 0600
11267  3700 | 700 | 0700 | 3700 | 700 | 0700
11268  3800 | 800 | 0800 | 3800 | 800 | 0800
11269  3900 | 900 | 0900 | 3900 | 900 | 0900
11270 (30 rows)
11272 DELETE FROM join_tbl;
11273 EXPLAIN (VERBOSE, COSTS OFF)
11274 INSERT INTO join_tbl SELECT t1.a, t1.b, 'AAA' || t1.c, t2.a, t2.b, 'AAA' || t2.c FROM async_pt t1, async_pt t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.b % 100 = 0;
11275                                                                                            QUERY PLAN                                                                                            
11276 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
11277  Insert on public.join_tbl
11278    ->  Append
11279          ->  Async Foreign Scan
11280                Output: t1_1.a, t1_1.b, ('AAA'::text || t1_1.c), t2_1.a, t2_1.b, ('AAA'::text || t2_1.c)
11281                Relations: (public.async_p1 t1_1) INNER JOIN (public.async_p1 t2_1)
11282                Remote SQL: SELECT r5.a, r5.b, r5.c, r8.a, r8.b, r8.c FROM (public.base_tbl1 r5 INNER JOIN public.base_tbl1 r8 ON (((r5.a = r8.a)) AND ((r5.b = r8.b)) AND (((r5.b % 100) = 0))))
11283          ->  Async Foreign Scan
11284                Output: t1_2.a, t1_2.b, ('AAA'::text || t1_2.c), t2_2.a, t2_2.b, ('AAA'::text || t2_2.c)
11285                Relations: (public.async_p2 t1_2) INNER JOIN (public.async_p2 t2_2)
11286                Remote SQL: SELECT r6.a, r6.b, r6.c, r9.a, r9.b, r9.c FROM (public.base_tbl2 r6 INNER JOIN public.base_tbl2 r9 ON (((r6.a = r9.a)) AND ((r6.b = r9.b)) AND (((r6.b % 100) = 0))))
11287          ->  Hash Join
11288                Output: t1_3.a, t1_3.b, ('AAA'::text || t1_3.c), t2_3.a, t2_3.b, ('AAA'::text || t2_3.c)
11289                Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.b = t1_3.b))
11290                ->  Seq Scan on public.async_p3 t2_3
11291                      Output: t2_3.a, t2_3.b, t2_3.c
11292                ->  Hash
11293                      Output: t1_3.a, t1_3.b, t1_3.c
11294                      ->  Seq Scan on public.async_p3 t1_3
11295                            Output: t1_3.a, t1_3.b, t1_3.c
11296                            Filter: ((t1_3.b % 100) = 0)
11297 (20 rows)
11299 INSERT INTO join_tbl SELECT t1.a, t1.b, 'AAA' || t1.c, t2.a, t2.b, 'AAA' || t2.c FROM async_pt t1, async_pt t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.b % 100 = 0;
11300 SELECT * FROM join_tbl ORDER BY a1;
11301   a1  | b1  |   c1    |  a2  | b2  |   c2    
11302 ------+-----+---------+------+-----+---------
11303  1000 |   0 | AAA0000 | 1000 |   0 | AAA0000
11304  1100 | 100 | AAA0100 | 1100 | 100 | AAA0100
11305  1200 | 200 | AAA0200 | 1200 | 200 | AAA0200
11306  1300 | 300 | AAA0300 | 1300 | 300 | AAA0300
11307  1400 | 400 | AAA0400 | 1400 | 400 | AAA0400
11308  1500 | 500 | AAA0500 | 1500 | 500 | AAA0500
11309  1600 | 600 | AAA0600 | 1600 | 600 | AAA0600
11310  1700 | 700 | AAA0700 | 1700 | 700 | AAA0700
11311  1800 | 800 | AAA0800 | 1800 | 800 | AAA0800
11312  1900 | 900 | AAA0900 | 1900 | 900 | AAA0900
11313  2000 |   0 | AAA0000 | 2000 |   0 | AAA0000
11314  2100 | 100 | AAA0100 | 2100 | 100 | AAA0100
11315  2200 | 200 | AAA0200 | 2200 | 200 | AAA0200
11316  2300 | 300 | AAA0300 | 2300 | 300 | AAA0300
11317  2400 | 400 | AAA0400 | 2400 | 400 | AAA0400
11318  2500 | 500 | AAA0500 | 2500 | 500 | AAA0500
11319  2600 | 600 | AAA0600 | 2600 | 600 | AAA0600
11320  2700 | 700 | AAA0700 | 2700 | 700 | AAA0700
11321  2800 | 800 | AAA0800 | 2800 | 800 | AAA0800
11322  2900 | 900 | AAA0900 | 2900 | 900 | AAA0900
11323  3000 |   0 | AAA0000 | 3000 |   0 | AAA0000
11324  3100 | 100 | AAA0100 | 3100 | 100 | AAA0100
11325  3200 | 200 | AAA0200 | 3200 | 200 | AAA0200
11326  3300 | 300 | AAA0300 | 3300 | 300 | AAA0300
11327  3400 | 400 | AAA0400 | 3400 | 400 | AAA0400
11328  3500 | 500 | AAA0500 | 3500 | 500 | AAA0500
11329  3600 | 600 | AAA0600 | 3600 | 600 | AAA0600
11330  3700 | 700 | AAA0700 | 3700 | 700 | AAA0700
11331  3800 | 800 | AAA0800 | 3800 | 800 | AAA0800
11332  3900 | 900 | AAA0900 | 3900 | 900 | AAA0900
11333 (30 rows)
11335 DELETE FROM join_tbl;
11336 RESET enable_partitionwise_join;
11337 -- Test rescan of an async Append node with do_exec_prune=false
11338 SET enable_hashjoin TO false;
11339 EXPLAIN (VERBOSE, COSTS OFF)
11340 INSERT INTO join_tbl SELECT * FROM async_p1 t1, async_pt t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.b % 100 = 0;
11341                                        QUERY PLAN                                       
11342 ----------------------------------------------------------------------------------------
11343  Insert on public.join_tbl
11344    ->  Nested Loop
11345          Output: t1.a, t1.b, t1.c, t2.a, t2.b, t2.c
11346          Join Filter: ((t1.a = t2.a) AND (t1.b = t2.b))
11347          ->  Foreign Scan on public.async_p1 t1
11348                Output: t1.a, t1.b, t1.c
11349                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE (((b % 100) = 0))
11350          ->  Append
11351                ->  Async Foreign Scan on public.async_p1 t2_1
11352                      Output: t2_1.a, t2_1.b, t2_1.c
11353                      Remote SQL: SELECT a, b, c FROM public.base_tbl1
11354                ->  Async Foreign Scan on public.async_p2 t2_2
11355                      Output: t2_2.a, t2_2.b, t2_2.c
11356                      Remote SQL: SELECT a, b, c FROM public.base_tbl2
11357                ->  Seq Scan on public.async_p3 t2_3
11358                      Output: t2_3.a, t2_3.b, t2_3.c
11359 (16 rows)
11361 INSERT INTO join_tbl SELECT * FROM async_p1 t1, async_pt t2 WHERE t1.a = t2.a AND t1.b = t2.b AND t1.b % 100 = 0;
11362 SELECT * FROM join_tbl ORDER BY a1;
11363   a1  | b1  |  c1  |  a2  | b2  |  c2  
11364 ------+-----+------+------+-----+------
11365  1000 |   0 | 0000 | 1000 |   0 | 0000
11366  1100 | 100 | 0100 | 1100 | 100 | 0100
11367  1200 | 200 | 0200 | 1200 | 200 | 0200
11368  1300 | 300 | 0300 | 1300 | 300 | 0300
11369  1400 | 400 | 0400 | 1400 | 400 | 0400
11370  1500 | 500 | 0500 | 1500 | 500 | 0500
11371  1600 | 600 | 0600 | 1600 | 600 | 0600
11372  1700 | 700 | 0700 | 1700 | 700 | 0700
11373  1800 | 800 | 0800 | 1800 | 800 | 0800
11374  1900 | 900 | 0900 | 1900 | 900 | 0900
11375 (10 rows)
11377 DELETE FROM join_tbl;
11378 RESET enable_hashjoin;
11379 -- Test interaction of async execution with plan-time partition pruning
11380 EXPLAIN (VERBOSE, COSTS OFF)
11381 SELECT * FROM async_pt WHERE a < 3000;
11382                                  QUERY PLAN                                  
11383 -----------------------------------------------------------------------------
11384  Append
11385    ->  Async Foreign Scan on public.async_p1 async_pt_1
11386          Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11387          Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((a < 3000))
11388    ->  Async Foreign Scan on public.async_p2 async_pt_2
11389          Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11390          Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((a < 3000))
11391 (7 rows)
11393 EXPLAIN (VERBOSE, COSTS OFF)
11394 SELECT * FROM async_pt WHERE a < 2000;
11395                               QUERY PLAN                               
11396 -----------------------------------------------------------------------
11397  Foreign Scan on public.async_p1 async_pt
11398    Output: async_pt.a, async_pt.b, async_pt.c
11399    Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((a < 2000))
11400 (3 rows)
11402 -- Test interaction of async execution with run-time partition pruning
11403 SET plan_cache_mode TO force_generic_plan;
11404 PREPARE async_pt_query (int, int) AS
11405   INSERT INTO result_tbl SELECT * FROM async_pt WHERE a < $1 AND b === $2;
11406 EXPLAIN (VERBOSE, COSTS OFF)
11407 EXECUTE async_pt_query (3000, 505);
11408                                         QUERY PLAN                                        
11409 ------------------------------------------------------------------------------------------
11410  Insert on public.result_tbl
11411    ->  Append
11412          Subplans Removed: 1
11413          ->  Async Foreign Scan on public.async_p1 async_pt_1
11414                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11415                Filter: (async_pt_1.b === $2)
11416                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((a < $1::integer))
11417          ->  Async Foreign Scan on public.async_p2 async_pt_2
11418                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11419                Filter: (async_pt_2.b === $2)
11420                Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((a < $1::integer))
11421 (11 rows)
11423 EXECUTE async_pt_query (3000, 505);
11424 SELECT * FROM result_tbl ORDER BY a;
11425   a   |  b  |  c   
11426 ------+-----+------
11427  1505 | 505 | 0505
11428  2505 | 505 | 0505
11429 (2 rows)
11431 DELETE FROM result_tbl;
11432 EXPLAIN (VERBOSE, COSTS OFF)
11433 EXECUTE async_pt_query (2000, 505);
11434                                         QUERY PLAN                                        
11435 ------------------------------------------------------------------------------------------
11436  Insert on public.result_tbl
11437    ->  Append
11438          Subplans Removed: 2
11439          ->  Async Foreign Scan on public.async_p1 async_pt_1
11440                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11441                Filter: (async_pt_1.b === $2)
11442                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((a < $1::integer))
11443 (7 rows)
11445 EXECUTE async_pt_query (2000, 505);
11446 SELECT * FROM result_tbl ORDER BY a;
11447   a   |  b  |  c   
11448 ------+-----+------
11449  1505 | 505 | 0505
11450 (1 row)
11452 DELETE FROM result_tbl;
11453 RESET plan_cache_mode;
11454 CREATE TABLE local_tbl(a int, b int, c text);
11455 INSERT INTO local_tbl VALUES (1505, 505, 'foo'), (2505, 505, 'bar');
11456 ANALYZE local_tbl;
11457 CREATE INDEX base_tbl1_idx ON base_tbl1 (a);
11458 CREATE INDEX base_tbl2_idx ON base_tbl2 (a);
11459 CREATE INDEX async_p3_idx ON async_p3 (a);
11460 ANALYZE base_tbl1;
11461 ANALYZE base_tbl2;
11462 ANALYZE async_p3;
11463 ALTER FOREIGN TABLE async_p1 OPTIONS (use_remote_estimate 'true');
11464 ALTER FOREIGN TABLE async_p2 OPTIONS (use_remote_estimate 'true');
11465 EXPLAIN (VERBOSE, COSTS OFF)
11466 SELECT * FROM local_tbl, async_pt WHERE local_tbl.a = async_pt.a AND local_tbl.c = 'bar';
11467                                         QUERY PLAN                                        
11468 ------------------------------------------------------------------------------------------
11469  Nested Loop
11470    Output: local_tbl.a, local_tbl.b, local_tbl.c, async_pt.a, async_pt.b, async_pt.c
11471    ->  Seq Scan on public.local_tbl
11472          Output: local_tbl.a, local_tbl.b, local_tbl.c
11473          Filter: (local_tbl.c = 'bar'::text)
11474    ->  Append
11475          ->  Async Foreign Scan on public.async_p1 async_pt_1
11476                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11477                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((a = $1::integer))
11478          ->  Async Foreign Scan on public.async_p2 async_pt_2
11479                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11480                Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((a = $1::integer))
11481          ->  Seq Scan on public.async_p3 async_pt_3
11482                Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
11483                Filter: (async_pt_3.a = local_tbl.a)
11484 (15 rows)
11486 EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
11487 SELECT * FROM local_tbl, async_pt WHERE local_tbl.a = async_pt.a AND local_tbl.c = 'bar';
11488                                   QUERY PLAN                                   
11489 -------------------------------------------------------------------------------
11490  Nested Loop (actual rows=1 loops=1)
11491    ->  Seq Scan on local_tbl (actual rows=1 loops=1)
11492          Filter: (c = 'bar'::text)
11493          Rows Removed by Filter: 1
11494    ->  Append (actual rows=1 loops=1)
11495          ->  Async Foreign Scan on async_p1 async_pt_1 (never executed)
11496          ->  Async Foreign Scan on async_p2 async_pt_2 (actual rows=1 loops=1)
11497          ->  Seq Scan on async_p3 async_pt_3 (never executed)
11498                Filter: (a = local_tbl.a)
11499 (9 rows)
11501 SELECT * FROM local_tbl, async_pt WHERE local_tbl.a = async_pt.a AND local_tbl.c = 'bar';
11502   a   |  b  |  c  |  a   |  b  |  c   
11503 ------+-----+-----+------+-----+------
11504  2505 | 505 | bar | 2505 | 505 | 0505
11505 (1 row)
11507 ALTER FOREIGN TABLE async_p1 OPTIONS (DROP use_remote_estimate);
11508 ALTER FOREIGN TABLE async_p2 OPTIONS (DROP use_remote_estimate);
11509 DROP TABLE local_tbl;
11510 DROP INDEX base_tbl1_idx;
11511 DROP INDEX base_tbl2_idx;
11512 DROP INDEX async_p3_idx;
11513 -- UNION queries
11514 EXPLAIN (VERBOSE, COSTS OFF)
11515 INSERT INTO result_tbl
11516 (SELECT a, b, 'AAA' || c FROM async_p1 ORDER BY a LIMIT 10)
11517 UNION
11518 (SELECT a, b, 'AAA' || c FROM async_p2 WHERE b < 10);
11519                                                    QUERY PLAN                                                    
11520 -----------------------------------------------------------------------------------------------------------------
11521  Insert on public.result_tbl
11522    ->  HashAggregate
11523          Output: async_p1.a, async_p1.b, (('AAA'::text || async_p1.c))
11524          Group Key: async_p1.a, async_p1.b, (('AAA'::text || async_p1.c))
11525          ->  Append
11526                ->  Async Foreign Scan on public.async_p1
11527                      Output: async_p1.a, async_p1.b, ('AAA'::text || async_p1.c)
11528                      Remote SQL: SELECT a, b, c FROM public.base_tbl1 ORDER BY a ASC NULLS LAST LIMIT 10::bigint
11529                ->  Async Foreign Scan on public.async_p2
11530                      Output: async_p2.a, async_p2.b, ('AAA'::text || async_p2.c)
11531                      Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((b < 10))
11532 (11 rows)
11534 INSERT INTO result_tbl
11535 (SELECT a, b, 'AAA' || c FROM async_p1 ORDER BY a LIMIT 10)
11536 UNION
11537 (SELECT a, b, 'AAA' || c FROM async_p2 WHERE b < 10);
11538 SELECT * FROM result_tbl ORDER BY a;
11539   a   | b  |    c    
11540 ------+----+---------
11541  1000 |  0 | AAA0000
11542  1005 |  5 | AAA0005
11543  1010 | 10 | AAA0010
11544  1015 | 15 | AAA0015
11545  1020 | 20 | AAA0020
11546  1025 | 25 | AAA0025
11547  1030 | 30 | AAA0030
11548  1035 | 35 | AAA0035
11549  1040 | 40 | AAA0040
11550  1045 | 45 | AAA0045
11551  2000 |  0 | AAA0000
11552  2005 |  5 | AAA0005
11553 (12 rows)
11555 DELETE FROM result_tbl;
11556 EXPLAIN (VERBOSE, COSTS OFF)
11557 INSERT INTO result_tbl
11558 (SELECT a, b, 'AAA' || c FROM async_p1 ORDER BY a LIMIT 10)
11559 UNION ALL
11560 (SELECT a, b, 'AAA' || c FROM async_p2 WHERE b < 10);
11561                                                 QUERY PLAN                                                 
11562 -----------------------------------------------------------------------------------------------------------
11563  Insert on public.result_tbl
11564    ->  Append
11565          ->  Async Foreign Scan on public.async_p1
11566                Output: async_p1.a, async_p1.b, ('AAA'::text || async_p1.c)
11567                Remote SQL: SELECT a, b, c FROM public.base_tbl1 ORDER BY a ASC NULLS LAST LIMIT 10::bigint
11568          ->  Async Foreign Scan on public.async_p2
11569                Output: async_p2.a, async_p2.b, ('AAA'::text || async_p2.c)
11570                Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((b < 10))
11571 (8 rows)
11573 INSERT INTO result_tbl
11574 (SELECT a, b, 'AAA' || c FROM async_p1 ORDER BY a LIMIT 10)
11575 UNION ALL
11576 (SELECT a, b, 'AAA' || c FROM async_p2 WHERE b < 10);
11577 SELECT * FROM result_tbl ORDER BY a;
11578   a   | b  |    c    
11579 ------+----+---------
11580  1000 |  0 | AAA0000
11581  1005 |  5 | AAA0005
11582  1010 | 10 | AAA0010
11583  1015 | 15 | AAA0015
11584  1020 | 20 | AAA0020
11585  1025 | 25 | AAA0025
11586  1030 | 30 | AAA0030
11587  1035 | 35 | AAA0035
11588  1040 | 40 | AAA0040
11589  1045 | 45 | AAA0045
11590  2000 |  0 | AAA0000
11591  2005 |  5 | AAA0005
11592 (12 rows)
11594 DELETE FROM result_tbl;
11595 -- Disable async execution if we use gating Result nodes for pseudoconstant
11596 -- quals
11597 EXPLAIN (VERBOSE, COSTS OFF)
11598 SELECT * FROM async_pt WHERE CURRENT_USER = SESSION_USER;
11599                            QUERY PLAN                           
11600 ----------------------------------------------------------------
11601  Append
11602    ->  Result
11603          Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11604          One-Time Filter: (CURRENT_USER = SESSION_USER)
11605          ->  Foreign Scan on public.async_p1 async_pt_1
11606                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11607                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11608    ->  Result
11609          Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11610          One-Time Filter: (CURRENT_USER = SESSION_USER)
11611          ->  Foreign Scan on public.async_p2 async_pt_2
11612                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11613                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11614    ->  Result
11615          Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
11616          One-Time Filter: (CURRENT_USER = SESSION_USER)
11617          ->  Seq Scan on public.async_p3 async_pt_3
11618                Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
11619 (18 rows)
11621 EXPLAIN (VERBOSE, COSTS OFF)
11622 (SELECT * FROM async_p1 WHERE CURRENT_USER = SESSION_USER)
11623 UNION ALL
11624 (SELECT * FROM async_p2 WHERE CURRENT_USER = SESSION_USER);
11625                            QUERY PLAN                           
11626 ----------------------------------------------------------------
11627  Append
11628    ->  Result
11629          Output: async_p1.a, async_p1.b, async_p1.c
11630          One-Time Filter: (CURRENT_USER = SESSION_USER)
11631          ->  Foreign Scan on public.async_p1
11632                Output: async_p1.a, async_p1.b, async_p1.c
11633                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11634    ->  Result
11635          Output: async_p2.a, async_p2.b, async_p2.c
11636          One-Time Filter: (CURRENT_USER = SESSION_USER)
11637          ->  Foreign Scan on public.async_p2
11638                Output: async_p2.a, async_p2.b, async_p2.c
11639                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11640 (13 rows)
11642 EXPLAIN (VERBOSE, COSTS OFF)
11643 SELECT * FROM ((SELECT * FROM async_p1 WHERE b < 10) UNION ALL (SELECT * FROM async_p2 WHERE b < 10)) s WHERE CURRENT_USER = SESSION_USER;
11644                                    QUERY PLAN                                    
11645 ---------------------------------------------------------------------------------
11646  Append
11647    ->  Result
11648          Output: async_p1.a, async_p1.b, async_p1.c
11649          One-Time Filter: (CURRENT_USER = SESSION_USER)
11650          ->  Foreign Scan on public.async_p1
11651                Output: async_p1.a, async_p1.b, async_p1.c
11652                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((b < 10))
11653    ->  Result
11654          Output: async_p2.a, async_p2.b, async_p2.c
11655          One-Time Filter: (CURRENT_USER = SESSION_USER)
11656          ->  Foreign Scan on public.async_p2
11657                Output: async_p2.a, async_p2.b, async_p2.c
11658                Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((b < 10))
11659 (13 rows)
11661 -- Test that pending requests are processed properly
11662 SET enable_mergejoin TO false;
11663 SET enable_hashjoin TO false;
11664 EXPLAIN (VERBOSE, COSTS OFF)
11665 SELECT * FROM async_pt t1, async_p2 t2 WHERE t1.a = t2.a AND t1.b === 505;
11666                            QUERY PLAN                           
11667 ----------------------------------------------------------------
11668  Nested Loop
11669    Output: t1.a, t1.b, t1.c, t2.a, t2.b, t2.c
11670    Join Filter: (t1.a = t2.a)
11671    ->  Append
11672          ->  Async Foreign Scan on public.async_p1 t1_1
11673                Output: t1_1.a, t1_1.b, t1_1.c
11674                Filter: (t1_1.b === 505)
11675                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11676          ->  Async Foreign Scan on public.async_p2 t1_2
11677                Output: t1_2.a, t1_2.b, t1_2.c
11678                Filter: (t1_2.b === 505)
11679                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11680          ->  Seq Scan on public.async_p3 t1_3
11681                Output: t1_3.a, t1_3.b, t1_3.c
11682                Filter: (t1_3.b === 505)
11683    ->  Materialize
11684          Output: t2.a, t2.b, t2.c
11685          ->  Foreign Scan on public.async_p2 t2
11686                Output: t2.a, t2.b, t2.c
11687                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11688 (20 rows)
11690 SELECT * FROM async_pt t1, async_p2 t2 WHERE t1.a = t2.a AND t1.b === 505;
11691   a   |  b  |  c   |  a   |  b  |  c   
11692 ------+-----+------+------+-----+------
11693  2505 | 505 | 0505 | 2505 | 505 | 0505
11694 (1 row)
11696 CREATE TABLE local_tbl (a int, b int, c text);
11697 INSERT INTO local_tbl VALUES (1505, 505, 'foo');
11698 ANALYZE local_tbl;
11699 EXPLAIN (VERBOSE, COSTS OFF)
11700 SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt WHERE a < 3000) FROM async_pt WHERE a < 3000) t2 ON t1.a = t2.a;
11701                                        QUERY PLAN                                       
11702 ----------------------------------------------------------------------------------------
11703  Nested Loop Left Join
11704    Output: t1.a, t1.b, t1.c, async_pt.a, async_pt.b, async_pt.c, ((InitPlan 1).col1)
11705    Join Filter: (t1.a = async_pt.a)
11706    InitPlan 1
11707      ->  Aggregate
11708            Output: count(*)
11709            ->  Append
11710                  ->  Async Foreign Scan on public.async_p1 async_pt_4
11711                        Remote SQL: SELECT NULL FROM public.base_tbl1 WHERE ((a < 3000))
11712                  ->  Async Foreign Scan on public.async_p2 async_pt_5
11713                        Remote SQL: SELECT NULL FROM public.base_tbl2 WHERE ((a < 3000))
11714    ->  Seq Scan on public.local_tbl t1
11715          Output: t1.a, t1.b, t1.c
11716    ->  Append
11717          ->  Async Foreign Scan on public.async_p1 async_pt_1
11718                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c, (InitPlan 1).col1
11719                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((a < 3000))
11720          ->  Async Foreign Scan on public.async_p2 async_pt_2
11721                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c, (InitPlan 1).col1
11722                Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((a < 3000))
11723 (20 rows)
11725 EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
11726 SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt WHERE a < 3000) FROM async_pt WHERE a < 3000) t2 ON t1.a = t2.a;
11727                                        QUERY PLAN                                        
11728 -----------------------------------------------------------------------------------------
11729  Nested Loop Left Join (actual rows=1 loops=1)
11730    Join Filter: (t1.a = async_pt.a)
11731    Rows Removed by Join Filter: 399
11732    InitPlan 1
11733      ->  Aggregate (actual rows=1 loops=1)
11734            ->  Append (actual rows=400 loops=1)
11735                  ->  Async Foreign Scan on async_p1 async_pt_4 (actual rows=200 loops=1)
11736                  ->  Async Foreign Scan on async_p2 async_pt_5 (actual rows=200 loops=1)
11737    ->  Seq Scan on local_tbl t1 (actual rows=1 loops=1)
11738    ->  Append (actual rows=400 loops=1)
11739          ->  Async Foreign Scan on async_p1 async_pt_1 (actual rows=200 loops=1)
11740          ->  Async Foreign Scan on async_p2 async_pt_2 (actual rows=200 loops=1)
11741 (12 rows)
11743 SELECT * FROM local_tbl t1 LEFT JOIN (SELECT *, (SELECT count(*) FROM async_pt WHERE a < 3000) FROM async_pt WHERE a < 3000) t2 ON t1.a = t2.a;
11744   a   |  b  |  c  |  a   |  b  |  c   | count 
11745 ------+-----+-----+------+-----+------+-------
11746  1505 | 505 | foo | 1505 | 505 | 0505 |   400
11747 (1 row)
11749 EXPLAIN (VERBOSE, COSTS OFF)
11750 SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1;
11751                            QUERY PLAN                           
11752 ----------------------------------------------------------------
11753  Limit
11754    Output: t1.a, t1.b, t1.c
11755    ->  Append
11756          ->  Async Foreign Scan on public.async_p1 t1_1
11757                Output: t1_1.a, t1_1.b, t1_1.c
11758                Filter: (t1_1.b === 505)
11759                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11760          ->  Async Foreign Scan on public.async_p2 t1_2
11761                Output: t1_2.a, t1_2.b, t1_2.c
11762                Filter: (t1_2.b === 505)
11763                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11764          ->  Seq Scan on public.async_p3 t1_3
11765                Output: t1_3.a, t1_3.b, t1_3.c
11766                Filter: (t1_3.b === 505)
11767 (14 rows)
11769 EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
11770 SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1;
11771                                QUERY PLAN                                
11772 -------------------------------------------------------------------------
11773  Limit (actual rows=1 loops=1)
11774    ->  Append (actual rows=1 loops=1)
11775          ->  Async Foreign Scan on async_p1 t1_1 (actual rows=0 loops=1)
11776                Filter: (b === 505)
11777          ->  Async Foreign Scan on async_p2 t1_2 (actual rows=0 loops=1)
11778                Filter: (b === 505)
11779          ->  Seq Scan on async_p3 t1_3 (actual rows=1 loops=1)
11780                Filter: (b === 505)
11781                Rows Removed by Filter: 101
11782 (9 rows)
11784 SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1;
11785   a   |  b  |  c   
11786 ------+-----+------
11787  3505 | 505 | 0505
11788 (1 row)
11790 -- Check with foreign modify
11791 CREATE TABLE base_tbl3 (a int, b int, c text);
11792 CREATE FOREIGN TABLE remote_tbl (a int, b int, c text)
11793   SERVER loopback OPTIONS (table_name 'base_tbl3');
11794 INSERT INTO remote_tbl VALUES (2505, 505, 'bar');
11795 CREATE TABLE base_tbl4 (a int, b int, c text);
11796 CREATE FOREIGN TABLE insert_tbl (a int, b int, c text)
11797   SERVER loopback OPTIONS (table_name 'base_tbl4');
11798 EXPLAIN (VERBOSE, COSTS OFF)
11799 INSERT INTO insert_tbl (SELECT * FROM local_tbl UNION ALL SELECT * FROM remote_tbl);
11800                                QUERY PLAN                                
11801 -------------------------------------------------------------------------
11802  Insert on public.insert_tbl
11803    Remote SQL: INSERT INTO public.base_tbl4(a, b, c) VALUES ($1, $2, $3)
11804    Batch Size: 1
11805    ->  Append
11806          ->  Seq Scan on public.local_tbl
11807                Output: local_tbl.a, local_tbl.b, local_tbl.c
11808          ->  Async Foreign Scan on public.remote_tbl
11809                Output: remote_tbl.a, remote_tbl.b, remote_tbl.c
11810                Remote SQL: SELECT a, b, c FROM public.base_tbl3
11811 (9 rows)
11813 INSERT INTO insert_tbl (SELECT * FROM local_tbl UNION ALL SELECT * FROM remote_tbl);
11814 SELECT * FROM insert_tbl ORDER BY a;
11815   a   |  b  |  c  
11816 ------+-----+-----
11817  1505 | 505 | foo
11818  2505 | 505 | bar
11819 (2 rows)
11821 -- Check with direct modify
11822 EXPLAIN (VERBOSE, COSTS OFF)
11823 WITH t AS (UPDATE remote_tbl SET c = c || c RETURNING *)
11824 INSERT INTO join_tbl SELECT * FROM async_pt LEFT JOIN t ON (async_pt.a = t.a AND async_pt.b = t.b) WHERE async_pt.b === 505;
11825                                        QUERY PLAN                                       
11826 ----------------------------------------------------------------------------------------
11827  Insert on public.join_tbl
11828    CTE t
11829      ->  Update on public.remote_tbl
11830            Output: remote_tbl.a, remote_tbl.b, remote_tbl.c
11831            ->  Foreign Update on public.remote_tbl
11832                  Remote SQL: UPDATE public.base_tbl3 SET c = (c || c) RETURNING a, b, c
11833    ->  Nested Loop Left Join
11834          Output: async_pt.a, async_pt.b, async_pt.c, t.a, t.b, t.c
11835          Join Filter: ((async_pt.a = t.a) AND (async_pt.b = t.b))
11836          ->  Append
11837                ->  Async Foreign Scan on public.async_p1 async_pt_1
11838                      Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11839                      Filter: (async_pt_1.b === 505)
11840                      Remote SQL: SELECT a, b, c FROM public.base_tbl1
11841                ->  Async Foreign Scan on public.async_p2 async_pt_2
11842                      Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11843                      Filter: (async_pt_2.b === 505)
11844                      Remote SQL: SELECT a, b, c FROM public.base_tbl2
11845                ->  Seq Scan on public.async_p3 async_pt_3
11846                      Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
11847                      Filter: (async_pt_3.b === 505)
11848          ->  CTE Scan on t
11849                Output: t.a, t.b, t.c
11850 (23 rows)
11852 WITH t AS (UPDATE remote_tbl SET c = c || c RETURNING *)
11853 INSERT INTO join_tbl SELECT * FROM async_pt LEFT JOIN t ON (async_pt.a = t.a AND async_pt.b = t.b) WHERE async_pt.b === 505;
11854 SELECT * FROM join_tbl ORDER BY a1;
11855   a1  | b1  |  c1  |  a2  | b2  |   c2   
11856 ------+-----+------+------+-----+--------
11857  1505 | 505 | 0505 |      |     | 
11858  2505 | 505 | 0505 | 2505 | 505 | barbar
11859  3505 | 505 | 0505 |      |     | 
11860 (3 rows)
11862 DELETE FROM join_tbl;
11863 DROP TABLE local_tbl;
11864 DROP FOREIGN TABLE remote_tbl;
11865 DROP FOREIGN TABLE insert_tbl;
11866 DROP TABLE base_tbl3;
11867 DROP TABLE base_tbl4;
11868 RESET enable_mergejoin;
11869 RESET enable_hashjoin;
11870 -- Test that UPDATE/DELETE with inherited target works with async_capable enabled
11871 EXPLAIN (VERBOSE, COSTS OFF)
11872 UPDATE async_pt SET c = c || c WHERE b = 0 RETURNING *;
11873                                                 QUERY PLAN                                                
11874 ----------------------------------------------------------------------------------------------------------
11875  Update on public.async_pt
11876    Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11877    Foreign Update on public.async_p1 async_pt_1
11878    Foreign Update on public.async_p2 async_pt_2
11879    Update on public.async_p3 async_pt_3
11880    ->  Append
11881          ->  Foreign Update on public.async_p1 async_pt_1
11882                Remote SQL: UPDATE public.base_tbl1 SET c = (c || c) WHERE ((b = 0)) RETURNING a, b, c
11883          ->  Foreign Update on public.async_p2 async_pt_2
11884                Remote SQL: UPDATE public.base_tbl2 SET c = (c || c) WHERE ((b = 0)) RETURNING a, b, c
11885          ->  Seq Scan on public.async_p3 async_pt_3
11886                Output: (async_pt_3.c || async_pt_3.c), async_pt_3.tableoid, async_pt_3.ctid, NULL::record
11887                Filter: (async_pt_3.b = 0)
11888 (13 rows)
11890 UPDATE async_pt SET c = c || c WHERE b = 0 RETURNING *;
11891   a   | b |    c     
11892 ------+---+----------
11893  1000 | 0 | 00000000
11894  2000 | 0 | 00000000
11895  3000 | 0 | 00000000
11896 (3 rows)
11898 EXPLAIN (VERBOSE, COSTS OFF)
11899 DELETE FROM async_pt WHERE b = 0 RETURNING *;
11900                                         QUERY PLAN                                        
11901 ------------------------------------------------------------------------------------------
11902  Delete on public.async_pt
11903    Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11904    Foreign Delete on public.async_p1 async_pt_1
11905    Foreign Delete on public.async_p2 async_pt_2
11906    Delete on public.async_p3 async_pt_3
11907    ->  Append
11908          ->  Foreign Delete on public.async_p1 async_pt_1
11909                Remote SQL: DELETE FROM public.base_tbl1 WHERE ((b = 0)) RETURNING a, b, c
11910          ->  Foreign Delete on public.async_p2 async_pt_2
11911                Remote SQL: DELETE FROM public.base_tbl2 WHERE ((b = 0)) RETURNING a, b, c
11912          ->  Seq Scan on public.async_p3 async_pt_3
11913                Output: async_pt_3.tableoid, async_pt_3.ctid
11914                Filter: (async_pt_3.b = 0)
11915 (13 rows)
11917 DELETE FROM async_pt WHERE b = 0 RETURNING *;
11918   a   | b |    c     
11919 ------+---+----------
11920  1000 | 0 | 00000000
11921  2000 | 0 | 00000000
11922  3000 | 0 | 00000000
11923 (3 rows)
11925 -- Check EXPLAIN ANALYZE for a query that scans empty partitions asynchronously
11926 DELETE FROM async_p1;
11927 DELETE FROM async_p2;
11928 DELETE FROM async_p3;
11929 EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
11930 SELECT * FROM async_pt;
11931                                QUERY PLAN                                
11932 -------------------------------------------------------------------------
11933  Append (actual rows=0 loops=1)
11934    ->  Async Foreign Scan on async_p1 async_pt_1 (actual rows=0 loops=1)
11935    ->  Async Foreign Scan on async_p2 async_pt_2 (actual rows=0 loops=1)
11936    ->  Seq Scan on async_p3 async_pt_3 (actual rows=0 loops=1)
11937 (4 rows)
11939 -- Clean up
11940 DROP TABLE async_pt;
11941 DROP TABLE base_tbl1;
11942 DROP TABLE base_tbl2;
11943 DROP TABLE result_tbl;
11944 DROP TABLE join_tbl;
11945 -- Test that an asynchronous fetch is processed before restarting the scan in
11946 -- ReScanForeignScan
11947 CREATE TABLE base_tbl (a int, b int);
11948 INSERT INTO base_tbl VALUES (1, 11), (2, 22), (3, 33);
11949 CREATE FOREIGN TABLE foreign_tbl (b int)
11950   SERVER loopback OPTIONS (table_name 'base_tbl');
11951 CREATE FOREIGN TABLE foreign_tbl2 () INHERITS (foreign_tbl)
11952   SERVER loopback OPTIONS (table_name 'base_tbl');
11953 EXPLAIN (VERBOSE, COSTS OFF)
11954 SELECT a FROM base_tbl WHERE (a, random() > 0) IN (SELECT a, random() > 0 FROM foreign_tbl);
11955                                                   QUERY PLAN                                                   
11956 ---------------------------------------------------------------------------------------------------------------
11957  Seq Scan on public.base_tbl
11958    Output: base_tbl.a
11959    Filter: (ANY ((base_tbl.a = (SubPlan 1).col1) AND ((random() > '0'::double precision) = (SubPlan 1).col2)))
11960    SubPlan 1
11961      ->  Result
11962            Output: base_tbl.a, (random() > '0'::double precision)
11963            ->  Append
11964                  ->  Async Foreign Scan on public.foreign_tbl foreign_tbl_1
11965                        Remote SQL: SELECT NULL FROM public.base_tbl
11966                  ->  Async Foreign Scan on public.foreign_tbl2 foreign_tbl_2
11967                        Remote SQL: SELECT NULL FROM public.base_tbl
11968 (11 rows)
11970 SELECT a FROM base_tbl WHERE (a, random() > 0) IN (SELECT a, random() > 0 FROM foreign_tbl);
11971  a 
11976 (3 rows)
11978 -- Clean up
11979 DROP FOREIGN TABLE foreign_tbl CASCADE;
11980 NOTICE:  drop cascades to foreign table foreign_tbl2
11981 DROP TABLE base_tbl;
11982 ALTER SERVER loopback OPTIONS (DROP async_capable);
11983 ALTER SERVER loopback2 OPTIONS (DROP async_capable);
11984 -- ===================================================================
11985 -- test invalid server, foreign table and foreign data wrapper options
11986 -- ===================================================================
11987 -- Invalid fdw_startup_cost option
11988 CREATE SERVER inv_scst FOREIGN DATA WRAPPER postgres_fdw
11989         OPTIONS(fdw_startup_cost '100$%$#$#');
11990 ERROR:  invalid value for floating point option "fdw_startup_cost": 100$%$#$#
11991 -- Invalid fdw_tuple_cost option
11992 CREATE SERVER inv_scst FOREIGN DATA WRAPPER postgres_fdw
11993         OPTIONS(fdw_tuple_cost '100$%$#$#');
11994 ERROR:  invalid value for floating point option "fdw_tuple_cost": 100$%$#$#
11995 -- Invalid fetch_size option
11996 CREATE FOREIGN TABLE inv_fsz (c1 int )
11997         SERVER loopback OPTIONS (fetch_size '100$%$#$#');
11998 ERROR:  invalid value for integer option "fetch_size": 100$%$#$#
11999 -- Invalid batch_size option
12000 CREATE FOREIGN TABLE inv_bsz (c1 int )
12001         SERVER loopback OPTIONS (batch_size '100$%$#$#');
12002 ERROR:  invalid value for integer option "batch_size": 100$%$#$#
12003 -- No option is allowed to be specified at foreign data wrapper level
12004 ALTER FOREIGN DATA WRAPPER postgres_fdw OPTIONS (nonexistent 'fdw');
12005 ERROR:  invalid option "nonexistent"
12006 HINT:  There are no valid options in this context.
12007 -- ===================================================================
12008 -- test postgres_fdw.application_name GUC
12009 -- ===================================================================
12010 -- To avoid race conditions in checking the remote session's application_name,
12011 -- use this view to make the remote session itself read its application_name.
12012 CREATE VIEW my_application_name AS
12013   SELECT application_name FROM pg_stat_activity WHERE pid = pg_backend_pid();
12014 CREATE FOREIGN TABLE remote_application_name (application_name text)
12015   SERVER loopback2
12016   OPTIONS (schema_name 'public', table_name 'my_application_name');
12017 SELECT count(*) FROM remote_application_name;
12018  count 
12019 -------
12020      1
12021 (1 row)
12023 -- Specify escape sequences in application_name option of a server
12024 -- object so as to test that they are replaced with status information
12025 -- expectedly.  Note that we are also relying on ALTER SERVER to force
12026 -- the remote session to be restarted with its new application name.
12028 -- Since pg_stat_activity.application_name may be truncated to less than
12029 -- NAMEDATALEN characters, note that substring() needs to be used
12030 -- at the condition of test query to make sure that the string consisting
12031 -- of database name and process ID is also less than that.
12032 ALTER SERVER loopback2 OPTIONS (application_name 'fdw_%d%p');
12033 SELECT count(*) FROM remote_application_name
12034   WHERE application_name =
12035     substring('fdw_' || current_database() || pg_backend_pid() for
12036       current_setting('max_identifier_length')::int);
12037  count 
12038 -------
12039      1
12040 (1 row)
12042 -- postgres_fdw.application_name overrides application_name option
12043 -- of a server object if both settings are present.
12044 ALTER SERVER loopback2 OPTIONS (SET application_name 'fdw_wrong');
12045 SET postgres_fdw.application_name TO 'fdw_%a%u%%';
12046 SELECT count(*) FROM remote_application_name
12047   WHERE application_name =
12048     substring('fdw_' || current_setting('application_name') ||
12049       CURRENT_USER || '%' for current_setting('max_identifier_length')::int);
12050  count 
12051 -------
12052      1
12053 (1 row)
12055 RESET postgres_fdw.application_name;
12056 -- Test %c (session ID) and %C (cluster name) escape sequences.
12057 ALTER SERVER loopback2 OPTIONS (SET application_name 'fdw_%C%c');
12058 SELECT count(*) FROM remote_application_name
12059   WHERE application_name =
12060     substring('fdw_' || current_setting('cluster_name') ||
12061       to_hex(trunc(EXTRACT(EPOCH FROM (SELECT backend_start FROM
12062       pg_stat_get_activity(pg_backend_pid()))))::integer) || '.' ||
12063       to_hex(pg_backend_pid())
12064       for current_setting('max_identifier_length')::int);
12065  count 
12066 -------
12067      1
12068 (1 row)
12070 -- Clean up.
12071 DROP FOREIGN TABLE remote_application_name;
12072 DROP VIEW my_application_name;
12073 -- ===================================================================
12074 -- test parallel commit and parallel abort
12075 -- ===================================================================
12076 ALTER SERVER loopback OPTIONS (ADD parallel_commit 'true');
12077 ALTER SERVER loopback OPTIONS (ADD parallel_abort 'true');
12078 ALTER SERVER loopback2 OPTIONS (ADD parallel_commit 'true');
12079 ALTER SERVER loopback2 OPTIONS (ADD parallel_abort 'true');
12080 CREATE TABLE ploc1 (f1 int, f2 text);
12081 CREATE FOREIGN TABLE prem1 (f1 int, f2 text)
12082   SERVER loopback OPTIONS (table_name 'ploc1');
12083 CREATE TABLE ploc2 (f1 int, f2 text);
12084 CREATE FOREIGN TABLE prem2 (f1 int, f2 text)
12085   SERVER loopback2 OPTIONS (table_name 'ploc2');
12086 BEGIN;
12087 INSERT INTO prem1 VALUES (101, 'foo');
12088 INSERT INTO prem2 VALUES (201, 'bar');
12089 COMMIT;
12090 SELECT * FROM prem1;
12091  f1  | f2  
12092 -----+-----
12093  101 | foo
12094 (1 row)
12096 SELECT * FROM prem2;
12097  f1  | f2  
12098 -----+-----
12099  201 | bar
12100 (1 row)
12102 BEGIN;
12103 SAVEPOINT s;
12104 INSERT INTO prem1 VALUES (102, 'foofoo');
12105 INSERT INTO prem2 VALUES (202, 'barbar');
12106 RELEASE SAVEPOINT s;
12107 COMMIT;
12108 SELECT * FROM prem1;
12109  f1  |   f2   
12110 -----+--------
12111  101 | foo
12112  102 | foofoo
12113 (2 rows)
12115 SELECT * FROM prem2;
12116  f1  |   f2   
12117 -----+--------
12118  201 | bar
12119  202 | barbar
12120 (2 rows)
12122 -- This tests executing DEALLOCATE ALL against foreign servers in parallel
12123 -- during pre-commit
12124 BEGIN;
12125 SAVEPOINT s;
12126 INSERT INTO prem1 VALUES (103, 'baz');
12127 INSERT INTO prem2 VALUES (203, 'qux');
12128 ROLLBACK TO SAVEPOINT s;
12129 RELEASE SAVEPOINT s;
12130 INSERT INTO prem1 VALUES (104, 'bazbaz');
12131 INSERT INTO prem2 VALUES (204, 'quxqux');
12132 COMMIT;
12133 SELECT * FROM prem1;
12134  f1  |   f2   
12135 -----+--------
12136  101 | foo
12137  102 | foofoo
12138  104 | bazbaz
12139 (3 rows)
12141 SELECT * FROM prem2;
12142  f1  |   f2   
12143 -----+--------
12144  201 | bar
12145  202 | barbar
12146  204 | quxqux
12147 (3 rows)
12149 BEGIN;
12150 INSERT INTO prem1 VALUES (105, 'test1');
12151 INSERT INTO prem2 VALUES (205, 'test2');
12152 ABORT;
12153 SELECT * FROM prem1;
12154  f1  |   f2   
12155 -----+--------
12156  101 | foo
12157  102 | foofoo
12158  104 | bazbaz
12159 (3 rows)
12161 SELECT * FROM prem2;
12162  f1  |   f2   
12163 -----+--------
12164  201 | bar
12165  202 | barbar
12166  204 | quxqux
12167 (3 rows)
12169 -- This tests executing DEALLOCATE ALL against foreign servers in parallel
12170 -- during post-abort
12171 BEGIN;
12172 SAVEPOINT s;
12173 INSERT INTO prem1 VALUES (105, 'test1');
12174 INSERT INTO prem2 VALUES (205, 'test2');
12175 ROLLBACK TO SAVEPOINT s;
12176 RELEASE SAVEPOINT s;
12177 INSERT INTO prem1 VALUES (105, 'test1');
12178 INSERT INTO prem2 VALUES (205, 'test2');
12179 ABORT;
12180 SELECT * FROM prem1;
12181  f1  |   f2   
12182 -----+--------
12183  101 | foo
12184  102 | foofoo
12185  104 | bazbaz
12186 (3 rows)
12188 SELECT * FROM prem2;
12189  f1  |   f2   
12190 -----+--------
12191  201 | bar
12192  202 | barbar
12193  204 | quxqux
12194 (3 rows)
12196 ALTER SERVER loopback OPTIONS (DROP parallel_commit);
12197 ALTER SERVER loopback OPTIONS (DROP parallel_abort);
12198 ALTER SERVER loopback2 OPTIONS (DROP parallel_commit);
12199 ALTER SERVER loopback2 OPTIONS (DROP parallel_abort);
12200 -- ===================================================================
12201 -- test for ANALYZE sampling
12202 -- ===================================================================
12203 CREATE TABLE analyze_table (id int, a text, b bigint);
12204 CREATE FOREIGN TABLE analyze_ftable (id int, a text, b bigint)
12205        SERVER loopback OPTIONS (table_name 'analyze_rtable1');
12206 INSERT INTO analyze_table (SELECT x FROM generate_series(1,1000) x);
12207 ANALYZE analyze_table;
12208 SET default_statistics_target = 10;
12209 ANALYZE analyze_table;
12210 ALTER SERVER loopback OPTIONS (analyze_sampling 'invalid');
12211 ERROR:  invalid value for string option "analyze_sampling": invalid
12212 ALTER SERVER loopback OPTIONS (analyze_sampling 'auto');
12213 ANALYZE analyze_table;
12214 ALTER SERVER loopback OPTIONS (SET analyze_sampling 'system');
12215 ANALYZE analyze_table;
12216 ALTER SERVER loopback OPTIONS (SET analyze_sampling 'bernoulli');
12217 ANALYZE analyze_table;
12218 ALTER SERVER loopback OPTIONS (SET analyze_sampling 'random');
12219 ANALYZE analyze_table;
12220 ALTER SERVER loopback OPTIONS (SET analyze_sampling 'off');
12221 ANALYZE analyze_table;
12222 -- cleanup
12223 DROP FOREIGN TABLE analyze_ftable;
12224 DROP TABLE analyze_table;