Support "Right Semi Join" plan shapes
[pgsql.git] / contrib / postgres_fdw / expected / postgres_fdw.out
blob1f223091949dd4b0af14a34ca7447006c3d5c7d3
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 -- Ensure we don't ship FETCH FIRST .. WITH TIES
1051 EXPLAIN (VERBOSE, COSTS OFF)
1052 SELECT t1.c2 FROM ft1 t1 WHERE t1.c1 > 960 ORDER BY t1.c2 FETCH FIRST 2 ROWS WITH TIES;
1053                                            QUERY PLAN                                            
1054 -------------------------------------------------------------------------------------------------
1055  Limit
1056    Output: c2
1057    ->  Foreign Scan on public.ft1 t1
1058          Output: c2
1059          Remote SQL: SELECT c2 FROM "S 1"."T 1" WHERE (("C 1" > 960)) ORDER BY c2 ASC NULLS LAST
1060 (5 rows)
1062 SELECT t1.c2 FROM ft1 t1 WHERE t1.c1 > 960 ORDER BY t1.c2 FETCH FIRST 2 ROWS WITH TIES;
1063  c2 
1064 ----
1065   0
1066   0
1067   0
1068   0
1069 (4 rows)
1071 -- Test CASE pushdown
1072 EXPLAIN (VERBOSE, COSTS OFF)
1073 SELECT c1,c2,c3 FROM ft2 WHERE CASE WHEN c1 > 990 THEN c1 END < 1000 ORDER BY c1;
1074                                                                            QUERY PLAN                                                                           
1075 ----------------------------------------------------------------------------------------------------------------------------------------------------------------
1076  Foreign Scan on public.ft2
1077    Output: c1, c2, c3
1078    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
1079 (3 rows)
1081 SELECT c1,c2,c3 FROM ft2 WHERE CASE WHEN c1 > 990 THEN c1 END < 1000 ORDER BY c1;
1082  c1  | c2 |  c3   
1083 -----+----+-------
1084  991 |  1 | 00991
1085  992 |  2 | 00992
1086  993 |  3 | 00993
1087  994 |  4 | 00994
1088  995 |  5 | 00995
1089  996 |  6 | 00996
1090  997 |  7 | 00997
1091  998 |  8 | 00998
1092  999 |  9 | 00999
1093 (9 rows)
1095 -- Nested CASE
1096 EXPLAIN (VERBOSE, COSTS OFF)
1097 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;
1098                                                                                                 QUERY PLAN                                                                                                 
1099 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1100  Foreign Scan on public.ft2
1101    Output: c1, c2, c3
1102    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
1103 (3 rows)
1105 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;
1106  c1 | c2 | c3 
1107 ----+----+----
1108 (0 rows)
1110 -- CASE arg WHEN
1111 EXPLAIN (VERBOSE, COSTS OFF)
1112 SELECT * FROM ft1 WHERE c1 > (CASE mod(c1, 4) WHEN 0 THEN 1 WHEN 2 THEN 50 ELSE 100 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 (("C 1" > (CASE mod("C 1", 4) WHEN 0 THEN 1 WHEN 2 THEN 50 ELSE 100 END)))
1118 (3 rows)
1120 -- CASE cannot be pushed down because of unshippable arg clause
1121 EXPLAIN (VERBOSE, COSTS OFF)
1122 SELECT * FROM ft1 WHERE c1 > (CASE random()::integer WHEN 0 THEN 1 WHEN 2 THEN 50 ELSE 100 END);
1123                                        QUERY PLAN                                        
1124 -----------------------------------------------------------------------------------------
1125  Foreign Scan on public.ft1
1126    Output: c1, c2, c3, c4, c5, c6, c7, c8
1127    Filter: (ft1.c1 > CASE (random())::integer WHEN 0 THEN 1 WHEN 2 THEN 50 ELSE 100 END)
1128    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1129 (4 rows)
1131 -- these are shippable
1132 EXPLAIN (VERBOSE, COSTS OFF)
1133 SELECT * FROM ft1 WHERE CASE c6 WHEN 'foo' THEN true ELSE c3 < 'bar' END;
1134                                                                  QUERY PLAN                                                                 
1135 --------------------------------------------------------------------------------------------------------------------------------------------
1136  Foreign Scan on public.ft1
1137    Output: c1, c2, c3, c4, c5, c6, c7, c8
1138    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))
1139 (3 rows)
1141 EXPLAIN (VERBOSE, COSTS OFF)
1142 SELECT * FROM ft1 WHERE CASE c3 WHEN c6 THEN true ELSE c3 < 'bar' END;
1143                                                             QUERY PLAN                                                             
1144 -----------------------------------------------------------------------------------------------------------------------------------
1145  Foreign Scan on public.ft1
1146    Output: c1, c2, c3, c4, c5, c6, c7, c8
1147    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))
1148 (3 rows)
1150 -- but this is not because of collation
1151 EXPLAIN (VERBOSE, COSTS OFF)
1152 SELECT * FROM ft1 WHERE CASE c3 COLLATE "C" WHEN c6 THEN true ELSE c3 < 'bar' END;
1153                                      QUERY PLAN                                      
1154 -------------------------------------------------------------------------------------
1155  Foreign Scan on public.ft1
1156    Output: c1, c2, c3, c4, c5, c6, c7, c8
1157    Filter: CASE (ft1.c3)::text WHEN ft1.c6 THEN true ELSE (ft1.c3 < 'bar'::text) END
1158    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1159 (4 rows)
1161 -- a regconfig constant referring to this text search configuration
1162 -- is initially unshippable
1163 CREATE TEXT SEARCH CONFIGURATION public.custom_search
1164   (COPY = pg_catalog.english);
1165 EXPLAIN (VERBOSE, COSTS OFF)
1166 SELECT c1, to_tsvector('custom_search'::regconfig, c3) FROM ft1
1167 WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
1168                                QUERY PLAN                                
1169 -------------------------------------------------------------------------
1170  Foreign Scan on public.ft1
1171    Output: c1, to_tsvector('custom_search'::regconfig, c3)
1172    Filter: (length(to_tsvector('custom_search'::regconfig, ft1.c3)) > 0)
1173    Remote SQL: SELECT "C 1", c3 FROM "S 1"."T 1" WHERE (("C 1" = 642))
1174 (4 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 -- but if it's in a shippable extension, it can be shipped
1184 ALTER EXTENSION postgres_fdw ADD TEXT SEARCH CONFIGURATION public.custom_search;
1185 -- however, that doesn't flush the shippability cache, so do a quick reconnect
1186 \c -
1187 EXPLAIN (VERBOSE, COSTS OFF)
1188 SELECT c1, to_tsvector('custom_search'::regconfig, c3) FROM ft1
1189 WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
1190                                                                   QUERY PLAN                                                                  
1191 ----------------------------------------------------------------------------------------------------------------------------------------------
1192  Foreign Scan on public.ft1
1193    Output: c1, to_tsvector('custom_search'::regconfig, c3)
1194    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))
1195 (3 rows)
1197 SELECT c1, to_tsvector('custom_search'::regconfig, c3) FROM ft1
1198 WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
1199  c1  | to_tsvector 
1200 -----+-------------
1201  642 | '00642':1
1202 (1 row)
1204 -- ===================================================================
1205 -- ORDER BY queries
1206 -- ===================================================================
1207 -- we should not push order by clause with volatile expressions or unsafe
1208 -- collations
1209 EXPLAIN (VERBOSE, COSTS OFF)
1210         SELECT * FROM ft2 ORDER BY ft2.c1, random();
1211                                   QUERY PLAN                                   
1212 -------------------------------------------------------------------------------
1213  Sort
1214    Output: c1, c2, c3, c4, c5, c6, c7, c8, (random())
1215    Sort Key: ft2.c1, (random())
1216    ->  Foreign Scan on public.ft2
1217          Output: c1, c2, c3, c4, c5, c6, c7, c8, random()
1218          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1219 (6 rows)
1221 EXPLAIN (VERBOSE, COSTS OFF)
1222         SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
1223                                   QUERY PLAN                                   
1224 -------------------------------------------------------------------------------
1225  Sort
1226    Output: c1, c2, c3, c4, c5, c6, c7, c8, ((c3)::text)
1227    Sort Key: ft2.c1, ft2.c3 COLLATE "C"
1228    ->  Foreign Scan on public.ft2
1229          Output: c1, c2, c3, c4, c5, c6, c7, c8, c3
1230          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1231 (6 rows)
1233 -- Ensure we don't push ORDER BY expressions which are Consts at the UNION
1234 -- child level to the foreign server.
1235 EXPLAIN (VERBOSE, COSTS OFF)
1236 SELECT * FROM (
1237     SELECT 1 AS type,c1 FROM ft1
1238     UNION ALL
1239     SELECT 2 AS type,c1 FROM ft2
1240 ) a ORDER BY type,c1;
1241                                    QUERY PLAN                                    
1242 ---------------------------------------------------------------------------------
1243  Merge Append
1244    Sort Key: (1), ft1.c1
1245    ->  Foreign Scan on public.ft1
1246          Output: 1, ft1.c1
1247          Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
1248    ->  Foreign Scan on public.ft2
1249          Output: 2, ft2.c1
1250          Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
1251 (8 rows)
1253 EXPLAIN (VERBOSE, COSTS OFF)
1254 SELECT * FROM (
1255     SELECT 1 AS type,c1 FROM ft1
1256     UNION ALL
1257     SELECT 2 AS type,c1 FROM ft2
1258 ) a ORDER BY type;
1259                     QUERY PLAN                     
1260 ---------------------------------------------------
1261  Merge Append
1262    Sort Key: (1)
1263    ->  Foreign Scan on public.ft1
1264          Output: 1, ft1.c1
1265          Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
1266    ->  Foreign Scan on public.ft2
1267          Output: 2, ft2.c1
1268          Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
1269 (8 rows)
1271 -- ===================================================================
1272 -- JOIN queries
1273 -- ===================================================================
1274 -- Analyze ft4 and ft5 so that we have better statistics. These tables do not
1275 -- have use_remote_estimate set.
1276 ANALYZE ft4;
1277 ANALYZE ft5;
1278 -- join two tables
1279 EXPLAIN (VERBOSE, COSTS OFF)
1280 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;
1281                                                                                                        QUERY PLAN                                                                                                       
1282 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1283  Foreign Scan
1284    Output: t1.c1, t2.c1, t1.c3
1285    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
1286    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
1287 (4 rows)
1289 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;
1290  c1  | c1  
1291 -----+-----
1292  101 | 101
1293  102 | 102
1294  103 | 103
1295  104 | 104
1296  105 | 105
1297  106 | 106
1298  107 | 107
1299  108 | 108
1300  109 | 109
1301  110 | 110
1302 (10 rows)
1304 -- join three tables
1305 EXPLAIN (VERBOSE, COSTS OFF)
1306 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;
1307                                                                                                                                    QUERY PLAN                                                                                                                                    
1308 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1309  Foreign Scan
1310    Output: t1.c1, t2.c2, t3.c3, t1.c3
1311    Relations: ((public.ft1 t1) INNER JOIN (public.ft2 t2)) INNER JOIN (public.ft4 t3)
1312    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
1313 (4 rows)
1315 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;
1316  c1 | c2 |   c3   
1317 ----+----+--------
1318  22 |  2 | AAA022
1319  24 |  4 | AAA024
1320  26 |  6 | AAA026
1321  28 |  8 | AAA028
1322  30 |  0 | AAA030
1323  32 |  2 | AAA032
1324  34 |  4 | AAA034
1325  36 |  6 | AAA036
1326  38 |  8 | AAA038
1327  40 |  0 | AAA040
1328 (10 rows)
1330 -- left outer join
1331 EXPLAIN (VERBOSE, COSTS OFF)
1332 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;
1333                                                                                            QUERY PLAN                                                                                           
1334 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1335  Foreign Scan
1336    Output: t1.c1, t2.c1
1337    Relations: (public.ft4 t1) LEFT JOIN (public.ft5 t2)
1338    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
1339 (4 rows)
1341 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;
1342  c1 | c1 
1343 ----+----
1344  22 |   
1345  24 | 24
1346  26 |   
1347  28 |   
1348  30 | 30
1349  32 |   
1350  34 |   
1351  36 | 36
1352  38 |   
1353  40 |   
1354 (10 rows)
1356 -- left outer join three tables
1357 EXPLAIN (VERBOSE, COSTS OFF)
1358 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;
1359                                                                                                    QUERY PLAN                                                                                                    
1360 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1361  Foreign Scan
1362    Output: t1.c1, t2.c2, t3.c3
1363    Relations: ((public.ft2 t1) LEFT JOIN (public.ft2 t2)) LEFT JOIN (public.ft4 t3)
1364    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
1365 (4 rows)
1367 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;
1368  c1 | c2 |   c3   
1369 ----+----+--------
1370  11 |  1 | 
1371  12 |  2 | AAA012
1372  13 |  3 | 
1373  14 |  4 | AAA014
1374  15 |  5 | 
1375  16 |  6 | AAA016
1376  17 |  7 | 
1377  18 |  8 | AAA018
1378  19 |  9 | 
1379  20 |  0 | AAA020
1380 (10 rows)
1382 -- left outer join + placement of clauses.
1383 -- clauses within the nullable side are not pulled up, but top level clause on
1384 -- non-nullable side is pushed into non-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) WHERE t1.c1 < 10;
1387                                                                           QUERY PLAN                                                                           
1388 ---------------------------------------------------------------------------------------------------------------------------------------------------------------
1389  Foreign Scan
1390    Output: t1.c1, t1.c2, ft5.c1, ft5.c2
1391    Relations: (public.ft4 t1) LEFT JOIN (public.ft5)
1392    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))
1393 (4 rows)
1395 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;
1396  c1 | c2 | c1 | c2 
1397 ----+----+----+----
1398   2 |  3 |    |   
1399   4 |  5 |    |   
1400   6 |  7 |  6 |  7
1401   8 |  9 |    |   
1402 (4 rows)
1404 -- clauses within the nullable side are not pulled up, but the top level clause
1405 -- on nullable side is not pushed down into nullable side
1406 EXPLAIN (VERBOSE, COSTS OFF)
1407 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)
1408                         WHERE (t2.c1 < 10 OR t2.c1 IS NULL) AND t1.c1 < 10;
1409                                                                                               QUERY PLAN                                                                                               
1410 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1411  Foreign Scan
1412    Output: t1.c1, t1.c2, ft5.c1, ft5.c2
1413    Relations: (public.ft4 t1) LEFT JOIN (public.ft5)
1414    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))
1415 (4 rows)
1417 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)
1418                         WHERE (t2.c1 < 10 OR t2.c1 IS NULL) AND t1.c1 < 10;
1419  c1 | c2 | c1 | c2 
1420 ----+----+----+----
1421   2 |  3 |    |   
1422   4 |  5 |    |   
1423   6 |  7 |  6 |  7
1424   8 |  9 |    |   
1425 (4 rows)
1427 -- right outer join
1428 EXPLAIN (VERBOSE, COSTS OFF)
1429 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;
1430                                                                                            QUERY PLAN                                                                                           
1431 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1432  Foreign Scan
1433    Output: t1.c1, t2.c1
1434    Relations: (public.ft4 t2) LEFT JOIN (public.ft5 t1)
1435    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
1436 (4 rows)
1438 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;
1439  c1 | c1 
1440 ----+----
1441     | 22
1442  24 | 24
1443     | 26
1444     | 28
1445  30 | 30
1446     | 32
1447     | 34
1448  36 | 36
1449     | 38
1450     | 40
1451 (10 rows)
1453 -- right outer join three tables
1454 EXPLAIN (VERBOSE, COSTS OFF)
1455 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;
1456                                                                                                    QUERY PLAN                                                                                                    
1457 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1458  Foreign Scan
1459    Output: t1.c1, t2.c2, t3.c3
1460    Relations: ((public.ft4 t3) LEFT JOIN (public.ft2 t2)) LEFT JOIN (public.ft2 t1)
1461    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
1462 (4 rows)
1464 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;
1465  c1 | c2 |   c3   
1466 ----+----+--------
1467  22 |  2 | AAA022
1468  24 |  4 | AAA024
1469  26 |  6 | AAA026
1470  28 |  8 | AAA028
1471  30 |  0 | AAA030
1472  32 |  2 | AAA032
1473  34 |  4 | AAA034
1474  36 |  6 | AAA036
1475  38 |  8 | AAA038
1476  40 |  0 | AAA040
1477 (10 rows)
1479 -- full outer join
1480 EXPLAIN (VERBOSE, COSTS OFF)
1481 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;
1482                                                                                            QUERY PLAN                                                                                           
1483 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1484  Foreign Scan
1485    Output: t1.c1, t2.c1
1486    Relations: (public.ft4 t1) FULL JOIN (public.ft5 t2)
1487    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
1488 (4 rows)
1490 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;
1491  c1  | c1 
1492 -----+----
1493   92 |   
1494   94 |   
1495   96 | 96
1496   98 |   
1497  100 |   
1498      |  3
1499      |  9
1500      | 15
1501      | 21
1502      | 27
1503 (10 rows)
1505 -- full outer join with restrictions on the joining relations
1506 -- a. the joining relations are both base relations
1507 EXPLAIN (VERBOSE, COSTS OFF)
1508 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;
1509                                                                                                                                   QUERY PLAN                                                                                                                                   
1510 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1511  Foreign Scan
1512    Output: ft4.c1, ft5.c1
1513    Relations: (public.ft4) FULL JOIN (public.ft5)
1514    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
1515 (4 rows)
1517 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;
1518  c1 | c1 
1519 ----+----
1520  50 |   
1521  52 |   
1522  54 | 54
1523  56 |   
1524  58 |   
1525  60 | 60
1526     | 51
1527     | 57
1528 (8 rows)
1530 EXPLAIN (VERBOSE, COSTS OFF)
1531 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;
1532                                                                                                              QUERY PLAN                                                                                                              
1533 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1534  Foreign Scan
1535    Output: 1
1536    Relations: (public.ft4) FULL JOIN (public.ft5)
1537    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
1538 (4 rows)
1540 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;
1541  ?column? 
1542 ----------
1543         1
1544         1
1545         1
1546         1
1547         1
1548         1
1549         1
1550         1
1551         1
1552         1
1553 (10 rows)
1555 -- b. one of the joining relations is a base relation and the other is a join
1556 -- relation
1557 EXPLAIN (VERBOSE, COSTS OFF)
1558 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;
1559                                                                                                                                                                                      QUERY PLAN                                                                                                                                                                                      
1560 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1561  Foreign Scan
1562    Output: ft4.c1, t2.c1, t3.c1
1563    Relations: (public.ft4) FULL JOIN ((public.ft4 t2) LEFT JOIN (public.ft5 t3))
1564    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
1565 (4 rows)
1567 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;
1568  c1 | a  | b  
1569 ----+----+----
1570  50 | 50 |   
1571  52 | 52 |   
1572  54 | 54 | 54
1573  56 | 56 |   
1574  58 | 58 |   
1575  60 | 60 | 60
1576 (6 rows)
1578 -- c. test deparsing the remote query as nested subqueries
1579 EXPLAIN (VERBOSE, COSTS OFF)
1580 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;
1581                                                                                                                                                                                                                                                      QUERY PLAN                                                                                                                                                                                                                                                     
1582 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1583  Foreign Scan
1584    Output: ft4.c1, ft4_1.c1, ft5.c1
1585    Relations: (public.ft4) FULL JOIN ((public.ft4 ft4_1) FULL JOIN (public.ft5))
1586    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
1587 (4 rows)
1589 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;
1590  c1 | a  | b  
1591 ----+----+----
1592  50 | 50 |   
1593  52 | 52 |   
1594  54 | 54 | 54
1595  56 | 56 |   
1596  58 | 58 |   
1597  60 | 60 | 60
1598     |    | 51
1599     |    | 57
1600 (8 rows)
1602 -- d. test deparsing rowmarked relations as subqueries
1603 EXPLAIN (VERBOSE, COSTS OFF)
1604 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;
1605                                                                                                                                                                                              QUERY PLAN                                                                                                                                                                                             
1606 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1607  LockRows
1608    Output: "T 3".c1, ft4.c1, ft5.c1, "T 3".ctid, ft4.*, ft5.*
1609    ->  Nested Loop
1610          Output: "T 3".c1, ft4.c1, ft5.c1, "T 3".ctid, ft4.*, ft5.*
1611          ->  Foreign Scan
1612                Output: ft4.c1, ft4.*, ft5.c1, ft5.*
1613                Relations: (public.ft4) FULL JOIN (public.ft5)
1614                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
1615                ->  Sort
1616                      Output: ft4.c1, ft4.*, ft5.c1, ft5.*
1617                      Sort Key: ft4.c1, ft5.c1
1618                      ->  Hash Full Join
1619                            Output: ft4.c1, ft4.*, ft5.c1, ft5.*
1620                            Hash Cond: (ft4.c1 = ft5.c1)
1621                            Filter: ((ft4.c1 IS NULL) OR (ft4.c1 IS NOT NULL))
1622                            ->  Foreign Scan on public.ft4
1623                                  Output: ft4.c1, ft4.*
1624                                  Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3" WHERE ((c1 >= 50)) AND ((c1 <= 60))
1625                            ->  Hash
1626                                  Output: ft5.c1, ft5.*
1627                                  ->  Foreign Scan on public.ft5
1628                                        Output: ft5.c1, ft5.*
1629                                        Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 4" WHERE ((c1 >= 50)) AND ((c1 <= 60))
1630          ->  Materialize
1631                Output: "T 3".c1, "T 3".ctid
1632                ->  Seq Scan on "S 1"."T 3"
1633                      Output: "T 3".c1, "T 3".ctid
1634                      Filter: ("T 3".c1 = 50)
1635 (28 rows)
1637 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;
1638  c1 | a  | b  
1639 ----+----+----
1640  50 | 50 |   
1641  50 | 52 |   
1642  50 | 54 | 54
1643  50 | 56 |   
1644  50 | 58 |   
1645  50 | 60 | 60
1646  50 |    | 51
1647  50 |    | 57
1648 (8 rows)
1650 -- full outer join + inner join
1651 EXPLAIN (VERBOSE, COSTS OFF)
1652 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;
1653                                                                                                                                                  QUERY PLAN                                                                                                                                                 
1654 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1655  Foreign Scan
1656    Output: t1.c1, t2.c1, t3.c1
1657    Relations: ((public.ft4 t1) INNER JOIN (public.ft5 t2)) FULL JOIN (public.ft4 t3)
1658    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
1659 (4 rows)
1661 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;
1662  c1 | c1 | c1 
1663 ----+----+----
1664  52 | 51 |   
1665  58 | 57 |   
1666     |    |  2
1667     |    |  4
1668     |    |  6
1669     |    |  8
1670     |    | 10
1671     |    | 12
1672     |    | 14
1673     |    | 16
1674 (10 rows)
1676 -- full outer join three tables
1677 EXPLAIN (VERBOSE, COSTS OFF)
1678 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;
1679                                                                                                    QUERY PLAN                                                                                                    
1680 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1681  Foreign Scan
1682    Output: t1.c1, t2.c2, t3.c3
1683    Relations: ((public.ft2 t1) FULL JOIN (public.ft2 t2)) FULL JOIN (public.ft4 t3)
1684    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
1685 (4 rows)
1687 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;
1688  c1 | c2 |   c3   
1689 ----+----+--------
1690  11 |  1 | 
1691  12 |  2 | AAA012
1692  13 |  3 | 
1693  14 |  4 | AAA014
1694  15 |  5 | 
1695  16 |  6 | AAA016
1696  17 |  7 | 
1697  18 |  8 | AAA018
1698  19 |  9 | 
1699  20 |  0 | AAA020
1700 (10 rows)
1702 -- full outer join + right outer join
1703 EXPLAIN (VERBOSE, COSTS OFF)
1704 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;
1705                                                                                                    QUERY PLAN                                                                                                    
1706 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1707  Foreign Scan
1708    Output: t1.c1, t2.c2, t3.c3
1709    Relations: ((public.ft4 t3) LEFT JOIN (public.ft2 t2)) LEFT JOIN (public.ft2 t1)
1710    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
1711 (4 rows)
1713 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;
1714  c1 | c2 |   c3   
1715 ----+----+--------
1716  22 |  2 | AAA022
1717  24 |  4 | AAA024
1718  26 |  6 | AAA026
1719  28 |  8 | AAA028
1720  30 |  0 | AAA030
1721  32 |  2 | AAA032
1722  34 |  4 | AAA034
1723  36 |  6 | AAA036
1724  38 |  8 | AAA038
1725  40 |  0 | AAA040
1726 (10 rows)
1728 -- right outer join + full outer join
1729 EXPLAIN (VERBOSE, COSTS OFF)
1730 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;
1731                                                                                                    QUERY PLAN                                                                                                    
1732 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1733  Foreign Scan
1734    Output: t1.c1, t2.c2, t3.c3
1735    Relations: ((public.ft2 t2) LEFT JOIN (public.ft2 t1)) FULL JOIN (public.ft4 t3)
1736    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
1737 (4 rows)
1739 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;
1740  c1 | c2 |   c3   
1741 ----+----+--------
1742  11 |  1 | 
1743  12 |  2 | AAA012
1744  13 |  3 | 
1745  14 |  4 | AAA014
1746  15 |  5 | 
1747  16 |  6 | AAA016
1748  17 |  7 | 
1749  18 |  8 | AAA018
1750  19 |  9 | 
1751  20 |  0 | AAA020
1752 (10 rows)
1754 -- full outer join + left outer join
1755 EXPLAIN (VERBOSE, COSTS OFF)
1756 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;
1757                                                                                                    QUERY PLAN                                                                                                    
1758 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1759  Foreign Scan
1760    Output: t1.c1, t2.c2, t3.c3
1761    Relations: ((public.ft2 t1) FULL JOIN (public.ft2 t2)) LEFT JOIN (public.ft4 t3)
1762    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
1763 (4 rows)
1765 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;
1766  c1 | c2 |   c3   
1767 ----+----+--------
1768  11 |  1 | 
1769  12 |  2 | AAA012
1770  13 |  3 | 
1771  14 |  4 | AAA014
1772  15 |  5 | 
1773  16 |  6 | AAA016
1774  17 |  7 | 
1775  18 |  8 | AAA018
1776  19 |  9 | 
1777  20 |  0 | AAA020
1778 (10 rows)
1780 -- left outer join + full outer join
1781 EXPLAIN (VERBOSE, COSTS OFF)
1782 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;
1783                                                                                                    QUERY PLAN                                                                                                    
1784 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1785  Foreign Scan
1786    Output: t1.c1, t2.c2, t3.c3
1787    Relations: ((public.ft2 t1) LEFT JOIN (public.ft2 t2)) FULL JOIN (public.ft4 t3)
1788    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
1789 (4 rows)
1791 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;
1792  c1 | c2 |   c3   
1793 ----+----+--------
1794  11 |  1 | 
1795  12 |  2 | AAA012
1796  13 |  3 | 
1797  14 |  4 | AAA014
1798  15 |  5 | 
1799  16 |  6 | AAA016
1800  17 |  7 | 
1801  18 |  8 | AAA018
1802  19 |  9 | 
1803  20 |  0 | AAA020
1804 (10 rows)
1806 SET enable_memoize TO off;
1807 -- right outer join + left outer join
1808 EXPLAIN (VERBOSE, COSTS OFF)
1809 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;
1810                                                                                                    QUERY PLAN                                                                                                    
1811 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1812  Foreign Scan
1813    Output: t1.c1, t2.c2, t3.c3
1814    Relations: ((public.ft2 t2) LEFT JOIN (public.ft2 t1)) LEFT JOIN (public.ft4 t3)
1815    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
1816 (4 rows)
1818 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;
1819  c1 | c2 |   c3   
1820 ----+----+--------
1821  11 |  1 | 
1822  12 |  2 | AAA012
1823  13 |  3 | 
1824  14 |  4 | AAA014
1825  15 |  5 | 
1826  16 |  6 | AAA016
1827  17 |  7 | 
1828  18 |  8 | AAA018
1829  19 |  9 | 
1830  20 |  0 | AAA020
1831 (10 rows)
1833 RESET enable_memoize;
1834 -- left outer join + right outer join
1835 EXPLAIN (VERBOSE, COSTS OFF)
1836 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;
1837                                                                                                     QUERY PLAN                                                                                                    
1838 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1839  Foreign Scan
1840    Output: t1.c1, t2.c2, t3.c3
1841    Relations: (public.ft4 t3) LEFT JOIN ((public.ft2 t1) INNER JOIN (public.ft2 t2))
1842    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
1843 (4 rows)
1845 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;
1846  c1 | c2 |   c3   
1847 ----+----+--------
1848  22 |  2 | AAA022
1849  24 |  4 | AAA024
1850  26 |  6 | AAA026
1851  28 |  8 | AAA028
1852  30 |  0 | AAA030
1853  32 |  2 | AAA032
1854  34 |  4 | AAA034
1855  36 |  6 | AAA036
1856  38 |  8 | AAA038
1857  40 |  0 | AAA040
1858 (10 rows)
1860 -- full outer join + WHERE clause, only matched rows
1861 EXPLAIN (VERBOSE, COSTS OFF)
1862 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;
1863                                                                             QUERY PLAN                                                                            
1864 ------------------------------------------------------------------------------------------------------------------------------------------------------------------
1865  Limit
1866    Output: t1.c1, t2.c1
1867    ->  Sort
1868          Output: t1.c1, t2.c1
1869          Sort Key: t1.c1, t2.c1
1870          ->  Foreign Scan
1871                Output: t1.c1, t2.c1
1872                Relations: (public.ft4 t1) FULL JOIN (public.ft5 t2)
1873                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)))
1874 (9 rows)
1876 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;
1877  c1 | c1 
1878 ----+----
1879  66 | 66
1880  72 | 72
1881  78 | 78
1882  84 | 84
1883  90 | 90
1884  96 | 96
1885     |  3
1886     |  9
1887     | 15
1888     | 21
1889 (10 rows)
1891 -- full outer join + WHERE clause with shippable extensions set
1892 EXPLAIN (VERBOSE, COSTS OFF)
1893 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;
1894                                                                                                  QUERY PLAN                                                                                                 
1895 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1896  Foreign Scan
1897    Output: t1.c1, t2.c2, t1.c3
1898    Relations: (public.ft1 t1) FULL JOIN (public.ft2 t2)
1899    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
1900 (4 rows)
1902 ALTER SERVER loopback OPTIONS (DROP extensions);
1903 -- full outer join + WHERE clause with shippable extensions not set
1904 EXPLAIN (VERBOSE, COSTS OFF)
1905 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;
1906                                                           QUERY PLAN                                                           
1907 -------------------------------------------------------------------------------------------------------------------------------
1908  Limit
1909    Output: t1.c1, t2.c2, t1.c3
1910    ->  Foreign Scan
1911          Output: t1.c1, t2.c2, t1.c3
1912          Filter: (postgres_fdw_abs(t1.c1) > 0)
1913          Relations: (public.ft1 t1) FULL JOIN (public.ft2 t2)
1914          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"))))
1915 (7 rows)
1917 ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
1918 -- join two tables with FOR UPDATE clause
1919 -- tests whole-row reference for row marks
1920 EXPLAIN (VERBOSE, COSTS OFF)
1921 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;
1922                                                                                                                                                                                                                            QUERY PLAN                                                                                                                                                                                                                            
1923 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1924  Foreign Scan
1925    Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
1926    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
1927    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
1928 (4 rows)
1930 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;
1931  c1  | c1  
1932 -----+-----
1933  101 | 101
1934  102 | 102
1935  103 | 103
1936  104 | 104
1937  105 | 105
1938  106 | 106
1939  107 | 107
1940  108 | 108
1941  109 | 109
1942  110 | 110
1943 (10 rows)
1945 EXPLAIN (VERBOSE, COSTS OFF)
1946 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;
1947                                                                                                                                                                                                                                     QUERY PLAN                                                                                                                                                                                                                                    
1948 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1949  Foreign Scan
1950    Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
1951    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
1952    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
1953 (4 rows)
1955 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;
1956  c1  | c1  
1957 -----+-----
1958  101 | 101
1959  102 | 102
1960  103 | 103
1961  104 | 104
1962  105 | 105
1963  106 | 106
1964  107 | 107
1965  108 | 108
1966  109 | 109
1967  110 | 110
1968 (10 rows)
1970 -- join two tables with FOR SHARE clause
1971 EXPLAIN (VERBOSE, COSTS OFF)
1972 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;
1973                                                                                                                                                                                                                            QUERY PLAN                                                                                                                                                                                                                           
1974 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1975  Foreign Scan
1976    Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
1977    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
1978    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
1979 (4 rows)
1981 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;
1982  c1  | c1  
1983 -----+-----
1984  101 | 101
1985  102 | 102
1986  103 | 103
1987  104 | 104
1988  105 | 105
1989  106 | 106
1990  107 | 107
1991  108 | 108
1992  109 | 109
1993  110 | 110
1994 (10 rows)
1996 EXPLAIN (VERBOSE, COSTS OFF)
1997 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;
1998                                                                                                                                                                                                                                    QUERY PLAN                                                                                                                                                                                                                                   
1999 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2000  Foreign Scan
2001    Output: t1.c1, t2.c1, t1.c3, t1.*, t2.*
2002    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2003    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
2004 (4 rows)
2006 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;
2007  c1  | c1  
2008 -----+-----
2009  101 | 101
2010  102 | 102
2011  103 | 103
2012  104 | 104
2013  105 | 105
2014  106 | 106
2015  107 | 107
2016  108 | 108
2017  109 | 109
2018  110 | 110
2019 (10 rows)
2021 -- join in CTE
2022 EXPLAIN (VERBOSE, COSTS OFF)
2023 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;
2024                                                              QUERY PLAN                                                              
2025 -------------------------------------------------------------------------------------------------------------------------------------
2026  Limit
2027    Output: t.c1_1, t.c2_1, t.c1_3
2028    CTE t
2029      ->  Foreign Scan
2030            Output: t1.c1, t1.c3, t2.c1
2031            Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2032            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"))))
2033    ->  Sort
2034          Output: t.c1_1, t.c2_1, t.c1_3
2035          Sort Key: t.c1_3, t.c1_1
2036          ->  CTE Scan on t
2037                Output: t.c1_1, t.c2_1, t.c1_3
2038 (12 rows)
2040 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;
2041  c1_1 | c2_1 
2042 ------+------
2043   101 |  101
2044   102 |  102
2045   103 |  103
2046   104 |  104
2047   105 |  105
2048   106 |  106
2049   107 |  107
2050   108 |  108
2051   109 |  109
2052   110 |  110
2053 (10 rows)
2055 -- ctid with whole-row reference
2056 EXPLAIN (VERBOSE, COSTS OFF)
2057 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;
2058                                                                                                                                                                                                                   QUERY PLAN                                                                                                                                                                                                                   
2059 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2060  Foreign Scan
2061    Output: t1.ctid, t1.*, t2.*, t1.c1, t1.c3
2062    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2063    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
2064 (4 rows)
2066 -- SEMI JOIN
2067 EXPLAIN (VERBOSE, COSTS OFF)
2068 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;
2069                                                                                              QUERY PLAN                                                                                              
2070 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2071  Foreign Scan
2072    Output: t1.c1
2073    Relations: (public.ft1 t1) SEMI JOIN (public.ft2 t2)
2074    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
2075 (4 rows)
2077 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;
2078  c1  
2079 -----
2080  101
2081  102
2082  103
2083  104
2084  105
2085  106
2086  107
2087  108
2088  109
2089  110
2090 (10 rows)
2092 -- ANTI JOIN, not pushed down
2093 EXPLAIN (VERBOSE, COSTS OFF)
2094 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;
2095                                       QUERY PLAN                                       
2096 ---------------------------------------------------------------------------------------
2097  Limit
2098    Output: t1.c1
2099    ->  Merge Anti Join
2100          Output: t1.c1
2101          Merge Cond: (t1.c1 = t2.c2)
2102          ->  Foreign Scan on public.ft1 t1
2103                Output: t1.c1
2104                Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
2105          ->  Foreign Scan on public.ft2 t2
2106                Output: t2.c2
2107                Remote SQL: SELECT c2 FROM "S 1"."T 1" ORDER BY c2 ASC NULLS LAST
2108 (11 rows)
2110 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;
2111  c1  
2112 -----
2113  110
2114  111
2115  112
2116  113
2117  114
2118  115
2119  116
2120  117
2121  118
2122  119
2123 (10 rows)
2125 -- CROSS JOIN can be pushed down
2126 EXPLAIN (VERBOSE, COSTS OFF)
2127 SELECT t1.c1, t2.c1 FROM ft1 t1 CROSS JOIN ft2 t2 ORDER BY t1.c1, t2.c1 OFFSET 100 LIMIT 10;
2128                                                                                            QUERY PLAN                                                                                            
2129 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2130  Foreign Scan
2131    Output: t1.c1, t2.c1
2132    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2133    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
2134 (4 rows)
2136 SELECT t1.c1, t2.c1 FROM ft1 t1 CROSS JOIN ft2 t2 ORDER BY t1.c1, t2.c1 OFFSET 100 LIMIT 10;
2137  c1 | c1  
2138 ----+-----
2139   1 | 101
2140   1 | 102
2141   1 | 103
2142   1 | 104
2143   1 | 105
2144   1 | 106
2145   1 | 107
2146   1 | 108
2147   1 | 109
2148   1 | 110
2149 (10 rows)
2151 -- different server, not pushed down. No result expected.
2152 EXPLAIN (VERBOSE, COSTS OFF)
2153 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;
2154                                       QUERY PLAN                                       
2155 ---------------------------------------------------------------------------------------
2156  Limit
2157    Output: t1.c1, t2.c1
2158    ->  Merge Join
2159          Output: t1.c1, t2.c1
2160          Merge Cond: (t2.c1 = t1.c1)
2161          ->  Foreign Scan on public.ft6 t2
2162                Output: t2.c1, t2.c2, t2.c3
2163                Remote SQL: SELECT c1 FROM "S 1"."T 4" ORDER BY c1 ASC NULLS LAST
2164          ->  Materialize
2165                Output: t1.c1, t1.c2, t1.c3
2166                ->  Foreign Scan on public.ft5 t1
2167                      Output: t1.c1, t1.c2, t1.c3
2168                      Remote SQL: SELECT c1 FROM "S 1"."T 4" ORDER BY c1 ASC NULLS LAST
2169 (13 rows)
2171 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;
2172  c1 | c1 
2173 ----+----
2174 (0 rows)
2176 -- unsafe join conditions (c8 has a UDT), not pushed down. Practically a CROSS
2177 -- JOIN since c8 in both tables has same value.
2178 EXPLAIN (VERBOSE, COSTS OFF)
2179 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;
2180                                QUERY PLAN                                
2181 -------------------------------------------------------------------------
2182  Limit
2183    Output: t1.c1, t2.c1
2184    ->  Sort
2185          Output: t1.c1, t2.c1
2186          Sort Key: t1.c1, t2.c1
2187          ->  Merge Left Join
2188                Output: t1.c1, t2.c1
2189                Merge Cond: (t1.c8 = t2.c8)
2190                ->  Sort
2191                      Output: t1.c1, t1.c8
2192                      Sort Key: t1.c8
2193                      ->  Foreign Scan on public.ft1 t1
2194                            Output: t1.c1, t1.c8
2195                            Remote SQL: SELECT "C 1", c8 FROM "S 1"."T 1"
2196                ->  Sort
2197                      Output: t2.c1, t2.c8
2198                      Sort Key: t2.c8
2199                      ->  Foreign Scan on public.ft2 t2
2200                            Output: t2.c1, t2.c8
2201                            Remote SQL: SELECT "C 1", c8 FROM "S 1"."T 1"
2202 (20 rows)
2204 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;
2205  c1 | c1  
2206 ----+-----
2207   1 | 101
2208   1 | 102
2209   1 | 103
2210   1 | 104
2211   1 | 105
2212   1 | 106
2213   1 | 107
2214   1 | 108
2215   1 | 109
2216   1 | 110
2217 (10 rows)
2219 -- unsafe conditions on one side (c8 has a UDT), not pushed down.
2220 EXPLAIN (VERBOSE, COSTS OFF)
2221 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;
2222                                  QUERY PLAN                                  
2223 -----------------------------------------------------------------------------
2224  Limit
2225    Output: t1.c1, t2.c1, t1.c3
2226    ->  Sort
2227          Output: t1.c1, t2.c1, t1.c3
2228          Sort Key: t1.c3, t1.c1
2229          ->  Hash Right Join
2230                Output: t1.c1, t2.c1, t1.c3
2231                Hash Cond: (t2.c1 = t1.c1)
2232                ->  Foreign Scan on public.ft2 t2
2233                      Output: t2.c1
2234                      Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
2235                ->  Hash
2236                      Output: t1.c1, t1.c3
2237                      ->  Foreign Scan on public.ft1 t1
2238                            Output: t1.c1, t1.c3
2239                            Filter: (t1.c8 = 'foo'::user_enum)
2240                            Remote SQL: SELECT "C 1", c3, c8 FROM "S 1"."T 1"
2241 (17 rows)
2243 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;
2244  c1  | c1  
2245 -----+-----
2246  101 | 101
2247  102 | 102
2248  103 | 103
2249  104 | 104
2250  105 | 105
2251  106 | 106
2252  107 | 107
2253  108 | 108
2254  109 | 109
2255  110 | 110
2256 (10 rows)
2258 -- join where unsafe to pushdown condition in WHERE clause has a column not
2259 -- in the SELECT clause. In this test unsafe clause needs to have column
2260 -- references from both joining sides so that the clause is not pushed down
2261 -- into one of the joining sides.
2262 EXPLAIN (VERBOSE, COSTS OFF)
2263 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;
2264                                                                       QUERY PLAN                                                                       
2265 -------------------------------------------------------------------------------------------------------------------------------------------------------
2266  Limit
2267    Output: t1.c1, t2.c1, t1.c3
2268    ->  Sort
2269          Output: t1.c1, t2.c1, t1.c3
2270          Sort Key: t1.c3, t1.c1
2271          ->  Foreign Scan
2272                Output: t1.c1, t2.c1, t1.c3
2273                Filter: (t1.c8 = t2.c8)
2274                Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2275                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"))))
2276 (10 rows)
2278 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;
2279  c1  | c1  
2280 -----+-----
2281  101 | 101
2282  102 | 102
2283  103 | 103
2284  104 | 104
2285  105 | 105
2286  106 | 106
2287  107 | 107
2288  108 | 108
2289  109 | 109
2290  110 | 110
2291 (10 rows)
2293 -- Aggregate after UNION, for testing setrefs
2294 EXPLAIN (VERBOSE, COSTS OFF)
2295 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;
2296                                                                      QUERY PLAN                                                                     
2297 ----------------------------------------------------------------------------------------------------------------------------------------------------
2298  Limit
2299    Output: t1.c1, (avg((t1.c1 + t2.c1)))
2300    ->  Sort
2301          Output: t1.c1, (avg((t1.c1 + t2.c1)))
2302          Sort Key: t1.c1
2303          ->  HashAggregate
2304                Output: t1.c1, avg((t1.c1 + t2.c1))
2305                Group Key: t1.c1
2306                ->  HashAggregate
2307                      Output: t1.c1, t2.c1
2308                      Group Key: t1.c1, t2.c1
2309                      ->  Append
2310                            ->  Foreign Scan
2311                                  Output: t1.c1, t2.c1
2312                                  Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2313                                  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"))))
2314                            ->  Foreign Scan
2315                                  Output: t1_1.c1, t2_1.c1
2316                                  Relations: (public.ft1 t1_1) INNER JOIN (public.ft2 t2_1)
2317                                  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"))))
2318 (20 rows)
2320 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;
2321  t1c1 |         avg          
2322 ------+----------------------
2323   101 | 202.0000000000000000
2324   102 | 204.0000000000000000
2325   103 | 206.0000000000000000
2326   104 | 208.0000000000000000
2327   105 | 210.0000000000000000
2328   106 | 212.0000000000000000
2329   107 | 214.0000000000000000
2330   108 | 216.0000000000000000
2331   109 | 218.0000000000000000
2332   110 | 220.0000000000000000
2333 (10 rows)
2335 -- join with lateral reference
2336 EXPLAIN (VERBOSE, COSTS OFF)
2337 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;
2338                                                                                    QUERY PLAN                                                                                   
2339 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2340  Limit
2341    Output: t1."C 1"
2342    ->  Nested Loop
2343          Output: t1."C 1"
2344          ->  Index Scan using t1_pkey on "S 1"."T 1" t1
2345                Output: t1."C 1", t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8
2346          ->  Memoize
2347                Cache Key: t1.c2
2348                Cache Mode: binary
2349                ->  Subquery Scan on q
2350                      ->  HashAggregate
2351                            Output: t2.c1, t3.c1
2352                            Group Key: t2.c1
2353                            ->  Foreign Scan
2354                                  Output: t2.c1, t3.c1
2355                                  Relations: (public.ft1 t2) INNER JOIN (public.ft2 t3)
2356                                  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))))
2357 (17 rows)
2359 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;
2360  C 1 
2361 -----
2362    1
2363    1
2364    1
2365    1
2366    1
2367    1
2368    1
2369    1
2370    1
2371    1
2372 (10 rows)
2374 -- join with pseudoconstant quals
2375 EXPLAIN (VERBOSE, COSTS OFF)
2376 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;
2377                                                                                            QUERY PLAN                                                                                           
2378 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2379  Limit
2380    Output: t1.c1, t2.c1, t1.c3
2381    ->  Result
2382          Output: t1.c1, t2.c1, t1.c3
2383          One-Time Filter: (CURRENT_USER = SESSION_USER)
2384          ->  Foreign Scan
2385                Output: t1.c1, t1.c3, t2.c1
2386                Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2387                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
2388 (9 rows)
2390 -- non-Var items in targetlist of the nullable rel of a join preventing
2391 -- push-down in some cases
2392 -- unable to push {ft1, ft2}
2393 EXPLAIN (VERBOSE, COSTS OFF)
2394 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;
2395                                                         QUERY PLAN                                                         
2396 ---------------------------------------------------------------------------------------------------------------------------
2397  Nested Loop Left Join
2398    Output: (13), ft2.c1
2399    Join Filter: (13 = ft2.c1)
2400    ->  Foreign Scan on public.ft2
2401          Output: ft2.c1
2402          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
2403    ->  Materialize
2404          Output: (13)
2405          ->  Foreign Scan on public.ft1
2406                Output: 13
2407                Remote SQL: SELECT NULL FROM "S 1"."T 1" WHERE (("C 1" = 13))
2408 (11 rows)
2410 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;
2411  a  | c1 
2412 ----+----
2413     | 10
2414     | 11
2415     | 12
2416  13 | 13
2417     | 14
2418     | 15
2419 (6 rows)
2421 -- ok to push {ft1, ft2} but not {ft1, ft2, ft4}
2422 EXPLAIN (VERBOSE, COSTS OFF)
2423 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;
2424                                                                                     QUERY PLAN                                                                                     
2425 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2426  Nested Loop Left Join
2427    Output: ft4.c1, (13), ft1.c1, ft2.c1
2428    Join Filter: (ft4.c1 = ft1.c1)
2429    ->  Foreign Scan on public.ft4
2430          Output: ft4.c1, ft4.c2, ft4.c3
2431          Remote SQL: SELECT c1 FROM "S 1"."T 3" WHERE ((c1 >= 10)) AND ((c1 <= 15))
2432    ->  Materialize
2433          Output: ft1.c1, ft2.c1, (13)
2434          ->  Foreign Scan
2435                Output: ft1.c1, ft2.c1, 13
2436                Relations: (public.ft1) INNER JOIN (public.ft2)
2437                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
2438 (12 rows)
2440 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;
2441  c1 | a  | b  | c  
2442 ----+----+----+----
2443  10 |    |    |   
2444  12 | 13 | 12 | 12
2445  14 |    |    |   
2446 (3 rows)
2448 -- join with nullable side with some columns with null values
2449 UPDATE ft5 SET c3 = null where c1 % 9 = 0;
2450 EXPLAIN (VERBOSE, COSTS OFF)
2451 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;
2452                                                                                                                                 QUERY PLAN                                                                                                                                 
2453 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2454  Foreign Scan
2455    Output: ft5.*, ft5.c1, ft5.c2, ft5.c3, ft4.c1, ft4.c2
2456    Relations: (public.ft5) INNER JOIN (public.ft4)
2457    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
2458 (4 rows)
2460 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;
2461       ft5       | c1 | c2 |   c3   | c1 | c2 
2462 ----------------+----+----+--------+----+----
2463  (12,13,AAA012) | 12 | 13 | AAA012 | 12 | 13
2464  (18,19,)       | 18 | 19 |        | 18 | 19
2465  (24,25,AAA024) | 24 | 25 | AAA024 | 24 | 25
2466  (30,31,AAA030) | 30 | 31 | AAA030 | 30 | 31
2467 (4 rows)
2469 -- multi-way join involving multiple merge joins
2470 -- (this case used to have EPQ-related planning problems)
2471 CREATE TABLE local_tbl (c1 int NOT NULL, c2 int NOT NULL, c3 text, CONSTRAINT local_tbl_pkey PRIMARY KEY (c1));
2472 INSERT INTO local_tbl SELECT id, id % 10, to_char(id, 'FM0000') FROM generate_series(1, 1000) id;
2473 ANALYZE local_tbl;
2474 SET enable_nestloop TO false;
2475 SET enable_hashjoin TO false;
2476 EXPLAIN (VERBOSE, COSTS OFF)
2477 SELECT * FROM ft1, ft2, ft4, ft5, local_tbl WHERE ft1.c1 = ft2.c1 AND ft1.c2 = ft4.c1
2478     AND ft1.c2 = ft5.c1 AND ft1.c2 = local_tbl.c1 AND ft1.c1 < 100 AND ft2.c1 < 100 FOR UPDATE;
2479                                                                                                                                                                                                                                                                                                                                                                                                                                                QUERY PLAN                                                                                                                                                                                                                                                                                                                                                                                                                                               
2480 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2481  LockRows
2482    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
2483    ->  Merge Join
2484          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
2485          Inner Unique: true
2486          Merge Cond: (ft1.c2 = local_tbl.c1)
2487          ->  Foreign Scan
2488                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.*
2489                Relations: (((public.ft1) INNER JOIN (public.ft2)) INNER JOIN (public.ft4)) INNER JOIN (public.ft5)
2490                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
2491                ->  Merge Join
2492                      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.*
2493                      Merge Cond: (ft1.c2 = ft5.c1)
2494                      ->  Merge Join
2495                            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.*
2496                            Merge Cond: (ft1.c2 = ft4.c1)
2497                            ->  Sort
2498                                  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.*
2499                                  Sort Key: ft1.c2
2500                                  ->  Merge Join
2501                                        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.*
2502                                        Merge Cond: (ft1.c1 = ft2.c1)
2503                                        ->  Sort
2504                                              Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*
2505                                              Sort Key: ft1.c1
2506                                              ->  Foreign Scan on public.ft1
2507                                                    Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*
2508                                                    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" < 100)) FOR UPDATE
2509                                        ->  Materialize
2510                                              Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.*
2511                                              ->  Foreign Scan on public.ft2
2512                                                    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.*
2513                                                    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
2514                            ->  Sort
2515                                  Output: ft4.c1, ft4.c2, ft4.c3, ft4.*
2516                                  Sort Key: ft4.c1
2517                                  ->  Foreign Scan on public.ft4
2518                                        Output: ft4.c1, ft4.c2, ft4.c3, ft4.*
2519                                        Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3" FOR UPDATE
2520                      ->  Sort
2521                            Output: ft5.c1, ft5.c2, ft5.c3, ft5.*
2522                            Sort Key: ft5.c1
2523                            ->  Foreign Scan on public.ft5
2524                                  Output: ft5.c1, ft5.c2, ft5.c3, ft5.*
2525                                  Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 4" FOR UPDATE
2526          ->  Index Scan using local_tbl_pkey on public.local_tbl
2527                Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, local_tbl.ctid
2528 (47 rows)
2530 SELECT * FROM ft1, ft2, ft4, ft5, local_tbl WHERE ft1.c1 = ft2.c1 AND ft1.c2 = ft4.c1
2531     AND ft1.c2 = ft5.c1 AND ft1.c2 = local_tbl.c1 AND ft1.c1 < 100 AND ft2.c1 < 100 FOR UPDATE;
2532  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  
2533 ----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+--------+----+----+--------+----+----+------
2534   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
2535  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
2536  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
2537  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
2538  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
2539  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
2540  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
2541  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
2542  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
2543  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
2544 (10 rows)
2546 RESET enable_nestloop;
2547 RESET enable_hashjoin;
2548 -- test that add_paths_with_pathkeys_for_rel() arranges for the epq_path to
2549 -- return columns needed by the parent ForeignScan node
2550 EXPLAIN (VERBOSE, COSTS OFF)
2551 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;
2552                                                                                                                                                                                                                               QUERY PLAN                                                                                                                                                                                                                              
2553 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2554  LockRows
2555    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.*
2556    ->  Merge Left Join
2557          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.*
2558          Merge Cond: (local_tbl.c1 = ft1.c1)
2559          ->  Index Scan using local_tbl_pkey on public.local_tbl
2560                Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, local_tbl.ctid
2561          ->  Materialize
2562                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))
2563                ->  Foreign Scan
2564                      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)
2565                      Relations: (public.ft1) INNER JOIN (public.ft2)
2566                      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
2567                      ->  Result
2568                            Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, ft2.c3
2569                            ->  Sort
2570                                  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
2571                                  Sort Key: ft1.c1
2572                                  ->  Hash Join
2573                                        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
2574                                        Hash Cond: (ft1.c1 = ft2.c1)
2575                                        ->  Foreign Scan on public.ft1
2576                                              Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*
2577                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" < 100))
2578                                        ->  Hash
2579                                              Output: ft2.*, ft2.c1, ft2.c3
2580                                              ->  Foreign Scan on public.ft2
2581                                                    Output: ft2.*, ft2.c1, ft2.c3
2582                                                    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
2583 (29 rows)
2585 ALTER SERVER loopback OPTIONS (DROP extensions);
2586 ALTER SERVER loopback OPTIONS (ADD fdw_startup_cost '10000.0');
2587 EXPLAIN (VERBOSE, COSTS OFF)
2588 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;
2589                                                                                                                                                                                                                             QUERY PLAN                                                                                                                                                                                                                             
2590 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2591  LockRows
2592    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.*
2593    ->  Nested Loop Left Join
2594          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.*
2595          Join Filter: (local_tbl.c3 = ft1.c3)
2596          ->  Index Scan using local_tbl_pkey on public.local_tbl
2597                Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, local_tbl.ctid
2598          ->  Materialize
2599                Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*
2600                ->  Foreign Scan
2601                      Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*
2602                      Filter: ((ft1.c1 - postgres_fdw_abs(ft2.c2)) = 0)
2603                      Relations: (public.ft1) INNER JOIN (public.ft2)
2604                      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
2605                      ->  Sort
2606                            Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, ft2.c2
2607                            Sort Key: ft1.c3
2608                            ->  Merge Join
2609                                  Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, ft2.c2
2610                                  Merge Cond: (ft1.c1 = ft2.c1)
2611                                  Join Filter: ((ft1.c1 - postgres_fdw_abs(ft2.c2)) = 0)
2612                                  ->  Sort
2613                                        Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*
2614                                        Sort Key: ft1.c1
2615                                        ->  Foreign Scan on public.ft1
2616                                              Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*
2617                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" < 100))
2618                                  ->  Materialize
2619                                        Output: ft2.*, ft2.c1, ft2.c2
2620                                        ->  Foreign Scan on public.ft2
2621                                              Output: ft2.*, ft2.c1, ft2.c2
2622                                              Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
2623 (32 rows)
2625 ALTER SERVER loopback OPTIONS (DROP fdw_startup_cost);
2626 ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
2627 DROP TABLE local_tbl;
2628 -- check join pushdown in situations where multiple userids are involved
2629 CREATE ROLE regress_view_owner SUPERUSER;
2630 CREATE USER MAPPING FOR regress_view_owner SERVER loopback;
2631 GRANT SELECT ON ft4 TO regress_view_owner;
2632 GRANT SELECT ON ft5 TO regress_view_owner;
2633 CREATE VIEW v4 AS SELECT * FROM ft4;
2634 CREATE VIEW v5 AS SELECT * FROM ft5;
2635 ALTER VIEW v5 OWNER TO regress_view_owner;
2636 EXPLAIN (VERBOSE, COSTS OFF)
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;  -- can't be pushed down, different view owners
2638                               QUERY PLAN                              
2639 ----------------------------------------------------------------------
2640  Limit
2641    Output: ft4.c1, ft5.c2, ft5.c1
2642    ->  Sort
2643          Output: ft4.c1, ft5.c2, ft5.c1
2644          Sort Key: ft4.c1, ft5.c1
2645          ->  Hash Left Join
2646                Output: ft4.c1, ft5.c2, ft5.c1
2647                Hash Cond: (ft4.c1 = ft5.c1)
2648                ->  Foreign Scan on public.ft4
2649                      Output: ft4.c1, ft4.c2, ft4.c3
2650                      Remote SQL: SELECT c1 FROM "S 1"."T 3"
2651                ->  Hash
2652                      Output: ft5.c2, ft5.c1
2653                      ->  Foreign Scan on public.ft5
2654                            Output: ft5.c2, ft5.c1
2655                            Remote SQL: SELECT c1, c2 FROM "S 1"."T 4"
2656 (16 rows)
2658 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;
2659  c1 | c2 
2660 ----+----
2661  22 |   
2662  24 | 25
2663  26 |   
2664  28 |   
2665  30 | 31
2666  32 |   
2667  34 |   
2668  36 | 37
2669  38 |   
2670  40 |   
2671 (10 rows)
2673 ALTER VIEW v4 OWNER TO regress_view_owner;
2674 EXPLAIN (VERBOSE, COSTS OFF)
2675 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
2676                                                                                               QUERY PLAN                                                                                               
2677 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2678  Foreign Scan
2679    Output: ft4.c1, ft5.c2, ft5.c1
2680    Relations: (public.ft4) LEFT JOIN (public.ft5)
2681    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
2682 (4 rows)
2684 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;
2685  c1 | c2 
2686 ----+----
2687  22 |   
2688  24 | 25
2689  26 |   
2690  28 |   
2691  30 | 31
2692  32 |   
2693  34 |   
2694  36 | 37
2695  38 |   
2696  40 |   
2697 (10 rows)
2699 EXPLAIN (VERBOSE, COSTS OFF)
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;  -- can't be pushed down, view owner not current user
2701                               QUERY PLAN                              
2702 ----------------------------------------------------------------------
2703  Limit
2704    Output: ft4.c1, t2.c2, t2.c1
2705    ->  Sort
2706          Output: ft4.c1, t2.c2, t2.c1
2707          Sort Key: ft4.c1, t2.c1
2708          ->  Hash Left Join
2709                Output: ft4.c1, t2.c2, t2.c1
2710                Hash Cond: (ft4.c1 = t2.c1)
2711                ->  Foreign Scan on public.ft4
2712                      Output: ft4.c1, ft4.c2, ft4.c3
2713                      Remote SQL: SELECT c1 FROM "S 1"."T 3"
2714                ->  Hash
2715                      Output: t2.c2, t2.c1
2716                      ->  Foreign Scan on public.ft5 t2
2717                            Output: t2.c2, t2.c1
2718                            Remote SQL: SELECT c1, c2 FROM "S 1"."T 4"
2719 (16 rows)
2721 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;
2722  c1 | c2 
2723 ----+----
2724  22 |   
2725  24 | 25
2726  26 |   
2727  28 |   
2728  30 | 31
2729  32 |   
2730  34 |   
2731  36 | 37
2732  38 |   
2733  40 |   
2734 (10 rows)
2736 ALTER VIEW v4 OWNER TO CURRENT_USER;
2737 EXPLAIN (VERBOSE, COSTS OFF)
2738 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
2739                                                                                               QUERY PLAN                                                                                               
2740 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2741  Foreign Scan
2742    Output: ft4.c1, t2.c2, t2.c1
2743    Relations: (public.ft4) LEFT JOIN (public.ft5 t2)
2744    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
2745 (4 rows)
2747 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;
2748  c1 | c2 
2749 ----+----
2750  22 |   
2751  24 | 25
2752  26 |   
2753  28 |   
2754  30 | 31
2755  32 |   
2756  34 |   
2757  36 | 37
2758  38 |   
2759  40 |   
2760 (10 rows)
2762 ALTER VIEW v4 OWNER TO regress_view_owner;
2763 -- Make sure this big CROSS JOIN query is pushed down
2764 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 CROSS JOIN ft2 CROSS JOIN ft4 CROSS JOIN ft5;
2765                                                                              QUERY PLAN                                                                              
2766 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
2767  Foreign Scan
2768    Output: (count(*))
2769    Relations: Aggregate on ((((public.ft1) INNER JOIN (public.ft2)) INNER JOIN (public.ft4)) INNER JOIN (public.ft5))
2770    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))
2771 (4 rows)
2773 -- Make sure query cancellation works
2774 BEGIN;
2775 SET LOCAL statement_timeout = '10ms';
2776 select count(*) from ft1 CROSS JOIN ft2 CROSS JOIN ft4 CROSS JOIN ft5; -- this takes very long
2777 ERROR:  canceling statement due to statement timeout
2778 COMMIT;
2779 -- ====================================================================
2780 -- Check that userid to use when querying the remote table is correctly
2781 -- propagated into foreign rels present in subqueries under an UNION ALL
2782 -- ====================================================================
2783 CREATE ROLE regress_view_owner_another;
2784 ALTER VIEW v4 OWNER TO regress_view_owner_another;
2785 GRANT SELECT ON ft4 TO regress_view_owner_another;
2786 ALTER FOREIGN TABLE ft4 OPTIONS (ADD use_remote_estimate 'true');
2787 -- The following should query the remote backing table of ft4 as user
2788 -- regress_view_owner_another, the view owner, though it fails as expected
2789 -- due to the lack of a user mapping for that user.
2790 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM v4;
2791 ERROR:  user mapping not found for user "regress_view_owner_another", server "loopback"
2792 -- Likewise, but with the query under an UNION ALL
2793 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM (SELECT * FROM v4 UNION ALL SELECT * FROM v4);
2794 ERROR:  user mapping not found for user "regress_view_owner_another", server "loopback"
2795 -- Should not get that error once a user mapping is created
2796 CREATE USER MAPPING FOR regress_view_owner_another SERVER loopback OPTIONS (password_required 'false');
2797 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM v4;
2798                     QUERY PLAN                    
2799 --------------------------------------------------
2800  Foreign Scan on public.ft4
2801    Output: ft4.c1, ft4.c2, ft4.c3
2802    Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3"
2803 (3 rows)
2805 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM (SELECT * FROM v4 UNION ALL SELECT * FROM v4);
2806                        QUERY PLAN                       
2807 --------------------------------------------------------
2808  Append
2809    ->  Foreign Scan on public.ft4
2810          Output: ft4.c1, ft4.c2, ft4.c3
2811          Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3"
2812    ->  Foreign Scan on public.ft4 ft4_1
2813          Output: ft4_1.c1, ft4_1.c2, ft4_1.c3
2814          Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3"
2815 (7 rows)
2817 DROP USER MAPPING FOR regress_view_owner_another SERVER loopback;
2818 DROP OWNED BY regress_view_owner_another;
2819 DROP ROLE regress_view_owner_another;
2820 ALTER FOREIGN TABLE ft4 OPTIONS (SET use_remote_estimate 'false');
2821 -- cleanup
2822 DROP OWNED BY regress_view_owner;
2823 DROP ROLE regress_view_owner;
2824 -- ===================================================================
2825 -- Aggregate and grouping queries
2826 -- ===================================================================
2827 -- Simple aggregates
2828 explain (verbose, costs off)
2829 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;
2830                                                                                               QUERY PLAN                                                                                               
2831 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2832  Foreign Scan
2833    Output: (count(c6)), (sum(c1)), (avg(c1)), (min(c2)), (max(c1)), (stddev(c2)), ((sum(c1)) * ((random() <= '1'::double precision))::integer), c2
2834    Relations: Aggregate on (public.ft1)
2835    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
2836 (4 rows)
2838 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;
2839  count |  sum  |         avg          | min | max  | stddev | sum2  
2840 -------+-------+----------------------+-----+------+--------+-------
2841    100 | 49600 | 496.0000000000000000 |   1 |  991 |      0 | 49600
2842    100 | 49700 | 497.0000000000000000 |   2 |  992 |      0 | 49700
2843    100 | 49800 | 498.0000000000000000 |   3 |  993 |      0 | 49800
2844    100 | 49900 | 499.0000000000000000 |   4 |  994 |      0 | 49900
2845    100 | 50500 | 505.0000000000000000 |   0 | 1000 |      0 | 50500
2846 (5 rows)
2848 explain (verbose, costs off)
2849 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;
2850                                                                                                       QUERY PLAN                                                                                                       
2851 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2852  Foreign Scan
2853    Output: (count(c6)), (sum(c1)), (avg(c1)), (min(c2)), (max(c1)), (stddev(c2)), ((sum(c1)) * ((random() <= '1'::double precision))::integer), c2
2854    Relations: Aggregate on (public.ft1)
2855    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
2856 (4 rows)
2858 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;
2859  count |  sum  |         avg          | min | max | stddev | sum2  
2860 -------+-------+----------------------+-----+-----+--------+-------
2861    100 | 49600 | 496.0000000000000000 |   1 | 991 |      0 | 49600
2862 (1 row)
2864 -- Aggregate is not pushed down as aggregation contains random()
2865 explain (verbose, costs off)
2866 select sum(c1 * (random() <= 1)::int) as sum, avg(c1) from ft1;
2867                                   QUERY PLAN                                   
2868 -------------------------------------------------------------------------------
2869  Aggregate
2870    Output: sum((c1 * ((random() <= '1'::double precision))::integer)), avg(c1)
2871    ->  Foreign Scan on public.ft1
2872          Output: c1
2873          Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
2874 (5 rows)
2876 -- Aggregate over join query
2877 explain (verbose, costs off)
2878 select count(*), sum(t1.c1), avg(t2.c1) from ft1 t1 inner join ft1 t2 on (t1.c2 = t2.c2) where t1.c2 = 6;
2879                                                                     QUERY PLAN                                                                    
2880 --------------------------------------------------------------------------------------------------------------------------------------------------
2881  Foreign Scan
2882    Output: (count(*)), (sum(t1.c1)), (avg(t2.c1))
2883    Relations: Aggregate on ((public.ft1 t1) INNER JOIN (public.ft1 t2))
2884    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))))
2885 (4 rows)
2887 select count(*), sum(t1.c1), avg(t2.c1) from ft1 t1 inner join ft1 t2 on (t1.c2 = t2.c2) where t1.c2 = 6;
2888  count |   sum   |         avg          
2889 -------+---------+----------------------
2890  10000 | 5010000 | 501.0000000000000000
2891 (1 row)
2893 -- Not pushed down due to local conditions present in underneath input rel
2894 explain (verbose, costs off)
2895 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;
2896                                                          QUERY PLAN                                                         
2897 ----------------------------------------------------------------------------------------------------------------------------
2898  Aggregate
2899    Output: sum(t1.c1), count(t2.c1)
2900    ->  Foreign Scan
2901          Output: t1.c1, t2.c1
2902          Filter: (((((t1.c1 * t2.c1) / (t1.c1 * t2.c1)))::double precision * random()) <= '1'::double precision)
2903          Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
2904          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"))))
2905 (7 rows)
2907 -- GROUP BY clause having expressions
2908 explain (verbose, costs off)
2909 select c2/2, sum(c2) * (c2/2) from ft1 group by c2/2 order by c2/2;
2910                                                     QUERY PLAN                                                    
2911 ------------------------------------------------------------------------------------------------------------------
2912  Foreign Scan
2913    Output: ((c2 / 2)), ((sum(c2) * (c2 / 2)))
2914    Relations: Aggregate on (public.ft1)
2915    Remote SQL: SELECT (c2 / 2), (sum(c2) * (c2 / 2)) FROM "S 1"."T 1" GROUP BY 1 ORDER BY (c2 / 2) ASC NULLS LAST
2916 (4 rows)
2918 select c2/2, sum(c2) * (c2/2) from ft1 group by c2/2 order by c2/2;
2919  ?column? | ?column? 
2920 ----------+----------
2921         0 |        0
2922         1 |      500
2923         2 |     1800
2924         3 |     3900
2925         4 |     6800
2926 (5 rows)
2928 -- Aggregates in subquery are pushed down.
2929 set enable_incremental_sort = off;
2930 explain (verbose, costs off)
2931 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;
2932                                                                  QUERY PLAN                                                                  
2933 ---------------------------------------------------------------------------------------------------------------------------------------------
2934  Aggregate
2935    Output: count(ft1.c2), sum(ft1.c2)
2936    ->  Foreign Scan
2937          Output: ft1.c2, (sum(ft1.c1)), (sqrt((ft1.c1)::double precision))
2938          Relations: Aggregate on (public.ft1)
2939          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
2940 (6 rows)
2942 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;
2943  count | sum  
2944 -------+------
2945   1000 | 4500
2946 (1 row)
2948 reset enable_incremental_sort;
2949 -- Aggregate is still pushed down by taking unshippable expression out
2950 explain (verbose, costs off)
2951 select c2 * (random() <= 1)::int as sum1, sum(c1) * c2 as sum2 from ft1 group by c2 order by 1, 2;
2952                                             QUERY PLAN                                             
2953 ---------------------------------------------------------------------------------------------------
2954  Sort
2955    Output: ((c2 * ((random() <= '1'::double precision))::integer)), ((sum(c1) * c2)), c2
2956    Sort Key: ((ft1.c2 * ((random() <= '1'::double precision))::integer)), ((sum(ft1.c1) * ft1.c2))
2957    ->  Foreign Scan
2958          Output: (c2 * ((random() <= '1'::double precision))::integer), ((sum(c1) * c2)), c2
2959          Relations: Aggregate on (public.ft1)
2960          Remote SQL: SELECT (sum("C 1") * c2), c2 FROM "S 1"."T 1" GROUP BY 2
2961 (7 rows)
2963 select c2 * (random() <= 1)::int as sum1, sum(c1) * c2 as sum2 from ft1 group by c2 order by 1, 2;
2964  sum1 |  sum2  
2965 ------+--------
2966     0 |      0
2967     1 |  49600
2968     2 |  99400
2969     3 | 149400
2970     4 | 199600
2971     5 | 250000
2972     6 | 300600
2973     7 | 351400
2974     8 | 402400
2975     9 | 453600
2976 (10 rows)
2978 -- Aggregate with unshippable GROUP BY clause are not pushed
2979 explain (verbose, costs off)
2980 select c2 * (random() <= 1)::int as c2 from ft2 group by c2 * (random() <= 1)::int order by 1;
2981                                   QUERY PLAN                                  
2982 ------------------------------------------------------------------------------
2983  Sort
2984    Output: ((c2 * ((random() <= '1'::double precision))::integer))
2985    Sort Key: ((ft2.c2 * ((random() <= '1'::double precision))::integer))
2986    ->  HashAggregate
2987          Output: ((c2 * ((random() <= '1'::double precision))::integer))
2988          Group Key: (ft2.c2 * ((random() <= '1'::double precision))::integer)
2989          ->  Foreign Scan on public.ft2
2990                Output: (c2 * ((random() <= '1'::double precision))::integer)
2991                Remote SQL: SELECT c2 FROM "S 1"."T 1"
2992 (9 rows)
2994 -- GROUP BY clause in various forms, cardinal, alias and constant expression
2995 explain (verbose, costs off)
2996 select count(c2) w, c2 x, 5 y, 7.0 z from ft1 group by 2, y, 9.0::int order by 2;
2997                                                  QUERY PLAN                                                 
2998 ------------------------------------------------------------------------------------------------------------
2999  Foreign Scan
3000    Output: (count(c2)), c2, 5, 7.0, 9
3001    Relations: Aggregate on (public.ft1)
3002    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
3003 (4 rows)
3005 select count(c2) w, c2 x, 5 y, 7.0 z from ft1 group by 2, y, 9.0::int order by 2;
3006   w  | x | y |  z  
3007 -----+---+---+-----
3008  100 | 0 | 5 | 7.0
3009  100 | 1 | 5 | 7.0
3010  100 | 2 | 5 | 7.0
3011  100 | 3 | 5 | 7.0
3012  100 | 4 | 5 | 7.0
3013  100 | 5 | 5 | 7.0
3014  100 | 6 | 5 | 7.0
3015  100 | 7 | 5 | 7.0
3016  100 | 8 | 5 | 7.0
3017  100 | 9 | 5 | 7.0
3018 (10 rows)
3020 -- GROUP BY clause referring to same column multiple times
3021 -- Also, ORDER BY contains an aggregate function
3022 explain (verbose, costs off)
3023 select c2, c2 from ft1 where c2 > 6 group by 1, 2 order by sum(c1);
3024                                                          QUERY PLAN                                                         
3025 ----------------------------------------------------------------------------------------------------------------------------
3026  Foreign Scan
3027    Output: c2, c2, (sum(c1))
3028    Relations: Aggregate on (public.ft1)
3029    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
3030 (4 rows)
3032 select c2, c2 from ft1 where c2 > 6 group by 1, 2 order by sum(c1);
3033  c2 | c2 
3034 ----+----
3035   7 |  7
3036   8 |  8
3037   9 |  9
3038 (3 rows)
3040 -- Testing HAVING clause shippability
3041 explain (verbose, costs off)
3042 select c2, sum(c1) from ft2 group by c2 having avg(c1) < 500 and sum(c1) < 49800 order by c2;
3043                                                                          QUERY PLAN                                                                         
3044 ------------------------------------------------------------------------------------------------------------------------------------------------------------
3045  Foreign Scan
3046    Output: c2, (sum(c1))
3047    Relations: Aggregate on (public.ft2)
3048    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
3049 (4 rows)
3051 select c2, sum(c1) from ft2 group by c2 having avg(c1) < 500 and sum(c1) < 49800 order by c2;
3052  c2 |  sum  
3053 ----+-------
3054   1 | 49600
3055   2 | 49700
3056 (2 rows)
3058 -- Unshippable HAVING clause will be evaluated locally, and other qual in HAVING clause is pushed down
3059 explain (verbose, costs off)
3060 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;
3061                                                               QUERY PLAN                                                               
3062 ---------------------------------------------------------------------------------------------------------------------------------------
3063  Aggregate
3064    Output: count(*)
3065    ->  Foreign Scan
3066          Output: ft1.c5, NULL::bigint, (sqrt((ft1.c2)::double precision))
3067          Filter: (((((avg(ft1.c1)) / (avg(ft1.c1))))::double precision * random()) <= '1'::double precision)
3068          Relations: Aggregate on (public.ft1)
3069          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))
3070 (7 rows)
3072 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;
3073  count 
3074 -------
3075     49
3076 (1 row)
3078 -- Aggregate in HAVING clause is not pushable, and thus aggregation is not pushed down
3079 explain (verbose, costs off)
3080 select sum(c1) from ft1 group by c2 having avg(c1 * (random() <= 1)::int) > 100 order by 1;
3081                                             QUERY PLAN                                             
3082 ---------------------------------------------------------------------------------------------------
3083  Sort
3084    Output: (sum(c1)), c2
3085    Sort Key: (sum(ft1.c1))
3086    ->  HashAggregate
3087          Output: sum(c1), c2
3088          Group Key: ft1.c2
3089          Filter: (avg((ft1.c1 * ((random() <= '1'::double precision))::integer)) > '100'::numeric)
3090          ->  Foreign Scan on public.ft1
3091                Output: c1, c2
3092                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1"
3093 (10 rows)
3095 -- Remote aggregate in combination with a local Param (for the output
3096 -- of an initplan) can be trouble, per bug #15781
3097 explain (verbose, costs off)
3098 select exists(select 1 from pg_enum), sum(c1) from ft1;
3099                     QUERY PLAN                    
3100 --------------------------------------------------
3101  Foreign Scan
3102    Output: (InitPlan 1).col1, (sum(ft1.c1))
3103    Relations: Aggregate on (public.ft1)
3104    Remote SQL: SELECT sum("C 1") FROM "S 1"."T 1"
3105    InitPlan 1
3106      ->  Seq Scan on pg_catalog.pg_enum
3107 (6 rows)
3109 select exists(select 1 from pg_enum), sum(c1) from ft1;
3110  exists |  sum   
3111 --------+--------
3112  t      | 500500
3113 (1 row)
3115 explain (verbose, costs off)
3116 select exists(select 1 from pg_enum), sum(c1) from ft1 group by 1;
3117                     QUERY PLAN                     
3118 ---------------------------------------------------
3119  GroupAggregate
3120    Output: (InitPlan 1).col1, sum(ft1.c1)
3121    InitPlan 1
3122      ->  Seq Scan on pg_catalog.pg_enum
3123    ->  Foreign Scan on public.ft1
3124          Output: ft1.c1
3125          Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
3126 (7 rows)
3128 select exists(select 1 from pg_enum), sum(c1) from ft1 group by 1;
3129  exists |  sum   
3130 --------+--------
3131  t      | 500500
3132 (1 row)
3134 -- Testing ORDER BY, DISTINCT, FILTER, Ordered-sets and VARIADIC within aggregates
3135 -- ORDER BY within aggregate, same column used to order
3136 explain (verbose, costs off)
3137 select array_agg(c1 order by c1) from ft1 where c1 < 100 group by c2 order by 1;
3138                                                                                             QUERY PLAN                                                                                            
3139 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3140  Foreign Scan
3141    Output: (array_agg(c1 ORDER BY c1)), c2
3142    Relations: Aggregate on (public.ft1)
3143    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
3144 (4 rows)
3146 select array_agg(c1 order by c1) from ft1 where c1 < 100 group by c2 order by 1;
3147            array_agg            
3148 --------------------------------
3149  {1,11,21,31,41,51,61,71,81,91}
3150  {2,12,22,32,42,52,62,72,82,92}
3151  {3,13,23,33,43,53,63,73,83,93}
3152  {4,14,24,34,44,54,64,74,84,94}
3153  {5,15,25,35,45,55,65,75,85,95}
3154  {6,16,26,36,46,56,66,76,86,96}
3155  {7,17,27,37,47,57,67,77,87,97}
3156  {8,18,28,38,48,58,68,78,88,98}
3157  {9,19,29,39,49,59,69,79,89,99}
3158  {10,20,30,40,50,60,70,80,90}
3159 (10 rows)
3161 -- ORDER BY within aggregate, different column used to order also using DESC
3162 explain (verbose, costs off)
3163 select array_agg(c5 order by c1 desc) from ft2 where c2 = 6 and c1 < 50;
3164                                                        QUERY PLAN                                                        
3165 -------------------------------------------------------------------------------------------------------------------------
3166  Foreign Scan
3167    Output: (array_agg(c5 ORDER BY c1 DESC))
3168    Relations: Aggregate on (public.ft2)
3169    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))
3170 (4 rows)
3172 select array_agg(c5 order by c1 desc) from ft2 where c2 = 6 and c1 < 50;
3173                                                                 array_agg                                                                 
3174 ------------------------------------------------------------------------------------------------------------------------------------------
3175  {"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"}
3176 (1 row)
3178 -- DISTINCT within aggregate
3179 explain (verbose, costs off)
3180 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;
3181                                                                                                                                QUERY PLAN                                                                                                                               
3182 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3183  Foreign Scan
3184    Output: (array_agg(DISTINCT (t1.c1 % 5))), ((t2.c1 % 3))
3185    Relations: Aggregate on ((public.ft4 t1) FULL JOIN (public.ft5 t2))
3186    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
3187 (4 rows)
3189 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;
3190   array_agg   
3191 --------------
3192  {0,1,2,3,4}
3193  {1,2,3,NULL}
3194 (2 rows)
3196 -- DISTINCT combined with ORDER BY within aggregate
3197 explain (verbose, costs off)
3198 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;
3199                                                                                                                                                                      QUERY PLAN                                                                                                                                                                     
3200 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3201  Foreign Scan
3202    Output: (array_agg(DISTINCT (t1.c1 % 5) ORDER BY (t1.c1 % 5))), ((t2.c1 % 3))
3203    Relations: Aggregate on ((public.ft4 t1) FULL JOIN (public.ft5 t2))
3204    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
3205 (4 rows)
3207 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;
3208   array_agg   
3209 --------------
3210  {0,1,2,3,4}
3211  {1,2,3,NULL}
3212 (2 rows)
3214 explain (verbose, costs off)
3215 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;
3216                                                                                                                                                                       QUERY PLAN                                                                                                                                                                      
3217 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3218  Foreign Scan
3219    Output: (array_agg(DISTINCT (t1.c1 % 5) ORDER BY (t1.c1 % 5) DESC NULLS LAST)), ((t2.c1 % 3))
3220    Relations: Aggregate on ((public.ft4 t1) FULL JOIN (public.ft5 t2))
3221    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
3222 (4 rows)
3224 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;
3225   array_agg   
3226 --------------
3227  {3,2,1,NULL}
3228  {4,3,2,1,0}
3229 (2 rows)
3231 -- FILTER within aggregate
3232 explain (verbose, costs off)
3233 select sum(c1) filter (where c1 < 100 and c2 > 5) from ft1 group by c2 order by 1 nulls last;
3234                                                                                          QUERY PLAN                                                                                         
3235 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3236  Foreign Scan
3237    Output: (sum(c1) FILTER (WHERE ((c1 < 100) AND (c2 > 5)))), c2
3238    Relations: Aggregate on (public.ft1)
3239    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
3240 (4 rows)
3242 select sum(c1) filter (where c1 < 100 and c2 > 5) from ft1 group by c2 order by 1 nulls last;
3243  sum 
3244 -----
3245  510
3246  520
3247  530
3248  540
3249     
3250     
3251     
3252     
3253     
3254     
3255 (10 rows)
3257 -- DISTINCT, ORDER BY and FILTER within aggregate
3258 explain (verbose, costs off)
3259 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;
3260                                                                                         QUERY PLAN                                                                                        
3261 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3262  Foreign Scan
3263    Output: (sum((c1 % 3))), (sum(DISTINCT (c1 % 3) ORDER BY (c1 % 3)) FILTER (WHERE ((c1 % 3) < 2))), c2
3264    Relations: Aggregate on (public.ft1)
3265    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
3266 (4 rows)
3268 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;
3269  sum | sum | c2 
3270 -----+-----+----
3271   99 |   1 |  6
3272 (1 row)
3274 -- Outer query is aggregation query
3275 explain (verbose, costs off)
3276 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;
3277                                                           QUERY PLAN                                                          
3278 ------------------------------------------------------------------------------------------------------------------------------
3279  Unique
3280    Output: ((SubPlan 1))
3281    ->  Sort
3282          Output: ((SubPlan 1))
3283          Sort Key: ((SubPlan 1))
3284          ->  Foreign Scan
3285                Output: (SubPlan 1)
3286                Relations: Aggregate on (public.ft2 t2)
3287                Remote SQL: SELECT count(*) FILTER (WHERE ((c2 = 6) AND ("C 1" < 10))) FROM "S 1"."T 1" WHERE (((c2 % 6) = 0))
3288                SubPlan 1
3289                  ->  Foreign Scan on public.ft1 t1
3290                        Output: (count(*) FILTER (WHERE ((t2.c2 = 6) AND (t2.c1 < 10))))
3291                        Remote SQL: SELECT NULL FROM "S 1"."T 1" WHERE (("C 1" = 6))
3292 (13 rows)
3294 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;
3295  count 
3296 -------
3297      1
3298 (1 row)
3300 -- Inner query is aggregation query
3301 explain (verbose, costs off)
3302 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;
3303                                                                       QUERY PLAN                                                                      
3304 ------------------------------------------------------------------------------------------------------------------------------------------------------
3305  Unique
3306    Output: ((SubPlan 1))
3307    ->  Sort
3308          Output: ((SubPlan 1))
3309          Sort Key: ((SubPlan 1))
3310          ->  Foreign Scan on public.ft2 t2
3311                Output: (SubPlan 1)
3312                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (((c2 % 6) = 0))
3313                SubPlan 1
3314                  ->  Foreign Scan
3315                        Output: (count(t1.c1) FILTER (WHERE ((t2.c2 = 6) AND (t2.c1 < 10))))
3316                        Relations: Aggregate on (public.ft1 t1)
3317                        Remote SQL: SELECT count("C 1") FILTER (WHERE (($1::integer = 6) AND ($2::integer < 10))) FROM "S 1"."T 1" WHERE (("C 1" = 6))
3318 (13 rows)
3320 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;
3321  count 
3322 -------
3323      0
3324      1
3325 (2 rows)
3327 -- Aggregate not pushed down as FILTER condition is not pushable
3328 explain (verbose, costs off)
3329 select sum(c1) filter (where (c1 / c1) * random() <= 1) from ft1 group by c2 order by 1;
3330                                                        QUERY PLAN                                                       
3331 ------------------------------------------------------------------------------------------------------------------------
3332  Sort
3333    Output: (sum(c1) FILTER (WHERE ((((c1 / c1))::double precision * random()) <= '1'::double precision))), c2
3334    Sort Key: (sum(ft1.c1) FILTER (WHERE ((((ft1.c1 / ft1.c1))::double precision * random()) <= '1'::double precision)))
3335    ->  HashAggregate
3336          Output: sum(c1) FILTER (WHERE ((((c1 / c1))::double precision * random()) <= '1'::double precision)), c2
3337          Group Key: ft1.c2
3338          ->  Foreign Scan on public.ft1
3339                Output: c1, c2
3340                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1"
3341 (9 rows)
3343 explain (verbose, costs off)
3344 select sum(c2) filter (where c2 in (select c2 from ft1 where c2 < 5)) from ft1;
3345                                   QUERY PLAN                                   
3346 -------------------------------------------------------------------------------
3347  Aggregate
3348    Output: sum(ft1.c2) FILTER (WHERE (ANY (ft1.c2 = (hashed SubPlan 1).col1)))
3349    ->  Foreign Scan on public.ft1
3350          Output: ft1.c2
3351          Remote SQL: SELECT c2 FROM "S 1"."T 1"
3352    SubPlan 1
3353      ->  Foreign Scan on public.ft1 ft1_1
3354            Output: ft1_1.c2
3355            Remote SQL: SELECT c2 FROM "S 1"."T 1" WHERE ((c2 < 5))
3356 (9 rows)
3358 -- Ordered-sets within aggregate
3359 explain (verbose, costs off)
3360 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;
3361                                                                                                                                                                            QUERY PLAN                                                                                                                                                                           
3362 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3363  Sort
3364    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)))
3365    Sort Key: ft1.c2
3366    ->  Foreign Scan
3367          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)))
3368          Relations: Aggregate on (public.ft1)
3369          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))
3370 (7 rows)
3372 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;
3373  c2 | rank | percentile_cont 
3374 ----+------+-----------------
3375   0 |  101 |              10
3376   1 |  101 |             100
3377   2 |    1 |             200
3378   3 |    1 |             300
3379   4 |    1 |             400
3380 (5 rows)
3382 -- Using multiple arguments within aggregates
3383 explain (verbose, costs off)
3384 select c1, rank(c1, c2) within group (order by c1, c2) from ft1 group by c1, c2 having c1 = 6 order by 1;
3385                                                                              QUERY PLAN                                                                             
3386 --------------------------------------------------------------------------------------------------------------------------------------------------------------------
3387  Foreign Scan
3388    Output: c1, (rank(c1, c2) WITHIN GROUP (ORDER BY c1, c2)), c2
3389    Relations: Aggregate on (public.ft1)
3390    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
3391 (4 rows)
3393 select c1, rank(c1, c2) within group (order by c1, c2) from ft1 group by c1, c2 having c1 = 6 order by 1;
3394  c1 | rank 
3395 ----+------
3396   6 |    1
3397 (1 row)
3399 -- User defined function for user defined aggregate, VARIADIC
3400 create function least_accum(anyelement, variadic anyarray)
3401 returns anyelement language sql as
3402   'select least($1, min($2[i])) from generate_subscripts($2,1) g(i)';
3403 create aggregate least_agg(variadic items anyarray) (
3404   stype = anyelement, sfunc = least_accum
3406 -- Disable hash aggregation for plan stability.
3407 set enable_hashagg to false;
3408 -- Not pushed down due to user defined aggregate
3409 explain (verbose, costs off)
3410 select c2, least_agg(c1) from ft1 group by c2 order by c2;
3411                                     QUERY PLAN                                    
3412 ----------------------------------------------------------------------------------
3413  GroupAggregate
3414    Output: c2, least_agg(VARIADIC ARRAY[c1])
3415    Group Key: ft1.c2
3416    ->  Foreign Scan on public.ft1
3417          Output: c2, c1
3418          Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" ORDER BY c2 ASC NULLS LAST
3419 (6 rows)
3421 -- Add function and aggregate into extension
3422 alter extension postgres_fdw add function least_accum(anyelement, variadic anyarray);
3423 alter extension postgres_fdw add aggregate least_agg(variadic items anyarray);
3424 alter server loopback options (set extensions 'postgres_fdw');
3425 -- Now aggregate will be pushed.  Aggregate will display VARIADIC argument.
3426 explain (verbose, costs off)
3427 select c2, least_agg(c1) from ft1 where c2 < 100 group by c2 order by c2;
3428                                                       QUERY PLAN                                                       
3429 -----------------------------------------------------------------------------------------------------------------------
3430  Sort
3431    Output: c2, (least_agg(VARIADIC ARRAY[c1]))
3432    Sort Key: ft1.c2
3433    ->  Foreign Scan
3434          Output: c2, (least_agg(VARIADIC ARRAY[c1]))
3435          Relations: Aggregate on (public.ft1)
3436          Remote SQL: SELECT c2, public.least_agg(VARIADIC ARRAY["C 1"]) FROM "S 1"."T 1" WHERE ((c2 < 100)) GROUP BY 1
3437 (7 rows)
3439 select c2, least_agg(c1) from ft1 where c2 < 100 group by c2 order by c2;
3440  c2 | least_agg 
3441 ----+-----------
3442   0 |        10
3443   1 |         1
3444   2 |         2
3445   3 |         3
3446   4 |         4
3447   5 |         5
3448   6 |         6
3449   7 |         7
3450   8 |         8
3451   9 |         9
3452 (10 rows)
3454 -- Remove function and aggregate from extension
3455 alter extension postgres_fdw drop function least_accum(anyelement, variadic anyarray);
3456 alter extension postgres_fdw drop aggregate least_agg(variadic items anyarray);
3457 alter server loopback options (set extensions 'postgres_fdw');
3458 -- Not pushed down as we have dropped objects from extension.
3459 explain (verbose, costs off)
3460 select c2, least_agg(c1) from ft1 group by c2 order by c2;
3461                                     QUERY PLAN                                    
3462 ----------------------------------------------------------------------------------
3463  GroupAggregate
3464    Output: c2, least_agg(VARIADIC ARRAY[c1])
3465    Group Key: ft1.c2
3466    ->  Foreign Scan on public.ft1
3467          Output: c2, c1
3468          Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" ORDER BY c2 ASC NULLS LAST
3469 (6 rows)
3471 -- Cleanup
3472 reset enable_hashagg;
3473 drop aggregate least_agg(variadic items anyarray);
3474 drop function least_accum(anyelement, variadic anyarray);
3475 -- Testing USING OPERATOR() in ORDER BY within aggregate.
3476 -- For this, we need user defined operators along with operator family and
3477 -- operator class.  Create those and then add them in extension.  Note that
3478 -- user defined objects are considered unshippable unless they are part of
3479 -- the extension.
3480 create operator public.<^ (
3481  leftarg = int4,
3482  rightarg = int4,
3483  procedure = int4eq
3485 create operator public.=^ (
3486  leftarg = int4,
3487  rightarg = int4,
3488  procedure = int4lt
3490 create operator public.>^ (
3491  leftarg = int4,
3492  rightarg = int4,
3493  procedure = int4gt
3495 create operator family my_op_family using btree;
3496 create function my_op_cmp(a int, b int) returns int as
3497   $$begin return btint4cmp(a, b); end $$ language plpgsql;
3498 create operator class my_op_class for type int using btree family my_op_family as
3499  operator 1 public.<^,
3500  operator 3 public.=^,
3501  operator 5 public.>^,
3502  function 1 my_op_cmp(int, int);
3503 -- This will not be pushed as user defined sort operator is not part of the
3504 -- extension yet.
3505 explain (verbose, costs off)
3506 select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
3507                                             QUERY PLAN                                            
3508 --------------------------------------------------------------------------------------------------
3509  GroupAggregate
3510    Output: array_agg(c1 ORDER BY c1 USING <^ NULLS LAST), c2
3511    ->  Sort
3512          Output: c1, c2
3513          Sort Key: ft2.c1 USING <^
3514          ->  Foreign Scan on public.ft2
3515                Output: c1, c2
3516                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6))
3517 (8 rows)
3519 -- This should not be pushed either.
3520 explain (verbose, costs off)
3521 select * from ft2 order by c1 using operator(public.<^);
3522                                   QUERY PLAN                                   
3523 -------------------------------------------------------------------------------
3524  Sort
3525    Output: c1, c2, c3, c4, c5, c6, c7, c8
3526    Sort Key: ft2.c1 USING <^
3527    ->  Foreign Scan on public.ft2
3528          Output: c1, c2, c3, c4, c5, c6, c7, c8
3529          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
3530 (6 rows)
3532 -- Update local stats on ft2
3533 ANALYZE ft2;
3534 -- Add into extension
3535 alter extension postgres_fdw add operator class my_op_class using btree;
3536 alter extension postgres_fdw add function my_op_cmp(a int, b int);
3537 alter extension postgres_fdw add operator family my_op_family using btree;
3538 alter extension postgres_fdw add operator public.<^(int, int);
3539 alter extension postgres_fdw add operator public.=^(int, int);
3540 alter extension postgres_fdw add operator public.>^(int, int);
3541 alter server loopback options (set extensions 'postgres_fdw');
3542 -- Now this will be pushed as sort operator is part of the extension.
3543 alter server loopback options (add fdw_tuple_cost '0.5');
3544 explain (verbose, costs off)
3545 select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
3546                                                                            QUERY PLAN                                                                           
3547 ----------------------------------------------------------------------------------------------------------------------------------------------------------------
3548  Foreign Scan
3549    Output: (array_agg(c1 ORDER BY c1 USING <^ NULLS LAST)), c2
3550    Relations: Aggregate on (public.ft2)
3551    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
3552 (4 rows)
3554 select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
3555            array_agg            
3556 --------------------------------
3557  {6,16,26,36,46,56,66,76,86,96}
3558 (1 row)
3560 alter server loopback options (drop fdw_tuple_cost);
3561 -- This should be pushed too.
3562 explain (verbose, costs off)
3563 select * from ft2 order by c1 using operator(public.<^);
3564                                                          QUERY PLAN                                                          
3565 -----------------------------------------------------------------------------------------------------------------------------
3566  Foreign Scan on public.ft2
3567    Output: c1, c2, c3, c4, c5, c6, c7, c8
3568    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
3569 (3 rows)
3571 -- Remove from extension
3572 alter extension postgres_fdw drop operator class my_op_class using btree;
3573 alter extension postgres_fdw drop function my_op_cmp(a int, b int);
3574 alter extension postgres_fdw drop operator family my_op_family using btree;
3575 alter extension postgres_fdw drop operator public.<^(int, int);
3576 alter extension postgres_fdw drop operator public.=^(int, int);
3577 alter extension postgres_fdw drop operator public.>^(int, int);
3578 alter server loopback options (set extensions 'postgres_fdw');
3579 -- This will not be pushed as sort operator is now removed from the extension.
3580 explain (verbose, costs off)
3581 select array_agg(c1 order by c1 using operator(public.<^)) from ft2 where c2 = 6 and c1 < 100 group by c2;
3582                                             QUERY PLAN                                            
3583 --------------------------------------------------------------------------------------------------
3584  GroupAggregate
3585    Output: array_agg(c1 ORDER BY c1 USING <^ NULLS LAST), c2
3586    ->  Sort
3587          Output: c1, c2
3588          Sort Key: ft2.c1 USING <^
3589          ->  Foreign Scan on public.ft2
3590                Output: c1, c2
3591                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE (("C 1" < 100)) AND ((c2 = 6))
3592 (8 rows)
3594 -- Cleanup
3595 drop operator class my_op_class using btree;
3596 drop function my_op_cmp(a int, b int);
3597 drop operator family my_op_family using btree;
3598 drop operator public.>^(int, int);
3599 drop operator public.=^(int, int);
3600 drop operator public.<^(int, int);
3601 -- Input relation to aggregate push down hook is not safe to pushdown and thus
3602 -- the aggregate cannot be pushed down to foreign server.
3603 explain (verbose, costs off)
3604 select count(t1.c3) from ft2 t1 left join ft2 t2 on (t1.c1 = random() * t2.c2);
3605                                         QUERY PLAN                                         
3606 -------------------------------------------------------------------------------------------
3607  Aggregate
3608    Output: count(t1.c3)
3609    ->  Nested Loop Left Join
3610          Output: t1.c3
3611          Join Filter: ((t1.c1)::double precision = (random() * (t2.c2)::double precision))
3612          ->  Foreign Scan on public.ft2 t1
3613                Output: t1.c3, t1.c1
3614                Remote SQL: SELECT "C 1", c3 FROM "S 1"."T 1"
3615          ->  Materialize
3616                Output: t2.c2
3617                ->  Foreign Scan on public.ft2 t2
3618                      Output: t2.c2
3619                      Remote SQL: SELECT c2 FROM "S 1"."T 1"
3620 (13 rows)
3622 -- Subquery in FROM clause having aggregate
3623 explain (verbose, costs off)
3624 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;
3625                                           QUERY PLAN                                           
3626 -----------------------------------------------------------------------------------------------
3627  Sort
3628    Output: (count(*)), x.b
3629    Sort Key: (count(*)), x.b
3630    ->  HashAggregate
3631          Output: count(*), x.b
3632          Group Key: x.b
3633          ->  Hash Join
3634                Output: x.b
3635                Inner Unique: true
3636                Hash Cond: (ft1.c2 = x.a)
3637                ->  Foreign Scan on public.ft1
3638                      Output: ft1.c2
3639                      Remote SQL: SELECT c2 FROM "S 1"."T 1"
3640                ->  Hash
3641                      Output: x.b, x.a
3642                      ->  Subquery Scan on x
3643                            Output: x.b, x.a
3644                            ->  Foreign Scan
3645                                  Output: ft1_1.c2, (sum(ft1_1.c1))
3646                                  Relations: Aggregate on (public.ft1 ft1_1)
3647                                  Remote SQL: SELECT c2, sum("C 1") FROM "S 1"."T 1" GROUP BY 1
3648 (21 rows)
3650 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;
3651  count |   b   
3652 -------+-------
3653    100 | 49600
3654    100 | 49700
3655    100 | 49800
3656    100 | 49900
3657    100 | 50000
3658    100 | 50100
3659    100 | 50200
3660    100 | 50300
3661    100 | 50400
3662    100 | 50500
3663 (10 rows)
3665 -- FULL join with IS NULL check in HAVING
3666 explain (verbose, costs off)
3667 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;
3668                                                                                                                                     QUERY PLAN                                                                                                                                     
3669 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3670  Foreign Scan
3671    Output: (avg(t1.c1)), (sum(t2.c1)), t2.c1
3672    Relations: Aggregate on ((public.ft4 t1) FULL JOIN (public.ft5 t2))
3673    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
3674 (4 rows)
3676 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;
3677          avg         | sum 
3678 ---------------------+-----
3679  51.0000000000000000 |    
3680                      |   3
3681                      |   9
3682 (3 rows)
3684 -- Aggregate over FULL join needing to deparse the joining relations as
3685 -- subqueries.
3686 explain (verbose, costs off)
3687 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);
3688                                                                                                                   QUERY PLAN                                                                                                                   
3689 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3690  Foreign Scan
3691    Output: (count(*)), (sum(ft4.c1)), (avg(ft5.c1))
3692    Relations: Aggregate on ((public.ft4) FULL JOIN (public.ft5))
3693    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))))
3694 (4 rows)
3696 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);
3697  count | sum |         avg         
3698 -------+-----+---------------------
3699      8 | 330 | 55.5000000000000000
3700 (1 row)
3702 -- ORDER BY expression is part of the target list but not pushed down to
3703 -- foreign server.
3704 explain (verbose, costs off)
3705 select sum(c2) * (random() <= 1)::int as sum from ft1 order by 1;
3706                                    QUERY PLAN                                   
3707 --------------------------------------------------------------------------------
3708  Sort
3709    Output: (((sum(c2)) * ((random() <= '1'::double precision))::integer))
3710    Sort Key: (((sum(ft1.c2)) * ((random() <= '1'::double precision))::integer))
3711    ->  Foreign Scan
3712          Output: ((sum(c2)) * ((random() <= '1'::double precision))::integer)
3713          Relations: Aggregate on (public.ft1)
3714          Remote SQL: SELECT sum(c2) FROM "S 1"."T 1"
3715 (7 rows)
3717 select sum(c2) * (random() <= 1)::int as sum from ft1 order by 1;
3718  sum  
3719 ------
3720  4500
3721 (1 row)
3723 -- LATERAL join, with parameterization
3724 set enable_hashagg to false;
3725 explain (verbose, costs off)
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                                               QUERY PLAN                                              
3728 ------------------------------------------------------------------------------------------------------
3729  Sort
3730    Output: t1.c2, qry.sum
3731    Sort Key: t1.c2
3732    ->  Nested Loop
3733          Output: t1.c2, qry.sum
3734          ->  Index Scan using t1_pkey on "S 1"."T 1" t1
3735                Output: t1."C 1", t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8
3736                Index Cond: (t1."C 1" < 100)
3737                Filter: (t1.c2 < 3)
3738          ->  Subquery Scan on qry
3739                Output: qry.sum, t2.c1
3740                Filter: ((t1.c2 * 2) = qry.sum)
3741                ->  Foreign Scan
3742                      Output: (sum((t2.c1 + t1."C 1"))), t2.c1
3743                      Relations: Aggregate on (public.ft2 t2)
3744                      Remote SQL: SELECT sum(("C 1" + $1::integer)), "C 1" FROM "S 1"."T 1" GROUP BY 2
3745 (16 rows)
3747 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;
3748  c2 | sum 
3749 ----+-----
3750   1 |   2
3751   2 |   4
3752 (2 rows)
3754 reset enable_hashagg;
3755 -- bug #15613: bad plan for foreign table scan with lateral reference
3756 EXPLAIN (VERBOSE, COSTS OFF)
3757 SELECT ref_0.c2, subq_1.*
3758 FROM
3759     "S 1"."T 1" AS ref_0,
3760     LATERAL (
3761         SELECT ref_0."C 1" c1, subq_0.*
3762         FROM (SELECT ref_0.c2, ref_1.c3
3763               FROM ft1 AS ref_1) AS subq_0
3764              RIGHT JOIN ft2 AS ref_3 ON (subq_0.c3 = ref_3.c3)
3765     ) AS subq_1
3766 WHERE ref_0."C 1" < 10 AND subq_1.c3 = '00001'
3767 ORDER BY ref_0."C 1";
3768                                                QUERY PLAN                                                
3769 ---------------------------------------------------------------------------------------------------------
3770  Nested Loop
3771    Output: ref_0.c2, ref_0."C 1", (ref_0.c2), ref_1.c3, ref_0."C 1"
3772    ->  Nested Loop
3773          Output: ref_0.c2, ref_0."C 1", ref_1.c3, (ref_0.c2)
3774          ->  Index Scan using t1_pkey on "S 1"."T 1" ref_0
3775                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
3776                Index Cond: (ref_0."C 1" < 10)
3777          ->  Foreign Scan on public.ft1 ref_1
3778                Output: ref_1.c3, ref_0.c2
3779                Remote SQL: SELECT c3 FROM "S 1"."T 1" WHERE ((c3 = '00001'))
3780    ->  Materialize
3781          Output: ref_3.c3
3782          ->  Foreign Scan on public.ft2 ref_3
3783                Output: ref_3.c3
3784                Remote SQL: SELECT c3 FROM "S 1"."T 1" WHERE ((c3 = '00001'))
3785 (15 rows)
3787 SELECT ref_0.c2, subq_1.*
3788 FROM
3789     "S 1"."T 1" AS ref_0,
3790     LATERAL (
3791         SELECT ref_0."C 1" c1, subq_0.*
3792         FROM (SELECT ref_0.c2, ref_1.c3
3793               FROM ft1 AS ref_1) AS subq_0
3794              RIGHT JOIN ft2 AS ref_3 ON (subq_0.c3 = ref_3.c3)
3795     ) AS subq_1
3796 WHERE ref_0."C 1" < 10 AND subq_1.c3 = '00001'
3797 ORDER BY ref_0."C 1";
3798  c2 | c1 | c2 |  c3   
3799 ----+----+----+-------
3800   1 |  1 |  1 | 00001
3801   2 |  2 |  2 | 00001
3802   3 |  3 |  3 | 00001
3803   4 |  4 |  4 | 00001
3804   5 |  5 |  5 | 00001
3805   6 |  6 |  6 | 00001
3806   7 |  7 |  7 | 00001
3807   8 |  8 |  8 | 00001
3808   9 |  9 |  9 | 00001
3809 (9 rows)
3811 -- Check with placeHolderVars
3812 explain (verbose, costs off)
3813 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);
3814                                                                         QUERY PLAN                                                                        
3815 ----------------------------------------------------------------------------------------------------------------------------------------------------------
3816  Aggregate
3817    Output: sum(q.a), count(q.b)
3818    ->  Nested Loop Left Join
3819          Output: q.a, q.b
3820          Inner Unique: true
3821          Join Filter: ((ft4.c1)::numeric <= q.b)
3822          ->  Foreign Scan on public.ft4
3823                Output: ft4.c1, ft4.c2, ft4.c3
3824                Remote SQL: SELECT c1 FROM "S 1"."T 3"
3825          ->  Materialize
3826                Output: q.a, q.b
3827                ->  Subquery Scan on q
3828                      Output: q.a, q.b
3829                      ->  Foreign Scan
3830                            Output: 13, (avg(ft1.c1)), NULL::bigint
3831                            Relations: Aggregate on ((public.ft2) LEFT JOIN (public.ft1))
3832                            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"))))
3833 (17 rows)
3835 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);
3836  sum | count 
3837 -----+-------
3838  650 |    50
3839 (1 row)
3841 -- Not supported cases
3842 -- Grouping sets
3843 explain (verbose, costs off)
3844 select c2, sum(c1) from ft1 where c2 < 3 group by rollup(c2) order by 1 nulls last;
3845                                   QUERY PLAN                                  
3846 ------------------------------------------------------------------------------
3847  Sort
3848    Output: c2, (sum(c1))
3849    Sort Key: ft1.c2
3850    ->  MixedAggregate
3851          Output: c2, sum(c1)
3852          Hash Key: ft1.c2
3853          Group Key: ()
3854          ->  Foreign Scan on public.ft1
3855                Output: c2, c1
3856                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE ((c2 < 3))
3857 (10 rows)
3859 select c2, sum(c1) from ft1 where c2 < 3 group by rollup(c2) order by 1 nulls last;
3860  c2 |  sum   
3861 ----+--------
3862   0 |  50500
3863   1 |  49600
3864   2 |  49700
3865     | 149800
3866 (4 rows)
3868 explain (verbose, costs off)
3869 select c2, sum(c1) from ft1 where c2 < 3 group by cube(c2) order by 1 nulls last;
3870                                   QUERY PLAN                                  
3871 ------------------------------------------------------------------------------
3872  Sort
3873    Output: c2, (sum(c1))
3874    Sort Key: ft1.c2
3875    ->  MixedAggregate
3876          Output: c2, sum(c1)
3877          Hash Key: ft1.c2
3878          Group Key: ()
3879          ->  Foreign Scan on public.ft1
3880                Output: c2, c1
3881                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE ((c2 < 3))
3882 (10 rows)
3884 select c2, sum(c1) from ft1 where c2 < 3 group by cube(c2) order by 1 nulls last;
3885  c2 |  sum   
3886 ----+--------
3887   0 |  50500
3888   1 |  49600
3889   2 |  49700
3890     | 149800
3891 (4 rows)
3893 explain (verbose, costs off)
3894 select c2, c6, sum(c1) from ft1 where c2 < 3 group by grouping sets(c2, c6) order by 1 nulls last, 2 nulls last;
3895                                     QUERY PLAN                                    
3896 ----------------------------------------------------------------------------------
3897  Sort
3898    Output: c2, c6, (sum(c1))
3899    Sort Key: ft1.c2, ft1.c6
3900    ->  HashAggregate
3901          Output: c2, c6, sum(c1)
3902          Hash Key: ft1.c2
3903          Hash Key: ft1.c6
3904          ->  Foreign Scan on public.ft1
3905                Output: c2, c6, c1
3906                Remote SQL: SELECT "C 1", c2, c6 FROM "S 1"."T 1" WHERE ((c2 < 3))
3907 (10 rows)
3909 select c2, c6, sum(c1) from ft1 where c2 < 3 group by grouping sets(c2, c6) order by 1 nulls last, 2 nulls last;
3910  c2 | c6 |  sum  
3911 ----+----+-------
3912   0 |    | 50500
3913   1 |    | 49600
3914   2 |    | 49700
3915     | 0  | 50500
3916     | 1  | 49600
3917     | 2  | 49700
3918 (6 rows)
3920 explain (verbose, costs off)
3921 select c2, sum(c1), grouping(c2) from ft1 where c2 < 3 group by c2 order by 1 nulls last;
3922                                   QUERY PLAN                                  
3923 ------------------------------------------------------------------------------
3924  Sort
3925    Output: c2, (sum(c1)), (GROUPING(c2))
3926    Sort Key: ft1.c2
3927    ->  HashAggregate
3928          Output: c2, sum(c1), GROUPING(c2)
3929          Group Key: ft1.c2
3930          ->  Foreign Scan on public.ft1
3931                Output: c2, c1
3932                Remote SQL: SELECT "C 1", c2 FROM "S 1"."T 1" WHERE ((c2 < 3))
3933 (9 rows)
3935 select c2, sum(c1), grouping(c2) from ft1 where c2 < 3 group by c2 order by 1 nulls last;
3936  c2 |  sum  | grouping 
3937 ----+-------+----------
3938   0 | 50500 |        0
3939   1 | 49600 |        0
3940   2 | 49700 |        0
3941 (3 rows)
3943 -- DISTINCT itself is not pushed down, whereas underneath aggregate is pushed
3944 explain (verbose, costs off)
3945 select distinct sum(c1)/1000 s from ft2 where c2 < 6 group by c2 order by 1;
3946                                               QUERY PLAN                                               
3947 -------------------------------------------------------------------------------------------------------
3948  Unique
3949    Output: ((sum(c1) / 1000)), c2
3950    ->  Sort
3951          Output: ((sum(c1) / 1000)), c2
3952          Sort Key: ((sum(ft2.c1) / 1000))
3953          ->  Foreign Scan
3954                Output: ((sum(c1) / 1000)), c2
3955                Relations: Aggregate on (public.ft2)
3956                Remote SQL: SELECT (sum("C 1") / 1000), c2 FROM "S 1"."T 1" WHERE ((c2 < 6)) GROUP BY 2
3957 (9 rows)
3959 select distinct sum(c1)/1000 s from ft2 where c2 < 6 group by c2 order by 1;
3960  s  
3961 ----
3962  49
3963  50
3964 (2 rows)
3966 -- WindowAgg
3967 explain (verbose, costs off)
3968 select c2, sum(c2), count(c2) over (partition by c2%2) from ft2 where c2 < 10 group by c2 order by 1;
3969                                                  QUERY PLAN                                                 
3970 ------------------------------------------------------------------------------------------------------------
3971  Sort
3972    Output: c2, (sum(c2)), (count(c2) OVER (?)), ((c2 % 2))
3973    Sort Key: ft2.c2
3974    ->  WindowAgg
3975          Output: c2, (sum(c2)), count(c2) OVER (?), ((c2 % 2))
3976          ->  Sort
3977                Output: c2, ((c2 % 2)), (sum(c2))
3978                Sort Key: ((ft2.c2 % 2))
3979                ->  Foreign Scan
3980                      Output: c2, ((c2 % 2)), (sum(c2))
3981                      Relations: Aggregate on (public.ft2)
3982                      Remote SQL: SELECT c2, (c2 % 2), sum(c2) FROM "S 1"."T 1" WHERE ((c2 < 10)) GROUP BY 1
3983 (12 rows)
3985 select c2, sum(c2), count(c2) over (partition by c2%2) from ft2 where c2 < 10 group by c2 order by 1;
3986  c2 | sum | count 
3987 ----+-----+-------
3988   0 |   0 |     5
3989   1 | 100 |     5
3990   2 | 200 |     5
3991   3 | 300 |     5
3992   4 | 400 |     5
3993   5 | 500 |     5
3994   6 | 600 |     5
3995   7 | 700 |     5
3996   8 | 800 |     5
3997   9 | 900 |     5
3998 (10 rows)
4000 explain (verbose, costs off)
4001 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;
4002                                             QUERY PLAN                                             
4003 ---------------------------------------------------------------------------------------------------
4004  Sort
4005    Output: c2, (array_agg(c2) OVER (?)), ((c2 % 2))
4006    Sort Key: ft1.c2
4007    ->  WindowAgg
4008          Output: c2, array_agg(c2) OVER (?), ((c2 % 2))
4009          ->  Sort
4010                Output: c2, ((c2 % 2))
4011                Sort Key: ((ft1.c2 % 2)), ft1.c2 DESC
4012                ->  Foreign Scan
4013                      Output: c2, ((c2 % 2))
4014                      Relations: Aggregate on (public.ft1)
4015                      Remote SQL: SELECT c2, (c2 % 2) FROM "S 1"."T 1" WHERE ((c2 < 10)) GROUP BY 1
4016 (12 rows)
4018 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;
4019  c2 |  array_agg  
4020 ----+-------------
4021   0 | {8,6,4,2,0}
4022   1 | {9,7,5,3,1}
4023   2 | {8,6,4,2}
4024   3 | {9,7,5,3}
4025   4 | {8,6,4}
4026   5 | {9,7,5}
4027   6 | {8,6}
4028   7 | {9,7}
4029   8 | {8}
4030   9 | {9}
4031 (10 rows)
4033 explain (verbose, costs off)
4034 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;
4035                                             QUERY PLAN                                             
4036 ---------------------------------------------------------------------------------------------------
4037  Sort
4038    Output: c2, (array_agg(c2) OVER (?)), ((c2 % 2))
4039    Sort Key: ft1.c2
4040    ->  WindowAgg
4041          Output: c2, array_agg(c2) OVER (?), ((c2 % 2))
4042          ->  Sort
4043                Output: c2, ((c2 % 2))
4044                Sort Key: ((ft1.c2 % 2)), ft1.c2
4045                ->  Foreign Scan
4046                      Output: c2, ((c2 % 2))
4047                      Relations: Aggregate on (public.ft1)
4048                      Remote SQL: SELECT c2, (c2 % 2) FROM "S 1"."T 1" WHERE ((c2 < 10)) GROUP BY 1
4049 (12 rows)
4051 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;
4052  c2 |  array_agg  
4053 ----+-------------
4054   0 | {0,2,4,6,8}
4055   1 | {1,3,5,7,9}
4056   2 | {2,4,6,8}
4057   3 | {3,5,7,9}
4058   4 | {4,6,8}
4059   5 | {5,7,9}
4060   6 | {6,8}
4061   7 | {7,9}
4062   8 | {8}
4063   9 | {9}
4064 (10 rows)
4066 -- ===================================================================
4067 -- parameterized queries
4068 -- ===================================================================
4069 -- simple join
4070 PREPARE st1(int, int) AS SELECT t1.c3, t2.c3 FROM ft1 t1, ft2 t2 WHERE t1.c1 = $1 AND t2.c1 = $2;
4071 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st1(1, 2);
4072                                                           QUERY PLAN                                                          
4073 ------------------------------------------------------------------------------------------------------------------------------
4074  Foreign Scan
4075    Output: t1.c3, t2.c3
4076    Relations: (public.ft1 t1) INNER JOIN (public.ft2 t2)
4077    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))))
4078 (4 rows)
4080 EXECUTE st1(1, 1);
4081   c3   |  c3   
4082 -------+-------
4083  00001 | 00001
4084 (1 row)
4086 EXECUTE st1(101, 101);
4087   c3   |  c3   
4088 -------+-------
4089  00101 | 00101
4090 (1 row)
4092 SET enable_hashjoin TO off;
4093 SET enable_sort TO off;
4094 -- subquery using stable function (can't be sent to remote)
4095 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;
4096 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st2(10, 20);
4097                                                             QUERY PLAN                                                            
4098 ----------------------------------------------------------------------------------------------------------------------------------
4099  Nested Loop Semi Join
4100    Output: t1.c1, t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8
4101    Join Filter: (t2.c3 = t1.c3)
4102    ->  Foreign Scan on public.ft1 t1
4103          Output: t1.c1, t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8
4104          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
4105    ->  Materialize
4106          Output: t2.c3
4107          ->  Foreign Scan on public.ft2 t2
4108                Output: t2.c3
4109                Filter: (date(t2.c4) = '01-17-1970'::date)
4110                Remote SQL: SELECT c3, c4 FROM "S 1"."T 1" WHERE (("C 1" > 10))
4111 (12 rows)
4113 EXECUTE st2(10, 20);
4114  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4115 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4116  16 |  6 | 00016 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
4117 (1 row)
4119 EXECUTE st2(101, 121);
4120  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4121 -----+----+-------+------------------------------+--------------------------+----+------------+-----
4122  116 |  6 | 00116 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
4123 (1 row)
4125 RESET enable_hashjoin;
4126 RESET enable_sort;
4127 -- subquery using immutable function (can be sent to remote)
4128 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;
4129 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st3(10, 20);
4130                                                                                                                               QUERY PLAN                                                                                                                              
4131 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4132  Sort
4133    Output: t1.c1, t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8
4134    Sort Key: t1.c1
4135    ->  Foreign Scan
4136          Output: t1.c1, t1.c2, t1.c3, t1.c4, t1.c5, t1.c6, t1.c7, t1.c8
4137          Relations: (public.ft1 t1) SEMI JOIN (public.ft2 t2)
4138          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)))
4139 (7 rows)
4141 EXECUTE st3(10, 20);
4142  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4143 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4144  16 |  6 | 00016 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo
4145 (1 row)
4147 EXECUTE st3(20, 30);
4148  c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 
4149 ----+----+----+----+----+----+----+----
4150 (0 rows)
4152 -- custom plan should be chosen initially
4153 PREPARE st4(int) AS SELECT * FROM ft1 t1 WHERE t1.c1 = $1;
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 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
4171                                          QUERY PLAN                                          
4172 ---------------------------------------------------------------------------------------------
4173  Foreign Scan on public.ft1 t1
4174    Output: c1, c2, c3, c4, c5, c6, c7, c8
4175    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4176 (3 rows)
4178 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
4179                                          QUERY PLAN                                          
4180 ---------------------------------------------------------------------------------------------
4181  Foreign Scan on public.ft1 t1
4182    Output: c1, c2, c3, c4, c5, c6, c7, c8
4183    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4184 (3 rows)
4186 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
4187                                          QUERY PLAN                                          
4188 ---------------------------------------------------------------------------------------------
4189  Foreign Scan on public.ft1 t1
4190    Output: c1, c2, c3, c4, c5, c6, c7, c8
4191    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4192 (3 rows)
4194 -- once we try it enough times, should switch to generic plan
4195 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st4(1);
4196                                               QUERY PLAN                                               
4197 -------------------------------------------------------------------------------------------------------
4198  Foreign Scan on public.ft1 t1
4199    Output: c1, c2, c3, c4, c5, c6, c7, c8
4200    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = $1::integer))
4201 (3 rows)
4203 -- value of $1 should not be sent to remote
4204 PREPARE st5(user_enum,int) AS SELECT * FROM ft1 t1 WHERE c8 = $1 and c1 = $2;
4205 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
4206                                          QUERY PLAN                                          
4207 ---------------------------------------------------------------------------------------------
4208  Foreign Scan on public.ft1 t1
4209    Output: c1, c2, c3, c4, c5, c6, c7, c8
4210    Filter: (t1.c8 = 'foo'::user_enum)
4211    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4212 (4 rows)
4214 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
4215                                          QUERY PLAN                                          
4216 ---------------------------------------------------------------------------------------------
4217  Foreign Scan on public.ft1 t1
4218    Output: c1, c2, c3, c4, c5, c6, c7, c8
4219    Filter: (t1.c8 = 'foo'::user_enum)
4220    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4221 (4 rows)
4223 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
4224                                          QUERY PLAN                                          
4225 ---------------------------------------------------------------------------------------------
4226  Foreign Scan on public.ft1 t1
4227    Output: c1, c2, c3, c4, c5, c6, c7, c8
4228    Filter: (t1.c8 = 'foo'::user_enum)
4229    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4230 (4 rows)
4232 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
4233                                          QUERY PLAN                                          
4234 ---------------------------------------------------------------------------------------------
4235  Foreign Scan on public.ft1 t1
4236    Output: c1, c2, c3, c4, c5, c6, c7, c8
4237    Filter: (t1.c8 = 'foo'::user_enum)
4238    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4239 (4 rows)
4241 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
4242                                          QUERY PLAN                                          
4243 ---------------------------------------------------------------------------------------------
4244  Foreign Scan on public.ft1 t1
4245    Output: c1, c2, c3, c4, c5, c6, c7, c8
4246    Filter: (t1.c8 = 'foo'::user_enum)
4247    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = 1))
4248 (4 rows)
4250 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st5('foo', 1);
4251                                               QUERY PLAN                                               
4252 -------------------------------------------------------------------------------------------------------
4253  Foreign Scan on public.ft1 t1
4254    Output: c1, c2, c3, c4, c5, c6, c7, c8
4255    Filter: (t1.c8 = $1)
4256    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = $1::integer))
4257 (4 rows)
4259 EXECUTE st5('foo', 1);
4260  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4261 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4262   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4263 (1 row)
4265 -- altering FDW options requires replanning
4266 PREPARE st6 AS SELECT * FROM ft1 t1 WHERE t1.c1 = t1.c2;
4267 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st6;
4268                                           QUERY PLAN                                          
4269 ----------------------------------------------------------------------------------------------
4270  Foreign Scan on public.ft1 t1
4271    Output: c1, c2, c3, c4, c5, c6, c7, c8
4272    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" = c2))
4273 (3 rows)
4275 PREPARE st7 AS INSERT INTO ft1 (c1,c2,c3) VALUES (1001,101,'foo');
4276 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st7;
4277                                                                                            QUERY PLAN                                                                                            
4278 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4279  Insert on public.ft1
4280    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)
4281    Batch Size: 1
4282    ->  Result
4283          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
4284 (5 rows)
4286 ALTER TABLE "S 1"."T 1" RENAME TO "T 0";
4287 ALTER FOREIGN TABLE ft1 OPTIONS (SET table_name 'T 0');
4288 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st6;
4289                                           QUERY PLAN                                          
4290 ----------------------------------------------------------------------------------------------
4291  Foreign Scan on public.ft1 t1
4292    Output: c1, c2, c3, c4, c5, c6, c7, c8
4293    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 0" WHERE (("C 1" = c2))
4294 (3 rows)
4296 EXECUTE st6;
4297  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4298 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4299   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4300   2 |  2 | 00002 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo
4301   3 |  3 | 00003 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo
4302   4 |  4 | 00004 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4  | 4          | foo
4303   5 |  5 | 00005 | Tue Jan 06 00:00:00 1970 PST | Tue Jan 06 00:00:00 1970 | 5  | 5          | foo
4304   6 |  6 | 00006 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo
4305   7 |  7 | 00007 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
4306   8 |  8 | 00008 | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
4307   9 |  9 | 00009 | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9  | 9          | foo
4308 (9 rows)
4310 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st7;
4311                                                                                            QUERY PLAN                                                                                            
4312 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4313  Insert on public.ft1
4314    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)
4315    Batch Size: 1
4316    ->  Result
4317          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
4318 (5 rows)
4320 ALTER TABLE "S 1"."T 0" RENAME TO "T 1";
4321 ALTER FOREIGN TABLE ft1 OPTIONS (SET table_name 'T 1');
4322 PREPARE st8 AS SELECT count(c3) FROM ft1 t1 WHERE t1.c1 === t1.c2;
4323 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8;
4324                                        QUERY PLAN                                        
4325 -----------------------------------------------------------------------------------------
4326  Foreign Scan
4327    Output: (count(c3))
4328    Relations: Aggregate on (public.ft1 t1)
4329    Remote SQL: SELECT count(c3) FROM "S 1"."T 1" WHERE (("C 1" OPERATOR(public.===) c2))
4330 (4 rows)
4332 ALTER SERVER loopback OPTIONS (DROP extensions);
4333 EXPLAIN (VERBOSE, COSTS OFF) EXECUTE st8;
4334                         QUERY PLAN                         
4335 -----------------------------------------------------------
4336  Aggregate
4337    Output: count(c3)
4338    ->  Foreign Scan on public.ft1 t1
4339          Output: c3
4340          Filter: (t1.c1 === t1.c2)
4341          Remote SQL: SELECT "C 1", c2, c3 FROM "S 1"."T 1"
4342 (6 rows)
4344 EXECUTE st8;
4345  count 
4346 -------
4347      9
4348 (1 row)
4350 ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
4351 -- cleanup
4352 DEALLOCATE st1;
4353 DEALLOCATE st2;
4354 DEALLOCATE st3;
4355 DEALLOCATE st4;
4356 DEALLOCATE st5;
4357 DEALLOCATE st6;
4358 DEALLOCATE st7;
4359 DEALLOCATE st8;
4360 -- System columns, except ctid and oid, should not be sent to remote
4361 EXPLAIN (VERBOSE, COSTS OFF)
4362 SELECT * FROM ft1 t1 WHERE t1.tableoid = 'pg_class'::regclass LIMIT 1;
4363                                   QUERY PLAN                                   
4364 -------------------------------------------------------------------------------
4365  Limit
4366    Output: c1, c2, c3, c4, c5, c6, c7, c8
4367    ->  Foreign Scan on public.ft1 t1
4368          Output: c1, c2, c3, c4, c5, c6, c7, c8
4369          Filter: (t1.tableoid = '1259'::oid)
4370          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
4371 (6 rows)
4373 SELECT * FROM ft1 t1 WHERE t1.tableoid = 'ft1'::regclass LIMIT 1;
4374  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4375 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4376   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4377 (1 row)
4379 EXPLAIN (VERBOSE, COSTS OFF)
4380 SELECT tableoid::regclass, * FROM ft1 t1 LIMIT 1;
4381                                        QUERY PLAN                                        
4382 -----------------------------------------------------------------------------------------
4383  Foreign Scan on public.ft1 t1
4384    Output: (tableoid)::regclass, c1, c2, c3, c4, c5, c6, c7, c8
4385    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" LIMIT 1::bigint
4386 (3 rows)
4388 SELECT tableoid::regclass, * FROM ft1 t1 LIMIT 1;
4389  tableoid | c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4390 ----------+----+----+-------+------------------------------+--------------------------+----+------------+-----
4391  ft1      |  1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4392 (1 row)
4394 EXPLAIN (VERBOSE, COSTS OFF)
4395 SELECT * FROM ft1 t1 WHERE t1.ctid = '(0,2)';
4396                                             QUERY PLAN                                            
4397 --------------------------------------------------------------------------------------------------
4398  Foreign Scan on public.ft1 t1
4399    Output: c1, c2, c3, c4, c5, c6, c7, c8
4400    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((ctid = '(0,2)'))
4401 (3 rows)
4403 SELECT * FROM ft1 t1 WHERE t1.ctid = '(0,2)';
4404  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4405 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4406   2 |  2 | 00002 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo
4407 (1 row)
4409 EXPLAIN (VERBOSE, COSTS OFF)
4410 SELECT ctid, * FROM ft1 t1 LIMIT 1;
4411                                           QUERY PLAN                                           
4412 -----------------------------------------------------------------------------------------------
4413  Foreign Scan on public.ft1 t1
4414    Output: ctid, c1, c2, c3, c4, c5, c6, c7, c8
4415    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8, ctid FROM "S 1"."T 1" LIMIT 1::bigint
4416 (3 rows)
4418 SELECT ctid, * FROM ft1 t1 LIMIT 1;
4419  ctid  | c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4420 -------+----+----+-------+------------------------------+--------------------------+----+------------+-----
4421  (0,1) |  1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4422 (1 row)
4424 -- ===================================================================
4425 -- used in PL/pgSQL function
4426 -- ===================================================================
4427 CREATE OR REPLACE FUNCTION f_test(p_c1 int) RETURNS int AS $$
4428 DECLARE
4429         v_c1 int;
4430 BEGIN
4431     SELECT c1 INTO v_c1 FROM ft1 WHERE c1 = p_c1 LIMIT 1;
4432     PERFORM c1 FROM ft1 WHERE c1 = p_c1 AND p_c1 = v_c1 LIMIT 1;
4433     RETURN v_c1;
4434 END;
4435 $$ LANGUAGE plpgsql;
4436 SELECT f_test(100);
4437  f_test 
4438 --------
4439     100
4440 (1 row)
4442 DROP FUNCTION f_test(int);
4443 -- ===================================================================
4444 -- REINDEX
4445 -- ===================================================================
4446 -- remote table is not created here
4447 CREATE FOREIGN TABLE reindex_foreign (c1 int, c2 int)
4448   SERVER loopback2 OPTIONS (table_name 'reindex_local');
4449 REINDEX TABLE reindex_foreign; -- error
4450 ERROR:  "reindex_foreign" is not a table or materialized view
4451 REINDEX TABLE CONCURRENTLY reindex_foreign; -- error
4452 ERROR:  "reindex_foreign" is not a table or materialized view
4453 DROP FOREIGN TABLE reindex_foreign;
4454 -- partitions and foreign tables
4455 CREATE TABLE reind_fdw_parent (c1 int) PARTITION BY RANGE (c1);
4456 CREATE TABLE reind_fdw_0_10 PARTITION OF reind_fdw_parent
4457   FOR VALUES FROM (0) TO (10);
4458 CREATE FOREIGN TABLE reind_fdw_10_20 PARTITION OF reind_fdw_parent
4459   FOR VALUES FROM (10) TO (20)
4460   SERVER loopback OPTIONS (table_name 'reind_local_10_20');
4461 REINDEX TABLE reind_fdw_parent; -- ok
4462 REINDEX TABLE CONCURRENTLY reind_fdw_parent; -- ok
4463 DROP TABLE reind_fdw_parent;
4464 -- ===================================================================
4465 -- conversion error
4466 -- ===================================================================
4467 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE int;
4468 SELECT * FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8) WHERE x1 = 1;  -- ERROR
4469 ERROR:  invalid input syntax for type integer: "foo"
4470 CONTEXT:  column "x8" of foreign table "ftx"
4471 SELECT ftx.x1, ft2.c2, ftx.x8 FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8), ft2
4472   WHERE ftx.x1 = ft2.c1 AND ftx.x1 = 1; -- ERROR
4473 ERROR:  invalid input syntax for type integer: "foo"
4474 CONTEXT:  column "x8" of foreign table "ftx"
4475 SELECT ftx.x1, ft2.c2, ftx FROM ft1 ftx(x1,x2,x3,x4,x5,x6,x7,x8), ft2
4476   WHERE ftx.x1 = ft2.c1 AND ftx.x1 = 1; -- ERROR
4477 ERROR:  invalid input syntax for type integer: "foo"
4478 CONTEXT:  whole-row reference to foreign table "ftx"
4479 SELECT sum(c2), array_agg(c8) FROM ft1 GROUP BY c8; -- ERROR
4480 ERROR:  invalid input syntax for type integer: "foo"
4481 CONTEXT:  processing expression at position 2 in select list
4482 ANALYZE ft1; -- ERROR
4483 ERROR:  invalid input syntax for type integer: "foo"
4484 CONTEXT:  column "c8" of foreign table "ft1"
4485 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE user_enum;
4486 -- ===================================================================
4487 -- local type can be different from remote type in some cases,
4488 -- in particular if similarly-named operators do equivalent things
4489 -- ===================================================================
4490 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE text;
4491 EXPLAIN (VERBOSE, COSTS OFF)
4492 SELECT * FROM ft1 WHERE c8 = 'foo' LIMIT 1;
4493                                                   QUERY PLAN                                                  
4494 --------------------------------------------------------------------------------------------------------------
4495  Foreign Scan on public.ft1
4496    Output: c1, c2, c3, c4, c5, c6, c7, c8
4497    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((c8 = 'foo')) LIMIT 1::bigint
4498 (3 rows)
4500 SELECT * FROM ft1 WHERE c8 = 'foo' LIMIT 1;
4501  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4502 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4503   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4504 (1 row)
4506 EXPLAIN (VERBOSE, COSTS OFF)
4507 SELECT * FROM ft1 WHERE 'foo' = c8 LIMIT 1;
4508                                                   QUERY PLAN                                                  
4509 --------------------------------------------------------------------------------------------------------------
4510  Foreign Scan on public.ft1
4511    Output: c1, c2, c3, c4, c5, c6, c7, c8
4512    Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (('foo' = c8)) LIMIT 1::bigint
4513 (3 rows)
4515 SELECT * FROM ft1 WHERE 'foo' = c8 LIMIT 1;
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 -- we declared c8 to be text locally, but it's still the same type on
4522 -- the remote which will balk if we try to do anything incompatible
4523 -- with that remote type
4524 SELECT * FROM ft1 WHERE c8 LIKE 'foo' LIMIT 1; -- ERROR
4525 ERROR:  operator does not exist: public.user_enum ~~ unknown
4526 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
4527 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
4528 SELECT * FROM ft1 WHERE c8::text LIKE 'foo' LIMIT 1; -- ERROR; cast not pushed down
4529 ERROR:  operator does not exist: public.user_enum ~~ unknown
4530 HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.
4531 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
4532 ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE user_enum;
4533 -- ===================================================================
4534 -- subtransaction
4535 --  + local/remote error doesn't break cursor
4536 -- ===================================================================
4537 BEGIN;
4538 DECLARE c CURSOR FOR SELECT * FROM ft1 ORDER BY c1;
4539 FETCH c;
4540  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4541 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4542   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4543 (1 row)
4545 SAVEPOINT s;
4546 ERROR OUT;          -- ERROR
4547 ERROR:  syntax error at or near "ERROR"
4548 LINE 1: ERROR OUT;
4549         ^
4550 ROLLBACK TO s;
4551 FETCH c;
4552  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4553 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4554   2 |  2 | 00002 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo
4555 (1 row)
4557 SAVEPOINT s;
4558 SELECT * FROM ft1 WHERE 1 / (c1 - 1) > 0;  -- ERROR
4559 ERROR:  division by zero
4560 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))
4561 ROLLBACK TO s;
4562 FETCH c;
4563  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4564 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4565   3 |  3 | 00003 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo
4566 (1 row)
4568 SELECT * FROM ft1 ORDER BY c1 LIMIT 1;
4569  c1 | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4570 ----+----+-------+------------------------------+--------------------------+----+------------+-----
4571   1 |  1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo
4572 (1 row)
4574 COMMIT;
4575 -- ===================================================================
4576 -- test handling of collations
4577 -- ===================================================================
4578 create table loct3 (f1 text collate "C" unique, f2 text, f3 varchar(10) unique);
4579 create foreign table ft3 (f1 text collate "C", f2 text, f3 varchar(10))
4580   server loopback options (table_name 'loct3', use_remote_estimate 'true');
4581 -- can be sent to remote
4582 explain (verbose, costs off) select * from ft3 where f1 = '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 ((f1 = 'foo'))
4588 (3 rows)
4590 explain (verbose, costs off) select * from ft3 where f1 COLLATE "C" = 'foo';
4591                                QUERY PLAN                               
4592 ------------------------------------------------------------------------
4593  Foreign Scan on public.ft3
4594    Output: f1, f2, f3
4595    Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE ((f1 = 'foo'))
4596 (3 rows)
4598 explain (verbose, costs off) select * from ft3 where f2 = 'foo';
4599                                QUERY PLAN                               
4600 ------------------------------------------------------------------------
4601  Foreign Scan on public.ft3
4602    Output: f1, f2, f3
4603    Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE ((f2 = 'foo'))
4604 (3 rows)
4606 explain (verbose, costs off) select * from ft3 where f3 = 'foo';
4607                                QUERY PLAN                               
4608 ------------------------------------------------------------------------
4609  Foreign Scan on public.ft3
4610    Output: f1, f2, f3
4611    Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE ((f3 = 'foo'))
4612 (3 rows)
4614 explain (verbose, costs off) select * from ft3 f, loct3 l
4615   where f.f3 = l.f3 and l.f1 = 'foo';
4616                                             QUERY PLAN                                            
4617 --------------------------------------------------------------------------------------------------
4618  Nested Loop
4619    Output: f.f1, f.f2, f.f3, l.f1, l.f2, l.f3
4620    ->  Index Scan using loct3_f1_key on public.loct3 l
4621          Output: l.f1, l.f2, l.f3
4622          Index Cond: (l.f1 = 'foo'::text)
4623    ->  Foreign Scan on public.ft3 f
4624          Output: f.f1, f.f2, f.f3
4625          Remote SQL: SELECT f1, f2, f3 FROM public.loct3 WHERE ((f3 = $1::character varying(10)))
4626 (8 rows)
4628 -- can't be sent to remote
4629 explain (verbose, costs off) select * from ft3 where f1 COLLATE "POSIX" = 'foo';
4630                     QUERY PLAN                     
4631 ---------------------------------------------------
4632  Foreign Scan on public.ft3
4633    Output: f1, f2, f3
4634    Filter: ((ft3.f1)::text = 'foo'::text)
4635    Remote SQL: SELECT f1, f2, f3 FROM public.loct3
4636 (4 rows)
4638 explain (verbose, costs off) select * from ft3 where f1 = 'foo' COLLATE "C";
4639                     QUERY PLAN                     
4640 ---------------------------------------------------
4641  Foreign Scan on public.ft3
4642    Output: f1, f2, f3
4643    Filter: (ft3.f1 = 'foo'::text COLLATE "C")
4644    Remote SQL: SELECT f1, f2, f3 FROM public.loct3
4645 (4 rows)
4647 explain (verbose, costs off) select * from ft3 where f2 COLLATE "C" = 'foo';
4648                     QUERY PLAN                     
4649 ---------------------------------------------------
4650  Foreign Scan on public.ft3
4651    Output: f1, f2, f3
4652    Filter: ((ft3.f2)::text = 'foo'::text)
4653    Remote SQL: SELECT f1, f2, f3 FROM public.loct3
4654 (4 rows)
4656 explain (verbose, costs off) select * from ft3 where f2 = 'foo' COLLATE "C";
4657                     QUERY PLAN                     
4658 ---------------------------------------------------
4659  Foreign Scan on public.ft3
4660    Output: f1, f2, f3
4661    Filter: (ft3.f2 = 'foo'::text COLLATE "C")
4662    Remote SQL: SELECT f1, f2, f3 FROM public.loct3
4663 (4 rows)
4665 explain (verbose, costs off) select * from ft3 f, loct3 l
4666   where f.f3 = l.f3 COLLATE "POSIX" and l.f1 = 'foo';
4667                          QUERY PLAN                          
4668 -------------------------------------------------------------
4669  Hash Join
4670    Output: f.f1, f.f2, f.f3, l.f1, l.f2, l.f3
4671    Inner Unique: true
4672    Hash Cond: ((f.f3)::text = (l.f3)::text)
4673    ->  Foreign Scan on public.ft3 f
4674          Output: f.f1, f.f2, f.f3
4675          Remote SQL: SELECT f1, f2, f3 FROM public.loct3
4676    ->  Hash
4677          Output: l.f1, l.f2, l.f3
4678          ->  Index Scan using loct3_f1_key on public.loct3 l
4679                Output: l.f1, l.f2, l.f3
4680                Index Cond: (l.f1 = 'foo'::text)
4681 (12 rows)
4683 -- ===================================================================
4684 -- test SEMI-JOIN pushdown
4685 -- ===================================================================
4686 EXPLAIN (verbose, costs off)
4687 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN ft4 ON ft2.c2 = ft4.c1
4688   WHERE ft2.c1 > 900
4689   AND EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)
4690   ORDER BY ft2.c1;
4691                                                                                                                                                 QUERY PLAN                                                                                                                                                 
4692 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4693  Foreign Scan
4694    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3
4695    Relations: ((public.ft2) INNER JOIN (public.ft4)) SEMI JOIN (public.ft5)
4696    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
4697 (4 rows)
4699 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN ft4 ON ft2.c2 = ft4.c1
4700   WHERE ft2.c1 > 900
4701   AND EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)
4702   ORDER BY ft2.c1;
4703  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  | c1 | c2 |   c3   
4704 -----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+--------
4705  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4706  916 |  6 | 00916 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4707  926 |  6 | 00926 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4708  936 |  6 | 00936 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4709  946 |  6 | 00946 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4710  956 |  6 | 00956 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4711  966 |  6 | 00966 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4712  976 |  6 | 00976 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4713  986 |  6 | 00986 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4714  996 |  6 | 00996 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4715 (10 rows)
4717 -- The same query, different join order
4718 EXPLAIN (verbose, costs off)
4719 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN
4720   (SELECT * FROM ft4 WHERE
4721   EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)) ft4
4722   ON ft2.c2 = ft4.c1
4723   WHERE ft2.c1 > 900
4724   ORDER BY ft2.c1;
4725                                                                                                                                                 QUERY PLAN                                                                                                                                                 
4726 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4727  Foreign Scan
4728    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3
4729    Relations: ((public.ft2) INNER JOIN (public.ft4)) SEMI JOIN (public.ft5)
4730    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
4731 (4 rows)
4733 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN
4734   (SELECT * FROM ft4 WHERE
4735   EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)) ft4
4736   ON ft2.c2 = ft4.c1
4737   WHERE ft2.c1 > 900
4738   ORDER BY ft2.c1;
4739  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  | c1 | c2 |   c3   
4740 -----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+--------
4741  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4742  916 |  6 | 00916 | Sat Jan 17 00:00:00 1970 PST | Sat Jan 17 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4743  926 |  6 | 00926 | Tue Jan 27 00:00:00 1970 PST | Tue Jan 27 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4744  936 |  6 | 00936 | Fri Feb 06 00:00:00 1970 PST | Fri Feb 06 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4745  946 |  6 | 00946 | Mon Feb 16 00:00:00 1970 PST | Mon Feb 16 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4746  956 |  6 | 00956 | Thu Feb 26 00:00:00 1970 PST | Thu Feb 26 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4747  966 |  6 | 00966 | Sun Mar 08 00:00:00 1970 PST | Sun Mar 08 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4748  976 |  6 | 00976 | Wed Mar 18 00:00:00 1970 PST | Wed Mar 18 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4749  986 |  6 | 00986 | Sat Mar 28 00:00:00 1970 PST | Sat Mar 28 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4750  996 |  6 | 00996 | Tue Apr 07 00:00:00 1970 PST | Tue Apr 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4751 (10 rows)
4753 -- Left join
4754 EXPLAIN (verbose, costs off)
4755 SELECT ft2.*, ft4.* FROM ft2 LEFT JOIN
4756   (SELECT * FROM ft4 WHERE
4757   EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)) ft4
4758   ON ft2.c2 = ft4.c1
4759   WHERE ft2.c1 > 900
4760   ORDER BY ft2.c1 LIMIT 10;
4761                                                                                                                                                                                   QUERY PLAN                                                                                                                                                                                  
4762 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4763  Foreign Scan
4764    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3
4765    Relations: (public.ft2) LEFT JOIN ((public.ft4) SEMI JOIN (public.ft5))
4766    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
4767 (4 rows)
4769 SELECT ft2.*, ft4.* FROM ft2 LEFT JOIN
4770   (SELECT * FROM ft4 WHERE
4771   EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)) ft4
4772   ON ft2.c2 = ft4.c1
4773   WHERE ft2.c1 > 900
4774   ORDER BY ft2.c1 LIMIT 10;
4775  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  | c1 | c2 |   c3   
4776 -----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+--------
4777  901 |  1 | 00901 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1  | 1          | foo |    |    | 
4778  902 |  2 | 00902 | Sat Jan 03 00:00:00 1970 PST | Sat Jan 03 00:00:00 1970 | 2  | 2          | foo |    |    | 
4779  903 |  3 | 00903 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo |    |    | 
4780  904 |  4 | 00904 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4  | 4          | foo |    |    | 
4781  905 |  5 | 00905 | Tue Jan 06 00:00:00 1970 PST | Tue Jan 06 00:00:00 1970 | 5  | 5          | foo |    |    | 
4782  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4783  907 |  7 | 00907 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo |    |    | 
4784  908 |  8 | 00908 | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo |    |    | 
4785  909 |  9 | 00909 | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9  | 9          | foo |    |    | 
4786  910 |  0 | 00910 | Sun Jan 11 00:00:00 1970 PST | Sun Jan 11 00:00:00 1970 | 0  | 0          | foo |    |    | 
4787 (10 rows)
4789 -- Several semi-joins per upper level join
4790 EXPLAIN (verbose, costs off)
4791 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN
4792   (SELECT * FROM ft4 WHERE
4793   EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)) ft4
4794   ON ft2.c2 = ft4.c1
4795   INNER JOIN (SELECT * FROM ft5 WHERE
4796   EXISTS (SELECT 1 FROM ft4 WHERE ft4.c1 = ft5.c1)) ft5
4797   ON ft2.c2 <= ft5.c1
4798   WHERE ft2.c1 > 900
4799   ORDER BY ft2.c1 LIMIT 10;
4800                                                                                                                                                                                                                      QUERY PLAN                                                                                                                                                                                                                      
4801 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4802  Foreign Scan
4803    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3
4804    Relations: ((((public.ft2) INNER JOIN (public.ft4)) SEMI JOIN (public.ft5)) INNER JOIN (public.ft5 ft5_1)) SEMI JOIN (public.ft4 ft4_1)
4805    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
4806 (4 rows)
4808 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN
4809   (SELECT * FROM ft4 WHERE
4810   EXISTS (SELECT 1 FROM ft5 WHERE ft4.c1 = ft5.c1)) ft4
4811   ON ft2.c2 = ft4.c1
4812   INNER JOIN (SELECT * FROM ft5 WHERE
4813   EXISTS (SELECT 1 FROM ft4 WHERE ft4.c1 = ft5.c1)) ft5
4814   ON ft2.c2 <= ft5.c1
4815   WHERE ft2.c1 > 900
4816   ORDER BY ft2.c1 LIMIT 10;
4817  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  | c1 | c2 |   c3   
4818 -----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+--------
4819  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4820  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4821  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4822  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4823  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4824  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4825  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4826  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4827  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4828  906 |  6 | 00906 | Wed Jan 07 00:00:00 1970 PST | Wed Jan 07 00:00:00 1970 | 6  | 6          | foo |  6 |  7 | AAA006
4829 (10 rows)
4831 -- Semi-join below Semi-join
4832 EXPLAIN (verbose, costs off)
4833 SELECT ft2.* FROM ft2 WHERE
4834   c1 = ANY (
4835         SELECT c1 FROM ft2 WHERE
4836           EXISTS (SELECT 1 FROM ft4 WHERE ft4.c2 = ft2.c2))
4837   AND ft2.c1 > 900
4838   ORDER BY ft2.c1 LIMIT 10;
4839                                                                                                                                                           QUERY PLAN                                                                                                                                                           
4840 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4841  Foreign Scan
4842    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8
4843    Relations: (public.ft2) SEMI JOIN ((public.ft2 ft2_1) SEMI JOIN (public.ft4))
4844    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
4845 (4 rows)
4847 SELECT ft2.* FROM ft2 WHERE
4848   c1 = ANY (
4849         SELECT c1 FROM ft2 WHERE
4850           EXISTS (SELECT 1 FROM ft4 WHERE ft4.c2 = ft2.c2))
4851   AND ft2.c1 > 900
4852   ORDER BY ft2.c1 LIMIT 10;
4853  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4854 -----+----+-------+------------------------------+--------------------------+----+------------+-----
4855  903 |  3 | 00903 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo
4856  905 |  5 | 00905 | Tue Jan 06 00:00:00 1970 PST | Tue Jan 06 00:00:00 1970 | 5  | 5          | foo
4857  907 |  7 | 00907 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
4858  909 |  9 | 00909 | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9  | 9          | foo
4859  913 |  3 | 00913 | Wed Jan 14 00:00:00 1970 PST | Wed Jan 14 00:00:00 1970 | 3  | 3          | foo
4860  915 |  5 | 00915 | Fri Jan 16 00:00:00 1970 PST | Fri Jan 16 00:00:00 1970 | 5  | 5          | foo
4861  917 |  7 | 00917 | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
4862  919 |  9 | 00919 | Tue Jan 20 00:00:00 1970 PST | Tue Jan 20 00:00:00 1970 | 9  | 9          | foo
4863  923 |  3 | 00923 | Sat Jan 24 00:00:00 1970 PST | Sat Jan 24 00:00:00 1970 | 3  | 3          | foo
4864  925 |  5 | 00925 | Mon Jan 26 00:00:00 1970 PST | Mon Jan 26 00:00:00 1970 | 5  | 5          | foo
4865 (10 rows)
4867 -- Upper level relations shouldn't refer EXISTS() subqueries
4868 EXPLAIN (verbose, costs off)
4869 SELECT * FROM ft2 ftupper WHERE
4870    EXISTS (
4871         SELECT c1 FROM ft2 WHERE
4872           EXISTS (SELECT 1 FROM ft4 WHERE ft4.c2 = ft2.c2) AND c1 = ftupper.c1 )
4873   AND ftupper.c1 > 900
4874   ORDER BY ftupper.c1 LIMIT 10;
4875                                                                                                                                                           QUERY PLAN                                                                                                                                                           
4876 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4877  Foreign Scan
4878    Output: ftupper.c1, ftupper.c2, ftupper.c3, ftupper.c4, ftupper.c5, ftupper.c6, ftupper.c7, ftupper.c8
4879    Relations: (public.ft2 ftupper) SEMI JOIN ((public.ft2) SEMI JOIN (public.ft4))
4880    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
4881 (4 rows)
4883 SELECT * FROM ft2 ftupper WHERE
4884    EXISTS (
4885         SELECT c1 FROM ft2 WHERE
4886           EXISTS (SELECT 1 FROM ft4 WHERE ft4.c2 = ft2.c2) AND c1 = ftupper.c1 )
4887   AND ftupper.c1 > 900
4888   ORDER BY ftupper.c1 LIMIT 10;
4889  c1  | c2 |  c3   |              c4              |            c5            | c6 |     c7     | c8  
4890 -----+----+-------+------------------------------+--------------------------+----+------------+-----
4891  903 |  3 | 00903 | Sun Jan 04 00:00:00 1970 PST | Sun Jan 04 00:00:00 1970 | 3  | 3          | foo
4892  905 |  5 | 00905 | Tue Jan 06 00:00:00 1970 PST | Tue Jan 06 00:00:00 1970 | 5  | 5          | foo
4893  907 |  7 | 00907 | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
4894  909 |  9 | 00909 | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9  | 9          | foo
4895  913 |  3 | 00913 | Wed Jan 14 00:00:00 1970 PST | Wed Jan 14 00:00:00 1970 | 3  | 3          | foo
4896  915 |  5 | 00915 | Fri Jan 16 00:00:00 1970 PST | Fri Jan 16 00:00:00 1970 | 5  | 5          | foo
4897  917 |  7 | 00917 | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
4898  919 |  9 | 00919 | Tue Jan 20 00:00:00 1970 PST | Tue Jan 20 00:00:00 1970 | 9  | 9          | foo
4899  923 |  3 | 00923 | Sat Jan 24 00:00:00 1970 PST | Sat Jan 24 00:00:00 1970 | 3  | 3          | foo
4900  925 |  5 | 00925 | Mon Jan 26 00:00:00 1970 PST | Mon Jan 26 00:00:00 1970 | 5  | 5          | foo
4901 (10 rows)
4903 -- EXISTS should be propagated to the highest upper inner join
4904 EXPLAIN (verbose, costs off)
4905         SELECT ft2.*, ft4.* FROM ft2 INNER JOIN
4906         (SELECT * FROM ft4 WHERE EXISTS (
4907                 SELECT 1 FROM ft2 WHERE ft2.c2 = ft4.c2)) ft4
4908         ON ft2.c2 = ft4.c1
4909         INNER JOIN
4910         (SELECT * FROM ft2 WHERE EXISTS (
4911                 SELECT 1 FROM ft4 WHERE ft2.c2 = ft4.c2)) ft21
4912         ON ft2.c2 = ft21.c2
4913         WHERE ft2.c1 > 900
4914         ORDER BY ft2.c1 LIMIT 10;
4915                                                                                                                                                                                                                      QUERY PLAN                                                                                                                                                                                                                     
4916 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4917  Foreign Scan
4918    Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3
4919    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)
4920    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
4921 (4 rows)
4923 SELECT ft2.*, ft4.* FROM ft2 INNER JOIN
4924         (SELECT * FROM ft4 WHERE EXISTS (
4925                 SELECT 1 FROM ft2 WHERE ft2.c2 = ft4.c2)) ft4
4926         ON ft2.c2 = ft4.c1
4927         INNER JOIN
4928         (SELECT * FROM ft2 WHERE EXISTS (
4929                 SELECT 1 FROM ft4 WHERE ft2.c2 = ft4.c2)) ft21
4930         ON ft2.c2 = ft21.c2
4931         WHERE ft2.c1 > 900
4932         ORDER BY ft2.c1 LIMIT 10;
4933  c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c1 | c2 | c3 
4934 ----+----+----+----+----+----+----+----+----+----+----
4935 (0 rows)
4937 -- Can't push down semi-join with inner rel vars in targetlist
4938 EXPLAIN (verbose, costs off)
4939 SELECT ft1.c1 FROM ft1 JOIN ft2 on ft1.c1 = ft2.c1 WHERE
4940         ft1.c1 IN (
4941                 SELECT ft2.c1 FROM ft2 JOIN ft4 ON ft2.c1 = ft4.c1)
4942         ORDER BY ft1.c1 LIMIT 5;
4943                                                                             QUERY PLAN                                                                             
4944 -------------------------------------------------------------------------------------------------------------------------------------------------------------------
4945  Limit
4946    Output: ft1.c1
4947    ->  Merge Semi Join
4948          Output: ft1.c1
4949          Merge Cond: (ft1.c1 = ft2_1.c1)
4950          ->  Foreign Scan
4951                Output: ft1.c1, ft2.c1
4952                Relations: (public.ft1) INNER JOIN (public.ft2)
4953                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
4954          ->  Foreign Scan
4955                Output: ft2_1.c1, ft4.c1
4956                Relations: (public.ft2 ft2_1) INNER JOIN (public.ft4)
4957                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
4958 (13 rows)
4960 -- ===================================================================
4961 -- test writable foreign table stuff
4962 -- ===================================================================
4963 EXPLAIN (verbose, costs off)
4964 INSERT INTO ft2 (c1,c2,c3) SELECT c1+1000,c2+100, c3 || c3 FROM ft2 LIMIT 20;
4965                                                                                                                     QUERY PLAN                                                                                                                    
4966 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
4967  Insert on public.ft2
4968    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)
4969    Batch Size: 1
4970    ->  Subquery Scan on "*SELECT*"
4971          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
4972          ->  Foreign Scan on public.ft2 ft2_1
4973                Output: (ft2_1.c1 + 1000), (ft2_1.c2 + 100), (ft2_1.c3 || ft2_1.c3)
4974                Remote SQL: SELECT "C 1", c2, c3 FROM "S 1"."T 1" LIMIT 20::bigint
4975 (8 rows)
4977 INSERT INTO ft2 (c1,c2,c3) SELECT c1+1000,c2+100, c3 || c3 FROM ft2 LIMIT 20;
4978 INSERT INTO ft2 (c1,c2,c3)
4979   VALUES (1101,201,'aaa'), (1102,202,'bbb'), (1103,203,'ccc') RETURNING *;
4980   c1  | c2  | c3  | c4 | c5 | c6 |     c7     | c8 
4981 ------+-----+-----+----+----+----+------------+----
4982  1101 | 201 | aaa |    |    |    | ft2        | 
4983  1102 | 202 | bbb |    |    |    | ft2        | 
4984  1103 | 203 | ccc |    |    |    | ft2        | 
4985 (3 rows)
4987 INSERT INTO ft2 (c1,c2,c3) VALUES (1104,204,'ddd'), (1105,205,'eee');
4988 EXPLAIN (verbose, costs off)
4989 UPDATE ft2 SET c2 = c2 + 300, c3 = c3 || '_update3' WHERE c1 % 10 = 3;              -- can be pushed down
4990                                                    QUERY PLAN                                                   
4991 ----------------------------------------------------------------------------------------------------------------
4992  Update on public.ft2
4993    ->  Foreign Update on public.ft2
4994          Remote SQL: UPDATE "S 1"."T 1" SET c2 = (c2 + 300), c3 = (c3 || '_update3') WHERE ((("C 1" % 10) = 3))
4995 (3 rows)
4997 UPDATE ft2 SET c2 = c2 + 300, c3 = c3 || '_update3' WHERE c1 % 10 = 3;
4998 EXPLAIN (verbose, costs off)
4999 UPDATE ft2 SET c2 = c2 + 400, c3 = c3 || '_update7' WHERE c1 % 10 = 7 RETURNING *;  -- can be pushed down
5000                                                                          QUERY PLAN                                                                         
5001 ------------------------------------------------------------------------------------------------------------------------------------------------------------
5002  Update on public.ft2
5003    Output: c1, c2, c3, c4, c5, c6, c7, c8
5004    ->  Foreign Update on public.ft2
5005          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
5006 (4 rows)
5008 UPDATE ft2 SET c2 = c2 + 400, c3 = c3 || '_update7' WHERE c1 % 10 = 7 RETURNING *;
5009   c1  | c2  |         c3         |              c4              |            c5            | c6 |     c7     | c8  
5010 ------+-----+--------------------+------------------------------+--------------------------+----+------------+-----
5011     7 | 407 | 00007_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5012    17 | 407 | 00017_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5013    27 | 407 | 00027_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5014    37 | 407 | 00037_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5015    47 | 407 | 00047_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5016    57 | 407 | 00057_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5017    67 | 407 | 00067_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5018    77 | 407 | 00077_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5019    87 | 407 | 00087_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5020    97 | 407 | 00097_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5021   107 | 407 | 00107_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5022   117 | 407 | 00117_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5023   127 | 407 | 00127_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5024   137 | 407 | 00137_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5025   147 | 407 | 00147_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5026   157 | 407 | 00157_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5027   167 | 407 | 00167_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5028   177 | 407 | 00177_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5029   187 | 407 | 00187_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5030   197 | 407 | 00197_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5031   207 | 407 | 00207_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5032   217 | 407 | 00217_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5033   227 | 407 | 00227_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5034   237 | 407 | 00237_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5035   247 | 407 | 00247_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5036   257 | 407 | 00257_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5037   267 | 407 | 00267_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5038   277 | 407 | 00277_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5039   287 | 407 | 00287_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5040   297 | 407 | 00297_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5041   307 | 407 | 00307_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5042   317 | 407 | 00317_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5043   327 | 407 | 00327_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5044   337 | 407 | 00337_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5045   347 | 407 | 00347_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5046   357 | 407 | 00357_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5047   367 | 407 | 00367_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5048   377 | 407 | 00377_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5049   387 | 407 | 00387_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5050   397 | 407 | 00397_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5051   407 | 407 | 00407_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5052   417 | 407 | 00417_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5053   427 | 407 | 00427_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5054   437 | 407 | 00437_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5055   447 | 407 | 00447_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5056   457 | 407 | 00457_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5057   467 | 407 | 00467_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5058   477 | 407 | 00477_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5059   487 | 407 | 00487_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5060   497 | 407 | 00497_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5061   507 | 407 | 00507_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5062   517 | 407 | 00517_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5063   527 | 407 | 00527_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5064   537 | 407 | 00537_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5065   547 | 407 | 00547_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5066   557 | 407 | 00557_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5067   567 | 407 | 00567_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5068   577 | 407 | 00577_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5069   587 | 407 | 00587_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5070   597 | 407 | 00597_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5071   607 | 407 | 00607_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5072   617 | 407 | 00617_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5073   627 | 407 | 00627_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5074   637 | 407 | 00637_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5075   647 | 407 | 00647_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5076   657 | 407 | 00657_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5077   667 | 407 | 00667_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5078   677 | 407 | 00677_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5079   687 | 407 | 00687_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5080   697 | 407 | 00697_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5081   707 | 407 | 00707_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5082   717 | 407 | 00717_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5083   727 | 407 | 00727_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5084   737 | 407 | 00737_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5085   747 | 407 | 00747_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5086   757 | 407 | 00757_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5087   767 | 407 | 00767_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5088   777 | 407 | 00777_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5089   787 | 407 | 00787_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5090   797 | 407 | 00797_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5091   807 | 407 | 00807_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5092   817 | 407 | 00817_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5093   827 | 407 | 00827_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5094   837 | 407 | 00837_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5095   847 | 407 | 00847_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5096   857 | 407 | 00857_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5097   867 | 407 | 00867_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5098   877 | 407 | 00877_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5099   887 | 407 | 00887_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5100   897 | 407 | 00897_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5101   907 | 407 | 00907_update7      | Thu Jan 08 00:00:00 1970 PST | Thu Jan 08 00:00:00 1970 | 7  | 7          | foo
5102   917 | 407 | 00917_update7      | Sun Jan 18 00:00:00 1970 PST | Sun Jan 18 00:00:00 1970 | 7  | 7          | foo
5103   927 | 407 | 00927_update7      | Wed Jan 28 00:00:00 1970 PST | Wed Jan 28 00:00:00 1970 | 7  | 7          | foo
5104   937 | 407 | 00937_update7      | Sat Feb 07 00:00:00 1970 PST | Sat Feb 07 00:00:00 1970 | 7  | 7          | foo
5105   947 | 407 | 00947_update7      | Tue Feb 17 00:00:00 1970 PST | Tue Feb 17 00:00:00 1970 | 7  | 7          | foo
5106   957 | 407 | 00957_update7      | Fri Feb 27 00:00:00 1970 PST | Fri Feb 27 00:00:00 1970 | 7  | 7          | foo
5107   967 | 407 | 00967_update7      | Mon Mar 09 00:00:00 1970 PST | Mon Mar 09 00:00:00 1970 | 7  | 7          | foo
5108   977 | 407 | 00977_update7      | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7  | 7          | foo
5109   987 | 407 | 00987_update7      | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7  | 7          | foo
5110   997 | 407 | 00997_update7      | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7  | 7          | foo
5111  1007 | 507 | 0000700007_update7 |                              |                          |    | ft2        | 
5112  1017 | 507 | 0001700017_update7 |                              |                          |    | ft2        | 
5113 (102 rows)
5115 EXPLAIN (verbose, costs off)
5116 UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT
5117   FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9;                               -- can be pushed down
5118                                                                                                 QUERY PLAN                                                                                                 
5119 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
5120  Update on public.ft2
5121    ->  Foreign Update
5122          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))
5123 (3 rows)
5125 UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT
5126   FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9;
5127 EXPLAIN (verbose, costs off)
5128   DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING c1, c4;                               -- can be pushed down
5129                                          QUERY PLAN                                         
5130 --------------------------------------------------------------------------------------------
5131  Delete on public.ft2
5132    Output: c1, c4
5133    ->  Foreign Delete on public.ft2
5134          Remote SQL: DELETE FROM "S 1"."T 1" WHERE ((("C 1" % 10) = 5)) RETURNING "C 1", c4
5135 (4 rows)
5137 DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING c1, c4;
5138   c1  |              c4              
5139 ------+------------------------------
5140     5 | Tue Jan 06 00:00:00 1970 PST
5141    15 | Fri Jan 16 00:00:00 1970 PST
5142    25 | Mon Jan 26 00:00:00 1970 PST
5143    35 | Thu Feb 05 00:00:00 1970 PST
5144    45 | Sun Feb 15 00:00:00 1970 PST
5145    55 | Wed Feb 25 00:00:00 1970 PST
5146    65 | Sat Mar 07 00:00:00 1970 PST
5147    75 | Tue Mar 17 00:00:00 1970 PST
5148    85 | Fri Mar 27 00:00:00 1970 PST
5149    95 | Mon Apr 06 00:00:00 1970 PST
5150   105 | Tue Jan 06 00:00:00 1970 PST
5151   115 | Fri Jan 16 00:00:00 1970 PST
5152   125 | Mon Jan 26 00:00:00 1970 PST
5153   135 | Thu Feb 05 00:00:00 1970 PST
5154   145 | Sun Feb 15 00:00:00 1970 PST
5155   155 | Wed Feb 25 00:00:00 1970 PST
5156   165 | Sat Mar 07 00:00:00 1970 PST
5157   175 | Tue Mar 17 00:00:00 1970 PST
5158   185 | Fri Mar 27 00:00:00 1970 PST
5159   195 | Mon Apr 06 00:00:00 1970 PST
5160   205 | Tue Jan 06 00:00:00 1970 PST
5161   215 | Fri Jan 16 00:00:00 1970 PST
5162   225 | Mon Jan 26 00:00:00 1970 PST
5163   235 | Thu Feb 05 00:00:00 1970 PST
5164   245 | Sun Feb 15 00:00:00 1970 PST
5165   255 | Wed Feb 25 00:00:00 1970 PST
5166   265 | Sat Mar 07 00:00:00 1970 PST
5167   275 | Tue Mar 17 00:00:00 1970 PST
5168   285 | Fri Mar 27 00:00:00 1970 PST
5169   295 | Mon Apr 06 00:00:00 1970 PST
5170   305 | Tue Jan 06 00:00:00 1970 PST
5171   315 | Fri Jan 16 00:00:00 1970 PST
5172   325 | Mon Jan 26 00:00:00 1970 PST
5173   335 | Thu Feb 05 00:00:00 1970 PST
5174   345 | Sun Feb 15 00:00:00 1970 PST
5175   355 | Wed Feb 25 00:00:00 1970 PST
5176   365 | Sat Mar 07 00:00:00 1970 PST
5177   375 | Tue Mar 17 00:00:00 1970 PST
5178   385 | Fri Mar 27 00:00:00 1970 PST
5179   395 | Mon Apr 06 00:00:00 1970 PST
5180   405 | Tue Jan 06 00:00:00 1970 PST
5181   415 | Fri Jan 16 00:00:00 1970 PST
5182   425 | Mon Jan 26 00:00:00 1970 PST
5183   435 | Thu Feb 05 00:00:00 1970 PST
5184   445 | Sun Feb 15 00:00:00 1970 PST
5185   455 | Wed Feb 25 00:00:00 1970 PST
5186   465 | Sat Mar 07 00:00:00 1970 PST
5187   475 | Tue Mar 17 00:00:00 1970 PST
5188   485 | Fri Mar 27 00:00:00 1970 PST
5189   495 | Mon Apr 06 00:00:00 1970 PST
5190   505 | Tue Jan 06 00:00:00 1970 PST
5191   515 | Fri Jan 16 00:00:00 1970 PST
5192   525 | Mon Jan 26 00:00:00 1970 PST
5193   535 | Thu Feb 05 00:00:00 1970 PST
5194   545 | Sun Feb 15 00:00:00 1970 PST
5195   555 | Wed Feb 25 00:00:00 1970 PST
5196   565 | Sat Mar 07 00:00:00 1970 PST
5197   575 | Tue Mar 17 00:00:00 1970 PST
5198   585 | Fri Mar 27 00:00:00 1970 PST
5199   595 | Mon Apr 06 00:00:00 1970 PST
5200   605 | Tue Jan 06 00:00:00 1970 PST
5201   615 | Fri Jan 16 00:00:00 1970 PST
5202   625 | Mon Jan 26 00:00:00 1970 PST
5203   635 | Thu Feb 05 00:00:00 1970 PST
5204   645 | Sun Feb 15 00:00:00 1970 PST
5205   655 | Wed Feb 25 00:00:00 1970 PST
5206   665 | Sat Mar 07 00:00:00 1970 PST
5207   675 | Tue Mar 17 00:00:00 1970 PST
5208   685 | Fri Mar 27 00:00:00 1970 PST
5209   695 | Mon Apr 06 00:00:00 1970 PST
5210   705 | Tue Jan 06 00:00:00 1970 PST
5211   715 | Fri Jan 16 00:00:00 1970 PST
5212   725 | Mon Jan 26 00:00:00 1970 PST
5213   735 | Thu Feb 05 00:00:00 1970 PST
5214   745 | Sun Feb 15 00:00:00 1970 PST
5215   755 | Wed Feb 25 00:00:00 1970 PST
5216   765 | Sat Mar 07 00:00:00 1970 PST
5217   775 | Tue Mar 17 00:00:00 1970 PST
5218   785 | Fri Mar 27 00:00:00 1970 PST
5219   795 | Mon Apr 06 00:00:00 1970 PST
5220   805 | Tue Jan 06 00:00:00 1970 PST
5221   815 | Fri Jan 16 00:00:00 1970 PST
5222   825 | Mon Jan 26 00:00:00 1970 PST
5223   835 | Thu Feb 05 00:00:00 1970 PST
5224   845 | Sun Feb 15 00:00:00 1970 PST
5225   855 | Wed Feb 25 00:00:00 1970 PST
5226   865 | Sat Mar 07 00:00:00 1970 PST
5227   875 | Tue Mar 17 00:00:00 1970 PST
5228   885 | Fri Mar 27 00:00:00 1970 PST
5229   895 | Mon Apr 06 00:00:00 1970 PST
5230   905 | Tue Jan 06 00:00:00 1970 PST
5231   915 | Fri Jan 16 00:00:00 1970 PST
5232   925 | Mon Jan 26 00:00:00 1970 PST
5233   935 | Thu Feb 05 00:00:00 1970 PST
5234   945 | Sun Feb 15 00:00:00 1970 PST
5235   955 | Wed Feb 25 00:00:00 1970 PST
5236   965 | Sat Mar 07 00:00:00 1970 PST
5237   975 | Tue Mar 17 00:00:00 1970 PST
5238   985 | Fri Mar 27 00:00:00 1970 PST
5239   995 | Mon Apr 06 00:00:00 1970 PST
5240  1005 | 
5241  1015 | 
5242  1105 | 
5243 (103 rows)
5245 EXPLAIN (verbose, costs off)
5246 DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2;                -- can be pushed down
5247                                                          QUERY PLAN                                                         
5248 ----------------------------------------------------------------------------------------------------------------------------
5249  Delete on public.ft2
5250    ->  Foreign Delete
5251          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))
5252 (3 rows)
5254 DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2;
5255 SELECT c1,c2,c3,c4 FROM ft2 ORDER BY c1;
5256   c1  | c2  |         c3         |              c4              
5257 ------+-----+--------------------+------------------------------
5258     1 |   1 | 00001              | Fri Jan 02 00:00:00 1970 PST
5259     3 | 303 | 00003_update3      | Sun Jan 04 00:00:00 1970 PST
5260     4 |   4 | 00004              | Mon Jan 05 00:00:00 1970 PST
5261     6 |   6 | 00006              | Wed Jan 07 00:00:00 1970 PST
5262     7 | 407 | 00007_update7      | Thu Jan 08 00:00:00 1970 PST
5263     8 |   8 | 00008              | Fri Jan 09 00:00:00 1970 PST
5264     9 | 509 | 00009_update9      | Sat Jan 10 00:00:00 1970 PST
5265    10 |   0 | 00010              | Sun Jan 11 00:00:00 1970 PST
5266    11 |   1 | 00011              | Mon Jan 12 00:00:00 1970 PST
5267    13 | 303 | 00013_update3      | Wed Jan 14 00:00:00 1970 PST
5268    14 |   4 | 00014              | Thu Jan 15 00:00:00 1970 PST
5269    16 |   6 | 00016              | Sat Jan 17 00:00:00 1970 PST
5270    17 | 407 | 00017_update7      | Sun Jan 18 00:00:00 1970 PST
5271    18 |   8 | 00018              | Mon Jan 19 00:00:00 1970 PST
5272    19 | 509 | 00019_update9      | Tue Jan 20 00:00:00 1970 PST
5273    20 |   0 | 00020              | Wed Jan 21 00:00:00 1970 PST
5274    21 |   1 | 00021              | Thu Jan 22 00:00:00 1970 PST
5275    23 | 303 | 00023_update3      | Sat Jan 24 00:00:00 1970 PST
5276    24 |   4 | 00024              | Sun Jan 25 00:00:00 1970 PST
5277    26 |   6 | 00026              | Tue Jan 27 00:00:00 1970 PST
5278    27 | 407 | 00027_update7      | Wed Jan 28 00:00:00 1970 PST
5279    28 |   8 | 00028              | Thu Jan 29 00:00:00 1970 PST
5280    29 | 509 | 00029_update9      | Fri Jan 30 00:00:00 1970 PST
5281    30 |   0 | 00030              | Sat Jan 31 00:00:00 1970 PST
5282    31 |   1 | 00031              | Sun Feb 01 00:00:00 1970 PST
5283    33 | 303 | 00033_update3      | Tue Feb 03 00:00:00 1970 PST
5284    34 |   4 | 00034              | Wed Feb 04 00:00:00 1970 PST
5285    36 |   6 | 00036              | Fri Feb 06 00:00:00 1970 PST
5286    37 | 407 | 00037_update7      | Sat Feb 07 00:00:00 1970 PST
5287    38 |   8 | 00038              | Sun Feb 08 00:00:00 1970 PST
5288    39 | 509 | 00039_update9      | Mon Feb 09 00:00:00 1970 PST
5289    40 |   0 | 00040              | Tue Feb 10 00:00:00 1970 PST
5290    41 |   1 | 00041              | Wed Feb 11 00:00:00 1970 PST
5291    43 | 303 | 00043_update3      | Fri Feb 13 00:00:00 1970 PST
5292    44 |   4 | 00044              | Sat Feb 14 00:00:00 1970 PST
5293    46 |   6 | 00046              | Mon Feb 16 00:00:00 1970 PST
5294    47 | 407 | 00047_update7      | Tue Feb 17 00:00:00 1970 PST
5295    48 |   8 | 00048              | Wed Feb 18 00:00:00 1970 PST
5296    49 | 509 | 00049_update9      | Thu Feb 19 00:00:00 1970 PST
5297    50 |   0 | 00050              | Fri Feb 20 00:00:00 1970 PST
5298    51 |   1 | 00051              | Sat Feb 21 00:00:00 1970 PST
5299    53 | 303 | 00053_update3      | Mon Feb 23 00:00:00 1970 PST
5300    54 |   4 | 00054              | Tue Feb 24 00:00:00 1970 PST
5301    56 |   6 | 00056              | Thu Feb 26 00:00:00 1970 PST
5302    57 | 407 | 00057_update7      | Fri Feb 27 00:00:00 1970 PST
5303    58 |   8 | 00058              | Sat Feb 28 00:00:00 1970 PST
5304    59 | 509 | 00059_update9      | Sun Mar 01 00:00:00 1970 PST
5305    60 |   0 | 00060              | Mon Mar 02 00:00:00 1970 PST
5306    61 |   1 | 00061              | Tue Mar 03 00:00:00 1970 PST
5307    63 | 303 | 00063_update3      | Thu Mar 05 00:00:00 1970 PST
5308    64 |   4 | 00064              | Fri Mar 06 00:00:00 1970 PST
5309    66 |   6 | 00066              | Sun Mar 08 00:00:00 1970 PST
5310    67 | 407 | 00067_update7      | Mon Mar 09 00:00:00 1970 PST
5311    68 |   8 | 00068              | Tue Mar 10 00:00:00 1970 PST
5312    69 | 509 | 00069_update9      | Wed Mar 11 00:00:00 1970 PST
5313    70 |   0 | 00070              | Thu Mar 12 00:00:00 1970 PST
5314    71 |   1 | 00071              | Fri Mar 13 00:00:00 1970 PST
5315    73 | 303 | 00073_update3      | Sun Mar 15 00:00:00 1970 PST
5316    74 |   4 | 00074              | Mon Mar 16 00:00:00 1970 PST
5317    76 |   6 | 00076              | Wed Mar 18 00:00:00 1970 PST
5318    77 | 407 | 00077_update7      | Thu Mar 19 00:00:00 1970 PST
5319    78 |   8 | 00078              | Fri Mar 20 00:00:00 1970 PST
5320    79 | 509 | 00079_update9      | Sat Mar 21 00:00:00 1970 PST
5321    80 |   0 | 00080              | Sun Mar 22 00:00:00 1970 PST
5322    81 |   1 | 00081              | Mon Mar 23 00:00:00 1970 PST
5323    83 | 303 | 00083_update3      | Wed Mar 25 00:00:00 1970 PST
5324    84 |   4 | 00084              | Thu Mar 26 00:00:00 1970 PST
5325    86 |   6 | 00086              | Sat Mar 28 00:00:00 1970 PST
5326    87 | 407 | 00087_update7      | Sun Mar 29 00:00:00 1970 PST
5327    88 |   8 | 00088              | Mon Mar 30 00:00:00 1970 PST
5328    89 | 509 | 00089_update9      | Tue Mar 31 00:00:00 1970 PST
5329    90 |   0 | 00090              | Wed Apr 01 00:00:00 1970 PST
5330    91 |   1 | 00091              | Thu Apr 02 00:00:00 1970 PST
5331    93 | 303 | 00093_update3      | Sat Apr 04 00:00:00 1970 PST
5332    94 |   4 | 00094              | Sun Apr 05 00:00:00 1970 PST
5333    96 |   6 | 00096              | Tue Apr 07 00:00:00 1970 PST
5334    97 | 407 | 00097_update7      | Wed Apr 08 00:00:00 1970 PST
5335    98 |   8 | 00098              | Thu Apr 09 00:00:00 1970 PST
5336    99 | 509 | 00099_update9      | Fri Apr 10 00:00:00 1970 PST
5337   100 |   0 | 00100              | Thu Jan 01 00:00:00 1970 PST
5338   101 |   1 | 00101              | Fri Jan 02 00:00:00 1970 PST
5339   103 | 303 | 00103_update3      | Sun Jan 04 00:00:00 1970 PST
5340   104 |   4 | 00104              | Mon Jan 05 00:00:00 1970 PST
5341   106 |   6 | 00106              | Wed Jan 07 00:00:00 1970 PST
5342   107 | 407 | 00107_update7      | Thu Jan 08 00:00:00 1970 PST
5343   108 |   8 | 00108              | Fri Jan 09 00:00:00 1970 PST
5344   109 | 509 | 00109_update9      | Sat Jan 10 00:00:00 1970 PST
5345   110 |   0 | 00110              | Sun Jan 11 00:00:00 1970 PST
5346   111 |   1 | 00111              | Mon Jan 12 00:00:00 1970 PST
5347   113 | 303 | 00113_update3      | Wed Jan 14 00:00:00 1970 PST
5348   114 |   4 | 00114              | Thu Jan 15 00:00:00 1970 PST
5349   116 |   6 | 00116              | Sat Jan 17 00:00:00 1970 PST
5350   117 | 407 | 00117_update7      | Sun Jan 18 00:00:00 1970 PST
5351   118 |   8 | 00118              | Mon Jan 19 00:00:00 1970 PST
5352   119 | 509 | 00119_update9      | Tue Jan 20 00:00:00 1970 PST
5353   120 |   0 | 00120              | Wed Jan 21 00:00:00 1970 PST
5354   121 |   1 | 00121              | Thu Jan 22 00:00:00 1970 PST
5355   123 | 303 | 00123_update3      | Sat Jan 24 00:00:00 1970 PST
5356   124 |   4 | 00124              | Sun Jan 25 00:00:00 1970 PST
5357   126 |   6 | 00126              | Tue Jan 27 00:00:00 1970 PST
5358   127 | 407 | 00127_update7      | Wed Jan 28 00:00:00 1970 PST
5359   128 |   8 | 00128              | Thu Jan 29 00:00:00 1970 PST
5360   129 | 509 | 00129_update9      | Fri Jan 30 00:00:00 1970 PST
5361   130 |   0 | 00130              | Sat Jan 31 00:00:00 1970 PST
5362   131 |   1 | 00131              | Sun Feb 01 00:00:00 1970 PST
5363   133 | 303 | 00133_update3      | Tue Feb 03 00:00:00 1970 PST
5364   134 |   4 | 00134              | Wed Feb 04 00:00:00 1970 PST
5365   136 |   6 | 00136              | Fri Feb 06 00:00:00 1970 PST
5366   137 | 407 | 00137_update7      | Sat Feb 07 00:00:00 1970 PST
5367   138 |   8 | 00138              | Sun Feb 08 00:00:00 1970 PST
5368   139 | 509 | 00139_update9      | Mon Feb 09 00:00:00 1970 PST
5369   140 |   0 | 00140              | Tue Feb 10 00:00:00 1970 PST
5370   141 |   1 | 00141              | Wed Feb 11 00:00:00 1970 PST
5371   143 | 303 | 00143_update3      | Fri Feb 13 00:00:00 1970 PST
5372   144 |   4 | 00144              | Sat Feb 14 00:00:00 1970 PST
5373   146 |   6 | 00146              | Mon Feb 16 00:00:00 1970 PST
5374   147 | 407 | 00147_update7      | Tue Feb 17 00:00:00 1970 PST
5375   148 |   8 | 00148              | Wed Feb 18 00:00:00 1970 PST
5376   149 | 509 | 00149_update9      | Thu Feb 19 00:00:00 1970 PST
5377   150 |   0 | 00150              | Fri Feb 20 00:00:00 1970 PST
5378   151 |   1 | 00151              | Sat Feb 21 00:00:00 1970 PST
5379   153 | 303 | 00153_update3      | Mon Feb 23 00:00:00 1970 PST
5380   154 |   4 | 00154              | Tue Feb 24 00:00:00 1970 PST
5381   156 |   6 | 00156              | Thu Feb 26 00:00:00 1970 PST
5382   157 | 407 | 00157_update7      | Fri Feb 27 00:00:00 1970 PST
5383   158 |   8 | 00158              | Sat Feb 28 00:00:00 1970 PST
5384   159 | 509 | 00159_update9      | Sun Mar 01 00:00:00 1970 PST
5385   160 |   0 | 00160              | Mon Mar 02 00:00:00 1970 PST
5386   161 |   1 | 00161              | Tue Mar 03 00:00:00 1970 PST
5387   163 | 303 | 00163_update3      | Thu Mar 05 00:00:00 1970 PST
5388   164 |   4 | 00164              | Fri Mar 06 00:00:00 1970 PST
5389   166 |   6 | 00166              | Sun Mar 08 00:00:00 1970 PST
5390   167 | 407 | 00167_update7      | Mon Mar 09 00:00:00 1970 PST
5391   168 |   8 | 00168              | Tue Mar 10 00:00:00 1970 PST
5392   169 | 509 | 00169_update9      | Wed Mar 11 00:00:00 1970 PST
5393   170 |   0 | 00170              | Thu Mar 12 00:00:00 1970 PST
5394   171 |   1 | 00171              | Fri Mar 13 00:00:00 1970 PST
5395   173 | 303 | 00173_update3      | Sun Mar 15 00:00:00 1970 PST
5396   174 |   4 | 00174              | Mon Mar 16 00:00:00 1970 PST
5397   176 |   6 | 00176              | Wed Mar 18 00:00:00 1970 PST
5398   177 | 407 | 00177_update7      | Thu Mar 19 00:00:00 1970 PST
5399   178 |   8 | 00178              | Fri Mar 20 00:00:00 1970 PST
5400   179 | 509 | 00179_update9      | Sat Mar 21 00:00:00 1970 PST
5401   180 |   0 | 00180              | Sun Mar 22 00:00:00 1970 PST
5402   181 |   1 | 00181              | Mon Mar 23 00:00:00 1970 PST
5403   183 | 303 | 00183_update3      | Wed Mar 25 00:00:00 1970 PST
5404   184 |   4 | 00184              | Thu Mar 26 00:00:00 1970 PST
5405   186 |   6 | 00186              | Sat Mar 28 00:00:00 1970 PST
5406   187 | 407 | 00187_update7      | Sun Mar 29 00:00:00 1970 PST
5407   188 |   8 | 00188              | Mon Mar 30 00:00:00 1970 PST
5408   189 | 509 | 00189_update9      | Tue Mar 31 00:00:00 1970 PST
5409   190 |   0 | 00190              | Wed Apr 01 00:00:00 1970 PST
5410   191 |   1 | 00191              | Thu Apr 02 00:00:00 1970 PST
5411   193 | 303 | 00193_update3      | Sat Apr 04 00:00:00 1970 PST
5412   194 |   4 | 00194              | Sun Apr 05 00:00:00 1970 PST
5413   196 |   6 | 00196              | Tue Apr 07 00:00:00 1970 PST
5414   197 | 407 | 00197_update7      | Wed Apr 08 00:00:00 1970 PST
5415   198 |   8 | 00198              | Thu Apr 09 00:00:00 1970 PST
5416   199 | 509 | 00199_update9      | Fri Apr 10 00:00:00 1970 PST
5417   200 |   0 | 00200              | Thu Jan 01 00:00:00 1970 PST
5418   201 |   1 | 00201              | Fri Jan 02 00:00:00 1970 PST
5419   203 | 303 | 00203_update3      | Sun Jan 04 00:00:00 1970 PST
5420   204 |   4 | 00204              | Mon Jan 05 00:00:00 1970 PST
5421   206 |   6 | 00206              | Wed Jan 07 00:00:00 1970 PST
5422   207 | 407 | 00207_update7      | Thu Jan 08 00:00:00 1970 PST
5423   208 |   8 | 00208              | Fri Jan 09 00:00:00 1970 PST
5424   209 | 509 | 00209_update9      | Sat Jan 10 00:00:00 1970 PST
5425   210 |   0 | 00210              | Sun Jan 11 00:00:00 1970 PST
5426   211 |   1 | 00211              | Mon Jan 12 00:00:00 1970 PST
5427   213 | 303 | 00213_update3      | Wed Jan 14 00:00:00 1970 PST
5428   214 |   4 | 00214              | Thu Jan 15 00:00:00 1970 PST
5429   216 |   6 | 00216              | Sat Jan 17 00:00:00 1970 PST
5430   217 | 407 | 00217_update7      | Sun Jan 18 00:00:00 1970 PST
5431   218 |   8 | 00218              | Mon Jan 19 00:00:00 1970 PST
5432   219 | 509 | 00219_update9      | Tue Jan 20 00:00:00 1970 PST
5433   220 |   0 | 00220              | Wed Jan 21 00:00:00 1970 PST
5434   221 |   1 | 00221              | Thu Jan 22 00:00:00 1970 PST
5435   223 | 303 | 00223_update3      | Sat Jan 24 00:00:00 1970 PST
5436   224 |   4 | 00224              | Sun Jan 25 00:00:00 1970 PST
5437   226 |   6 | 00226              | Tue Jan 27 00:00:00 1970 PST
5438   227 | 407 | 00227_update7      | Wed Jan 28 00:00:00 1970 PST
5439   228 |   8 | 00228              | Thu Jan 29 00:00:00 1970 PST
5440   229 | 509 | 00229_update9      | Fri Jan 30 00:00:00 1970 PST
5441   230 |   0 | 00230              | Sat Jan 31 00:00:00 1970 PST
5442   231 |   1 | 00231              | Sun Feb 01 00:00:00 1970 PST
5443   233 | 303 | 00233_update3      | Tue Feb 03 00:00:00 1970 PST
5444   234 |   4 | 00234              | Wed Feb 04 00:00:00 1970 PST
5445   236 |   6 | 00236              | Fri Feb 06 00:00:00 1970 PST
5446   237 | 407 | 00237_update7      | Sat Feb 07 00:00:00 1970 PST
5447   238 |   8 | 00238              | Sun Feb 08 00:00:00 1970 PST
5448   239 | 509 | 00239_update9      | Mon Feb 09 00:00:00 1970 PST
5449   240 |   0 | 00240              | Tue Feb 10 00:00:00 1970 PST
5450   241 |   1 | 00241              | Wed Feb 11 00:00:00 1970 PST
5451   243 | 303 | 00243_update3      | Fri Feb 13 00:00:00 1970 PST
5452   244 |   4 | 00244              | Sat Feb 14 00:00:00 1970 PST
5453   246 |   6 | 00246              | Mon Feb 16 00:00:00 1970 PST
5454   247 | 407 | 00247_update7      | Tue Feb 17 00:00:00 1970 PST
5455   248 |   8 | 00248              | Wed Feb 18 00:00:00 1970 PST
5456   249 | 509 | 00249_update9      | Thu Feb 19 00:00:00 1970 PST
5457   250 |   0 | 00250              | Fri Feb 20 00:00:00 1970 PST
5458   251 |   1 | 00251              | Sat Feb 21 00:00:00 1970 PST
5459   253 | 303 | 00253_update3      | Mon Feb 23 00:00:00 1970 PST
5460   254 |   4 | 00254              | Tue Feb 24 00:00:00 1970 PST
5461   256 |   6 | 00256              | Thu Feb 26 00:00:00 1970 PST
5462   257 | 407 | 00257_update7      | Fri Feb 27 00:00:00 1970 PST
5463   258 |   8 | 00258              | Sat Feb 28 00:00:00 1970 PST
5464   259 | 509 | 00259_update9      | Sun Mar 01 00:00:00 1970 PST
5465   260 |   0 | 00260              | Mon Mar 02 00:00:00 1970 PST
5466   261 |   1 | 00261              | Tue Mar 03 00:00:00 1970 PST
5467   263 | 303 | 00263_update3      | Thu Mar 05 00:00:00 1970 PST
5468   264 |   4 | 00264              | Fri Mar 06 00:00:00 1970 PST
5469   266 |   6 | 00266              | Sun Mar 08 00:00:00 1970 PST
5470   267 | 407 | 00267_update7      | Mon Mar 09 00:00:00 1970 PST
5471   268 |   8 | 00268              | Tue Mar 10 00:00:00 1970 PST
5472   269 | 509 | 00269_update9      | Wed Mar 11 00:00:00 1970 PST
5473   270 |   0 | 00270              | Thu Mar 12 00:00:00 1970 PST
5474   271 |   1 | 00271              | Fri Mar 13 00:00:00 1970 PST
5475   273 | 303 | 00273_update3      | Sun Mar 15 00:00:00 1970 PST
5476   274 |   4 | 00274              | Mon Mar 16 00:00:00 1970 PST
5477   276 |   6 | 00276              | Wed Mar 18 00:00:00 1970 PST
5478   277 | 407 | 00277_update7      | Thu Mar 19 00:00:00 1970 PST
5479   278 |   8 | 00278              | Fri Mar 20 00:00:00 1970 PST
5480   279 | 509 | 00279_update9      | Sat Mar 21 00:00:00 1970 PST
5481   280 |   0 | 00280              | Sun Mar 22 00:00:00 1970 PST
5482   281 |   1 | 00281              | Mon Mar 23 00:00:00 1970 PST
5483   283 | 303 | 00283_update3      | Wed Mar 25 00:00:00 1970 PST
5484   284 |   4 | 00284              | Thu Mar 26 00:00:00 1970 PST
5485   286 |   6 | 00286              | Sat Mar 28 00:00:00 1970 PST
5486   287 | 407 | 00287_update7      | Sun Mar 29 00:00:00 1970 PST
5487   288 |   8 | 00288              | Mon Mar 30 00:00:00 1970 PST
5488   289 | 509 | 00289_update9      | Tue Mar 31 00:00:00 1970 PST
5489   290 |   0 | 00290              | Wed Apr 01 00:00:00 1970 PST
5490   291 |   1 | 00291              | Thu Apr 02 00:00:00 1970 PST
5491   293 | 303 | 00293_update3      | Sat Apr 04 00:00:00 1970 PST
5492   294 |   4 | 00294              | Sun Apr 05 00:00:00 1970 PST
5493   296 |   6 | 00296              | Tue Apr 07 00:00:00 1970 PST
5494   297 | 407 | 00297_update7      | Wed Apr 08 00:00:00 1970 PST
5495   298 |   8 | 00298              | Thu Apr 09 00:00:00 1970 PST
5496   299 | 509 | 00299_update9      | Fri Apr 10 00:00:00 1970 PST
5497   300 |   0 | 00300              | Thu Jan 01 00:00:00 1970 PST
5498   301 |   1 | 00301              | Fri Jan 02 00:00:00 1970 PST
5499   303 | 303 | 00303_update3      | Sun Jan 04 00:00:00 1970 PST
5500   304 |   4 | 00304              | Mon Jan 05 00:00:00 1970 PST
5501   306 |   6 | 00306              | Wed Jan 07 00:00:00 1970 PST
5502   307 | 407 | 00307_update7      | Thu Jan 08 00:00:00 1970 PST
5503   308 |   8 | 00308              | Fri Jan 09 00:00:00 1970 PST
5504   309 | 509 | 00309_update9      | Sat Jan 10 00:00:00 1970 PST
5505   310 |   0 | 00310              | Sun Jan 11 00:00:00 1970 PST
5506   311 |   1 | 00311              | Mon Jan 12 00:00:00 1970 PST
5507   313 | 303 | 00313_update3      | Wed Jan 14 00:00:00 1970 PST
5508   314 |   4 | 00314              | Thu Jan 15 00:00:00 1970 PST
5509   316 |   6 | 00316              | Sat Jan 17 00:00:00 1970 PST
5510   317 | 407 | 00317_update7      | Sun Jan 18 00:00:00 1970 PST
5511   318 |   8 | 00318              | Mon Jan 19 00:00:00 1970 PST
5512   319 | 509 | 00319_update9      | Tue Jan 20 00:00:00 1970 PST
5513   320 |   0 | 00320              | Wed Jan 21 00:00:00 1970 PST
5514   321 |   1 | 00321              | Thu Jan 22 00:00:00 1970 PST
5515   323 | 303 | 00323_update3      | Sat Jan 24 00:00:00 1970 PST
5516   324 |   4 | 00324              | Sun Jan 25 00:00:00 1970 PST
5517   326 |   6 | 00326              | Tue Jan 27 00:00:00 1970 PST
5518   327 | 407 | 00327_update7      | Wed Jan 28 00:00:00 1970 PST
5519   328 |   8 | 00328              | Thu Jan 29 00:00:00 1970 PST
5520   329 | 509 | 00329_update9      | Fri Jan 30 00:00:00 1970 PST
5521   330 |   0 | 00330              | Sat Jan 31 00:00:00 1970 PST
5522   331 |   1 | 00331              | Sun Feb 01 00:00:00 1970 PST
5523   333 | 303 | 00333_update3      | Tue Feb 03 00:00:00 1970 PST
5524   334 |   4 | 00334              | Wed Feb 04 00:00:00 1970 PST
5525   336 |   6 | 00336              | Fri Feb 06 00:00:00 1970 PST
5526   337 | 407 | 00337_update7      | Sat Feb 07 00:00:00 1970 PST
5527   338 |   8 | 00338              | Sun Feb 08 00:00:00 1970 PST
5528   339 | 509 | 00339_update9      | Mon Feb 09 00:00:00 1970 PST
5529   340 |   0 | 00340              | Tue Feb 10 00:00:00 1970 PST
5530   341 |   1 | 00341              | Wed Feb 11 00:00:00 1970 PST
5531   343 | 303 | 00343_update3      | Fri Feb 13 00:00:00 1970 PST
5532   344 |   4 | 00344              | Sat Feb 14 00:00:00 1970 PST
5533   346 |   6 | 00346              | Mon Feb 16 00:00:00 1970 PST
5534   347 | 407 | 00347_update7      | Tue Feb 17 00:00:00 1970 PST
5535   348 |   8 | 00348              | Wed Feb 18 00:00:00 1970 PST
5536   349 | 509 | 00349_update9      | Thu Feb 19 00:00:00 1970 PST
5537   350 |   0 | 00350              | Fri Feb 20 00:00:00 1970 PST
5538   351 |   1 | 00351              | Sat Feb 21 00:00:00 1970 PST
5539   353 | 303 | 00353_update3      | Mon Feb 23 00:00:00 1970 PST
5540   354 |   4 | 00354              | Tue Feb 24 00:00:00 1970 PST
5541   356 |   6 | 00356              | Thu Feb 26 00:00:00 1970 PST
5542   357 | 407 | 00357_update7      | Fri Feb 27 00:00:00 1970 PST
5543   358 |   8 | 00358              | Sat Feb 28 00:00:00 1970 PST
5544   359 | 509 | 00359_update9      | Sun Mar 01 00:00:00 1970 PST
5545   360 |   0 | 00360              | Mon Mar 02 00:00:00 1970 PST
5546   361 |   1 | 00361              | Tue Mar 03 00:00:00 1970 PST
5547   363 | 303 | 00363_update3      | Thu Mar 05 00:00:00 1970 PST
5548   364 |   4 | 00364              | Fri Mar 06 00:00:00 1970 PST
5549   366 |   6 | 00366              | Sun Mar 08 00:00:00 1970 PST
5550   367 | 407 | 00367_update7      | Mon Mar 09 00:00:00 1970 PST
5551   368 |   8 | 00368              | Tue Mar 10 00:00:00 1970 PST
5552   369 | 509 | 00369_update9      | Wed Mar 11 00:00:00 1970 PST
5553   370 |   0 | 00370              | Thu Mar 12 00:00:00 1970 PST
5554   371 |   1 | 00371              | Fri Mar 13 00:00:00 1970 PST
5555   373 | 303 | 00373_update3      | Sun Mar 15 00:00:00 1970 PST
5556   374 |   4 | 00374              | Mon Mar 16 00:00:00 1970 PST
5557   376 |   6 | 00376              | Wed Mar 18 00:00:00 1970 PST
5558   377 | 407 | 00377_update7      | Thu Mar 19 00:00:00 1970 PST
5559   378 |   8 | 00378              | Fri Mar 20 00:00:00 1970 PST
5560   379 | 509 | 00379_update9      | Sat Mar 21 00:00:00 1970 PST
5561   380 |   0 | 00380              | Sun Mar 22 00:00:00 1970 PST
5562   381 |   1 | 00381              | Mon Mar 23 00:00:00 1970 PST
5563   383 | 303 | 00383_update3      | Wed Mar 25 00:00:00 1970 PST
5564   384 |   4 | 00384              | Thu Mar 26 00:00:00 1970 PST
5565   386 |   6 | 00386              | Sat Mar 28 00:00:00 1970 PST
5566   387 | 407 | 00387_update7      | Sun Mar 29 00:00:00 1970 PST
5567   388 |   8 | 00388              | Mon Mar 30 00:00:00 1970 PST
5568   389 | 509 | 00389_update9      | Tue Mar 31 00:00:00 1970 PST
5569   390 |   0 | 00390              | Wed Apr 01 00:00:00 1970 PST
5570   391 |   1 | 00391              | Thu Apr 02 00:00:00 1970 PST
5571   393 | 303 | 00393_update3      | Sat Apr 04 00:00:00 1970 PST
5572   394 |   4 | 00394              | Sun Apr 05 00:00:00 1970 PST
5573   396 |   6 | 00396              | Tue Apr 07 00:00:00 1970 PST
5574   397 | 407 | 00397_update7      | Wed Apr 08 00:00:00 1970 PST
5575   398 |   8 | 00398              | Thu Apr 09 00:00:00 1970 PST
5576   399 | 509 | 00399_update9      | Fri Apr 10 00:00:00 1970 PST
5577   400 |   0 | 00400              | Thu Jan 01 00:00:00 1970 PST
5578   401 |   1 | 00401              | Fri Jan 02 00:00:00 1970 PST
5579   403 | 303 | 00403_update3      | Sun Jan 04 00:00:00 1970 PST
5580   404 |   4 | 00404              | Mon Jan 05 00:00:00 1970 PST
5581   406 |   6 | 00406              | Wed Jan 07 00:00:00 1970 PST
5582   407 | 407 | 00407_update7      | Thu Jan 08 00:00:00 1970 PST
5583   408 |   8 | 00408              | Fri Jan 09 00:00:00 1970 PST
5584   409 | 509 | 00409_update9      | Sat Jan 10 00:00:00 1970 PST
5585   410 |   0 | 00410              | Sun Jan 11 00:00:00 1970 PST
5586   411 |   1 | 00411              | Mon Jan 12 00:00:00 1970 PST
5587   413 | 303 | 00413_update3      | Wed Jan 14 00:00:00 1970 PST
5588   414 |   4 | 00414              | Thu Jan 15 00:00:00 1970 PST
5589   416 |   6 | 00416              | Sat Jan 17 00:00:00 1970 PST
5590   417 | 407 | 00417_update7      | Sun Jan 18 00:00:00 1970 PST
5591   418 |   8 | 00418              | Mon Jan 19 00:00:00 1970 PST
5592   419 | 509 | 00419_update9      | Tue Jan 20 00:00:00 1970 PST
5593   420 |   0 | 00420              | Wed Jan 21 00:00:00 1970 PST
5594   421 |   1 | 00421              | Thu Jan 22 00:00:00 1970 PST
5595   423 | 303 | 00423_update3      | Sat Jan 24 00:00:00 1970 PST
5596   424 |   4 | 00424              | Sun Jan 25 00:00:00 1970 PST
5597   426 |   6 | 00426              | Tue Jan 27 00:00:00 1970 PST
5598   427 | 407 | 00427_update7      | Wed Jan 28 00:00:00 1970 PST
5599   428 |   8 | 00428              | Thu Jan 29 00:00:00 1970 PST
5600   429 | 509 | 00429_update9      | Fri Jan 30 00:00:00 1970 PST
5601   430 |   0 | 00430              | Sat Jan 31 00:00:00 1970 PST
5602   431 |   1 | 00431              | Sun Feb 01 00:00:00 1970 PST
5603   433 | 303 | 00433_update3      | Tue Feb 03 00:00:00 1970 PST
5604   434 |   4 | 00434              | Wed Feb 04 00:00:00 1970 PST
5605   436 |   6 | 00436              | Fri Feb 06 00:00:00 1970 PST
5606   437 | 407 | 00437_update7      | Sat Feb 07 00:00:00 1970 PST
5607   438 |   8 | 00438              | Sun Feb 08 00:00:00 1970 PST
5608   439 | 509 | 00439_update9      | Mon Feb 09 00:00:00 1970 PST
5609   440 |   0 | 00440              | Tue Feb 10 00:00:00 1970 PST
5610   441 |   1 | 00441              | Wed Feb 11 00:00:00 1970 PST
5611   443 | 303 | 00443_update3      | Fri Feb 13 00:00:00 1970 PST
5612   444 |   4 | 00444              | Sat Feb 14 00:00:00 1970 PST
5613   446 |   6 | 00446              | Mon Feb 16 00:00:00 1970 PST
5614   447 | 407 | 00447_update7      | Tue Feb 17 00:00:00 1970 PST
5615   448 |   8 | 00448              | Wed Feb 18 00:00:00 1970 PST
5616   449 | 509 | 00449_update9      | Thu Feb 19 00:00:00 1970 PST
5617   450 |   0 | 00450              | Fri Feb 20 00:00:00 1970 PST
5618   451 |   1 | 00451              | Sat Feb 21 00:00:00 1970 PST
5619   453 | 303 | 00453_update3      | Mon Feb 23 00:00:00 1970 PST
5620   454 |   4 | 00454              | Tue Feb 24 00:00:00 1970 PST
5621   456 |   6 | 00456              | Thu Feb 26 00:00:00 1970 PST
5622   457 | 407 | 00457_update7      | Fri Feb 27 00:00:00 1970 PST
5623   458 |   8 | 00458              | Sat Feb 28 00:00:00 1970 PST
5624   459 | 509 | 00459_update9      | Sun Mar 01 00:00:00 1970 PST
5625   460 |   0 | 00460              | Mon Mar 02 00:00:00 1970 PST
5626   461 |   1 | 00461              | Tue Mar 03 00:00:00 1970 PST
5627   463 | 303 | 00463_update3      | Thu Mar 05 00:00:00 1970 PST
5628   464 |   4 | 00464              | Fri Mar 06 00:00:00 1970 PST
5629   466 |   6 | 00466              | Sun Mar 08 00:00:00 1970 PST
5630   467 | 407 | 00467_update7      | Mon Mar 09 00:00:00 1970 PST
5631   468 |   8 | 00468              | Tue Mar 10 00:00:00 1970 PST
5632   469 | 509 | 00469_update9      | Wed Mar 11 00:00:00 1970 PST
5633   470 |   0 | 00470              | Thu Mar 12 00:00:00 1970 PST
5634   471 |   1 | 00471              | Fri Mar 13 00:00:00 1970 PST
5635   473 | 303 | 00473_update3      | Sun Mar 15 00:00:00 1970 PST
5636   474 |   4 | 00474              | Mon Mar 16 00:00:00 1970 PST
5637   476 |   6 | 00476              | Wed Mar 18 00:00:00 1970 PST
5638   477 | 407 | 00477_update7      | Thu Mar 19 00:00:00 1970 PST
5639   478 |   8 | 00478              | Fri Mar 20 00:00:00 1970 PST
5640   479 | 509 | 00479_update9      | Sat Mar 21 00:00:00 1970 PST
5641   480 |   0 | 00480              | Sun Mar 22 00:00:00 1970 PST
5642   481 |   1 | 00481              | Mon Mar 23 00:00:00 1970 PST
5643   483 | 303 | 00483_update3      | Wed Mar 25 00:00:00 1970 PST
5644   484 |   4 | 00484              | Thu Mar 26 00:00:00 1970 PST
5645   486 |   6 | 00486              | Sat Mar 28 00:00:00 1970 PST
5646   487 | 407 | 00487_update7      | Sun Mar 29 00:00:00 1970 PST
5647   488 |   8 | 00488              | Mon Mar 30 00:00:00 1970 PST
5648   489 | 509 | 00489_update9      | Tue Mar 31 00:00:00 1970 PST
5649   490 |   0 | 00490              | Wed Apr 01 00:00:00 1970 PST
5650   491 |   1 | 00491              | Thu Apr 02 00:00:00 1970 PST
5651   493 | 303 | 00493_update3      | Sat Apr 04 00:00:00 1970 PST
5652   494 |   4 | 00494              | Sun Apr 05 00:00:00 1970 PST
5653   496 |   6 | 00496              | Tue Apr 07 00:00:00 1970 PST
5654   497 | 407 | 00497_update7      | Wed Apr 08 00:00:00 1970 PST
5655   498 |   8 | 00498              | Thu Apr 09 00:00:00 1970 PST
5656   499 | 509 | 00499_update9      | Fri Apr 10 00:00:00 1970 PST
5657   500 |   0 | 00500              | Thu Jan 01 00:00:00 1970 PST
5658   501 |   1 | 00501              | Fri Jan 02 00:00:00 1970 PST
5659   503 | 303 | 00503_update3      | Sun Jan 04 00:00:00 1970 PST
5660   504 |   4 | 00504              | Mon Jan 05 00:00:00 1970 PST
5661   506 |   6 | 00506              | Wed Jan 07 00:00:00 1970 PST
5662   507 | 407 | 00507_update7      | Thu Jan 08 00:00:00 1970 PST
5663   508 |   8 | 00508              | Fri Jan 09 00:00:00 1970 PST
5664   509 | 509 | 00509_update9      | Sat Jan 10 00:00:00 1970 PST
5665   510 |   0 | 00510              | Sun Jan 11 00:00:00 1970 PST
5666   511 |   1 | 00511              | Mon Jan 12 00:00:00 1970 PST
5667   513 | 303 | 00513_update3      | Wed Jan 14 00:00:00 1970 PST
5668   514 |   4 | 00514              | Thu Jan 15 00:00:00 1970 PST
5669   516 |   6 | 00516              | Sat Jan 17 00:00:00 1970 PST
5670   517 | 407 | 00517_update7      | Sun Jan 18 00:00:00 1970 PST
5671   518 |   8 | 00518              | Mon Jan 19 00:00:00 1970 PST
5672   519 | 509 | 00519_update9      | Tue Jan 20 00:00:00 1970 PST
5673   520 |   0 | 00520              | Wed Jan 21 00:00:00 1970 PST
5674   521 |   1 | 00521              | Thu Jan 22 00:00:00 1970 PST
5675   523 | 303 | 00523_update3      | Sat Jan 24 00:00:00 1970 PST
5676   524 |   4 | 00524              | Sun Jan 25 00:00:00 1970 PST
5677   526 |   6 | 00526              | Tue Jan 27 00:00:00 1970 PST
5678   527 | 407 | 00527_update7      | Wed Jan 28 00:00:00 1970 PST
5679   528 |   8 | 00528              | Thu Jan 29 00:00:00 1970 PST
5680   529 | 509 | 00529_update9      | Fri Jan 30 00:00:00 1970 PST
5681   530 |   0 | 00530              | Sat Jan 31 00:00:00 1970 PST
5682   531 |   1 | 00531              | Sun Feb 01 00:00:00 1970 PST
5683   533 | 303 | 00533_update3      | Tue Feb 03 00:00:00 1970 PST
5684   534 |   4 | 00534              | Wed Feb 04 00:00:00 1970 PST
5685   536 |   6 | 00536              | Fri Feb 06 00:00:00 1970 PST
5686   537 | 407 | 00537_update7      | Sat Feb 07 00:00:00 1970 PST
5687   538 |   8 | 00538              | Sun Feb 08 00:00:00 1970 PST
5688   539 | 509 | 00539_update9      | Mon Feb 09 00:00:00 1970 PST
5689   540 |   0 | 00540              | Tue Feb 10 00:00:00 1970 PST
5690   541 |   1 | 00541              | Wed Feb 11 00:00:00 1970 PST
5691   543 | 303 | 00543_update3      | Fri Feb 13 00:00:00 1970 PST
5692   544 |   4 | 00544              | Sat Feb 14 00:00:00 1970 PST
5693   546 |   6 | 00546              | Mon Feb 16 00:00:00 1970 PST
5694   547 | 407 | 00547_update7      | Tue Feb 17 00:00:00 1970 PST
5695   548 |   8 | 00548              | Wed Feb 18 00:00:00 1970 PST
5696   549 | 509 | 00549_update9      | Thu Feb 19 00:00:00 1970 PST
5697   550 |   0 | 00550              | Fri Feb 20 00:00:00 1970 PST
5698   551 |   1 | 00551              | Sat Feb 21 00:00:00 1970 PST
5699   553 | 303 | 00553_update3      | Mon Feb 23 00:00:00 1970 PST
5700   554 |   4 | 00554              | Tue Feb 24 00:00:00 1970 PST
5701   556 |   6 | 00556              | Thu Feb 26 00:00:00 1970 PST
5702   557 | 407 | 00557_update7      | Fri Feb 27 00:00:00 1970 PST
5703   558 |   8 | 00558              | Sat Feb 28 00:00:00 1970 PST
5704   559 | 509 | 00559_update9      | Sun Mar 01 00:00:00 1970 PST
5705   560 |   0 | 00560              | Mon Mar 02 00:00:00 1970 PST
5706   561 |   1 | 00561              | Tue Mar 03 00:00:00 1970 PST
5707   563 | 303 | 00563_update3      | Thu Mar 05 00:00:00 1970 PST
5708   564 |   4 | 00564              | Fri Mar 06 00:00:00 1970 PST
5709   566 |   6 | 00566              | Sun Mar 08 00:00:00 1970 PST
5710   567 | 407 | 00567_update7      | Mon Mar 09 00:00:00 1970 PST
5711   568 |   8 | 00568              | Tue Mar 10 00:00:00 1970 PST
5712   569 | 509 | 00569_update9      | Wed Mar 11 00:00:00 1970 PST
5713   570 |   0 | 00570              | Thu Mar 12 00:00:00 1970 PST
5714   571 |   1 | 00571              | Fri Mar 13 00:00:00 1970 PST
5715   573 | 303 | 00573_update3      | Sun Mar 15 00:00:00 1970 PST
5716   574 |   4 | 00574              | Mon Mar 16 00:00:00 1970 PST
5717   576 |   6 | 00576              | Wed Mar 18 00:00:00 1970 PST
5718   577 | 407 | 00577_update7      | Thu Mar 19 00:00:00 1970 PST
5719   578 |   8 | 00578              | Fri Mar 20 00:00:00 1970 PST
5720   579 | 509 | 00579_update9      | Sat Mar 21 00:00:00 1970 PST
5721   580 |   0 | 00580              | Sun Mar 22 00:00:00 1970 PST
5722   581 |   1 | 00581              | Mon Mar 23 00:00:00 1970 PST
5723   583 | 303 | 00583_update3      | Wed Mar 25 00:00:00 1970 PST
5724   584 |   4 | 00584              | Thu Mar 26 00:00:00 1970 PST
5725   586 |   6 | 00586              | Sat Mar 28 00:00:00 1970 PST
5726   587 | 407 | 00587_update7      | Sun Mar 29 00:00:00 1970 PST
5727   588 |   8 | 00588              | Mon Mar 30 00:00:00 1970 PST
5728   589 | 509 | 00589_update9      | Tue Mar 31 00:00:00 1970 PST
5729   590 |   0 | 00590              | Wed Apr 01 00:00:00 1970 PST
5730   591 |   1 | 00591              | Thu Apr 02 00:00:00 1970 PST
5731   593 | 303 | 00593_update3      | Sat Apr 04 00:00:00 1970 PST
5732   594 |   4 | 00594              | Sun Apr 05 00:00:00 1970 PST
5733   596 |   6 | 00596              | Tue Apr 07 00:00:00 1970 PST
5734   597 | 407 | 00597_update7      | Wed Apr 08 00:00:00 1970 PST
5735   598 |   8 | 00598              | Thu Apr 09 00:00:00 1970 PST
5736   599 | 509 | 00599_update9      | Fri Apr 10 00:00:00 1970 PST
5737   600 |   0 | 00600              | Thu Jan 01 00:00:00 1970 PST
5738   601 |   1 | 00601              | Fri Jan 02 00:00:00 1970 PST
5739   603 | 303 | 00603_update3      | Sun Jan 04 00:00:00 1970 PST
5740   604 |   4 | 00604              | Mon Jan 05 00:00:00 1970 PST
5741   606 |   6 | 00606              | Wed Jan 07 00:00:00 1970 PST
5742   607 | 407 | 00607_update7      | Thu Jan 08 00:00:00 1970 PST
5743   608 |   8 | 00608              | Fri Jan 09 00:00:00 1970 PST
5744   609 | 509 | 00609_update9      | Sat Jan 10 00:00:00 1970 PST
5745   610 |   0 | 00610              | Sun Jan 11 00:00:00 1970 PST
5746   611 |   1 | 00611              | Mon Jan 12 00:00:00 1970 PST
5747   613 | 303 | 00613_update3      | Wed Jan 14 00:00:00 1970 PST
5748   614 |   4 | 00614              | Thu Jan 15 00:00:00 1970 PST
5749   616 |   6 | 00616              | Sat Jan 17 00:00:00 1970 PST
5750   617 | 407 | 00617_update7      | Sun Jan 18 00:00:00 1970 PST
5751   618 |   8 | 00618              | Mon Jan 19 00:00:00 1970 PST
5752   619 | 509 | 00619_update9      | Tue Jan 20 00:00:00 1970 PST
5753   620 |   0 | 00620              | Wed Jan 21 00:00:00 1970 PST
5754   621 |   1 | 00621              | Thu Jan 22 00:00:00 1970 PST
5755   623 | 303 | 00623_update3      | Sat Jan 24 00:00:00 1970 PST
5756   624 |   4 | 00624              | Sun Jan 25 00:00:00 1970 PST
5757   626 |   6 | 00626              | Tue Jan 27 00:00:00 1970 PST
5758   627 | 407 | 00627_update7      | Wed Jan 28 00:00:00 1970 PST
5759   628 |   8 | 00628              | Thu Jan 29 00:00:00 1970 PST
5760   629 | 509 | 00629_update9      | Fri Jan 30 00:00:00 1970 PST
5761   630 |   0 | 00630              | Sat Jan 31 00:00:00 1970 PST
5762   631 |   1 | 00631              | Sun Feb 01 00:00:00 1970 PST
5763   633 | 303 | 00633_update3      | Tue Feb 03 00:00:00 1970 PST
5764   634 |   4 | 00634              | Wed Feb 04 00:00:00 1970 PST
5765   636 |   6 | 00636              | Fri Feb 06 00:00:00 1970 PST
5766   637 | 407 | 00637_update7      | Sat Feb 07 00:00:00 1970 PST
5767   638 |   8 | 00638              | Sun Feb 08 00:00:00 1970 PST
5768   639 | 509 | 00639_update9      | Mon Feb 09 00:00:00 1970 PST
5769   640 |   0 | 00640              | Tue Feb 10 00:00:00 1970 PST
5770   641 |   1 | 00641              | Wed Feb 11 00:00:00 1970 PST
5771   643 | 303 | 00643_update3      | Fri Feb 13 00:00:00 1970 PST
5772   644 |   4 | 00644              | Sat Feb 14 00:00:00 1970 PST
5773   646 |   6 | 00646              | Mon Feb 16 00:00:00 1970 PST
5774   647 | 407 | 00647_update7      | Tue Feb 17 00:00:00 1970 PST
5775   648 |   8 | 00648              | Wed Feb 18 00:00:00 1970 PST
5776   649 | 509 | 00649_update9      | Thu Feb 19 00:00:00 1970 PST
5777   650 |   0 | 00650              | Fri Feb 20 00:00:00 1970 PST
5778   651 |   1 | 00651              | Sat Feb 21 00:00:00 1970 PST
5779   653 | 303 | 00653_update3      | Mon Feb 23 00:00:00 1970 PST
5780   654 |   4 | 00654              | Tue Feb 24 00:00:00 1970 PST
5781   656 |   6 | 00656              | Thu Feb 26 00:00:00 1970 PST
5782   657 | 407 | 00657_update7      | Fri Feb 27 00:00:00 1970 PST
5783   658 |   8 | 00658              | Sat Feb 28 00:00:00 1970 PST
5784   659 | 509 | 00659_update9      | Sun Mar 01 00:00:00 1970 PST
5785   660 |   0 | 00660              | Mon Mar 02 00:00:00 1970 PST
5786   661 |   1 | 00661              | Tue Mar 03 00:00:00 1970 PST
5787   663 | 303 | 00663_update3      | Thu Mar 05 00:00:00 1970 PST
5788   664 |   4 | 00664              | Fri Mar 06 00:00:00 1970 PST
5789   666 |   6 | 00666              | Sun Mar 08 00:00:00 1970 PST
5790   667 | 407 | 00667_update7      | Mon Mar 09 00:00:00 1970 PST
5791   668 |   8 | 00668              | Tue Mar 10 00:00:00 1970 PST
5792   669 | 509 | 00669_update9      | Wed Mar 11 00:00:00 1970 PST
5793   670 |   0 | 00670              | Thu Mar 12 00:00:00 1970 PST
5794   671 |   1 | 00671              | Fri Mar 13 00:00:00 1970 PST
5795   673 | 303 | 00673_update3      | Sun Mar 15 00:00:00 1970 PST
5796   674 |   4 | 00674              | Mon Mar 16 00:00:00 1970 PST
5797   676 |   6 | 00676              | Wed Mar 18 00:00:00 1970 PST
5798   677 | 407 | 00677_update7      | Thu Mar 19 00:00:00 1970 PST
5799   678 |   8 | 00678              | Fri Mar 20 00:00:00 1970 PST
5800   679 | 509 | 00679_update9      | Sat Mar 21 00:00:00 1970 PST
5801   680 |   0 | 00680              | Sun Mar 22 00:00:00 1970 PST
5802   681 |   1 | 00681              | Mon Mar 23 00:00:00 1970 PST
5803   683 | 303 | 00683_update3      | Wed Mar 25 00:00:00 1970 PST
5804   684 |   4 | 00684              | Thu Mar 26 00:00:00 1970 PST
5805   686 |   6 | 00686              | Sat Mar 28 00:00:00 1970 PST
5806   687 | 407 | 00687_update7      | Sun Mar 29 00:00:00 1970 PST
5807   688 |   8 | 00688              | Mon Mar 30 00:00:00 1970 PST
5808   689 | 509 | 00689_update9      | Tue Mar 31 00:00:00 1970 PST
5809   690 |   0 | 00690              | Wed Apr 01 00:00:00 1970 PST
5810   691 |   1 | 00691              | Thu Apr 02 00:00:00 1970 PST
5811   693 | 303 | 00693_update3      | Sat Apr 04 00:00:00 1970 PST
5812   694 |   4 | 00694              | Sun Apr 05 00:00:00 1970 PST
5813   696 |   6 | 00696              | Tue Apr 07 00:00:00 1970 PST
5814   697 | 407 | 00697_update7      | Wed Apr 08 00:00:00 1970 PST
5815   698 |   8 | 00698              | Thu Apr 09 00:00:00 1970 PST
5816   699 | 509 | 00699_update9      | Fri Apr 10 00:00:00 1970 PST
5817   700 |   0 | 00700              | Thu Jan 01 00:00:00 1970 PST
5818   701 |   1 | 00701              | Fri Jan 02 00:00:00 1970 PST
5819   703 | 303 | 00703_update3      | Sun Jan 04 00:00:00 1970 PST
5820   704 |   4 | 00704              | Mon Jan 05 00:00:00 1970 PST
5821   706 |   6 | 00706              | Wed Jan 07 00:00:00 1970 PST
5822   707 | 407 | 00707_update7      | Thu Jan 08 00:00:00 1970 PST
5823   708 |   8 | 00708              | Fri Jan 09 00:00:00 1970 PST
5824   709 | 509 | 00709_update9      | Sat Jan 10 00:00:00 1970 PST
5825   710 |   0 | 00710              | Sun Jan 11 00:00:00 1970 PST
5826   711 |   1 | 00711              | Mon Jan 12 00:00:00 1970 PST
5827   713 | 303 | 00713_update3      | Wed Jan 14 00:00:00 1970 PST
5828   714 |   4 | 00714              | Thu Jan 15 00:00:00 1970 PST
5829   716 |   6 | 00716              | Sat Jan 17 00:00:00 1970 PST
5830   717 | 407 | 00717_update7      | Sun Jan 18 00:00:00 1970 PST
5831   718 |   8 | 00718              | Mon Jan 19 00:00:00 1970 PST
5832   719 | 509 | 00719_update9      | Tue Jan 20 00:00:00 1970 PST
5833   720 |   0 | 00720              | Wed Jan 21 00:00:00 1970 PST
5834   721 |   1 | 00721              | Thu Jan 22 00:00:00 1970 PST
5835   723 | 303 | 00723_update3      | Sat Jan 24 00:00:00 1970 PST
5836   724 |   4 | 00724              | Sun Jan 25 00:00:00 1970 PST
5837   726 |   6 | 00726              | Tue Jan 27 00:00:00 1970 PST
5838   727 | 407 | 00727_update7      | Wed Jan 28 00:00:00 1970 PST
5839   728 |   8 | 00728              | Thu Jan 29 00:00:00 1970 PST
5840   729 | 509 | 00729_update9      | Fri Jan 30 00:00:00 1970 PST
5841   730 |   0 | 00730              | Sat Jan 31 00:00:00 1970 PST
5842   731 |   1 | 00731              | Sun Feb 01 00:00:00 1970 PST
5843   733 | 303 | 00733_update3      | Tue Feb 03 00:00:00 1970 PST
5844   734 |   4 | 00734              | Wed Feb 04 00:00:00 1970 PST
5845   736 |   6 | 00736              | Fri Feb 06 00:00:00 1970 PST
5846   737 | 407 | 00737_update7      | Sat Feb 07 00:00:00 1970 PST
5847   738 |   8 | 00738              | Sun Feb 08 00:00:00 1970 PST
5848   739 | 509 | 00739_update9      | Mon Feb 09 00:00:00 1970 PST
5849   740 |   0 | 00740              | Tue Feb 10 00:00:00 1970 PST
5850   741 |   1 | 00741              | Wed Feb 11 00:00:00 1970 PST
5851   743 | 303 | 00743_update3      | Fri Feb 13 00:00:00 1970 PST
5852   744 |   4 | 00744              | Sat Feb 14 00:00:00 1970 PST
5853   746 |   6 | 00746              | Mon Feb 16 00:00:00 1970 PST
5854   747 | 407 | 00747_update7      | Tue Feb 17 00:00:00 1970 PST
5855   748 |   8 | 00748              | Wed Feb 18 00:00:00 1970 PST
5856   749 | 509 | 00749_update9      | Thu Feb 19 00:00:00 1970 PST
5857   750 |   0 | 00750              | Fri Feb 20 00:00:00 1970 PST
5858   751 |   1 | 00751              | Sat Feb 21 00:00:00 1970 PST
5859   753 | 303 | 00753_update3      | Mon Feb 23 00:00:00 1970 PST
5860   754 |   4 | 00754              | Tue Feb 24 00:00:00 1970 PST
5861   756 |   6 | 00756              | Thu Feb 26 00:00:00 1970 PST
5862   757 | 407 | 00757_update7      | Fri Feb 27 00:00:00 1970 PST
5863   758 |   8 | 00758              | Sat Feb 28 00:00:00 1970 PST
5864   759 | 509 | 00759_update9      | Sun Mar 01 00:00:00 1970 PST
5865   760 |   0 | 00760              | Mon Mar 02 00:00:00 1970 PST
5866   761 |   1 | 00761              | Tue Mar 03 00:00:00 1970 PST
5867   763 | 303 | 00763_update3      | Thu Mar 05 00:00:00 1970 PST
5868   764 |   4 | 00764              | Fri Mar 06 00:00:00 1970 PST
5869   766 |   6 | 00766              | Sun Mar 08 00:00:00 1970 PST
5870   767 | 407 | 00767_update7      | Mon Mar 09 00:00:00 1970 PST
5871   768 |   8 | 00768              | Tue Mar 10 00:00:00 1970 PST
5872   769 | 509 | 00769_update9      | Wed Mar 11 00:00:00 1970 PST
5873   770 |   0 | 00770              | Thu Mar 12 00:00:00 1970 PST
5874   771 |   1 | 00771              | Fri Mar 13 00:00:00 1970 PST
5875   773 | 303 | 00773_update3      | Sun Mar 15 00:00:00 1970 PST
5876   774 |   4 | 00774              | Mon Mar 16 00:00:00 1970 PST
5877   776 |   6 | 00776              | Wed Mar 18 00:00:00 1970 PST
5878   777 | 407 | 00777_update7      | Thu Mar 19 00:00:00 1970 PST
5879   778 |   8 | 00778              | Fri Mar 20 00:00:00 1970 PST
5880   779 | 509 | 00779_update9      | Sat Mar 21 00:00:00 1970 PST
5881   780 |   0 | 00780              | Sun Mar 22 00:00:00 1970 PST
5882   781 |   1 | 00781              | Mon Mar 23 00:00:00 1970 PST
5883   783 | 303 | 00783_update3      | Wed Mar 25 00:00:00 1970 PST
5884   784 |   4 | 00784              | Thu Mar 26 00:00:00 1970 PST
5885   786 |   6 | 00786              | Sat Mar 28 00:00:00 1970 PST
5886   787 | 407 | 00787_update7      | Sun Mar 29 00:00:00 1970 PST
5887   788 |   8 | 00788              | Mon Mar 30 00:00:00 1970 PST
5888   789 | 509 | 00789_update9      | Tue Mar 31 00:00:00 1970 PST
5889   790 |   0 | 00790              | Wed Apr 01 00:00:00 1970 PST
5890   791 |   1 | 00791              | Thu Apr 02 00:00:00 1970 PST
5891   793 | 303 | 00793_update3      | Sat Apr 04 00:00:00 1970 PST
5892   794 |   4 | 00794              | Sun Apr 05 00:00:00 1970 PST
5893   796 |   6 | 00796              | Tue Apr 07 00:00:00 1970 PST
5894   797 | 407 | 00797_update7      | Wed Apr 08 00:00:00 1970 PST
5895   798 |   8 | 00798              | Thu Apr 09 00:00:00 1970 PST
5896   799 | 509 | 00799_update9      | Fri Apr 10 00:00:00 1970 PST
5897   800 |   0 | 00800              | Thu Jan 01 00:00:00 1970 PST
5898   801 |   1 | 00801              | Fri Jan 02 00:00:00 1970 PST
5899   803 | 303 | 00803_update3      | Sun Jan 04 00:00:00 1970 PST
5900   804 |   4 | 00804              | Mon Jan 05 00:00:00 1970 PST
5901   806 |   6 | 00806              | Wed Jan 07 00:00:00 1970 PST
5902   807 | 407 | 00807_update7      | Thu Jan 08 00:00:00 1970 PST
5903   808 |   8 | 00808              | Fri Jan 09 00:00:00 1970 PST
5904   809 | 509 | 00809_update9      | Sat Jan 10 00:00:00 1970 PST
5905   810 |   0 | 00810              | Sun Jan 11 00:00:00 1970 PST
5906   811 |   1 | 00811              | Mon Jan 12 00:00:00 1970 PST
5907   813 | 303 | 00813_update3      | Wed Jan 14 00:00:00 1970 PST
5908   814 |   4 | 00814              | Thu Jan 15 00:00:00 1970 PST
5909   816 |   6 | 00816              | Sat Jan 17 00:00:00 1970 PST
5910   817 | 407 | 00817_update7      | Sun Jan 18 00:00:00 1970 PST
5911   818 |   8 | 00818              | Mon Jan 19 00:00:00 1970 PST
5912   819 | 509 | 00819_update9      | Tue Jan 20 00:00:00 1970 PST
5913   820 |   0 | 00820              | Wed Jan 21 00:00:00 1970 PST
5914   821 |   1 | 00821              | Thu Jan 22 00:00:00 1970 PST
5915   823 | 303 | 00823_update3      | Sat Jan 24 00:00:00 1970 PST
5916   824 |   4 | 00824              | Sun Jan 25 00:00:00 1970 PST
5917   826 |   6 | 00826              | Tue Jan 27 00:00:00 1970 PST
5918   827 | 407 | 00827_update7      | Wed Jan 28 00:00:00 1970 PST
5919   828 |   8 | 00828              | Thu Jan 29 00:00:00 1970 PST
5920   829 | 509 | 00829_update9      | Fri Jan 30 00:00:00 1970 PST
5921   830 |   0 | 00830              | Sat Jan 31 00:00:00 1970 PST
5922   831 |   1 | 00831              | Sun Feb 01 00:00:00 1970 PST
5923   833 | 303 | 00833_update3      | Tue Feb 03 00:00:00 1970 PST
5924   834 |   4 | 00834              | Wed Feb 04 00:00:00 1970 PST
5925   836 |   6 | 00836              | Fri Feb 06 00:00:00 1970 PST
5926   837 | 407 | 00837_update7      | Sat Feb 07 00:00:00 1970 PST
5927   838 |   8 | 00838              | Sun Feb 08 00:00:00 1970 PST
5928   839 | 509 | 00839_update9      | Mon Feb 09 00:00:00 1970 PST
5929   840 |   0 | 00840              | Tue Feb 10 00:00:00 1970 PST
5930   841 |   1 | 00841              | Wed Feb 11 00:00:00 1970 PST
5931   843 | 303 | 00843_update3      | Fri Feb 13 00:00:00 1970 PST
5932   844 |   4 | 00844              | Sat Feb 14 00:00:00 1970 PST
5933   846 |   6 | 00846              | Mon Feb 16 00:00:00 1970 PST
5934   847 | 407 | 00847_update7      | Tue Feb 17 00:00:00 1970 PST
5935   848 |   8 | 00848              | Wed Feb 18 00:00:00 1970 PST
5936   849 | 509 | 00849_update9      | Thu Feb 19 00:00:00 1970 PST
5937   850 |   0 | 00850              | Fri Feb 20 00:00:00 1970 PST
5938   851 |   1 | 00851              | Sat Feb 21 00:00:00 1970 PST
5939   853 | 303 | 00853_update3      | Mon Feb 23 00:00:00 1970 PST
5940   854 |   4 | 00854              | Tue Feb 24 00:00:00 1970 PST
5941   856 |   6 | 00856              | Thu Feb 26 00:00:00 1970 PST
5942   857 | 407 | 00857_update7      | Fri Feb 27 00:00:00 1970 PST
5943   858 |   8 | 00858              | Sat Feb 28 00:00:00 1970 PST
5944   859 | 509 | 00859_update9      | Sun Mar 01 00:00:00 1970 PST
5945   860 |   0 | 00860              | Mon Mar 02 00:00:00 1970 PST
5946   861 |   1 | 00861              | Tue Mar 03 00:00:00 1970 PST
5947   863 | 303 | 00863_update3      | Thu Mar 05 00:00:00 1970 PST
5948   864 |   4 | 00864              | Fri Mar 06 00:00:00 1970 PST
5949   866 |   6 | 00866              | Sun Mar 08 00:00:00 1970 PST
5950   867 | 407 | 00867_update7      | Mon Mar 09 00:00:00 1970 PST
5951   868 |   8 | 00868              | Tue Mar 10 00:00:00 1970 PST
5952   869 | 509 | 00869_update9      | Wed Mar 11 00:00:00 1970 PST
5953   870 |   0 | 00870              | Thu Mar 12 00:00:00 1970 PST
5954   871 |   1 | 00871              | Fri Mar 13 00:00:00 1970 PST
5955   873 | 303 | 00873_update3      | Sun Mar 15 00:00:00 1970 PST
5956   874 |   4 | 00874              | Mon Mar 16 00:00:00 1970 PST
5957   876 |   6 | 00876              | Wed Mar 18 00:00:00 1970 PST
5958   877 | 407 | 00877_update7      | Thu Mar 19 00:00:00 1970 PST
5959   878 |   8 | 00878              | Fri Mar 20 00:00:00 1970 PST
5960   879 | 509 | 00879_update9      | Sat Mar 21 00:00:00 1970 PST
5961   880 |   0 | 00880              | Sun Mar 22 00:00:00 1970 PST
5962   881 |   1 | 00881              | Mon Mar 23 00:00:00 1970 PST
5963   883 | 303 | 00883_update3      | Wed Mar 25 00:00:00 1970 PST
5964   884 |   4 | 00884              | Thu Mar 26 00:00:00 1970 PST
5965   886 |   6 | 00886              | Sat Mar 28 00:00:00 1970 PST
5966   887 | 407 | 00887_update7      | Sun Mar 29 00:00:00 1970 PST
5967   888 |   8 | 00888              | Mon Mar 30 00:00:00 1970 PST
5968   889 | 509 | 00889_update9      | Tue Mar 31 00:00:00 1970 PST
5969   890 |   0 | 00890              | Wed Apr 01 00:00:00 1970 PST
5970   891 |   1 | 00891              | Thu Apr 02 00:00:00 1970 PST
5971   893 | 303 | 00893_update3      | Sat Apr 04 00:00:00 1970 PST
5972   894 |   4 | 00894              | Sun Apr 05 00:00:00 1970 PST
5973   896 |   6 | 00896              | Tue Apr 07 00:00:00 1970 PST
5974   897 | 407 | 00897_update7      | Wed Apr 08 00:00:00 1970 PST
5975   898 |   8 | 00898              | Thu Apr 09 00:00:00 1970 PST
5976   899 | 509 | 00899_update9      | Fri Apr 10 00:00:00 1970 PST
5977   900 |   0 | 00900              | Thu Jan 01 00:00:00 1970 PST
5978   901 |   1 | 00901              | Fri Jan 02 00:00:00 1970 PST
5979   903 | 303 | 00903_update3      | Sun Jan 04 00:00:00 1970 PST
5980   904 |   4 | 00904              | Mon Jan 05 00:00:00 1970 PST
5981   906 |   6 | 00906              | Wed Jan 07 00:00:00 1970 PST
5982   907 | 407 | 00907_update7      | Thu Jan 08 00:00:00 1970 PST
5983   908 |   8 | 00908              | Fri Jan 09 00:00:00 1970 PST
5984   909 | 509 | 00909_update9      | Sat Jan 10 00:00:00 1970 PST
5985   910 |   0 | 00910              | Sun Jan 11 00:00:00 1970 PST
5986   911 |   1 | 00911              | Mon Jan 12 00:00:00 1970 PST
5987   913 | 303 | 00913_update3      | Wed Jan 14 00:00:00 1970 PST
5988   914 |   4 | 00914              | Thu Jan 15 00:00:00 1970 PST
5989   916 |   6 | 00916              | Sat Jan 17 00:00:00 1970 PST
5990   917 | 407 | 00917_update7      | Sun Jan 18 00:00:00 1970 PST
5991   918 |   8 | 00918              | Mon Jan 19 00:00:00 1970 PST
5992   919 | 509 | 00919_update9      | Tue Jan 20 00:00:00 1970 PST
5993   920 |   0 | 00920              | Wed Jan 21 00:00:00 1970 PST
5994   921 |   1 | 00921              | Thu Jan 22 00:00:00 1970 PST
5995   923 | 303 | 00923_update3      | Sat Jan 24 00:00:00 1970 PST
5996   924 |   4 | 00924              | Sun Jan 25 00:00:00 1970 PST
5997   926 |   6 | 00926              | Tue Jan 27 00:00:00 1970 PST
5998   927 | 407 | 00927_update7      | Wed Jan 28 00:00:00 1970 PST
5999   928 |   8 | 00928              | Thu Jan 29 00:00:00 1970 PST
6000   929 | 509 | 00929_update9      | Fri Jan 30 00:00:00 1970 PST
6001   930 |   0 | 00930              | Sat Jan 31 00:00:00 1970 PST
6002   931 |   1 | 00931              | Sun Feb 01 00:00:00 1970 PST
6003   933 | 303 | 00933_update3      | Tue Feb 03 00:00:00 1970 PST
6004   934 |   4 | 00934              | Wed Feb 04 00:00:00 1970 PST
6005   936 |   6 | 00936              | Fri Feb 06 00:00:00 1970 PST
6006   937 | 407 | 00937_update7      | Sat Feb 07 00:00:00 1970 PST
6007   938 |   8 | 00938              | Sun Feb 08 00:00:00 1970 PST
6008   939 | 509 | 00939_update9      | Mon Feb 09 00:00:00 1970 PST
6009   940 |   0 | 00940              | Tue Feb 10 00:00:00 1970 PST
6010   941 |   1 | 00941              | Wed Feb 11 00:00:00 1970 PST
6011   943 | 303 | 00943_update3      | Fri Feb 13 00:00:00 1970 PST
6012   944 |   4 | 00944              | Sat Feb 14 00:00:00 1970 PST
6013   946 |   6 | 00946              | Mon Feb 16 00:00:00 1970 PST
6014   947 | 407 | 00947_update7      | Tue Feb 17 00:00:00 1970 PST
6015   948 |   8 | 00948              | Wed Feb 18 00:00:00 1970 PST
6016   949 | 509 | 00949_update9      | Thu Feb 19 00:00:00 1970 PST
6017   950 |   0 | 00950              | Fri Feb 20 00:00:00 1970 PST
6018   951 |   1 | 00951              | Sat Feb 21 00:00:00 1970 PST
6019   953 | 303 | 00953_update3      | Mon Feb 23 00:00:00 1970 PST
6020   954 |   4 | 00954              | Tue Feb 24 00:00:00 1970 PST
6021   956 |   6 | 00956              | Thu Feb 26 00:00:00 1970 PST
6022   957 | 407 | 00957_update7      | Fri Feb 27 00:00:00 1970 PST
6023   958 |   8 | 00958              | Sat Feb 28 00:00:00 1970 PST
6024   959 | 509 | 00959_update9      | Sun Mar 01 00:00:00 1970 PST
6025   960 |   0 | 00960              | Mon Mar 02 00:00:00 1970 PST
6026   961 |   1 | 00961              | Tue Mar 03 00:00:00 1970 PST
6027   963 | 303 | 00963_update3      | Thu Mar 05 00:00:00 1970 PST
6028   964 |   4 | 00964              | Fri Mar 06 00:00:00 1970 PST
6029   966 |   6 | 00966              | Sun Mar 08 00:00:00 1970 PST
6030   967 | 407 | 00967_update7      | Mon Mar 09 00:00:00 1970 PST
6031   968 |   8 | 00968              | Tue Mar 10 00:00:00 1970 PST
6032   969 | 509 | 00969_update9      | Wed Mar 11 00:00:00 1970 PST
6033   970 |   0 | 00970              | Thu Mar 12 00:00:00 1970 PST
6034   971 |   1 | 00971              | Fri Mar 13 00:00:00 1970 PST
6035   973 | 303 | 00973_update3      | Sun Mar 15 00:00:00 1970 PST
6036   974 |   4 | 00974              | Mon Mar 16 00:00:00 1970 PST
6037   976 |   6 | 00976              | Wed Mar 18 00:00:00 1970 PST
6038   977 | 407 | 00977_update7      | Thu Mar 19 00:00:00 1970 PST
6039   978 |   8 | 00978              | Fri Mar 20 00:00:00 1970 PST
6040   979 | 509 | 00979_update9      | Sat Mar 21 00:00:00 1970 PST
6041   980 |   0 | 00980              | Sun Mar 22 00:00:00 1970 PST
6042   981 |   1 | 00981              | Mon Mar 23 00:00:00 1970 PST
6043   983 | 303 | 00983_update3      | Wed Mar 25 00:00:00 1970 PST
6044   984 |   4 | 00984              | Thu Mar 26 00:00:00 1970 PST
6045   986 |   6 | 00986              | Sat Mar 28 00:00:00 1970 PST
6046   987 | 407 | 00987_update7      | Sun Mar 29 00:00:00 1970 PST
6047   988 |   8 | 00988              | Mon Mar 30 00:00:00 1970 PST
6048   989 | 509 | 00989_update9      | Tue Mar 31 00:00:00 1970 PST
6049   990 |   0 | 00990              | Wed Apr 01 00:00:00 1970 PST
6050   991 |   1 | 00991              | Thu Apr 02 00:00:00 1970 PST
6051   993 | 303 | 00993_update3      | Sat Apr 04 00:00:00 1970 PST
6052   994 |   4 | 00994              | Sun Apr 05 00:00:00 1970 PST
6053   996 |   6 | 00996              | Tue Apr 07 00:00:00 1970 PST
6054   997 | 407 | 00997_update7      | Wed Apr 08 00:00:00 1970 PST
6055   998 |   8 | 00998              | Thu Apr 09 00:00:00 1970 PST
6056   999 | 509 | 00999_update9      | Fri Apr 10 00:00:00 1970 PST
6057  1000 |   0 | 01000              | Thu Jan 01 00:00:00 1970 PST
6058  1001 | 101 | 0000100001         | 
6059  1003 | 403 | 0000300003_update3 | 
6060  1004 | 104 | 0000400004         | 
6061  1006 | 106 | 0000600006         | 
6062  1007 | 507 | 0000700007_update7 | 
6063  1008 | 108 | 0000800008         | 
6064  1009 | 609 | 0000900009_update9 | 
6065  1010 | 100 | 0001000010         | 
6066  1011 | 101 | 0001100011         | 
6067  1013 | 403 | 0001300013_update3 | 
6068  1014 | 104 | 0001400014         | 
6069  1016 | 106 | 0001600016         | 
6070  1017 | 507 | 0001700017_update7 | 
6071  1018 | 108 | 0001800018         | 
6072  1019 | 609 | 0001900019_update9 | 
6073  1020 | 100 | 0002000020         | 
6074  1101 | 201 | aaa                | 
6075  1103 | 503 | ccc_update3        | 
6076  1104 | 204 | ddd                | 
6077 (819 rows)
6079 EXPLAIN (verbose, costs off)
6080 INSERT INTO ft2 (c1,c2,c3) VALUES (1200,999,'foo') RETURNING tableoid::regclass;
6081                                                                                            QUERY PLAN                                                                                            
6082 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6083  Insert on public.ft2
6084    Output: (ft2.tableoid)::regclass
6085    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)
6086    Batch Size: 1
6087    ->  Result
6088          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
6089 (6 rows)
6091 INSERT INTO ft2 (c1,c2,c3) VALUES (1200,999,'foo') RETURNING tableoid::regclass;
6092  tableoid 
6093 ----------
6094  ft2
6095 (1 row)
6097 EXPLAIN (verbose, costs off)
6098 UPDATE ft2 SET c3 = 'bar' WHERE c1 = 1200 RETURNING tableoid::regclass;             -- can be pushed down
6099                                      QUERY PLAN                                     
6100 ------------------------------------------------------------------------------------
6101  Update on public.ft2
6102    Output: (tableoid)::regclass
6103    ->  Foreign Update on public.ft2
6104          Remote SQL: UPDATE "S 1"."T 1" SET c3 = 'bar'::text WHERE (("C 1" = 1200))
6105 (4 rows)
6107 UPDATE ft2 SET c3 = 'bar' WHERE c1 = 1200 RETURNING tableoid::regclass;
6108  tableoid 
6109 ----------
6110  ft2
6111 (1 row)
6113 EXPLAIN (verbose, costs off)
6114 DELETE FROM ft2 WHERE c1 = 1200 RETURNING tableoid::regclass;                       -- can be pushed down
6115                              QUERY PLAN                             
6116 --------------------------------------------------------------------
6117  Delete on public.ft2
6118    Output: (tableoid)::regclass
6119    ->  Foreign Delete on public.ft2
6120          Remote SQL: DELETE FROM "S 1"."T 1" WHERE (("C 1" = 1200))
6121 (4 rows)
6123 DELETE FROM ft2 WHERE c1 = 1200 RETURNING tableoid::regclass;
6124  tableoid 
6125 ----------
6126  ft2
6127 (1 row)
6129 -- Test UPDATE/DELETE with RETURNING on a three-table join
6130 INSERT INTO ft2 (c1,c2,c3)
6131   SELECT id, id - 1200, to_char(id, 'FM00000') FROM generate_series(1201, 1300) id;
6132 EXPLAIN (verbose, costs off)
6133 UPDATE ft2 SET c3 = 'foo'
6134   FROM ft4 INNER JOIN ft5 ON (ft4.c1 = ft5.c1)
6135   WHERE ft2.c1 > 1200 AND ft2.c2 = ft4.c1
6136   RETURNING ft2, ft2.*, ft4, ft4.*;       -- can be pushed down
6137                                                                                                                                                                           QUERY PLAN                                                                                                                                                                           
6138 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6139  Update on public.ft2
6140    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
6141    ->  Foreign Update
6142          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
6143 (4 rows)
6145 UPDATE ft2 SET c3 = 'foo'
6146   FROM ft4 INNER JOIN ft5 ON (ft4.c1 = ft5.c1)
6147   WHERE ft2.c1 > 1200 AND ft2.c2 = ft4.c1
6148   RETURNING ft2, ft2.*, ft4, ft4.*;
6149               ft2               |  c1  | c2 | c3  | c4 | c5 | c6 |     c7     | c8 |      ft4       | c1 | c2 |   c3   
6150 --------------------------------+------+----+-----+----+----+----+------------+----+----------------+----+----+--------
6151  (1206,6,foo,,,,"ft2       ",)  | 1206 |  6 | foo |    |    |    | ft2        |    | (6,7,AAA006)   |  6 |  7 | AAA006
6152  (1212,12,foo,,,,"ft2       ",) | 1212 | 12 | foo |    |    |    | ft2        |    | (12,13,AAA012) | 12 | 13 | AAA012
6153  (1218,18,foo,,,,"ft2       ",) | 1218 | 18 | foo |    |    |    | ft2        |    | (18,19,AAA018) | 18 | 19 | AAA018
6154  (1224,24,foo,,,,"ft2       ",) | 1224 | 24 | foo |    |    |    | ft2        |    | (24,25,AAA024) | 24 | 25 | AAA024
6155  (1230,30,foo,,,,"ft2       ",) | 1230 | 30 | foo |    |    |    | ft2        |    | (30,31,AAA030) | 30 | 31 | AAA030
6156  (1236,36,foo,,,,"ft2       ",) | 1236 | 36 | foo |    |    |    | ft2        |    | (36,37,AAA036) | 36 | 37 | AAA036
6157  (1242,42,foo,,,,"ft2       ",) | 1242 | 42 | foo |    |    |    | ft2        |    | (42,43,AAA042) | 42 | 43 | AAA042
6158  (1248,48,foo,,,,"ft2       ",) | 1248 | 48 | foo |    |    |    | ft2        |    | (48,49,AAA048) | 48 | 49 | AAA048
6159  (1254,54,foo,,,,"ft2       ",) | 1254 | 54 | foo |    |    |    | ft2        |    | (54,55,AAA054) | 54 | 55 | AAA054
6160  (1260,60,foo,,,,"ft2       ",) | 1260 | 60 | foo |    |    |    | ft2        |    | (60,61,AAA060) | 60 | 61 | AAA060
6161  (1266,66,foo,,,,"ft2       ",) | 1266 | 66 | foo |    |    |    | ft2        |    | (66,67,AAA066) | 66 | 67 | AAA066
6162  (1272,72,foo,,,,"ft2       ",) | 1272 | 72 | foo |    |    |    | ft2        |    | (72,73,AAA072) | 72 | 73 | AAA072
6163  (1278,78,foo,,,,"ft2       ",) | 1278 | 78 | foo |    |    |    | ft2        |    | (78,79,AAA078) | 78 | 79 | AAA078
6164  (1284,84,foo,,,,"ft2       ",) | 1284 | 84 | foo |    |    |    | ft2        |    | (84,85,AAA084) | 84 | 85 | AAA084
6165  (1290,90,foo,,,,"ft2       ",) | 1290 | 90 | foo |    |    |    | ft2        |    | (90,91,AAA090) | 90 | 91 | AAA090
6166  (1296,96,foo,,,,"ft2       ",) | 1296 | 96 | foo |    |    |    | ft2        |    | (96,97,AAA096) | 96 | 97 | AAA096
6167 (16 rows)
6169 EXPLAIN (verbose, costs off)
6170 DELETE FROM ft2
6171   USING ft4 LEFT JOIN ft5 ON (ft4.c1 = ft5.c1)
6172   WHERE ft2.c1 > 1200 AND ft2.c1 % 10 = 0 AND ft2.c2 = ft4.c1
6173   RETURNING 100;                          -- can be pushed down
6174                                                                                             QUERY PLAN                                                                                             
6175 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6176  Delete on public.ft2
6177    Output: 100
6178    ->  Foreign Delete
6179          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))
6180 (4 rows)
6182 DELETE FROM ft2
6183   USING ft4 LEFT JOIN ft5 ON (ft4.c1 = ft5.c1)
6184   WHERE ft2.c1 > 1200 AND ft2.c1 % 10 = 0 AND ft2.c2 = ft4.c1
6185   RETURNING 100;
6186  ?column? 
6187 ----------
6188       100
6189       100
6190       100
6191       100
6192       100
6193       100
6194       100
6195       100
6196       100
6197       100
6198 (10 rows)
6200 DELETE FROM ft2 WHERE ft2.c1 > 1200;
6201 -- Test UPDATE with a MULTIEXPR sub-select
6202 -- (maybe someday this'll be remotely executable, but not today)
6203 EXPLAIN (verbose, costs off)
6204 UPDATE ft2 AS target SET (c2, c7) = (
6205     SELECT c2 * 10, c7
6206         FROM ft2 AS src
6207         WHERE target.c1 = src.c1
6208 ) WHERE c1 > 1100;
6209                                                       QUERY PLAN                                                       
6210 -----------------------------------------------------------------------------------------------------------------------
6211  Update on public.ft2 target
6212    Remote SQL: UPDATE "S 1"."T 1" SET c2 = $2, c7 = $3 WHERE ctid = $1
6213    ->  Foreign Scan on public.ft2 target
6214          Output: (SubPlan 1).col1, (SubPlan 1).col2, (rescan SubPlan 1), target.ctid, target.*
6215          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8, ctid FROM "S 1"."T 1" WHERE (("C 1" > 1100)) FOR UPDATE
6216          SubPlan 1
6217            ->  Foreign Scan on public.ft2 src
6218                  Output: (src.c2 * 10), src.c7
6219                  Remote SQL: SELECT c2, c7 FROM "S 1"."T 1" WHERE (($1::integer = "C 1"))
6220 (9 rows)
6222 UPDATE ft2 AS target SET (c2, c7) = (
6223     SELECT c2 * 10, c7
6224         FROM ft2 AS src
6225         WHERE target.c1 = src.c1
6226 ) WHERE c1 > 1100;
6227 UPDATE ft2 AS target SET (c2) = (
6228     SELECT c2 / 10
6229         FROM ft2 AS src
6230         WHERE target.c1 = src.c1
6231 ) WHERE c1 > 1100;
6232 -- Test UPDATE involving a join that can be pushed down,
6233 -- but a SET clause that can't be
6234 EXPLAIN (VERBOSE, COSTS OFF)
6235 UPDATE ft2 d SET c2 = CASE WHEN random() >= 0 THEN d.c2 ELSE 0 END
6236   FROM ft2 AS t WHERE d.c1 = t.c1 AND d.c1 > 1000;
6237                                                                                                                                                                                        QUERY PLAN                                                                                                                                                                                        
6238 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6239  Update on public.ft2 d
6240    Remote SQL: UPDATE "S 1"."T 1" SET c2 = $2 WHERE ctid = $1
6241    ->  Foreign Scan
6242          Output: CASE WHEN (random() >= '0'::double precision) THEN d.c2 ELSE 0 END, d.ctid, d.*, t.*
6243          Relations: (public.ft2 d) INNER JOIN (public.ft2 t)
6244          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
6245          ->  Hash Join
6246                Output: d.c2, d.ctid, d.*, t.*
6247                Hash Cond: (d.c1 = t.c1)
6248                ->  Foreign Scan on public.ft2 d
6249                      Output: d.c2, d.ctid, d.*, d.c1
6250                      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
6251                ->  Hash
6252                      Output: t.*, t.c1
6253                      ->  Foreign Scan on public.ft2 t
6254                            Output: t.*, t.c1
6255                            Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
6256 (17 rows)
6258 UPDATE ft2 d SET c2 = CASE WHEN random() >= 0 THEN d.c2 ELSE 0 END
6259   FROM ft2 AS t WHERE d.c1 = t.c1 AND d.c1 > 1000;
6260 -- Test UPDATE/DELETE with WHERE or JOIN/ON conditions containing
6261 -- user-defined operators/functions
6262 ALTER SERVER loopback OPTIONS (DROP extensions);
6263 INSERT INTO ft2 (c1,c2,c3)
6264   SELECT id, id % 10, to_char(id, 'FM00000') FROM generate_series(2001, 2010) id;
6265 EXPLAIN (verbose, costs off)
6266 UPDATE ft2 SET c3 = 'bar' WHERE postgres_fdw_abs(c1) > 2000 RETURNING *;            -- can't be pushed down
6267                                                 QUERY PLAN                                                
6268 ----------------------------------------------------------------------------------------------------------
6269  Update on public.ft2
6270    Output: c1, c2, c3, c4, c5, c6, c7, c8
6271    Remote SQL: UPDATE "S 1"."T 1" SET c3 = $2 WHERE ctid = $1 RETURNING "C 1", c2, c3, c4, c5, c6, c7, c8
6272    ->  Foreign Scan on public.ft2
6273          Output: 'bar'::text, ctid, ft2.*
6274          Filter: (postgres_fdw_abs(ft2.c1) > 2000)
6275          Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8, ctid FROM "S 1"."T 1" FOR UPDATE
6276 (7 rows)
6278 UPDATE ft2 SET c3 = 'bar' WHERE postgres_fdw_abs(c1) > 2000 RETURNING *;
6279   c1  | c2 | c3  | c4 | c5 | c6 |     c7     | c8 
6280 ------+----+-----+----+----+----+------------+----
6281  2001 |  1 | bar |    |    |    | ft2        | 
6282  2002 |  2 | bar |    |    |    | ft2        | 
6283  2003 |  3 | bar |    |    |    | ft2        | 
6284  2004 |  4 | bar |    |    |    | ft2        | 
6285  2005 |  5 | bar |    |    |    | ft2        | 
6286  2006 |  6 | bar |    |    |    | ft2        | 
6287  2007 |  7 | bar |    |    |    | ft2        | 
6288  2008 |  8 | bar |    |    |    | ft2        | 
6289  2009 |  9 | bar |    |    |    | ft2        | 
6290  2010 |  0 | bar |    |    |    | ft2        | 
6291 (10 rows)
6293 EXPLAIN (verbose, costs off)
6294 UPDATE ft2 SET c3 = 'baz'
6295   FROM ft4 INNER JOIN ft5 ON (ft4.c1 = ft5.c1)
6296   WHERE ft2.c1 > 2000 AND ft2.c2 === ft4.c1
6297   RETURNING ft2.*, ft4.*, ft5.*;                                                    -- can't be pushed down
6298                                                                                                                                           QUERY PLAN                                                                                                                                          
6299 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6300  Update on public.ft2
6301    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
6302    Remote SQL: UPDATE "S 1"."T 1" SET c3 = $2 WHERE ctid = $1 RETURNING "C 1", c2, c3, c4, c5, c6, c7, c8
6303    ->  Nested Loop
6304          Output: 'baz'::text, ft2.ctid, ft2.*, ft4.*, ft5.*, ft4.c1, ft4.c2, ft4.c3, ft5.c1, ft5.c2, ft5.c3
6305          Join Filter: (ft2.c2 === ft4.c1)
6306          ->  Foreign Scan on public.ft2
6307                Output: ft2.ctid, ft2.*, ft2.c2
6308                Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8, ctid FROM "S 1"."T 1" WHERE (("C 1" > 2000)) FOR UPDATE
6309          ->  Foreign Scan
6310                Output: ft4.*, ft4.c1, ft4.c2, ft4.c3, ft5.*, ft5.c1, ft5.c2, ft5.c3
6311                Relations: (public.ft4) INNER JOIN (public.ft5)
6312                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))))
6313                ->  Hash Join
6314                      Output: ft4.*, ft4.c1, ft4.c2, ft4.c3, ft5.*, ft5.c1, ft5.c2, ft5.c3
6315                      Hash Cond: (ft4.c1 = ft5.c1)
6316                      ->  Foreign Scan on public.ft4
6317                            Output: ft4.*, ft4.c1, ft4.c2, ft4.c3
6318                            Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3"
6319                      ->  Hash
6320                            Output: ft5.*, ft5.c1, ft5.c2, ft5.c3
6321                            ->  Foreign Scan on public.ft5
6322                                  Output: ft5.*, ft5.c1, ft5.c2, ft5.c3
6323                                  Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 4"
6324 (24 rows)
6326 UPDATE ft2 SET c3 = 'baz'
6327   FROM ft4 INNER JOIN ft5 ON (ft4.c1 = ft5.c1)
6328   WHERE ft2.c1 > 2000 AND ft2.c2 === ft4.c1
6329   RETURNING ft2.*, ft4.*, ft5.*;
6330   c1  | c2 | c3  | c4 | c5 | c6 |     c7     | c8 | c1 | c2 |   c3   | c1 | c2 |   c3   
6331 ------+----+-----+----+----+----+------------+----+----+----+--------+----+----+--------
6332  2006 |  6 | baz |    |    |    | ft2        |    |  6 |  7 | AAA006 |  6 |  7 | AAA006
6333 (1 row)
6335 EXPLAIN (verbose, costs off)
6336 DELETE FROM ft2
6337   USING ft4 INNER JOIN ft5 ON (ft4.c1 === ft5.c1)
6338   WHERE ft2.c1 > 2000 AND ft2.c2 = ft4.c1
6339   RETURNING ft2.c1, ft2.c2, ft2.c3;       -- can't be pushed down
6340                                                                                                                                                                      QUERY PLAN                                                                                                                                                                     
6341 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6342  Delete on public.ft2
6343    Output: ft2.c1, ft2.c2, ft2.c3
6344    Remote SQL: DELETE FROM "S 1"."T 1" WHERE ctid = $1 RETURNING "C 1", c2, c3
6345    ->  Foreign Scan
6346          Output: ft2.ctid, ft4.*, ft5.*
6347          Filter: (ft4.c1 === ft5.c1)
6348          Relations: ((public.ft2) INNER JOIN (public.ft4)) INNER JOIN (public.ft5)
6349          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
6350          ->  Nested Loop
6351                Output: ft2.ctid, ft4.*, ft5.*, ft4.c1, ft5.c1
6352                ->  Nested Loop
6353                      Output: ft2.ctid, ft4.*, ft4.c1
6354                      Join Filter: (ft2.c2 = ft4.c1)
6355                      ->  Foreign Scan on public.ft2
6356                            Output: ft2.ctid, ft2.c2
6357                            Remote SQL: SELECT c2, ctid FROM "S 1"."T 1" WHERE (("C 1" > 2000)) FOR UPDATE
6358                      ->  Foreign Scan on public.ft4
6359                            Output: ft4.*, ft4.c1
6360                            Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3"
6361                ->  Foreign Scan on public.ft5
6362                      Output: ft5.*, ft5.c1
6363                      Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 4"
6364 (22 rows)
6366 DELETE FROM ft2
6367   USING ft4 INNER JOIN ft5 ON (ft4.c1 === ft5.c1)
6368   WHERE ft2.c1 > 2000 AND ft2.c2 = ft4.c1
6369   RETURNING ft2.c1, ft2.c2, ft2.c3;
6370   c1  | c2 | c3  
6371 ------+----+-----
6372  2006 |  6 | baz
6373 (1 row)
6375 DELETE FROM ft2 WHERE ft2.c1 > 2000;
6376 ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
6377 -- Test that trigger on remote table works as expected
6378 CREATE OR REPLACE FUNCTION "S 1".F_BRTRIG() RETURNS trigger AS $$
6379 BEGIN
6380     NEW.c3 = NEW.c3 || '_trig_update';
6381     RETURN NEW;
6382 END;
6383 $$ LANGUAGE plpgsql;
6384 CREATE TRIGGER t1_br_insert BEFORE INSERT OR UPDATE
6385     ON "S 1"."T 1" FOR EACH ROW EXECUTE PROCEDURE "S 1".F_BRTRIG();
6386 INSERT INTO ft2 (c1,c2,c3) VALUES (1208, 818, 'fff') RETURNING *;
6387   c1  | c2  |       c3        | c4 | c5 | c6 |     c7     | c8 
6388 ------+-----+-----------------+----+----+----+------------+----
6389  1208 | 818 | fff_trig_update |    |    |    | ft2        | 
6390 (1 row)
6392 INSERT INTO ft2 (c1,c2,c3,c6) VALUES (1218, 818, 'ggg', '(--;') RETURNING *;
6393   c1  | c2  |       c3        | c4 | c5 |  c6  |     c7     | c8 
6394 ------+-----+-----------------+----+----+------+------------+----
6395  1218 | 818 | ggg_trig_update |    |    | (--; | ft2        | 
6396 (1 row)
6398 UPDATE ft2 SET c2 = c2 + 600 WHERE c1 % 10 = 8 AND c1 < 1200 RETURNING *;
6399   c1  | c2  |           c3           |              c4              |            c5            | c6 |     c7     | c8  
6400 ------+-----+------------------------+------------------------------+--------------------------+----+------------+-----
6401     8 | 608 | 00008_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6402    18 | 608 | 00018_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6403    28 | 608 | 00028_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6404    38 | 608 | 00038_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6405    48 | 608 | 00048_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6406    58 | 608 | 00058_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6407    68 | 608 | 00068_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6408    78 | 608 | 00078_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6409    88 | 608 | 00088_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6410    98 | 608 | 00098_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6411   108 | 608 | 00108_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6412   118 | 608 | 00118_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6413   128 | 608 | 00128_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6414   138 | 608 | 00138_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6415   148 | 608 | 00148_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6416   158 | 608 | 00158_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6417   168 | 608 | 00168_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6418   178 | 608 | 00178_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6419   188 | 608 | 00188_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6420   198 | 608 | 00198_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6421   208 | 608 | 00208_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6422   218 | 608 | 00218_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6423   228 | 608 | 00228_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6424   238 | 608 | 00238_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6425   248 | 608 | 00248_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6426   258 | 608 | 00258_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6427   268 | 608 | 00268_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6428   278 | 608 | 00278_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6429   288 | 608 | 00288_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6430   298 | 608 | 00298_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6431   308 | 608 | 00308_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6432   318 | 608 | 00318_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6433   328 | 608 | 00328_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6434   338 | 608 | 00338_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6435   348 | 608 | 00348_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6436   358 | 608 | 00358_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6437   368 | 608 | 00368_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6438   378 | 608 | 00378_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6439   388 | 608 | 00388_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6440   398 | 608 | 00398_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6441   408 | 608 | 00408_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6442   418 | 608 | 00418_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6443   428 | 608 | 00428_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6444   438 | 608 | 00438_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6445   448 | 608 | 00448_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6446   458 | 608 | 00458_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6447   468 | 608 | 00468_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6448   478 | 608 | 00478_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6449   488 | 608 | 00488_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6450   498 | 608 | 00498_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6451   508 | 608 | 00508_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6452   518 | 608 | 00518_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6453   528 | 608 | 00528_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6454   538 | 608 | 00538_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6455   548 | 608 | 00548_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6456   558 | 608 | 00558_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6457   568 | 608 | 00568_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6458   578 | 608 | 00578_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6459   588 | 608 | 00588_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6460   598 | 608 | 00598_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6461   608 | 608 | 00608_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6462   618 | 608 | 00618_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6463   628 | 608 | 00628_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6464   638 | 608 | 00638_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6465   648 | 608 | 00648_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6466   658 | 608 | 00658_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6467   668 | 608 | 00668_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6468   678 | 608 | 00678_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6469   688 | 608 | 00688_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6470   698 | 608 | 00698_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6471   708 | 608 | 00708_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6472   718 | 608 | 00718_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6473   728 | 608 | 00728_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6474   738 | 608 | 00738_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6475   748 | 608 | 00748_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6476   758 | 608 | 00758_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6477   768 | 608 | 00768_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6478   778 | 608 | 00778_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6479   788 | 608 | 00788_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6480   798 | 608 | 00798_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6481   808 | 608 | 00808_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6482   818 | 608 | 00818_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6483   828 | 608 | 00828_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6484   838 | 608 | 00838_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6485   848 | 608 | 00848_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6486   858 | 608 | 00858_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6487   868 | 608 | 00868_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6488   878 | 608 | 00878_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6489   888 | 608 | 00888_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6490   898 | 608 | 00898_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6491   908 | 608 | 00908_trig_update      | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8  | 8          | foo
6492   918 | 608 | 00918_trig_update      | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8  | 8          | foo
6493   928 | 608 | 00928_trig_update      | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8  | 8          | foo
6494   938 | 608 | 00938_trig_update      | Sun Feb 08 00:00:00 1970 PST | Sun Feb 08 00:00:00 1970 | 8  | 8          | foo
6495   948 | 608 | 00948_trig_update      | Wed Feb 18 00:00:00 1970 PST | Wed Feb 18 00:00:00 1970 | 8  | 8          | foo
6496   958 | 608 | 00958_trig_update      | Sat Feb 28 00:00:00 1970 PST | Sat Feb 28 00:00:00 1970 | 8  | 8          | foo
6497   968 | 608 | 00968_trig_update      | Tue Mar 10 00:00:00 1970 PST | Tue Mar 10 00:00:00 1970 | 8  | 8          | foo
6498   978 | 608 | 00978_trig_update      | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8  | 8          | foo
6499   988 | 608 | 00988_trig_update      | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8  | 8          | foo
6500   998 | 608 | 00998_trig_update      | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8  | 8          | foo
6501  1008 | 708 | 0000800008_trig_update |                              |                          |    | ft2        | 
6502  1018 | 708 | 0001800018_trig_update |                              |                          |    | ft2        | 
6503 (102 rows)
6505 -- Test errors thrown on remote side during update
6506 ALTER TABLE "S 1"."T 1" ADD CONSTRAINT c2positive CHECK (c2 >= 0);
6507 INSERT INTO ft1(c1, c2) VALUES(11, 12);  -- duplicate key
6508 ERROR:  duplicate key value violates unique constraint "t1_pkey"
6509 DETAIL:  Key ("C 1")=(11) already exists.
6510 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)
6511 INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT DO NOTHING; -- works
6512 INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT (c1, c2) DO NOTHING; -- unsupported
6513 ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification
6514 INSERT INTO ft1(c1, c2) VALUES(11, 12) ON CONFLICT (c1, c2) DO UPDATE SET c3 = 'ffg'; -- unsupported
6515 ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification
6516 INSERT INTO ft1(c1, c2) VALUES(1111, -2);  -- c2positive
6517 ERROR:  new row for relation "T 1" violates check constraint "c2positive"
6518 DETAIL:  Failing row contains (1111, -2, null, null, null, null, ft1       , null).
6519 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)
6520 UPDATE ft1 SET c2 = -c2 WHERE c1 = 1;  -- c2positive
6521 ERROR:  new row for relation "T 1" violates check constraint "c2positive"
6522 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).
6523 CONTEXT:  remote SQL command: UPDATE "S 1"."T 1" SET c2 = (- c2) WHERE (("C 1" = 1))
6524 -- Test savepoint/rollback behavior
6525 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6526  c2  | count 
6527 -----+-------
6528    0 |   100
6529    1 |   100
6530    4 |   100
6531    6 |   100
6532  100 |     2
6533  101 |     2
6534  104 |     2
6535  106 |     2
6536  201 |     1
6537  204 |     1
6538  303 |   100
6539  403 |     2
6540  407 |   100
6541 (13 rows)
6543 select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
6544  c2  | count 
6545 -----+-------
6546    0 |   100
6547    1 |   100
6548    4 |   100
6549    6 |   100
6550  100 |     2
6551  101 |     2
6552  104 |     2
6553  106 |     2
6554  201 |     1
6555  204 |     1
6556  303 |   100
6557  403 |     2
6558  407 |   100
6559 (13 rows)
6561 begin;
6562 update ft2 set c2 = 42 where c2 = 0;
6563 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6564  c2  | count 
6565 -----+-------
6566    1 |   100
6567    4 |   100
6568    6 |   100
6569   42 |   100
6570  100 |     2
6571  101 |     2
6572  104 |     2
6573  106 |     2
6574  201 |     1
6575  204 |     1
6576  303 |   100
6577  403 |     2
6578  407 |   100
6579 (13 rows)
6581 savepoint s1;
6582 update ft2 set c2 = 44 where c2 = 4;
6583 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6584  c2  | count 
6585 -----+-------
6586    1 |   100
6587    6 |   100
6588   42 |   100
6589   44 |   100
6590  100 |     2
6591  101 |     2
6592  104 |     2
6593  106 |     2
6594  201 |     1
6595  204 |     1
6596  303 |   100
6597  403 |     2
6598  407 |   100
6599 (13 rows)
6601 release savepoint s1;
6602 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6603  c2  | count 
6604 -----+-------
6605    1 |   100
6606    6 |   100
6607   42 |   100
6608   44 |   100
6609  100 |     2
6610  101 |     2
6611  104 |     2
6612  106 |     2
6613  201 |     1
6614  204 |     1
6615  303 |   100
6616  403 |     2
6617  407 |   100
6618 (13 rows)
6620 savepoint s2;
6621 update ft2 set c2 = 46 where c2 = 6;
6622 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6623  c2  | count 
6624 -----+-------
6625    1 |   100
6626   42 |   100
6627   44 |   100
6628   46 |   100
6629  100 |     2
6630  101 |     2
6631  104 |     2
6632  106 |     2
6633  201 |     1
6634  204 |     1
6635  303 |   100
6636  403 |     2
6637  407 |   100
6638 (13 rows)
6640 rollback to savepoint s2;
6641 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6642  c2  | count 
6643 -----+-------
6644    1 |   100
6645    6 |   100
6646   42 |   100
6647   44 |   100
6648  100 |     2
6649  101 |     2
6650  104 |     2
6651  106 |     2
6652  201 |     1
6653  204 |     1
6654  303 |   100
6655  403 |     2
6656  407 |   100
6657 (13 rows)
6659 release savepoint s2;
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 savepoint s3;
6679 update ft2 set c2 = -2 where c2 = 42 and c1 = 10; -- fail on remote side
6680 ERROR:  new row for relation "T 1" violates check constraint "c2positive"
6681 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).
6682 CONTEXT:  remote SQL command: UPDATE "S 1"."T 1" SET c2 = (-2) WHERE ((c2 = 42)) AND (("C 1" = 10))
6683 rollback to savepoint s3;
6684 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6685  c2  | count 
6686 -----+-------
6687    1 |   100
6688    6 |   100
6689   42 |   100
6690   44 |   100
6691  100 |     2
6692  101 |     2
6693  104 |     2
6694  106 |     2
6695  201 |     1
6696  204 |     1
6697  303 |   100
6698  403 |     2
6699  407 |   100
6700 (13 rows)
6702 release savepoint s3;
6703 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6704  c2  | count 
6705 -----+-------
6706    1 |   100
6707    6 |   100
6708   42 |   100
6709   44 |   100
6710  100 |     2
6711  101 |     2
6712  104 |     2
6713  106 |     2
6714  201 |     1
6715  204 |     1
6716  303 |   100
6717  403 |     2
6718  407 |   100
6719 (13 rows)
6721 -- none of the above is committed yet remotely
6722 select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
6723  c2  | count 
6724 -----+-------
6725    0 |   100
6726    1 |   100
6727    4 |   100
6728    6 |   100
6729  100 |     2
6730  101 |     2
6731  104 |     2
6732  106 |     2
6733  201 |     1
6734  204 |     1
6735  303 |   100
6736  403 |     2
6737  407 |   100
6738 (13 rows)
6740 commit;
6741 select c2, count(*) from ft2 where c2 < 500 group by 1 order by 1;
6742  c2  | count 
6743 -----+-------
6744    1 |   100
6745    6 |   100
6746   42 |   100
6747   44 |   100
6748  100 |     2
6749  101 |     2
6750  104 |     2
6751  106 |     2
6752  201 |     1
6753  204 |     1
6754  303 |   100
6755  403 |     2
6756  407 |   100
6757 (13 rows)
6759 select c2, count(*) from "S 1"."T 1" where c2 < 500 group by 1 order by 1;
6760  c2  | count 
6761 -----+-------
6762    1 |   100
6763    6 |   100
6764   42 |   100
6765   44 |   100
6766  100 |     2
6767  101 |     2
6768  104 |     2
6769  106 |     2
6770  201 |     1
6771  204 |     1
6772  303 |   100
6773  403 |     2
6774  407 |   100
6775 (13 rows)
6777 VACUUM ANALYZE "S 1"."T 1";
6778 -- Above DMLs add data with c6 as NULL in ft1, so test ORDER BY NULLS LAST and NULLs
6779 -- FIRST behavior here.
6780 -- ORDER BY DESC NULLS LAST options
6781 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 ORDER BY c6 DESC NULLS LAST, c1 OFFSET 795 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 LAST, "C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 795::bigint
6787 (3 rows)
6789 SELECT * FROM ft1 ORDER BY c6 DESC NULLS LAST, c1 OFFSET 795  LIMIT 10;
6790   c1  | c2  |         c3         |              c4              |            c5            |  c6  |     c7     | c8  
6791 ------+-----+--------------------+------------------------------+--------------------------+------+------------+-----
6792   960 |  42 | 00960_trig_update  | Mon Mar 02 00:00:00 1970 PST | Mon Mar 02 00:00:00 1970 | 0    | 0          | foo
6793   970 |  42 | 00970_trig_update  | Thu Mar 12 00:00:00 1970 PST | Thu Mar 12 00:00:00 1970 | 0    | 0          | foo
6794   980 |  42 | 00980_trig_update  | Sun Mar 22 00:00:00 1970 PST | Sun Mar 22 00:00:00 1970 | 0    | 0          | foo
6795   990 |  42 | 00990_trig_update  | Wed Apr 01 00:00:00 1970 PST | Wed Apr 01 00:00:00 1970 | 0    | 0          | foo
6796  1000 |  42 | 01000_trig_update  | Thu Jan 01 00:00:00 1970 PST | Thu Jan 01 00:00:00 1970 | 0    | 0          | foo
6797  1218 | 818 | ggg_trig_update    |                              |                          | (--; | ft2        | 
6798  1001 | 101 | 0000100001         |                              |                          |      | ft2        | 
6799  1003 | 403 | 0000300003_update3 |                              |                          |      | ft2        | 
6800  1004 | 104 | 0000400004         |                              |                          |      | ft2        | 
6801  1006 | 106 | 0000600006         |                              |                          |      | ft2        | 
6802 (10 rows)
6804 -- ORDER BY DESC NULLS FIRST options
6805 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 ORDER BY c6 DESC 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 DESC NULLS FIRST, "C 1" ASC NULLS LAST LIMIT 10::bigint OFFSET 15::bigint
6811 (3 rows)
6813 SELECT * FROM ft1 ORDER BY c6 DESC 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     9 | 509 | 00009_update9   | Sat Jan 10 00:00:00 1970 PST | Sat Jan 10 00:00:00 1970 | 9  | ft2        | foo
6822    19 | 509 | 00019_update9   | Tue Jan 20 00:00:00 1970 PST | Tue Jan 20 00:00:00 1970 | 9  | ft2        | foo
6823    29 | 509 | 00029_update9   | Fri Jan 30 00:00:00 1970 PST | Fri Jan 30 00:00:00 1970 | 9  | ft2        | foo
6824    39 | 509 | 00039_update9   | Mon Feb 09 00:00:00 1970 PST | Mon Feb 09 00:00:00 1970 | 9  | ft2        | foo
6825    49 | 509 | 00049_update9   | Thu Feb 19 00:00:00 1970 PST | Thu Feb 19 00:00:00 1970 | 9  | ft2        | foo
6826 (10 rows)
6828 -- ORDER BY ASC NULLS FIRST options
6829 EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft1 ORDER BY c6 ASC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
6830                                                                           QUERY PLAN                                                                          
6831 --------------------------------------------------------------------------------------------------------------------------------------------------------------
6832  Foreign Scan on public.ft1
6833    Output: c1, c2, c3, c4, c5, c6, c7, c8
6834    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
6835 (3 rows)
6837 SELECT * FROM ft1 ORDER BY c6 ASC NULLS FIRST, c1 OFFSET 15 LIMIT 10;
6838   c1  | c2  |        c3         |              c4              |            c5            |  c6  |     c7     | c8  
6839 ------+-----+-------------------+------------------------------+--------------------------+------+------------+-----
6840  1020 | 100 | 0002000020        |                              |                          |      | ft2        | 
6841  1101 | 201 | aaa               |                              |                          |      | ft2        | 
6842  1103 | 503 | ccc_update3       |                              |                          |      | ft2        | 
6843  1104 | 204 | ddd               |                              |                          |      | ft2        | 
6844  1208 | 818 | fff_trig_update   |                              |                          |      | ft2        | 
6845  1218 | 818 | ggg_trig_update   |                              |                          | (--; | ft2        | 
6846    10 |  42 | 00010_trig_update | Sun Jan 11 00:00:00 1970 PST | Sun Jan 11 00:00:00 1970 | 0    | 0          | foo
6847    20 |  42 | 00020_trig_update | Wed Jan 21 00:00:00 1970 PST | Wed Jan 21 00:00:00 1970 | 0    | 0          | foo
6848    30 |  42 | 00030_trig_update | Sat Jan 31 00:00:00 1970 PST | Sat Jan 31 00:00:00 1970 | 0    | 0          | foo
6849    40 |  42 | 00040_trig_update | Tue Feb 10 00:00:00 1970 PST | Tue Feb 10 00:00:00 1970 | 0    | 0          | foo
6850 (10 rows)
6852 -- ===================================================================
6853 -- test check constraints
6854 -- ===================================================================
6855 -- Consistent check constraints provide consistent results
6856 ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c2positive CHECK (c2 >= 0);
6857 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 < 0;
6858                            QUERY PLAN                            
6859 -----------------------------------------------------------------
6860  Foreign Scan
6861    Output: (count(*))
6862    Relations: Aggregate on (public.ft1)
6863    Remote SQL: SELECT count(*) FROM "S 1"."T 1" WHERE ((c2 < 0))
6864 (4 rows)
6866 SELECT count(*) FROM ft1 WHERE c2 < 0;
6867  count 
6868 -------
6869      0
6870 (1 row)
6872 SET constraint_exclusion = 'on';
6873 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 < 0;
6874            QUERY PLAN           
6875 --------------------------------
6876  Aggregate
6877    Output: count(*)
6878    ->  Result
6879          One-Time Filter: false
6880 (4 rows)
6882 SELECT count(*) FROM ft1 WHERE c2 < 0;
6883  count 
6884 -------
6885      0
6886 (1 row)
6888 RESET constraint_exclusion;
6889 -- check constraint is enforced on the remote side, not locally
6890 INSERT INTO ft1(c1, c2) VALUES(1111, -2);  -- c2positive
6891 ERROR:  new row for relation "T 1" violates check constraint "c2positive"
6892 DETAIL:  Failing row contains (1111, -2, null, null, null, null, ft1       , null).
6893 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)
6894 UPDATE ft1 SET c2 = -c2 WHERE c1 = 1;  -- c2positive
6895 ERROR:  new row for relation "T 1" violates check constraint "c2positive"
6896 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).
6897 CONTEXT:  remote SQL command: UPDATE "S 1"."T 1" SET c2 = (- c2) WHERE (("C 1" = 1))
6898 ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2positive;
6899 -- But inconsistent check constraints provide inconsistent results
6900 ALTER FOREIGN TABLE ft1 ADD CONSTRAINT ft1_c2negative CHECK (c2 < 0);
6901 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 >= 0;
6902                             QUERY PLAN                            
6903 ------------------------------------------------------------------
6904  Foreign Scan
6905    Output: (count(*))
6906    Relations: Aggregate on (public.ft1)
6907    Remote SQL: SELECT count(*) FROM "S 1"."T 1" WHERE ((c2 >= 0))
6908 (4 rows)
6910 SELECT count(*) FROM ft1 WHERE c2 >= 0;
6911  count 
6912 -------
6913    821
6914 (1 row)
6916 SET constraint_exclusion = 'on';
6917 EXPLAIN (VERBOSE, COSTS OFF) SELECT count(*) FROM ft1 WHERE c2 >= 0;
6918            QUERY PLAN           
6919 --------------------------------
6920  Aggregate
6921    Output: count(*)
6922    ->  Result
6923          One-Time Filter: false
6924 (4 rows)
6926 SELECT count(*) FROM ft1 WHERE c2 >= 0;
6927  count 
6928 -------
6929      0
6930 (1 row)
6932 RESET constraint_exclusion;
6933 -- local check constraint is not actually enforced
6934 INSERT INTO ft1(c1, c2) VALUES(1111, 2);
6935 UPDATE ft1 SET c2 = c2 + 1 WHERE c1 = 1;
6936 ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2negative;
6937 -- ===================================================================
6938 -- test WITH CHECK OPTION constraints
6939 -- ===================================================================
6940 CREATE FUNCTION row_before_insupd_trigfunc() RETURNS trigger AS $$BEGIN NEW.a := NEW.a + 10; RETURN NEW; END$$ LANGUAGE plpgsql;
6941 CREATE TABLE base_tbl (a int, b int);
6942 ALTER TABLE base_tbl SET (autovacuum_enabled = 'false');
6943 CREATE TRIGGER row_before_insupd_trigger BEFORE INSERT OR UPDATE ON base_tbl FOR EACH ROW EXECUTE PROCEDURE row_before_insupd_trigfunc();
6944 CREATE FOREIGN TABLE foreign_tbl (a int, b int)
6945   SERVER loopback OPTIONS (table_name 'base_tbl');
6946 CREATE VIEW rw_view AS SELECT * FROM foreign_tbl
6947   WHERE a < b WITH CHECK OPTION;
6948 \d+ rw_view
6949                            View "public.rw_view"
6950  Column |  Type   | Collation | Nullable | Default | Storage | Description 
6951 --------+---------+-----------+----------+---------+---------+-------------
6952  a      | integer |           |          |         | plain   | 
6953  b      | integer |           |          |         | plain   | 
6954 View definition:
6955  SELECT a,
6956     b
6957    FROM foreign_tbl
6958   WHERE a < b;
6959 Options: check_option=cascaded
6961 EXPLAIN (VERBOSE, COSTS OFF)
6962 INSERT INTO rw_view VALUES (0, 5);
6963                                    QUERY PLAN                                   
6964 --------------------------------------------------------------------------------
6965  Insert on public.foreign_tbl
6966    Remote SQL: INSERT INTO public.base_tbl(a, b) VALUES ($1, $2) RETURNING a, b
6967    Batch Size: 1
6968    ->  Result
6969          Output: 0, 5
6970 (5 rows)
6972 INSERT INTO rw_view VALUES (0, 5); -- should fail
6973 ERROR:  new row violates check option for view "rw_view"
6974 DETAIL:  Failing row contains (10, 5).
6975 EXPLAIN (VERBOSE, COSTS OFF)
6976 INSERT INTO rw_view VALUES (0, 15);
6977                                    QUERY PLAN                                   
6978 --------------------------------------------------------------------------------
6979  Insert on public.foreign_tbl
6980    Remote SQL: INSERT INTO public.base_tbl(a, b) VALUES ($1, $2) RETURNING a, b
6981    Batch Size: 1
6982    ->  Result
6983          Output: 0, 15
6984 (5 rows)
6986 INSERT INTO rw_view VALUES (0, 15); -- ok
6987 SELECT * FROM foreign_tbl;
6988  a  | b  
6989 ----+----
6990  10 | 15
6991 (1 row)
6993 EXPLAIN (VERBOSE, COSTS OFF)
6994 UPDATE rw_view SET b = b + 5;
6995                                       QUERY PLAN                                       
6996 ---------------------------------------------------------------------------------------
6997  Update on public.foreign_tbl
6998    Remote SQL: UPDATE public.base_tbl SET b = $2 WHERE ctid = $1 RETURNING a, b
6999    ->  Foreign Scan on public.foreign_tbl
7000          Output: (foreign_tbl.b + 5), foreign_tbl.ctid, foreign_tbl.*
7001          Remote SQL: SELECT a, b, ctid FROM public.base_tbl WHERE ((a < b)) FOR UPDATE
7002 (5 rows)
7004 UPDATE rw_view SET b = b + 5; -- should fail
7005 ERROR:  new row violates check option for view "rw_view"
7006 DETAIL:  Failing row contains (20, 20).
7007 EXPLAIN (VERBOSE, COSTS OFF)
7008 UPDATE rw_view SET b = b + 15;
7009                                       QUERY PLAN                                       
7010 ---------------------------------------------------------------------------------------
7011  Update on public.foreign_tbl
7012    Remote SQL: UPDATE public.base_tbl SET b = $2 WHERE ctid = $1 RETURNING a, b
7013    ->  Foreign Scan on public.foreign_tbl
7014          Output: (foreign_tbl.b + 15), foreign_tbl.ctid, foreign_tbl.*
7015          Remote SQL: SELECT a, b, ctid FROM public.base_tbl WHERE ((a < b)) FOR UPDATE
7016 (5 rows)
7018 UPDATE rw_view SET b = b + 15; -- ok
7019 SELECT * FROM foreign_tbl;
7020  a  | b  
7021 ----+----
7022  20 | 30
7023 (1 row)
7025 -- We don't allow batch insert when there are any WCO constraints
7026 ALTER SERVER loopback OPTIONS (ADD batch_size '10');
7027 EXPLAIN (VERBOSE, COSTS OFF)
7028 INSERT INTO rw_view VALUES (0, 15), (0, 5);
7029                                    QUERY PLAN                                   
7030 --------------------------------------------------------------------------------
7031  Insert on public.foreign_tbl
7032    Remote SQL: INSERT INTO public.base_tbl(a, b) VALUES ($1, $2) RETURNING a, b
7033    Batch Size: 1
7034    ->  Values Scan on "*VALUES*"
7035          Output: "*VALUES*".column1, "*VALUES*".column2
7036 (5 rows)
7038 INSERT INTO rw_view VALUES (0, 15), (0, 5); -- should fail
7039 ERROR:  new row violates check option for view "rw_view"
7040 DETAIL:  Failing row contains (10, 5).
7041 SELECT * FROM foreign_tbl;
7042  a  | b  
7043 ----+----
7044  20 | 30
7045 (1 row)
7047 ALTER SERVER loopback OPTIONS (DROP batch_size);
7048 DROP FOREIGN TABLE foreign_tbl CASCADE;
7049 NOTICE:  drop cascades to view rw_view
7050 DROP TRIGGER row_before_insupd_trigger ON base_tbl;
7051 DROP TABLE base_tbl;
7052 -- test WCO for partitions
7053 CREATE TABLE child_tbl (a int, b int);
7054 ALTER TABLE child_tbl SET (autovacuum_enabled = 'false');
7055 CREATE TRIGGER row_before_insupd_trigger BEFORE INSERT OR UPDATE ON child_tbl FOR EACH ROW EXECUTE PROCEDURE row_before_insupd_trigfunc();
7056 CREATE FOREIGN TABLE foreign_tbl (a int, b int)
7057   SERVER loopback OPTIONS (table_name 'child_tbl');
7058 CREATE TABLE parent_tbl (a int, b int) PARTITION BY RANGE(a);
7059 ALTER TABLE parent_tbl ATTACH PARTITION foreign_tbl FOR VALUES FROM (0) TO (100);
7060 -- Detach and re-attach once, to stress the concurrent detach case.
7061 ALTER TABLE parent_tbl DETACH PARTITION foreign_tbl CONCURRENTLY;
7062 ALTER TABLE parent_tbl ATTACH PARTITION foreign_tbl FOR VALUES FROM (0) TO (100);
7063 CREATE VIEW rw_view AS SELECT * FROM parent_tbl
7064   WHERE a < b WITH CHECK OPTION;
7065 \d+ rw_view
7066                            View "public.rw_view"
7067  Column |  Type   | Collation | Nullable | Default | Storage | Description 
7068 --------+---------+-----------+----------+---------+---------+-------------
7069  a      | integer |           |          |         | plain   | 
7070  b      | integer |           |          |         | plain   | 
7071 View definition:
7072  SELECT a,
7073     b
7074    FROM parent_tbl
7075   WHERE a < b;
7076 Options: check_option=cascaded
7078 EXPLAIN (VERBOSE, COSTS OFF)
7079 INSERT INTO rw_view VALUES (0, 5);
7080          QUERY PLAN          
7081 -----------------------------
7082  Insert on public.parent_tbl
7083    ->  Result
7084          Output: 0, 5
7085 (3 rows)
7087 INSERT INTO rw_view VALUES (0, 5); -- should fail
7088 ERROR:  new row violates check option for view "rw_view"
7089 DETAIL:  Failing row contains (10, 5).
7090 EXPLAIN (VERBOSE, COSTS OFF)
7091 INSERT INTO rw_view VALUES (0, 15);
7092          QUERY PLAN          
7093 -----------------------------
7094  Insert on public.parent_tbl
7095    ->  Result
7096          Output: 0, 15
7097 (3 rows)
7099 INSERT INTO rw_view VALUES (0, 15); -- ok
7100 SELECT * FROM foreign_tbl;
7101  a  | b  
7102 ----+----
7103  10 | 15
7104 (1 row)
7106 EXPLAIN (VERBOSE, COSTS OFF)
7107 UPDATE rw_view SET b = b + 5;
7108                                            QUERY PLAN                                           
7109 ------------------------------------------------------------------------------------------------
7110  Update on public.parent_tbl
7111    Foreign Update on public.foreign_tbl parent_tbl_1
7112      Remote SQL: UPDATE public.child_tbl SET b = $2 WHERE ctid = $1 RETURNING a, b
7113    ->  Foreign Scan on public.foreign_tbl parent_tbl_1
7114          Output: (parent_tbl_1.b + 5), parent_tbl_1.tableoid, parent_tbl_1.ctid, parent_tbl_1.*
7115          Remote SQL: SELECT a, b, ctid FROM public.child_tbl WHERE ((a < b)) FOR UPDATE
7116 (6 rows)
7118 UPDATE rw_view SET b = b + 5; -- should fail
7119 ERROR:  new row violates check option for view "rw_view"
7120 DETAIL:  Failing row contains (20, 20).
7121 EXPLAIN (VERBOSE, COSTS OFF)
7122 UPDATE rw_view SET b = b + 15;
7123                                            QUERY PLAN                                            
7124 -------------------------------------------------------------------------------------------------
7125  Update on public.parent_tbl
7126    Foreign Update on public.foreign_tbl parent_tbl_1
7127      Remote SQL: UPDATE public.child_tbl SET b = $2 WHERE ctid = $1 RETURNING a, b
7128    ->  Foreign Scan on public.foreign_tbl parent_tbl_1
7129          Output: (parent_tbl_1.b + 15), parent_tbl_1.tableoid, parent_tbl_1.ctid, parent_tbl_1.*
7130          Remote SQL: SELECT a, b, ctid FROM public.child_tbl WHERE ((a < b)) FOR UPDATE
7131 (6 rows)
7133 UPDATE rw_view SET b = b + 15; -- ok
7134 SELECT * FROM foreign_tbl;
7135  a  | b  
7136 ----+----
7137  20 | 30
7138 (1 row)
7140 -- We don't allow batch insert when there are any WCO constraints
7141 ALTER SERVER loopback OPTIONS (ADD batch_size '10');
7142 EXPLAIN (VERBOSE, COSTS OFF)
7143 INSERT INTO rw_view VALUES (0, 15), (0, 5);
7144                        QUERY PLAN                       
7145 --------------------------------------------------------
7146  Insert on public.parent_tbl
7147    ->  Values Scan on "*VALUES*"
7148          Output: "*VALUES*".column1, "*VALUES*".column2
7149 (3 rows)
7151 INSERT INTO rw_view VALUES (0, 15), (0, 5); -- should fail
7152 ERROR:  new row violates check option for view "rw_view"
7153 DETAIL:  Failing row contains (10, 5).
7154 SELECT * FROM foreign_tbl;
7155  a  | b  
7156 ----+----
7157  20 | 30
7158 (1 row)
7160 ALTER SERVER loopback OPTIONS (DROP batch_size);
7161 DROP FOREIGN TABLE foreign_tbl CASCADE;
7162 DROP TRIGGER row_before_insupd_trigger ON child_tbl;
7163 DROP TABLE parent_tbl CASCADE;
7164 NOTICE:  drop cascades to view rw_view
7165 DROP FUNCTION row_before_insupd_trigfunc;
7166 -- Try a more complex permutation of WCO where there are multiple levels of
7167 -- partitioned tables with columns not all in the same order
7168 CREATE TABLE parent_tbl (a int, b text, c numeric) PARTITION BY RANGE(a);
7169 CREATE TABLE sub_parent (c numeric, a int, b text) PARTITION BY RANGE(a);
7170 ALTER TABLE parent_tbl ATTACH PARTITION sub_parent FOR VALUES FROM (1) TO (10);
7171 CREATE TABLE child_local (b text, c numeric, a int);
7172 CREATE FOREIGN TABLE child_foreign (b text, c numeric, a int)
7173   SERVER loopback OPTIONS (table_name 'child_local');
7174 ALTER TABLE sub_parent ATTACH PARTITION child_foreign FOR VALUES FROM (1) TO (10);
7175 CREATE VIEW rw_view AS SELECT * FROM parent_tbl WHERE a < 5 WITH CHECK OPTION;
7176 INSERT INTO parent_tbl (a) VALUES(1),(5);
7177 EXPLAIN (VERBOSE, COSTS OFF)
7178 UPDATE rw_view SET b = 'text', c = 123.456;
7179                                            QUERY PLAN                                            
7180 -------------------------------------------------------------------------------------------------
7181  Update on public.parent_tbl
7182    Foreign Update on public.child_foreign parent_tbl_1
7183      Remote SQL: UPDATE public.child_local SET b = $2, c = $3 WHERE ctid = $1 RETURNING a
7184    ->  Foreign Scan on public.child_foreign parent_tbl_1
7185          Output: 'text'::text, 123.456, parent_tbl_1.tableoid, parent_tbl_1.ctid, parent_tbl_1.*
7186          Remote SQL: SELECT b, c, a, ctid FROM public.child_local WHERE ((a < 5)) FOR UPDATE
7187 (6 rows)
7189 UPDATE rw_view SET b = 'text', c = 123.456;
7190 SELECT * FROM parent_tbl ORDER BY a;
7191  a |  b   |    c    
7192 ---+------+---------
7193  1 | text | 123.456
7194  5 |      |        
7195 (2 rows)
7197 DROP VIEW rw_view;
7198 DROP TABLE child_local;
7199 DROP FOREIGN TABLE child_foreign;
7200 DROP TABLE sub_parent;
7201 DROP TABLE parent_tbl;
7202 -- ===================================================================
7203 -- test serial columns (ie, sequence-based defaults)
7204 -- ===================================================================
7205 create table loc1 (f1 serial, f2 text);
7206 alter table loc1 set (autovacuum_enabled = 'false');
7207 create foreign table rem1 (f1 serial, f2 text)
7208   server loopback options(table_name 'loc1');
7209 select pg_catalog.setval('rem1_f1_seq', 10, false);
7210  setval 
7211 --------
7212      10
7213 (1 row)
7215 insert into loc1(f2) values('hi');
7216 insert into rem1(f2) values('hi remote');
7217 insert into loc1(f2) values('bye');
7218 insert into rem1(f2) values('bye remote');
7219 select * from loc1;
7220  f1 |     f2     
7221 ----+------------
7222   1 | hi
7223  10 | hi remote
7224   2 | bye
7225  11 | bye remote
7226 (4 rows)
7228 select * from rem1;
7229  f1 |     f2     
7230 ----+------------
7231   1 | hi
7232  10 | hi remote
7233   2 | bye
7234  11 | bye remote
7235 (4 rows)
7237 -- ===================================================================
7238 -- test generated columns
7239 -- ===================================================================
7240 create table gloc1 (
7241   a int,
7242   b int generated always as (a * 2) stored);
7243 alter table gloc1 set (autovacuum_enabled = 'false');
7244 create foreign table grem1 (
7245   a int,
7246   b int generated always as (a * 2) stored)
7247   server loopback options(table_name 'gloc1');
7248 explain (verbose, costs off)
7249 insert into grem1 (a) values (1), (2);
7250                             QUERY PLAN                             
7251 -------------------------------------------------------------------
7252  Insert on public.grem1
7253    Remote SQL: INSERT INTO public.gloc1(a, b) VALUES ($1, DEFAULT)
7254    Batch Size: 1
7255    ->  Values Scan on "*VALUES*"
7256          Output: "*VALUES*".column1, NULL::integer
7257 (5 rows)
7259 insert into grem1 (a) values (1), (2);
7260 explain (verbose, costs off)
7261 update grem1 set a = 22 where a = 2;
7262                                      QUERY PLAN                                     
7263 ------------------------------------------------------------------------------------
7264  Update on public.grem1
7265    Remote SQL: UPDATE public.gloc1 SET a = $2, b = DEFAULT WHERE ctid = $1
7266    ->  Foreign Scan on public.grem1
7267          Output: 22, ctid, grem1.*
7268          Remote SQL: SELECT a, b, ctid FROM public.gloc1 WHERE ((a = 2)) FOR UPDATE
7269 (5 rows)
7271 update grem1 set a = 22 where a = 2;
7272 select * from gloc1;
7273  a  | b  
7274 ----+----
7275   1 |  2
7276  22 | 44
7277 (2 rows)
7279 select * from grem1;
7280  a  | b  
7281 ----+----
7282   1 |  2
7283  22 | 44
7284 (2 rows)
7286 delete from grem1;
7287 -- test copy from
7288 copy grem1 from stdin;
7289 select * from gloc1;
7290  a | b 
7291 ---+---
7292  1 | 2
7293  2 | 4
7294 (2 rows)
7296 select * from grem1;
7297  a | b 
7298 ---+---
7299  1 | 2
7300  2 | 4
7301 (2 rows)
7303 delete from grem1;
7304 -- test batch insert
7305 alter server loopback options (add batch_size '10');
7306 explain (verbose, costs off)
7307 insert into grem1 (a) values (1), (2);
7308                             QUERY PLAN                             
7309 -------------------------------------------------------------------
7310  Insert on public.grem1
7311    Remote SQL: INSERT INTO public.gloc1(a, b) VALUES ($1, DEFAULT)
7312    Batch Size: 10
7313    ->  Values Scan on "*VALUES*"
7314          Output: "*VALUES*".column1, NULL::integer
7315 (5 rows)
7317 insert into grem1 (a) values (1), (2);
7318 select * from gloc1;
7319  a | b 
7320 ---+---
7321  1 | 2
7322  2 | 4
7323 (2 rows)
7325 select * from grem1;
7326  a | b 
7327 ---+---
7328  1 | 2
7329  2 | 4
7330 (2 rows)
7332 delete from grem1;
7333 -- batch insert with foreign partitions.
7334 -- This schema uses two partitions, one local and one remote with a modulo
7335 -- to loop across all of them in batches.
7336 create table tab_batch_local (id int, data text);
7337 insert into tab_batch_local select i, 'test'|| i from generate_series(1, 45) i;
7338 create table tab_batch_sharded (id int, data text) partition by hash(id);
7339 create table tab_batch_sharded_p0 partition of tab_batch_sharded
7340   for values with (modulus 2, remainder 0);
7341 create table tab_batch_sharded_p1_remote (id int, data text);
7342 create foreign table tab_batch_sharded_p1 partition of tab_batch_sharded
7343   for values with (modulus 2, remainder 1)
7344   server loopback options (table_name 'tab_batch_sharded_p1_remote');
7345 insert into tab_batch_sharded select * from tab_batch_local;
7346 select count(*) from tab_batch_sharded;
7347  count 
7348 -------
7349     45
7350 (1 row)
7352 drop table tab_batch_local;
7353 drop table tab_batch_sharded;
7354 drop table tab_batch_sharded_p1_remote;
7355 alter server loopback options (drop batch_size);
7356 -- ===================================================================
7357 -- test local triggers
7358 -- ===================================================================
7359 -- Trigger functions "borrowed" from triggers regress test.
7360 CREATE FUNCTION trigger_func() RETURNS trigger LANGUAGE plpgsql AS $$
7361 BEGIN
7362         RAISE NOTICE 'trigger_func(%) called: action = %, when = %, level = %',
7363                 TG_ARGV[0], TG_OP, TG_WHEN, TG_LEVEL;
7364         RETURN NULL;
7365 END;$$;
7366 CREATE TRIGGER trig_stmt_before BEFORE DELETE OR INSERT OR UPDATE OR TRUNCATE ON rem1
7367         FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
7368 CREATE TRIGGER trig_stmt_after AFTER DELETE OR INSERT OR UPDATE OR TRUNCATE ON rem1
7369         FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
7370 CREATE OR REPLACE FUNCTION trigger_data()  RETURNS trigger
7371 LANGUAGE plpgsql AS $$
7373 declare
7374         oldnew text[];
7375         relid text;
7376     argstr text;
7377 begin
7379         relid := TG_relid::regclass;
7380         argstr := '';
7381         for i in 0 .. TG_nargs - 1 loop
7382                 if i > 0 then
7383                         argstr := argstr || ', ';
7384                 end if;
7385                 argstr := argstr || TG_argv[i];
7386         end loop;
7388     RAISE NOTICE '%(%) % % % ON %',
7389                 tg_name, argstr, TG_when, TG_level, TG_OP, relid;
7390     oldnew := '{}'::text[];
7391         if TG_OP != 'INSERT' then
7392                 oldnew := array_append(oldnew, format('OLD: %s', OLD));
7393         end if;
7395         if TG_OP != 'DELETE' then
7396                 oldnew := array_append(oldnew, format('NEW: %s', NEW));
7397         end if;
7399     RAISE NOTICE '%', array_to_string(oldnew, ',');
7401         if TG_OP = 'DELETE' then
7402                 return OLD;
7403         else
7404                 return NEW;
7405         end if;
7406 end;
7408 -- Test basic functionality
7409 CREATE TRIGGER trig_row_before
7410 BEFORE INSERT OR UPDATE OR DELETE ON rem1
7411 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7412 CREATE TRIGGER trig_row_after
7413 AFTER INSERT OR UPDATE OR DELETE ON rem1
7414 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7415 delete from rem1;
7416 NOTICE:  trigger_func(<NULL>) called: action = DELETE, when = BEFORE, level = STATEMENT
7417 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW DELETE ON rem1
7418 NOTICE:  OLD: (1,hi)
7419 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW DELETE ON rem1
7420 NOTICE:  OLD: (10,"hi remote")
7421 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW DELETE ON rem1
7422 NOTICE:  OLD: (2,bye)
7423 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW DELETE ON rem1
7424 NOTICE:  OLD: (11,"bye remote")
7425 NOTICE:  trig_row_after(23, skidoo) AFTER ROW DELETE ON rem1
7426 NOTICE:  OLD: (1,hi)
7427 NOTICE:  trig_row_after(23, skidoo) AFTER ROW DELETE ON rem1
7428 NOTICE:  OLD: (10,"hi remote")
7429 NOTICE:  trig_row_after(23, skidoo) AFTER ROW DELETE ON rem1
7430 NOTICE:  OLD: (2,bye)
7431 NOTICE:  trig_row_after(23, skidoo) AFTER ROW DELETE ON rem1
7432 NOTICE:  OLD: (11,"bye remote")
7433 NOTICE:  trigger_func(<NULL>) called: action = DELETE, when = AFTER, level = STATEMENT
7434 insert into rem1 values(1,'insert');
7435 NOTICE:  trigger_func(<NULL>) called: action = INSERT, when = BEFORE, level = STATEMENT
7436 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem1
7437 NOTICE:  NEW: (1,insert)
7438 NOTICE:  trig_row_after(23, skidoo) AFTER ROW INSERT ON rem1
7439 NOTICE:  NEW: (1,insert)
7440 NOTICE:  trigger_func(<NULL>) called: action = INSERT, when = AFTER, level = STATEMENT
7441 update rem1 set f2  = 'update' where f1 = 1;
7442 NOTICE:  trigger_func(<NULL>) called: action = UPDATE, when = BEFORE, level = STATEMENT
7443 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON rem1
7444 NOTICE:  OLD: (1,insert),NEW: (1,update)
7445 NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON rem1
7446 NOTICE:  OLD: (1,insert),NEW: (1,update)
7447 NOTICE:  trigger_func(<NULL>) called: action = UPDATE, when = AFTER, level = STATEMENT
7448 update rem1 set f2 = f2 || f2;
7449 NOTICE:  trigger_func(<NULL>) called: action = UPDATE, when = BEFORE, level = STATEMENT
7450 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON rem1
7451 NOTICE:  OLD: (1,update),NEW: (1,updateupdate)
7452 NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON rem1
7453 NOTICE:  OLD: (1,update),NEW: (1,updateupdate)
7454 NOTICE:  trigger_func(<NULL>) called: action = UPDATE, when = AFTER, level = STATEMENT
7455 truncate rem1;
7456 NOTICE:  trigger_func(<NULL>) called: action = TRUNCATE, when = BEFORE, level = STATEMENT
7457 NOTICE:  trigger_func(<NULL>) called: action = TRUNCATE, when = AFTER, level = STATEMENT
7458 -- cleanup
7459 DROP TRIGGER trig_row_before ON rem1;
7460 DROP TRIGGER trig_row_after ON rem1;
7461 DROP TRIGGER trig_stmt_before ON rem1;
7462 DROP TRIGGER trig_stmt_after ON rem1;
7463 DELETE from rem1;
7464 -- Test multiple AFTER ROW triggers on a foreign table
7465 CREATE TRIGGER trig_row_after1
7466 AFTER INSERT OR UPDATE OR DELETE ON rem1
7467 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7468 CREATE TRIGGER trig_row_after2
7469 AFTER INSERT OR UPDATE OR DELETE ON rem1
7470 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7471 insert into rem1 values(1,'insert');
7472 NOTICE:  trig_row_after1(23, skidoo) AFTER ROW INSERT ON rem1
7473 NOTICE:  NEW: (1,insert)
7474 NOTICE:  trig_row_after2(23, skidoo) AFTER ROW INSERT ON rem1
7475 NOTICE:  NEW: (1,insert)
7476 update rem1 set f2  = 'update' where f1 = 1;
7477 NOTICE:  trig_row_after1(23, skidoo) AFTER ROW UPDATE ON rem1
7478 NOTICE:  OLD: (1,insert),NEW: (1,update)
7479 NOTICE:  trig_row_after2(23, skidoo) AFTER ROW UPDATE ON rem1
7480 NOTICE:  OLD: (1,insert),NEW: (1,update)
7481 update rem1 set f2 = f2 || f2;
7482 NOTICE:  trig_row_after1(23, skidoo) AFTER ROW UPDATE ON rem1
7483 NOTICE:  OLD: (1,update),NEW: (1,updateupdate)
7484 NOTICE:  trig_row_after2(23, skidoo) AFTER ROW UPDATE ON rem1
7485 NOTICE:  OLD: (1,update),NEW: (1,updateupdate)
7486 delete from rem1;
7487 NOTICE:  trig_row_after1(23, skidoo) AFTER ROW DELETE ON rem1
7488 NOTICE:  OLD: (1,updateupdate)
7489 NOTICE:  trig_row_after2(23, skidoo) AFTER ROW DELETE ON rem1
7490 NOTICE:  OLD: (1,updateupdate)
7491 -- cleanup
7492 DROP TRIGGER trig_row_after1 ON rem1;
7493 DROP TRIGGER trig_row_after2 ON rem1;
7494 -- Test WHEN conditions
7495 CREATE TRIGGER trig_row_before_insupd
7496 BEFORE INSERT OR UPDATE ON rem1
7497 FOR EACH ROW
7498 WHEN (NEW.f2 like '%update%')
7499 EXECUTE PROCEDURE trigger_data(23,'skidoo');
7500 CREATE TRIGGER trig_row_after_insupd
7501 AFTER INSERT OR UPDATE ON rem1
7502 FOR EACH ROW
7503 WHEN (NEW.f2 like '%update%')
7504 EXECUTE PROCEDURE trigger_data(23,'skidoo');
7505 -- Insert or update not matching: nothing happens
7506 INSERT INTO rem1 values(1, 'insert');
7507 UPDATE rem1 set f2 = 'test';
7508 -- Insert or update matching: triggers are fired
7509 INSERT INTO rem1 values(2, 'update');
7510 NOTICE:  trig_row_before_insupd(23, skidoo) BEFORE ROW INSERT ON rem1
7511 NOTICE:  NEW: (2,update)
7512 NOTICE:  trig_row_after_insupd(23, skidoo) AFTER ROW INSERT ON rem1
7513 NOTICE:  NEW: (2,update)
7514 UPDATE rem1 set f2 = 'update update' where f1 = '2';
7515 NOTICE:  trig_row_before_insupd(23, skidoo) BEFORE ROW UPDATE ON rem1
7516 NOTICE:  OLD: (2,update),NEW: (2,"update update")
7517 NOTICE:  trig_row_after_insupd(23, skidoo) AFTER ROW UPDATE ON rem1
7518 NOTICE:  OLD: (2,update),NEW: (2,"update update")
7519 CREATE TRIGGER trig_row_before_delete
7520 BEFORE DELETE ON rem1
7521 FOR EACH ROW
7522 WHEN (OLD.f2 like '%update%')
7523 EXECUTE PROCEDURE trigger_data(23,'skidoo');
7524 CREATE TRIGGER trig_row_after_delete
7525 AFTER DELETE ON rem1
7526 FOR EACH ROW
7527 WHEN (OLD.f2 like '%update%')
7528 EXECUTE PROCEDURE trigger_data(23,'skidoo');
7529 -- Trigger is fired for f1=2, not for f1=1
7530 DELETE FROM rem1;
7531 NOTICE:  trig_row_before_delete(23, skidoo) BEFORE ROW DELETE ON rem1
7532 NOTICE:  OLD: (2,"update update")
7533 NOTICE:  trig_row_after_delete(23, skidoo) AFTER ROW DELETE ON rem1
7534 NOTICE:  OLD: (2,"update update")
7535 -- cleanup
7536 DROP TRIGGER trig_row_before_insupd ON rem1;
7537 DROP TRIGGER trig_row_after_insupd ON rem1;
7538 DROP TRIGGER trig_row_before_delete ON rem1;
7539 DROP TRIGGER trig_row_after_delete ON rem1;
7540 -- Test various RETURN statements in BEFORE triggers.
7541 CREATE FUNCTION trig_row_before_insupdate() RETURNS TRIGGER AS $$
7542   BEGIN
7543     NEW.f2 := NEW.f2 || ' triggered !';
7544     RETURN NEW;
7545   END
7546 $$ language plpgsql;
7547 CREATE TRIGGER trig_row_before_insupd
7548 BEFORE INSERT OR UPDATE ON rem1
7549 FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate();
7550 -- The new values should have 'triggered' appended
7551 INSERT INTO rem1 values(1, 'insert');
7552 SELECT * from loc1;
7553  f1 |         f2         
7554 ----+--------------------
7555   1 | insert triggered !
7556 (1 row)
7558 INSERT INTO rem1 values(2, 'insert') RETURNING f2;
7559          f2         
7560 --------------------
7561  insert triggered !
7562 (1 row)
7564 SELECT * from loc1;
7565  f1 |         f2         
7566 ----+--------------------
7567   1 | insert triggered !
7568   2 | insert triggered !
7569 (2 rows)
7571 UPDATE rem1 set f2 = '';
7572 SELECT * from loc1;
7573  f1 |      f2      
7574 ----+--------------
7575   1 |  triggered !
7576   2 |  triggered !
7577 (2 rows)
7579 UPDATE rem1 set f2 = 'skidoo' RETURNING f2;
7580          f2         
7581 --------------------
7582  skidoo triggered !
7583  skidoo triggered !
7584 (2 rows)
7586 SELECT * from loc1;
7587  f1 |         f2         
7588 ----+--------------------
7589   1 | skidoo triggered !
7590   2 | skidoo triggered !
7591 (2 rows)
7593 EXPLAIN (verbose, costs off)
7594 UPDATE rem1 set f1 = 10;          -- all columns should be transmitted
7595                               QUERY PLAN                               
7596 -----------------------------------------------------------------------
7597  Update on public.rem1
7598    Remote SQL: UPDATE public.loc1 SET f1 = $2, f2 = $3 WHERE ctid = $1
7599    ->  Foreign Scan on public.rem1
7600          Output: 10, ctid, rem1.*
7601          Remote SQL: SELECT f1, f2, ctid FROM public.loc1 FOR UPDATE
7602 (5 rows)
7604 UPDATE rem1 set f1 = 10;
7605 SELECT * from loc1;
7606  f1 |               f2               
7607 ----+--------------------------------
7608  10 | skidoo triggered ! triggered !
7609  10 | skidoo triggered ! triggered !
7610 (2 rows)
7612 DELETE FROM rem1;
7613 -- Add a second trigger, to check that the changes are propagated correctly
7614 -- from trigger to trigger
7615 CREATE TRIGGER trig_row_before_insupd2
7616 BEFORE INSERT OR UPDATE ON rem1
7617 FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate();
7618 INSERT INTO rem1 values(1, 'insert');
7619 SELECT * from loc1;
7620  f1 |               f2               
7621 ----+--------------------------------
7622   1 | insert triggered ! triggered !
7623 (1 row)
7625 INSERT INTO rem1 values(2, 'insert') RETURNING f2;
7626                f2               
7627 --------------------------------
7628  insert triggered ! triggered !
7629 (1 row)
7631 SELECT * from loc1;
7632  f1 |               f2               
7633 ----+--------------------------------
7634   1 | insert triggered ! triggered !
7635   2 | insert triggered ! triggered !
7636 (2 rows)
7638 UPDATE rem1 set f2 = '';
7639 SELECT * from loc1;
7640  f1 |            f2            
7641 ----+--------------------------
7642   1 |  triggered ! triggered !
7643   2 |  triggered ! triggered !
7644 (2 rows)
7646 UPDATE rem1 set f2 = 'skidoo' RETURNING f2;
7647                f2               
7648 --------------------------------
7649  skidoo triggered ! triggered !
7650  skidoo triggered ! triggered !
7651 (2 rows)
7653 SELECT * from loc1;
7654  f1 |               f2               
7655 ----+--------------------------------
7656   1 | skidoo triggered ! triggered !
7657   2 | skidoo triggered ! triggered !
7658 (2 rows)
7660 DROP TRIGGER trig_row_before_insupd ON rem1;
7661 DROP TRIGGER trig_row_before_insupd2 ON rem1;
7662 DELETE from rem1;
7663 INSERT INTO rem1 VALUES (1, 'test');
7664 -- Test with a trigger returning NULL
7665 CREATE FUNCTION trig_null() RETURNS TRIGGER AS $$
7666   BEGIN
7667     RETURN NULL;
7668   END
7669 $$ language plpgsql;
7670 CREATE TRIGGER trig_null
7671 BEFORE INSERT OR UPDATE OR DELETE ON rem1
7672 FOR EACH ROW EXECUTE PROCEDURE trig_null();
7673 -- Nothing should have changed.
7674 INSERT INTO rem1 VALUES (2, 'test2');
7675 SELECT * from loc1;
7676  f1 |  f2  
7677 ----+------
7678   1 | test
7679 (1 row)
7681 UPDATE rem1 SET f2 = 'test2';
7682 SELECT * from loc1;
7683  f1 |  f2  
7684 ----+------
7685   1 | test
7686 (1 row)
7688 DELETE from rem1;
7689 SELECT * from loc1;
7690  f1 |  f2  
7691 ----+------
7692   1 | test
7693 (1 row)
7695 DROP TRIGGER trig_null ON rem1;
7696 DELETE from rem1;
7697 -- Test a combination of local and remote triggers
7698 CREATE TRIGGER trig_row_before
7699 BEFORE INSERT OR UPDATE OR DELETE ON rem1
7700 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7701 CREATE TRIGGER trig_row_after
7702 AFTER INSERT OR UPDATE OR DELETE ON rem1
7703 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7704 CREATE TRIGGER trig_local_before BEFORE INSERT OR UPDATE ON loc1
7705 FOR EACH ROW EXECUTE PROCEDURE trig_row_before_insupdate();
7706 INSERT INTO rem1(f2) VALUES ('test');
7707 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem1
7708 NOTICE:  NEW: (12,test)
7709 NOTICE:  trig_row_after(23, skidoo) AFTER ROW INSERT ON rem1
7710 NOTICE:  NEW: (12,"test triggered !")
7711 UPDATE rem1 SET f2 = 'testo';
7712 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON rem1
7713 NOTICE:  OLD: (12,"test triggered !"),NEW: (12,testo)
7714 NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON rem1
7715 NOTICE:  OLD: (12,"test triggered !"),NEW: (12,"testo triggered !")
7716 -- Test returning a system attribute
7717 INSERT INTO rem1(f2) VALUES ('test') RETURNING ctid;
7718 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem1
7719 NOTICE:  NEW: (13,test)
7720 NOTICE:  trig_row_after(23, skidoo) AFTER ROW INSERT ON rem1
7721 NOTICE:  NEW: (13,"test triggered !")
7722   ctid  
7723 --------
7724  (0,25)
7725 (1 row)
7727 -- cleanup
7728 DROP TRIGGER trig_row_before ON rem1;
7729 DROP TRIGGER trig_row_after ON rem1;
7730 DROP TRIGGER trig_local_before ON loc1;
7731 -- Test direct foreign table modification functionality
7732 EXPLAIN (verbose, costs off)
7733 DELETE FROM rem1;                 -- can be pushed down
7734                  QUERY PLAN                  
7735 ---------------------------------------------
7736  Delete on public.rem1
7737    ->  Foreign Delete on public.rem1
7738          Remote SQL: DELETE FROM public.loc1
7739 (3 rows)
7741 EXPLAIN (verbose, costs off)
7742 DELETE FROM rem1 WHERE false;     -- currently can't be pushed down
7743                       QUERY PLAN                       
7744 -------------------------------------------------------
7745  Delete on public.rem1
7746    Remote SQL: DELETE FROM public.loc1 WHERE ctid = $1
7747    ->  Result
7748          Output: ctid
7749          One-Time Filter: false
7750 (5 rows)
7752 -- Test with statement-level triggers
7753 CREATE TRIGGER trig_stmt_before
7754         BEFORE DELETE OR INSERT OR UPDATE ON rem1
7755         FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
7756 EXPLAIN (verbose, costs off)
7757 UPDATE rem1 set f2 = '';          -- can be pushed down
7758                         QUERY PLAN                        
7759 ----------------------------------------------------------
7760  Update on public.rem1
7761    ->  Foreign Update on public.rem1
7762          Remote SQL: UPDATE public.loc1 SET f2 = ''::text
7763 (3 rows)
7765 EXPLAIN (verbose, costs off)
7766 DELETE FROM rem1;                 -- can be pushed down
7767                  QUERY PLAN                  
7768 ---------------------------------------------
7769  Delete on public.rem1
7770    ->  Foreign Delete on public.rem1
7771          Remote SQL: DELETE FROM public.loc1
7772 (3 rows)
7774 DROP TRIGGER trig_stmt_before ON rem1;
7775 CREATE TRIGGER trig_stmt_after
7776         AFTER DELETE OR INSERT OR UPDATE ON rem1
7777         FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
7778 EXPLAIN (verbose, costs off)
7779 UPDATE rem1 set f2 = '';          -- can be pushed down
7780                         QUERY PLAN                        
7781 ----------------------------------------------------------
7782  Update on public.rem1
7783    ->  Foreign Update on public.rem1
7784          Remote SQL: UPDATE public.loc1 SET f2 = ''::text
7785 (3 rows)
7787 EXPLAIN (verbose, costs off)
7788 DELETE FROM rem1;                 -- can be pushed down
7789                  QUERY PLAN                  
7790 ---------------------------------------------
7791  Delete on public.rem1
7792    ->  Foreign Delete on public.rem1
7793          Remote SQL: DELETE FROM public.loc1
7794 (3 rows)
7796 DROP TRIGGER trig_stmt_after ON rem1;
7797 -- Test with row-level ON INSERT triggers
7798 CREATE TRIGGER trig_row_before_insert
7799 BEFORE INSERT ON rem1
7800 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7801 EXPLAIN (verbose, costs off)
7802 UPDATE rem1 set f2 = '';          -- can be pushed down
7803                         QUERY PLAN                        
7804 ----------------------------------------------------------
7805  Update on public.rem1
7806    ->  Foreign Update on public.rem1
7807          Remote SQL: UPDATE public.loc1 SET f2 = ''::text
7808 (3 rows)
7810 EXPLAIN (verbose, costs off)
7811 DELETE FROM rem1;                 -- can be pushed down
7812                  QUERY PLAN                  
7813 ---------------------------------------------
7814  Delete on public.rem1
7815    ->  Foreign Delete on public.rem1
7816          Remote SQL: DELETE FROM public.loc1
7817 (3 rows)
7819 DROP TRIGGER trig_row_before_insert ON rem1;
7820 CREATE TRIGGER trig_row_after_insert
7821 AFTER INSERT ON rem1
7822 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7823 EXPLAIN (verbose, costs off)
7824 UPDATE rem1 set f2 = '';          -- can be pushed down
7825                         QUERY PLAN                        
7826 ----------------------------------------------------------
7827  Update on public.rem1
7828    ->  Foreign Update on public.rem1
7829          Remote SQL: UPDATE public.loc1 SET f2 = ''::text
7830 (3 rows)
7832 EXPLAIN (verbose, costs off)
7833 DELETE FROM rem1;                 -- can be pushed down
7834                  QUERY PLAN                  
7835 ---------------------------------------------
7836  Delete on public.rem1
7837    ->  Foreign Delete on public.rem1
7838          Remote SQL: DELETE FROM public.loc1
7839 (3 rows)
7841 DROP TRIGGER trig_row_after_insert ON rem1;
7842 -- Test with row-level ON UPDATE triggers
7843 CREATE TRIGGER trig_row_before_update
7844 BEFORE 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 f1 = $2, f2 = $3 WHERE ctid = $1
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_before_update ON rem1;
7867 CREATE TRIGGER trig_row_after_update
7868 AFTER UPDATE ON rem1
7869 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7870 EXPLAIN (verbose, costs off)
7871 UPDATE rem1 set f2 = '';          -- can't be pushed down
7872                                   QUERY PLAN                                   
7873 -------------------------------------------------------------------------------
7874  Update on public.rem1
7875    Remote SQL: UPDATE public.loc1 SET f2 = $2 WHERE ctid = $1 RETURNING f1, f2
7876    ->  Foreign Scan on public.rem1
7877          Output: ''::text, ctid, rem1.*
7878          Remote SQL: SELECT f1, f2, ctid FROM public.loc1 FOR UPDATE
7879 (5 rows)
7881 EXPLAIN (verbose, costs off)
7882 DELETE FROM rem1;                 -- can be pushed down
7883                  QUERY PLAN                  
7884 ---------------------------------------------
7885  Delete on public.rem1
7886    ->  Foreign Delete on public.rem1
7887          Remote SQL: DELETE FROM public.loc1
7888 (3 rows)
7890 DROP TRIGGER trig_row_after_update ON rem1;
7891 -- Test with row-level ON DELETE triggers
7892 CREATE TRIGGER trig_row_before_delete
7893 BEFORE 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
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_before_delete ON rem1;
7916 CREATE TRIGGER trig_row_after_delete
7917 AFTER DELETE ON rem1
7918 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
7919 EXPLAIN (verbose, costs off)
7920 UPDATE rem1 set f2 = '';          -- can be pushed down
7921                         QUERY PLAN                        
7922 ----------------------------------------------------------
7923  Update on public.rem1
7924    ->  Foreign Update on public.rem1
7925          Remote SQL: UPDATE public.loc1 SET f2 = ''::text
7926 (3 rows)
7928 EXPLAIN (verbose, costs off)
7929 DELETE FROM rem1;                 -- can't be pushed down
7930                                QUERY PLAN                               
7931 ------------------------------------------------------------------------
7932  Delete on public.rem1
7933    Remote SQL: DELETE FROM public.loc1 WHERE ctid = $1 RETURNING f1, f2
7934    ->  Foreign Scan on public.rem1
7935          Output: ctid, rem1.*
7936          Remote SQL: SELECT f1, f2, ctid FROM public.loc1 FOR UPDATE
7937 (5 rows)
7939 DROP TRIGGER trig_row_after_delete ON rem1;
7940 -- ===================================================================
7941 -- test inheritance features
7942 -- ===================================================================
7943 CREATE TABLE a (aa TEXT);
7944 CREATE TABLE loct (aa TEXT, bb TEXT);
7945 ALTER TABLE a SET (autovacuum_enabled = 'false');
7946 ALTER TABLE loct SET (autovacuum_enabled = 'false');
7947 CREATE FOREIGN TABLE b (bb TEXT) INHERITS (a)
7948   SERVER loopback OPTIONS (table_name 'loct');
7949 INSERT INTO a(aa) VALUES('aaa');
7950 INSERT INTO a(aa) VALUES('aaaa');
7951 INSERT INTO a(aa) VALUES('aaaaa');
7952 INSERT INTO b(aa) VALUES('bbb');
7953 INSERT INTO b(aa) VALUES('bbbb');
7954 INSERT INTO b(aa) VALUES('bbbbb');
7955 SELECT tableoid::regclass, * FROM a;
7956  tableoid |  aa   
7957 ----------+-------
7958  a        | aaa
7959  a        | aaaa
7960  a        | aaaaa
7961  b        | bbb
7962  b        | bbbb
7963  b        | bbbbb
7964 (6 rows)
7966 SELECT tableoid::regclass, * FROM b;
7967  tableoid |  aa   | bb 
7968 ----------+-------+----
7969  b        | bbb   | 
7970  b        | bbbb  | 
7971  b        | bbbbb | 
7972 (3 rows)
7974 SELECT tableoid::regclass, * FROM ONLY a;
7975  tableoid |  aa   
7976 ----------+-------
7977  a        | aaa
7978  a        | aaaa
7979  a        | aaaaa
7980 (3 rows)
7982 UPDATE a SET aa = 'zzzzzz' WHERE aa LIKE 'aaaa%';
7983 SELECT tableoid::regclass, * FROM a;
7984  tableoid |   aa   
7985 ----------+--------
7986  a        | aaa
7987  a        | zzzzzz
7988  a        | zzzzzz
7989  b        | bbb
7990  b        | bbbb
7991  b        | bbbbb
7992 (6 rows)
7994 SELECT tableoid::regclass, * FROM b;
7995  tableoid |  aa   | bb 
7996 ----------+-------+----
7997  b        | bbb   | 
7998  b        | bbbb  | 
7999  b        | bbbbb | 
8000 (3 rows)
8002 SELECT tableoid::regclass, * FROM ONLY a;
8003  tableoid |   aa   
8004 ----------+--------
8005  a        | aaa
8006  a        | zzzzzz
8007  a        | zzzzzz
8008 (3 rows)
8010 UPDATE b SET aa = 'new';
8011 SELECT tableoid::regclass, * FROM a;
8012  tableoid |   aa   
8013 ----------+--------
8014  a        | aaa
8015  a        | zzzzzz
8016  a        | zzzzzz
8017  b        | new
8018  b        | new
8019  b        | new
8020 (6 rows)
8022 SELECT tableoid::regclass, * FROM b;
8023  tableoid | aa  | bb 
8024 ----------+-----+----
8025  b        | new | 
8026  b        | new | 
8027  b        | new | 
8028 (3 rows)
8030 SELECT tableoid::regclass, * FROM ONLY a;
8031  tableoid |   aa   
8032 ----------+--------
8033  a        | aaa
8034  a        | zzzzzz
8035  a        | zzzzzz
8036 (3 rows)
8038 UPDATE a SET aa = 'newtoo';
8039 SELECT tableoid::regclass, * FROM a;
8040  tableoid |   aa   
8041 ----------+--------
8042  a        | newtoo
8043  a        | newtoo
8044  a        | newtoo
8045  b        | newtoo
8046  b        | newtoo
8047  b        | newtoo
8048 (6 rows)
8050 SELECT tableoid::regclass, * FROM b;
8051  tableoid |   aa   | bb 
8052 ----------+--------+----
8053  b        | newtoo | 
8054  b        | newtoo | 
8055  b        | newtoo | 
8056 (3 rows)
8058 SELECT tableoid::regclass, * FROM ONLY a;
8059  tableoid |   aa   
8060 ----------+--------
8061  a        | newtoo
8062  a        | newtoo
8063  a        | newtoo
8064 (3 rows)
8066 DELETE FROM a;
8067 SELECT tableoid::regclass, * FROM a;
8068  tableoid | aa 
8069 ----------+----
8070 (0 rows)
8072 SELECT tableoid::regclass, * FROM b;
8073  tableoid | aa | bb 
8074 ----------+----+----
8075 (0 rows)
8077 SELECT tableoid::regclass, * FROM ONLY a;
8078  tableoid | aa 
8079 ----------+----
8080 (0 rows)
8082 DROP TABLE a CASCADE;
8083 NOTICE:  drop cascades to foreign table b
8084 DROP TABLE loct;
8085 -- Check SELECT FOR UPDATE/SHARE with an inherited source table
8086 create table loct1 (f1 int, f2 int, f3 int);
8087 create table loct2 (f1 int, f2 int, f3 int);
8088 alter table loct1 set (autovacuum_enabled = 'false');
8089 alter table loct2 set (autovacuum_enabled = 'false');
8090 create table foo (f1 int, f2 int);
8091 create foreign table foo2 (f3 int) inherits (foo)
8092   server loopback options (table_name 'loct1');
8093 create table bar (f1 int, f2 int);
8094 create foreign table bar2 (f3 int) inherits (bar)
8095   server loopback options (table_name 'loct2');
8096 alter table foo set (autovacuum_enabled = 'false');
8097 alter table bar set (autovacuum_enabled = 'false');
8098 insert into foo values(1,1);
8099 insert into foo values(3,3);
8100 insert into foo2 values(2,2,2);
8101 insert into foo2 values(4,4,4);
8102 insert into bar values(1,11);
8103 insert into bar values(2,22);
8104 insert into bar values(6,66);
8105 insert into bar2 values(3,33,33);
8106 insert into bar2 values(4,44,44);
8107 insert into bar2 values(7,77,77);
8108 explain (verbose, costs off)
8109 select * from bar where f1 in (select f1 from foo) for update;
8110                                           QUERY PLAN                                          
8111 ----------------------------------------------------------------------------------------------
8112  LockRows
8113    Output: bar.f1, bar.f2, bar.ctid, foo.ctid, bar.*, bar.tableoid, foo.*, foo.tableoid
8114    ->  Hash Join
8115          Output: bar.f1, bar.f2, bar.ctid, foo.ctid, bar.*, bar.tableoid, foo.*, foo.tableoid
8116          Inner Unique: true
8117          Hash Cond: (bar.f1 = foo.f1)
8118          ->  Append
8119                ->  Seq Scan on public.bar bar_1
8120                      Output: bar_1.f1, bar_1.f2, bar_1.ctid, bar_1.*, bar_1.tableoid
8121                ->  Foreign Scan on public.bar2 bar_2
8122                      Output: bar_2.f1, bar_2.f2, bar_2.ctid, bar_2.*, bar_2.tableoid
8123                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
8124          ->  Hash
8125                Output: foo.ctid, foo.f1, foo.*, foo.tableoid
8126                ->  HashAggregate
8127                      Output: foo.ctid, foo.f1, foo.*, foo.tableoid
8128                      Group Key: foo.f1
8129                      ->  Append
8130                            ->  Seq Scan on public.foo foo_1
8131                                  Output: foo_1.ctid, foo_1.f1, foo_1.*, foo_1.tableoid
8132                            ->  Foreign Scan on public.foo2 foo_2
8133                                  Output: foo_2.ctid, foo_2.f1, foo_2.*, foo_2.tableoid
8134                                  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
8135 (23 rows)
8137 select * from bar where f1 in (select f1 from foo) for update;
8138  f1 | f2 
8139 ----+----
8140   1 | 11
8141   2 | 22
8142   3 | 33
8143   4 | 44
8144 (4 rows)
8146 explain (verbose, costs off)
8147 select * from bar where f1 in (select f1 from foo) for share;
8148                                           QUERY PLAN                                          
8149 ----------------------------------------------------------------------------------------------
8150  LockRows
8151    Output: bar.f1, bar.f2, bar.ctid, foo.ctid, bar.*, bar.tableoid, foo.*, foo.tableoid
8152    ->  Hash Join
8153          Output: bar.f1, bar.f2, bar.ctid, foo.ctid, bar.*, bar.tableoid, foo.*, foo.tableoid
8154          Inner Unique: true
8155          Hash Cond: (bar.f1 = foo.f1)
8156          ->  Append
8157                ->  Seq Scan on public.bar bar_1
8158                      Output: bar_1.f1, bar_1.f2, bar_1.ctid, bar_1.*, bar_1.tableoid
8159                ->  Foreign Scan on public.bar2 bar_2
8160                      Output: bar_2.f1, bar_2.f2, bar_2.ctid, bar_2.*, bar_2.tableoid
8161                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR SHARE
8162          ->  Hash
8163                Output: foo.ctid, foo.f1, foo.*, foo.tableoid
8164                ->  HashAggregate
8165                      Output: foo.ctid, foo.f1, foo.*, foo.tableoid
8166                      Group Key: foo.f1
8167                      ->  Append
8168                            ->  Seq Scan on public.foo foo_1
8169                                  Output: foo_1.ctid, foo_1.f1, foo_1.*, foo_1.tableoid
8170                            ->  Foreign Scan on public.foo2 foo_2
8171                                  Output: foo_2.ctid, foo_2.f1, foo_2.*, foo_2.tableoid
8172                                  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
8173 (23 rows)
8175 select * from bar where f1 in (select f1 from foo) for share;
8176  f1 | f2 
8177 ----+----
8178   1 | 11
8179   2 | 22
8180   3 | 33
8181   4 | 44
8182 (4 rows)
8184 -- Now check SELECT FOR UPDATE/SHARE with an inherited source table,
8185 -- where the parent is itself a foreign table
8186 create table loct4 (f1 int, f2 int, f3 int);
8187 create foreign table foo2child (f3 int) inherits (foo2)
8188   server loopback options (table_name 'loct4');
8189 NOTICE:  moving and merging column "f3" with inherited definition
8190 DETAIL:  User-specified column moved to the position of the inherited column.
8191 explain (verbose, costs off)
8192 select * from bar where f1 in (select f1 from foo2) for share;
8193                                       QUERY PLAN                                      
8194 --------------------------------------------------------------------------------------
8195  LockRows
8196    Output: bar.f1, bar.f2, bar.ctid, foo2.*, bar.*, bar.tableoid, foo2.tableoid
8197    ->  Hash Join
8198          Output: bar.f1, bar.f2, bar.ctid, foo2.*, bar.*, bar.tableoid, foo2.tableoid
8199          Inner Unique: true
8200          Hash Cond: (bar.f1 = foo2.f1)
8201          ->  Append
8202                ->  Seq Scan on public.bar bar_1
8203                      Output: bar_1.f1, bar_1.f2, bar_1.ctid, bar_1.*, bar_1.tableoid
8204                ->  Foreign Scan on public.bar2 bar_2
8205                      Output: bar_2.f1, bar_2.f2, bar_2.ctid, bar_2.*, bar_2.tableoid
8206                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR SHARE
8207          ->  Hash
8208                Output: foo2.*, foo2.f1, foo2.tableoid
8209                ->  HashAggregate
8210                      Output: foo2.*, foo2.f1, foo2.tableoid
8211                      Group Key: foo2.f1
8212                      ->  Append
8213                            ->  Foreign Scan on public.foo2 foo2_1
8214                                  Output: foo2_1.*, foo2_1.f1, foo2_1.tableoid
8215                                  Remote SQL: SELECT f1, f2, f3 FROM public.loct1
8216                            ->  Foreign Scan on public.foo2child foo2_2
8217                                  Output: foo2_2.*, foo2_2.f1, foo2_2.tableoid
8218                                  Remote SQL: SELECT f1, f2, f3 FROM public.loct4
8219 (24 rows)
8221 select * from bar where f1 in (select f1 from foo2) for share;
8222  f1 | f2 
8223 ----+----
8224   2 | 22
8225   4 | 44
8226 (2 rows)
8228 drop foreign table foo2child;
8229 -- And with a local child relation of the foreign table parent
8230 create table foo2child (f3 int) inherits (foo2);
8231 NOTICE:  moving and merging column "f3" with inherited definition
8232 DETAIL:  User-specified column moved to the position of the inherited column.
8233 explain (verbose, costs off)
8234 select * from bar where f1 in (select f1 from foo2) for share;
8235                                            QUERY PLAN                                            
8236 -------------------------------------------------------------------------------------------------
8237  LockRows
8238    Output: bar.f1, bar.f2, bar.ctid, foo2.*, bar.*, bar.tableoid, foo2.ctid, foo2.tableoid
8239    ->  Hash Join
8240          Output: bar.f1, bar.f2, bar.ctid, foo2.*, bar.*, bar.tableoid, foo2.ctid, foo2.tableoid
8241          Inner Unique: true
8242          Hash Cond: (bar.f1 = foo2.f1)
8243          ->  Append
8244                ->  Seq Scan on public.bar bar_1
8245                      Output: bar_1.f1, bar_1.f2, bar_1.ctid, bar_1.*, bar_1.tableoid
8246                ->  Foreign Scan on public.bar2 bar_2
8247                      Output: bar_2.f1, bar_2.f2, bar_2.ctid, bar_2.*, bar_2.tableoid
8248                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR SHARE
8249          ->  Hash
8250                Output: foo2.*, foo2.f1, foo2.ctid, foo2.tableoid
8251                ->  HashAggregate
8252                      Output: foo2.*, foo2.f1, foo2.ctid, foo2.tableoid
8253                      Group Key: foo2.f1
8254                      ->  Append
8255                            ->  Foreign Scan on public.foo2 foo2_1
8256                                  Output: foo2_1.*, foo2_1.f1, foo2_1.ctid, foo2_1.tableoid
8257                                  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
8258                            ->  Seq Scan on public.foo2child foo2_2
8259                                  Output: foo2_2.*, foo2_2.f1, foo2_2.ctid, foo2_2.tableoid
8260 (23 rows)
8262 select * from bar where f1 in (select f1 from foo2) for share;
8263  f1 | f2 
8264 ----+----
8265   2 | 22
8266   4 | 44
8267 (2 rows)
8269 drop table foo2child;
8270 -- Check UPDATE with inherited target and an inherited source table
8271 explain (verbose, costs off)
8272 update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
8273                                               QUERY PLAN                                               
8274 -------------------------------------------------------------------------------------------------------
8275  Update on public.bar
8276    Update on public.bar bar_1
8277    Foreign Update on public.bar2 bar_2
8278      Remote SQL: UPDATE public.loct2 SET f2 = $2 WHERE ctid = $1
8279    ->  Hash Join
8280          Output: (bar.f2 + 100), foo.ctid, bar.tableoid, bar.ctid, (NULL::record), foo.*, foo.tableoid
8281          Inner Unique: true
8282          Hash Cond: (bar.f1 = foo.f1)
8283          ->  Append
8284                ->  Seq Scan on public.bar bar_1
8285                      Output: bar_1.f2, bar_1.f1, bar_1.tableoid, bar_1.ctid, NULL::record
8286                ->  Foreign Scan on public.bar2 bar_2
8287                      Output: bar_2.f2, bar_2.f1, bar_2.tableoid, bar_2.ctid, bar_2.*
8288                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
8289          ->  Hash
8290                Output: foo.ctid, foo.f1, foo.*, foo.tableoid
8291                ->  HashAggregate
8292                      Output: foo.ctid, foo.f1, foo.*, foo.tableoid
8293                      Group Key: foo.f1
8294                      ->  Append
8295                            ->  Seq Scan on public.foo foo_1
8296                                  Output: foo_1.ctid, foo_1.f1, foo_1.*, foo_1.tableoid
8297                            ->  Foreign Scan on public.foo2 foo_2
8298                                  Output: foo_2.ctid, foo_2.f1, foo_2.*, foo_2.tableoid
8299                                  Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1
8300 (25 rows)
8302 update bar set f2 = f2 + 100 where f1 in (select f1 from foo);
8303 select tableoid::regclass, * from bar order by 1,2;
8304  tableoid | f1 | f2  
8305 ----------+----+-----
8306  bar      |  1 | 111
8307  bar      |  2 | 122
8308  bar      |  6 |  66
8309  bar2     |  3 | 133
8310  bar2     |  4 | 144
8311  bar2     |  7 |  77
8312 (6 rows)
8314 -- Check UPDATE with inherited target and an appendrel subquery
8315 explain (verbose, costs off)
8316 update bar set f2 = f2 + 100
8317 from
8318   ( select f1 from foo union all select f1+3 from foo ) ss
8319 where bar.f1 = ss.f1;
8320                                            QUERY PLAN                                           
8321 ------------------------------------------------------------------------------------------------
8322  Update on public.bar
8323    Update on public.bar bar_1
8324    Foreign Update on public.bar2 bar_2
8325      Remote SQL: UPDATE public.loct2 SET f2 = $2 WHERE ctid = $1
8326    ->  Merge Join
8327          Output: (bar.f2 + 100), (ROW(foo.f1)), bar.tableoid, bar.ctid, (NULL::record)
8328          Merge Cond: (bar.f1 = foo.f1)
8329          ->  Sort
8330                Output: bar.f2, bar.f1, bar.tableoid, bar.ctid, (NULL::record)
8331                Sort Key: bar.f1
8332                ->  Append
8333                      ->  Seq Scan on public.bar bar_1
8334                            Output: bar_1.f2, bar_1.f1, bar_1.tableoid, bar_1.ctid, NULL::record
8335                      ->  Foreign Scan on public.bar2 bar_2
8336                            Output: bar_2.f2, bar_2.f1, bar_2.tableoid, bar_2.ctid, bar_2.*
8337                            Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
8338          ->  Sort
8339                Output: (ROW(foo.f1)), foo.f1
8340                Sort Key: foo.f1
8341                ->  Append
8342                      ->  Seq Scan on public.foo
8343                            Output: ROW(foo.f1), foo.f1
8344                      ->  Foreign Scan on public.foo2 foo_1
8345                            Output: ROW(foo_1.f1), foo_1.f1
8346                            Remote SQL: SELECT f1 FROM public.loct1
8347                      ->  Seq Scan on public.foo foo_2
8348                            Output: ROW((foo_2.f1 + 3)), (foo_2.f1 + 3)
8349                      ->  Foreign Scan on public.foo2 foo_3
8350                            Output: ROW((foo_3.f1 + 3)), (foo_3.f1 + 3)
8351                            Remote SQL: SELECT f1 FROM public.loct1
8352 (30 rows)
8354 update bar set f2 = f2 + 100
8355 from
8356   ( select f1 from foo union all select f1+3 from foo ) ss
8357 where bar.f1 = ss.f1;
8358 select tableoid::regclass, * from bar order by 1,2;
8359  tableoid | f1 | f2  
8360 ----------+----+-----
8361  bar      |  1 | 211
8362  bar      |  2 | 222
8363  bar      |  6 | 166
8364  bar2     |  3 | 233
8365  bar2     |  4 | 244
8366  bar2     |  7 | 177
8367 (6 rows)
8369 -- Test forcing the remote server to produce sorted data for a merge join,
8370 -- but the foreign table is an inheritance child.
8371 truncate table loct1;
8372 truncate table only foo;
8373 \set num_rows_foo 2000
8374 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);
8375 insert into foo select generate_series(1, :num_rows_foo, 2), generate_series(1, :num_rows_foo, 2);
8376 SET enable_hashjoin to false;
8377 SET enable_nestloop to false;
8378 alter foreign table foo2 options (use_remote_estimate 'true');
8379 create index i_loct1_f1 on loct1(f1);
8380 create index i_foo_f1 on foo(f1);
8381 analyze foo;
8382 analyze loct1;
8383 -- inner join; expressions in the clauses appear in the equivalence class list
8384 explain (verbose, costs off)
8385         select foo.f1, loct1.f1 from foo join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
8386                                             QUERY PLAN                                            
8387 --------------------------------------------------------------------------------------------------
8388  Limit
8389    Output: foo.f1, loct1.f1, foo.f2
8390    ->  Sort
8391          Output: foo.f1, loct1.f1, foo.f2
8392          Sort Key: foo.f2
8393          ->  Merge Join
8394                Output: foo.f1, loct1.f1, foo.f2
8395                Merge Cond: (foo.f1 = loct1.f1)
8396                ->  Merge Append
8397                      Sort Key: foo.f1
8398                      ->  Index Scan using i_foo_f1 on public.foo foo_1
8399                            Output: foo_1.f1, foo_1.f2
8400                      ->  Foreign Scan on public.foo2 foo_2
8401                            Output: foo_2.f1, foo_2.f2
8402                            Remote SQL: SELECT f1, f2 FROM public.loct1 ORDER BY f1 ASC NULLS LAST
8403                ->  Index Only Scan using i_loct1_f1 on public.loct1
8404                      Output: loct1.f1
8405 (17 rows)
8407 select foo.f1, loct1.f1 from foo join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
8408  f1 | f1 
8409 ----+----
8410  20 | 20
8411  22 | 22
8412  24 | 24
8413  26 | 26
8414  28 | 28
8415  30 | 30
8416  32 | 32
8417  34 | 34
8418  36 | 36
8419  38 | 38
8420 (10 rows)
8422 -- outer join; expressions in the clauses do not appear in equivalence class
8423 -- list but no output change as compared to the previous query
8424 explain (verbose, costs off)
8425         select foo.f1, loct1.f1 from foo left join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
8426                                             QUERY PLAN                                            
8427 --------------------------------------------------------------------------------------------------
8428  Limit
8429    Output: foo.f1, loct1.f1, foo.f2
8430    ->  Sort
8431          Output: foo.f1, loct1.f1, foo.f2
8432          Sort Key: foo.f2
8433          ->  Merge Left Join
8434                Output: foo.f1, loct1.f1, foo.f2
8435                Merge Cond: (foo.f1 = loct1.f1)
8436                ->  Merge Append
8437                      Sort Key: foo.f1
8438                      ->  Index Scan using i_foo_f1 on public.foo foo_1
8439                            Output: foo_1.f1, foo_1.f2
8440                      ->  Foreign Scan on public.foo2 foo_2
8441                            Output: foo_2.f1, foo_2.f2
8442                            Remote SQL: SELECT f1, f2 FROM public.loct1 ORDER BY f1 ASC NULLS LAST
8443                ->  Index Only Scan using i_loct1_f1 on public.loct1
8444                      Output: loct1.f1
8445 (17 rows)
8447 select foo.f1, loct1.f1 from foo left join loct1 on (foo.f1 = loct1.f1) order by foo.f2 offset 10 limit 10;
8448  f1 | f1 
8449 ----+----
8450  10 | 10
8451  11 |   
8452  12 | 12
8453  13 |   
8454  14 | 14
8455  15 |   
8456  16 | 16
8457  17 |   
8458  18 | 18
8459  19 |   
8460 (10 rows)
8462 RESET enable_hashjoin;
8463 RESET enable_nestloop;
8464 -- Test that WHERE CURRENT OF is not supported
8465 begin;
8466 declare c cursor for select * from bar where f1 = 7;
8467 fetch from c;
8468  f1 | f2  
8469 ----+-----
8470   7 | 177
8471 (1 row)
8473 update bar set f2 = null where current of c;
8474 ERROR:  WHERE CURRENT OF is not supported for this table type
8475 rollback;
8476 explain (verbose, costs off)
8477 delete from foo where f1 < 5 returning *;
8478                                       QUERY PLAN                                      
8479 --------------------------------------------------------------------------------------
8480  Delete on public.foo
8481    Output: foo_1.f1, foo_1.f2
8482    Delete on public.foo foo_1
8483    Foreign Delete on public.foo2 foo_2
8484    ->  Append
8485          ->  Index Scan using i_foo_f1 on public.foo foo_1
8486                Output: foo_1.tableoid, foo_1.ctid
8487                Index Cond: (foo_1.f1 < 5)
8488          ->  Foreign Delete on public.foo2 foo_2
8489                Remote SQL: DELETE FROM public.loct1 WHERE ((f1 < 5)) RETURNING f1, f2
8490 (10 rows)
8492 delete from foo where f1 < 5 returning *;
8493  f1 | f2 
8494 ----+----
8495   1 |  1
8496   3 |  3
8497   0 |  0
8498   2 |  2
8499   4 |  4
8500 (5 rows)
8502 explain (verbose, costs off)
8503 update bar set f2 = f2 + 100 returning *;
8504                                         QUERY PLAN                                        
8505 ------------------------------------------------------------------------------------------
8506  Update on public.bar
8507    Output: bar_1.f1, bar_1.f2
8508    Update on public.bar bar_1
8509    Foreign Update on public.bar2 bar_2
8510    ->  Result
8511          Output: (bar.f2 + 100), bar.tableoid, bar.ctid, (NULL::record)
8512          ->  Append
8513                ->  Seq Scan on public.bar bar_1
8514                      Output: bar_1.f2, bar_1.tableoid, bar_1.ctid, NULL::record
8515                ->  Foreign Update on public.bar2 bar_2
8516                      Remote SQL: UPDATE public.loct2 SET f2 = (f2 + 100) RETURNING f1, f2
8517 (11 rows)
8519 update bar set f2 = f2 + 100 returning *;
8520  f1 | f2  
8521 ----+-----
8522   1 | 311
8523   2 | 322
8524   6 | 266
8525   3 | 333
8526   4 | 344
8527   7 | 277
8528 (6 rows)
8530 -- Test that UPDATE/DELETE with inherited target works with row-level triggers
8531 CREATE TRIGGER trig_row_before
8532 BEFORE UPDATE OR DELETE ON bar2
8533 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
8534 CREATE TRIGGER trig_row_after
8535 AFTER UPDATE OR DELETE ON bar2
8536 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
8537 explain (verbose, costs off)
8538 update bar set f2 = f2 + 100;
8539                                                QUERY PLAN                                               
8540 --------------------------------------------------------------------------------------------------------
8541  Update on public.bar
8542    Update on public.bar bar_1
8543    Foreign Update on public.bar2 bar_2
8544      Remote SQL: UPDATE public.loct2 SET f1 = $2, f2 = $3, f3 = $4 WHERE ctid = $1 RETURNING f1, f2, f3
8545    ->  Result
8546          Output: (bar.f2 + 100), bar.tableoid, bar.ctid, (NULL::record)
8547          ->  Append
8548                ->  Seq Scan on public.bar bar_1
8549                      Output: bar_1.f2, bar_1.tableoid, bar_1.ctid, NULL::record
8550                ->  Foreign Scan on public.bar2 bar_2
8551                      Output: bar_2.f2, bar_2.tableoid, bar_2.ctid, bar_2.*
8552                      Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE
8553 (12 rows)
8555 update bar set f2 = f2 + 100;
8556 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
8557 NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
8558 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
8559 NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
8560 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW UPDATE ON bar2
8561 NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
8562 NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
8563 NOTICE:  OLD: (3,333,33),NEW: (3,433,33)
8564 NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
8565 NOTICE:  OLD: (4,344,44),NEW: (4,444,44)
8566 NOTICE:  trig_row_after(23, skidoo) AFTER ROW UPDATE ON bar2
8567 NOTICE:  OLD: (7,277,77),NEW: (7,377,77)
8568 explain (verbose, costs off)
8569 delete from bar where f2 < 400;
8570                                             QUERY PLAN                                             
8571 ---------------------------------------------------------------------------------------------------
8572  Delete on public.bar
8573    Delete on public.bar bar_1
8574    Foreign Delete on public.bar2 bar_2
8575      Remote SQL: DELETE FROM public.loct2 WHERE ctid = $1 RETURNING f1, f2, f3
8576    ->  Append
8577          ->  Seq Scan on public.bar bar_1
8578                Output: bar_1.tableoid, bar_1.ctid, NULL::record
8579                Filter: (bar_1.f2 < 400)
8580          ->  Foreign Scan on public.bar2 bar_2
8581                Output: bar_2.tableoid, bar_2.ctid, bar_2.*
8582                Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 WHERE ((f2 < 400)) FOR UPDATE
8583 (11 rows)
8585 delete from bar where f2 < 400;
8586 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW DELETE ON bar2
8587 NOTICE:  OLD: (7,377,77)
8588 NOTICE:  trig_row_after(23, skidoo) AFTER ROW DELETE ON bar2
8589 NOTICE:  OLD: (7,377,77)
8590 -- cleanup
8591 drop table foo cascade;
8592 NOTICE:  drop cascades to foreign table foo2
8593 drop table bar cascade;
8594 NOTICE:  drop cascades to foreign table bar2
8595 drop table loct1;
8596 drop table loct2;
8597 -- Test pushing down UPDATE/DELETE joins to the remote server
8598 create table parent (a int, b text);
8599 create table loct1 (a int, b text);
8600 create table loct2 (a int, b text);
8601 create foreign table remt1 (a int, b text)
8602   server loopback options (table_name 'loct1');
8603 create foreign table remt2 (a int, b text)
8604   server loopback options (table_name 'loct2');
8605 alter foreign table remt1 inherit parent;
8606 insert into remt1 values (1, 'foo');
8607 insert into remt1 values (2, 'bar');
8608 insert into remt2 values (1, 'foo');
8609 insert into remt2 values (2, 'bar');
8610 analyze remt1;
8611 analyze remt2;
8612 explain (verbose, costs off)
8613 update parent set b = parent.b || remt2.b from remt2 where parent.a = remt2.a returning *;
8614                                                    QUERY PLAN                                                   
8615 ----------------------------------------------------------------------------------------------------------------
8616  Update on public.parent
8617    Output: parent_1.a, parent_1.b, remt2.a, remt2.b
8618    Update on public.parent parent_1
8619    Foreign Update on public.remt1 parent_2
8620      Remote SQL: UPDATE public.loct1 SET b = $2 WHERE ctid = $1 RETURNING a, b
8621    ->  Nested Loop
8622          Output: (parent.b || remt2.b), remt2.*, remt2.a, remt2.b, parent.tableoid, parent.ctid, (NULL::record)
8623          Join Filter: (parent.a = remt2.a)
8624          ->  Append
8625                ->  Seq Scan on public.parent parent_1
8626                      Output: parent_1.b, parent_1.a, parent_1.tableoid, parent_1.ctid, NULL::record
8627                ->  Foreign Scan on public.remt1 parent_2
8628                      Output: parent_2.b, parent_2.a, parent_2.tableoid, parent_2.ctid, parent_2.*
8629                      Remote SQL: SELECT a, b, ctid FROM public.loct1 FOR UPDATE
8630          ->  Materialize
8631                Output: remt2.b, remt2.*, remt2.a
8632                ->  Foreign Scan on public.remt2
8633                      Output: remt2.b, remt2.*, remt2.a
8634                      Remote SQL: SELECT a, b FROM public.loct2
8635 (19 rows)
8637 update parent set b = parent.b || remt2.b from remt2 where parent.a = remt2.a returning *;
8638  a |   b    | a |  b  
8639 ---+--------+---+-----
8640  1 | foofoo | 1 | foo
8641  2 | barbar | 2 | bar
8642 (2 rows)
8644 explain (verbose, costs off)
8645 delete from parent using remt2 where parent.a = remt2.a returning parent;
8646                                  QUERY PLAN                                  
8647 -----------------------------------------------------------------------------
8648  Delete on public.parent
8649    Output: parent_1.*
8650    Delete on public.parent parent_1
8651    Foreign Delete on public.remt1 parent_2
8652      Remote SQL: DELETE FROM public.loct1 WHERE ctid = $1 RETURNING a, b
8653    ->  Nested Loop
8654          Output: remt2.*, parent.tableoid, parent.ctid
8655          Join Filter: (parent.a = remt2.a)
8656          ->  Append
8657                ->  Seq Scan on public.parent parent_1
8658                      Output: parent_1.a, parent_1.tableoid, parent_1.ctid
8659                ->  Foreign Scan on public.remt1 parent_2
8660                      Output: parent_2.a, parent_2.tableoid, parent_2.ctid
8661                      Remote SQL: SELECT a, ctid FROM public.loct1 FOR UPDATE
8662          ->  Materialize
8663                Output: remt2.*, remt2.a
8664                ->  Foreign Scan on public.remt2
8665                      Output: remt2.*, remt2.a
8666                      Remote SQL: SELECT a, b FROM public.loct2
8667 (19 rows)
8669 delete from parent using remt2 where parent.a = remt2.a returning parent;
8670    parent   
8671 ------------
8672  (1,foofoo)
8673  (2,barbar)
8674 (2 rows)
8676 -- cleanup
8677 drop foreign table remt1;
8678 drop foreign table remt2;
8679 drop table loct1;
8680 drop table loct2;
8681 drop table parent;
8682 -- ===================================================================
8683 -- test tuple routing for foreign-table partitions
8684 -- ===================================================================
8685 -- Test insert tuple routing
8686 create table itrtest (a int, b text) partition by list (a);
8687 create table loct1 (a int check (a in (1)), b text);
8688 create foreign table remp1 (a int check (a in (1)), b text) server loopback options (table_name 'loct1');
8689 create table loct2 (a int check (a in (2)), b text);
8690 create foreign table remp2 (b text, a int check (a in (2))) server loopback options (table_name 'loct2');
8691 alter table itrtest attach partition remp1 for values in (1);
8692 alter table itrtest attach partition remp2 for values in (2);
8693 insert into itrtest values (1, 'foo');
8694 insert into itrtest values (1, 'bar') returning *;
8695  a |  b  
8696 ---+-----
8697  1 | bar
8698 (1 row)
8700 insert into itrtest values (2, 'baz');
8701 insert into itrtest values (2, 'qux') returning *;
8702  a |  b  
8703 ---+-----
8704  2 | qux
8705 (1 row)
8707 insert into itrtest values (1, 'test1'), (2, 'test2') returning *;
8708  a |   b   
8709 ---+-------
8710  1 | test1
8711  2 | test2
8712 (2 rows)
8714 select tableoid::regclass, * FROM itrtest;
8715  tableoid | a |   b   
8716 ----------+---+-------
8717  remp1    | 1 | foo
8718  remp1    | 1 | bar
8719  remp1    | 1 | test1
8720  remp2    | 2 | baz
8721  remp2    | 2 | qux
8722  remp2    | 2 | test2
8723 (6 rows)
8725 select tableoid::regclass, * FROM remp1;
8726  tableoid | a |   b   
8727 ----------+---+-------
8728  remp1    | 1 | foo
8729  remp1    | 1 | bar
8730  remp1    | 1 | test1
8731 (3 rows)
8733 select tableoid::regclass, * FROM remp2;
8734  tableoid |   b   | a 
8735 ----------+-------+---
8736  remp2    | baz   | 2
8737  remp2    | qux   | 2
8738  remp2    | test2 | 2
8739 (3 rows)
8741 delete from itrtest;
8742 -- MERGE ought to fail cleanly
8743 merge into itrtest using (select 1, 'foo') as source on (true)
8744   when matched then do nothing;
8745 ERROR:  cannot execute MERGE on relation "remp1"
8746 DETAIL:  This operation is not supported for foreign tables.
8747 create unique index loct1_idx on loct1 (a);
8748 -- DO NOTHING without an inference specification is supported
8749 insert into itrtest values (1, 'foo') on conflict do nothing returning *;
8750  a |  b  
8751 ---+-----
8752  1 | foo
8753 (1 row)
8755 insert into itrtest values (1, 'foo') on conflict do nothing returning *;
8756  a | b 
8757 ---+---
8758 (0 rows)
8760 -- But other cases are not supported
8761 insert into itrtest values (1, 'bar') on conflict (a) do nothing;
8762 ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification
8763 insert into itrtest values (1, 'bar') on conflict (a) do update set b = excluded.b;
8764 ERROR:  there is no unique or exclusion constraint matching the ON CONFLICT specification
8765 select tableoid::regclass, * FROM itrtest;
8766  tableoid | a |  b  
8767 ----------+---+-----
8768  remp1    | 1 | foo
8769 (1 row)
8771 delete from itrtest;
8772 drop index loct1_idx;
8773 -- Test that remote triggers work with insert tuple routing
8774 create function br_insert_trigfunc() returns trigger as $$
8775 begin
8776         new.b := new.b || ' triggered !';
8777         return new;
8779 $$ language plpgsql;
8780 create trigger loct1_br_insert_trigger before insert on loct1
8781         for each row execute procedure br_insert_trigfunc();
8782 create trigger loct2_br_insert_trigger before insert on loct2
8783         for each row execute procedure br_insert_trigfunc();
8784 -- The new values are concatenated with ' triggered !'
8785 insert into itrtest values (1, 'foo') returning *;
8786  a |        b        
8787 ---+-----------------
8788  1 | foo triggered !
8789 (1 row)
8791 insert into itrtest values (2, 'qux') returning *;
8792  a |        b        
8793 ---+-----------------
8794  2 | qux triggered !
8795 (1 row)
8797 insert into itrtest values (1, 'test1'), (2, 'test2') returning *;
8798  a |         b         
8799 ---+-------------------
8800  1 | test1 triggered !
8801  2 | test2 triggered !
8802 (2 rows)
8804 with result as (insert into itrtest values (1, 'test1'), (2, 'test2') returning *) select * from result;
8805  a |         b         
8806 ---+-------------------
8807  1 | test1 triggered !
8808  2 | test2 triggered !
8809 (2 rows)
8811 drop trigger loct1_br_insert_trigger on loct1;
8812 drop trigger loct2_br_insert_trigger on loct2;
8813 drop table itrtest;
8814 drop table loct1;
8815 drop table loct2;
8816 -- Test update tuple routing
8817 create table utrtest (a int, b text) partition by list (a);
8818 create table loct (a int check (a in (1)), b text);
8819 create foreign table remp (a int check (a in (1)), b text) server loopback options (table_name 'loct');
8820 create table locp (a int check (a in (2)), b text);
8821 alter table utrtest attach partition remp for values in (1);
8822 alter table utrtest attach partition locp for values in (2);
8823 insert into utrtest values (1, 'foo');
8824 insert into utrtest values (2, 'qux');
8825 select tableoid::regclass, * FROM utrtest;
8826  tableoid | a |  b  
8827 ----------+---+-----
8828  remp     | 1 | foo
8829  locp     | 2 | qux
8830 (2 rows)
8832 select tableoid::regclass, * FROM remp;
8833  tableoid | a |  b  
8834 ----------+---+-----
8835  remp     | 1 | foo
8836 (1 row)
8838 select tableoid::regclass, * FROM locp;
8839  tableoid | a |  b  
8840 ----------+---+-----
8841  locp     | 2 | qux
8842 (1 row)
8844 -- It's not allowed to move a row from a partition that is foreign to another
8845 update utrtest set a = 2 where b = 'foo' returning *;
8846 ERROR:  new row for relation "loct" violates check constraint "loct_a_check"
8847 DETAIL:  Failing row contains (2, foo).
8848 CONTEXT:  remote SQL command: UPDATE public.loct SET a = 2 WHERE ((b = 'foo')) RETURNING a, b
8849 -- But the reverse is allowed
8850 update utrtest set a = 1 where b = 'qux' returning *;
8851 ERROR:  cannot route tuples into foreign table to be updated "remp"
8852 select tableoid::regclass, * FROM utrtest;
8853  tableoid | a |  b  
8854 ----------+---+-----
8855  remp     | 1 | foo
8856  locp     | 2 | qux
8857 (2 rows)
8859 select tableoid::regclass, * FROM remp;
8860  tableoid | a |  b  
8861 ----------+---+-----
8862  remp     | 1 | foo
8863 (1 row)
8865 select tableoid::regclass, * FROM locp;
8866  tableoid | a |  b  
8867 ----------+---+-----
8868  locp     | 2 | qux
8869 (1 row)
8871 -- The executor should not let unexercised FDWs shut down
8872 update utrtest set a = 1 where b = 'foo';
8873 -- Test that remote triggers work with update tuple routing
8874 create trigger loct_br_insert_trigger before insert on loct
8875         for each row execute procedure br_insert_trigfunc();
8876 delete from utrtest;
8877 insert into utrtest values (2, 'qux');
8878 -- Check case where the foreign partition is a subplan target rel
8879 explain (verbose, costs off)
8880 update utrtest set a = 1 where a = 1 or a = 2 returning *;
8881                                              QUERY PLAN                                             
8882 ----------------------------------------------------------------------------------------------------
8883  Update on public.utrtest
8884    Output: utrtest_1.a, utrtest_1.b
8885    Foreign Update on public.remp utrtest_1
8886    Update on public.locp utrtest_2
8887    ->  Append
8888          ->  Foreign Update on public.remp utrtest_1
8889                Remote SQL: UPDATE public.loct SET a = 1 WHERE (((a = 1) OR (a = 2))) RETURNING a, b
8890          ->  Seq Scan on public.locp utrtest_2
8891                Output: 1, utrtest_2.tableoid, utrtest_2.ctid, NULL::record
8892                Filter: ((utrtest_2.a = 1) OR (utrtest_2.a = 2))
8893 (10 rows)
8895 -- The new values are concatenated with ' triggered !'
8896 update utrtest set a = 1 where a = 1 or a = 2 returning *;
8897 ERROR:  cannot route tuples into foreign table to be updated "remp"
8898 delete from utrtest;
8899 insert into utrtest values (2, 'qux');
8900 -- Check case where the foreign partition isn't a subplan target rel
8901 explain (verbose, costs off)
8902 update utrtest set a = 1 where a = 2 returning *;
8903                       QUERY PLAN                       
8904 -------------------------------------------------------
8905  Update on public.utrtest
8906    Output: utrtest_1.a, utrtest_1.b
8907    Update on public.locp utrtest_1
8908    ->  Seq Scan on public.locp utrtest_1
8909          Output: 1, utrtest_1.tableoid, utrtest_1.ctid
8910          Filter: (utrtest_1.a = 2)
8911 (6 rows)
8913 -- The new values are concatenated with ' triggered !'
8914 update utrtest set a = 1 where a = 2 returning *;
8915  a |        b        
8916 ---+-----------------
8917  1 | qux triggered !
8918 (1 row)
8920 drop trigger loct_br_insert_trigger on loct;
8921 -- We can move rows to a foreign partition that has been updated already,
8922 -- but can't move rows to a foreign partition that hasn't been updated yet
8923 delete from utrtest;
8924 insert into utrtest values (1, 'foo');
8925 insert into utrtest values (2, 'qux');
8926 -- Test the former case:
8927 -- with a direct modification plan
8928 explain (verbose, costs off)
8929 update utrtest set a = 1 returning *;
8930                                 QUERY PLAN                                 
8931 ---------------------------------------------------------------------------
8932  Update on public.utrtest
8933    Output: utrtest_1.a, utrtest_1.b
8934    Foreign Update on public.remp utrtest_1
8935    Update on public.locp utrtest_2
8936    ->  Append
8937          ->  Foreign Update on public.remp utrtest_1
8938                Remote SQL: UPDATE public.loct SET a = 1 RETURNING a, b
8939          ->  Seq Scan on public.locp utrtest_2
8940                Output: 1, utrtest_2.tableoid, utrtest_2.ctid, NULL::record
8941 (9 rows)
8943 update utrtest set a = 1 returning *;
8944 ERROR:  cannot route tuples into foreign table to be updated "remp"
8945 delete from utrtest;
8946 insert into utrtest values (1, 'foo');
8947 insert into utrtest values (2, 'qux');
8948 -- with a non-direct modification plan
8949 explain (verbose, costs off)
8950 update utrtest set a = 1 from (values (1), (2)) s(x) where a = s.x returning *;
8951                                            QUERY PLAN                                           
8952 ------------------------------------------------------------------------------------------------
8953  Update on public.utrtest
8954    Output: utrtest_1.a, utrtest_1.b, "*VALUES*".column1
8955    Foreign Update on public.remp utrtest_1
8956      Remote SQL: UPDATE public.loct SET a = $2 WHERE ctid = $1 RETURNING a, b
8957    Update on public.locp utrtest_2
8958    ->  Hash Join
8959          Output: 1, "*VALUES*".*, "*VALUES*".column1, utrtest.tableoid, utrtest.ctid, utrtest.*
8960          Hash Cond: (utrtest.a = "*VALUES*".column1)
8961          ->  Append
8962                ->  Foreign Scan on public.remp utrtest_1
8963                      Output: utrtest_1.a, utrtest_1.tableoid, utrtest_1.ctid, utrtest_1.*
8964                      Remote SQL: SELECT a, b, ctid FROM public.loct FOR UPDATE
8965                ->  Seq Scan on public.locp utrtest_2
8966                      Output: utrtest_2.a, utrtest_2.tableoid, utrtest_2.ctid, NULL::record
8967          ->  Hash
8968                Output: "*VALUES*".*, "*VALUES*".column1
8969                ->  Values Scan on "*VALUES*"
8970                      Output: "*VALUES*".*, "*VALUES*".column1
8971 (18 rows)
8973 update utrtest set a = 1 from (values (1), (2)) s(x) where a = s.x returning *;
8974 ERROR:  cannot route tuples into foreign table to be updated "remp"
8975 -- Change the definition of utrtest so that the foreign partition get updated
8976 -- after the local partition
8977 delete from utrtest;
8978 alter table utrtest detach partition remp;
8979 drop foreign table remp;
8980 alter table loct drop constraint loct_a_check;
8981 alter table loct add check (a in (3));
8982 create foreign table remp (a int check (a in (3)), b text) server loopback options (table_name 'loct');
8983 alter table utrtest attach partition remp for values in (3);
8984 insert into utrtest values (2, 'qux');
8985 insert into utrtest values (3, 'xyzzy');
8986 -- Test the latter case:
8987 -- with a direct modification plan
8988 explain (verbose, costs off)
8989 update utrtest set a = 3 returning *;
8990                                 QUERY PLAN                                 
8991 ---------------------------------------------------------------------------
8992  Update on public.utrtest
8993    Output: utrtest_1.a, utrtest_1.b
8994    Update on public.locp utrtest_1
8995    Foreign Update on public.remp utrtest_2
8996    ->  Append
8997          ->  Seq Scan on public.locp utrtest_1
8998                Output: 3, utrtest_1.tableoid, utrtest_1.ctid, NULL::record
8999          ->  Foreign Update on public.remp utrtest_2
9000                Remote SQL: UPDATE public.loct SET a = 3 RETURNING a, b
9001 (9 rows)
9003 update utrtest set a = 3 returning *; -- ERROR
9004 ERROR:  cannot route tuples into foreign table to be updated "remp"
9005 -- with a non-direct modification plan
9006 explain (verbose, costs off)
9007 update utrtest set a = 3 from (values (2), (3)) s(x) where a = s.x returning *;
9008                                              QUERY PLAN                                              
9009 -----------------------------------------------------------------------------------------------------
9010  Update on public.utrtest
9011    Output: utrtest_1.a, utrtest_1.b, "*VALUES*".column1
9012    Update on public.locp utrtest_1
9013    Foreign Update on public.remp utrtest_2
9014      Remote SQL: UPDATE public.loct SET a = $2 WHERE ctid = $1 RETURNING a, b
9015    ->  Hash Join
9016          Output: 3, "*VALUES*".*, "*VALUES*".column1, utrtest.tableoid, utrtest.ctid, (NULL::record)
9017          Hash Cond: (utrtest.a = "*VALUES*".column1)
9018          ->  Append
9019                ->  Seq Scan on public.locp utrtest_1
9020                      Output: utrtest_1.a, utrtest_1.tableoid, utrtest_1.ctid, NULL::record
9021                ->  Foreign Scan on public.remp utrtest_2
9022                      Output: utrtest_2.a, utrtest_2.tableoid, utrtest_2.ctid, utrtest_2.*
9023                      Remote SQL: SELECT a, b, ctid FROM public.loct FOR UPDATE
9024          ->  Hash
9025                Output: "*VALUES*".*, "*VALUES*".column1
9026                ->  Values Scan on "*VALUES*"
9027                      Output: "*VALUES*".*, "*VALUES*".column1
9028 (18 rows)
9030 update utrtest set a = 3 from (values (2), (3)) s(x) where a = s.x returning *; -- ERROR
9031 ERROR:  cannot route tuples into foreign table to be updated "remp"
9032 drop table utrtest;
9033 drop table loct;
9034 -- Test copy tuple routing
9035 create table ctrtest (a int, b text) partition by list (a);
9036 create table loct1 (a int check (a in (1)), b text);
9037 create foreign table remp1 (a int check (a in (1)), b text) server loopback options (table_name 'loct1');
9038 create table loct2 (a int check (a in (2)), b text);
9039 create foreign table remp2 (b text, a int check (a in (2))) server loopback options (table_name 'loct2');
9040 alter table ctrtest attach partition remp1 for values in (1);
9041 alter table ctrtest attach partition remp2 for values in (2);
9042 copy ctrtest from stdin;
9043 select tableoid::regclass, * FROM ctrtest;
9044  tableoid | a |  b  
9045 ----------+---+-----
9046  remp1    | 1 | foo
9047  remp2    | 2 | qux
9048 (2 rows)
9050 select tableoid::regclass, * FROM remp1;
9051  tableoid | a |  b  
9052 ----------+---+-----
9053  remp1    | 1 | foo
9054 (1 row)
9056 select tableoid::regclass, * FROM remp2;
9057  tableoid |  b  | a 
9058 ----------+-----+---
9059  remp2    | qux | 2
9060 (1 row)
9062 -- Copying into foreign partitions directly should work as well
9063 copy remp1 from stdin;
9064 select tableoid::regclass, * FROM remp1;
9065  tableoid | a |  b  
9066 ----------+---+-----
9067  remp1    | 1 | foo
9068  remp1    | 1 | bar
9069 (2 rows)
9071 delete from ctrtest;
9072 -- Test copy tuple routing with the batch_size option enabled
9073 alter server loopback options (add batch_size '2');
9074 copy ctrtest from stdin;
9075 select tableoid::regclass, * FROM ctrtest;
9076  tableoid | a |   b   
9077 ----------+---+-------
9078  remp1    | 1 | foo
9079  remp1    | 1 | bar
9080  remp1    | 1 | test1
9081  remp2    | 2 | baz
9082  remp2    | 2 | qux
9083  remp2    | 2 | test2
9084 (6 rows)
9086 select tableoid::regclass, * FROM remp1;
9087  tableoid | a |   b   
9088 ----------+---+-------
9089  remp1    | 1 | foo
9090  remp1    | 1 | bar
9091  remp1    | 1 | test1
9092 (3 rows)
9094 select tableoid::regclass, * FROM remp2;
9095  tableoid |   b   | a 
9096 ----------+-------+---
9097  remp2    | baz   | 2
9098  remp2    | qux   | 2
9099  remp2    | test2 | 2
9100 (3 rows)
9102 delete from ctrtest;
9103 alter server loopback options (drop batch_size);
9104 drop table ctrtest;
9105 drop table loct1;
9106 drop table loct2;
9107 -- ===================================================================
9108 -- test COPY FROM
9109 -- ===================================================================
9110 create table loc2 (f1 int, f2 text);
9111 alter table loc2 set (autovacuum_enabled = 'false');
9112 create foreign table rem2 (f1 int, f2 text) server loopback options(table_name 'loc2');
9113 -- Test basic functionality
9114 copy rem2 from stdin;
9115 select * from rem2;
9116  f1 | f2  
9117 ----+-----
9118   1 | foo
9119   2 | bar
9120 (2 rows)
9122 delete from rem2;
9123 -- Test check constraints
9124 alter table loc2 add constraint loc2_f1positive check (f1 >= 0);
9125 alter foreign table rem2 add constraint rem2_f1positive check (f1 >= 0);
9126 -- check constraint is enforced on the remote side, not locally
9127 copy rem2 from stdin;
9128 copy rem2 from stdin; -- ERROR
9129 ERROR:  new row for relation "loc2" violates check constraint "loc2_f1positive"
9130 DETAIL:  Failing row contains (-1, xyzzy).
9131 CONTEXT:  remote SQL command: INSERT INTO public.loc2(f1, f2) VALUES ($1, $2)
9132 COPY rem2, line 1: "-1  xyzzy"
9133 select * from rem2;
9134  f1 | f2  
9135 ----+-----
9136   1 | foo
9137   2 | bar
9138 (2 rows)
9140 alter foreign table rem2 drop constraint rem2_f1positive;
9141 alter table loc2 drop constraint loc2_f1positive;
9142 delete from rem2;
9143 -- Test local triggers
9144 create trigger trig_stmt_before before insert on rem2
9145         for each statement execute procedure trigger_func();
9146 create trigger trig_stmt_after after insert on rem2
9147         for each statement execute procedure trigger_func();
9148 create trigger trig_row_before before insert on rem2
9149         for each row execute procedure trigger_data(23,'skidoo');
9150 create trigger trig_row_after after insert on rem2
9151         for each row execute procedure trigger_data(23,'skidoo');
9152 copy rem2 from stdin;
9153 NOTICE:  trigger_func(<NULL>) called: action = INSERT, when = BEFORE, level = STATEMENT
9154 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem2
9155 NOTICE:  NEW: (1,foo)
9156 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem2
9157 NOTICE:  NEW: (2,bar)
9158 NOTICE:  trig_row_after(23, skidoo) AFTER ROW INSERT ON rem2
9159 NOTICE:  NEW: (1,foo)
9160 NOTICE:  trig_row_after(23, skidoo) AFTER ROW INSERT ON rem2
9161 NOTICE:  NEW: (2,bar)
9162 NOTICE:  trigger_func(<NULL>) called: action = INSERT, when = AFTER, level = STATEMENT
9163 select * from rem2;
9164  f1 | f2  
9165 ----+-----
9166   1 | foo
9167   2 | bar
9168 (2 rows)
9170 drop trigger trig_row_before on rem2;
9171 drop trigger trig_row_after on rem2;
9172 drop trigger trig_stmt_before on rem2;
9173 drop trigger trig_stmt_after on rem2;
9174 delete from rem2;
9175 create trigger trig_row_before_insert before insert on rem2
9176         for each row execute procedure trig_row_before_insupdate();
9177 -- The new values are concatenated with ' triggered !'
9178 copy rem2 from stdin;
9179 select * from rem2;
9180  f1 |       f2        
9181 ----+-----------------
9182   1 | foo triggered !
9183   2 | bar triggered !
9184 (2 rows)
9186 drop trigger trig_row_before_insert on rem2;
9187 delete from rem2;
9188 create trigger trig_null before insert on rem2
9189         for each row execute procedure trig_null();
9190 -- Nothing happens
9191 copy rem2 from stdin;
9192 select * from rem2;
9193  f1 | f2 
9194 ----+----
9195 (0 rows)
9197 drop trigger trig_null on rem2;
9198 delete from rem2;
9199 -- Test remote triggers
9200 create trigger trig_row_before_insert before insert on loc2
9201         for each row execute procedure trig_row_before_insupdate();
9202 -- The new values are concatenated with ' triggered !'
9203 copy rem2 from stdin;
9204 select * from rem2;
9205  f1 |       f2        
9206 ----+-----------------
9207   1 | foo triggered !
9208   2 | bar triggered !
9209 (2 rows)
9211 drop trigger trig_row_before_insert on loc2;
9212 delete from rem2;
9213 create trigger trig_null before insert on loc2
9214         for each row execute procedure trig_null();
9215 -- Nothing happens
9216 copy rem2 from stdin;
9217 select * from rem2;
9218  f1 | f2 
9219 ----+----
9220 (0 rows)
9222 drop trigger trig_null on loc2;
9223 delete from rem2;
9224 -- Test a combination of local and remote triggers
9225 create trigger rem2_trig_row_before before insert on rem2
9226         for each row execute procedure trigger_data(23,'skidoo');
9227 create trigger rem2_trig_row_after after insert on rem2
9228         for each row execute procedure trigger_data(23,'skidoo');
9229 create trigger loc2_trig_row_before_insert before insert on loc2
9230         for each row execute procedure trig_row_before_insupdate();
9231 copy rem2 from stdin;
9232 NOTICE:  rem2_trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem2
9233 NOTICE:  NEW: (1,foo)
9234 NOTICE:  rem2_trig_row_before(23, skidoo) BEFORE ROW INSERT ON rem2
9235 NOTICE:  NEW: (2,bar)
9236 NOTICE:  rem2_trig_row_after(23, skidoo) AFTER ROW INSERT ON rem2
9237 NOTICE:  NEW: (1,"foo triggered !")
9238 NOTICE:  rem2_trig_row_after(23, skidoo) AFTER ROW INSERT ON rem2
9239 NOTICE:  NEW: (2,"bar triggered !")
9240 select * from rem2;
9241  f1 |       f2        
9242 ----+-----------------
9243   1 | foo triggered !
9244   2 | bar triggered !
9245 (2 rows)
9247 drop trigger rem2_trig_row_before on rem2;
9248 drop trigger rem2_trig_row_after on rem2;
9249 drop trigger loc2_trig_row_before_insert on loc2;
9250 delete from rem2;
9251 -- test COPY FROM with foreign table created in the same transaction
9252 create table loc3 (f1 int, f2 text);
9253 begin;
9254 create foreign table rem3 (f1 int, f2 text)
9255         server loopback options(table_name 'loc3');
9256 copy rem3 from stdin;
9257 commit;
9258 select * from rem3;
9259  f1 | f2  
9260 ----+-----
9261   1 | foo
9262   2 | bar
9263 (2 rows)
9265 drop foreign table rem3;
9266 drop table loc3;
9267 -- Test COPY FROM with the batch_size option enabled
9268 alter server loopback options (add batch_size '2');
9269 -- Test basic functionality
9270 copy rem2 from stdin;
9271 select * from rem2;
9272  f1 | f2  
9273 ----+-----
9274   1 | foo
9275   2 | bar
9276   3 | baz
9277 (3 rows)
9279 delete from rem2;
9280 -- Test check constraints
9281 alter table loc2 add constraint loc2_f1positive check (f1 >= 0);
9282 alter foreign table rem2 add constraint rem2_f1positive check (f1 >= 0);
9283 -- check constraint is enforced on the remote side, not locally
9284 copy rem2 from stdin;
9285 copy rem2 from stdin; -- ERROR
9286 ERROR:  new row for relation "loc2" violates check constraint "loc2_f1positive"
9287 DETAIL:  Failing row contains (-1, xyzzy).
9288 CONTEXT:  remote SQL command: INSERT INTO public.loc2(f1, f2) VALUES ($1, $2)
9289 COPY rem2
9290 select * from rem2;
9291  f1 | f2  
9292 ----+-----
9293   1 | foo
9294   2 | bar
9295   3 | baz
9296 (3 rows)
9298 alter foreign table rem2 drop constraint rem2_f1positive;
9299 alter table loc2 drop constraint loc2_f1positive;
9300 delete from rem2;
9301 -- Test remote triggers
9302 create trigger trig_row_before_insert before insert on loc2
9303         for each row execute procedure trig_row_before_insupdate();
9304 -- The new values are concatenated with ' triggered !'
9305 copy rem2 from stdin;
9306 select * from rem2;
9307  f1 |       f2        
9308 ----+-----------------
9309   1 | foo triggered !
9310   2 | bar triggered !
9311   3 | baz triggered !
9312 (3 rows)
9314 drop trigger trig_row_before_insert on loc2;
9315 delete from rem2;
9316 create trigger trig_null before insert on loc2
9317         for each row execute procedure trig_null();
9318 -- Nothing happens
9319 copy rem2 from stdin;
9320 select * from rem2;
9321  f1 | f2 
9322 ----+----
9323 (0 rows)
9325 drop trigger trig_null on loc2;
9326 delete from rem2;
9327 -- Check with zero-column foreign table; batch insert will be disabled
9328 alter table loc2 drop column f1;
9329 alter table loc2 drop column f2;
9330 alter table rem2 drop column f1;
9331 alter table rem2 drop column f2;
9332 copy rem2 from stdin;
9333 select * from rem2;
9335 (3 rows)
9337 delete from rem2;
9338 alter server loopback options (drop batch_size);
9339 -- ===================================================================
9340 -- test for TRUNCATE
9341 -- ===================================================================
9342 CREATE TABLE tru_rtable0 (id int primary key);
9343 CREATE FOREIGN TABLE tru_ftable (id int)
9344        SERVER loopback OPTIONS (table_name 'tru_rtable0');
9345 INSERT INTO tru_rtable0 (SELECT x FROM generate_series(1,10) x);
9346 CREATE TABLE tru_ptable (id int) PARTITION BY HASH(id);
9347 CREATE TABLE tru_ptable__p0 PARTITION OF tru_ptable
9348                             FOR VALUES WITH (MODULUS 2, REMAINDER 0);
9349 CREATE TABLE tru_rtable1 (id int primary key);
9350 CREATE FOREIGN TABLE tru_ftable__p1 PARTITION OF tru_ptable
9351                                     FOR VALUES WITH (MODULUS 2, REMAINDER 1)
9352        SERVER loopback OPTIONS (table_name 'tru_rtable1');
9353 INSERT INTO tru_ptable (SELECT x FROM generate_series(11,20) x);
9354 CREATE TABLE tru_pk_table(id int primary key);
9355 CREATE TABLE tru_fk_table(fkey int references tru_pk_table(id));
9356 INSERT INTO tru_pk_table (SELECT x FROM generate_series(1,10) x);
9357 INSERT INTO tru_fk_table (SELECT x % 10 + 1 FROM generate_series(5,25) x);
9358 CREATE FOREIGN TABLE tru_pk_ftable (id int)
9359        SERVER loopback OPTIONS (table_name 'tru_pk_table');
9360 CREATE TABLE tru_rtable_parent (id int);
9361 CREATE TABLE tru_rtable_child (id int);
9362 CREATE FOREIGN TABLE tru_ftable_parent (id int)
9363        SERVER loopback OPTIONS (table_name 'tru_rtable_parent');
9364 CREATE FOREIGN TABLE tru_ftable_child () INHERITS (tru_ftable_parent)
9365        SERVER loopback OPTIONS (table_name 'tru_rtable_child');
9366 INSERT INTO tru_rtable_parent (SELECT x FROM generate_series(1,8) x);
9367 INSERT INTO tru_rtable_child  (SELECT x FROM generate_series(10, 18) x);
9368 -- normal truncate
9369 SELECT sum(id) FROM tru_ftable;        -- 55
9370  sum 
9371 -----
9372   55
9373 (1 row)
9375 TRUNCATE tru_ftable;
9376 SELECT count(*) FROM tru_rtable0;               -- 0
9377  count 
9378 -------
9379      0
9380 (1 row)
9382 SELECT count(*) FROM tru_ftable;                -- 0
9383  count 
9384 -------
9385      0
9386 (1 row)
9388 -- 'truncatable' option
9389 ALTER SERVER loopback OPTIONS (ADD truncatable 'false');
9390 TRUNCATE tru_ftable;                    -- error
9391 ERROR:  foreign table "tru_ftable" does not allow truncates
9392 ALTER FOREIGN TABLE tru_ftable OPTIONS (ADD truncatable 'true');
9393 TRUNCATE tru_ftable;                    -- accepted
9394 ALTER FOREIGN TABLE tru_ftable OPTIONS (SET truncatable 'false');
9395 TRUNCATE tru_ftable;                    -- error
9396 ERROR:  foreign table "tru_ftable" does not allow truncates
9397 ALTER SERVER loopback OPTIONS (DROP truncatable);
9398 ALTER FOREIGN TABLE tru_ftable OPTIONS (SET truncatable 'false');
9399 TRUNCATE tru_ftable;                    -- error
9400 ERROR:  foreign table "tru_ftable" does not allow truncates
9401 ALTER FOREIGN TABLE tru_ftable OPTIONS (SET truncatable 'true');
9402 TRUNCATE tru_ftable;                    -- accepted
9403 -- partitioned table with both local and foreign tables as partitions
9404 SELECT sum(id) FROM tru_ptable;        -- 155
9405  sum 
9406 -----
9407  155
9408 (1 row)
9410 TRUNCATE tru_ptable;
9411 SELECT count(*) FROM tru_ptable;                -- 0
9412  count 
9413 -------
9414      0
9415 (1 row)
9417 SELECT count(*) FROM tru_ptable__p0;    -- 0
9418  count 
9419 -------
9420      0
9421 (1 row)
9423 SELECT count(*) FROM tru_ftable__p1;    -- 0
9424  count 
9425 -------
9426      0
9427 (1 row)
9429 SELECT count(*) FROM tru_rtable1;               -- 0
9430  count 
9431 -------
9432      0
9433 (1 row)
9435 -- 'CASCADE' option
9436 SELECT sum(id) FROM tru_pk_ftable;      -- 55
9437  sum 
9438 -----
9439   55
9440 (1 row)
9442 TRUNCATE tru_pk_ftable; -- failed by FK reference
9443 ERROR:  cannot truncate a table referenced in a foreign key constraint
9444 DETAIL:  Table "tru_fk_table" references "tru_pk_table".
9445 HINT:  Truncate table "tru_fk_table" at the same time, or use TRUNCATE ... CASCADE.
9446 CONTEXT:  remote SQL command: TRUNCATE public.tru_pk_table CONTINUE IDENTITY RESTRICT
9447 TRUNCATE tru_pk_ftable CASCADE;
9448 SELECT count(*) FROM tru_pk_ftable;    -- 0
9449  count 
9450 -------
9451      0
9452 (1 row)
9454 SELECT count(*) FROM tru_fk_table;              -- also truncated,0
9455  count 
9456 -------
9457      0
9458 (1 row)
9460 -- truncate two tables at a command
9461 INSERT INTO tru_ftable (SELECT x FROM generate_series(1,8) x);
9462 INSERT INTO tru_pk_ftable (SELECT x FROM generate_series(3,10) x);
9463 SELECT count(*) from tru_ftable; -- 8
9464  count 
9465 -------
9466      8
9467 (1 row)
9469 SELECT count(*) from tru_pk_ftable; -- 8
9470  count 
9471 -------
9472      8
9473 (1 row)
9475 TRUNCATE tru_ftable, tru_pk_ftable CASCADE;
9476 SELECT count(*) from tru_ftable; -- 0
9477  count 
9478 -------
9479      0
9480 (1 row)
9482 SELECT count(*) from tru_pk_ftable; -- 0
9483  count 
9484 -------
9485      0
9486 (1 row)
9488 -- truncate with ONLY clause
9489 -- Since ONLY is specified, the table tru_ftable_child that inherits
9490 -- tru_ftable_parent locally is not truncated.
9491 TRUNCATE ONLY tru_ftable_parent;
9492 SELECT sum(id) FROM tru_ftable_parent;  -- 126
9493  sum 
9494 -----
9495  126
9496 (1 row)
9498 TRUNCATE tru_ftable_parent;
9499 SELECT count(*) FROM tru_ftable_parent; -- 0
9500  count 
9501 -------
9502      0
9503 (1 row)
9505 -- in case when remote table has inherited children
9506 CREATE TABLE tru_rtable0_child () INHERITS (tru_rtable0);
9507 INSERT INTO tru_rtable0 (SELECT x FROM generate_series(5,9) x);
9508 INSERT INTO tru_rtable0_child (SELECT x FROM generate_series(10,14) x);
9509 SELECT sum(id) FROM tru_ftable;   -- 95
9510  sum 
9511 -----
9512   95
9513 (1 row)
9515 -- Both parent and child tables in the foreign server are truncated
9516 -- even though ONLY is specified because ONLY has no effect
9517 -- when truncating a foreign table.
9518 TRUNCATE ONLY tru_ftable;
9519 SELECT count(*) FROM tru_ftable;   -- 0
9520  count 
9521 -------
9522      0
9523 (1 row)
9525 INSERT INTO tru_rtable0 (SELECT x FROM generate_series(21,25) x);
9526 INSERT INTO tru_rtable0_child (SELECT x FROM generate_series(26,30) x);
9527 SELECT sum(id) FROM tru_ftable;         -- 255
9528  sum 
9529 -----
9530  255
9531 (1 row)
9533 TRUNCATE tru_ftable;                    -- truncate both of parent and child
9534 SELECT count(*) FROM tru_ftable;    -- 0
9535  count 
9536 -------
9537      0
9538 (1 row)
9540 -- cleanup
9541 DROP FOREIGN TABLE tru_ftable_parent, tru_ftable_child, tru_pk_ftable,tru_ftable__p1,tru_ftable;
9542 DROP TABLE tru_rtable0, tru_rtable1, tru_ptable, tru_ptable__p0, tru_pk_table, tru_fk_table,
9543 tru_rtable_parent,tru_rtable_child, tru_rtable0_child;
9544 -- ===================================================================
9545 -- test IMPORT FOREIGN SCHEMA
9546 -- ===================================================================
9547 CREATE SCHEMA import_source;
9548 CREATE TABLE import_source.t1 (c1 int, c2 varchar NOT NULL);
9549 CREATE TABLE import_source.t2 (c1 int default 42, c2 varchar NULL, c3 text collate "POSIX");
9550 CREATE TYPE typ1 AS (m1 int, m2 varchar);
9551 CREATE TABLE import_source.t3 (c1 timestamptz default now(), c2 typ1);
9552 CREATE TABLE import_source."x 4" (c1 float8, "C 2" text, c3 varchar(42));
9553 CREATE TABLE import_source."x 5" (c1 float8);
9554 ALTER TABLE import_source."x 5" DROP COLUMN c1;
9555 CREATE TABLE import_source."x 6" (c1 int, c2 int generated always as (c1 * 2) stored);
9556 CREATE TABLE import_source.t4 (c1 int) PARTITION BY RANGE (c1);
9557 CREATE TABLE import_source.t4_part PARTITION OF import_source.t4
9558   FOR VALUES FROM (1) TO (100);
9559 CREATE TABLE import_source.t4_part2 PARTITION OF import_source.t4
9560   FOR VALUES FROM (100) TO (200);
9561 CREATE SCHEMA import_dest1;
9562 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest1;
9563 \det+ import_dest1.*
9564                                      List of foreign tables
9565     Schema    | Table |  Server  |                   FDW options                   | Description 
9566 --------------+-------+----------+-------------------------------------------------+-------------
9567  import_dest1 | t1    | loopback | (schema_name 'import_source', table_name 't1')  | 
9568  import_dest1 | t2    | loopback | (schema_name 'import_source', table_name 't2')  | 
9569  import_dest1 | t3    | loopback | (schema_name 'import_source', table_name 't3')  | 
9570  import_dest1 | t4    | loopback | (schema_name 'import_source', table_name 't4')  | 
9571  import_dest1 | x 4   | loopback | (schema_name 'import_source', table_name 'x 4') | 
9572  import_dest1 | x 5   | loopback | (schema_name 'import_source', table_name 'x 5') | 
9573  import_dest1 | x 6   | loopback | (schema_name 'import_source', table_name 'x 6') | 
9574 (7 rows)
9576 \d import_dest1.*
9577                          Foreign table "import_dest1.t1"
9578  Column |       Type        | Collation | Nullable | Default |    FDW options     
9579 --------+-------------------+-----------+----------+---------+--------------------
9580  c1     | integer           |           |          |         | (column_name 'c1')
9581  c2     | character varying |           | not null |         | (column_name 'c2')
9582 Server: loopback
9583 FDW options: (schema_name 'import_source', table_name 't1')
9585                          Foreign table "import_dest1.t2"
9586  Column |       Type        | Collation | Nullable | Default |    FDW options     
9587 --------+-------------------+-----------+----------+---------+--------------------
9588  c1     | integer           |           |          |         | (column_name 'c1')
9589  c2     | character varying |           |          |         | (column_name 'c2')
9590  c3     | text              | POSIX     |          |         | (column_name 'c3')
9591 Server: loopback
9592 FDW options: (schema_name 'import_source', table_name 't2')
9594                              Foreign table "import_dest1.t3"
9595  Column |           Type           | Collation | Nullable | Default |    FDW options     
9596 --------+--------------------------+-----------+----------+---------+--------------------
9597  c1     | timestamp with time zone |           |          |         | (column_name 'c1')
9598  c2     | typ1                     |           |          |         | (column_name 'c2')
9599 Server: loopback
9600 FDW options: (schema_name 'import_source', table_name 't3')
9602                     Foreign table "import_dest1.t4"
9603  Column |  Type   | Collation | Nullable | Default |    FDW options     
9604 --------+---------+-----------+----------+---------+--------------------
9605  c1     | integer |           |          |         | (column_name 'c1')
9606 Server: loopback
9607 FDW options: (schema_name 'import_source', table_name 't4')
9609                            Foreign table "import_dest1.x 4"
9610  Column |         Type          | Collation | Nullable | Default |     FDW options     
9611 --------+-----------------------+-----------+----------+---------+---------------------
9612  c1     | double precision      |           |          |         | (column_name 'c1')
9613  C 2    | text                  |           |          |         | (column_name 'C 2')
9614  c3     | character varying(42) |           |          |         | (column_name 'c3')
9615 Server: loopback
9616 FDW options: (schema_name 'import_source', table_name 'x 4')
9618                Foreign table "import_dest1.x 5"
9619  Column | Type | Collation | Nullable | Default | FDW options 
9620 --------+------+-----------+----------+---------+-------------
9621 Server: loopback
9622 FDW options: (schema_name 'import_source', table_name 'x 5')
9624                                   Foreign table "import_dest1.x 6"
9625  Column |  Type   | Collation | Nullable |               Default               |    FDW options     
9626 --------+---------+-----------+----------+-------------------------------------+--------------------
9627  c1     | integer |           |          |                                     | (column_name 'c1')
9628  c2     | integer |           |          | generated always as (c1 * 2) stored | (column_name 'c2')
9629 Server: loopback
9630 FDW options: (schema_name 'import_source', table_name 'x 6')
9632 -- Options
9633 CREATE SCHEMA import_dest2;
9634 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest2
9635   OPTIONS (import_default 'true');
9636 \det+ import_dest2.*
9637                                      List of foreign tables
9638     Schema    | Table |  Server  |                   FDW options                   | Description 
9639 --------------+-------+----------+-------------------------------------------------+-------------
9640  import_dest2 | t1    | loopback | (schema_name 'import_source', table_name 't1')  | 
9641  import_dest2 | t2    | loopback | (schema_name 'import_source', table_name 't2')  | 
9642  import_dest2 | t3    | loopback | (schema_name 'import_source', table_name 't3')  | 
9643  import_dest2 | t4    | loopback | (schema_name 'import_source', table_name 't4')  | 
9644  import_dest2 | x 4   | loopback | (schema_name 'import_source', table_name 'x 4') | 
9645  import_dest2 | x 5   | loopback | (schema_name 'import_source', table_name 'x 5') | 
9646  import_dest2 | x 6   | loopback | (schema_name 'import_source', table_name 'x 6') | 
9647 (7 rows)
9649 \d import_dest2.*
9650                          Foreign table "import_dest2.t1"
9651  Column |       Type        | Collation | Nullable | Default |    FDW options     
9652 --------+-------------------+-----------+----------+---------+--------------------
9653  c1     | integer           |           |          |         | (column_name 'c1')
9654  c2     | character varying |           | not null |         | (column_name 'c2')
9655 Server: loopback
9656 FDW options: (schema_name 'import_source', table_name 't1')
9658                          Foreign table "import_dest2.t2"
9659  Column |       Type        | Collation | Nullable | Default |    FDW options     
9660 --------+-------------------+-----------+----------+---------+--------------------
9661  c1     | integer           |           |          | 42      | (column_name 'c1')
9662  c2     | character varying |           |          |         | (column_name 'c2')
9663  c3     | text              | POSIX     |          |         | (column_name 'c3')
9664 Server: loopback
9665 FDW options: (schema_name 'import_source', table_name 't2')
9667                              Foreign table "import_dest2.t3"
9668  Column |           Type           | Collation | Nullable | Default |    FDW options     
9669 --------+--------------------------+-----------+----------+---------+--------------------
9670  c1     | timestamp with time zone |           |          | now()   | (column_name 'c1')
9671  c2     | typ1                     |           |          |         | (column_name 'c2')
9672 Server: loopback
9673 FDW options: (schema_name 'import_source', table_name 't3')
9675                     Foreign table "import_dest2.t4"
9676  Column |  Type   | Collation | Nullable | Default |    FDW options     
9677 --------+---------+-----------+----------+---------+--------------------
9678  c1     | integer |           |          |         | (column_name 'c1')
9679 Server: loopback
9680 FDW options: (schema_name 'import_source', table_name 't4')
9682                            Foreign table "import_dest2.x 4"
9683  Column |         Type          | Collation | Nullable | Default |     FDW options     
9684 --------+-----------------------+-----------+----------+---------+---------------------
9685  c1     | double precision      |           |          |         | (column_name 'c1')
9686  C 2    | text                  |           |          |         | (column_name 'C 2')
9687  c3     | character varying(42) |           |          |         | (column_name 'c3')
9688 Server: loopback
9689 FDW options: (schema_name 'import_source', table_name 'x 4')
9691                Foreign table "import_dest2.x 5"
9692  Column | Type | Collation | Nullable | Default | FDW options 
9693 --------+------+-----------+----------+---------+-------------
9694 Server: loopback
9695 FDW options: (schema_name 'import_source', table_name 'x 5')
9697                                   Foreign table "import_dest2.x 6"
9698  Column |  Type   | Collation | Nullable |               Default               |    FDW options     
9699 --------+---------+-----------+----------+-------------------------------------+--------------------
9700  c1     | integer |           |          |                                     | (column_name 'c1')
9701  c2     | integer |           |          | generated always as (c1 * 2) stored | (column_name 'c2')
9702 Server: loopback
9703 FDW options: (schema_name 'import_source', table_name 'x 6')
9705 CREATE SCHEMA import_dest3;
9706 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest3
9707   OPTIONS (import_collate 'false', import_generated 'false', import_not_null 'false');
9708 \det+ import_dest3.*
9709                                      List of foreign tables
9710     Schema    | Table |  Server  |                   FDW options                   | Description 
9711 --------------+-------+----------+-------------------------------------------------+-------------
9712  import_dest3 | t1    | loopback | (schema_name 'import_source', table_name 't1')  | 
9713  import_dest3 | t2    | loopback | (schema_name 'import_source', table_name 't2')  | 
9714  import_dest3 | t3    | loopback | (schema_name 'import_source', table_name 't3')  | 
9715  import_dest3 | t4    | loopback | (schema_name 'import_source', table_name 't4')  | 
9716  import_dest3 | x 4   | loopback | (schema_name 'import_source', table_name 'x 4') | 
9717  import_dest3 | x 5   | loopback | (schema_name 'import_source', table_name 'x 5') | 
9718  import_dest3 | x 6   | loopback | (schema_name 'import_source', table_name 'x 6') | 
9719 (7 rows)
9721 \d import_dest3.*
9722                          Foreign table "import_dest3.t1"
9723  Column |       Type        | Collation | Nullable | Default |    FDW options     
9724 --------+-------------------+-----------+----------+---------+--------------------
9725  c1     | integer           |           |          |         | (column_name 'c1')
9726  c2     | character varying |           |          |         | (column_name 'c2')
9727 Server: loopback
9728 FDW options: (schema_name 'import_source', table_name 't1')
9730                          Foreign table "import_dest3.t2"
9731  Column |       Type        | Collation | Nullable | Default |    FDW options     
9732 --------+-------------------+-----------+----------+---------+--------------------
9733  c1     | integer           |           |          |         | (column_name 'c1')
9734  c2     | character varying |           |          |         | (column_name 'c2')
9735  c3     | text              |           |          |         | (column_name 'c3')
9736 Server: loopback
9737 FDW options: (schema_name 'import_source', table_name 't2')
9739                              Foreign table "import_dest3.t3"
9740  Column |           Type           | Collation | Nullable | Default |    FDW options     
9741 --------+--------------------------+-----------+----------+---------+--------------------
9742  c1     | timestamp with time zone |           |          |         | (column_name 'c1')
9743  c2     | typ1                     |           |          |         | (column_name 'c2')
9744 Server: loopback
9745 FDW options: (schema_name 'import_source', table_name 't3')
9747                     Foreign table "import_dest3.t4"
9748  Column |  Type   | Collation | Nullable | Default |    FDW options     
9749 --------+---------+-----------+----------+---------+--------------------
9750  c1     | integer |           |          |         | (column_name 'c1')
9751 Server: loopback
9752 FDW options: (schema_name 'import_source', table_name 't4')
9754                            Foreign table "import_dest3.x 4"
9755  Column |         Type          | Collation | Nullable | Default |     FDW options     
9756 --------+-----------------------+-----------+----------+---------+---------------------
9757  c1     | double precision      |           |          |         | (column_name 'c1')
9758  C 2    | text                  |           |          |         | (column_name 'C 2')
9759  c3     | character varying(42) |           |          |         | (column_name 'c3')
9760 Server: loopback
9761 FDW options: (schema_name 'import_source', table_name 'x 4')
9763                Foreign table "import_dest3.x 5"
9764  Column | Type | Collation | Nullable | Default | FDW options 
9765 --------+------+-----------+----------+---------+-------------
9766 Server: loopback
9767 FDW options: (schema_name 'import_source', table_name 'x 5')
9769                     Foreign table "import_dest3.x 6"
9770  Column |  Type   | Collation | Nullable | Default |    FDW options     
9771 --------+---------+-----------+----------+---------+--------------------
9772  c1     | integer |           |          |         | (column_name 'c1')
9773  c2     | integer |           |          |         | (column_name 'c2')
9774 Server: loopback
9775 FDW options: (schema_name 'import_source', table_name 'x 6')
9777 -- Check LIMIT TO and EXCEPT
9778 CREATE SCHEMA import_dest4;
9779 IMPORT FOREIGN SCHEMA import_source LIMIT TO (t1, nonesuch, t4_part)
9780   FROM SERVER loopback INTO import_dest4;
9781 \det+ import_dest4.*
9782                                         List of foreign tables
9783     Schema    |  Table  |  Server  |                     FDW options                     | Description 
9784 --------------+---------+----------+-----------------------------------------------------+-------------
9785  import_dest4 | t1      | loopback | (schema_name 'import_source', table_name 't1')      | 
9786  import_dest4 | t4_part | loopback | (schema_name 'import_source', table_name 't4_part') | 
9787 (2 rows)
9789 IMPORT FOREIGN SCHEMA import_source EXCEPT (t1, "x 4", nonesuch, t4_part)
9790   FROM SERVER loopback INTO import_dest4;
9791 \det+ import_dest4.*
9792                                         List of foreign tables
9793     Schema    |  Table  |  Server  |                     FDW options                     | Description 
9794 --------------+---------+----------+-----------------------------------------------------+-------------
9795  import_dest4 | t1      | loopback | (schema_name 'import_source', table_name 't1')      | 
9796  import_dest4 | t2      | loopback | (schema_name 'import_source', table_name 't2')      | 
9797  import_dest4 | t3      | loopback | (schema_name 'import_source', table_name 't3')      | 
9798  import_dest4 | t4      | loopback | (schema_name 'import_source', table_name 't4')      | 
9799  import_dest4 | t4_part | loopback | (schema_name 'import_source', table_name 't4_part') | 
9800  import_dest4 | x 5     | loopback | (schema_name 'import_source', table_name 'x 5')     | 
9801  import_dest4 | x 6     | loopback | (schema_name 'import_source', table_name 'x 6')     | 
9802 (7 rows)
9804 -- Assorted error cases
9805 IMPORT FOREIGN SCHEMA import_source FROM SERVER loopback INTO import_dest4;
9806 ERROR:  relation "t1" already exists
9807 CONTEXT:  importing foreign table "t1"
9808 IMPORT FOREIGN SCHEMA nonesuch FROM SERVER loopback INTO import_dest4;
9809 ERROR:  schema "nonesuch" is not present on foreign server "loopback"
9810 IMPORT FOREIGN SCHEMA nonesuch FROM SERVER loopback INTO notthere;
9811 ERROR:  schema "notthere" does not exist
9812 IMPORT FOREIGN SCHEMA nonesuch FROM SERVER nowhere INTO notthere;
9813 ERROR:  server "nowhere" does not exist
9814 -- Check case of a type present only on the remote server.
9815 -- We can fake this by dropping the type locally in our transaction.
9816 CREATE TYPE "Colors" AS ENUM ('red', 'green', 'blue');
9817 CREATE TABLE import_source.t5 (c1 int, c2 text collate "C", "Col" "Colors");
9818 CREATE SCHEMA import_dest5;
9819 BEGIN;
9820 DROP TYPE "Colors" CASCADE;
9821 NOTICE:  drop cascades to column Col of table import_source.t5
9822 IMPORT FOREIGN SCHEMA import_source LIMIT TO (t5)
9823   FROM SERVER loopback INTO import_dest5;  -- ERROR
9824 ERROR:  type "public.Colors" does not exist
9825 LINE 4:   "Col" public."Colors" OPTIONS (column_name 'Col')
9826                 ^
9827 QUERY:  CREATE FOREIGN TABLE t5 (
9828   c1 integer OPTIONS (column_name 'c1'),
9829   c2 text OPTIONS (column_name 'c2') COLLATE pg_catalog."C",
9830   "Col" public."Colors" OPTIONS (column_name 'Col')
9831 ) SERVER loopback
9832 OPTIONS (schema_name 'import_source', table_name 't5');
9833 CONTEXT:  importing foreign table "t5"
9834 ROLLBACK;
9835 BEGIN;
9836 CREATE SERVER fetch101 FOREIGN DATA WRAPPER postgres_fdw OPTIONS( fetch_size '101' );
9837 SELECT count(*)
9838 FROM pg_foreign_server
9839 WHERE srvname = 'fetch101'
9840 AND srvoptions @> array['fetch_size=101'];
9841  count 
9842 -------
9843      1
9844 (1 row)
9846 ALTER SERVER fetch101 OPTIONS( SET fetch_size '202' );
9847 SELECT count(*)
9848 FROM pg_foreign_server
9849 WHERE srvname = 'fetch101'
9850 AND srvoptions @> array['fetch_size=101'];
9851  count 
9852 -------
9853      0
9854 (1 row)
9856 SELECT count(*)
9857 FROM pg_foreign_server
9858 WHERE srvname = 'fetch101'
9859 AND srvoptions @> array['fetch_size=202'];
9860  count 
9861 -------
9862      1
9863 (1 row)
9865 CREATE FOREIGN TABLE table30000 ( x int ) SERVER fetch101 OPTIONS ( fetch_size '30000' );
9866 SELECT COUNT(*)
9867 FROM pg_foreign_table
9868 WHERE ftrelid = 'table30000'::regclass
9869 AND ftoptions @> array['fetch_size=30000'];
9870  count 
9871 -------
9872      1
9873 (1 row)
9875 ALTER FOREIGN TABLE table30000 OPTIONS ( SET fetch_size '60000');
9876 SELECT COUNT(*)
9877 FROM pg_foreign_table
9878 WHERE ftrelid = 'table30000'::regclass
9879 AND ftoptions @> array['fetch_size=30000'];
9880  count 
9881 -------
9882      0
9883 (1 row)
9885 SELECT COUNT(*)
9886 FROM pg_foreign_table
9887 WHERE ftrelid = 'table30000'::regclass
9888 AND ftoptions @> array['fetch_size=60000'];
9889  count 
9890 -------
9891      1
9892 (1 row)
9894 ROLLBACK;
9895 -- ===================================================================
9896 -- test partitionwise joins
9897 -- ===================================================================
9898 SET enable_partitionwise_join=on;
9899 CREATE TABLE fprt1 (a int, b int, c varchar) PARTITION BY RANGE(a);
9900 CREATE TABLE fprt1_p1 (LIKE fprt1);
9901 CREATE TABLE fprt1_p2 (LIKE fprt1);
9902 ALTER TABLE fprt1_p1 SET (autovacuum_enabled = 'false');
9903 ALTER TABLE fprt1_p2 SET (autovacuum_enabled = 'false');
9904 INSERT INTO fprt1_p1 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 249, 2) i;
9905 INSERT INTO fprt1_p2 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(250, 499, 2) i;
9906 CREATE FOREIGN TABLE ftprt1_p1 PARTITION OF fprt1 FOR VALUES FROM (0) TO (250)
9907         SERVER loopback OPTIONS (table_name 'fprt1_p1', use_remote_estimate 'true');
9908 CREATE FOREIGN TABLE ftprt1_p2 PARTITION OF fprt1 FOR VALUES FROM (250) TO (500)
9909         SERVER loopback OPTIONS (TABLE_NAME 'fprt1_p2');
9910 ANALYZE fprt1;
9911 ANALYZE fprt1_p1;
9912 ANALYZE fprt1_p2;
9913 CREATE TABLE fprt2 (a int, b int, c varchar) PARTITION BY RANGE(b);
9914 CREATE TABLE fprt2_p1 (LIKE fprt2);
9915 CREATE TABLE fprt2_p2 (LIKE fprt2);
9916 ALTER TABLE fprt2_p1 SET (autovacuum_enabled = 'false');
9917 ALTER TABLE fprt2_p2 SET (autovacuum_enabled = 'false');
9918 INSERT INTO fprt2_p1 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(0, 249, 3) i;
9919 INSERT INTO fprt2_p2 SELECT i, i, to_char(i/50, 'FM0000') FROM generate_series(250, 499, 3) i;
9920 CREATE FOREIGN TABLE ftprt2_p1 (b int, c varchar, a int)
9921         SERVER loopback OPTIONS (table_name 'fprt2_p1', use_remote_estimate 'true');
9922 ALTER TABLE fprt2 ATTACH PARTITION ftprt2_p1 FOR VALUES FROM (0) TO (250);
9923 CREATE FOREIGN TABLE ftprt2_p2 PARTITION OF fprt2 FOR VALUES FROM (250) TO (500)
9924         SERVER loopback OPTIONS (table_name 'fprt2_p2', use_remote_estimate 'true');
9925 ANALYZE fprt2;
9926 ANALYZE fprt2_p1;
9927 ANALYZE fprt2_p2;
9928 -- inner join three tables
9929 EXPLAIN (COSTS OFF)
9930 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;
9931                                              QUERY PLAN                                              
9932 -----------------------------------------------------------------------------------------------------
9933  Sort
9934    Sort Key: t1.a, t3.c
9935    ->  Append
9936          ->  Foreign Scan
9937                Relations: ((ftprt1_p1 t1_1) INNER JOIN (ftprt2_p1 t2_1)) INNER JOIN (ftprt1_p1 t3_1)
9938          ->  Foreign Scan
9939                Relations: ((ftprt1_p2 t1_2) INNER JOIN (ftprt2_p2 t2_2)) INNER JOIN (ftprt1_p2 t3_2)
9940 (7 rows)
9942 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;
9943   a  |  b  |  c   
9944 -----+-----+------
9945    0 |   0 | 0000
9946  150 | 150 | 0003
9947  250 | 250 | 0005
9948  400 | 400 | 0008
9949 (4 rows)
9951 -- left outer join + nullable clause
9952 EXPLAIN (VERBOSE, COSTS OFF)
9953 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;
9954                                                                                                                      QUERY PLAN                                                                                                                     
9955 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
9956  Foreign Scan
9957    Output: t1.a, fprt2.b, fprt2.c
9958    Relations: (public.ftprt1_p1 t1) LEFT JOIN (public.ftprt2_p1 fprt2)
9959    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
9960 (4 rows)
9962 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;
9963  a | b |  c   
9964 ---+---+------
9965  0 | 0 | 0000
9966  2 |   | 
9967  4 |   | 
9968  6 | 6 | 0000
9969  8 |   | 
9970 (5 rows)
9972 -- with whole-row reference; partitionwise join does not apply
9973 EXPLAIN (COSTS OFF)
9974 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;
9975                        QUERY PLAN                       
9976 --------------------------------------------------------
9977  Sort
9978    Sort Key: ((t1.*)::fprt1), ((t2.*)::fprt2)
9979    ->  Hash Full Join
9980          Hash Cond: (t1.a = t2.b)
9981          ->  Append
9982                ->  Foreign Scan on ftprt1_p1 t1_1
9983                ->  Foreign Scan on ftprt1_p2 t1_2
9984          ->  Hash
9985                ->  Append
9986                      ->  Foreign Scan on ftprt2_p1 t2_1
9987                      ->  Foreign Scan on ftprt2_p2 t2_2
9988 (11 rows)
9990 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;
9991        wr       |       wr       
9992 ----------------+----------------
9993  (0,0,0000)     | (0,0,0000)
9994  (50,50,0001)   | 
9995  (100,100,0002) | 
9996  (150,150,0003) | (150,150,0003)
9997  (200,200,0004) | 
9998  (250,250,0005) | (250,250,0005)
9999  (300,300,0006) | 
10000  (350,350,0007) | 
10001  (400,400,0008) | (400,400,0008)
10002  (450,450,0009) | 
10003                 | (75,75,0001)
10004                 | (225,225,0004)
10005                 | (325,325,0006)
10006                 | (475,475,0009)
10007 (14 rows)
10009 -- join with lateral reference
10010 EXPLAIN (COSTS OFF)
10011 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;
10012                               QUERY PLAN                               
10013 -----------------------------------------------------------------------
10014  Sort
10015    Sort Key: t1.a, t1.b
10016    ->  Append
10017          ->  Foreign Scan
10018                Relations: (ftprt1_p1 t1_1) INNER JOIN (ftprt2_p1 t2_1)
10019          ->  Foreign Scan
10020                Relations: (ftprt1_p2 t1_2) INNER JOIN (ftprt2_p2 t2_2)
10021 (7 rows)
10023 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;
10024   a  |  b  
10025 -----+-----
10026    0 |   0
10027  150 | 150
10028  250 | 250
10029  400 | 400
10030 (4 rows)
10032 -- with PHVs, partitionwise join selected but no join pushdown
10033 EXPLAIN (COSTS OFF)
10034 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;
10035                         QUERY PLAN                         
10036 -----------------------------------------------------------
10037  Sort
10038    Sort Key: fprt1.a, fprt2.b
10039    ->  Append
10040          ->  Hash Full Join
10041                Hash Cond: (fprt1_1.a = fprt2_1.b)
10042                ->  Foreign Scan on ftprt1_p1 fprt1_1
10043                ->  Hash
10044                      ->  Foreign Scan on ftprt2_p1 fprt2_1
10045          ->  Hash Full Join
10046                Hash Cond: (fprt1_2.a = fprt2_2.b)
10047                ->  Foreign Scan on ftprt1_p2 fprt1_2
10048                ->  Hash
10049                      ->  Foreign Scan on ftprt2_p2 fprt2_2
10050 (13 rows)
10052 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;
10053   a  |  phv   |  b  |  phv   
10054 -----+--------+-----+--------
10055    0 | t1_phv |   0 | t2_phv
10056   50 | t1_phv |     | 
10057  100 | t1_phv |     | 
10058  150 | t1_phv | 150 | t2_phv
10059  200 | t1_phv |     | 
10060  250 | t1_phv | 250 | t2_phv
10061  300 | t1_phv |     | 
10062  350 | t1_phv |     | 
10063  400 | t1_phv | 400 | t2_phv
10064  450 | t1_phv |     | 
10065      |        |  75 | t2_phv
10066      |        | 225 | t2_phv
10067      |        | 325 | t2_phv
10068      |        | 475 | t2_phv
10069 (14 rows)
10071 -- test FOR UPDATE; partitionwise join does not apply
10072 EXPLAIN (COSTS OFF)
10073 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;
10074                        QUERY PLAN                       
10075 --------------------------------------------------------
10076  LockRows
10077    ->  Nested Loop
10078          Join Filter: (t1.a = t2.b)
10079          ->  Append
10080                ->  Foreign Scan on ftprt1_p1 t1_1
10081                ->  Foreign Scan on ftprt1_p2 t1_2
10082          ->  Materialize
10083                ->  Append
10084                      ->  Foreign Scan on ftprt2_p1 t2_1
10085                      ->  Foreign Scan on ftprt2_p2 t2_2
10086 (10 rows)
10088 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;
10089   a  |  b  
10090 -----+-----
10091    0 |   0
10092  150 | 150
10093  250 | 250
10094  400 | 400
10095 (4 rows)
10097 RESET enable_partitionwise_join;
10098 -- ===================================================================
10099 -- test partitionwise aggregates
10100 -- ===================================================================
10101 CREATE TABLE pagg_tab (a int, b int, c text) PARTITION BY RANGE(a);
10102 CREATE TABLE pagg_tab_p1 (LIKE pagg_tab);
10103 CREATE TABLE pagg_tab_p2 (LIKE pagg_tab);
10104 CREATE TABLE pagg_tab_p3 (LIKE pagg_tab);
10105 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;
10106 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;
10107 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;
10108 -- Create foreign partitions
10109 CREATE FOREIGN TABLE fpagg_tab_p1 PARTITION OF pagg_tab FOR VALUES FROM (0) TO (10) SERVER loopback OPTIONS (table_name 'pagg_tab_p1');
10110 CREATE FOREIGN TABLE fpagg_tab_p2 PARTITION OF pagg_tab FOR VALUES FROM (10) TO (20) SERVER loopback OPTIONS (table_name 'pagg_tab_p2');
10111 CREATE FOREIGN TABLE fpagg_tab_p3 PARTITION OF pagg_tab FOR VALUES FROM (20) TO (30) SERVER loopback OPTIONS (table_name 'pagg_tab_p3');
10112 ANALYZE pagg_tab;
10113 ANALYZE fpagg_tab_p1;
10114 ANALYZE fpagg_tab_p2;
10115 ANALYZE fpagg_tab_p3;
10116 -- When GROUP BY clause matches with PARTITION KEY.
10117 -- Plan with partitionwise aggregates is disabled
10118 SET enable_partitionwise_aggregate TO false;
10119 EXPLAIN (COSTS OFF)
10120 SELECT a, sum(b), min(b), count(*) FROM pagg_tab GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
10121                      QUERY PLAN                      
10122 -----------------------------------------------------
10123  GroupAggregate
10124    Group Key: pagg_tab.a
10125    Filter: (avg(pagg_tab.b) < '22'::numeric)
10126    ->  Append
10127          ->  Foreign Scan on fpagg_tab_p1 pagg_tab_1
10128          ->  Foreign Scan on fpagg_tab_p2 pagg_tab_2
10129          ->  Foreign Scan on fpagg_tab_p3 pagg_tab_3
10130 (7 rows)
10132 -- Plan with partitionwise aggregates is enabled
10133 SET enable_partitionwise_aggregate TO true;
10134 EXPLAIN (COSTS OFF)
10135 SELECT a, sum(b), min(b), count(*) FROM pagg_tab GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
10136                            QUERY PLAN                            
10137 -----------------------------------------------------------------
10138  Sort
10139    Sort Key: pagg_tab.a
10140    ->  Append
10141          ->  Foreign Scan
10142                Relations: Aggregate on (fpagg_tab_p1 pagg_tab)
10143          ->  Foreign Scan
10144                Relations: Aggregate on (fpagg_tab_p2 pagg_tab_1)
10145          ->  Foreign Scan
10146                Relations: Aggregate on (fpagg_tab_p3 pagg_tab_2)
10147 (9 rows)
10149 SELECT a, sum(b), min(b), count(*) FROM pagg_tab GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
10150  a  | sum  | min | count 
10151 ----+------+-----+-------
10152   0 | 2000 |   0 |   100
10153   1 | 2100 |   1 |   100
10154  10 | 2000 |   0 |   100
10155  11 | 2100 |   1 |   100
10156  20 | 2000 |   0 |   100
10157  21 | 2100 |   1 |   100
10158 (6 rows)
10160 -- Check with whole-row reference
10161 -- Should have all the columns in the target list for the given relation
10162 EXPLAIN (VERBOSE, COSTS OFF)
10163 SELECT a, count(t1) FROM pagg_tab t1 GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
10164                                          QUERY PLAN                                         
10165 --------------------------------------------------------------------------------------------
10166  Merge Append
10167    Sort Key: t1.a
10168    ->  GroupAggregate
10169          Output: t1.a, count(((t1.*)::pagg_tab))
10170          Group Key: t1.a
10171          Filter: (avg(t1.b) < '22'::numeric)
10172          ->  Foreign Scan on public.fpagg_tab_p1 t1
10173                Output: t1.a, t1.*, t1.b
10174                Remote SQL: SELECT a, b, c FROM public.pagg_tab_p1 ORDER BY a ASC NULLS LAST
10175    ->  GroupAggregate
10176          Output: t1_1.a, count(((t1_1.*)::pagg_tab))
10177          Group Key: t1_1.a
10178          Filter: (avg(t1_1.b) < '22'::numeric)
10179          ->  Foreign Scan on public.fpagg_tab_p2 t1_1
10180                Output: t1_1.a, t1_1.*, t1_1.b
10181                Remote SQL: SELECT a, b, c FROM public.pagg_tab_p2 ORDER BY a ASC NULLS LAST
10182    ->  GroupAggregate
10183          Output: t1_2.a, count(((t1_2.*)::pagg_tab))
10184          Group Key: t1_2.a
10185          Filter: (avg(t1_2.b) < '22'::numeric)
10186          ->  Foreign Scan on public.fpagg_tab_p3 t1_2
10187                Output: t1_2.a, t1_2.*, t1_2.b
10188                Remote SQL: SELECT a, b, c FROM public.pagg_tab_p3 ORDER BY a ASC NULLS LAST
10189 (23 rows)
10191 SELECT a, count(t1) FROM pagg_tab t1 GROUP BY a HAVING avg(b) < 22 ORDER BY 1;
10192  a  | count 
10193 ----+-------
10194   0 |   100
10195   1 |   100
10196  10 |   100
10197  11 |   100
10198  20 |   100
10199  21 |   100
10200 (6 rows)
10202 -- When GROUP BY clause does not match with PARTITION KEY.
10203 EXPLAIN (COSTS OFF)
10204 SELECT b, avg(a), max(a), count(*) FROM pagg_tab GROUP BY b HAVING sum(a) < 700 ORDER BY 1;
10205                         QUERY PLAN                         
10206 -----------------------------------------------------------
10207  Finalize GroupAggregate
10208    Group Key: pagg_tab.b
10209    Filter: (sum(pagg_tab.a) < 700)
10210    ->  Merge Append
10211          Sort Key: pagg_tab.b
10212          ->  Partial GroupAggregate
10213                Group Key: pagg_tab.b
10214                ->  Foreign Scan on fpagg_tab_p1 pagg_tab
10215          ->  Partial GroupAggregate
10216                Group Key: pagg_tab_1.b
10217                ->  Foreign Scan on fpagg_tab_p2 pagg_tab_1
10218          ->  Partial GroupAggregate
10219                Group Key: pagg_tab_2.b
10220                ->  Foreign Scan on fpagg_tab_p3 pagg_tab_2
10221 (14 rows)
10223 -- ===================================================================
10224 -- access rights and superuser
10225 -- ===================================================================
10226 -- Non-superuser cannot create a FDW without a password in the connstr
10227 CREATE ROLE regress_nosuper NOSUPERUSER;
10228 GRANT USAGE ON FOREIGN DATA WRAPPER postgres_fdw TO regress_nosuper;
10229 SET ROLE regress_nosuper;
10230 SHOW is_superuser;
10231  is_superuser 
10232 --------------
10233  off
10234 (1 row)
10236 -- This will be OK, we can create the FDW
10237 DO $d$
10238     BEGIN
10239         EXECUTE $$CREATE SERVER loopback_nopw FOREIGN DATA WRAPPER postgres_fdw
10240             OPTIONS (dbname '$$||current_database()||$$',
10241                      port '$$||current_setting('port')||$$'
10242             )$$;
10243     END;
10244 $d$;
10245 -- But creation of user mappings for non-superusers should fail
10246 CREATE USER MAPPING FOR public SERVER loopback_nopw;
10247 CREATE USER MAPPING FOR CURRENT_USER SERVER loopback_nopw;
10248 CREATE FOREIGN TABLE pg_temp.ft1_nopw (
10249         c1 int NOT NULL,
10250         c2 int NOT NULL,
10251         c3 text,
10252         c4 timestamptz,
10253         c5 timestamp,
10254         c6 varchar(10),
10255         c7 char(10) default 'ft1',
10256         c8 user_enum
10257 ) SERVER loopback_nopw OPTIONS (schema_name 'public', table_name 'ft1');
10258 SELECT 1 FROM ft1_nopw LIMIT 1;
10259 ERROR:  password or GSSAPI delegated credentials required
10260 DETAIL:  Non-superusers must delegate GSSAPI credentials or provide a password in the user mapping.
10261 -- If we add a password to the connstr it'll fail, because we don't allow passwords
10262 -- in connstrs only in user mappings.
10263 ALTER SERVER loopback_nopw OPTIONS (ADD password 'dummypw');
10264 ERROR:  invalid option "password"
10265 HINT:  Perhaps you meant the option "passfile".
10266 -- If we add a password for our user mapping instead, we should get a different
10267 -- error because the password wasn't actually *used* when we run with trust auth.
10269 -- This won't work with installcheck, but neither will most of the FDW checks.
10270 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback_nopw OPTIONS (ADD password 'dummypw');
10271 SELECT 1 FROM ft1_nopw LIMIT 1;
10272 ERROR:  password or GSSAPI delegated credentials required
10273 DETAIL:  Non-superuser cannot connect if the server does not request a password or use GSSAPI with delegated credentials.
10274 HINT:  Target server's authentication method must be changed or password_required=false set in the user mapping attributes.
10275 -- Unpriv user cannot make the mapping passwordless
10276 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback_nopw OPTIONS (ADD password_required 'false');
10277 ERROR:  password_required=false is superuser-only
10278 HINT:  User mappings with the password_required option set to false may only be created or modified by the superuser.
10279 SELECT 1 FROM ft1_nopw LIMIT 1;
10280 ERROR:  password or GSSAPI delegated credentials required
10281 DETAIL:  Non-superuser cannot connect if the server does not request a password or use GSSAPI with delegated credentials.
10282 HINT:  Target server's authentication method must be changed or password_required=false set in the user mapping attributes.
10283 RESET ROLE;
10284 -- But the superuser can
10285 ALTER USER MAPPING FOR regress_nosuper SERVER loopback_nopw OPTIONS (ADD password_required 'false');
10286 SET ROLE regress_nosuper;
10287 -- Should finally work now
10288 SELECT 1 FROM ft1_nopw LIMIT 1;
10289  ?column? 
10290 ----------
10291         1
10292 (1 row)
10294 -- unpriv user also cannot set sslcert / sslkey on the user mapping
10295 -- first set password_required so we see the right error messages
10296 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback_nopw OPTIONS (SET password_required 'true');
10297 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback_nopw OPTIONS (ADD sslcert 'foo.crt');
10298 ERROR:  sslcert and sslkey are superuser-only
10299 HINT:  User mappings with the sslcert or sslkey options set may only be created or modified by the superuser.
10300 ALTER USER MAPPING FOR CURRENT_USER SERVER loopback_nopw OPTIONS (ADD sslkey 'foo.key');
10301 ERROR:  sslcert and sslkey are superuser-only
10302 HINT:  User mappings with the sslcert or sslkey options set may only be created or modified by the superuser.
10303 -- We're done with the role named after a specific user and need to check the
10304 -- changes to the public mapping.
10305 DROP USER MAPPING FOR CURRENT_USER SERVER loopback_nopw;
10306 -- This will fail again as it'll resolve the user mapping for public, which
10307 -- lacks password_required=false
10308 SELECT 1 FROM ft1_nopw LIMIT 1;
10309 ERROR:  password or GSSAPI delegated credentials required
10310 DETAIL:  Non-superusers must delegate GSSAPI credentials or provide a password in the user mapping.
10311 RESET ROLE;
10312 -- The user mapping for public is passwordless and lacks the password_required=false
10313 -- mapping option, but will work because the current user is a superuser.
10314 SELECT 1 FROM ft1_nopw LIMIT 1;
10315  ?column? 
10316 ----------
10317         1
10318 (1 row)
10320 -- cleanup
10321 DROP USER MAPPING FOR public SERVER loopback_nopw;
10322 DROP OWNED BY regress_nosuper;
10323 DROP ROLE regress_nosuper;
10324 -- Clean-up
10325 RESET enable_partitionwise_aggregate;
10326 -- Two-phase transactions are not supported.
10327 BEGIN;
10328 SELECT count(*) FROM ft1;
10329  count 
10330 -------
10331    822
10332 (1 row)
10334 -- error here
10335 PREPARE TRANSACTION 'fdw_tpc';
10336 ERROR:  cannot PREPARE a transaction that has operated on postgres_fdw foreign tables
10337 ROLLBACK;
10338 WARNING:  there is no transaction in progress
10339 -- ===================================================================
10340 -- reestablish new connection
10341 -- ===================================================================
10342 -- Change application_name of remote connection to special one
10343 -- so that we can easily terminate the connection later.
10344 ALTER SERVER loopback OPTIONS (application_name 'fdw_retry_check');
10345 -- Make sure we have a remote connection.
10346 SELECT 1 FROM ft1 LIMIT 1;
10347  ?column? 
10348 ----------
10349         1
10350 (1 row)
10352 -- Terminate the remote connection and wait for the termination to complete.
10353 -- (If a cache flush happens, the remote connection might have already been
10354 -- dropped; so code this step in a way that doesn't fail if no connection.)
10355 DO $$ BEGIN
10356 PERFORM pg_terminate_backend(pid, 180000) FROM pg_stat_activity
10357         WHERE application_name = 'fdw_retry_check';
10358 END $$;
10359 -- This query should detect the broken connection when starting new remote
10360 -- transaction, reestablish new connection, and then succeed.
10361 BEGIN;
10362 SELECT 1 FROM ft1 LIMIT 1;
10363  ?column? 
10364 ----------
10365         1
10366 (1 row)
10368 -- If we detect the broken connection when starting a new remote
10369 -- subtransaction, we should fail instead of establishing a new connection.
10370 -- Terminate the remote connection and wait for the termination to complete.
10371 DO $$ BEGIN
10372 PERFORM pg_terminate_backend(pid, 180000) FROM pg_stat_activity
10373         WHERE application_name = 'fdw_retry_check';
10374 END $$;
10375 SAVEPOINT s;
10376 -- The text of the error might vary across platforms, so only show SQLSTATE.
10377 \set VERBOSITY sqlstate
10378 SELECT 1 FROM ft1 LIMIT 1;    -- should fail
10379 ERROR:  08006
10380 \set VERBOSITY default
10381 COMMIT;
10382 -- =============================================================================
10383 -- test connection invalidation cases and postgres_fdw_get_connections function
10384 -- =============================================================================
10385 -- Let's ensure to close all the existing cached connections.
10386 SELECT 1 FROM postgres_fdw_disconnect_all();
10387  ?column? 
10388 ----------
10389         1
10390 (1 row)
10392 -- No cached connections, so no records should be output.
10393 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10394  server_name 
10395 -------------
10396 (0 rows)
10398 -- This test case is for closing the connection in pgfdw_xact_callback
10399 BEGIN;
10400 -- Connection xact depth becomes 1 i.e. the connection is in midst of the xact.
10401 SELECT 1 FROM ft1 LIMIT 1;
10402  ?column? 
10403 ----------
10404         1
10405 (1 row)
10407 SELECT 1 FROM ft7 LIMIT 1;
10408  ?column? 
10409 ----------
10410         1
10411 (1 row)
10413 -- List all the existing cached connections. loopback and loopback3 should be
10414 -- output.
10415 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10416  server_name 
10417 -------------
10418  loopback
10419  loopback3
10420 (2 rows)
10422 -- Connections are not closed at the end of the alter and drop statements.
10423 -- That's because the connections are in midst of this xact,
10424 -- they are just marked as invalid in pgfdw_inval_callback.
10425 ALTER SERVER loopback OPTIONS (ADD use_remote_estimate 'off');
10426 DROP SERVER loopback3 CASCADE;
10427 NOTICE:  drop cascades to 2 other objects
10428 DETAIL:  drop cascades to user mapping for public on server loopback3
10429 drop cascades to foreign table ft7
10430 -- List all the existing cached connections. loopback and loopback3
10431 -- should be output as invalid connections. Also the server name for
10432 -- loopback3 should be NULL because the server was dropped.
10433 SELECT * FROM postgres_fdw_get_connections() ORDER BY 1;
10434  server_name | valid 
10435 -------------+-------
10436  loopback    | f
10437              | f
10438 (2 rows)
10440 -- The invalid connections get closed in pgfdw_xact_callback during commit.
10441 COMMIT;
10442 -- All cached connections were closed while committing above xact, so no
10443 -- records should be output.
10444 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10445  server_name 
10446 -------------
10447 (0 rows)
10449 -- =======================================================================
10450 -- test postgres_fdw_disconnect and postgres_fdw_disconnect_all functions
10451 -- =======================================================================
10452 BEGIN;
10453 -- Ensure to cache loopback connection.
10454 SELECT 1 FROM ft1 LIMIT 1;
10455  ?column? 
10456 ----------
10457         1
10458 (1 row)
10460 -- Ensure to cache loopback2 connection.
10461 SELECT 1 FROM ft6 LIMIT 1;
10462  ?column? 
10463 ----------
10464         1
10465 (1 row)
10467 -- List all the existing cached connections. loopback and loopback2 should be
10468 -- output.
10469 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10470  server_name 
10471 -------------
10472  loopback
10473  loopback2
10474 (2 rows)
10476 -- Issue a warning and return false as loopback connection is still in use and
10477 -- can not be closed.
10478 SELECT postgres_fdw_disconnect('loopback');
10479 WARNING:  cannot close connection for server "loopback" because it is still in use
10480  postgres_fdw_disconnect 
10481 -------------------------
10483 (1 row)
10485 -- List all the existing cached connections. loopback and loopback2 should be
10486 -- output.
10487 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10488  server_name 
10489 -------------
10490  loopback
10491  loopback2
10492 (2 rows)
10494 -- Return false as connections are still in use, warnings are issued.
10495 -- But disable warnings temporarily because the order of them is not stable.
10496 SET client_min_messages = 'ERROR';
10497 SELECT postgres_fdw_disconnect_all();
10498  postgres_fdw_disconnect_all 
10499 -----------------------------
10501 (1 row)
10503 RESET client_min_messages;
10504 COMMIT;
10505 -- Ensure that loopback2 connection is closed.
10506 SELECT 1 FROM postgres_fdw_disconnect('loopback2');
10507  ?column? 
10508 ----------
10509         1
10510 (1 row)
10512 SELECT server_name FROM postgres_fdw_get_connections() WHERE server_name = 'loopback2';
10513  server_name 
10514 -------------
10515 (0 rows)
10517 -- Return false as loopback2 connection is closed already.
10518 SELECT postgres_fdw_disconnect('loopback2');
10519  postgres_fdw_disconnect 
10520 -------------------------
10522 (1 row)
10524 -- Return an error as there is no foreign server with given name.
10525 SELECT postgres_fdw_disconnect('unknownserver');
10526 ERROR:  server "unknownserver" does not exist
10527 -- Let's ensure to close all the existing cached connections.
10528 SELECT 1 FROM postgres_fdw_disconnect_all();
10529  ?column? 
10530 ----------
10531         1
10532 (1 row)
10534 -- No cached connections, so no records should be output.
10535 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10536  server_name 
10537 -------------
10538 (0 rows)
10540 -- =============================================================================
10541 -- test case for having multiple cached connections for a foreign server
10542 -- =============================================================================
10543 CREATE ROLE regress_multi_conn_user1 SUPERUSER;
10544 CREATE ROLE regress_multi_conn_user2 SUPERUSER;
10545 CREATE USER MAPPING FOR regress_multi_conn_user1 SERVER loopback;
10546 CREATE USER MAPPING FOR regress_multi_conn_user2 SERVER loopback;
10547 BEGIN;
10548 -- Will cache loopback connection with user mapping for regress_multi_conn_user1
10549 SET ROLE regress_multi_conn_user1;
10550 SELECT 1 FROM ft1 LIMIT 1;
10551  ?column? 
10552 ----------
10553         1
10554 (1 row)
10556 RESET ROLE;
10557 -- Will cache loopback connection with user mapping for regress_multi_conn_user2
10558 SET ROLE regress_multi_conn_user2;
10559 SELECT 1 FROM ft1 LIMIT 1;
10560  ?column? 
10561 ----------
10562         1
10563 (1 row)
10565 RESET ROLE;
10566 -- Should output two connections for loopback server
10567 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10568  server_name 
10569 -------------
10570  loopback
10571  loopback
10572 (2 rows)
10574 COMMIT;
10575 -- Let's ensure to close all the existing cached connections.
10576 SELECT 1 FROM postgres_fdw_disconnect_all();
10577  ?column? 
10578 ----------
10579         1
10580 (1 row)
10582 -- No cached connections, so no records should be output.
10583 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10584  server_name 
10585 -------------
10586 (0 rows)
10588 -- Clean up
10589 DROP USER MAPPING FOR regress_multi_conn_user1 SERVER loopback;
10590 DROP USER MAPPING FOR regress_multi_conn_user2 SERVER loopback;
10591 DROP ROLE regress_multi_conn_user1;
10592 DROP ROLE regress_multi_conn_user2;
10593 -- ===================================================================
10594 -- Test foreign server level option keep_connections
10595 -- ===================================================================
10596 -- By default, the connections associated with foreign server are cached i.e.
10597 -- keep_connections option is on. Set it to off.
10598 ALTER SERVER loopback OPTIONS (keep_connections 'off');
10599 -- connection to loopback server is closed at the end of xact
10600 -- as keep_connections was set to off.
10601 SELECT 1 FROM ft1 LIMIT 1;
10602  ?column? 
10603 ----------
10604         1
10605 (1 row)
10607 -- No cached connections, so no records should be output.
10608 SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
10609  server_name 
10610 -------------
10611 (0 rows)
10613 ALTER SERVER loopback OPTIONS (SET keep_connections 'on');
10614 -- ===================================================================
10615 -- batch insert
10616 -- ===================================================================
10617 BEGIN;
10618 CREATE SERVER batch10 FOREIGN DATA WRAPPER postgres_fdw OPTIONS( batch_size '10' );
10619 SELECT count(*)
10620 FROM pg_foreign_server
10621 WHERE srvname = 'batch10'
10622 AND srvoptions @> array['batch_size=10'];
10623  count 
10624 -------
10625      1
10626 (1 row)
10628 ALTER SERVER batch10 OPTIONS( SET batch_size '20' );
10629 SELECT count(*)
10630 FROM pg_foreign_server
10631 WHERE srvname = 'batch10'
10632 AND srvoptions @> array['batch_size=10'];
10633  count 
10634 -------
10635      0
10636 (1 row)
10638 SELECT count(*)
10639 FROM pg_foreign_server
10640 WHERE srvname = 'batch10'
10641 AND srvoptions @> array['batch_size=20'];
10642  count 
10643 -------
10644      1
10645 (1 row)
10647 CREATE FOREIGN TABLE table30 ( x int ) SERVER batch10 OPTIONS ( batch_size '30' );
10648 SELECT COUNT(*)
10649 FROM pg_foreign_table
10650 WHERE ftrelid = 'table30'::regclass
10651 AND ftoptions @> array['batch_size=30'];
10652  count 
10653 -------
10654      1
10655 (1 row)
10657 ALTER FOREIGN TABLE table30 OPTIONS ( SET batch_size '40');
10658 SELECT COUNT(*)
10659 FROM pg_foreign_table
10660 WHERE ftrelid = 'table30'::regclass
10661 AND ftoptions @> array['batch_size=30'];
10662  count 
10663 -------
10664      0
10665 (1 row)
10667 SELECT COUNT(*)
10668 FROM pg_foreign_table
10669 WHERE ftrelid = 'table30'::regclass
10670 AND ftoptions @> array['batch_size=40'];
10671  count 
10672 -------
10673      1
10674 (1 row)
10676 ROLLBACK;
10677 CREATE TABLE batch_table ( x int );
10678 CREATE FOREIGN TABLE ftable ( x int ) SERVER loopback OPTIONS ( table_name 'batch_table', batch_size '10' );
10679 EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable SELECT * FROM generate_series(1, 10) i;
10680                          QUERY PLAN                          
10681 -------------------------------------------------------------
10682  Insert on public.ftable
10683    Remote SQL: INSERT INTO public.batch_table(x) VALUES ($1)
10684    Batch Size: 10
10685    ->  Function Scan on pg_catalog.generate_series i
10686          Output: i.i
10687          Function Call: generate_series(1, 10)
10688 (6 rows)
10690 INSERT INTO ftable SELECT * FROM generate_series(1, 10) i;
10691 INSERT INTO ftable SELECT * FROM generate_series(11, 31) i;
10692 INSERT INTO ftable VALUES (32);
10693 INSERT INTO ftable VALUES (33), (34);
10694 SELECT COUNT(*) FROM ftable;
10695  count 
10696 -------
10697     34
10698 (1 row)
10700 TRUNCATE batch_table;
10701 DROP FOREIGN TABLE ftable;
10702 -- Disable batch insert
10703 CREATE FOREIGN TABLE ftable ( x int ) SERVER loopback OPTIONS ( table_name 'batch_table', batch_size '1' );
10704 EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable VALUES (1), (2);
10705                          QUERY PLAN                          
10706 -------------------------------------------------------------
10707  Insert on public.ftable
10708    Remote SQL: INSERT INTO public.batch_table(x) VALUES ($1)
10709    Batch Size: 1
10710    ->  Values Scan on "*VALUES*"
10711          Output: "*VALUES*".column1
10712 (5 rows)
10714 INSERT INTO ftable VALUES (1), (2);
10715 SELECT COUNT(*) FROM ftable;
10716  count 
10717 -------
10718      2
10719 (1 row)
10721 -- Disable batch inserting into foreign tables with BEFORE ROW INSERT triggers
10722 -- even if the batch_size option is enabled.
10723 ALTER FOREIGN TABLE ftable OPTIONS ( SET batch_size '10' );
10724 CREATE TRIGGER trig_row_before BEFORE INSERT ON ftable
10725 FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
10726 EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable VALUES (3), (4);
10727                          QUERY PLAN                          
10728 -------------------------------------------------------------
10729  Insert on public.ftable
10730    Remote SQL: INSERT INTO public.batch_table(x) VALUES ($1)
10731    Batch Size: 1
10732    ->  Values Scan on "*VALUES*"
10733          Output: "*VALUES*".column1
10734 (5 rows)
10736 INSERT INTO ftable VALUES (3), (4);
10737 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON ftable
10738 NOTICE:  NEW: (3)
10739 NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON ftable
10740 NOTICE:  NEW: (4)
10741 SELECT COUNT(*) FROM ftable;
10742  count 
10743 -------
10744      4
10745 (1 row)
10747 -- Clean up
10748 DROP TRIGGER trig_row_before ON ftable;
10749 DROP FOREIGN TABLE ftable;
10750 DROP TABLE batch_table;
10751 -- Use partitioning
10752 CREATE TABLE batch_table ( x int ) PARTITION BY HASH (x);
10753 CREATE TABLE batch_table_p0 (LIKE batch_table);
10754 CREATE FOREIGN TABLE batch_table_p0f
10755         PARTITION OF batch_table
10756         FOR VALUES WITH (MODULUS 3, REMAINDER 0)
10757         SERVER loopback
10758         OPTIONS (table_name 'batch_table_p0', batch_size '10');
10759 CREATE TABLE batch_table_p1 (LIKE batch_table);
10760 CREATE FOREIGN TABLE batch_table_p1f
10761         PARTITION OF batch_table
10762         FOR VALUES WITH (MODULUS 3, REMAINDER 1)
10763         SERVER loopback
10764         OPTIONS (table_name 'batch_table_p1', batch_size '1');
10765 CREATE TABLE batch_table_p2
10766         PARTITION OF batch_table
10767         FOR VALUES WITH (MODULUS 3, REMAINDER 2);
10768 INSERT INTO batch_table SELECT * FROM generate_series(1, 66) i;
10769 SELECT COUNT(*) FROM batch_table;
10770  count 
10771 -------
10772     66
10773 (1 row)
10775 -- Clean up
10776 DROP TABLE batch_table;
10777 DROP TABLE batch_table_p0;
10778 DROP TABLE batch_table_p1;
10779 -- Check that batched mode also works for some inserts made during
10780 -- cross-partition updates
10781 CREATE TABLE batch_cp_upd_test (a int) PARTITION BY LIST (a);
10782 CREATE TABLE batch_cp_upd_test1 (LIKE batch_cp_upd_test);
10783 CREATE FOREIGN TABLE batch_cp_upd_test1_f
10784         PARTITION OF batch_cp_upd_test
10785         FOR VALUES IN (1)
10786         SERVER loopback
10787         OPTIONS (table_name 'batch_cp_upd_test1', batch_size '10');
10788 CREATE TABLE batch_cp_upd_test2 PARTITION OF batch_cp_upd_test
10789         FOR VALUES IN (2);
10790 CREATE TABLE batch_cp_upd_test3 (LIKE batch_cp_upd_test);
10791 CREATE FOREIGN TABLE batch_cp_upd_test3_f
10792         PARTITION OF batch_cp_upd_test
10793         FOR VALUES IN (3)
10794         SERVER loopback
10795         OPTIONS (table_name 'batch_cp_upd_test3', batch_size '1');
10796 -- Create statement triggers on remote tables that "log" any INSERTs
10797 -- performed on them.
10798 CREATE TABLE cmdlog (cmd text);
10799 CREATE FUNCTION log_stmt() RETURNS TRIGGER LANGUAGE plpgsql AS $$
10800         BEGIN INSERT INTO public.cmdlog VALUES (TG_OP || ' on ' || TG_RELNAME); RETURN NULL; END;
10802 CREATE TRIGGER stmt_trig AFTER INSERT ON batch_cp_upd_test1
10803         FOR EACH STATEMENT EXECUTE FUNCTION log_stmt();
10804 CREATE TRIGGER stmt_trig AFTER INSERT ON batch_cp_upd_test3
10805         FOR EACH STATEMENT EXECUTE FUNCTION log_stmt();
10806 -- This update moves rows from the local partition 'batch_cp_upd_test2' to the
10807 -- foreign partition 'batch_cp_upd_test1', one that has insert batching
10808 -- enabled, so a single INSERT for both rows.
10809 INSERT INTO batch_cp_upd_test VALUES (2), (2);
10810 UPDATE batch_cp_upd_test t SET a = 1 FROM (VALUES (1), (2)) s(a) WHERE t.a = s.a AND s.a = 2;
10811 -- This one moves rows from the local partition 'batch_cp_upd_test2' to the
10812 -- foreign partition 'batch_cp_upd_test2', one that has insert batching
10813 -- disabled, so separate INSERTs for the two rows.
10814 INSERT INTO batch_cp_upd_test VALUES (2), (2);
10815 UPDATE batch_cp_upd_test t SET a = 3 FROM (VALUES (1), (2)) s(a) WHERE t.a = s.a AND s.a = 2;
10816 SELECT tableoid::regclass, * FROM batch_cp_upd_test ORDER BY 1;
10817        tableoid       | a 
10818 ----------------------+---
10819  batch_cp_upd_test1_f | 1
10820  batch_cp_upd_test1_f | 1
10821  batch_cp_upd_test3_f | 3
10822  batch_cp_upd_test3_f | 3
10823 (4 rows)
10825 -- Should see 1 INSERT on batch_cp_upd_test1 and 2 on batch_cp_upd_test3 as
10826 -- described above.
10827 SELECT * FROM cmdlog ORDER BY 1;
10828              cmd              
10829 ------------------------------
10830  INSERT on batch_cp_upd_test1
10831  INSERT on batch_cp_upd_test3
10832  INSERT on batch_cp_upd_test3
10833 (3 rows)
10835 -- Clean up
10836 DROP TABLE batch_cp_upd_test;
10837 DROP TABLE batch_cp_upd_test1;
10838 DROP TABLE batch_cp_upd_test3;
10839 DROP TABLE cmdlog;
10840 DROP FUNCTION log_stmt();
10841 -- Use partitioning
10842 ALTER SERVER loopback OPTIONS (ADD batch_size '10');
10843 CREATE TABLE batch_table ( x int, field1 text, field2 text) PARTITION BY HASH (x);
10844 CREATE TABLE batch_table_p0 (LIKE batch_table);
10845 ALTER TABLE batch_table_p0 ADD CONSTRAINT p0_pkey PRIMARY KEY (x);
10846 CREATE FOREIGN TABLE batch_table_p0f
10847         PARTITION OF batch_table
10848         FOR VALUES WITH (MODULUS 2, REMAINDER 0)
10849         SERVER loopback
10850         OPTIONS (table_name 'batch_table_p0');
10851 CREATE TABLE batch_table_p1 (LIKE batch_table);
10852 ALTER TABLE batch_table_p1 ADD CONSTRAINT p1_pkey PRIMARY KEY (x);
10853 CREATE FOREIGN TABLE batch_table_p1f
10854         PARTITION OF batch_table
10855         FOR VALUES WITH (MODULUS 2, REMAINDER 1)
10856         SERVER loopback
10857         OPTIONS (table_name 'batch_table_p1');
10858 INSERT INTO batch_table SELECT i, 'test'||i, 'test'|| i FROM generate_series(1, 50) i;
10859 SELECT COUNT(*) FROM batch_table;
10860  count 
10861 -------
10862     50
10863 (1 row)
10865 SELECT * FROM batch_table ORDER BY x;
10866  x  | field1 | field2 
10867 ----+--------+--------
10868   1 | test1  | test1
10869   2 | test2  | test2
10870   3 | test3  | test3
10871   4 | test4  | test4
10872   5 | test5  | test5
10873   6 | test6  | test6
10874   7 | test7  | test7
10875   8 | test8  | test8
10876   9 | test9  | test9
10877  10 | test10 | test10
10878  11 | test11 | test11
10879  12 | test12 | test12
10880  13 | test13 | test13
10881  14 | test14 | test14
10882  15 | test15 | test15
10883  16 | test16 | test16
10884  17 | test17 | test17
10885  18 | test18 | test18
10886  19 | test19 | test19
10887  20 | test20 | test20
10888  21 | test21 | test21
10889  22 | test22 | test22
10890  23 | test23 | test23
10891  24 | test24 | test24
10892  25 | test25 | test25
10893  26 | test26 | test26
10894  27 | test27 | test27
10895  28 | test28 | test28
10896  29 | test29 | test29
10897  30 | test30 | test30
10898  31 | test31 | test31
10899  32 | test32 | test32
10900  33 | test33 | test33
10901  34 | test34 | test34
10902  35 | test35 | test35
10903  36 | test36 | test36
10904  37 | test37 | test37
10905  38 | test38 | test38
10906  39 | test39 | test39
10907  40 | test40 | test40
10908  41 | test41 | test41
10909  42 | test42 | test42
10910  43 | test43 | test43
10911  44 | test44 | test44
10912  45 | test45 | test45
10913  46 | test46 | test46
10914  47 | test47 | test47
10915  48 | test48 | test48
10916  49 | test49 | test49
10917  50 | test50 | test50
10918 (50 rows)
10920 -- Clean up
10921 DROP TABLE batch_table;
10922 DROP TABLE batch_table_p0;
10923 DROP TABLE batch_table_p1;
10924 ALTER SERVER loopback OPTIONS (DROP batch_size);
10925 -- Test that pending inserts are handled properly when needed
10926 CREATE TABLE batch_table (a text, b int);
10927 CREATE FOREIGN TABLE ftable (a text, b int)
10928         SERVER loopback
10929         OPTIONS (table_name 'batch_table', batch_size '2');
10930 CREATE TABLE ltable (a text, b int);
10931 CREATE FUNCTION ftable_rowcount_trigf() RETURNS trigger LANGUAGE plpgsql AS
10933 begin
10934         raise notice '%: there are % rows in ftable',
10935                 TG_NAME, (SELECT count(*) FROM ftable);
10936         if TG_OP = 'DELETE' then
10937                 return OLD;
10938         else
10939                 return NEW;
10940         end if;
10941 end;
10943 CREATE TRIGGER ftable_rowcount_trigger
10944 BEFORE INSERT OR UPDATE OR DELETE ON ltable
10945 FOR EACH ROW EXECUTE PROCEDURE ftable_rowcount_trigf();
10946 WITH t AS (
10947         INSERT INTO ltable VALUES ('AAA', 42), ('BBB', 42) RETURNING *
10949 INSERT INTO ftable SELECT * FROM t;
10950 NOTICE:  ftable_rowcount_trigger: there are 0 rows in ftable
10951 NOTICE:  ftable_rowcount_trigger: there are 1 rows in ftable
10952 SELECT * FROM ltable;
10953   a  | b  
10954 -----+----
10955  AAA | 42
10956  BBB | 42
10957 (2 rows)
10959 SELECT * FROM ftable;
10960   a  | b  
10961 -----+----
10962  AAA | 42
10963  BBB | 42
10964 (2 rows)
10966 DELETE FROM ftable;
10967 WITH t AS (
10968         UPDATE ltable SET b = b + 100 RETURNING *
10970 INSERT INTO ftable SELECT * FROM t;
10971 NOTICE:  ftable_rowcount_trigger: there are 0 rows in ftable
10972 NOTICE:  ftable_rowcount_trigger: there are 1 rows in ftable
10973 SELECT * FROM ltable;
10974   a  |  b  
10975 -----+-----
10976  AAA | 142
10977  BBB | 142
10978 (2 rows)
10980 SELECT * FROM ftable;
10981   a  |  b  
10982 -----+-----
10983  AAA | 142
10984  BBB | 142
10985 (2 rows)
10987 DELETE FROM ftable;
10988 WITH t AS (
10989         DELETE FROM ltable RETURNING *
10991 INSERT INTO ftable SELECT * FROM t;
10992 NOTICE:  ftable_rowcount_trigger: there are 0 rows in ftable
10993 NOTICE:  ftable_rowcount_trigger: there are 1 rows in ftable
10994 SELECT * FROM ltable;
10995  a | b 
10996 ---+---
10997 (0 rows)
10999 SELECT * FROM ftable;
11000   a  |  b  
11001 -----+-----
11002  AAA | 142
11003  BBB | 142
11004 (2 rows)
11006 DELETE FROM ftable;
11007 -- Clean up
11008 DROP FOREIGN TABLE ftable;
11009 DROP TABLE batch_table;
11010 DROP TRIGGER ftable_rowcount_trigger ON ltable;
11011 DROP TABLE ltable;
11012 CREATE TABLE parent (a text, b int) PARTITION BY LIST (a);
11013 CREATE TABLE batch_table (a text, b int);
11014 CREATE FOREIGN TABLE ftable
11015         PARTITION OF parent
11016         FOR VALUES IN ('AAA')
11017         SERVER loopback
11018         OPTIONS (table_name 'batch_table', batch_size '2');
11019 CREATE TABLE ltable
11020         PARTITION OF parent
11021         FOR VALUES IN ('BBB');
11022 CREATE TRIGGER ftable_rowcount_trigger
11023 BEFORE INSERT ON ltable
11024 FOR EACH ROW EXECUTE PROCEDURE ftable_rowcount_trigf();
11025 INSERT INTO parent VALUES ('AAA', 42), ('BBB', 42), ('AAA', 42), ('BBB', 42);
11026 NOTICE:  ftable_rowcount_trigger: there are 1 rows in ftable
11027 NOTICE:  ftable_rowcount_trigger: there are 2 rows in ftable
11028 SELECT tableoid::regclass, * FROM parent;
11029  tableoid |  a  | b  
11030 ----------+-----+----
11031  ftable   | AAA | 42
11032  ftable   | AAA | 42
11033  ltable   | BBB | 42
11034  ltable   | BBB | 42
11035 (4 rows)
11037 -- Clean up
11038 DROP FOREIGN TABLE ftable;
11039 DROP TABLE batch_table;
11040 DROP TRIGGER ftable_rowcount_trigger ON ltable;
11041 DROP TABLE ltable;
11042 DROP TABLE parent;
11043 DROP FUNCTION ftable_rowcount_trigf;
11044 -- ===================================================================
11045 -- test asynchronous execution
11046 -- ===================================================================
11047 ALTER SERVER loopback OPTIONS (DROP extensions);
11048 ALTER SERVER loopback OPTIONS (ADD async_capable 'true');
11049 ALTER SERVER loopback2 OPTIONS (ADD async_capable 'true');
11050 CREATE TABLE async_pt (a int, b int, c text) PARTITION BY RANGE (a);
11051 CREATE TABLE base_tbl1 (a int, b int, c text);
11052 CREATE TABLE base_tbl2 (a int, b int, c text);
11053 CREATE FOREIGN TABLE async_p1 PARTITION OF async_pt FOR VALUES FROM (1000) TO (2000)
11054   SERVER loopback OPTIONS (table_name 'base_tbl1');
11055 CREATE FOREIGN TABLE async_p2 PARTITION OF async_pt FOR VALUES FROM (2000) TO (3000)
11056   SERVER loopback2 OPTIONS (table_name 'base_tbl2');
11057 INSERT INTO async_p1 SELECT 1000 + i, i, to_char(i, 'FM0000') FROM generate_series(0, 999, 5) i;
11058 INSERT INTO async_p2 SELECT 2000 + i, i, to_char(i, 'FM0000') FROM generate_series(0, 999, 5) i;
11059 ANALYZE async_pt;
11060 -- simple queries
11061 CREATE TABLE result_tbl (a int, b int, c text);
11062 EXPLAIN (VERBOSE, COSTS OFF)
11063 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b % 100 = 0;
11064                                        QUERY PLAN                                       
11065 ----------------------------------------------------------------------------------------
11066  Insert on public.result_tbl
11067    ->  Append
11068          ->  Async Foreign Scan on public.async_p1 async_pt_1
11069                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11070                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE (((b % 100) = 0))
11071          ->  Async Foreign Scan on public.async_p2 async_pt_2
11072                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11073                Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE (((b % 100) = 0))
11074 (8 rows)
11076 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b % 100 = 0;
11077 SELECT * FROM result_tbl ORDER BY a;
11078   a   |  b  |  c   
11079 ------+-----+------
11080  1000 |   0 | 0000
11081  1100 | 100 | 0100
11082  1200 | 200 | 0200
11083  1300 | 300 | 0300
11084  1400 | 400 | 0400
11085  1500 | 500 | 0500
11086  1600 | 600 | 0600
11087  1700 | 700 | 0700
11088  1800 | 800 | 0800
11089  1900 | 900 | 0900
11090  2000 |   0 | 0000
11091  2100 | 100 | 0100
11092  2200 | 200 | 0200
11093  2300 | 300 | 0300
11094  2400 | 400 | 0400
11095  2500 | 500 | 0500
11096  2600 | 600 | 0600
11097  2700 | 700 | 0700
11098  2800 | 800 | 0800
11099  2900 | 900 | 0900
11100 (20 rows)
11102 DELETE FROM result_tbl;
11103 EXPLAIN (VERBOSE, COSTS OFF)
11104 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b === 505;
11105                            QUERY PLAN                           
11106 ----------------------------------------------------------------
11107  Insert on public.result_tbl
11108    ->  Append
11109          ->  Async Foreign Scan on public.async_p1 async_pt_1
11110                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11111                Filter: (async_pt_1.b === 505)
11112                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11113          ->  Async Foreign Scan on public.async_p2 async_pt_2
11114                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11115                Filter: (async_pt_2.b === 505)
11116                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11117 (10 rows)
11119 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b === 505;
11120 SELECT * FROM result_tbl ORDER BY a;
11121   a   |  b  |  c   
11122 ------+-----+------
11123  1505 | 505 | 0505
11124  2505 | 505 | 0505
11125 (2 rows)
11127 DELETE FROM result_tbl;
11128 EXPLAIN (VERBOSE, COSTS OFF)
11129 INSERT INTO result_tbl SELECT a, b, 'AAA' || c FROM async_pt WHERE b === 505;
11130                                    QUERY PLAN                                    
11131 ---------------------------------------------------------------------------------
11132  Insert on public.result_tbl
11133    ->  Append
11134          ->  Async Foreign Scan on public.async_p1 async_pt_1
11135                Output: async_pt_1.a, async_pt_1.b, ('AAA'::text || async_pt_1.c)
11136                Filter: (async_pt_1.b === 505)
11137                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11138          ->  Async Foreign Scan on public.async_p2 async_pt_2
11139                Output: async_pt_2.a, async_pt_2.b, ('AAA'::text || async_pt_2.c)
11140                Filter: (async_pt_2.b === 505)
11141                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11142 (10 rows)
11144 INSERT INTO result_tbl SELECT a, b, 'AAA' || c FROM async_pt WHERE b === 505;
11145 SELECT * FROM result_tbl ORDER BY a;
11146   a   |  b  |    c    
11147 ------+-----+---------
11148  1505 | 505 | AAA0505
11149  2505 | 505 | AAA0505
11150 (2 rows)
11152 DELETE FROM result_tbl;
11153 -- Test error handling, if accessing one of the foreign partitions errors out
11154 CREATE FOREIGN TABLE async_p_broken PARTITION OF async_pt FOR VALUES FROM (10000) TO (10001)
11155   SERVER loopback OPTIONS (table_name 'non_existent_table');
11156 SELECT * FROM async_pt;
11157 ERROR:  relation "public.non_existent_table" does not exist
11158 CONTEXT:  remote SQL command: SELECT a, b, c FROM public.non_existent_table
11159 DROP FOREIGN TABLE async_p_broken;
11160 -- Check case where multiple partitions use the same connection
11161 CREATE TABLE base_tbl3 (a int, b int, c text);
11162 CREATE FOREIGN TABLE async_p3 PARTITION OF async_pt FOR VALUES FROM (3000) TO (4000)
11163   SERVER loopback2 OPTIONS (table_name 'base_tbl3');
11164 INSERT INTO async_p3 SELECT 3000 + i, i, to_char(i, 'FM0000') FROM generate_series(0, 999, 5) i;
11165 ANALYZE async_pt;
11166 EXPLAIN (VERBOSE, COSTS OFF)
11167 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b === 505;
11168                            QUERY PLAN                           
11169 ----------------------------------------------------------------
11170  Insert on public.result_tbl
11171    ->  Append
11172          ->  Async Foreign Scan on public.async_p1 async_pt_1
11173                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11174                Filter: (async_pt_1.b === 505)
11175                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11176          ->  Async Foreign Scan on public.async_p2 async_pt_2
11177                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11178                Filter: (async_pt_2.b === 505)
11179                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11180          ->  Async Foreign Scan on public.async_p3 async_pt_3
11181                Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
11182                Filter: (async_pt_3.b === 505)
11183                Remote SQL: SELECT a, b, c FROM public.base_tbl3
11184 (14 rows)
11186 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b === 505;
11187 SELECT * FROM result_tbl ORDER BY a;
11188   a   |  b  |  c   
11189 ------+-----+------
11190  1505 | 505 | 0505
11191  2505 | 505 | 0505
11192  3505 | 505 | 0505
11193 (3 rows)
11195 DELETE FROM result_tbl;
11196 DROP FOREIGN TABLE async_p3;
11197 DROP TABLE base_tbl3;
11198 -- Check case where the partitioned table has local/remote partitions
11199 CREATE TABLE async_p3 PARTITION OF async_pt FOR VALUES FROM (3000) TO (4000);
11200 INSERT INTO async_p3 SELECT 3000 + i, i, to_char(i, 'FM0000') FROM generate_series(0, 999, 5) i;
11201 ANALYZE async_pt;
11202 EXPLAIN (VERBOSE, COSTS OFF)
11203 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b === 505;
11204                            QUERY PLAN                           
11205 ----------------------------------------------------------------
11206  Insert on public.result_tbl
11207    ->  Append
11208          ->  Async Foreign Scan on public.async_p1 async_pt_1
11209                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11210                Filter: (async_pt_1.b === 505)
11211                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11212          ->  Async Foreign Scan on public.async_p2 async_pt_2
11213                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11214                Filter: (async_pt_2.b === 505)
11215                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11216          ->  Seq Scan on public.async_p3 async_pt_3
11217                Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
11218                Filter: (async_pt_3.b === 505)
11219 (13 rows)
11221 INSERT INTO result_tbl SELECT * FROM async_pt WHERE b === 505;
11222 SELECT * FROM result_tbl ORDER BY a;
11223   a   |  b  |  c   
11224 ------+-----+------
11225  1505 | 505 | 0505
11226  2505 | 505 | 0505
11227  3505 | 505 | 0505
11228 (3 rows)
11230 DELETE FROM result_tbl;
11231 -- partitionwise joins
11232 SET enable_partitionwise_join TO true;
11233 CREATE TABLE join_tbl (a1 int, b1 int, c1 text, a2 int, b2 int, c2 text);
11234 EXPLAIN (VERBOSE, COSTS OFF)
11235 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;
11236                                                                                            QUERY PLAN                                                                                            
11237 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
11238  Insert on public.join_tbl
11239    ->  Append
11240          ->  Async Foreign Scan
11241                Output: t1_1.a, t1_1.b, t1_1.c, t2_1.a, t2_1.b, t2_1.c
11242                Relations: (public.async_p1 t1_1) INNER JOIN (public.async_p1 t2_1)
11243                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))))
11244          ->  Async Foreign Scan
11245                Output: t1_2.a, t1_2.b, t1_2.c, t2_2.a, t2_2.b, t2_2.c
11246                Relations: (public.async_p2 t1_2) INNER JOIN (public.async_p2 t2_2)
11247                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))))
11248          ->  Hash Join
11249                Output: t1_3.a, t1_3.b, t1_3.c, t2_3.a, t2_3.b, t2_3.c
11250                Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.b = t1_3.b))
11251                ->  Seq Scan on public.async_p3 t2_3
11252                      Output: t2_3.a, t2_3.b, t2_3.c
11253                ->  Hash
11254                      Output: t1_3.a, t1_3.b, t1_3.c
11255                      ->  Seq Scan on public.async_p3 t1_3
11256                            Output: t1_3.a, t1_3.b, t1_3.c
11257                            Filter: ((t1_3.b % 100) = 0)
11258 (20 rows)
11260 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;
11261 SELECT * FROM join_tbl ORDER BY a1;
11262   a1  | b1  |  c1  |  a2  | b2  |  c2  
11263 ------+-----+------+------+-----+------
11264  1000 |   0 | 0000 | 1000 |   0 | 0000
11265  1100 | 100 | 0100 | 1100 | 100 | 0100
11266  1200 | 200 | 0200 | 1200 | 200 | 0200
11267  1300 | 300 | 0300 | 1300 | 300 | 0300
11268  1400 | 400 | 0400 | 1400 | 400 | 0400
11269  1500 | 500 | 0500 | 1500 | 500 | 0500
11270  1600 | 600 | 0600 | 1600 | 600 | 0600
11271  1700 | 700 | 0700 | 1700 | 700 | 0700
11272  1800 | 800 | 0800 | 1800 | 800 | 0800
11273  1900 | 900 | 0900 | 1900 | 900 | 0900
11274  2000 |   0 | 0000 | 2000 |   0 | 0000
11275  2100 | 100 | 0100 | 2100 | 100 | 0100
11276  2200 | 200 | 0200 | 2200 | 200 | 0200
11277  2300 | 300 | 0300 | 2300 | 300 | 0300
11278  2400 | 400 | 0400 | 2400 | 400 | 0400
11279  2500 | 500 | 0500 | 2500 | 500 | 0500
11280  2600 | 600 | 0600 | 2600 | 600 | 0600
11281  2700 | 700 | 0700 | 2700 | 700 | 0700
11282  2800 | 800 | 0800 | 2800 | 800 | 0800
11283  2900 | 900 | 0900 | 2900 | 900 | 0900
11284  3000 |   0 | 0000 | 3000 |   0 | 0000
11285  3100 | 100 | 0100 | 3100 | 100 | 0100
11286  3200 | 200 | 0200 | 3200 | 200 | 0200
11287  3300 | 300 | 0300 | 3300 | 300 | 0300
11288  3400 | 400 | 0400 | 3400 | 400 | 0400
11289  3500 | 500 | 0500 | 3500 | 500 | 0500
11290  3600 | 600 | 0600 | 3600 | 600 | 0600
11291  3700 | 700 | 0700 | 3700 | 700 | 0700
11292  3800 | 800 | 0800 | 3800 | 800 | 0800
11293  3900 | 900 | 0900 | 3900 | 900 | 0900
11294 (30 rows)
11296 DELETE FROM join_tbl;
11297 EXPLAIN (VERBOSE, COSTS OFF)
11298 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;
11299                                                                                            QUERY PLAN                                                                                            
11300 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
11301  Insert on public.join_tbl
11302    ->  Append
11303          ->  Async Foreign Scan
11304                Output: t1_1.a, t1_1.b, ('AAA'::text || t1_1.c), t2_1.a, t2_1.b, ('AAA'::text || t2_1.c)
11305                Relations: (public.async_p1 t1_1) INNER JOIN (public.async_p1 t2_1)
11306                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))))
11307          ->  Async Foreign Scan
11308                Output: t1_2.a, t1_2.b, ('AAA'::text || t1_2.c), t2_2.a, t2_2.b, ('AAA'::text || t2_2.c)
11309                Relations: (public.async_p2 t1_2) INNER JOIN (public.async_p2 t2_2)
11310                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))))
11311          ->  Hash Join
11312                Output: t1_3.a, t1_3.b, ('AAA'::text || t1_3.c), t2_3.a, t2_3.b, ('AAA'::text || t2_3.c)
11313                Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.b = t1_3.b))
11314                ->  Seq Scan on public.async_p3 t2_3
11315                      Output: t2_3.a, t2_3.b, t2_3.c
11316                ->  Hash
11317                      Output: t1_3.a, t1_3.b, t1_3.c
11318                      ->  Seq Scan on public.async_p3 t1_3
11319                            Output: t1_3.a, t1_3.b, t1_3.c
11320                            Filter: ((t1_3.b % 100) = 0)
11321 (20 rows)
11323 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;
11324 SELECT * FROM join_tbl ORDER BY a1;
11325   a1  | b1  |   c1    |  a2  | b2  |   c2    
11326 ------+-----+---------+------+-----+---------
11327  1000 |   0 | AAA0000 | 1000 |   0 | AAA0000
11328  1100 | 100 | AAA0100 | 1100 | 100 | AAA0100
11329  1200 | 200 | AAA0200 | 1200 | 200 | AAA0200
11330  1300 | 300 | AAA0300 | 1300 | 300 | AAA0300
11331  1400 | 400 | AAA0400 | 1400 | 400 | AAA0400
11332  1500 | 500 | AAA0500 | 1500 | 500 | AAA0500
11333  1600 | 600 | AAA0600 | 1600 | 600 | AAA0600
11334  1700 | 700 | AAA0700 | 1700 | 700 | AAA0700
11335  1800 | 800 | AAA0800 | 1800 | 800 | AAA0800
11336  1900 | 900 | AAA0900 | 1900 | 900 | AAA0900
11337  2000 |   0 | AAA0000 | 2000 |   0 | AAA0000
11338  2100 | 100 | AAA0100 | 2100 | 100 | AAA0100
11339  2200 | 200 | AAA0200 | 2200 | 200 | AAA0200
11340  2300 | 300 | AAA0300 | 2300 | 300 | AAA0300
11341  2400 | 400 | AAA0400 | 2400 | 400 | AAA0400
11342  2500 | 500 | AAA0500 | 2500 | 500 | AAA0500
11343  2600 | 600 | AAA0600 | 2600 | 600 | AAA0600
11344  2700 | 700 | AAA0700 | 2700 | 700 | AAA0700
11345  2800 | 800 | AAA0800 | 2800 | 800 | AAA0800
11346  2900 | 900 | AAA0900 | 2900 | 900 | AAA0900
11347  3000 |   0 | AAA0000 | 3000 |   0 | AAA0000
11348  3100 | 100 | AAA0100 | 3100 | 100 | AAA0100
11349  3200 | 200 | AAA0200 | 3200 | 200 | AAA0200
11350  3300 | 300 | AAA0300 | 3300 | 300 | AAA0300
11351  3400 | 400 | AAA0400 | 3400 | 400 | AAA0400
11352  3500 | 500 | AAA0500 | 3500 | 500 | AAA0500
11353  3600 | 600 | AAA0600 | 3600 | 600 | AAA0600
11354  3700 | 700 | AAA0700 | 3700 | 700 | AAA0700
11355  3800 | 800 | AAA0800 | 3800 | 800 | AAA0800
11356  3900 | 900 | AAA0900 | 3900 | 900 | AAA0900
11357 (30 rows)
11359 DELETE FROM join_tbl;
11360 RESET enable_partitionwise_join;
11361 -- Test rescan of an async Append node with do_exec_prune=false
11362 SET enable_hashjoin TO false;
11363 EXPLAIN (VERBOSE, COSTS OFF)
11364 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;
11365                                        QUERY PLAN                                       
11366 ----------------------------------------------------------------------------------------
11367  Insert on public.join_tbl
11368    ->  Nested Loop
11369          Output: t1.a, t1.b, t1.c, t2.a, t2.b, t2.c
11370          Join Filter: ((t1.a = t2.a) AND (t1.b = t2.b))
11371          ->  Foreign Scan on public.async_p1 t1
11372                Output: t1.a, t1.b, t1.c
11373                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE (((b % 100) = 0))
11374          ->  Append
11375                ->  Async Foreign Scan on public.async_p1 t2_1
11376                      Output: t2_1.a, t2_1.b, t2_1.c
11377                      Remote SQL: SELECT a, b, c FROM public.base_tbl1
11378                ->  Async Foreign Scan on public.async_p2 t2_2
11379                      Output: t2_2.a, t2_2.b, t2_2.c
11380                      Remote SQL: SELECT a, b, c FROM public.base_tbl2
11381                ->  Seq Scan on public.async_p3 t2_3
11382                      Output: t2_3.a, t2_3.b, t2_3.c
11383 (16 rows)
11385 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;
11386 SELECT * FROM join_tbl ORDER BY a1;
11387   a1  | b1  |  c1  |  a2  | b2  |  c2  
11388 ------+-----+------+------+-----+------
11389  1000 |   0 | 0000 | 1000 |   0 | 0000
11390  1100 | 100 | 0100 | 1100 | 100 | 0100
11391  1200 | 200 | 0200 | 1200 | 200 | 0200
11392  1300 | 300 | 0300 | 1300 | 300 | 0300
11393  1400 | 400 | 0400 | 1400 | 400 | 0400
11394  1500 | 500 | 0500 | 1500 | 500 | 0500
11395  1600 | 600 | 0600 | 1600 | 600 | 0600
11396  1700 | 700 | 0700 | 1700 | 700 | 0700
11397  1800 | 800 | 0800 | 1800 | 800 | 0800
11398  1900 | 900 | 0900 | 1900 | 900 | 0900
11399 (10 rows)
11401 DELETE FROM join_tbl;
11402 RESET enable_hashjoin;
11403 -- Test interaction of async execution with plan-time partition pruning
11404 EXPLAIN (VERBOSE, COSTS OFF)
11405 SELECT * FROM async_pt WHERE a < 3000;
11406                                  QUERY PLAN                                  
11407 -----------------------------------------------------------------------------
11408  Append
11409    ->  Async Foreign Scan on public.async_p1 async_pt_1
11410          Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11411          Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((a < 3000))
11412    ->  Async Foreign Scan on public.async_p2 async_pt_2
11413          Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11414          Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((a < 3000))
11415 (7 rows)
11417 EXPLAIN (VERBOSE, COSTS OFF)
11418 SELECT * FROM async_pt WHERE a < 2000;
11419                               QUERY PLAN                               
11420 -----------------------------------------------------------------------
11421  Foreign Scan on public.async_p1 async_pt
11422    Output: async_pt.a, async_pt.b, async_pt.c
11423    Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((a < 2000))
11424 (3 rows)
11426 -- Test interaction of async execution with run-time partition pruning
11427 SET plan_cache_mode TO force_generic_plan;
11428 PREPARE async_pt_query (int, int) AS
11429   INSERT INTO result_tbl SELECT * FROM async_pt WHERE a < $1 AND b === $2;
11430 EXPLAIN (VERBOSE, COSTS OFF)
11431 EXECUTE async_pt_query (3000, 505);
11432                                         QUERY PLAN                                        
11433 ------------------------------------------------------------------------------------------
11434  Insert on public.result_tbl
11435    ->  Append
11436          Subplans Removed: 1
11437          ->  Async Foreign Scan on public.async_p1 async_pt_1
11438                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11439                Filter: (async_pt_1.b === $2)
11440                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((a < $1::integer))
11441          ->  Async Foreign Scan on public.async_p2 async_pt_2
11442                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11443                Filter: (async_pt_2.b === $2)
11444                Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((a < $1::integer))
11445 (11 rows)
11447 EXECUTE async_pt_query (3000, 505);
11448 SELECT * FROM result_tbl ORDER BY a;
11449   a   |  b  |  c   
11450 ------+-----+------
11451  1505 | 505 | 0505
11452  2505 | 505 | 0505
11453 (2 rows)
11455 DELETE FROM result_tbl;
11456 EXPLAIN (VERBOSE, COSTS OFF)
11457 EXECUTE async_pt_query (2000, 505);
11458                                         QUERY PLAN                                        
11459 ------------------------------------------------------------------------------------------
11460  Insert on public.result_tbl
11461    ->  Append
11462          Subplans Removed: 2
11463          ->  Async Foreign Scan on public.async_p1 async_pt_1
11464                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11465                Filter: (async_pt_1.b === $2)
11466                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((a < $1::integer))
11467 (7 rows)
11469 EXECUTE async_pt_query (2000, 505);
11470 SELECT * FROM result_tbl ORDER BY a;
11471   a   |  b  |  c   
11472 ------+-----+------
11473  1505 | 505 | 0505
11474 (1 row)
11476 DELETE FROM result_tbl;
11477 RESET plan_cache_mode;
11478 CREATE TABLE local_tbl(a int, b int, c text);
11479 INSERT INTO local_tbl VALUES (1505, 505, 'foo'), (2505, 505, 'bar');
11480 ANALYZE local_tbl;
11481 CREATE INDEX base_tbl1_idx ON base_tbl1 (a);
11482 CREATE INDEX base_tbl2_idx ON base_tbl2 (a);
11483 CREATE INDEX async_p3_idx ON async_p3 (a);
11484 ANALYZE base_tbl1;
11485 ANALYZE base_tbl2;
11486 ANALYZE async_p3;
11487 ALTER FOREIGN TABLE async_p1 OPTIONS (use_remote_estimate 'true');
11488 ALTER FOREIGN TABLE async_p2 OPTIONS (use_remote_estimate 'true');
11489 EXPLAIN (VERBOSE, COSTS OFF)
11490 SELECT * FROM local_tbl, async_pt WHERE local_tbl.a = async_pt.a AND local_tbl.c = 'bar';
11491                                         QUERY PLAN                                        
11492 ------------------------------------------------------------------------------------------
11493  Nested Loop
11494    Output: local_tbl.a, local_tbl.b, local_tbl.c, async_pt.a, async_pt.b, async_pt.c
11495    ->  Seq Scan on public.local_tbl
11496          Output: local_tbl.a, local_tbl.b, local_tbl.c
11497          Filter: (local_tbl.c = 'bar'::text)
11498    ->  Append
11499          ->  Async Foreign Scan on public.async_p1 async_pt_1
11500                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11501                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((a = $1::integer))
11502          ->  Async Foreign Scan on public.async_p2 async_pt_2
11503                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11504                Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((a = $1::integer))
11505          ->  Seq Scan on public.async_p3 async_pt_3
11506                Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
11507                Filter: (async_pt_3.a = local_tbl.a)
11508 (15 rows)
11510 EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
11511 SELECT * FROM local_tbl, async_pt WHERE local_tbl.a = async_pt.a AND local_tbl.c = 'bar';
11512                                   QUERY PLAN                                   
11513 -------------------------------------------------------------------------------
11514  Nested Loop (actual rows=1 loops=1)
11515    ->  Seq Scan on local_tbl (actual rows=1 loops=1)
11516          Filter: (c = 'bar'::text)
11517          Rows Removed by Filter: 1
11518    ->  Append (actual rows=1 loops=1)
11519          ->  Async Foreign Scan on async_p1 async_pt_1 (never executed)
11520          ->  Async Foreign Scan on async_p2 async_pt_2 (actual rows=1 loops=1)
11521          ->  Seq Scan on async_p3 async_pt_3 (never executed)
11522                Filter: (a = local_tbl.a)
11523 (9 rows)
11525 SELECT * FROM local_tbl, async_pt WHERE local_tbl.a = async_pt.a AND local_tbl.c = 'bar';
11526   a   |  b  |  c  |  a   |  b  |  c   
11527 ------+-----+-----+------+-----+------
11528  2505 | 505 | bar | 2505 | 505 | 0505
11529 (1 row)
11531 ALTER FOREIGN TABLE async_p1 OPTIONS (DROP use_remote_estimate);
11532 ALTER FOREIGN TABLE async_p2 OPTIONS (DROP use_remote_estimate);
11533 DROP TABLE local_tbl;
11534 DROP INDEX base_tbl1_idx;
11535 DROP INDEX base_tbl2_idx;
11536 DROP INDEX async_p3_idx;
11537 -- UNION queries
11538 SET enable_sort TO off;
11539 SET enable_incremental_sort TO off;
11540 -- Adjust fdw_startup_cost so that we get an unordered path in the Append.
11541 ALTER SERVER loopback2 OPTIONS (ADD fdw_startup_cost '0.00');
11542 EXPLAIN (VERBOSE, COSTS OFF)
11543 INSERT INTO result_tbl
11544 (SELECT a, b, 'AAA' || c FROM async_p1 ORDER BY a LIMIT 10)
11545 UNION
11546 (SELECT a, b, 'AAA' || c FROM async_p2 WHERE b < 10);
11547                                                    QUERY PLAN                                                    
11548 -----------------------------------------------------------------------------------------------------------------
11549  Insert on public.result_tbl
11550    ->  HashAggregate
11551          Output: async_p1.a, async_p1.b, (('AAA'::text || async_p1.c))
11552          Group Key: async_p1.a, async_p1.b, (('AAA'::text || async_p1.c))
11553          ->  Append
11554                ->  Async Foreign Scan on public.async_p1
11555                      Output: async_p1.a, async_p1.b, ('AAA'::text || async_p1.c)
11556                      Remote SQL: SELECT a, b, c FROM public.base_tbl1 ORDER BY a ASC NULLS LAST LIMIT 10::bigint
11557                ->  Async Foreign Scan on public.async_p2
11558                      Output: async_p2.a, async_p2.b, ('AAA'::text || async_p2.c)
11559                      Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((b < 10))
11560 (11 rows)
11562 INSERT INTO result_tbl
11563 (SELECT a, b, 'AAA' || c FROM async_p1 ORDER BY a LIMIT 10)
11564 UNION
11565 (SELECT a, b, 'AAA' || c FROM async_p2 WHERE b < 10);
11566 SELECT * FROM result_tbl ORDER BY a;
11567   a   | b  |    c    
11568 ------+----+---------
11569  1000 |  0 | AAA0000
11570  1005 |  5 | AAA0005
11571  1010 | 10 | AAA0010
11572  1015 | 15 | AAA0015
11573  1020 | 20 | AAA0020
11574  1025 | 25 | AAA0025
11575  1030 | 30 | AAA0030
11576  1035 | 35 | AAA0035
11577  1040 | 40 | AAA0040
11578  1045 | 45 | AAA0045
11579  2000 |  0 | AAA0000
11580  2005 |  5 | AAA0005
11581 (12 rows)
11583 DELETE FROM result_tbl;
11584 EXPLAIN (VERBOSE, COSTS OFF)
11585 INSERT INTO result_tbl
11586 (SELECT a, b, 'AAA' || c FROM async_p1 ORDER BY a LIMIT 10)
11587 UNION ALL
11588 (SELECT a, b, 'AAA' || c FROM async_p2 WHERE b < 10);
11589                                                 QUERY PLAN                                                 
11590 -----------------------------------------------------------------------------------------------------------
11591  Insert on public.result_tbl
11592    ->  Append
11593          ->  Async Foreign Scan on public.async_p1
11594                Output: async_p1.a, async_p1.b, ('AAA'::text || async_p1.c)
11595                Remote SQL: SELECT a, b, c FROM public.base_tbl1 ORDER BY a ASC NULLS LAST LIMIT 10::bigint
11596          ->  Async Foreign Scan on public.async_p2
11597                Output: async_p2.a, async_p2.b, ('AAA'::text || async_p2.c)
11598                Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((b < 10))
11599 (8 rows)
11601 INSERT INTO result_tbl
11602 (SELECT a, b, 'AAA' || c FROM async_p1 ORDER BY a LIMIT 10)
11603 UNION ALL
11604 (SELECT a, b, 'AAA' || c FROM async_p2 WHERE b < 10);
11605 SELECT * FROM result_tbl ORDER BY a;
11606   a   | b  |    c    
11607 ------+----+---------
11608  1000 |  0 | AAA0000
11609  1005 |  5 | AAA0005
11610  1010 | 10 | AAA0010
11611  1015 | 15 | AAA0015
11612  1020 | 20 | AAA0020
11613  1025 | 25 | AAA0025
11614  1030 | 30 | AAA0030
11615  1035 | 35 | AAA0035
11616  1040 | 40 | AAA0040
11617  1045 | 45 | AAA0045
11618  2000 |  0 | AAA0000
11619  2005 |  5 | AAA0005
11620 (12 rows)
11622 DELETE FROM result_tbl;
11623 RESET enable_incremental_sort;
11624 RESET enable_sort;
11625 ALTER SERVER loopback2 OPTIONS (DROP fdw_startup_cost);
11626 -- Disable async execution if we use gating Result nodes for pseudoconstant
11627 -- quals
11628 EXPLAIN (VERBOSE, COSTS OFF)
11629 SELECT * FROM async_pt WHERE CURRENT_USER = SESSION_USER;
11630                            QUERY PLAN                           
11631 ----------------------------------------------------------------
11632  Append
11633    ->  Result
11634          Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11635          One-Time Filter: (CURRENT_USER = SESSION_USER)
11636          ->  Foreign Scan on public.async_p1 async_pt_1
11637                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11638                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11639    ->  Result
11640          Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11641          One-Time Filter: (CURRENT_USER = SESSION_USER)
11642          ->  Foreign Scan on public.async_p2 async_pt_2
11643                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11644                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11645    ->  Result
11646          Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
11647          One-Time Filter: (CURRENT_USER = SESSION_USER)
11648          ->  Seq Scan on public.async_p3 async_pt_3
11649                Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
11650 (18 rows)
11652 EXPLAIN (VERBOSE, COSTS OFF)
11653 (SELECT * FROM async_p1 WHERE CURRENT_USER = SESSION_USER)
11654 UNION ALL
11655 (SELECT * FROM async_p2 WHERE CURRENT_USER = SESSION_USER);
11656                            QUERY PLAN                           
11657 ----------------------------------------------------------------
11658  Append
11659    ->  Result
11660          Output: async_p1.a, async_p1.b, async_p1.c
11661          One-Time Filter: (CURRENT_USER = SESSION_USER)
11662          ->  Foreign Scan on public.async_p1
11663                Output: async_p1.a, async_p1.b, async_p1.c
11664                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11665    ->  Result
11666          Output: async_p2.a, async_p2.b, async_p2.c
11667          One-Time Filter: (CURRENT_USER = SESSION_USER)
11668          ->  Foreign Scan on public.async_p2
11669                Output: async_p2.a, async_p2.b, async_p2.c
11670                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11671 (13 rows)
11673 EXPLAIN (VERBOSE, COSTS OFF)
11674 SELECT * FROM ((SELECT * FROM async_p1 WHERE b < 10) UNION ALL (SELECT * FROM async_p2 WHERE b < 10)) s WHERE CURRENT_USER = SESSION_USER;
11675                                    QUERY PLAN                                    
11676 ---------------------------------------------------------------------------------
11677  Append
11678    ->  Result
11679          Output: async_p1.a, async_p1.b, async_p1.c
11680          One-Time Filter: (CURRENT_USER = SESSION_USER)
11681          ->  Foreign Scan on public.async_p1
11682                Output: async_p1.a, async_p1.b, async_p1.c
11683                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((b < 10))
11684    ->  Result
11685          Output: async_p2.a, async_p2.b, async_p2.c
11686          One-Time Filter: (CURRENT_USER = SESSION_USER)
11687          ->  Foreign Scan on public.async_p2
11688                Output: async_p2.a, async_p2.b, async_p2.c
11689                Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((b < 10))
11690 (13 rows)
11692 -- Test that pending requests are processed properly
11693 SET enable_mergejoin TO false;
11694 SET enable_hashjoin TO false;
11695 EXPLAIN (VERBOSE, COSTS OFF)
11696 SELECT * FROM async_pt t1, async_p2 t2 WHERE t1.a = t2.a AND t1.b === 505;
11697                            QUERY PLAN                           
11698 ----------------------------------------------------------------
11699  Nested Loop
11700    Output: t1.a, t1.b, t1.c, t2.a, t2.b, t2.c
11701    Join Filter: (t1.a = t2.a)
11702    ->  Append
11703          ->  Async Foreign Scan on public.async_p1 t1_1
11704                Output: t1_1.a, t1_1.b, t1_1.c
11705                Filter: (t1_1.b === 505)
11706                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11707          ->  Async Foreign Scan on public.async_p2 t1_2
11708                Output: t1_2.a, t1_2.b, t1_2.c
11709                Filter: (t1_2.b === 505)
11710                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11711          ->  Seq Scan on public.async_p3 t1_3
11712                Output: t1_3.a, t1_3.b, t1_3.c
11713                Filter: (t1_3.b === 505)
11714    ->  Materialize
11715          Output: t2.a, t2.b, t2.c
11716          ->  Foreign Scan on public.async_p2 t2
11717                Output: t2.a, t2.b, t2.c
11718                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11719 (20 rows)
11721 SELECT * FROM async_pt t1, async_p2 t2 WHERE t1.a = t2.a AND t1.b === 505;
11722   a   |  b  |  c   |  a   |  b  |  c   
11723 ------+-----+------+------+-----+------
11724  2505 | 505 | 0505 | 2505 | 505 | 0505
11725 (1 row)
11727 CREATE TABLE local_tbl (a int, b int, c text);
11728 INSERT INTO local_tbl VALUES (1505, 505, 'foo');
11729 ANALYZE local_tbl;
11730 EXPLAIN (VERBOSE, COSTS OFF)
11731 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;
11732                                        QUERY PLAN                                       
11733 ----------------------------------------------------------------------------------------
11734  Nested Loop Left Join
11735    Output: t1.a, t1.b, t1.c, async_pt.a, async_pt.b, async_pt.c, ((InitPlan 1).col1)
11736    Join Filter: (t1.a = async_pt.a)
11737    InitPlan 1
11738      ->  Aggregate
11739            Output: count(*)
11740            ->  Append
11741                  ->  Async Foreign Scan on public.async_p1 async_pt_4
11742                        Remote SQL: SELECT NULL FROM public.base_tbl1 WHERE ((a < 3000))
11743                  ->  Async Foreign Scan on public.async_p2 async_pt_5
11744                        Remote SQL: SELECT NULL FROM public.base_tbl2 WHERE ((a < 3000))
11745    ->  Seq Scan on public.local_tbl t1
11746          Output: t1.a, t1.b, t1.c
11747    ->  Append
11748          ->  Async Foreign Scan on public.async_p1 async_pt_1
11749                Output: async_pt_1.a, async_pt_1.b, async_pt_1.c, (InitPlan 1).col1
11750                Remote SQL: SELECT a, b, c FROM public.base_tbl1 WHERE ((a < 3000))
11751          ->  Async Foreign Scan on public.async_p2 async_pt_2
11752                Output: async_pt_2.a, async_pt_2.b, async_pt_2.c, (InitPlan 1).col1
11753                Remote SQL: SELECT a, b, c FROM public.base_tbl2 WHERE ((a < 3000))
11754 (20 rows)
11756 EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
11757 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;
11758                                        QUERY PLAN                                        
11759 -----------------------------------------------------------------------------------------
11760  Nested Loop Left Join (actual rows=1 loops=1)
11761    Join Filter: (t1.a = async_pt.a)
11762    Rows Removed by Join Filter: 399
11763    InitPlan 1
11764      ->  Aggregate (actual rows=1 loops=1)
11765            ->  Append (actual rows=400 loops=1)
11766                  ->  Async Foreign Scan on async_p1 async_pt_4 (actual rows=200 loops=1)
11767                  ->  Async Foreign Scan on async_p2 async_pt_5 (actual rows=200 loops=1)
11768    ->  Seq Scan on local_tbl t1 (actual rows=1 loops=1)
11769    ->  Append (actual rows=400 loops=1)
11770          ->  Async Foreign Scan on async_p1 async_pt_1 (actual rows=200 loops=1)
11771          ->  Async Foreign Scan on async_p2 async_pt_2 (actual rows=200 loops=1)
11772 (12 rows)
11774 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;
11775   a   |  b  |  c  |  a   |  b  |  c   | count 
11776 ------+-----+-----+------+-----+------+-------
11777  1505 | 505 | foo | 1505 | 505 | 0505 |   400
11778 (1 row)
11780 EXPLAIN (VERBOSE, COSTS OFF)
11781 SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1;
11782                            QUERY PLAN                           
11783 ----------------------------------------------------------------
11784  Limit
11785    Output: t1.a, t1.b, t1.c
11786    ->  Append
11787          ->  Async Foreign Scan on public.async_p1 t1_1
11788                Output: t1_1.a, t1_1.b, t1_1.c
11789                Filter: (t1_1.b === 505)
11790                Remote SQL: SELECT a, b, c FROM public.base_tbl1
11791          ->  Async Foreign Scan on public.async_p2 t1_2
11792                Output: t1_2.a, t1_2.b, t1_2.c
11793                Filter: (t1_2.b === 505)
11794                Remote SQL: SELECT a, b, c FROM public.base_tbl2
11795          ->  Seq Scan on public.async_p3 t1_3
11796                Output: t1_3.a, t1_3.b, t1_3.c
11797                Filter: (t1_3.b === 505)
11798 (14 rows)
11800 EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
11801 SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1;
11802                                QUERY PLAN                                
11803 -------------------------------------------------------------------------
11804  Limit (actual rows=1 loops=1)
11805    ->  Append (actual rows=1 loops=1)
11806          ->  Async Foreign Scan on async_p1 t1_1 (actual rows=0 loops=1)
11807                Filter: (b === 505)
11808          ->  Async Foreign Scan on async_p2 t1_2 (actual rows=0 loops=1)
11809                Filter: (b === 505)
11810          ->  Seq Scan on async_p3 t1_3 (actual rows=1 loops=1)
11811                Filter: (b === 505)
11812                Rows Removed by Filter: 101
11813 (9 rows)
11815 SELECT * FROM async_pt t1 WHERE t1.b === 505 LIMIT 1;
11816   a   |  b  |  c   
11817 ------+-----+------
11818  3505 | 505 | 0505
11819 (1 row)
11821 -- Check with foreign modify
11822 CREATE TABLE base_tbl3 (a int, b int, c text);
11823 CREATE FOREIGN TABLE remote_tbl (a int, b int, c text)
11824   SERVER loopback OPTIONS (table_name 'base_tbl3');
11825 INSERT INTO remote_tbl VALUES (2505, 505, 'bar');
11826 CREATE TABLE base_tbl4 (a int, b int, c text);
11827 CREATE FOREIGN TABLE insert_tbl (a int, b int, c text)
11828   SERVER loopback OPTIONS (table_name 'base_tbl4');
11829 EXPLAIN (VERBOSE, COSTS OFF)
11830 INSERT INTO insert_tbl (SELECT * FROM local_tbl UNION ALL SELECT * FROM remote_tbl);
11831                                QUERY PLAN                                
11832 -------------------------------------------------------------------------
11833  Insert on public.insert_tbl
11834    Remote SQL: INSERT INTO public.base_tbl4(a, b, c) VALUES ($1, $2, $3)
11835    Batch Size: 1
11836    ->  Append
11837          ->  Seq Scan on public.local_tbl
11838                Output: local_tbl.a, local_tbl.b, local_tbl.c
11839          ->  Async Foreign Scan on public.remote_tbl
11840                Output: remote_tbl.a, remote_tbl.b, remote_tbl.c
11841                Remote SQL: SELECT a, b, c FROM public.base_tbl3
11842 (9 rows)
11844 INSERT INTO insert_tbl (SELECT * FROM local_tbl UNION ALL SELECT * FROM remote_tbl);
11845 SELECT * FROM insert_tbl ORDER BY a;
11846   a   |  b  |  c  
11847 ------+-----+-----
11848  1505 | 505 | foo
11849  2505 | 505 | bar
11850 (2 rows)
11852 -- Check with direct modify
11853 EXPLAIN (VERBOSE, COSTS OFF)
11854 WITH t AS (UPDATE remote_tbl SET c = c || c RETURNING *)
11855 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;
11856                                        QUERY PLAN                                       
11857 ----------------------------------------------------------------------------------------
11858  Insert on public.join_tbl
11859    CTE t
11860      ->  Update on public.remote_tbl
11861            Output: remote_tbl.a, remote_tbl.b, remote_tbl.c
11862            ->  Foreign Update on public.remote_tbl
11863                  Remote SQL: UPDATE public.base_tbl3 SET c = (c || c) RETURNING a, b, c
11864    ->  Nested Loop Left Join
11865          Output: async_pt.a, async_pt.b, async_pt.c, t.a, t.b, t.c
11866          Join Filter: ((async_pt.a = t.a) AND (async_pt.b = t.b))
11867          ->  Append
11868                ->  Async Foreign Scan on public.async_p1 async_pt_1
11869                      Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11870                      Filter: (async_pt_1.b === 505)
11871                      Remote SQL: SELECT a, b, c FROM public.base_tbl1
11872                ->  Async Foreign Scan on public.async_p2 async_pt_2
11873                      Output: async_pt_2.a, async_pt_2.b, async_pt_2.c
11874                      Filter: (async_pt_2.b === 505)
11875                      Remote SQL: SELECT a, b, c FROM public.base_tbl2
11876                ->  Seq Scan on public.async_p3 async_pt_3
11877                      Output: async_pt_3.a, async_pt_3.b, async_pt_3.c
11878                      Filter: (async_pt_3.b === 505)
11879          ->  CTE Scan on t
11880                Output: t.a, t.b, t.c
11881 (23 rows)
11883 WITH t AS (UPDATE remote_tbl SET c = c || c RETURNING *)
11884 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;
11885 SELECT * FROM join_tbl ORDER BY a1;
11886   a1  | b1  |  c1  |  a2  | b2  |   c2   
11887 ------+-----+------+------+-----+--------
11888  1505 | 505 | 0505 |      |     | 
11889  2505 | 505 | 0505 | 2505 | 505 | barbar
11890  3505 | 505 | 0505 |      |     | 
11891 (3 rows)
11893 DELETE FROM join_tbl;
11894 DROP TABLE local_tbl;
11895 DROP FOREIGN TABLE remote_tbl;
11896 DROP FOREIGN TABLE insert_tbl;
11897 DROP TABLE base_tbl3;
11898 DROP TABLE base_tbl4;
11899 RESET enable_mergejoin;
11900 RESET enable_hashjoin;
11901 -- Test that UPDATE/DELETE with inherited target works with async_capable enabled
11902 EXPLAIN (VERBOSE, COSTS OFF)
11903 UPDATE async_pt SET c = c || c WHERE b = 0 RETURNING *;
11904                                                 QUERY PLAN                                                
11905 ----------------------------------------------------------------------------------------------------------
11906  Update on public.async_pt
11907    Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11908    Foreign Update on public.async_p1 async_pt_1
11909    Foreign Update on public.async_p2 async_pt_2
11910    Update on public.async_p3 async_pt_3
11911    ->  Append
11912          ->  Foreign Update on public.async_p1 async_pt_1
11913                Remote SQL: UPDATE public.base_tbl1 SET c = (c || c) WHERE ((b = 0)) RETURNING a, b, c
11914          ->  Foreign Update on public.async_p2 async_pt_2
11915                Remote SQL: UPDATE public.base_tbl2 SET c = (c || c) WHERE ((b = 0)) RETURNING a, b, c
11916          ->  Seq Scan on public.async_p3 async_pt_3
11917                Output: (async_pt_3.c || async_pt_3.c), async_pt_3.tableoid, async_pt_3.ctid, NULL::record
11918                Filter: (async_pt_3.b = 0)
11919 (13 rows)
11921 UPDATE async_pt SET c = c || c WHERE b = 0 RETURNING *;
11922   a   | b |    c     
11923 ------+---+----------
11924  1000 | 0 | 00000000
11925  2000 | 0 | 00000000
11926  3000 | 0 | 00000000
11927 (3 rows)
11929 EXPLAIN (VERBOSE, COSTS OFF)
11930 DELETE FROM async_pt WHERE b = 0 RETURNING *;
11931                                         QUERY PLAN                                        
11932 ------------------------------------------------------------------------------------------
11933  Delete on public.async_pt
11934    Output: async_pt_1.a, async_pt_1.b, async_pt_1.c
11935    Foreign Delete on public.async_p1 async_pt_1
11936    Foreign Delete on public.async_p2 async_pt_2
11937    Delete on public.async_p3 async_pt_3
11938    ->  Append
11939          ->  Foreign Delete on public.async_p1 async_pt_1
11940                Remote SQL: DELETE FROM public.base_tbl1 WHERE ((b = 0)) RETURNING a, b, c
11941          ->  Foreign Delete on public.async_p2 async_pt_2
11942                Remote SQL: DELETE FROM public.base_tbl2 WHERE ((b = 0)) RETURNING a, b, c
11943          ->  Seq Scan on public.async_p3 async_pt_3
11944                Output: async_pt_3.tableoid, async_pt_3.ctid
11945                Filter: (async_pt_3.b = 0)
11946 (13 rows)
11948 DELETE FROM async_pt WHERE b = 0 RETURNING *;
11949   a   | b |    c     
11950 ------+---+----------
11951  1000 | 0 | 00000000
11952  2000 | 0 | 00000000
11953  3000 | 0 | 00000000
11954 (3 rows)
11956 -- Check EXPLAIN ANALYZE for a query that scans empty partitions asynchronously
11957 DELETE FROM async_p1;
11958 DELETE FROM async_p2;
11959 DELETE FROM async_p3;
11960 EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
11961 SELECT * FROM async_pt;
11962                                QUERY PLAN                                
11963 -------------------------------------------------------------------------
11964  Append (actual rows=0 loops=1)
11965    ->  Async Foreign Scan on async_p1 async_pt_1 (actual rows=0 loops=1)
11966    ->  Async Foreign Scan on async_p2 async_pt_2 (actual rows=0 loops=1)
11967    ->  Seq Scan on async_p3 async_pt_3 (actual rows=0 loops=1)
11968 (4 rows)
11970 -- Clean up
11971 DROP TABLE async_pt;
11972 DROP TABLE base_tbl1;
11973 DROP TABLE base_tbl2;
11974 DROP TABLE result_tbl;
11975 DROP TABLE join_tbl;
11976 -- Test that an asynchronous fetch is processed before restarting the scan in
11977 -- ReScanForeignScan
11978 CREATE TABLE base_tbl (a int, b int);
11979 INSERT INTO base_tbl VALUES (1, 11), (2, 22), (3, 33);
11980 CREATE FOREIGN TABLE foreign_tbl (b int)
11981   SERVER loopback OPTIONS (table_name 'base_tbl');
11982 CREATE FOREIGN TABLE foreign_tbl2 () INHERITS (foreign_tbl)
11983   SERVER loopback OPTIONS (table_name 'base_tbl');
11984 EXPLAIN (VERBOSE, COSTS OFF)
11985 SELECT a FROM base_tbl WHERE (a, random() > 0) IN (SELECT a, random() > 0 FROM foreign_tbl);
11986                                                   QUERY PLAN                                                   
11987 ---------------------------------------------------------------------------------------------------------------
11988  Seq Scan on public.base_tbl
11989    Output: base_tbl.a
11990    Filter: (ANY ((base_tbl.a = (SubPlan 1).col1) AND ((random() > '0'::double precision) = (SubPlan 1).col2)))
11991    SubPlan 1
11992      ->  Result
11993            Output: base_tbl.a, (random() > '0'::double precision)
11994            ->  Append
11995                  ->  Async Foreign Scan on public.foreign_tbl foreign_tbl_1
11996                        Remote SQL: SELECT NULL FROM public.base_tbl
11997                  ->  Async Foreign Scan on public.foreign_tbl2 foreign_tbl_2
11998                        Remote SQL: SELECT NULL FROM public.base_tbl
11999 (11 rows)
12001 SELECT a FROM base_tbl WHERE (a, random() > 0) IN (SELECT a, random() > 0 FROM foreign_tbl);
12002  a 
12007 (3 rows)
12009 -- Clean up
12010 DROP FOREIGN TABLE foreign_tbl CASCADE;
12011 NOTICE:  drop cascades to foreign table foreign_tbl2
12012 DROP TABLE base_tbl;
12013 ALTER SERVER loopback OPTIONS (DROP async_capable);
12014 ALTER SERVER loopback2 OPTIONS (DROP async_capable);
12015 -- ===================================================================
12016 -- test invalid server, foreign table and foreign data wrapper options
12017 -- ===================================================================
12018 -- Invalid fdw_startup_cost option
12019 CREATE SERVER inv_scst FOREIGN DATA WRAPPER postgres_fdw
12020         OPTIONS(fdw_startup_cost '100$%$#$#');
12021 ERROR:  invalid value for floating point option "fdw_startup_cost": 100$%$#$#
12022 -- Invalid fdw_tuple_cost option
12023 CREATE SERVER inv_scst FOREIGN DATA WRAPPER postgres_fdw
12024         OPTIONS(fdw_tuple_cost '100$%$#$#');
12025 ERROR:  invalid value for floating point option "fdw_tuple_cost": 100$%$#$#
12026 -- Invalid fetch_size option
12027 CREATE FOREIGN TABLE inv_fsz (c1 int )
12028         SERVER loopback OPTIONS (fetch_size '100$%$#$#');
12029 ERROR:  invalid value for integer option "fetch_size": 100$%$#$#
12030 -- Invalid batch_size option
12031 CREATE FOREIGN TABLE inv_bsz (c1 int )
12032         SERVER loopback OPTIONS (batch_size '100$%$#$#');
12033 ERROR:  invalid value for integer option "batch_size": 100$%$#$#
12034 -- No option is allowed to be specified at foreign data wrapper level
12035 ALTER FOREIGN DATA WRAPPER postgres_fdw OPTIONS (nonexistent 'fdw');
12036 ERROR:  invalid option "nonexistent"
12037 HINT:  There are no valid options in this context.
12038 -- ===================================================================
12039 -- test postgres_fdw.application_name GUC
12040 -- ===================================================================
12041 -- To avoid race conditions in checking the remote session's application_name,
12042 -- use this view to make the remote session itself read its application_name.
12043 CREATE VIEW my_application_name AS
12044   SELECT application_name FROM pg_stat_activity WHERE pid = pg_backend_pid();
12045 CREATE FOREIGN TABLE remote_application_name (application_name text)
12046   SERVER loopback2
12047   OPTIONS (schema_name 'public', table_name 'my_application_name');
12048 SELECT count(*) FROM remote_application_name;
12049  count 
12050 -------
12051      1
12052 (1 row)
12054 -- Specify escape sequences in application_name option of a server
12055 -- object so as to test that they are replaced with status information
12056 -- expectedly.  Note that we are also relying on ALTER SERVER to force
12057 -- the remote session to be restarted with its new application name.
12059 -- Since pg_stat_activity.application_name may be truncated to less than
12060 -- NAMEDATALEN characters, note that substring() needs to be used
12061 -- at the condition of test query to make sure that the string consisting
12062 -- of database name and process ID is also less than that.
12063 ALTER SERVER loopback2 OPTIONS (application_name 'fdw_%d%p');
12064 SELECT count(*) FROM remote_application_name
12065   WHERE application_name =
12066     substring('fdw_' || current_database() || pg_backend_pid() for
12067       current_setting('max_identifier_length')::int);
12068  count 
12069 -------
12070      1
12071 (1 row)
12073 -- postgres_fdw.application_name overrides application_name option
12074 -- of a server object if both settings are present.
12075 ALTER SERVER loopback2 OPTIONS (SET application_name 'fdw_wrong');
12076 SET postgres_fdw.application_name TO 'fdw_%a%u%%';
12077 SELECT count(*) FROM remote_application_name
12078   WHERE application_name =
12079     substring('fdw_' || current_setting('application_name') ||
12080       CURRENT_USER || '%' for current_setting('max_identifier_length')::int);
12081  count 
12082 -------
12083      1
12084 (1 row)
12086 RESET postgres_fdw.application_name;
12087 -- Test %c (session ID) and %C (cluster name) escape sequences.
12088 ALTER SERVER loopback2 OPTIONS (SET application_name 'fdw_%C%c');
12089 SELECT count(*) FROM remote_application_name
12090   WHERE application_name =
12091     substring('fdw_' || current_setting('cluster_name') ||
12092       to_hex(trunc(EXTRACT(EPOCH FROM (SELECT backend_start FROM
12093       pg_stat_get_activity(pg_backend_pid()))))::integer) || '.' ||
12094       to_hex(pg_backend_pid())
12095       for current_setting('max_identifier_length')::int);
12096  count 
12097 -------
12098      1
12099 (1 row)
12101 -- Clean up.
12102 DROP FOREIGN TABLE remote_application_name;
12103 DROP VIEW my_application_name;
12104 -- ===================================================================
12105 -- test parallel commit and parallel abort
12106 -- ===================================================================
12107 ALTER SERVER loopback OPTIONS (ADD parallel_commit 'true');
12108 ALTER SERVER loopback OPTIONS (ADD parallel_abort 'true');
12109 ALTER SERVER loopback2 OPTIONS (ADD parallel_commit 'true');
12110 ALTER SERVER loopback2 OPTIONS (ADD parallel_abort 'true');
12111 CREATE TABLE ploc1 (f1 int, f2 text);
12112 CREATE FOREIGN TABLE prem1 (f1 int, f2 text)
12113   SERVER loopback OPTIONS (table_name 'ploc1');
12114 CREATE TABLE ploc2 (f1 int, f2 text);
12115 CREATE FOREIGN TABLE prem2 (f1 int, f2 text)
12116   SERVER loopback2 OPTIONS (table_name 'ploc2');
12117 BEGIN;
12118 INSERT INTO prem1 VALUES (101, 'foo');
12119 INSERT INTO prem2 VALUES (201, 'bar');
12120 COMMIT;
12121 SELECT * FROM prem1;
12122  f1  | f2  
12123 -----+-----
12124  101 | foo
12125 (1 row)
12127 SELECT * FROM prem2;
12128  f1  | f2  
12129 -----+-----
12130  201 | bar
12131 (1 row)
12133 BEGIN;
12134 SAVEPOINT s;
12135 INSERT INTO prem1 VALUES (102, 'foofoo');
12136 INSERT INTO prem2 VALUES (202, 'barbar');
12137 RELEASE SAVEPOINT s;
12138 COMMIT;
12139 SELECT * FROM prem1;
12140  f1  |   f2   
12141 -----+--------
12142  101 | foo
12143  102 | foofoo
12144 (2 rows)
12146 SELECT * FROM prem2;
12147  f1  |   f2   
12148 -----+--------
12149  201 | bar
12150  202 | barbar
12151 (2 rows)
12153 -- This tests executing DEALLOCATE ALL against foreign servers in parallel
12154 -- during pre-commit
12155 BEGIN;
12156 SAVEPOINT s;
12157 INSERT INTO prem1 VALUES (103, 'baz');
12158 INSERT INTO prem2 VALUES (203, 'qux');
12159 ROLLBACK TO SAVEPOINT s;
12160 RELEASE SAVEPOINT s;
12161 INSERT INTO prem1 VALUES (104, 'bazbaz');
12162 INSERT INTO prem2 VALUES (204, 'quxqux');
12163 COMMIT;
12164 SELECT * FROM prem1;
12165  f1  |   f2   
12166 -----+--------
12167  101 | foo
12168  102 | foofoo
12169  104 | bazbaz
12170 (3 rows)
12172 SELECT * FROM prem2;
12173  f1  |   f2   
12174 -----+--------
12175  201 | bar
12176  202 | barbar
12177  204 | quxqux
12178 (3 rows)
12180 BEGIN;
12181 INSERT INTO prem1 VALUES (105, 'test1');
12182 INSERT INTO prem2 VALUES (205, 'test2');
12183 ABORT;
12184 SELECT * FROM prem1;
12185  f1  |   f2   
12186 -----+--------
12187  101 | foo
12188  102 | foofoo
12189  104 | bazbaz
12190 (3 rows)
12192 SELECT * FROM prem2;
12193  f1  |   f2   
12194 -----+--------
12195  201 | bar
12196  202 | barbar
12197  204 | quxqux
12198 (3 rows)
12200 -- This tests executing DEALLOCATE ALL against foreign servers in parallel
12201 -- during post-abort
12202 BEGIN;
12203 SAVEPOINT s;
12204 INSERT INTO prem1 VALUES (105, 'test1');
12205 INSERT INTO prem2 VALUES (205, 'test2');
12206 ROLLBACK TO SAVEPOINT s;
12207 RELEASE SAVEPOINT s;
12208 INSERT INTO prem1 VALUES (105, 'test1');
12209 INSERT INTO prem2 VALUES (205, 'test2');
12210 ABORT;
12211 SELECT * FROM prem1;
12212  f1  |   f2   
12213 -----+--------
12214  101 | foo
12215  102 | foofoo
12216  104 | bazbaz
12217 (3 rows)
12219 SELECT * FROM prem2;
12220  f1  |   f2   
12221 -----+--------
12222  201 | bar
12223  202 | barbar
12224  204 | quxqux
12225 (3 rows)
12227 ALTER SERVER loopback OPTIONS (DROP parallel_commit);
12228 ALTER SERVER loopback OPTIONS (DROP parallel_abort);
12229 ALTER SERVER loopback2 OPTIONS (DROP parallel_commit);
12230 ALTER SERVER loopback2 OPTIONS (DROP parallel_abort);
12231 -- ===================================================================
12232 -- test for ANALYZE sampling
12233 -- ===================================================================
12234 CREATE TABLE analyze_table (id int, a text, b bigint);
12235 CREATE FOREIGN TABLE analyze_ftable (id int, a text, b bigint)
12236        SERVER loopback OPTIONS (table_name 'analyze_rtable1');
12237 INSERT INTO analyze_table (SELECT x FROM generate_series(1,1000) x);
12238 ANALYZE analyze_table;
12239 SET default_statistics_target = 10;
12240 ANALYZE analyze_table;
12241 ALTER SERVER loopback OPTIONS (analyze_sampling 'invalid');
12242 ERROR:  invalid value for string option "analyze_sampling": invalid
12243 ALTER SERVER loopback OPTIONS (analyze_sampling 'auto');
12244 ANALYZE analyze_table;
12245 ALTER SERVER loopback OPTIONS (SET analyze_sampling 'system');
12246 ANALYZE analyze_table;
12247 ALTER SERVER loopback OPTIONS (SET analyze_sampling 'bernoulli');
12248 ANALYZE analyze_table;
12249 ALTER SERVER loopback OPTIONS (SET analyze_sampling 'random');
12250 ANALYZE analyze_table;
12251 ALTER SERVER loopback OPTIONS (SET analyze_sampling 'off');
12252 ANALYZE analyze_table;
12253 -- cleanup
12254 DROP FOREIGN TABLE analyze_ftable;
12255 DROP TABLE analyze_table;