@@ -631,6 +631,17 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT * FROM ft_empty ORDER BY c1;
631
631
Remote SQL: SELECT c1, c2 FROM public.loct_empty ORDER BY c1 ASC NULLS LAST
632
632
(3 rows)
633
633
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;
634
645
-- ===================================================================
635
646
-- WHERE with remotely-executable conditions
636
647
-- ===================================================================
@@ -738,10 +749,10 @@ EXPLAIN (VERBOSE, COSTS OFF)
738
749
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (($1::integer = "C 1"))
739
750
(8 rows)
740
751
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
745
756
(1 row)
746
757
747
758
-- 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));
887
898
4 | 4 | 00004 | Mon Jan 05 00:00:00 1970 PST | Mon Jan 05 00:00:00 1970 | 4 | 4 | foo
888
899
(4 rows)
889
900
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
-
916
901
-- user-defined operator/function
917
902
CREATE FUNCTION postgres_fdw_abs(int) RETURNS int AS $$
918
903
BEGIN
@@ -1067,6 +1052,27 @@ SELECT * FROM ft1 t1 WHERE t1.c1 === t1.c2 order by t1.c2 limit 1;
1067
1052
1 | 1 | 00001 | Fri Jan 02 00:00:00 1970 PST | Fri Jan 02 00:00:00 1970 | 1 | 1 | foo
1068
1053
(1 row)
1069
1054
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
+
1070
1076
-- check schema-qualification of regconfig constant
1071
1077
CREATE TEXT SEARCH CONFIGURATION public.custom_search
1072
1078
(COPY = pg_catalog.english);
@@ -1087,6 +1093,73 @@ WHERE c1 = 642 AND length(to_tsvector('custom_search'::regconfig, c3)) > 0;
1087
1093
642 | '00642':1
1088
1094
(1 row)
1089
1095
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
+
1090
1163
-- ===================================================================
1091
1164
-- JOIN queries
1092
1165
-- ===================================================================
@@ -2197,6 +2270,32 @@ SELECT t1."C 1" FROM "S 1"."T 1" t1, LATERAL (SELECT DISTINCT t2.c1, t3.c1 FROM
2197
2270
1
2198
2271
(10 rows)
2199
2272
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
+
2200
2299
-- non-Var items in targetlist of the nullable rel of a join preventing
2201
2300
-- push-down in some cases
2202
2301
-- unable to push {ft1, ft2}
@@ -6724,6 +6823,28 @@ select * from grem1;
6724
6823
(2 rows)
6725
6824
6726
6825
delete 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;
6727
6848
alter server loopback options (drop batch_size);
6728
6849
-- ===================================================================
6729
6850
-- test local triggers
@@ -9969,17 +10090,6 @@ SELECT COUNT(*) FROM ftable;
9969
10090
34
9970
10091
(1 row)
9971
10092
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
-
9983
10093
TRUNCATE batch_table;
9984
10094
DROP FOREIGN TABLE ftable;
9985
10095
-- Disable batch insert
@@ -10366,6 +10476,13 @@ SELECT * FROM result_tbl ORDER BY a;
10366
10476
(2 rows)
10367
10477
10368
10478
DELETE 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;
10369
10486
-- Check case where multiple partitions use the same connection
10370
10487
CREATE TABLE base_tbl3 (a int, b int, c text);
10371
10488
CREATE FOREIGN TABLE async_p3 PARTITION OF async_pt FOR VALUES FROM (3000) TO (4000)
0 commit comments