@@ -631,6 +631,17 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft_empty ORDER BY c1;
631631 Remote SQL: SELECT c1, c2 FROM public.loct_empty ORDER BY c1 ASC NULLS LAST
632632(3 rows)
633633
634+ -- test restriction on non-system foreign tables.
635+ SET restrict_nonsystem_relation_kind TO 'foreign-table';
636+ SELECT * from ft1 where c1 < 1; -- ERROR
637+ ERROR: access to non-system foreign table is restricted
638+ INSERT INTO ft1 (c1) VALUES (1); -- ERROR
639+ ERROR: access to non-system foreign table is restricted
640+ DELETE FROM ft1 WHERE c1 = 1; -- ERROR
641+ ERROR: access to non-system foreign table is restricted
642+ TRUNCATE ft1; -- ERROR
643+ ERROR: access to non-system foreign table is restricted
644+ RESET restrict_nonsystem_relation_kind;
634645-- ===================================================================
635646-- WHERE with remotely-executable conditions
636647-- ===================================================================
@@ -738,10 +749,10 @@ EXPLAIN (VERBOSE, COSTS OFF)
738749 Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (($1::integer = "C 1"))
739750(8 rows)
740751
741- SELECT * FROM ft2 a, ft2 b WHERE a.c1 = 47 AND b.c1 = a.c2;
742- c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8
743- ----+----+-------+------------------------------+--------------------------+----+------------+-----+----+----+-------+------------------------------+--------------------------+----+------------+-----
744- 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
752+ SELECT * FROM "S 1"."T 1" a, ft2 b WHERE a."C 1" = 47 AND b.c1 = a.c2;
753+ C 1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 | c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8
754+ ----- +----+-------+------------------------------+--------------------------+----+------------+-----+----+----+-------+------------------------------+--------------------------+----+------------+-----
755+ 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
745756(1 row)
746757
747758-- check both safe and unsafe join conditions
@@ -887,32 +898,6 @@ SELECT * FROM ft2 WHERE c1 = ANY (ARRAY(SELECT c1 FROM ft1 WHERE c1 < 5));
887898 4 | 4 | 00004 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4 | 4 | foo
888899(4 rows)
889900
890- -- we should not push order by clause with volatile expressions or unsafe
891- -- collations
892- EXPLAIN (VERBOSE, COSTS OFF)
893- SELECT * FROM ft2 ORDER BY ft2.c1, random();
894- QUERY PLAN
895- -------------------------------------------------------------------------------
896- Sort
897- Output: c1, c2, c3, c4, c5, c6, c7, c8, (random())
898- Sort Key: ft2.c1, (random())
899- -> Foreign Scan on public.ft2
900- Output: c1, c2, c3, c4, c5, c6, c7, c8, random()
901- Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
902- (6 rows)
903-
904- EXPLAIN (VERBOSE, COSTS OFF)
905- SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
906- QUERY PLAN
907- -------------------------------------------------------------------------------
908- Sort
909- Output: c1, c2, c3, c4, c5, c6, c7, c8, ((c3)::text)
910- Sort Key: ft2.c1, ft2.c3 COLLATE "C"
911- -> Foreign Scan on public.ft2
912- Output: c1, c2, c3, c4, c5, c6, c7, c8, c3
913- Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
914- (6 rows)
915-
916901-- user-defined operator/function
917902CREATE FUNCTION postgres_fdw_abs(int) RETURNS int AS $$
918903BEGIN
@@ -1067,6 +1052,27 @@ SELECT * FROM ft1 t1 WHERE t1.c1 === t1.c2 order by t1.c2 limit 1;
10671052 1 | 1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1 | 1 | foo
10681053(1 row)
10691054
1055+ -- Ensure we don't ship FETCH FIRST .. WITH TIES
1056+ EXPLAIN (VERBOSE, COSTS OFF)
1057+ SELECT t1.c2 FROM ft1 t1 WHERE t1.c1 > 960 ORDER BY t1.c2 FETCH FIRST 2 ROWS WITH TIES;
1058+ QUERY PLAN
1059+ -------------------------------------------------------------------------------------------------
1060+ Limit
1061+ Output: c2
1062+ -> Foreign Scan on public.ft1 t1
1063+ Output: c2
1064+ Remote SQL: SELECT c2 FROM "S 1"."T 1" WHERE (("C 1" > 960)) ORDER BY c2 ASC NULLS LAST
1065+ (5 rows)
1066+
1067+ SELECT t1.c2 FROM ft1 t1 WHERE t1.c1 > 960 ORDER BY t1.c2 FETCH FIRST 2 ROWS WITH TIES;
1068+ c2
1069+ ----
1070+ 0
1071+ 0
1072+ 0
1073+ 0
1074+ (4 rows)
1075+
10701076-- check schema-qualification of regconfig constant
10711077CREATE TEXT SEARCH CONFIGURATION public.custom_search
10721078 (COPY = pg_catalog.english);
@@ -1087,6 +1093,73 @@ WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
10871093 642 | '00642':1
10881094(1 row)
10891095
1096+ -- ===================================================================
1097+ -- ORDER BY queries
1098+ -- ===================================================================
1099+ -- we should not push order by clause with volatile expressions or unsafe
1100+ -- collations
1101+ EXPLAIN (VERBOSE, COSTS OFF)
1102+ SELECT * FROM ft2 ORDER BY ft2.c1, random();
1103+ QUERY PLAN
1104+ -------------------------------------------------------------------------------
1105+ Sort
1106+ Output: c1, c2, c3, c4, c5, c6, c7, c8, (random())
1107+ Sort Key: ft2.c1, (random())
1108+ -> Foreign Scan on public.ft2
1109+ Output: c1, c2, c3, c4, c5, c6, c7, c8, random()
1110+ Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1111+ (6 rows)
1112+
1113+ EXPLAIN (VERBOSE, COSTS OFF)
1114+ SELECT * FROM ft2 ORDER BY ft2.c1, ft2.c3 collate "C";
1115+ QUERY PLAN
1116+ -------------------------------------------------------------------------------
1117+ Sort
1118+ Output: c1, c2, c3, c4, c5, c6, c7, c8, ((c3)::text)
1119+ Sort Key: ft2.c1, ft2.c3 COLLATE "C"
1120+ -> Foreign Scan on public.ft2
1121+ Output: c1, c2, c3, c4, c5, c6, c7, c8, c3
1122+ Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
1123+ (6 rows)
1124+
1125+ -- Ensure we don't push ORDER BY expressions which are Consts at the UNION
1126+ -- child level to the foreign server.
1127+ EXPLAIN (VERBOSE, COSTS OFF)
1128+ SELECT * FROM (
1129+ SELECT 1 AS type,c1 FROM ft1
1130+ UNION ALL
1131+ SELECT 2 AS type,c1 FROM ft2
1132+ ) a ORDER BY type,c1;
1133+ QUERY PLAN
1134+ ---------------------------------------------------------------------------------
1135+ Merge Append
1136+ Sort Key: (1), ft1.c1
1137+ -> Foreign Scan on public.ft1
1138+ Output: 1, ft1.c1
1139+ Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
1140+ -> Foreign Scan on public.ft2
1141+ Output: 2, ft2.c1
1142+ Remote SQL: SELECT "C 1" FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
1143+ (8 rows)
1144+
1145+ EXPLAIN (VERBOSE, COSTS OFF)
1146+ SELECT * FROM (
1147+ SELECT 1 AS type,c1 FROM ft1
1148+ UNION ALL
1149+ SELECT 2 AS type,c1 FROM ft2
1150+ ) a ORDER BY type;
1151+ QUERY PLAN
1152+ ---------------------------------------------------
1153+ Merge Append
1154+ Sort Key: (1)
1155+ -> Foreign Scan on public.ft1
1156+ Output: 1, ft1.c1
1157+ Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
1158+ -> Foreign Scan on public.ft2
1159+ Output: 2, ft2.c1
1160+ Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
1161+ (8 rows)
1162+
10901163-- ===================================================================
10911164-- JOIN queries
10921165-- ===================================================================
@@ -2197,6 +2270,32 @@ SELECT t1."C 1" FROM "S 1"."T 1" t1, LATERAL (SELECT DISTINCT t2.c1, t3.c1 FROM
21972270 1
21982271(10 rows)
21992272
2273+ -- join with pseudoconstant quals, not pushed down.
2274+ EXPLAIN (VERBOSE, COSTS OFF)
2275+ 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;
2276+ QUERY PLAN
2277+ -------------------------------------------------------------------------------
2278+ Limit
2279+ Output: t1.c1, t2.c1, t1.c3
2280+ -> Sort
2281+ Output: t1.c1, t2.c1, t1.c3
2282+ Sort Key: t1.c3, t1.c1
2283+ -> Result
2284+ Output: t1.c1, t2.c1, t1.c3
2285+ One-Time Filter: (CURRENT_USER = SESSION_USER)
2286+ -> Hash Join
2287+ Output: t1.c1, t1.c3, t2.c1
2288+ Hash Cond: (t2.c1 = t1.c1)
2289+ -> Foreign Scan on public.ft2 t2
2290+ Output: t2.c1
2291+ Remote SQL: SELECT "C 1" FROM "S 1"."T 1"
2292+ -> Hash
2293+ Output: t1.c1, t1.c3
2294+ -> Foreign Scan on public.ft1 t1
2295+ Output: t1.c1, t1.c3
2296+ Remote SQL: SELECT "C 1", c3 FROM "S 1"."T 1"
2297+ (19 rows)
2298+
22002299-- non-Var items in targetlist of the nullable rel of a join preventing
22012300-- push-down in some cases
22022301-- unable to push {ft1, ft2}
@@ -6724,6 +6823,28 @@ select * from grem1;
67246823(2 rows)
67256824
67266825delete from grem1;
6826+ -- batch insert with foreign partitions.
6827+ -- This schema uses two partitions, one local and one remote with a modulo
6828+ -- to loop across all of them in batches.
6829+ create table tab_batch_local (id int, data text);
6830+ insert into tab_batch_local select i, 'test'|| i from generate_series(1, 45) i;
6831+ create table tab_batch_sharded (id int, data text) partition by hash(id);
6832+ create table tab_batch_sharded_p0 partition of tab_batch_sharded
6833+ for values with (modulus 2, remainder 0);
6834+ create table tab_batch_sharded_p1_remote (id int, data text);
6835+ create foreign table tab_batch_sharded_p1 partition of tab_batch_sharded
6836+ for values with (modulus 2, remainder 1)
6837+ server loopback options (table_name 'tab_batch_sharded_p1_remote');
6838+ insert into tab_batch_sharded select * from tab_batch_local;
6839+ select count(*) from tab_batch_sharded;
6840+ count
6841+ -------
6842+ 45
6843+ (1 row)
6844+
6845+ drop table tab_batch_local;
6846+ drop table tab_batch_sharded;
6847+ drop table tab_batch_sharded_p1_remote;
67276848alter server loopback options (drop batch_size);
67286849-- ===================================================================
67296850-- test local triggers
@@ -9969,17 +10090,6 @@ SELECT COUNT(*) FROM ftable;
996910090 34
997010091(1 row)
997110092
9972- TRUNCATE batch_table;
9973- DROP FOREIGN TABLE ftable;
9974- -- try if large batches exceed max number of bind parameters
9975- CREATE FOREIGN TABLE ftable ( x int ) SERVER loopback OPTIONS ( table_name 'batch_table', batch_size '100000' );
9976- INSERT INTO ftable SELECT * FROM generate_series(1, 70000) i;
9977- SELECT COUNT(*) FROM ftable;
9978- count
9979- -------
9980- 70000
9981- (1 row)
9982-
998310093TRUNCATE batch_table;
998410094DROP FOREIGN TABLE ftable;
998510095-- Disable batch insert
@@ -10366,6 +10476,13 @@ SELECT * FROM result_tbl ORDER BY a;
1036610476(2 rows)
1036710477
1036810478DELETE FROM result_tbl;
10479+ -- Test error handling, if accessing one of the foreign partitions errors out
10480+ CREATE FOREIGN TABLE async_p_broken PARTITION OF async_pt FOR VALUES FROM (10000) TO (10001)
10481+ SERVER loopback OPTIONS (table_name 'non_existent_table');
10482+ SELECT * FROM async_pt;
10483+ ERROR: relation "public.non_existent_table" does not exist
10484+ CONTEXT: remote SQL command: SELECT a, b, c FROM public.non_existent_table
10485+ DROP FOREIGN TABLE async_p_broken;
1036910486-- Check case where multiple partitions use the same connection
1037010487CREATE TABLE base_tbl3 (a int, b int, c text);
1037110488CREATE FOREIGN TABLE async_p3 PARTITION OF async_pt FOR VALUES FROM (3000) TO (4000)
0 commit comments