0001-delta.patch
application/octet-stream
Filename: 0001-delta.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
Series: patch 0001
| File | + | − |
|---|---|---|
| src/backend/commands/copy.c | 21 | 49 |
| src/backend/executor/execMain.c | 49 | 0 |
| src/backend/executor/execPartition.c | 1 | 41 |
| src/include/executor/executor.h | 2 | 0 |
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 2119db4..41a7067 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2826,52 +2826,24 @@ CopyFrom(CopyState cstate)
/*
* It's generally more efficient to prepare a bunch of tuples for
* insertion, and insert them in bulk, for example, with one
- * table_multi_insert() call than call table_tuple_insert() separately
- * for every tuple. However, there are a number of reasons why we might
- * not be able to do this. We check some conditions below while some
- * other target relation properties are checked in InitResultRelInfo().
- * Partition initialization will use result of this check implicitly as
- * the ri_usesMultiInsert value of the parent relation.
+ * table_multi_insert() call than call table_tuple_insert() separately for
+ * every tuple. However, there are a number of reasons why we might not be
+ * able to do this. For example, if there any volatile expressions in the
+ * table's default values or in the statement's WHERE clause, which may
+ * query the table we are inserting into, buffering tuples might produce
+ * wrong results. Also, the relation we are trying to insert into itself
+ * may not be amenable to buffered inserts.
+ *
+ * Note: For partitions, this flag is set considering the target table's
+ * flag that is being set here and partition's own properties which are
+ * checked by calling ExecRelationAllowsMultiInsert(). It does not matter
+ * whether partitions have any volatile default expressions as we use the
+ * defaults from the target of the COPY command.
*/
- if (!checkMultiInsertMode(target_resultRelInfo, NULL))
- {
- /*
- * Do nothing. Can't allow multi-insert mode if previous conditions
- * checking disallow this.
- */
- }
- else if (cstate->volatile_defexprs || list_length(cstate->attnumlist) == 0)
- {
- /*
- * Can't support bufferization of copy into foreign tables without any
- * defined columns or if there are any volatile default expressions in the
- * table. Similarly to the trigger case above, such expressions may query
- * the table we're inserting into.
- *
- * Note: It does not matter if any partitions have any volatile
- * default expressions as we use the defaults from the target of the
- * COPY command.
- */
- }
- else if (contain_volatile_functions(cstate->whereClause))
- {
- /*
- * Can't support multi-inserts if there are any volatile function
- * expressions in WHERE clause. Similarly to the trigger case above,
- * such expressions may query the table we're inserting into.
- */
- }
- else
- {
- /*
- * Looks okay to try multi-insert.
- *
- * For partitioned tables, whether or not to use multi-insert depends
- * on the individual parition's properties which are also checked in
- * InitResultRelInfo().
- */
+ if (!cstate->volatile_defexprs &&
+ !contain_volatile_functions(cstate->whereClause) &&
+ ExecRelationAllowsMultiInsert(target_resultRelInfo, NULL))
target_resultRelInfo->ri_usesMultiInsert = true;
- }
/* Verify the named relation is a valid target for INSERT */
CheckValidResultRel(resultRelInfo, CMD_INSERT);
@@ -2898,10 +2870,10 @@ CopyFrom(CopyState cstate)
* Init COPY into foreign table. Initialization of copying into foreign
* partitions will be done later.
*/
- if (target_resultRelInfo->ri_FdwRoutine != NULL &&
- target_resultRelInfo->ri_FdwRoutine->BeginForeignInsert != NULL)
- target_resultRelInfo->ri_FdwRoutine->BeginForeignInsert(mtstate,
- resultRelInfo);
+ if (resultRelInfo->ri_FdwRoutine != NULL &&
+ resultRelInfo->ri_FdwRoutine->BeginForeignInsert != NULL)
+ resultRelInfo->ri_FdwRoutine->BeginForeignInsert(mtstate,
+ resultRelInfo);
/* Prepare to catch AFTER triggers. */
AfterTriggerBeginQuery();
@@ -3302,7 +3274,7 @@ CopyFrom(CopyState cstate)
if (target_resultRelInfo->ri_FdwRoutine != NULL &&
target_resultRelInfo->ri_FdwRoutine->EndForeignInsert != NULL)
target_resultRelInfo->ri_FdwRoutine->EndForeignInsert(estate,
- target_resultRelInfo);
+ target_resultRelInfo);
/* Tear down the multi-insert buffer data */
CopyMultiInsertInfoCleanup(&multiInsertInfo);
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 12ee7f2..4999474 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1351,6 +1351,55 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
}
/*
+ * ExecRelationAllowsMultiInsert
+ * Does this relation allow caller to use multi-insert mode when
+ * inserting rows into it?
+ */
+bool
+ExecRelationAllowsMultiInsert(const ResultRelInfo *rri,
+ const ResultRelInfo *partition_root)
+{
+ Assert(rri->ri_usesMultiInsert == false);
+
+ /*
+ * If a partition's root parent isn't allowed to use it, neither is the
+ * partition.
+ */
+ if (partition_root && !partition_root->ri_usesMultiInsert)
+ return false;
+
+ /*
+ * Can't support multi-inserts when there are any BEFORE/INSTEAD OF
+ * triggers on the table. 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 (rri->ri_TrigDesc != NULL &&
+ (rri->ri_TrigDesc->trig_insert_before_row ||
+ rri->ri_TrigDesc->trig_insert_instead_row))
+ return false;
+
+ /*
+ * For partitioned tables we can't support multi-inserts when there are
+ * any statement level insert triggers. It might be possible to allow
+ * partitioned tables with such triggers in the future, but for now,
+ * CopyMultiInsertInfoFlush expects that any before row insert and
+ * statement level insert triggers are on the same relation.
+ */
+ if (rri->ri_RelationDesc->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+ rri->ri_TrigDesc != NULL &&
+ rri->ri_TrigDesc->trig_insert_new_table)
+ return false;
+
+ /* Foreign tables don't support multi-inserts. */
+ if (rri->ri_FdwRoutine != NULL)
+ return false;
+
+ /* OK, caller can use multi-insert on this relation. */
+ return true;
+}
+
+/*
* ExecGetTriggerResultRel
* Get a ResultRelInfo for a trigger target relation.
*
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index baaa0f6..d752fe3 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -548,46 +548,6 @@ ExecHashSubPlanResultRelsByOid(ModifyTableState *mtstate,
}
}
-bool
-checkMultiInsertMode(const ResultRelInfo *rri, const ResultRelInfo *parent)
-{
- Assert(rri->ri_usesMultiInsert == false);
-
- if (parent && !parent->ri_usesMultiInsert)
- return false;
-
- /* Check if the relation allows to use "multi-insert" mode. */
- if (rri->ri_TrigDesc != NULL &&
- (rri->ri_TrigDesc->trig_insert_before_row ||
- rri->ri_TrigDesc->trig_insert_instead_row))
- /*
- * Can't support multi-inserts when there are any BEFORE/INSTEAD OF
- * triggers on the table. 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.
- */
- return false;
-
- if (rri->ri_RelationDesc->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
- rri->ri_TrigDesc != NULL &&
- rri->ri_TrigDesc->trig_insert_new_table)
- /*
- * For partitioned tables we can't support multi-inserts when there
- * are any statement level insert triggers. It might be possible to
- * allow partitioned tables with such triggers in the future, but for
- * now, CopyMultiInsertInfoFlush expects that any before row insert
- * and statement level insert triggers are on the same relation.
- */
- return false;
-
- if (rri->ri_FdwRoutine != NULL)
- /* Foreign tables don't support multi-inserts. */
- return false;
-
- /* OK, caller can use multi-insert on this relation. */
- return true;
-}
-
/*
* ExecInitPartitionInfo
* Lock the partition and initialize ResultRelInfo. Also setup other
@@ -628,7 +588,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
* parent and its child.
*/
leaf_part_rri->ri_usesMultiInsert =
- checkMultiInsertMode(leaf_part_rri, rootResultRelInfo);
+ ExecRelationAllowsMultiInsert(leaf_part_rri, rootResultRelInfo);
/*
* Verify result relation is a valid target for an INSERT. An UPDATE of a
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 415e117..1146685 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -190,6 +190,8 @@ extern void InitResultRelInfo(ResultRelInfo *resultRelInfo,
Index resultRelationIndex,
Relation partition_root,
int instrument_options);
+extern bool ExecRelationAllowsMultiInsert(const ResultRelInfo *rri,
+ const ResultRelInfo *partition_root);
extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid);
extern void ExecCleanUpTriggerState(EState *estate);
extern void ExecConstraints(ResultRelInfo *resultRelInfo,