]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/nodeModifyTable.c
Phase 2 of pgindent updates.
[postgresql] / src / backend / executor / nodeModifyTable.c
index 95e158970c30958596f23a842b5d156e965a280d..11594b58b57e32d2dfd00a0fb6ed5493d57e8b9d 100644 (file)
@@ -45,6 +45,7 @@
 #include "foreign/fdwapi.h"
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
+#include "parser/parsetree.h"
 #include "storage/bufmgr.h"
 #include "storage/lmgr.h"
 #include "utils/builtins.h"
@@ -262,8 +263,7 @@ ExecInsert(ModifyTableState *mtstate,
        Relation        resultRelationDesc;
        Oid                     newId;
        List       *recheckIndexes = NIL;
-       TupleTableSlot *oldslot = slot,
-                          *result = NULL;
+       TupleTableSlot *result = NULL;
 
        /*
         * get the heap tuple out of the tuple table slot, making sure we have a
@@ -414,6 +414,16 @@ ExecInsert(ModifyTableState *mtstate,
        }
        else
        {
+               /*
+                * We always check the partition constraint, including when the tuple
+                * got here via tuple-routing.  However we don't need to in the latter
+                * case if no BR trigger is defined on the partition.  Note that a BR
+                * trigger might modify the tuple such that the partition constraint
+                * is no longer satisfied, so we need to check in that case.
+                */
+               bool            check_partition_constr =
+               (resultRelInfo->ri_PartitionCheck != NIL);
+
                /*
                 * Constraints might reference the tableoid column, so initialize
                 * t_tableOid before evaluating them.
@@ -431,10 +441,17 @@ ExecInsert(ModifyTableState *mtstate,
                                                                 resultRelInfo, slot, estate);
 
                /*
-                * Check the constraints of the tuple
+                * No need though if the tuple has been routed, and a BR trigger
+                * doesn't exist.
                 */
-               if (resultRelationDesc->rd_att->constr || resultRelInfo->ri_PartitionCheck)
-                       ExecConstraints(resultRelInfo, slot, oldslot, estate);
+               if (saved_resultRelInfo != NULL &&
+                       !(resultRelInfo->ri_TrigDesc &&
+                         resultRelInfo->ri_TrigDesc->trig_insert_before_row))
+                       check_partition_constr = false;
+
+               /* Check the constraints of the tuple */
+               if (resultRelationDesc->rd_att->constr || check_partition_constr)
+                       ExecConstraints(resultRelInfo, slot, estate);
 
                if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0)
                {
@@ -992,7 +1009,7 @@ lreplace:;
                 * tuple-routing is performed here, hence the slot remains unchanged.
                 */
                if (resultRelationDesc->rd_att->constr || resultRelInfo->ri_PartitionCheck)
-                       ExecConstraints(resultRelInfo, slot, slot, estate);
+                       ExecConstraints(resultRelInfo, slot, estate);
 
                /*
                 * replace the heap tuple
@@ -1151,7 +1168,7 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
 {
        ExprContext *econtext = mtstate->ps.ps_ExprContext;
        Relation        relation = resultRelInfo->ri_RelationDesc;
-       List       *onConflictSetWhere = resultRelInfo->ri_onConflictSetWhere;
+       ExprState  *onConflictSetWhere = resultRelInfo->ri_onConflictSetWhere;
        HeapTupleData tuple;
        HeapUpdateFailureData hufd;
        LockTupleMode lockmode;
@@ -1270,7 +1287,7 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
        econtext->ecxt_innertuple = excludedSlot;
        econtext->ecxt_outertuple = NULL;
 
-       if (!ExecQual(onConflictSetWhere, econtext, false))
+       if (!ExecQual(onConflictSetWhere, econtext))
        {
                ReleaseBuffer(buffer);
                InstrCountFiltered1(&mtstate->ps, 1);
@@ -1328,19 +1345,29 @@ ExecOnConflictUpdate(ModifyTableState *mtstate,
 static void
 fireBSTriggers(ModifyTableState *node)
 {
+       ResultRelInfo *resultRelInfo = node->resultRelInfo;
+
+       /*
+        * If the node modifies a partitioned table, we must fire its triggers.
+        * Note that in that case, node->resultRelInfo points to the first leaf
+        * partition, not the root table.
+        */
+       if (node->rootResultRelInfo != NULL)
+               resultRelInfo = node->rootResultRelInfo;
+
        switch (node->operation)
        {
                case CMD_INSERT:
-                       ExecBSInsertTriggers(node->ps.state, node->resultRelInfo);
+                       ExecBSInsertTriggers(node->ps.state, resultRelInfo);
                        if (node->mt_onconflict == ONCONFLICT_UPDATE)
                                ExecBSUpdateTriggers(node->ps.state,
-                                                                        node->resultRelInfo);
+                                                                        resultRelInfo);
                        break;
                case CMD_UPDATE:
-                       ExecBSUpdateTriggers(node->ps.state, node->resultRelInfo);
+                       ExecBSUpdateTriggers(node->ps.state, resultRelInfo);
                        break;
                case CMD_DELETE:
-                       ExecBSDeleteTriggers(node->ps.state, node->resultRelInfo);
+                       ExecBSDeleteTriggers(node->ps.state, resultRelInfo);
                        break;
                default:
                        elog(ERROR, "unknown operation");
@@ -1354,19 +1381,29 @@ fireBSTriggers(ModifyTableState *node)
 static void
 fireASTriggers(ModifyTableState *node)
 {
+       ResultRelInfo *resultRelInfo = node->resultRelInfo;
+
+       /*
+        * If the node modifies a partitioned table, we must fire its triggers.
+        * Note that in that case, node->resultRelInfo points to the first leaf
+        * partition, not the root table.
+        */
+       if (node->rootResultRelInfo != NULL)
+               resultRelInfo = node->rootResultRelInfo;
+
        switch (node->operation)
        {
                case CMD_INSERT:
                        if (node->mt_onconflict == ONCONFLICT_UPDATE)
                                ExecASUpdateTriggers(node->ps.state,
-                                                                        node->resultRelInfo);
-                       ExecASInsertTriggers(node->ps.state, node->resultRelInfo);
+                                                                        resultRelInfo);
+                       ExecASInsertTriggers(node->ps.state, resultRelInfo);
                        break;
                case CMD_UPDATE:
-                       ExecASUpdateTriggers(node->ps.state, node->resultRelInfo);
+                       ExecASUpdateTriggers(node->ps.state, resultRelInfo);
                        break;
                case CMD_DELETE:
-                       ExecASDeleteTriggers(node->ps.state, node->resultRelInfo);
+                       ExecASDeleteTriggers(node->ps.state, resultRelInfo);
                        break;
                default:
                        elog(ERROR, "unknown operation");
@@ -1524,8 +1561,7 @@ ExecModifyTable(ModifyTableState *node)
                                                elog(ERROR, "ctid is NULL");
 
                                        tupleid = (ItemPointer) DatumGetPointer(datum);
-                                       tuple_ctid = *tupleid;          /* be sure we don't free
-                                                                                                * ctid!! */
+                                       tuple_ctid = *tupleid;  /* be sure we don't free ctid!! */
                                        tupleid = &tuple_ctid;
                                }
 
@@ -1645,7 +1681,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
        mtstate = makeNode(ModifyTableState);
        mtstate->ps.plan = (Plan *) node;
        mtstate->ps.state = estate;
-       mtstate->ps.targetlist = NIL;           /* not actually used */
 
        mtstate->operation = operation;
        mtstate->canSetTag = node->canSetTag;
@@ -1653,6 +1688,12 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 
        mtstate->mt_plans = (PlanState **) palloc0(sizeof(PlanState *) * nplans);
        mtstate->resultRelInfo = estate->es_result_relations + node->resultRelIndex;
+
+       /* If modifying a partitioned table, initialize the root table info */
+       if (node->rootResultRelIndex >= 0)
+               mtstate->rootResultRelInfo = estate->es_root_result_relations +
+                       node->rootResultRelIndex;
+
        mtstate->mt_arowmarks = (List **) palloc0(sizeof(List *) * nplans);
        mtstate->mt_nplans = nplans;
        mtstate->mt_onconflict = node->onConflictAction;
@@ -1725,8 +1766,20 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
 
        estate->es_result_relation_info = saved_resultRelInfo;
 
+       /* The root table RT index is at the head of the partitioned_rels list */
+       if (node->partitioned_rels)
+       {
+               Index           root_rti;
+               Oid                     root_oid;
+
+               root_rti = linitial_int(node->partitioned_rels);
+               root_oid = getrelid(root_rti, estate->es_range_table);
+               rel = heap_open(root_oid, NoLock);      /* locked by InitPlan */
+       }
+       else
+               rel = mtstate->resultRelInfo->ri_RelationDesc;
+
        /* Build state for INSERT tuple routing */
-       rel = mtstate->resultRelInfo->ri_RelationDesc;
        if (operation == CMD_INSERT &&
                rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
        {
@@ -1765,7 +1818,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                foreach(ll, wcoList)
                {
                        WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
-                       ExprState  *wcoExpr = ExecInitExpr((Expr *) wco->qual,
+                       ExprState  *wcoExpr = ExecInitQual((List *) wco->qual,
                                                                                           mtstate->mt_plans[i]);
 
                        wcoExprs = lappend(wcoExprs, wcoExpr);
@@ -1778,19 +1831,30 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
        }
 
        /*
-        * Build WITH CHECK OPTION constraints for each leaf partition rel.
-        * Note that we didn't build the withCheckOptionList for each partition
-        * within the planner, but simple translation of the varattnos for each
-        * partition will suffice.  This only occurs for the INSERT case;
-        * UPDATE/DELETE cases are handled above.
+        * Build WITH CHECK OPTION constraints for each leaf partition rel. Note
+        * that we didn't build the withCheckOptionList for each partition within
+        * the planner, but simple translation of the varattnos for each partition
+        * will suffice.  This only occurs for the INSERT case; UPDATE/DELETE
+        * cases are handled above.
         */
        if (node->withCheckOptionLists != NIL && mtstate->mt_num_partitions > 0)
        {
-               List            *wcoList;
+               List       *wcoList;
+               PlanState  *plan;
 
-               Assert(operation == CMD_INSERT);
-               resultRelInfo = mtstate->mt_partitions;
+               /*
+                * In case of INSERT on partitioned tables, there is only one plan.
+                * Likewise, there is only one WITH CHECK OPTIONS list, not one per
+                * partition.  We make a copy of the WCO qual for each partition; note
+                * that, if there are SubPlans in there, they all end up attached to
+                * the one parent Plan node.
+                */
+               Assert(operation == CMD_INSERT &&
+                          list_length(node->withCheckOptionLists) == 1 &&
+                          mtstate->mt_nplans == 1);
                wcoList = linitial(node->withCheckOptionLists);
+               plan = mtstate->mt_plans[0];
+               resultRelInfo = mtstate->mt_partitions;
                for (i = 0; i < mtstate->mt_num_partitions; i++)
                {
                        Relation        partrel = resultRelInfo->ri_RelationDesc;
@@ -1804,9 +1868,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                                                                                                         partrel, rel);
                        foreach(ll, mapped_wcoList)
                        {
-                               WithCheckOption *wco = (WithCheckOption *) lfirst(ll);
-                               ExprState  *wcoExpr = ExecInitExpr((Expr *) wco->qual,
-                                                                                          mtstate->mt_plans[i]);
+                               WithCheckOption *wco = castNode(WithCheckOption, lfirst(ll));
+                               ExprState  *wcoExpr = ExecInitQual(castNode(List, wco->qual),
+                                                                                                  plan);
 
                                wcoExprs = lappend(wcoExprs, wcoExpr);
                        }
@@ -1839,8 +1903,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                slot = mtstate->ps.ps_ResultTupleSlot;
 
                /* Need an econtext too */
-               econtext = CreateExprContext(estate);
-               mtstate->ps.ps_ExprContext = econtext;
+               if (mtstate->ps.ps_ExprContext == NULL)
+                       ExecAssignExprContext(estate, &mtstate->ps);
+               econtext = mtstate->ps.ps_ExprContext;
 
                /*
                 * Build a projection for each result rel.
@@ -1849,11 +1914,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                foreach(l, node->returningLists)
                {
                        List       *rlist = (List *) lfirst(l);
-                       List       *rliststate;
 
-                       rliststate = (List *) ExecInitExpr((Expr *) rlist, &mtstate->ps);
                        resultRelInfo->ri_projectReturning =
-                               ExecBuildProjectionInfo(rliststate, econtext, slot,
+                               ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
                                                                         resultRelInfo->ri_RelationDesc->rd_att);
                        resultRelInfo++;
                }
@@ -1870,16 +1933,14 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                for (i = 0; i < mtstate->mt_num_partitions; i++)
                {
                        Relation        partrel = resultRelInfo->ri_RelationDesc;
-                       List       *rlist,
-                                          *rliststate;
+                       List       *rlist;
 
                        /* varno = node->nominalRelation */
                        rlist = map_partition_varattnos(returningList,
                                                                                        node->nominalRelation,
                                                                                        partrel, rel);
-                       rliststate = (List *) ExecInitExpr((Expr *) rlist, &mtstate->ps);
                        resultRelInfo->ri_projectReturning =
-                               ExecBuildProjectionInfo(rliststate, econtext, slot,
+                               ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
                                                                         resultRelInfo->ri_RelationDesc->rd_att);
                        resultRelInfo++;
                }
@@ -1897,6 +1958,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                mtstate->ps.ps_ExprContext = NULL;
        }
 
+       /* Close the root partitioned rel if we opened it above. */
+       if (rel != mtstate->resultRelInfo->ri_RelationDesc)
+               heap_close(rel, NoLock);
+
        /*
         * If needed, Initialize target list, projection and qual for ON CONFLICT
         * DO UPDATE.
@@ -1905,7 +1970,6 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
        if (node->onConflictAction == ONCONFLICT_UPDATE)
        {
                ExprContext *econtext;
-               ExprState  *setexpr;
                TupleDesc       tupDesc;
 
                /* insert may only have one plan, inheritance is not expanded */
@@ -1931,11 +1995,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                mtstate->mt_conflproj = ExecInitExtraTupleSlot(mtstate->ps.state);
                ExecSetSlotDescriptor(mtstate->mt_conflproj, tupDesc);
 
-               /* build UPDATE SET expression and projection state */
-               setexpr = ExecInitExpr((Expr *) node->onConflictSet, &mtstate->ps);
+               /* build UPDATE SET projection state */
                resultRelInfo->ri_onConflictSetProj =
-                       ExecBuildProjectionInfo((List *) setexpr, econtext,
-                                                                       mtstate->mt_conflproj,
+                       ExecBuildProjectionInfo(node->onConflictSet, econtext,
+                                                                       mtstate->mt_conflproj, &mtstate->ps,
                                                                        resultRelInfo->ri_RelationDesc->rd_att);
 
                /* build DO UPDATE WHERE clause expression */
@@ -1943,10 +2006,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
                {
                        ExprState  *qualexpr;
 
-                       qualexpr = ExecInitExpr((Expr *) node->onConflictWhere,
+                       qualexpr = ExecInitQual((List *) node->onConflictWhere,
                                                                        &mtstate->ps);
 
-                       resultRelInfo->ri_onConflictSetWhere = (List *) qualexpr;
+                       resultRelInfo->ri_onConflictSetWhere = qualexpr;
                }
        }
 
@@ -1958,7 +2021,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
         */
        foreach(l, node->rowMarks)
        {
-               PlanRowMark *rc = castNode(PlanRowMark, lfirst(l));
+               PlanRowMark *rc = lfirst_node(PlanRowMark, l);
                ExecRowMark *erm;
 
                /* ignore "parent" rowmarks; they are irrelevant at runtime */