]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
postgres_fdw: Disable batch insert when BEFORE ROW INSERT triggers exist.
authorEtsuro Fujita <efujita@postgresql.org>
Thu, 21 Apr 2022 06:30:02 +0000 (15:30 +0900)
committerEtsuro Fujita <efujita@postgresql.org>
Thu, 21 Apr 2022 06:30:02 +0000 (15:30 +0900)
Previously, we allowed this, but such triggers might query the table to
insert into and act differently if the tuples that have already been
processed and prepared for insertion are not there, so disable it in
such cases.

Back-patch to v14 where batch insert was added.

Discussion: https://postgr.es/m/CAPmGK16_uPqsmgK0-LpLSUk54_BoK13bPrhxhfjSoSTVz414hA%40mail.gmail.com

contrib/postgres_fdw/expected/postgres_fdw.out
contrib/postgres_fdw/postgres_fdw.c
contrib/postgres_fdw/sql/postgres_fdw.sql

index 02313dd28e2ae9b52c2b80a93acddf8e9970e7f3..8bcc18eca61909be7e6ea0ecfbf226b42fada444 100644 (file)
@@ -9868,6 +9868,34 @@ SELECT COUNT(*) FROM ftable;
      2
 (1 row)
 
+-- Disable batch inserting into foreign tables with BEFORE ROW INSERT triggers
+-- even if the batch_size option is enabled.
+ALTER FOREIGN TABLE ftable OPTIONS ( SET batch_size '10' );
+CREATE TRIGGER trig_row_before BEFORE INSERT ON ftable
+FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable VALUES (3), (4);
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Insert on public.ftable
+   Remote SQL: INSERT INTO public.batch_table(x) VALUES ($1)
+   Batch Size: 1
+   ->  Values Scan on "*VALUES*"
+         Output: "*VALUES*".column1
+(5 rows)
+
+INSERT INTO ftable VALUES (3), (4);
+NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON ftable
+NOTICE:  NEW: (3)
+NOTICE:  trig_row_before(23, skidoo) BEFORE ROW INSERT ON ftable
+NOTICE:  NEW: (4)
+SELECT COUNT(*) FROM ftable;
+ count 
+-------
+     4
+(1 row)
+
+-- Clean up
+DROP TRIGGER trig_row_before ON ftable;
 DROP FOREIGN TABLE ftable;
 DROP TABLE batch_table;
 -- Use partitioning
index 2193383eecb69515f9c0870ba5f345ae51005ea1..0e24ed2a4879fe2d365d5baae1f03af8856ce845 100644 (file)
@@ -2012,8 +2012,8 @@ postgresExecForeignBatchInsert(EState *estate,
  *             Determine the maximum number of tuples that can be inserted in bulk
  *
  * Returns the batch size specified for server or table. When batching is not
- * allowed (e.g. for tables with AFTER ROW triggers or with RETURNING clause),
- * returns 1.
+ * allowed (e.g. for tables with BEFORE/AFTER ROW triggers or with RETURNING
+ * clause), returns 1.
  */
 static int
 postgresGetForeignModifyBatchSize(ResultRelInfo *resultRelInfo)
@@ -2042,10 +2042,19 @@ postgresGetForeignModifyBatchSize(ResultRelInfo *resultRelInfo)
        else
                batch_size = get_batch_size_option(resultRelInfo->ri_RelationDesc);
 
-       /* Disable batching when we have to use RETURNING. */
+       /*
+        * Disable batching when we have to use RETURNING or there are any
+        * BEFORE/AFTER ROW INSERT triggers on the foreign table.
+        *
+        * When there are any BEFORE ROW INSERT triggers on the table, we can't
+        * support it, because such triggers might query the table we're inserting
+        * into and act differently if the tuples that have already been processed
+        * and prepared for insertion are not there.
+        */
        if (resultRelInfo->ri_projectReturning != NULL ||
                (resultRelInfo->ri_TrigDesc &&
-                resultRelInfo->ri_TrigDesc->trig_insert_after_row))
+                (resultRelInfo->ri_TrigDesc->trig_insert_before_row ||
+                 resultRelInfo->ri_TrigDesc->trig_insert_after_row)))
                return 1;
 
        /*
index 4680e5cba379b7892f13cf2b895e7233782f1fd6..855c7ea70edbbc7c17fc94b5f45121a783ee43fb 100644 (file)
@@ -3083,6 +3083,18 @@ CREATE FOREIGN TABLE ftable ( x int ) SERVER loopback OPTIONS ( table_name 'batc
 EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable VALUES (1), (2);
 INSERT INTO ftable VALUES (1), (2);
 SELECT COUNT(*) FROM ftable;
+
+-- Disable batch inserting into foreign tables with BEFORE ROW INSERT triggers
+-- even if the batch_size option is enabled.
+ALTER FOREIGN TABLE ftable OPTIONS ( SET batch_size '10' );
+CREATE TRIGGER trig_row_before BEFORE INSERT ON ftable
+FOR EACH ROW EXECUTE PROCEDURE trigger_data(23,'skidoo');
+EXPLAIN (VERBOSE, COSTS OFF) INSERT INTO ftable VALUES (3), (4);
+INSERT INTO ftable VALUES (3), (4);
+SELECT COUNT(*) FROM ftable;
+
+-- Clean up
+DROP TRIGGER trig_row_before ON ftable;
 DROP FOREIGN TABLE ftable;
 DROP TABLE batch_table;