Skip to content

Commit 5bee956

Browse files
Etsuro Fujitareshke
authored andcommitted
postgres_fdw: Disable batch insertion when there are WCO constraints.
When inserting a view referencing a foreign table that has WITH CHECK OPTION constraints, in single-insert mode postgres_fdw retrieves the data that was actually inserted on the remote side so that the WITH CHECK OPTION constraints are enforced with the data locally, but in batch-insert mode it cannot currently retrieve the data (except for the row first inserted through the view), resulting in enforcing the WITH CHECK OPTION constraints with the data passed from the core (except for the first-inserted row), which led to incorrect results when inserting into a view referencing a foreign table in which a remote BEFORE ROW INSERT trigger changes the rows inserted through the view so that they violate the view's WITH CHECK OPTION constraint. Also, the query inserting into the view caused an assertion failure in assert-enabled builds. Fix these by disabling batch insertion when inserting into such a view. Back-patch to v14 where batch insertion was added. Discussion: https://postgr.es/m/CAPmGK17LpbTZs4m4a_6THP54UBeK9fHvX8aVVA%2BC6yEZDZwQcg%40mail.gmail.com
1 parent 7e30f9d commit 5bee956

3 files changed

Lines changed: 64 additions & 2 deletions

File tree

contrib/postgres_fdw/expected/postgres_fdw.out

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6486,6 +6486,29 @@ SELECT * FROM foreign_tbl;
64866486
20 | 30
64876487
(1 row)
64886488

6489+
-- We don't allow batch insert when there are any WCO constraints
6490+
ALTER SERVER loopback OPTIONS (ADD batch_size '10');
6491+
EXPLAIN (VERBOSE, COSTS OFF)
6492+
INSERT INTO rw_view VALUES (0, 15), (0, 5);
6493+
QUERY PLAN
6494+
--------------------------------------------------------------------------------
6495+
Insert on public.foreign_tbl
6496+
Remote SQL: INSERT INTO public.base_tbl(a, b) VALUES ($1, $2) RETURNING a, b
6497+
Batch Size: 1
6498+
-> Values Scan on "*VALUES*"
6499+
Output: "*VALUES*".column1, "*VALUES*".column2
6500+
(5 rows)
6501+
6502+
INSERT INTO rw_view VALUES (0, 15), (0, 5); -- should fail
6503+
ERROR: new row violates check option for view "rw_view"
6504+
DETAIL: Failing row contains (10, 5).
6505+
SELECT * FROM foreign_tbl;
6506+
a | b
6507+
----+----
6508+
20 | 30
6509+
(1 row)
6510+
6511+
ALTER SERVER loopback OPTIONS (DROP batch_size);
64896512
DROP FOREIGN TABLE foreign_tbl CASCADE;
64906513
NOTICE: drop cascades to view rw_view
64916514
DROP TRIGGER row_before_insupd_trigger ON base_tbl;
@@ -6578,6 +6601,27 @@ SELECT * FROM foreign_tbl;
65786601
20 | 30
65796602
(1 row)
65806603

6604+
-- We don't allow batch insert when there are any WCO constraints
6605+
ALTER SERVER loopback OPTIONS (ADD batch_size '10');
6606+
EXPLAIN (VERBOSE, COSTS OFF)
6607+
INSERT INTO rw_view VALUES (0, 15), (0, 5);
6608+
QUERY PLAN
6609+
--------------------------------------------------------
6610+
Insert on public.parent_tbl
6611+
-> Values Scan on "*VALUES*"
6612+
Output: "*VALUES*".column1, "*VALUES*".column2
6613+
(3 rows)
6614+
6615+
INSERT INTO rw_view VALUES (0, 15), (0, 5); -- should fail
6616+
ERROR: new row violates check option for view "rw_view"
6617+
DETAIL: Failing row contains (10, 5).
6618+
SELECT * FROM foreign_tbl;
6619+
a | b
6620+
----+----
6621+
20 | 30
6622+
(1 row)
6623+
6624+
ALTER SERVER loopback OPTIONS (DROP batch_size);
65816625
DROP FOREIGN TABLE foreign_tbl CASCADE;
65826626
DROP TRIGGER row_before_insupd_trigger ON child_tbl;
65836627
DROP TABLE parent_tbl CASCADE;

contrib/postgres_fdw/postgres_fdw.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2046,15 +2046,17 @@ postgresGetForeignModifyBatchSize(ResultRelInfo *resultRelInfo)
20462046
batch_size = get_batch_size_option(resultRelInfo->ri_RelationDesc);
20472047

20482048
/*
2049-
* Disable batching when we have to use RETURNING or there are any
2050-
* BEFORE/AFTER ROW INSERT triggers on the foreign table.
2049+
* Disable batching when we have to use RETURNING, there are any
2050+
* BEFORE/AFTER ROW INSERT triggers on the foreign table, or there are any
2051+
* WITH CHECK OPTION constraints from parent views.
20512052
*
20522053
* When there are any BEFORE ROW INSERT triggers on the table, we can't
20532054
* support it, because such triggers might query the table we're inserting
20542055
* into and act differently if the tuples that have already been processed
20552056
* and prepared for insertion are not there.
20562057
*/
20572058
if (resultRelInfo->ri_projectReturning != NULL ||
2059+
resultRelInfo->ri_WithCheckOptions != NIL ||
20582060
(resultRelInfo->ri_TrigDesc &&
20592061
(resultRelInfo->ri_TrigDesc->trig_insert_before_row ||
20602062
resultRelInfo->ri_TrigDesc->trig_insert_after_row)))

contrib/postgres_fdw/sql/postgres_fdw.sql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1442,6 +1442,14 @@ UPDATE rw_view SET b = b + 15;
14421442
UPDATE rw_view SET b = b + 15; -- ok
14431443
SELECT * FROM foreign_tbl;
14441444

1445+
-- We don't allow batch insert when there are any WCO constraints
1446+
ALTER SERVER loopback OPTIONS (ADD batch_size '10');
1447+
EXPLAIN (VERBOSE, COSTS OFF)
1448+
INSERT INTO rw_view VALUES (0, 15), (0, 5);
1449+
INSERT INTO rw_view VALUES (0, 15), (0, 5); -- should fail
1450+
SELECT * FROM foreign_tbl;
1451+
ALTER SERVER loopback OPTIONS (DROP batch_size);
1452+
14451453
DROP FOREIGN TABLE foreign_tbl CASCADE;
14461454
DROP TRIGGER row_before_insupd_trigger ON base_tbl;
14471455
DROP TABLE base_tbl;
@@ -1480,6 +1488,14 @@ UPDATE rw_view SET b = b + 15;
14801488
UPDATE rw_view SET b = b + 15; -- ok
14811489
SELECT * FROM foreign_tbl;
14821490

1491+
-- We don't allow batch insert when there are any WCO constraints
1492+
ALTER SERVER loopback OPTIONS (ADD batch_size '10');
1493+
EXPLAIN (VERBOSE, COSTS OFF)
1494+
INSERT INTO rw_view VALUES (0, 15), (0, 5);
1495+
INSERT INTO rw_view VALUES (0, 15), (0, 5); -- should fail
1496+
SELECT * FROM foreign_tbl;
1497+
ALTER SERVER loopback OPTIONS (DROP batch_size);
1498+
14831499
DROP FOREIGN TABLE foreign_tbl CASCADE;
14841500
DROP TRIGGER row_before_insupd_trigger ON child_tbl;
14851501
DROP TABLE parent_tbl CASCADE;

0 commit comments

Comments
 (0)