PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
execMain.c File Reference
#include "postgres.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "access/tableam.h"
#include "access/xact.h"
#include "catalog/namespace.h"
#include "catalog/partition.h"
#include "commands/matview.h"
#include "commands/trigger.h"
#include "executor/executor.h"
#include "executor/execPartition.h"
#include "executor/nodeSubplan.h"
#include "foreign/fdwapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/queryjumble.h"
#include "parser/parse_relation.h"
#include "pgstat.h"
#include "rewrite/rewriteHandler.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/backend_status.h"
#include "utils/lsyscache.h"
#include "utils/partcache.h"
#include "utils/rls.h"
#include "utils/snapmgr.h"
Include dependency graph for execMain.c:

Go to the source code of this file.

Functions

static void InitPlan (QueryDesc *queryDesc, int eflags)
 
static void CheckValidRowMarkRel (Relation rel, RowMarkType markType)
 
static void ExecPostprocessPlan (EState *estate)
 
static void ExecEndPlan (PlanState *planstate, EState *estate)
 
static void ExecutePlan (QueryDesc *queryDesc, CmdType operation, bool sendTuples, uint64 numberTuples, ScanDirection direction, DestReceiver *dest)
 
static bool ExecCheckPermissionsModified (Oid relOid, Oid userid, Bitmapset *modifiedCols, AclMode requiredPerms)
 
static void ExecCheckXactReadOnly (PlannedStmt *plannedstmt)
 
static void EvalPlanQualStart (EPQState *epqstate, Plan *planTree)
 
static void ReportNotNullViolationError (ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, int attnum)
 
void ExecutorStart (QueryDesc *queryDesc, int eflags)
 
void standard_ExecutorStart (QueryDesc *queryDesc, int eflags)
 
void ExecutorRun (QueryDesc *queryDesc, ScanDirection direction, uint64 count)
 
void standard_ExecutorRun (QueryDesc *queryDesc, ScanDirection direction, uint64 count)
 
void ExecutorFinish (QueryDesc *queryDesc)
 
void standard_ExecutorFinish (QueryDesc *queryDesc)
 
void ExecutorEnd (QueryDesc *queryDesc)
 
void standard_ExecutorEnd (QueryDesc *queryDesc)
 
void ExecutorRewind (QueryDesc *queryDesc)
 
bool ExecCheckPermissions (List *rangeTable, List *rteperminfos, bool ereport_on_violation)
 
bool ExecCheckOneRelPerms (RTEPermissionInfo *perminfo)
 
void CheckValidResultRel (ResultRelInfo *resultRelInfo, CmdType operation, OnConflictAction onConflictAction, List *mergeActions)
 
void InitResultRelInfo (ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
 
ResultRelInfoExecGetTriggerResultRel (EState *estate, Oid relid, ResultRelInfo *rootRelInfo)
 
ListExecGetAncestorResultRels (EState *estate, ResultRelInfo *resultRelInfo)
 
void ExecCloseResultRelations (EState *estate)
 
void ExecCloseRangeTableRelations (EState *estate)
 
static const char * ExecRelCheck (ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
 
bool ExecPartitionCheck (ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, bool emitError)
 
void ExecPartitionCheckEmitError (ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
 
void ExecConstraints (ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
 
AttrNumber ExecRelGenVirtualNotNull (ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, List *notnull_virtual_attrs)
 
void ExecWithCheckOptions (WCOKind kind, ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
 
char * ExecBuildSlotValueDescription (Oid reloid, TupleTableSlot *slot, TupleDesc tupdesc, Bitmapset *modifiedCols, int maxfieldlen)
 
LockTupleMode ExecUpdateLockMode (EState *estate, ResultRelInfo *relinfo)
 
ExecRowMarkExecFindRowMark (EState *estate, Index rti, bool missing_ok)
 
ExecAuxRowMarkExecBuildAuxRowMark (ExecRowMark *erm, List *targetlist)
 
TupleTableSlotEvalPlanQual (EPQState *epqstate, Relation relation, Index rti, TupleTableSlot *inputslot)
 
void EvalPlanQualInit (EPQState *epqstate, EState *parentestate, Plan *subplan, List *auxrowmarks, int epqParam, List *resultRelations)
 
void EvalPlanQualSetPlan (EPQState *epqstate, Plan *subplan, List *auxrowmarks)
 
TupleTableSlotEvalPlanQualSlot (EPQState *epqstate, Relation relation, Index rti)
 
bool EvalPlanQualFetchRowMark (EPQState *epqstate, Index rti, TupleTableSlot *slot)
 
TupleTableSlotEvalPlanQualNext (EPQState *epqstate)
 
void EvalPlanQualBegin (EPQState *epqstate)
 
void EvalPlanQualEnd (EPQState *epqstate)
 

Variables

ExecutorStart_hook_type ExecutorStart_hook = NULL
 
ExecutorRun_hook_type ExecutorRun_hook = NULL
 
ExecutorFinish_hook_type ExecutorFinish_hook = NULL
 
ExecutorEnd_hook_type ExecutorEnd_hook = NULL
 
ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook = NULL
 

Function Documentation

◆ CheckValidResultRel()

void CheckValidResultRel ( ResultRelInfo resultRelInfo,
CmdType  operation,
OnConflictAction  onConflictAction,
List mergeActions 
)

Definition at line 1050 of file execMain.c.

1052{
1053 Relation resultRel = resultRelInfo->ri_RelationDesc;
1054 FdwRoutine *fdwroutine;
1055
1056 /* Expect a fully-formed ResultRelInfo from InitResultRelInfo(). */
1057 Assert(resultRelInfo->ri_needLockTagTuple ==
1058 IsInplaceUpdateRelation(resultRel));
1059
1060 switch (resultRel->rd_rel->relkind)
1061 {
1062 case RELKIND_RELATION:
1063 case RELKIND_PARTITIONED_TABLE:
1064
1065 /*
1066 * For MERGE, check that the target relation supports each action.
1067 * For other operations, just check the operation itself.
1068 */
1069 if (operation == CMD_MERGE)
1070 foreach_node(MergeAction, action, mergeActions)
1071 CheckCmdReplicaIdentity(resultRel, action->commandType);
1072 else
1073 CheckCmdReplicaIdentity(resultRel, operation);
1074
1075 /*
1076 * For INSERT ON CONFLICT DO UPDATE, additionally check that the
1077 * target relation supports UPDATE.
1078 */
1079 if (onConflictAction == ONCONFLICT_UPDATE)
1081 break;
1082 case RELKIND_SEQUENCE:
1083 ereport(ERROR,
1084 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1085 errmsg("cannot change sequence \"%s\"",
1086 RelationGetRelationName(resultRel))));
1087 break;
1088 case RELKIND_TOASTVALUE:
1089 ereport(ERROR,
1090 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1091 errmsg("cannot change TOAST relation \"%s\"",
1092 RelationGetRelationName(resultRel))));
1093 break;
1094 case RELKIND_VIEW:
1095
1096 /*
1097 * Okay only if there's a suitable INSTEAD OF trigger. Otherwise,
1098 * complain, but omit errdetail because we haven't got the
1099 * information handy (and given that it really shouldn't happen,
1100 * it's not worth great exertion to get).
1101 */
1102 if (!view_has_instead_trigger(resultRel, operation, mergeActions))
1103 error_view_not_updatable(resultRel, operation, mergeActions,
1104 NULL);
1105 break;
1106 case RELKIND_MATVIEW:
1108 ereport(ERROR,
1109 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1110 errmsg("cannot change materialized view \"%s\"",
1111 RelationGetRelationName(resultRel))));
1112 break;
1113 case RELKIND_FOREIGN_TABLE:
1114 /* Okay only if the FDW supports it */
1115 fdwroutine = resultRelInfo->ri_FdwRoutine;
1116 switch (operation)
1117 {
1118 case CMD_INSERT:
1119 if (fdwroutine->ExecForeignInsert == NULL)
1120 ereport(ERROR,
1121 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1122 errmsg("cannot insert into foreign table \"%s\"",
1123 RelationGetRelationName(resultRel))));
1124 if (fdwroutine->IsForeignRelUpdatable != NULL &&
1125 (fdwroutine->IsForeignRelUpdatable(resultRel) & (1 << CMD_INSERT)) == 0)
1126 ereport(ERROR,
1127 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1128 errmsg("foreign table \"%s\" does not allow inserts",
1129 RelationGetRelationName(resultRel))));
1130 break;
1131 case CMD_UPDATE:
1132 if (fdwroutine->ExecForeignUpdate == NULL)
1133 ereport(ERROR,
1134 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1135 errmsg("cannot update foreign table \"%s\"",
1136 RelationGetRelationName(resultRel))));
1137 if (fdwroutine->IsForeignRelUpdatable != NULL &&
1138 (fdwroutine->IsForeignRelUpdatable(resultRel) & (1 << CMD_UPDATE)) == 0)
1139 ereport(ERROR,
1140 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1141 errmsg("foreign table \"%s\" does not allow updates",
1142 RelationGetRelationName(resultRel))));
1143 break;
1144 case CMD_DELETE:
1145 if (fdwroutine->ExecForeignDelete == NULL)
1146 ereport(ERROR,
1147 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1148 errmsg("cannot delete from foreign table \"%s\"",
1149 RelationGetRelationName(resultRel))));
1150 if (fdwroutine->IsForeignRelUpdatable != NULL &&
1151 (fdwroutine->IsForeignRelUpdatable(resultRel) & (1 << CMD_DELETE)) == 0)
1152 ereport(ERROR,
1153 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1154 errmsg("foreign table \"%s\" does not allow deletes",
1155 RelationGetRelationName(resultRel))));
1156 break;
1157 default:
1158 elog(ERROR, "unrecognized CmdType: %d", (int) operation);
1159 break;
1160 }
1161 break;
1162 default:
1163 ereport(ERROR,
1164 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1165 errmsg("cannot change relation \"%s\"",
1166 RelationGetRelationName(resultRel))));
1167 break;
1168 }
1169}
bool IsInplaceUpdateRelation(Relation relation)
Definition: catalog.c:183
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
void CheckCmdReplicaIdentity(Relation rel, CmdType cmd)
Assert(PointerIsAligned(start, uint64))
bool MatViewIncrementalMaintenanceIsEnabled(void)
Definition: matview.c:952
@ ONCONFLICT_UPDATE
Definition: nodes.h:430
@ CMD_MERGE
Definition: nodes.h:279
@ CMD_INSERT
Definition: nodes.h:277
@ CMD_DELETE
Definition: nodes.h:278
@ CMD_UPDATE
Definition: nodes.h:276
#define foreach_node(type, var, lst)
Definition: pg_list.h:496
#define RelationGetRelationName(relation)
Definition: rel.h:549
bool view_has_instead_trigger(Relation view, CmdType event, List *mergeActionList)
void error_view_not_updatable(Relation view, CmdType command, List *mergeActionList, const char *detail)
ExecForeignInsert_function ExecForeignInsert
Definition: fdwapi.h:232
ExecForeignUpdate_function ExecForeignUpdate
Definition: fdwapi.h:235
ExecForeignDelete_function ExecForeignDelete
Definition: fdwapi.h:236
IsForeignRelUpdatable_function IsForeignRelUpdatable
Definition: fdwapi.h:240
Form_pg_class rd_rel
Definition: rel.h:111
bool ri_needLockTagTuple
Definition: execnodes.h:512
Relation ri_RelationDesc
Definition: execnodes.h:480
struct FdwRoutine * ri_FdwRoutine
Definition: execnodes.h:533

References generate_unaccent_rules::action, Assert(), CheckCmdReplicaIdentity(), CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_UPDATE, elog, ereport, errcode(), errmsg(), ERROR, error_view_not_updatable(), FdwRoutine::ExecForeignDelete, FdwRoutine::ExecForeignInsert, FdwRoutine::ExecForeignUpdate, foreach_node, FdwRoutine::IsForeignRelUpdatable, IsInplaceUpdateRelation(), MatViewIncrementalMaintenanceIsEnabled(), ONCONFLICT_UPDATE, RelationData::rd_rel, RelationGetRelationName, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_needLockTagTuple, ResultRelInfo::ri_RelationDesc, and view_has_instead_trigger().

Referenced by CopyFrom(), ExecFindPartition(), ExecInitModifyTable(), and ExecInitPartitionInfo().

◆ CheckValidRowMarkRel()

static void CheckValidRowMarkRel ( Relation  rel,
RowMarkType  markType 
)
static

Definition at line 1178 of file execMain.c.

1179{
1180 FdwRoutine *fdwroutine;
1181
1182 switch (rel->rd_rel->relkind)
1183 {
1184 case RELKIND_RELATION:
1185 case RELKIND_PARTITIONED_TABLE:
1186 /* OK */
1187 break;
1188 case RELKIND_SEQUENCE:
1189 /* Must disallow this because we don't vacuum sequences */
1190 ereport(ERROR,
1191 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1192 errmsg("cannot lock rows in sequence \"%s\"",
1194 break;
1195 case RELKIND_TOASTVALUE:
1196 /* We could allow this, but there seems no good reason to */
1197 ereport(ERROR,
1198 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1199 errmsg("cannot lock rows in TOAST relation \"%s\"",
1201 break;
1202 case RELKIND_VIEW:
1203 /* Should not get here; planner should have expanded the view */
1204 ereport(ERROR,
1205 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1206 errmsg("cannot lock rows in view \"%s\"",
1208 break;
1209 case RELKIND_MATVIEW:
1210 /* Allow referencing a matview, but not actual locking clauses */
1211 if (markType != ROW_MARK_REFERENCE)
1212 ereport(ERROR,
1213 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1214 errmsg("cannot lock rows in materialized view \"%s\"",
1216 break;
1217 case RELKIND_FOREIGN_TABLE:
1218 /* Okay only if the FDW supports it */
1219 fdwroutine = GetFdwRoutineForRelation(rel, false);
1220 if (fdwroutine->RefetchForeignRow == NULL)
1221 ereport(ERROR,
1222 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1223 errmsg("cannot lock rows in foreign table \"%s\"",
1225 break;
1226 default:
1227 ereport(ERROR,
1228 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1229 errmsg("cannot lock rows in relation \"%s\"",
1231 break;
1232 }
1233}
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:443
@ ROW_MARK_REFERENCE
Definition: plannodes.h:1540
RefetchForeignRow_function RefetchForeignRow
Definition: fdwapi.h:248

References ereport, errcode(), errmsg(), ERROR, GetFdwRoutineForRelation(), RelationData::rd_rel, FdwRoutine::RefetchForeignRow, RelationGetRelationName, and ROW_MARK_REFERENCE.

Referenced by InitPlan().

◆ EvalPlanQual()

TupleTableSlot * EvalPlanQual ( EPQState epqstate,
Relation  relation,
Index  rti,
TupleTableSlot inputslot 
)

Definition at line 2649 of file execMain.c.

2651{
2652 TupleTableSlot *slot;
2653 TupleTableSlot *testslot;
2654
2655 Assert(rti > 0);
2656
2657 /*
2658 * Need to run a recheck subquery. Initialize or reinitialize EPQ state.
2659 */
2660 EvalPlanQualBegin(epqstate);
2661
2662 /*
2663 * Callers will often use the EvalPlanQualSlot to store the tuple to avoid
2664 * an unnecessary copy.
2665 */
2666 testslot = EvalPlanQualSlot(epqstate, relation, rti);
2667 if (testslot != inputslot)
2668 ExecCopySlot(testslot, inputslot);
2669
2670 /*
2671 * Mark that an EPQ tuple is available for this relation. (If there is
2672 * more than one result relation, the others remain marked as having no
2673 * tuple available.)
2674 */
2675 epqstate->relsubs_done[rti - 1] = false;
2676 epqstate->relsubs_blocked[rti - 1] = false;
2677
2678 /*
2679 * Run the EPQ query. We assume it will return at most one tuple.
2680 */
2681 slot = EvalPlanQualNext(epqstate);
2682
2683 /*
2684 * If we got a tuple, force the slot to materialize the tuple so that it
2685 * is not dependent on any local state in the EPQ query (in particular,
2686 * it's highly likely that the slot contains references to any pass-by-ref
2687 * datums that may be present in copyTuple). As with the next step, this
2688 * is to guard against early re-use of the EPQ query.
2689 */
2690 if (!TupIsNull(slot))
2691 ExecMaterializeSlot(slot);
2692
2693 /*
2694 * Clear out the test tuple, and mark that no tuple is available here.
2695 * This is needed in case the EPQ state is re-used to test a tuple for a
2696 * different target relation.
2697 */
2698 ExecClearTuple(testslot);
2699 epqstate->relsubs_blocked[rti - 1] = true;
2700
2701 return slot;
2702}
TupleTableSlot * EvalPlanQualSlot(EPQState *epqstate, Relation relation, Index rti)
Definition: execMain.c:2777
void EvalPlanQualBegin(EPQState *epqstate)
Definition: execMain.c:2932
TupleTableSlot * EvalPlanQualNext(EPQState *epqstate)
Definition: execMain.c:2916
bool * relsubs_blocked
Definition: execnodes.h:1356
bool * relsubs_done
Definition: execnodes.h:1347
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:457
#define TupIsNull(slot)
Definition: tuptable.h:309
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition: tuptable.h:524
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition: tuptable.h:475

References Assert(), EvalPlanQualBegin(), EvalPlanQualNext(), EvalPlanQualSlot(), ExecClearTuple(), ExecCopySlot(), ExecMaterializeSlot(), EPQState::relsubs_blocked, EPQState::relsubs_done, and TupIsNull.

Referenced by ExecDelete(), ExecMergeMatched(), ExecUpdate(), and GetTupleForTrigger().

◆ EvalPlanQualBegin()

void EvalPlanQualBegin ( EPQState epqstate)

Definition at line 2932 of file execMain.c.

2933{
2934 EState *parentestate = epqstate->parentestate;
2935 EState *recheckestate = epqstate->recheckestate;
2936
2937 if (recheckestate == NULL)
2938 {
2939 /* First time through, so create a child EState */
2940 EvalPlanQualStart(epqstate, epqstate->plan);
2941 }
2942 else
2943 {
2944 /*
2945 * We already have a suitable child EPQ tree, so just reset it.
2946 */
2947 Index rtsize = parentestate->es_range_table_size;
2948 PlanState *rcplanstate = epqstate->recheckplanstate;
2949
2950 /*
2951 * Reset the relsubs_done[] flags to equal relsubs_blocked[], so that
2952 * the EPQ run will never attempt to fetch tuples from blocked target
2953 * relations.
2954 */
2955 memcpy(epqstate->relsubs_done, epqstate->relsubs_blocked,
2956 rtsize * sizeof(bool));
2957
2958 /* Recopy current values of parent parameters */
2959 if (parentestate->es_plannedstmt->paramExecTypes != NIL)
2960 {
2961 int i;
2962
2963 /*
2964 * Force evaluation of any InitPlan outputs that could be needed
2965 * by the subplan, just in case they got reset since
2966 * EvalPlanQualStart (see comments therein).
2967 */
2968 ExecSetParamPlanMulti(rcplanstate->plan->extParam,
2969 GetPerTupleExprContext(parentestate));
2970
2971 i = list_length(parentestate->es_plannedstmt->paramExecTypes);
2972
2973 while (--i >= 0)
2974 {
2975 /* copy value if any, but not execPlan link */
2976 recheckestate->es_param_exec_vals[i].value =
2977 parentestate->es_param_exec_vals[i].value;
2978 recheckestate->es_param_exec_vals[i].isnull =
2979 parentestate->es_param_exec_vals[i].isnull;
2980 }
2981 }
2982
2983 /*
2984 * Mark child plan tree as needing rescan at all scan nodes. The
2985 * first ExecProcNode will take care of actually doing the rescan.
2986 */
2987 rcplanstate->chgParam = bms_add_member(rcplanstate->chgParam,
2988 epqstate->epqParam);
2989 }
2990}
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
unsigned int Index
Definition: c.h:623
static void EvalPlanQualStart(EPQState *epqstate, Plan *planTree)
Definition: execMain.c:2999
#define GetPerTupleExprContext(estate)
Definition: executor.h:656
int i
Definition: isn.c:77
void ExecSetParamPlanMulti(const Bitmapset *params, ExprContext *econtext)
Definition: nodeSubplan.c:1296
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
Plan * plan
Definition: execnodes.h:1319
int epqParam
Definition: execnodes.h:1302
EState * parentestate
Definition: execnodes.h:1301
EState * recheckestate
Definition: execnodes.h:1333
PlanState * recheckplanstate
Definition: execnodes.h:1358
PlannedStmt * es_plannedstmt
Definition: execnodes.h:669
ParamExecData * es_param_exec_vals
Definition: execnodes.h:705
Index es_range_table_size
Definition: execnodes.h:663
bool isnull
Definition: params.h:149
Datum value
Definition: params.h:148
Plan * plan
Definition: execnodes.h:1165
Bitmapset * chgParam
Definition: execnodes.h:1197
Bitmapset * extParam
Definition: plannodes.h:249
List * paramExecTypes
Definition: plannodes.h:147

References bms_add_member(), PlanState::chgParam, EPQState::epqParam, EState::es_param_exec_vals, EState::es_plannedstmt, EState::es_range_table_size, EvalPlanQualStart(), ExecSetParamPlanMulti(), Plan::extParam, GetPerTupleExprContext, i, ParamExecData::isnull, list_length(), NIL, PlannedStmt::paramExecTypes, EPQState::parentestate, PlanState::plan, EPQState::plan, EPQState::recheckestate, EPQState::recheckplanstate, EPQState::relsubs_blocked, EPQState::relsubs_done, and ParamExecData::value.

Referenced by EvalPlanQual(), ExecDelete(), and ExecLockRows().

◆ EvalPlanQualEnd()

void EvalPlanQualEnd ( EPQState epqstate)

Definition at line 3182 of file execMain.c.

3183{
3184 EState *estate = epqstate->recheckestate;
3185 Index rtsize;
3186 MemoryContext oldcontext;
3187 ListCell *l;
3188
3189 rtsize = epqstate->parentestate->es_range_table_size;
3190
3191 /*
3192 * We may have a tuple table, even if EPQ wasn't started, because we allow
3193 * use of EvalPlanQualSlot() without calling EvalPlanQualBegin().
3194 */
3195 if (epqstate->tuple_table != NIL)
3196 {
3197 memset(epqstate->relsubs_slot, 0,
3198 rtsize * sizeof(TupleTableSlot *));
3199 ExecResetTupleTable(epqstate->tuple_table, true);
3200 epqstate->tuple_table = NIL;
3201 }
3202
3203 /* EPQ wasn't started, nothing further to do */
3204 if (estate == NULL)
3205 return;
3206
3207 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
3208
3209 ExecEndNode(epqstate->recheckplanstate);
3210
3211 foreach(l, estate->es_subplanstates)
3212 {
3213 PlanState *subplanstate = (PlanState *) lfirst(l);
3214
3215 ExecEndNode(subplanstate);
3216 }
3217
3218 /* throw away the per-estate tuple table, some node may have used it */
3219 ExecResetTupleTable(estate->es_tupleTable, false);
3220
3221 /* Close any result and trigger target relations attached to this EState */
3223
3224 MemoryContextSwitchTo(oldcontext);
3225
3226 /*
3227 * NULLify the partition directory before freeing the executor state.
3228 * Since EvalPlanQualStart() just borrowed the parent EState's directory,
3229 * we'd better leave it up to the parent to delete it.
3230 */
3231 estate->es_partition_directory = NULL;
3232
3233 FreeExecutorState(estate);
3234
3235 /* Mark EPQState idle */
3236 epqstate->origslot = NULL;
3237 epqstate->recheckestate = NULL;
3238 epqstate->recheckplanstate = NULL;
3239 epqstate->relsubs_rowmark = NULL;
3240 epqstate->relsubs_done = NULL;
3241 epqstate->relsubs_blocked = NULL;
3242}
void ExecCloseResultRelations(EState *estate)
Definition: execMain.c:1575
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:562
void ExecResetTupleTable(List *tupleTable, bool shouldFree)
Definition: execTuples.c:1380
void FreeExecutorState(EState *estate)
Definition: execUtils.c:192
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define lfirst(lc)
Definition: pg_list.h:172
ExecAuxRowMark ** relsubs_rowmark
Definition: execnodes.h:1340
TupleTableSlot * origslot
Definition: execnodes.h:1328
TupleTableSlot ** relsubs_slot
Definition: execnodes.h:1312
List * tuple_table
Definition: execnodes.h:1311
MemoryContext es_query_cxt
Definition: execnodes.h:710
List * es_tupleTable
Definition: execnodes.h:712
PartitionDirectory es_partition_directory
Definition: execnodes.h:692
List * es_subplanstates
Definition: execnodes.h:725

References EState::es_partition_directory, EState::es_query_cxt, EState::es_range_table_size, EState::es_subplanstates, EState::es_tupleTable, ExecCloseResultRelations(), ExecEndNode(), ExecResetTupleTable(), FreeExecutorState(), lfirst, MemoryContextSwitchTo(), NIL, EPQState::origslot, EPQState::parentestate, EPQState::recheckestate, EPQState::recheckplanstate, EPQState::relsubs_blocked, EPQState::relsubs_done, EPQState::relsubs_rowmark, EPQState::relsubs_slot, and EPQState::tuple_table.

Referenced by apply_handle_delete_internal(), apply_handle_tuple_routing(), apply_handle_update_internal(), EvalPlanQualSetPlan(), ExecEndLockRows(), ExecEndModifyTable(), and ExecLockRows().

◆ EvalPlanQualFetchRowMark()

bool EvalPlanQualFetchRowMark ( EPQState epqstate,
Index  rti,
TupleTableSlot slot 
)

Definition at line 2805 of file execMain.c.

2806{
2807 ExecAuxRowMark *earm = epqstate->relsubs_rowmark[rti - 1];
2808 ExecRowMark *erm;
2809 Datum datum;
2810 bool isNull;
2811
2812 Assert(earm != NULL);
2813 Assert(epqstate->origslot != NULL);
2814
2815 erm = earm->rowmark;
2816
2818 elog(ERROR, "EvalPlanQual doesn't support locking rowmarks");
2819
2820 /* if child rel, must check whether it produced this row */
2821 if (erm->rti != erm->prti)
2822 {
2823 Oid tableoid;
2824
2825 datum = ExecGetJunkAttribute(epqstate->origslot,
2826 earm->toidAttNo,
2827 &isNull);
2828 /* non-locked rels could be on the inside of outer joins */
2829 if (isNull)
2830 return false;
2831
2832 tableoid = DatumGetObjectId(datum);
2833
2834 Assert(OidIsValid(erm->relid));
2835 if (tableoid != erm->relid)
2836 {
2837 /* this child is inactive right now */
2838 return false;
2839 }
2840 }
2841
2842 if (erm->markType == ROW_MARK_REFERENCE)
2843 {
2844 Assert(erm->relation != NULL);
2845
2846 /* fetch the tuple's ctid */
2847 datum = ExecGetJunkAttribute(epqstate->origslot,
2848 earm->ctidAttNo,
2849 &isNull);
2850 /* non-locked rels could be on the inside of outer joins */
2851 if (isNull)
2852 return false;
2853
2854 /* fetch requests on foreign tables must be passed to their FDW */
2855 if (erm->relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2856 {
2857 FdwRoutine *fdwroutine;
2858 bool updated = false;
2859
2860 fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
2861 /* this should have been checked already, but let's be safe */
2862 if (fdwroutine->RefetchForeignRow == NULL)
2863 ereport(ERROR,
2864 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2865 errmsg("cannot lock rows in foreign table \"%s\"",
2867
2868 fdwroutine->RefetchForeignRow(epqstate->recheckestate,
2869 erm,
2870 datum,
2871 slot,
2872 &updated);
2873 if (TupIsNull(slot))
2874 elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
2875
2876 /*
2877 * Ideally we'd insist on updated == false here, but that assumes
2878 * that FDWs can track that exactly, which they might not be able
2879 * to. So just ignore the flag.
2880 */
2881 return true;
2882 }
2883 else
2884 {
2885 /* ordinary table, fetch the tuple */
2888 SnapshotAny, slot))
2889 elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
2890 return true;
2891 }
2892 }
2893 else
2894 {
2895 Assert(erm->markType == ROW_MARK_COPY);
2896
2897 /* fetch the whole-row Var for the relation */
2898 datum = ExecGetJunkAttribute(epqstate->origslot,
2899 earm->wholeAttNo,
2900 &isNull);
2901 /* non-locked rels could be on the inside of outer joins */
2902 if (isNull)
2903 return false;
2904
2905 ExecStoreHeapTupleDatum(datum, slot);
2906 return true;
2907 }
2908}
#define OidIsValid(objectId)
Definition: c.h:778
void ExecStoreHeapTupleDatum(Datum data, TupleTableSlot *slot)
Definition: execTuples.c:1795
static Datum ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno, bool *isNull)
Definition: executor.h:225
#define RowMarkRequiresRowShareLock(marktype)
Definition: plannodes.h:1544
@ ROW_MARK_COPY
Definition: plannodes.h:1541
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:252
uint64_t Datum
Definition: postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:322
unsigned int Oid
Definition: postgres_ext.h:32
#define SnapshotAny
Definition: snapmgr.h:33
AttrNumber wholeAttNo
Definition: execnodes.h:824
ExecRowMark * rowmark
Definition: execnodes.h:821
AttrNumber toidAttNo
Definition: execnodes.h:823
AttrNumber ctidAttNo
Definition: execnodes.h:822
Index rti
Definition: execnodes.h:799
Index prti
Definition: execnodes.h:800
Relation relation
Definition: execnodes.h:797
RowMarkType markType
Definition: execnodes.h:802
static bool table_tuple_fetch_row_version(Relation rel, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot)
Definition: tableam.h:1253

References Assert(), ExecAuxRowMark::ctidAttNo, DatumGetObjectId(), DatumGetPointer(), elog, ereport, errcode(), errmsg(), ERROR, ExecGetJunkAttribute(), ExecStoreHeapTupleDatum(), GetFdwRoutineForRelation(), ExecRowMark::markType, OidIsValid, EPQState::origslot, ExecRowMark::prti, RelationData::rd_rel, EPQState::recheckestate, FdwRoutine::RefetchForeignRow, ExecRowMark::relation, RelationGetRelationName, ExecRowMark::relid, EPQState::relsubs_rowmark, ROW_MARK_COPY, ROW_MARK_REFERENCE, ExecAuxRowMark::rowmark, RowMarkRequiresRowShareLock, ExecRowMark::rti, SnapshotAny, table_tuple_fetch_row_version(), ExecAuxRowMark::toidAttNo, TupIsNull, and ExecAuxRowMark::wholeAttNo.

Referenced by ExecScanFetch().

◆ EvalPlanQualInit()

void EvalPlanQualInit ( EPQState epqstate,
EState parentestate,
Plan subplan,
List auxrowmarks,
int  epqParam,
List resultRelations 
)

Definition at line 2718 of file execMain.c.

2721{
2722 Index rtsize = parentestate->es_range_table_size;
2723
2724 /* initialize data not changing over EPQState's lifetime */
2725 epqstate->parentestate = parentestate;
2726 epqstate->epqParam = epqParam;
2727 epqstate->resultRelations = resultRelations;
2728
2729 /*
2730 * Allocate space to reference a slot for each potential rti - do so now
2731 * rather than in EvalPlanQualBegin(), as done for other dynamically
2732 * allocated resources, so EvalPlanQualSlot() can be used to hold tuples
2733 * that *may* need EPQ later, without forcing the overhead of
2734 * EvalPlanQualBegin().
2735 */
2736 epqstate->tuple_table = NIL;
2737 epqstate->relsubs_slot = (TupleTableSlot **)
2738 palloc0(rtsize * sizeof(TupleTableSlot *));
2739
2740 /* ... and remember data that EvalPlanQualBegin will need */
2741 epqstate->plan = subplan;
2742 epqstate->arowMarks = auxrowmarks;
2743
2744 /* ... and mark the EPQ state inactive */
2745 epqstate->origslot = NULL;
2746 epqstate->recheckestate = NULL;
2747 epqstate->recheckplanstate = NULL;
2748 epqstate->relsubs_rowmark = NULL;
2749 epqstate->relsubs_done = NULL;
2750 epqstate->relsubs_blocked = NULL;
2751}
void * palloc0(Size size)
Definition: mcxt.c:1395
List * resultRelations
Definition: execnodes.h:1303
List * arowMarks
Definition: execnodes.h:1320

References EPQState::arowMarks, EPQState::epqParam, EState::es_range_table_size, NIL, EPQState::origslot, palloc0(), EPQState::parentestate, EPQState::plan, EPQState::recheckestate, EPQState::recheckplanstate, EPQState::relsubs_blocked, EPQState::relsubs_done, EPQState::relsubs_rowmark, EPQState::relsubs_slot, EPQState::resultRelations, and EPQState::tuple_table.

Referenced by apply_handle_delete_internal(), apply_handle_tuple_routing(), apply_handle_update_internal(), ExecInitLockRows(), and ExecInitModifyTable().

◆ EvalPlanQualNext()

TupleTableSlot * EvalPlanQualNext ( EPQState epqstate)

Definition at line 2916 of file execMain.c.

2917{
2918 MemoryContext oldcontext;
2919 TupleTableSlot *slot;
2920
2921 oldcontext = MemoryContextSwitchTo(epqstate->recheckestate->es_query_cxt);
2922 slot = ExecProcNode(epqstate->recheckplanstate);
2923 MemoryContextSwitchTo(oldcontext);
2924
2925 return slot;
2926}
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition: executor.h:314

References EState::es_query_cxt, ExecProcNode(), MemoryContextSwitchTo(), EPQState::recheckestate, and EPQState::recheckplanstate.

Referenced by EvalPlanQual(), and ExecLockRows().

◆ EvalPlanQualSetPlan()

void EvalPlanQualSetPlan ( EPQState epqstate,
Plan subplan,
List auxrowmarks 
)

Definition at line 2760 of file execMain.c.

2761{
2762 /* If we have a live EPQ query, shut it down */
2763 EvalPlanQualEnd(epqstate);
2764 /* And set/change the plan pointer */
2765 epqstate->plan = subplan;
2766 /* The rowmarks depend on the plan, too */
2767 epqstate->arowMarks = auxrowmarks;
2768}
void EvalPlanQualEnd(EPQState *epqstate)
Definition: execMain.c:3182

References EPQState::arowMarks, EvalPlanQualEnd(), and EPQState::plan.

Referenced by ExecInitModifyTable().

◆ EvalPlanQualSlot()

TupleTableSlot * EvalPlanQualSlot ( EPQState epqstate,
Relation  relation,
Index  rti 
)

Definition at line 2777 of file execMain.c.

2779{
2780 TupleTableSlot **slot;
2781
2782 Assert(relation);
2783 Assert(rti > 0 && rti <= epqstate->parentestate->es_range_table_size);
2784 slot = &epqstate->relsubs_slot[rti - 1];
2785
2786 if (*slot == NULL)
2787 {
2788 MemoryContext oldcontext;
2789
2790 oldcontext = MemoryContextSwitchTo(epqstate->parentestate->es_query_cxt);
2791 *slot = table_slot_create(relation, &epqstate->tuple_table);
2792 MemoryContextSwitchTo(oldcontext);
2793 }
2794
2795 return *slot;
2796}
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition: tableam.c:92

References Assert(), EState::es_query_cxt, MemoryContextSwitchTo(), EPQState::parentestate, EPQState::relsubs_slot, table_slot_create(), and EPQState::tuple_table.

Referenced by EvalPlanQual(), ExecDelete(), ExecLockRows(), ExecMergeMatched(), and ExecUpdate().

◆ EvalPlanQualStart()

static void EvalPlanQualStart ( EPQState epqstate,
Plan planTree 
)
static

Definition at line 2999 of file execMain.c.

3000{
3001 EState *parentestate = epqstate->parentestate;
3002 Index rtsize = parentestate->es_range_table_size;
3003 EState *rcestate;
3004 MemoryContext oldcontext;
3005 ListCell *l;
3006
3007 epqstate->recheckestate = rcestate = CreateExecutorState();
3008
3009 oldcontext = MemoryContextSwitchTo(rcestate->es_query_cxt);
3010
3011 /* signal that this is an EState for executing EPQ */
3012 rcestate->es_epq_active = epqstate;
3013
3014 /*
3015 * Child EPQ EStates share the parent's copy of unchanging state such as
3016 * the snapshot, rangetable, and external Param info. They need their own
3017 * copies of local state, including a tuple table, es_param_exec_vals,
3018 * result-rel info, etc.
3019 */
3021 rcestate->es_snapshot = parentestate->es_snapshot;
3022 rcestate->es_crosscheck_snapshot = parentestate->es_crosscheck_snapshot;
3023 rcestate->es_range_table = parentestate->es_range_table;
3024 rcestate->es_range_table_size = parentestate->es_range_table_size;
3025 rcestate->es_relations = parentestate->es_relations;
3026 rcestate->es_rowmarks = parentestate->es_rowmarks;
3027 rcestate->es_rteperminfos = parentestate->es_rteperminfos;
3028 rcestate->es_plannedstmt = parentestate->es_plannedstmt;
3029 rcestate->es_junkFilter = parentestate->es_junkFilter;
3030 rcestate->es_output_cid = parentestate->es_output_cid;
3031 rcestate->es_queryEnv = parentestate->es_queryEnv;
3032
3033 /*
3034 * ResultRelInfos needed by subplans are initialized from scratch when the
3035 * subplans themselves are initialized.
3036 */
3037 rcestate->es_result_relations = NULL;
3038 /* es_trig_target_relations must NOT be copied */
3039 rcestate->es_top_eflags = parentestate->es_top_eflags;
3040 rcestate->es_instrument = parentestate->es_instrument;
3041 /* es_auxmodifytables must NOT be copied */
3042
3043 /*
3044 * The external param list is simply shared from parent. The internal
3045 * param workspace has to be local state, but we copy the initial values
3046 * from the parent, so as to have access to any param values that were
3047 * already set from other parts of the parent's plan tree.
3048 */
3049 rcestate->es_param_list_info = parentestate->es_param_list_info;
3050 if (parentestate->es_plannedstmt->paramExecTypes != NIL)
3051 {
3052 int i;
3053
3054 /*
3055 * Force evaluation of any InitPlan outputs that could be needed by
3056 * the subplan. (With more complexity, maybe we could postpone this
3057 * till the subplan actually demands them, but it doesn't seem worth
3058 * the trouble; this is a corner case already, since usually the
3059 * InitPlans would have been evaluated before reaching EvalPlanQual.)
3060 *
3061 * This will not touch output params of InitPlans that occur somewhere
3062 * within the subplan tree, only those that are attached to the
3063 * ModifyTable node or above it and are referenced within the subplan.
3064 * That's OK though, because the planner would only attach such
3065 * InitPlans to a lower-level SubqueryScan node, and EPQ execution
3066 * will not descend into a SubqueryScan.
3067 *
3068 * The EState's per-output-tuple econtext is sufficiently short-lived
3069 * for this, since it should get reset before there is any chance of
3070 * doing EvalPlanQual again.
3071 */
3073 GetPerTupleExprContext(parentestate));
3074
3075 /* now make the internal param workspace ... */
3076 i = list_length(parentestate->es_plannedstmt->paramExecTypes);
3077 rcestate->es_param_exec_vals = (ParamExecData *)
3078 palloc0(i * sizeof(ParamExecData));
3079 /* ... and copy down all values, whether really needed or not */
3080 while (--i >= 0)
3081 {
3082 /* copy value if any, but not execPlan link */
3083 rcestate->es_param_exec_vals[i].value =
3084 parentestate->es_param_exec_vals[i].value;
3085 rcestate->es_param_exec_vals[i].isnull =
3086 parentestate->es_param_exec_vals[i].isnull;
3087 }
3088 }
3089
3090 /*
3091 * Copy es_unpruned_relids so that pruned relations are ignored by
3092 * ExecInitLockRows() and ExecInitModifyTable() when initializing the plan
3093 * trees below.
3094 */
3095 rcestate->es_unpruned_relids = parentestate->es_unpruned_relids;
3096
3097 /*
3098 * Also make the PartitionPruneInfo and the results of pruning available.
3099 * These need to match exactly so that we initialize all the same Append
3100 * and MergeAppend subplans as the parent did.
3101 */
3102 rcestate->es_part_prune_infos = parentestate->es_part_prune_infos;
3103 rcestate->es_part_prune_states = parentestate->es_part_prune_states;
3104 rcestate->es_part_prune_results = parentestate->es_part_prune_results;
3105
3106 /* We'll also borrow the es_partition_directory from the parent state */
3107 rcestate->es_partition_directory = parentestate->es_partition_directory;
3108
3109 /*
3110 * Initialize private state information for each SubPlan. We must do this
3111 * before running ExecInitNode on the main query tree, since
3112 * ExecInitSubPlan expects to be able to find these entries. Some of the
3113 * SubPlans might not be used in the part of the plan tree we intend to
3114 * run, but since it's not easy to tell which, we just initialize them
3115 * all.
3116 */
3117 Assert(rcestate->es_subplanstates == NIL);
3118 foreach(l, parentestate->es_plannedstmt->subplans)
3119 {
3120 Plan *subplan = (Plan *) lfirst(l);
3121 PlanState *subplanstate;
3122
3123 subplanstate = ExecInitNode(subplan, rcestate, 0);
3124 rcestate->es_subplanstates = lappend(rcestate->es_subplanstates,
3125 subplanstate);
3126 }
3127
3128 /*
3129 * Build an RTI indexed array of rowmarks, so that
3130 * EvalPlanQualFetchRowMark() can efficiently access the to be fetched
3131 * rowmark.
3132 */
3133 epqstate->relsubs_rowmark = (ExecAuxRowMark **)
3134 palloc0(rtsize * sizeof(ExecAuxRowMark *));
3135 foreach(l, epqstate->arowMarks)
3136 {
3137 ExecAuxRowMark *earm = (ExecAuxRowMark *) lfirst(l);
3138
3139 epqstate->relsubs_rowmark[earm->rowmark->rti - 1] = earm;
3140 }
3141
3142 /*
3143 * Initialize per-relation EPQ tuple states. Result relations, if any,
3144 * get marked as blocked; others as not-fetched.
3145 */
3146 epqstate->relsubs_done = palloc_array(bool, rtsize);
3147 epqstate->relsubs_blocked = palloc0_array(bool, rtsize);
3148
3149 foreach(l, epqstate->resultRelations)
3150 {
3151 int rtindex = lfirst_int(l);
3152
3153 Assert(rtindex > 0 && rtindex <= rtsize);
3154 epqstate->relsubs_blocked[rtindex - 1] = true;
3155 }
3156
3157 memcpy(epqstate->relsubs_done, epqstate->relsubs_blocked,
3158 rtsize * sizeof(bool));
3159
3160 /*
3161 * Initialize the private state information for all the nodes in the part
3162 * of the plan tree we need to run. This opens files, allocates storage
3163 * and leaves us ready to start processing tuples.
3164 */
3165 epqstate->recheckplanstate = ExecInitNode(planTree, rcestate, 0);
3166
3167 MemoryContextSwitchTo(oldcontext);
3168}
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:142
EState * CreateExecutorState(void)
Definition: execUtils.c:88
#define palloc_array(type, count)
Definition: fe_memutils.h:76
#define palloc0_array(type, count)
Definition: fe_memutils.h:77
List * lappend(List *list, void *datum)
Definition: list.c:339
#define lfirst_int(lc)
Definition: pg_list.h:173
@ ForwardScanDirection
Definition: sdir.h:28
List * es_part_prune_infos
Definition: execnodes.h:670
int es_top_eflags
Definition: execnodes.h:719
int es_instrument
Definition: execnodes.h:720
QueryEnvironment * es_queryEnv
Definition: execnodes.h:707
ResultRelInfo ** es_result_relations
Definition: execnodes.h:685
List * es_range_table
Definition: execnodes.h:662
List * es_rteperminfos
Definition: execnodes.h:668
Bitmapset * es_unpruned_relids
Definition: execnodes.h:673
List * es_part_prune_states
Definition: execnodes.h:671
ParamListInfo es_param_list_info
Definition: execnodes.h:704
ExecRowMark ** es_rowmarks
Definition: execnodes.h:666
ScanDirection es_direction
Definition: execnodes.h:659
struct EPQState * es_epq_active
Definition: execnodes.h:742
Relation * es_relations
Definition: execnodes.h:664
CommandId es_output_cid
Definition: execnodes.h:682
Snapshot es_snapshot
Definition: execnodes.h:660
JunkFilter * es_junkFilter
Definition: execnodes.h:679
List * es_part_prune_results
Definition: execnodes.h:672
Snapshot es_crosscheck_snapshot
Definition: execnodes.h:661
List * subplans
Definition: plannodes.h:132

References EPQState::arowMarks, Assert(), CreateExecutorState(), EState::es_crosscheck_snapshot, EState::es_direction, EState::es_epq_active, EState::es_instrument, EState::es_junkFilter, EState::es_output_cid, EState::es_param_exec_vals, EState::es_param_list_info, EState::es_part_prune_infos, EState::es_part_prune_results, EState::es_part_prune_states, EState::es_partition_directory, EState::es_plannedstmt, EState::es_query_cxt, EState::es_queryEnv, EState::es_range_table, EState::es_range_table_size, EState::es_relations, EState::es_result_relations, EState::es_rowmarks, EState::es_rteperminfos, EState::es_snapshot, EState::es_subplanstates, EState::es_top_eflags, EState::es_unpruned_relids, ExecInitNode(), ExecSetParamPlanMulti(), Plan::extParam, ForwardScanDirection, GetPerTupleExprContext, i, ParamExecData::isnull, lappend(), lfirst, lfirst_int, list_length(), MemoryContextSwitchTo(), NIL, palloc0(), palloc0_array, palloc_array, PlannedStmt::paramExecTypes, EPQState::parentestate, EPQState::recheckestate, EPQState::recheckplanstate, EPQState::relsubs_blocked, EPQState::relsubs_done, EPQState::relsubs_rowmark, EPQState::resultRelations, ExecAuxRowMark::rowmark, ExecRowMark::rti, PlannedStmt::subplans, and ParamExecData::value.

Referenced by EvalPlanQualBegin().

◆ ExecBuildAuxRowMark()

ExecAuxRowMark * ExecBuildAuxRowMark ( ExecRowMark erm,
List targetlist 
)

Definition at line 2579 of file execMain.c.

2580{
2582 char resname[32];
2583
2584 aerm->rowmark = erm;
2585
2586 /* Look up the resjunk columns associated with this rowmark */
2587 if (erm->markType != ROW_MARK_COPY)
2588 {
2589 /* need ctid for all methods other than COPY */
2590 snprintf(resname, sizeof(resname), "ctid%u", erm->rowmarkId);
2591 aerm->ctidAttNo = ExecFindJunkAttributeInTlist(targetlist,
2592 resname);
2594 elog(ERROR, "could not find junk %s column", resname);
2595 }
2596 else
2597 {
2598 /* need wholerow if COPY */
2599 snprintf(resname, sizeof(resname), "wholerow%u", erm->rowmarkId);
2600 aerm->wholeAttNo = ExecFindJunkAttributeInTlist(targetlist,
2601 resname);
2603 elog(ERROR, "could not find junk %s column", resname);
2604 }
2605
2606 /* if child rel, need tableoid */
2607 if (erm->rti != erm->prti)
2608 {
2609 snprintf(resname, sizeof(resname), "tableoid%u", erm->rowmarkId);
2610 aerm->toidAttNo = ExecFindJunkAttributeInTlist(targetlist,
2611 resname);
2613 elog(ERROR, "could not find junk %s column", resname);
2614 }
2615
2616 return aerm;
2617}
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
Definition: execJunk.c:222
#define snprintf
Definition: port.h:239
Index rowmarkId
Definition: execnodes.h:801

References AttributeNumberIsValid, ExecAuxRowMark::ctidAttNo, elog, ERROR, ExecFindJunkAttributeInTlist(), ExecRowMark::markType, palloc0(), ExecRowMark::prti, ROW_MARK_COPY, ExecAuxRowMark::rowmark, ExecRowMark::rowmarkId, ExecRowMark::rti, snprintf, ExecAuxRowMark::toidAttNo, and ExecAuxRowMark::wholeAttNo.

Referenced by ExecInitLockRows(), and ExecInitModifyTable().

◆ ExecBuildSlotValueDescription()

char * ExecBuildSlotValueDescription ( Oid  reloid,
TupleTableSlot slot,
TupleDesc  tupdesc,
Bitmapset modifiedCols,
int  maxfieldlen 
)

Definition at line 2391 of file execMain.c.

2396{
2398 StringInfoData collist;
2399 bool write_comma = false;
2400 bool write_comma_collist = false;
2401 int i;
2402 AclResult aclresult;
2403 bool table_perm = false;
2404 bool any_perm = false;
2405
2406 /*
2407 * Check if RLS is enabled and should be active for the relation; if so,
2408 * then don't return anything. Otherwise, go through normal permission
2409 * checks.
2410 */
2411 if (check_enable_rls(reloid, InvalidOid, true) == RLS_ENABLED)
2412 return NULL;
2413
2415
2417
2418 /*
2419 * Check if the user has permissions to see the row. Table-level SELECT
2420 * allows access to all columns. If the user does not have table-level
2421 * SELECT then we check each column and include those the user has SELECT
2422 * rights on. Additionally, we always include columns the user provided
2423 * data for.
2424 */
2425 aclresult = pg_class_aclcheck(reloid, GetUserId(), ACL_SELECT);
2426 if (aclresult != ACLCHECK_OK)
2427 {
2428 /* Set up the buffer for the column list */
2429 initStringInfo(&collist);
2430 appendStringInfoChar(&collist, '(');
2431 }
2432 else
2433 table_perm = any_perm = true;
2434
2435 /* Make sure the tuple is fully deconstructed */
2436 slot_getallattrs(slot);
2437
2438 for (i = 0; i < tupdesc->natts; i++)
2439 {
2440 bool column_perm = false;
2441 char *val;
2442 int vallen;
2443 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
2444
2445 /* ignore dropped columns */
2446 if (att->attisdropped)
2447 continue;
2448
2449 if (!table_perm)
2450 {
2451 /*
2452 * No table-level SELECT, so need to make sure they either have
2453 * SELECT rights on the column or that they have provided the data
2454 * for the column. If not, omit this column from the error
2455 * message.
2456 */
2457 aclresult = pg_attribute_aclcheck(reloid, att->attnum,
2460 modifiedCols) || aclresult == ACLCHECK_OK)
2461 {
2462 column_perm = any_perm = true;
2463
2464 if (write_comma_collist)
2465 appendStringInfoString(&collist, ", ");
2466 else
2467 write_comma_collist = true;
2468
2469 appendStringInfoString(&collist, NameStr(att->attname));
2470 }
2471 }
2472
2473 if (table_perm || column_perm)
2474 {
2475 if (att->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
2476 val = "virtual";
2477 else if (slot->tts_isnull[i])
2478 val = "null";
2479 else
2480 {
2481 Oid foutoid;
2482 bool typisvarlena;
2483
2484 getTypeOutputInfo(att->atttypid,
2485 &foutoid, &typisvarlena);
2486 val = OidOutputFunctionCall(foutoid, slot->tts_values[i]);
2487 }
2488
2489 if (write_comma)
2491 else
2492 write_comma = true;
2493
2494 /* truncate if needed */
2495 vallen = strlen(val);
2496 if (vallen <= maxfieldlen)
2497 appendBinaryStringInfo(&buf, val, vallen);
2498 else
2499 {
2500 vallen = pg_mbcliplen(val, vallen, maxfieldlen);
2501 appendBinaryStringInfo(&buf, val, vallen);
2502 appendStringInfoString(&buf, "...");
2503 }
2504 }
2505 }
2506
2507 /* If we end up with zero columns being returned, then return NULL. */
2508 if (!any_perm)
2509 return NULL;
2510
2512
2513 if (!table_perm)
2514 {
2515 appendStringInfoString(&collist, ") = ");
2516 appendBinaryStringInfo(&collist, buf.data, buf.len);
2517
2518 return collist.data;
2519 }
2520
2521 return buf.data;
2522}
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition: aclchk.c:3866
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4037
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
#define NameStr(name)
Definition: c.h:755
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:1763
long val
Definition: informix.c:689
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:3074
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1084
Oid GetUserId(void)
Definition: miscinit.c:469
#define ACL_SELECT
Definition: parsenodes.h:77
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
static char * buf
Definition: pg_test_fsync.c:72
#define InvalidOid
Definition: postgres_ext.h:37
int check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
Definition: rls.c:52
@ RLS_ENABLED
Definition: rls.h:45
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:281
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
bool * tts_isnull
Definition: tuptable.h:126
Datum * tts_values
Definition: tuptable.h:124
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:371

References ACL_SELECT, ACLCHECK_OK, appendBinaryStringInfo(), appendStringInfoChar(), appendStringInfoString(), bms_is_member(), buf, check_enable_rls(), StringInfoData::data, FirstLowInvalidHeapAttributeNumber, getTypeOutputInfo(), GetUserId(), i, initStringInfo(), InvalidOid, NameStr, TupleDescData::natts, OidOutputFunctionCall(), pg_attribute_aclcheck(), pg_class_aclcheck(), pg_mbcliplen(), RLS_ENABLED, slot_getallattrs(), TupleTableSlot::tts_isnull, TupleTableSlot::tts_values, TupleDescAttr(), and val.

Referenced by build_tuple_value_details(), ExecConstraints(), ExecPartitionCheckEmitError(), ExecWithCheckOptions(), and ReportNotNullViolationError().

◆ ExecCheckOneRelPerms()

bool ExecCheckOneRelPerms ( RTEPermissionInfo perminfo)

Definition at line 646 of file execMain.c.

647{
648 AclMode requiredPerms;
649 AclMode relPerms;
650 AclMode remainingPerms;
651 Oid userid;
652 Oid relOid = perminfo->relid;
653
654 requiredPerms = perminfo->requiredPerms;
655 Assert(requiredPerms != 0);
656
657 /*
658 * userid to check as: current user unless we have a setuid indication.
659 *
660 * Note: GetUserId() is presently fast enough that there's no harm in
661 * calling it separately for each relation. If that stops being true, we
662 * could call it once in ExecCheckPermissions and pass the userid down
663 * from there. But for now, no need for the extra clutter.
664 */
665 userid = OidIsValid(perminfo->checkAsUser) ?
666 perminfo->checkAsUser : GetUserId();
667
668 /*
669 * We must have *all* the requiredPerms bits, but some of the bits can be
670 * satisfied from column-level rather than relation-level permissions.
671 * First, remove any bits that are satisfied by relation permissions.
672 */
673 relPerms = pg_class_aclmask(relOid, userid, requiredPerms, ACLMASK_ALL);
674 remainingPerms = requiredPerms & ~relPerms;
675 if (remainingPerms != 0)
676 {
677 int col = -1;
678
679 /*
680 * If we lack any permissions that exist only as relation permissions,
681 * we can fail straight away.
682 */
683 if (remainingPerms & ~(ACL_SELECT | ACL_INSERT | ACL_UPDATE))
684 return false;
685
686 /*
687 * Check to see if we have the needed privileges at column level.
688 *
689 * Note: failures just report a table-level error; it would be nicer
690 * to report a column-level error if we have some but not all of the
691 * column privileges.
692 */
693 if (remainingPerms & ACL_SELECT)
694 {
695 /*
696 * When the query doesn't explicitly reference any columns (for
697 * example, SELECT COUNT(*) FROM table), allow the query if we
698 * have SELECT on any column of the rel, as per SQL spec.
699 */
700 if (bms_is_empty(perminfo->selectedCols))
701 {
702 if (pg_attribute_aclcheck_all(relOid, userid, ACL_SELECT,
704 return false;
705 }
706
707 while ((col = bms_next_member(perminfo->selectedCols, col)) >= 0)
708 {
709 /* bit #s are offset by FirstLowInvalidHeapAttributeNumber */
711
712 if (attno == InvalidAttrNumber)
713 {
714 /* Whole-row reference, must have priv on all cols */
715 if (pg_attribute_aclcheck_all(relOid, userid, ACL_SELECT,
717 return false;
718 }
719 else
720 {
721 if (pg_attribute_aclcheck(relOid, attno, userid,
723 return false;
724 }
725 }
726 }
727
728 /*
729 * Basically the same for the mod columns, for both INSERT and UPDATE
730 * privilege as specified by remainingPerms.
731 */
732 if (remainingPerms & ACL_INSERT &&
734 userid,
735 perminfo->insertedCols,
736 ACL_INSERT))
737 return false;
738
739 if (remainingPerms & ACL_UPDATE &&
741 userid,
742 perminfo->updatedCols,
743 ACL_UPDATE))
744 return false;
745 }
746 return true;
747}
@ ACLMASK_ANY
Definition: acl.h:177
@ ACLMASK_ALL
Definition: acl.h:176
AclResult pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode, AclMaskHow how)
Definition: aclchk.c:3908
AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how)
Definition: aclchk.c:3270
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
#define bms_is_empty(a)
Definition: bitmapset.h:118
static bool ExecCheckPermissionsModified(Oid relOid, Oid userid, Bitmapset *modifiedCols, AclMode requiredPerms)
Definition: execMain.c:755
uint64 AclMode
Definition: parsenodes.h:74
#define ACL_INSERT
Definition: parsenodes.h:76
#define ACL_UPDATE
Definition: parsenodes.h:78
Bitmapset * selectedCols
Definition: parsenodes.h:1324
AclMode requiredPerms
Definition: parsenodes.h:1322
Bitmapset * insertedCols
Definition: parsenodes.h:1325
Bitmapset * updatedCols
Definition: parsenodes.h:1326

References ACL_INSERT, ACL_SELECT, ACL_UPDATE, ACLCHECK_OK, ACLMASK_ALL, ACLMASK_ANY, Assert(), bms_is_empty, bms_next_member(), RTEPermissionInfo::checkAsUser, ExecCheckPermissionsModified(), FirstLowInvalidHeapAttributeNumber, GetUserId(), RTEPermissionInfo::insertedCols, InvalidAttrNumber, OidIsValid, pg_attribute_aclcheck(), pg_attribute_aclcheck_all(), pg_class_aclmask(), RTEPermissionInfo::relid, RTEPermissionInfo::requiredPerms, RTEPermissionInfo::selectedCols, and RTEPermissionInfo::updatedCols.

Referenced by ExecCheckPermissions(), and subquery_planner().

◆ ExecCheckPermissions()

bool ExecCheckPermissions ( List rangeTable,
List rteperminfos,
bool  ereport_on_violation 
)

Definition at line 582 of file execMain.c.

584{
585 ListCell *l;
586 bool result = true;
587
588#ifdef USE_ASSERT_CHECKING
589 Bitmapset *indexset = NULL;
590
591 /* Check that rteperminfos is consistent with rangeTable */
592 foreach(l, rangeTable)
593 {
595
596 if (rte->perminfoindex != 0)
597 {
598 /* Sanity checks */
599
600 /*
601 * Only relation RTEs and subquery RTEs that were once relation
602 * RTEs (views) have their perminfoindex set.
603 */
604 Assert(rte->rtekind == RTE_RELATION ||
605 (rte->rtekind == RTE_SUBQUERY &&
606 rte->relkind == RELKIND_VIEW));
607
608 (void) getRTEPermissionInfo(rteperminfos, rte);
609 /* Many-to-one mapping not allowed */
610 Assert(!bms_is_member(rte->perminfoindex, indexset));
611 indexset = bms_add_member(indexset, rte->perminfoindex);
612 }
613 }
614
615 /* All rteperminfos are referenced */
616 Assert(bms_num_members(indexset) == list_length(rteperminfos));
617#endif
618
619 foreach(l, rteperminfos)
620 {
622
623 Assert(OidIsValid(perminfo->relid));
624 result = ExecCheckOneRelPerms(perminfo);
625 if (!result)
626 {
627 if (ereport_on_violation)
630 get_rel_name(perminfo->relid));
631 return false;
632 }
633 }
634
636 result = (*ExecutorCheckPerms_hook) (rangeTable, rteperminfos,
637 ereport_on_violation);
638 return result;
639}
@ ACLCHECK_NO_PRIV
Definition: acl.h:184
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2652
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:751
ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook
Definition: execMain.c:74
bool ExecCheckOneRelPerms(RTEPermissionInfo *perminfo)
Definition: execMain.c:646
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2095
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2170
ObjectType get_relkind_objtype(char relkind)
RTEPermissionInfo * getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
@ RTE_SUBQUERY
Definition: parsenodes.h:1044
@ RTE_RELATION
Definition: parsenodes.h:1043
#define lfirst_node(type, lc)
Definition: pg_list.h:176
RTEKind rtekind
Definition: parsenodes.h:1078

References aclcheck_error(), ACLCHECK_NO_PRIV, Assert(), bms_add_member(), bms_is_member(), bms_num_members(), ExecCheckOneRelPerms(), ExecutorCheckPerms_hook, get_rel_name(), get_rel_relkind(), get_relkind_objtype(), getRTEPermissionInfo(), lfirst_node, list_length(), OidIsValid, RTEPermissionInfo::relid, RTE_RELATION, RTE_SUBQUERY, and RangeTblEntry::rtekind.

Referenced by DoCopy(), InitPlan(), and RI_Initial_Check().

◆ ExecCheckPermissionsModified()

static bool ExecCheckPermissionsModified ( Oid  relOid,
Oid  userid,
Bitmapset modifiedCols,
AclMode  requiredPerms 
)
static

Definition at line 755 of file execMain.c.

757{
758 int col = -1;
759
760 /*
761 * When the query doesn't explicitly update any columns, allow the query
762 * if we have permission on any column of the rel. This is to handle
763 * SELECT FOR UPDATE as well as possible corner cases in UPDATE.
764 */
765 if (bms_is_empty(modifiedCols))
766 {
767 if (pg_attribute_aclcheck_all(relOid, userid, requiredPerms,
769 return false;
770 }
771
772 while ((col = bms_next_member(modifiedCols, col)) >= 0)
773 {
774 /* bit #s are offset by FirstLowInvalidHeapAttributeNumber */
776
777 if (attno == InvalidAttrNumber)
778 {
779 /* whole-row reference can't happen here */
780 elog(ERROR, "whole-row update is not implemented");
781 }
782 else
783 {
784 if (pg_attribute_aclcheck(relOid, attno, userid,
785 requiredPerms) != ACLCHECK_OK)
786 return false;
787 }
788 }
789 return true;
790}

References ACLCHECK_OK, ACLMASK_ANY, bms_is_empty, bms_next_member(), elog, ERROR, FirstLowInvalidHeapAttributeNumber, InvalidAttrNumber, pg_attribute_aclcheck(), and pg_attribute_aclcheck_all().

Referenced by ExecCheckOneRelPerms().

◆ ExecCheckXactReadOnly()

static void ExecCheckXactReadOnly ( PlannedStmt plannedstmt)
static

Definition at line 802 of file execMain.c.

803{
804 ListCell *l;
805
806 /*
807 * Fail if write permissions are requested in parallel mode for table
808 * (temp or non-temp), otherwise fail for any non-temp table.
809 */
810 foreach(l, plannedstmt->permInfos)
811 {
813
814 if ((perminfo->requiredPerms & (~ACL_SELECT)) == 0)
815 continue;
816
818 continue;
819
821 }
822
823 if (plannedstmt->commandType != CMD_SELECT || plannedstmt->hasModifyingCTE)
825}
Oid get_rel_namespace(Oid relid)
Definition: lsyscache.c:2119
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3719
@ CMD_SELECT
Definition: nodes.h:275
Definition: nodes.h:135
bool hasModifyingCTE
Definition: plannodes.h:83
List * permInfos
Definition: plannodes.h:120
CmdType commandType
Definition: plannodes.h:68
void PreventCommandIfReadOnly(const char *cmdname)
Definition: utility.c:404
void PreventCommandIfParallelMode(const char *cmdname)
Definition: utility.c:422
static const char * CreateCommandName(Node *parsetree)
Definition: utility.h:103

References ACL_SELECT, CMD_SELECT, PlannedStmt::commandType, CreateCommandName(), get_rel_namespace(), PlannedStmt::hasModifyingCTE, isTempNamespace(), lfirst_node, PlannedStmt::permInfos, PreventCommandIfParallelMode(), PreventCommandIfReadOnly(), RTEPermissionInfo::relid, and RTEPermissionInfo::requiredPerms.

Referenced by standard_ExecutorStart().

◆ ExecCloseRangeTableRelations()

void ExecCloseRangeTableRelations ( EState estate)

Definition at line 1635 of file execMain.c.

1636{
1637 int i;
1638
1639 for (i = 0; i < estate->es_range_table_size; i++)
1640 {
1641 if (estate->es_relations[i])
1642 table_close(estate->es_relations[i], NoLock);
1643 }
1644}
#define NoLock
Definition: lockdefs.h:34
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126

References EState::es_range_table_size, EState::es_relations, i, NoLock, and table_close().

Referenced by CopyFrom(), and ExecEndPlan().

◆ ExecCloseResultRelations()

void ExecCloseResultRelations ( EState estate)

Definition at line 1575 of file execMain.c.

1576{
1577 ListCell *l;
1578
1579 /*
1580 * close indexes of result relation(s) if any. (Rels themselves are
1581 * closed in ExecCloseRangeTableRelations())
1582 *
1583 * In addition, close the stub RTs that may be in each resultrel's
1584 * ri_ancestorResultRels.
1585 */
1586 foreach(l, estate->es_opened_result_relations)
1587 {
1588 ResultRelInfo *resultRelInfo = lfirst(l);
1589 ListCell *lc;
1590
1591 ExecCloseIndices(resultRelInfo);
1592 foreach(lc, resultRelInfo->ri_ancestorResultRels)
1593 {
1594 ResultRelInfo *rInfo = lfirst(lc);
1595
1596 /*
1597 * Ancestors with RTI > 0 (should only be the root ancestor) are
1598 * closed by ExecCloseRangeTableRelations.
1599 */
1600 if (rInfo->ri_RangeTableIndex > 0)
1601 continue;
1602
1604 }
1605 }
1606
1607 /* Close any relations that have been opened by ExecGetTriggerResultRel(). */
1608 foreach(l, estate->es_trig_target_relations)
1609 {
1610 ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
1611
1612 /*
1613 * Assert this is a "dummy" ResultRelInfo, see above. Otherwise we
1614 * might be issuing a duplicate close against a Relation opened by
1615 * ExecGetRangeTableRelation.
1616 */
1617 Assert(resultRelInfo->ri_RangeTableIndex == 0);
1618
1619 /*
1620 * Since ExecGetTriggerResultRel doesn't call ExecOpenIndices for
1621 * these rels, we needn't call ExecCloseIndices either.
1622 */
1623 Assert(resultRelInfo->ri_NumIndices == 0);
1624
1625 table_close(resultRelInfo->ri_RelationDesc, NoLock);
1626 }
1627}
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
Definition: execIndexing.c:238
List * es_trig_target_relations
Definition: execnodes.h:701
List * es_opened_result_relations
Definition: execnodes.h:688
int ri_NumIndices
Definition: execnodes.h:483
Index ri_RangeTableIndex
Definition: execnodes.h:477
List * ri_ancestorResultRels
Definition: execnodes.h:628

References Assert(), EState::es_opened_result_relations, EState::es_trig_target_relations, ExecCloseIndices(), lfirst, NoLock, ResultRelInfo::ri_ancestorResultRels, ResultRelInfo::ri_NumIndices, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_RelationDesc, and table_close().

Referenced by afterTriggerInvokeEvents(), CopyFrom(), EvalPlanQualEnd(), and ExecEndPlan().

◆ ExecConstraints()

void ExecConstraints ( ResultRelInfo resultRelInfo,
TupleTableSlot slot,
EState estate 
)

Definition at line 1980 of file execMain.c.

1982{
1983 Relation rel = resultRelInfo->ri_RelationDesc;
1984 TupleDesc tupdesc = RelationGetDescr(rel);
1985 TupleConstr *constr = tupdesc->constr;
1986 Bitmapset *modifiedCols;
1987 List *notnull_virtual_attrs = NIL;
1988
1989 Assert(constr); /* we should not be called otherwise */
1990
1991 /*
1992 * Verify not-null constraints.
1993 *
1994 * Not-null constraints on virtual generated columns are collected and
1995 * checked separately below.
1996 */
1997 if (constr->has_not_null)
1998 {
1999 for (AttrNumber attnum = 1; attnum <= tupdesc->natts; attnum++)
2000 {
2001 Form_pg_attribute att = TupleDescAttr(tupdesc, attnum - 1);
2002
2003 if (att->attnotnull && att->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
2004 notnull_virtual_attrs = lappend_int(notnull_virtual_attrs, attnum);
2005 else if (att->attnotnull && slot_attisnull(slot, attnum))
2006 ReportNotNullViolationError(resultRelInfo, slot, estate, attnum);
2007 }
2008 }
2009
2010 /*
2011 * Verify not-null constraints on virtual generated column, if any.
2012 */
2013 if (notnull_virtual_attrs)
2014 {
2016
2017 attnum = ExecRelGenVirtualNotNull(resultRelInfo, slot, estate,
2018 notnull_virtual_attrs);
2020 ReportNotNullViolationError(resultRelInfo, slot, estate, attnum);
2021 }
2022
2023 /*
2024 * Verify check constraints.
2025 */
2026 if (rel->rd_rel->relchecks > 0)
2027 {
2028 const char *failed;
2029
2030 if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL)
2031 {
2032 char *val_desc;
2033 Relation orig_rel = rel;
2034
2035 /*
2036 * If the tuple has been routed, it's been converted to the
2037 * partition's rowtype, which might differ from the root table's.
2038 * We must convert it back to the root table's rowtype so that
2039 * val_desc shown error message matches the input tuple.
2040 */
2041 if (resultRelInfo->ri_RootResultRelInfo)
2042 {
2043 ResultRelInfo *rootrel = resultRelInfo->ri_RootResultRelInfo;
2044 TupleDesc old_tupdesc = RelationGetDescr(rel);
2045 AttrMap *map;
2046
2047 tupdesc = RelationGetDescr(rootrel->ri_RelationDesc);
2048 /* a reverse map */
2049 map = build_attrmap_by_name_if_req(old_tupdesc,
2050 tupdesc,
2051 false);
2052
2053 /*
2054 * Partition-specific slot's tupdesc can't be changed, so
2055 * allocate a new one.
2056 */
2057 if (map != NULL)
2058 slot = execute_attr_map_slot(map, slot,
2060 modifiedCols = bms_union(ExecGetInsertedCols(rootrel, estate),
2061 ExecGetUpdatedCols(rootrel, estate));
2062 rel = rootrel->ri_RelationDesc;
2063 }
2064 else
2065 modifiedCols = bms_union(ExecGetInsertedCols(resultRelInfo, estate),
2066 ExecGetUpdatedCols(resultRelInfo, estate));
2068 slot,
2069 tupdesc,
2070 modifiedCols,
2071 64);
2072 ereport(ERROR,
2073 (errcode(ERRCODE_CHECK_VIOLATION),
2074 errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
2075 RelationGetRelationName(orig_rel), failed),
2076 val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
2077 errtableconstraint(orig_rel, failed)));
2078 }
2079 }
2080}
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:261
Bitmapset * bms_union(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:251
int errdetail(const char *fmt,...)
Definition: elog.c:1216
static void ReportNotNullViolationError(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, int attnum)
Definition: execMain.c:2159
char * ExecBuildSlotValueDescription(Oid reloid, TupleTableSlot *slot, TupleDesc tupdesc, Bitmapset *modifiedCols, int maxfieldlen)
Definition: execMain.c:2391
AttrNumber ExecRelGenVirtualNotNull(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, List *notnull_virtual_attrs)
Definition: execMain.c:2094
static const char * ExecRelCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:1778
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
TupleTableSlot * MakeTupleTableSlot(TupleDesc tupleDesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1301
Bitmapset * ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1361
Bitmapset * ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1382
List * lappend_int(List *list, int datum)
Definition: list.c:357
int16 attnum
Definition: pg_attribute.h:74
#define RelationGetRelid(relation)
Definition: rel.h:515
#define RelationGetDescr(relation)
Definition: rel.h:541
int errtableconstraint(Relation rel, const char *conname)
Definition: relcache.c:6103
Definition: attmap.h:35
Definition: pg_list.h:54
struct ResultRelInfo * ri_RootResultRelInfo
Definition: execnodes.h:618
bool has_not_null
Definition: tupdesc.h:45
TupleConstr * constr
Definition: tupdesc.h:141
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:193
static bool slot_attisnull(TupleTableSlot *slot, int attnum)
Definition: tuptable.h:384

References Assert(), attnum, bms_union(), build_attrmap_by_name_if_req(), TupleDescData::constr, ereport, errcode(), errdetail(), errmsg(), ERROR, errtableconstraint(), ExecBuildSlotValueDescription(), ExecGetInsertedCols(), ExecGetUpdatedCols(), ExecRelCheck(), ExecRelGenVirtualNotNull(), execute_attr_map_slot(), TupleConstr::has_not_null, InvalidAttrNumber, lappend_int(), MakeTupleTableSlot(), TupleDescData::natts, NIL, RelationData::rd_rel, RelationGetDescr, RelationGetRelationName, RelationGetRelid, ReportNotNullViolationError(), ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_RootResultRelInfo, slot_attisnull(), TTSOpsVirtual, and TupleDescAttr().

Referenced by CopyFrom(), ExecInsert(), ExecSimpleRelationInsert(), ExecSimpleRelationUpdate(), and ExecUpdateAct().

◆ ExecEndPlan()

static void ExecEndPlan ( PlanState planstate,
EState estate 
)
static

Definition at line 1536 of file execMain.c.

1537{
1538 ListCell *l;
1539
1540 /*
1541 * shut down the node-type-specific query processing
1542 */
1543 ExecEndNode(planstate);
1544
1545 /*
1546 * for subplans too
1547 */
1548 foreach(l, estate->es_subplanstates)
1549 {
1550 PlanState *subplanstate = (PlanState *) lfirst(l);
1551
1552 ExecEndNode(subplanstate);
1553 }
1554
1555 /*
1556 * destroy the executor's tuple table. Actually we only care about
1557 * releasing buffer pins and tupdesc refcounts; there's no need to pfree
1558 * the TupleTableSlots, since the containing memory context is about to go
1559 * away anyway.
1560 */
1561 ExecResetTupleTable(estate->es_tupleTable, false);
1562
1563 /*
1564 * Close any Relations that have been opened for range table entries or
1565 * result relations.
1566 */
1569}
void ExecCloseRangeTableRelations(EState *estate)
Definition: execMain.c:1635

References EState::es_subplanstates, EState::es_tupleTable, ExecCloseRangeTableRelations(), ExecCloseResultRelations(), ExecEndNode(), ExecResetTupleTable(), and lfirst.

Referenced by standard_ExecutorEnd().

◆ ExecFindRowMark()

ExecRowMark * ExecFindRowMark ( EState estate,
Index  rti,
bool  missing_ok 
)

Definition at line 2556 of file execMain.c.

2557{
2558 if (rti > 0 && rti <= estate->es_range_table_size &&
2559 estate->es_rowmarks != NULL)
2560 {
2561 ExecRowMark *erm = estate->es_rowmarks[rti - 1];
2562
2563 if (erm)
2564 return erm;
2565 }
2566 if (!missing_ok)
2567 elog(ERROR, "failed to find ExecRowMark for rangetable index %u", rti);
2568 return NULL;
2569}

References elog, ERROR, and EState::es_rowmarks.

Referenced by ExecInitLockRows(), and ExecInitModifyTable().

◆ ExecGetAncestorResultRels()

List * ExecGetAncestorResultRels ( EState estate,
ResultRelInfo resultRelInfo 
)

Definition at line 1430 of file execMain.c.

1431{
1432 ResultRelInfo *rootRelInfo = resultRelInfo->ri_RootResultRelInfo;
1433 Relation partRel = resultRelInfo->ri_RelationDesc;
1434 Oid rootRelOid;
1435
1436 if (!partRel->rd_rel->relispartition)
1437 elog(ERROR, "cannot find ancestors of a non-partition result relation");
1438 Assert(rootRelInfo != NULL);
1439 rootRelOid = RelationGetRelid(rootRelInfo->ri_RelationDesc);
1440 if (resultRelInfo->ri_ancestorResultRels == NIL)
1441 {
1442 ListCell *lc;
1444 List *ancResultRels = NIL;
1445
1446 foreach(lc, oids)
1447 {
1448 Oid ancOid = lfirst_oid(lc);
1449 Relation ancRel;
1450 ResultRelInfo *rInfo;
1451
1452 /*
1453 * Ignore the root ancestor here, and use ri_RootResultRelInfo
1454 * (below) for it instead. Also, we stop climbing up the
1455 * hierarchy when we find the table that was mentioned in the
1456 * query.
1457 */
1458 if (ancOid == rootRelOid)
1459 break;
1460
1461 /*
1462 * All ancestors up to the root target relation must have been
1463 * locked by the planner or AcquireExecutorLocks().
1464 */
1465 ancRel = table_open(ancOid, NoLock);
1466 rInfo = makeNode(ResultRelInfo);
1467
1468 /* dummy rangetable index */
1469 InitResultRelInfo(rInfo, ancRel, 0, NULL,
1470 estate->es_instrument);
1471 ancResultRels = lappend(ancResultRels, rInfo);
1472 }
1473 ancResultRels = lappend(ancResultRels, rootRelInfo);
1474 resultRelInfo->ri_ancestorResultRels = ancResultRels;
1475 }
1476
1477 /* We must have found some ancestor */
1478 Assert(resultRelInfo->ri_ancestorResultRels != NIL);
1479
1480 return resultRelInfo->ri_ancestorResultRels;
1481}
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition: execMain.c:1243
#define makeNode(_type_)
Definition: nodes.h:161
List * get_partition_ancestors(Oid relid)
Definition: partition.c:134
#define lfirst_oid(lc)
Definition: pg_list.h:174
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References Assert(), elog, ERROR, EState::es_instrument, get_partition_ancestors(), InitResultRelInfo(), lappend(), lfirst_oid, makeNode, NIL, NoLock, RelationData::rd_rel, RelationGetRelid, ResultRelInfo::ri_ancestorResultRels, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_RootResultRelInfo, and table_open().

Referenced by ExecCrossPartitionUpdateForeignKey().

◆ ExecGetTriggerResultRel()

ResultRelInfo * ExecGetTriggerResultRel ( EState estate,
Oid  relid,
ResultRelInfo rootRelInfo 
)

Definition at line 1343 of file execMain.c.

1345{
1346 ResultRelInfo *rInfo;
1347 ListCell *l;
1348 Relation rel;
1349 MemoryContext oldcontext;
1350
1351 /*
1352 * Before creating a new ResultRelInfo, check if we've already made and
1353 * cached one for this relation. We must ensure that the given
1354 * 'rootRelInfo' matches the one stored in the cached ResultRelInfo as
1355 * trigger handling for partitions can result in mixed requirements for
1356 * what ri_RootResultRelInfo is set to.
1357 */
1358
1359 /* Search through the query result relations */
1360 foreach(l, estate->es_opened_result_relations)
1361 {
1362 rInfo = lfirst(l);
1363 if (RelationGetRelid(rInfo->ri_RelationDesc) == relid &&
1364 rInfo->ri_RootResultRelInfo == rootRelInfo)
1365 return rInfo;
1366 }
1367
1368 /*
1369 * Search through the result relations that were created during tuple
1370 * routing, if any.
1371 */
1372 foreach(l, estate->es_tuple_routing_result_relations)
1373 {
1374 rInfo = (ResultRelInfo *) lfirst(l);
1375 if (RelationGetRelid(rInfo->ri_RelationDesc) == relid &&
1376 rInfo->ri_RootResultRelInfo == rootRelInfo)
1377 return rInfo;
1378 }
1379
1380 /* Nope, but maybe we already made an extra ResultRelInfo for it */
1381 foreach(l, estate->es_trig_target_relations)
1382 {
1383 rInfo = (ResultRelInfo *) lfirst(l);
1384 if (RelationGetRelid(rInfo->ri_RelationDesc) == relid &&
1385 rInfo->ri_RootResultRelInfo == rootRelInfo)
1386 return rInfo;
1387 }
1388 /* Nope, so we need a new one */
1389
1390 /*
1391 * Open the target relation's relcache entry. We assume that an
1392 * appropriate lock is still held by the backend from whenever the trigger
1393 * event got queued, so we need take no new lock here. Also, we need not
1394 * recheck the relkind, so no need for CheckValidResultRel.
1395 */
1396 rel = table_open(relid, NoLock);
1397
1398 /*
1399 * Make the new entry in the right context.
1400 */
1401 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1402 rInfo = makeNode(ResultRelInfo);
1403 InitResultRelInfo(rInfo,
1404 rel,
1405 0, /* dummy rangetable index */
1406 rootRelInfo,
1407 estate->es_instrument);
1408 estate->es_trig_target_relations =
1409 lappend(estate->es_trig_target_relations, rInfo);
1410 MemoryContextSwitchTo(oldcontext);
1411
1412 /*
1413 * Currently, we don't need any index information in ResultRelInfos used
1414 * only for triggers, so no need to call ExecOpenIndices.
1415 */
1416
1417 return rInfo;
1418}
List * es_tuple_routing_result_relations
Definition: execnodes.h:698

References EState::es_instrument, EState::es_opened_result_relations, EState::es_query_cxt, EState::es_trig_target_relations, EState::es_tuple_routing_result_relations, InitResultRelInfo(), lappend(), lfirst, makeNode, MemoryContextSwitchTo(), NoLock, RelationGetRelid, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_RootResultRelInfo, and table_open().

Referenced by afterTriggerInvokeEvents().

◆ ExecPartitionCheck()

bool ExecPartitionCheck ( ResultRelInfo resultRelInfo,
TupleTableSlot slot,
EState estate,
bool  emitError 
)

Definition at line 1856 of file execMain.c.

1858{
1859 ExprContext *econtext;
1860 bool success;
1861
1862 /*
1863 * If first time through, build expression state tree for the partition
1864 * check expression. (In the corner case where the partition check
1865 * expression is empty, ie there's a default partition and nothing else,
1866 * we'll be fooled into executing this code each time through. But it's
1867 * pretty darn cheap in that case, so we don't worry about it.)
1868 */
1869 if (resultRelInfo->ri_PartitionCheckExpr == NULL)
1870 {
1871 /*
1872 * Ensure that the qual tree and prepared expression are in the
1873 * query-lifespan context.
1874 */
1876 List *qual = RelationGetPartitionQual(resultRelInfo->ri_RelationDesc);
1877
1878 resultRelInfo->ri_PartitionCheckExpr = ExecPrepareCheck(qual, estate);
1879 MemoryContextSwitchTo(oldcxt);
1880 }
1881
1882 /*
1883 * We will use the EState's per-tuple context for evaluating constraint
1884 * expressions (creating it if it's not already there).
1885 */
1886 econtext = GetPerTupleExprContext(estate);
1887
1888 /* Arrange for econtext's scan tuple to be the tuple under test */
1889 econtext->ecxt_scantuple = slot;
1890
1891 /*
1892 * As in case of the cataloged constraints, we treat a NULL result as
1893 * success here, not a failure.
1894 */
1895 success = ExecCheck(resultRelInfo->ri_PartitionCheckExpr, econtext);
1896
1897 /* if asked to emit error, don't actually return on failure */
1898 if (!success && emitError)
1899 ExecPartitionCheckEmitError(resultRelInfo, slot, estate);
1900
1901 return success;
1902}
bool ExecCheck(ExprState *state, ExprContext *econtext)
Definition: execExpr.c:872
ExprState * ExecPrepareCheck(List *qual, EState *estate)
Definition: execExpr.c:816
void ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition: execMain.c:1909
static bool success
Definition: initdb.c:187
List * RelationGetPartitionQual(Relation rel)
Definition: partcache.c:277
TupleTableSlot * ecxt_scantuple
Definition: execnodes.h:273
ExprState * ri_PartitionCheckExpr
Definition: execnodes.h:592

References ExprContext::ecxt_scantuple, EState::es_query_cxt, ExecCheck(), ExecPartitionCheckEmitError(), ExecPrepareCheck(), GetPerTupleExprContext, MemoryContextSwitchTo(), RelationGetPartitionQual(), ResultRelInfo::ri_PartitionCheckExpr, ResultRelInfo::ri_RelationDesc, and success.

Referenced by apply_handle_tuple_routing(), CopyFrom(), ExecBRInsertTriggers(), ExecFindPartition(), ExecInsert(), ExecSimpleRelationInsert(), ExecSimpleRelationUpdate(), and ExecUpdateAct().

◆ ExecPartitionCheckEmitError()

void ExecPartitionCheckEmitError ( ResultRelInfo resultRelInfo,
TupleTableSlot slot,
EState estate 
)

Definition at line 1909 of file execMain.c.

1912{
1913 Oid root_relid;
1914 TupleDesc tupdesc;
1915 char *val_desc;
1916 Bitmapset *modifiedCols;
1917
1918 /*
1919 * If the tuple has been routed, it's been converted to the partition's
1920 * rowtype, which might differ from the root table's. We must convert it
1921 * back to the root table's rowtype so that val_desc in the error message
1922 * matches the input tuple.
1923 */
1924 if (resultRelInfo->ri_RootResultRelInfo)
1925 {
1926 ResultRelInfo *rootrel = resultRelInfo->ri_RootResultRelInfo;
1927 TupleDesc old_tupdesc;
1928 AttrMap *map;
1929
1930 root_relid = RelationGetRelid(rootrel->ri_RelationDesc);
1931 tupdesc = RelationGetDescr(rootrel->ri_RelationDesc);
1932
1933 old_tupdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
1934 /* a reverse map */
1935 map = build_attrmap_by_name_if_req(old_tupdesc, tupdesc, false);
1936
1937 /*
1938 * Partition-specific slot's tupdesc can't be changed, so allocate a
1939 * new one.
1940 */
1941 if (map != NULL)
1942 slot = execute_attr_map_slot(map, slot,
1944 modifiedCols = bms_union(ExecGetInsertedCols(rootrel, estate),
1945 ExecGetUpdatedCols(rootrel, estate));
1946 }
1947 else
1948 {
1949 root_relid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
1950 tupdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
1951 modifiedCols = bms_union(ExecGetInsertedCols(resultRelInfo, estate),
1952 ExecGetUpdatedCols(resultRelInfo, estate));
1953 }
1954
1955 val_desc = ExecBuildSlotValueDescription(root_relid,
1956 slot,
1957 tupdesc,
1958 modifiedCols,
1959 64);
1960 ereport(ERROR,
1961 (errcode(ERRCODE_CHECK_VIOLATION),
1962 errmsg("new row for relation \"%s\" violates partition constraint",
1964 val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
1965 errtable(resultRelInfo->ri_RelationDesc)));
1966}
int errtable(Relation rel)
Definition: relcache.c:6049

References bms_union(), build_attrmap_by_name_if_req(), ereport, errcode(), errdetail(), errmsg(), ERROR, errtable(), ExecBuildSlotValueDescription(), ExecGetInsertedCols(), ExecGetUpdatedCols(), execute_attr_map_slot(), MakeTupleTableSlot(), RelationGetDescr, RelationGetRelationName, RelationGetRelid, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_RootResultRelInfo, and TTSOpsVirtual.

Referenced by ExecCrossPartitionUpdate(), and ExecPartitionCheck().

◆ ExecPostprocessPlan()

static void ExecPostprocessPlan ( EState estate)
static

Definition at line 1490 of file execMain.c.

1491{
1492 ListCell *lc;
1493
1494 /*
1495 * Make sure nodes run forward.
1496 */
1498
1499 /*
1500 * Run any secondary ModifyTable nodes to completion, in case the main
1501 * query did not fetch all rows from them. (We do this to ensure that
1502 * such nodes have predictable results.)
1503 */
1504 foreach(lc, estate->es_auxmodifytables)
1505 {
1506 PlanState *ps = (PlanState *) lfirst(lc);
1507
1508 for (;;)
1509 {
1510 TupleTableSlot *slot;
1511
1512 /* Reset the per-output-tuple exprcontext each time */
1514
1515 slot = ExecProcNode(ps);
1516
1517 if (TupIsNull(slot))
1518 break;
1519 }
1520 }
1521}
#define ResetPerTupleExprContext(estate)
Definition: executor.h:665
struct parser_state ps
List * es_auxmodifytables
Definition: execnodes.h:727

References EState::es_auxmodifytables, EState::es_direction, ExecProcNode(), ForwardScanDirection, lfirst, ps, ResetPerTupleExprContext, and TupIsNull.

Referenced by standard_ExecutorFinish().

◆ ExecRelCheck()

static const char * ExecRelCheck ( ResultRelInfo resultRelInfo,
TupleTableSlot slot,
EState estate 
)
static

Definition at line 1778 of file execMain.c.

1780{
1781 Relation rel = resultRelInfo->ri_RelationDesc;
1782 int ncheck = rel->rd_att->constr->num_check;
1783 ConstrCheck *check = rel->rd_att->constr->check;
1784 ExprContext *econtext;
1785 MemoryContext oldContext;
1786
1787 /*
1788 * CheckNNConstraintFetch let this pass with only a warning, but now we
1789 * should fail rather than possibly failing to enforce an important
1790 * constraint.
1791 */
1792 if (ncheck != rel->rd_rel->relchecks)
1793 elog(ERROR, "%d pg_constraint record(s) missing for relation \"%s\"",
1794 rel->rd_rel->relchecks - ncheck, RelationGetRelationName(rel));
1795
1796 /*
1797 * If first time through for this result relation, build expression
1798 * nodetrees for rel's constraint expressions. Keep them in the per-query
1799 * memory context so they'll survive throughout the query.
1800 */
1801 if (resultRelInfo->ri_CheckConstraintExprs == NULL)
1802 {
1803 oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
1804 resultRelInfo->ri_CheckConstraintExprs = palloc0_array(ExprState *, ncheck);
1805 for (int i = 0; i < ncheck; i++)
1806 {
1807 Expr *checkconstr;
1808
1809 /* Skip not enforced constraint */
1810 if (!check[i].ccenforced)
1811 continue;
1812
1813 checkconstr = stringToNode(check[i].ccbin);
1814 checkconstr = (Expr *) expand_generated_columns_in_expr((Node *) checkconstr, rel, 1);
1815 resultRelInfo->ri_CheckConstraintExprs[i] =
1816 ExecPrepareExpr(checkconstr, estate);
1817 }
1818 MemoryContextSwitchTo(oldContext);
1819 }
1820
1821 /*
1822 * We will use the EState's per-tuple context for evaluating constraint
1823 * expressions (creating it if it's not already there).
1824 */
1825 econtext = GetPerTupleExprContext(estate);
1826
1827 /* Arrange for econtext's scan tuple to be the tuple under test */
1828 econtext->ecxt_scantuple = slot;
1829
1830 /* And evaluate the constraints */
1831 for (int i = 0; i < ncheck; i++)
1832 {
1833 ExprState *checkconstr = resultRelInfo->ri_CheckConstraintExprs[i];
1834
1835 /*
1836 * NOTE: SQL specifies that a NULL result from a constraint expression
1837 * is not to be treated as a failure. Therefore, use ExecCheck not
1838 * ExecQual.
1839 */
1840 if (checkconstr && !ExecCheck(checkconstr, econtext))
1841 return check[i].ccname;
1842 }
1843
1844 /* NULL result means no error */
1845 return NULL;
1846}
ExprState * ExecPrepareExpr(Expr *node, EState *estate)
Definition: execExpr.c:765
void * stringToNode(const char *str)
Definition: read.c:90
Node * expand_generated_columns_in_expr(Node *node, Relation rel, int rt_index)
char * ccname
Definition: tupdesc.h:30
TupleDesc rd_att
Definition: rel.h:112
ExprState ** ri_CheckConstraintExprs
Definition: execnodes.h:555
ConstrCheck * check
Definition: tupdesc.h:41
uint16 num_check
Definition: tupdesc.h:44

References ConstrCheck::ccname, TupleConstr::check, TupleDescData::constr, ExprContext::ecxt_scantuple, elog, ERROR, EState::es_query_cxt, ExecCheck(), ExecPrepareExpr(), expand_generated_columns_in_expr(), GetPerTupleExprContext, i, MemoryContextSwitchTo(), TupleConstr::num_check, palloc0_array, RelationData::rd_att, RelationData::rd_rel, RelationGetRelationName, ResultRelInfo::ri_CheckConstraintExprs, ResultRelInfo::ri_RelationDesc, and stringToNode().

Referenced by ExecConstraints().

◆ ExecRelGenVirtualNotNull()

AttrNumber ExecRelGenVirtualNotNull ( ResultRelInfo resultRelInfo,
TupleTableSlot slot,
EState estate,
List notnull_virtual_attrs 
)

Definition at line 2094 of file execMain.c.

2096{
2097 Relation rel = resultRelInfo->ri_RelationDesc;
2098 ExprContext *econtext;
2099 MemoryContext oldContext;
2100
2101 /*
2102 * We implement this by building a NullTest node for each virtual
2103 * generated column, which we cache in resultRelInfo, and running those
2104 * through ExecCheck().
2105 */
2106 if (resultRelInfo->ri_GenVirtualNotNullConstraintExprs == NULL)
2107 {
2108 oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
2110 palloc0_array(ExprState *, list_length(notnull_virtual_attrs));
2111
2112 foreach_int(attnum, notnull_virtual_attrs)
2113 {
2115 NullTest *nnulltest;
2116
2117 /* "generated_expression IS NOT NULL" check. */
2118 nnulltest = makeNode(NullTest);
2119 nnulltest->arg = (Expr *) build_generation_expression(rel, attnum);
2120 nnulltest->nulltesttype = IS_NOT_NULL;
2121 nnulltest->argisrow = false;
2122 nnulltest->location = -1;
2123
2124 resultRelInfo->ri_GenVirtualNotNullConstraintExprs[i] =
2125 ExecPrepareExpr((Expr *) nnulltest, estate);
2126 }
2127 MemoryContextSwitchTo(oldContext);
2128 }
2129
2130 /*
2131 * We will use the EState's per-tuple context for evaluating virtual
2132 * generated column not null constraint expressions (creating it if it's
2133 * not already there).
2134 */
2135 econtext = GetPerTupleExprContext(estate);
2136
2137 /* Arrange for econtext's scan tuple to be the tuple under test */
2138 econtext->ecxt_scantuple = slot;
2139
2140 /* And evaluate the check constraints for virtual generated column */
2141 foreach_int(attnum, notnull_virtual_attrs)
2142 {
2144 ExprState *exprstate = resultRelInfo->ri_GenVirtualNotNullConstraintExprs[i];
2145
2146 Assert(exprstate != NULL);
2147 if (!ExecCheck(exprstate, econtext))
2148 return attnum;
2149 }
2150
2151 /* InvalidAttrNumber result means no error */
2152 return InvalidAttrNumber;
2153}
#define foreach_current_index(var_or_cell)
Definition: pg_list.h:403
#define foreach_int(var, lst)
Definition: pg_list.h:470
@ IS_NOT_NULL
Definition: primnodes.h:1977
Node * build_generation_expression(Relation rel, int attrno)
NullTestType nulltesttype
Definition: primnodes.h:1984
ParseLoc location
Definition: primnodes.h:1987
Expr * arg
Definition: primnodes.h:1983
ExprState ** ri_GenVirtualNotNullConstraintExprs
Definition: execnodes.h:561

References NullTest::arg, Assert(), attnum, build_generation_expression(), ExprContext::ecxt_scantuple, EState::es_query_cxt, ExecCheck(), ExecPrepareExpr(), foreach_current_index, foreach_int, GetPerTupleExprContext, i, InvalidAttrNumber, IS_NOT_NULL, list_length(), NullTest::location, makeNode, MemoryContextSwitchTo(), NullTest::nulltesttype, palloc0_array, ResultRelInfo::ri_GenVirtualNotNullConstraintExprs, and ResultRelInfo::ri_RelationDesc.

Referenced by ATRewriteTable(), and ExecConstraints().

◆ ExecUpdateLockMode()

LockTupleMode ExecUpdateLockMode ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2530 of file execMain.c.

2531{
2532 Bitmapset *keyCols;
2533 Bitmapset *updatedCols;
2534
2535 /*
2536 * Compute lock mode to use. If columns that are part of the key have not
2537 * been modified, then we can use a weaker lock, allowing for better
2538 * concurrency.
2539 */
2540 updatedCols = ExecGetAllUpdatedCols(relinfo, estate);
2543
2544 if (bms_overlap(keyCols, updatedCols))
2545 return LockTupleExclusive;
2546
2548}
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:582
Bitmapset * ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition: execUtils.c:1418
@ LockTupleExclusive
Definition: lockoptions.h:58
@ LockTupleNoKeyExclusive
Definition: lockoptions.h:56
Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Definition: relcache.c:5303
@ INDEX_ATTR_BITMAP_KEY
Definition: relcache.h:69

References bms_overlap(), ExecGetAllUpdatedCols(), INDEX_ATTR_BITMAP_KEY, LockTupleExclusive, LockTupleNoKeyExclusive, RelationGetIndexAttrBitmap(), and ResultRelInfo::ri_RelationDesc.

Referenced by ExecBRUpdateTriggers(), ExecMergeMatched(), and ExecOnConflictUpdate().

◆ ExecutePlan()

static void ExecutePlan ( QueryDesc queryDesc,
CmdType  operation,
bool  sendTuples,
uint64  numberTuples,
ScanDirection  direction,
DestReceiver dest 
)
static

Definition at line 1656 of file execMain.c.

1662{
1663 EState *estate = queryDesc->estate;
1664 PlanState *planstate = queryDesc->planstate;
1665 bool use_parallel_mode;
1666 TupleTableSlot *slot;
1667 uint64 current_tuple_count;
1668
1669 /*
1670 * initialize local variables
1671 */
1672 current_tuple_count = 0;
1673
1674 /*
1675 * Set the direction.
1676 */
1677 estate->es_direction = direction;
1678
1679 /*
1680 * Set up parallel mode if appropriate.
1681 *
1682 * Parallel mode only supports complete execution of a plan. If we've
1683 * already partially executed it, or if the caller asks us to exit early,
1684 * we must force the plan to run without parallelism.
1685 */
1686 if (queryDesc->already_executed || numberTuples != 0)
1687 use_parallel_mode = false;
1688 else
1689 use_parallel_mode = queryDesc->plannedstmt->parallelModeNeeded;
1690 queryDesc->already_executed = true;
1691
1692 estate->es_use_parallel_mode = use_parallel_mode;
1693 if (use_parallel_mode)
1695
1696 /*
1697 * Loop until we've processed the proper number of tuples from the plan.
1698 */
1699 for (;;)
1700 {
1701 /* Reset the per-output-tuple exprcontext */
1703
1704 /*
1705 * Execute the plan and obtain a tuple
1706 */
1707 slot = ExecProcNode(planstate);
1708
1709 /*
1710 * if the tuple is null, then we assume there is nothing more to
1711 * process so we just end the loop...
1712 */
1713 if (TupIsNull(slot))
1714 break;
1715
1716 /*
1717 * If we have a junk filter, then project a new tuple with the junk
1718 * removed.
1719 *
1720 * Store this new "clean" tuple in the junkfilter's resultSlot.
1721 * (Formerly, we stored it back over the "dirty" tuple, which is WRONG
1722 * because that tuple slot has the wrong descriptor.)
1723 */
1724 if (estate->es_junkFilter != NULL)
1725 slot = ExecFilterJunk(estate->es_junkFilter, slot);
1726
1727 /*
1728 * If we are supposed to send the tuple somewhere, do so. (In
1729 * practice, this is probably always the case at this point.)
1730 */
1731 if (sendTuples)
1732 {
1733 /*
1734 * If we are not able to send the tuple, we assume the destination
1735 * has closed and no more tuples can be sent. If that's the case,
1736 * end the loop.
1737 */
1738 if (!dest->receiveSlot(slot, dest))
1739 break;
1740 }
1741
1742 /*
1743 * Count tuples processed, if this is a SELECT. (For other operation
1744 * types, the ModifyTable plan node must count the appropriate
1745 * events.)
1746 */
1747 if (operation == CMD_SELECT)
1748 (estate->es_processed)++;
1749
1750 /*
1751 * check our tuple count.. if we've processed the proper number then
1752 * quit, else loop again and process more tuples. Zero numberTuples
1753 * means no limit.
1754 */
1755 current_tuple_count++;
1756 if (numberTuples && numberTuples == current_tuple_count)
1757 break;
1758 }
1759
1760 /*
1761 * If we know we won't need to back up, we can release resources at this
1762 * point.
1763 */
1764 if (!(estate->es_top_eflags & EXEC_FLAG_BACKWARD))
1765 ExecShutdownNode(planstate);
1766
1767 if (use_parallel_mode)
1769}
uint64_t uint64
Definition: c.h:543
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition: execJunk.c:247
void ExecShutdownNode(PlanState *node)
Definition: execProcnode.c:772
#define EXEC_FLAG_BACKWARD
Definition: executor.h:69
uint64 es_processed
Definition: execnodes.h:714
bool es_use_parallel_mode
Definition: execnodes.h:744
bool parallelModeNeeded
Definition: plannodes.h:95
EState * estate
Definition: execdesc.h:48
bool already_executed
Definition: execdesc.h:52
PlannedStmt * plannedstmt
Definition: execdesc.h:37
PlanState * planstate
Definition: execdesc.h:49
void ExitParallelMode(void)
Definition: xact.c:1064
void EnterParallelMode(void)
Definition: xact.c:1051

References QueryDesc::already_executed, CMD_SELECT, generate_unaccent_rules::dest, EnterParallelMode(), EState::es_direction, EState::es_junkFilter, EState::es_processed, EState::es_top_eflags, EState::es_use_parallel_mode, QueryDesc::estate, EXEC_FLAG_BACKWARD, ExecFilterJunk(), ExecProcNode(), ExecShutdownNode(), ExitParallelMode(), PlannedStmt::parallelModeNeeded, QueryDesc::plannedstmt, QueryDesc::planstate, ResetPerTupleExprContext, and TupIsNull.

Referenced by standard_ExecutorRun().

◆ ExecutorEnd()

void ExecutorEnd ( QueryDesc queryDesc)

Definition at line 466 of file execMain.c.

467{
469 (*ExecutorEnd_hook) (queryDesc);
470 else
471 standard_ExecutorEnd(queryDesc);
472}
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:71
void standard_ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:475

References ExecutorEnd_hook, and standard_ExecutorEnd().

Referenced by _SPI_pquery(), EndCopyTo(), ExecCreateTableAs(), execute_sql_string(), ExplainOnePlan(), ParallelQueryMain(), PersistHoldablePortal(), PortalCleanup(), postquel_end(), ProcessQuery(), and refresh_matview_datafill().

◆ ExecutorFinish()

void ExecutorFinish ( QueryDesc queryDesc)

Definition at line 406 of file execMain.c.

407{
409 (*ExecutorFinish_hook) (queryDesc);
410 else
411 standard_ExecutorFinish(queryDesc);
412}
ExecutorFinish_hook_type ExecutorFinish_hook
Definition: execMain.c:70
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:415

References ExecutorFinish_hook, and standard_ExecutorFinish().

Referenced by _SPI_pquery(), EndCopyTo(), ExecCreateTableAs(), execute_sql_string(), ExplainOnePlan(), ParallelQueryMain(), PersistHoldablePortal(), PortalCleanup(), postquel_end(), ProcessQuery(), and refresh_matview_datafill().

◆ ExecutorRewind()

void ExecutorRewind ( QueryDesc queryDesc)

Definition at line 536 of file execMain.c.

537{
538 EState *estate;
539 MemoryContext oldcontext;
540
541 /* sanity checks */
542 Assert(queryDesc != NULL);
543
544 estate = queryDesc->estate;
545
546 Assert(estate != NULL);
547
548 /* It's probably not sensible to rescan updating queries */
549 Assert(queryDesc->operation == CMD_SELECT);
550
551 /*
552 * Switch into per-query memory context
553 */
554 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
555
556 /*
557 * rescan plan
558 */
559 ExecReScan(queryDesc->planstate);
560
561 MemoryContextSwitchTo(oldcontext);
562}
void ExecReScan(PlanState *node)
Definition: execAmi.c:77
CmdType operation
Definition: execdesc.h:36

References Assert(), CMD_SELECT, EState::es_query_cxt, QueryDesc::estate, ExecReScan(), MemoryContextSwitchTo(), QueryDesc::operation, and QueryDesc::planstate.

Referenced by DoPortalRewind(), and PersistHoldablePortal().

◆ ExecutorRun()

void ExecutorRun ( QueryDesc queryDesc,
ScanDirection  direction,
uint64  count 
)

Definition at line 297 of file execMain.c.

299{
301 (*ExecutorRun_hook) (queryDesc, direction, count);
302 else
303 standard_ExecutorRun(queryDesc, direction, count);
304}
ExecutorRun_hook_type ExecutorRun_hook
Definition: execMain.c:69
void standard_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
Definition: execMain.c:307

References ExecutorRun_hook, and standard_ExecutorRun().

Referenced by _SPI_pquery(), DoCopyTo(), ExecCreateTableAs(), execute_sql_string(), ExplainOnePlan(), ParallelQueryMain(), PersistHoldablePortal(), PortalRunSelect(), postquel_getnext(), ProcessQuery(), and refresh_matview_datafill().

◆ ExecutorStart()

void ExecutorStart ( QueryDesc queryDesc,
int  eflags 
)

Definition at line 122 of file execMain.c.

123{
124 /*
125 * In some cases (e.g. an EXECUTE statement or an execute message with the
126 * extended query protocol) the query_id won't be reported, so do it now.
127 *
128 * Note that it's harmless to report the query_id multiple times, as the
129 * call will be ignored if the top level query_id has already been
130 * reported.
131 */
132 pgstat_report_query_id(queryDesc->plannedstmt->queryId, false);
133
135 (*ExecutorStart_hook) (queryDesc, eflags);
136 else
137 standard_ExecutorStart(queryDesc, eflags);
138}
void pgstat_report_query_id(int64 query_id, bool force)
ExecutorStart_hook_type ExecutorStart_hook
Definition: execMain.c:68
void standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:141
int64 queryId
Definition: plannodes.h:71

References ExecutorStart_hook, pgstat_report_query_id(), QueryDesc::plannedstmt, PlannedStmt::queryId, and standard_ExecutorStart().

Referenced by _SPI_pquery(), BeginCopyTo(), ExecCreateTableAs(), execute_sql_string(), ExplainOnePlan(), ParallelQueryMain(), PortalStart(), postquel_start(), ProcessQuery(), and refresh_matview_datafill().

◆ ExecWithCheckOptions()

void ExecWithCheckOptions ( WCOKind  kind,
ResultRelInfo resultRelInfo,
TupleTableSlot slot,
EState estate 
)

Definition at line 2228 of file execMain.c.

2230{
2231 Relation rel = resultRelInfo->ri_RelationDesc;
2232 TupleDesc tupdesc = RelationGetDescr(rel);
2233 ExprContext *econtext;
2234 ListCell *l1,
2235 *l2;
2236
2237 /*
2238 * We will use the EState's per-tuple context for evaluating constraint
2239 * expressions (creating it if it's not already there).
2240 */
2241 econtext = GetPerTupleExprContext(estate);
2242
2243 /* Arrange for econtext's scan tuple to be the tuple under test */
2244 econtext->ecxt_scantuple = slot;
2245
2246 /* Check each of the constraints */
2247 forboth(l1, resultRelInfo->ri_WithCheckOptions,
2248 l2, resultRelInfo->ri_WithCheckOptionExprs)
2249 {
2250 WithCheckOption *wco = (WithCheckOption *) lfirst(l1);
2251 ExprState *wcoExpr = (ExprState *) lfirst(l2);
2252
2253 /*
2254 * Skip any WCOs which are not the kind we are looking for at this
2255 * time.
2256 */
2257 if (wco->kind != kind)
2258 continue;
2259
2260 /*
2261 * WITH CHECK OPTION checks are intended to ensure that the new tuple
2262 * is visible (in the case of a view) or that it passes the
2263 * 'with-check' policy (in the case of row security). If the qual
2264 * evaluates to NULL or FALSE, then the new tuple won't be included in
2265 * the view or doesn't pass the 'with-check' policy for the table.
2266 */
2267 if (!ExecQual(wcoExpr, econtext))
2268 {
2269 char *val_desc;
2270 Bitmapset *modifiedCols;
2271
2272 switch (wco->kind)
2273 {
2274 /*
2275 * For WITH CHECK OPTIONs coming from views, we might be
2276 * able to provide the details on the row, depending on
2277 * the permissions on the relation (that is, if the user
2278 * could view it directly anyway). For RLS violations, we
2279 * don't include the data since we don't know if the user
2280 * should be able to view the tuple as that depends on the
2281 * USING policy.
2282 */
2283 case WCO_VIEW_CHECK:
2284 /* See the comment in ExecConstraints(). */
2285 if (resultRelInfo->ri_RootResultRelInfo)
2286 {
2287 ResultRelInfo *rootrel = resultRelInfo->ri_RootResultRelInfo;
2288 TupleDesc old_tupdesc = RelationGetDescr(rel);
2289 AttrMap *map;
2290
2291 tupdesc = RelationGetDescr(rootrel->ri_RelationDesc);
2292 /* a reverse map */
2293 map = build_attrmap_by_name_if_req(old_tupdesc,
2294 tupdesc,
2295 false);
2296
2297 /*
2298 * Partition-specific slot's tupdesc can't be changed,
2299 * so allocate a new one.
2300 */
2301 if (map != NULL)
2302 slot = execute_attr_map_slot(map, slot,
2304
2305 modifiedCols = bms_union(ExecGetInsertedCols(rootrel, estate),
2306 ExecGetUpdatedCols(rootrel, estate));
2307 rel = rootrel->ri_RelationDesc;
2308 }
2309 else
2310 modifiedCols = bms_union(ExecGetInsertedCols(resultRelInfo, estate),
2311 ExecGetUpdatedCols(resultRelInfo, estate));
2313 slot,
2314 tupdesc,
2315 modifiedCols,
2316 64);
2317
2318 ereport(ERROR,
2319 (errcode(ERRCODE_WITH_CHECK_OPTION_VIOLATION),
2320 errmsg("new row violates check option for view \"%s\"",
2321 wco->relname),
2322 val_desc ? errdetail("Failing row contains %s.",
2323 val_desc) : 0));
2324 break;
2327 if (wco->polname != NULL)
2328 ereport(ERROR,
2329 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2330 errmsg("new row violates row-level security policy \"%s\" for table \"%s\"",
2331 wco->polname, wco->relname)));
2332 else
2333 ereport(ERROR,
2334 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2335 errmsg("new row violates row-level security policy for table \"%s\"",
2336 wco->relname)));
2337 break;
2340 if (wco->polname != NULL)
2341 ereport(ERROR,
2342 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2343 errmsg("target row violates row-level security policy \"%s\" (USING expression) for table \"%s\"",
2344 wco->polname, wco->relname)));
2345 else
2346 ereport(ERROR,
2347 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2348 errmsg("target row violates row-level security policy (USING expression) for table \"%s\"",
2349 wco->relname)));
2350 break;
2352 if (wco->polname != NULL)
2353 ereport(ERROR,
2354 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2355 errmsg("new row violates row-level security policy \"%s\" (USING expression) for table \"%s\"",
2356 wco->polname, wco->relname)));
2357 else
2358 ereport(ERROR,
2359 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2360 errmsg("new row violates row-level security policy (USING expression) for table \"%s\"",
2361 wco->relname)));
2362 break;
2363 default:
2364 elog(ERROR, "unrecognized WCO kind: %u", wco->kind);
2365 break;
2366 }
2367 }
2368 }
2369}
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition: executor.h:519
@ WCO_RLS_MERGE_UPDATE_CHECK
Definition: parsenodes.h:1394
@ WCO_RLS_CONFLICT_CHECK
Definition: parsenodes.h:1393
@ WCO_RLS_INSERT_CHECK
Definition: parsenodes.h:1391
@ WCO_VIEW_CHECK
Definition: parsenodes.h:1390
@ WCO_RLS_UPDATE_CHECK
Definition: parsenodes.h:1392
@ WCO_RLS_MERGE_DELETE_CHECK
Definition: parsenodes.h:1395
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
List * ri_WithCheckOptions
Definition: execnodes.h:549
List * ri_WithCheckOptionExprs
Definition: execnodes.h:552

References bms_union(), build_attrmap_by_name_if_req(), ExprContext::ecxt_scantuple, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, ExecBuildSlotValueDescription(), ExecGetInsertedCols(), ExecGetUpdatedCols(), ExecQual(), execute_attr_map_slot(), forboth, GetPerTupleExprContext, WithCheckOption::kind, lfirst, MakeTupleTableSlot(), WithCheckOption::polname, RelationGetDescr, RelationGetRelid, WithCheckOption::relname, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_RootResultRelInfo, ResultRelInfo::ri_WithCheckOptionExprs, ResultRelInfo::ri_WithCheckOptions, TTSOpsVirtual, WCO_RLS_CONFLICT_CHECK, WCO_RLS_INSERT_CHECK, WCO_RLS_MERGE_DELETE_CHECK, WCO_RLS_MERGE_UPDATE_CHECK, WCO_RLS_UPDATE_CHECK, and WCO_VIEW_CHECK.

Referenced by ExecBatchInsert(), ExecInsert(), ExecMergeMatched(), ExecOnConflictUpdate(), ExecUpdateAct(), and ExecUpdateEpilogue().

◆ InitPlan()

static void InitPlan ( QueryDesc queryDesc,
int  eflags 
)
static

Definition at line 836 of file execMain.c.

837{
838 CmdType operation = queryDesc->operation;
839 PlannedStmt *plannedstmt = queryDesc->plannedstmt;
840 Plan *plan = plannedstmt->planTree;
841 List *rangeTable = plannedstmt->rtable;
842 EState *estate = queryDesc->estate;
843 PlanState *planstate;
844 TupleDesc tupType;
845 ListCell *l;
846 int i;
847
848 /*
849 * Do permissions checks
850 */
851 ExecCheckPermissions(rangeTable, plannedstmt->permInfos, true);
852
853 /*
854 * initialize the node's execution state
855 */
856 ExecInitRangeTable(estate, rangeTable, plannedstmt->permInfos,
857 bms_copy(plannedstmt->unprunableRelids));
858
859 estate->es_plannedstmt = plannedstmt;
860 estate->es_part_prune_infos = plannedstmt->partPruneInfos;
861
862 /*
863 * Perform runtime "initial" pruning to identify which child subplans,
864 * corresponding to the children of plan nodes that contain
865 * PartitionPruneInfo such as Append, will not be executed. The results,
866 * which are bitmapsets of indexes of the child subplans that will be
867 * executed, are saved in es_part_prune_results. These results correspond
868 * to each PartitionPruneInfo entry, and the es_part_prune_results list is
869 * parallel to es_part_prune_infos.
870 */
871 ExecDoInitialPruning(estate);
872
873 /*
874 * Next, build the ExecRowMark array from the PlanRowMark(s), if any.
875 */
876 if (plannedstmt->rowMarks)
877 {
878 estate->es_rowmarks = (ExecRowMark **)
879 palloc0(estate->es_range_table_size * sizeof(ExecRowMark *));
880 foreach(l, plannedstmt->rowMarks)
881 {
882 PlanRowMark *rc = (PlanRowMark *) lfirst(l);
883 Oid relid;
884 Relation relation;
885 ExecRowMark *erm;
886
887 /*
888 * Ignore "parent" rowmarks, because they are irrelevant at
889 * runtime. Also ignore the rowmarks belonging to child tables
890 * that have been pruned in ExecDoInitialPruning().
891 */
892 if (rc->isParent ||
893 !bms_is_member(rc->rti, estate->es_unpruned_relids))
894 continue;
895
896 /* get relation's OID (will produce InvalidOid if subquery) */
897 relid = exec_rt_fetch(rc->rti, estate)->relid;
898
899 /* open relation, if we need to access it for this mark type */
900 switch (rc->markType)
901 {
904 case ROW_MARK_SHARE:
907 relation = ExecGetRangeTableRelation(estate, rc->rti, false);
908 break;
909 case ROW_MARK_COPY:
910 /* no physical table access is required */
911 relation = NULL;
912 break;
913 default:
914 elog(ERROR, "unrecognized markType: %d", rc->markType);
915 relation = NULL; /* keep compiler quiet */
916 break;
917 }
918
919 /* Check that relation is a legal target for marking */
920 if (relation)
921 CheckValidRowMarkRel(relation, rc->markType);
922
923 erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
924 erm->relation = relation;
925 erm->relid = relid;
926 erm->rti = rc->rti;
927 erm->prti = rc->prti;
928 erm->rowmarkId = rc->rowmarkId;
929 erm->markType = rc->markType;
930 erm->strength = rc->strength;
931 erm->waitPolicy = rc->waitPolicy;
932 erm->ermActive = false;
934 erm->ermExtra = NULL;
935
936 Assert(erm->rti > 0 && erm->rti <= estate->es_range_table_size &&
937 estate->es_rowmarks[erm->rti - 1] == NULL);
938
939 estate->es_rowmarks[erm->rti - 1] = erm;
940 }
941 }
942
943 /*
944 * Initialize the executor's tuple table to empty.
945 */
946 estate->es_tupleTable = NIL;
947
948 /* signal that this EState is not used for EPQ */
949 estate->es_epq_active = NULL;
950
951 /*
952 * Initialize private state information for each SubPlan. We must do this
953 * before running ExecInitNode on the main query tree, since
954 * ExecInitSubPlan expects to be able to find these entries.
955 */
956 Assert(estate->es_subplanstates == NIL);
957 i = 1; /* subplan indices count from 1 */
958 foreach(l, plannedstmt->subplans)
959 {
960 Plan *subplan = (Plan *) lfirst(l);
961 PlanState *subplanstate;
962 int sp_eflags;
963
964 /*
965 * A subplan will never need to do BACKWARD scan nor MARK/RESTORE. If
966 * it is a parameterless subplan (not initplan), we suggest that it be
967 * prepared to handle REWIND efficiently; otherwise there is no need.
968 */
969 sp_eflags = eflags
971 if (bms_is_member(i, plannedstmt->rewindPlanIDs))
972 sp_eflags |= EXEC_FLAG_REWIND;
973
974 subplanstate = ExecInitNode(subplan, estate, sp_eflags);
975
976 estate->es_subplanstates = lappend(estate->es_subplanstates,
977 subplanstate);
978
979 i++;
980 }
981
982 /*
983 * Initialize the private state information for all the nodes in the query
984 * tree. This opens files, allocates storage and leaves us ready to start
985 * processing tuples.
986 */
987 planstate = ExecInitNode(plan, estate, eflags);
988
989 /*
990 * Get the tuple descriptor describing the type of tuples to return.
991 */
992 tupType = ExecGetResultType(planstate);
993
994 /*
995 * Initialize the junk filter if needed. SELECT queries need a filter if
996 * there are any junk attrs in the top-level tlist.
997 */
998 if (operation == CMD_SELECT)
999 {
1000 bool junk_filter_needed = false;
1001 ListCell *tlist;
1002
1003 foreach(tlist, plan->targetlist)
1004 {
1005 TargetEntry *tle = (TargetEntry *) lfirst(tlist);
1006
1007 if (tle->resjunk)
1008 {
1009 junk_filter_needed = true;
1010 break;
1011 }
1012 }
1013
1014 if (junk_filter_needed)
1015 {
1016 JunkFilter *j;
1017 TupleTableSlot *slot;
1018
1019 slot = ExecInitExtraTupleSlot(estate, NULL, &TTSOpsVirtual);
1020 j = ExecInitJunkFilter(planstate->plan->targetlist,
1021 slot);
1022 estate->es_junkFilter = j;
1023
1024 /* Want to return the cleaned tuple type */
1025 tupType = j->jf_cleanTupType;
1026 }
1027 }
1028
1029 queryDesc->tupDesc = tupType;
1030 queryDesc->planstate = planstate;
1031}
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:122
JunkFilter * ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
Definition: execJunk.c:60
static void CheckValidRowMarkRel(Relation rel, RowMarkType markType)
Definition: execMain.c:1178
bool ExecCheckPermissions(List *rangeTable, List *rteperminfos, bool ereport_on_violation)
Definition: execMain.c:582
void ExecDoInitialPruning(EState *estate)
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:2020
TupleDesc ExecGetResultType(PlanState *planstate)
Definition: execUtils.c:495
Relation ExecGetRangeTableRelation(EState *estate, Index rti, bool isResultRel)
Definition: execUtils.c:825
void ExecInitRangeTable(EState *estate, List *rangeTable, List *permInfos, Bitmapset *unpruned_relids)
Definition: execUtils.c:773
#define EXEC_FLAG_REWIND
Definition: executor.h:68
static RangeTblEntry * exec_rt_fetch(Index rti, EState *estate)
Definition: executor.h:697
#define EXEC_FLAG_MARK
Definition: executor.h:70
int j
Definition: isn.c:78
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition: itemptr.h:184
void * palloc(Size size)
Definition: mcxt.c:1365
CmdType
Definition: nodes.h:273
#define plan(x)
Definition: pg_regress.c:161
@ ROW_MARK_SHARE
Definition: plannodes.h:1538
@ ROW_MARK_EXCLUSIVE
Definition: plannodes.h:1536
@ ROW_MARK_NOKEYEXCLUSIVE
Definition: plannodes.h:1537
@ ROW_MARK_KEYSHARE
Definition: plannodes.h:1539
ItemPointerData curCtid
Definition: execnodes.h:806
LockClauseStrength strength
Definition: execnodes.h:803
bool ermActive
Definition: execnodes.h:805
LockWaitPolicy waitPolicy
Definition: execnodes.h:804
void * ermExtra
Definition: execnodes.h:807
LockClauseStrength strength
Definition: plannodes.h:1600
Index prti
Definition: plannodes.h:1592
RowMarkType markType
Definition: plannodes.h:1596
LockWaitPolicy waitPolicy
Definition: plannodes.h:1602
bool isParent
Definition: plannodes.h:1604
Index rowmarkId
Definition: plannodes.h:1594
List * targetlist
Definition: plannodes.h:229
struct Plan * planTree
Definition: plannodes.h:101
List * rowMarks
Definition: plannodes.h:138
Bitmapset * rewindPlanIDs
Definition: plannodes.h:135
Bitmapset * unprunableRelids
Definition: plannodes.h:115
List * rtable
Definition: plannodes.h:109
List * partPruneInfos
Definition: plannodes.h:106
TupleDesc tupDesc
Definition: execdesc.h:47

References Assert(), bms_copy(), bms_is_member(), CheckValidRowMarkRel(), CMD_SELECT, ExecRowMark::curCtid, elog, ExecRowMark::ermActive, ExecRowMark::ermExtra, ERROR, EState::es_epq_active, EState::es_junkFilter, EState::es_part_prune_infos, EState::es_plannedstmt, EState::es_range_table_size, EState::es_rowmarks, EState::es_subplanstates, EState::es_tupleTable, EState::es_unpruned_relids, QueryDesc::estate, EXEC_FLAG_BACKWARD, EXEC_FLAG_MARK, EXEC_FLAG_REWIND, exec_rt_fetch(), ExecCheckPermissions(), ExecDoInitialPruning(), ExecGetRangeTableRelation(), ExecGetResultType(), ExecInitExtraTupleSlot(), ExecInitJunkFilter(), ExecInitNode(), ExecInitRangeTable(), i, PlanRowMark::isParent, ItemPointerSetInvalid(), j, lappend(), lfirst, ExecRowMark::markType, PlanRowMark::markType, NIL, QueryDesc::operation, palloc(), palloc0(), PlannedStmt::partPruneInfos, PlannedStmt::permInfos, PlanState::plan, plan, QueryDesc::plannedstmt, QueryDesc::planstate, PlannedStmt::planTree, ExecRowMark::prti, PlanRowMark::prti, ExecRowMark::relation, ExecRowMark::relid, PlannedStmt::rewindPlanIDs, ROW_MARK_COPY, ROW_MARK_EXCLUSIVE, ROW_MARK_KEYSHARE, ROW_MARK_NOKEYEXCLUSIVE, ROW_MARK_REFERENCE, ROW_MARK_SHARE, ExecRowMark::rowmarkId, PlanRowMark::rowmarkId, PlannedStmt::rowMarks, PlannedStmt::rtable, ExecRowMark::rti, PlanRowMark::rti, ExecRowMark::strength, PlanRowMark::strength, PlannedStmt::subplans, Plan::targetlist, TTSOpsVirtual, QueryDesc::tupDesc, PlannedStmt::unprunableRelids, ExecRowMark::waitPolicy, and PlanRowMark::waitPolicy.

Referenced by standard_ExecutorStart().

◆ InitResultRelInfo()

void InitResultRelInfo ( ResultRelInfo resultRelInfo,
Relation  resultRelationDesc,
Index  resultRelationIndex,
ResultRelInfo partition_root_rri,
int  instrument_options 
)

Definition at line 1243 of file execMain.c.

1248{
1249 MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
1250 resultRelInfo->type = T_ResultRelInfo;
1251 resultRelInfo->ri_RangeTableIndex = resultRelationIndex;
1252 resultRelInfo->ri_RelationDesc = resultRelationDesc;
1253 resultRelInfo->ri_NumIndices = 0;
1254 resultRelInfo->ri_IndexRelationDescs = NULL;
1255 resultRelInfo->ri_IndexRelationInfo = NULL;
1256 resultRelInfo->ri_needLockTagTuple =
1257 IsInplaceUpdateRelation(resultRelationDesc);
1258 /* make a copy so as not to depend on relcache info not changing... */
1259 resultRelInfo->ri_TrigDesc = CopyTriggerDesc(resultRelationDesc->trigdesc);
1260 if (resultRelInfo->ri_TrigDesc)
1261 {
1262 int n = resultRelInfo->ri_TrigDesc->numtriggers;
1263
1264 resultRelInfo->ri_TrigFunctions = (FmgrInfo *)
1265 palloc0(n * sizeof(FmgrInfo));
1266 resultRelInfo->ri_TrigWhenExprs = (ExprState **)
1267 palloc0(n * sizeof(ExprState *));
1268 if (instrument_options)
1269 resultRelInfo->ri_TrigInstrument = InstrAlloc(n, instrument_options, false);
1270 }
1271 else
1272 {
1273 resultRelInfo->ri_TrigFunctions = NULL;
1274 resultRelInfo->ri_TrigWhenExprs = NULL;
1275 resultRelInfo->ri_TrigInstrument = NULL;
1276 }
1277 if (resultRelationDesc->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1278 resultRelInfo->ri_FdwRoutine = GetFdwRoutineForRelation(resultRelationDesc, true);
1279 else
1280 resultRelInfo->ri_FdwRoutine = NULL;
1281
1282 /* The following fields are set later if needed */
1283 resultRelInfo->ri_RowIdAttNo = 0;
1284 resultRelInfo->ri_extraUpdatedCols = NULL;
1285 resultRelInfo->ri_projectNew = NULL;
1286 resultRelInfo->ri_newTupleSlot = NULL;
1287 resultRelInfo->ri_oldTupleSlot = NULL;
1288 resultRelInfo->ri_projectNewInfoValid = false;
1289 resultRelInfo->ri_FdwState = NULL;
1290 resultRelInfo->ri_usesFdwDirectModify = false;
1291 resultRelInfo->ri_CheckConstraintExprs = NULL;
1292 resultRelInfo->ri_GenVirtualNotNullConstraintExprs = NULL;
1293 resultRelInfo->ri_GeneratedExprsI = NULL;
1294 resultRelInfo->ri_GeneratedExprsU = NULL;
1295 resultRelInfo->ri_projectReturning = NULL;
1296 resultRelInfo->ri_onConflictArbiterIndexes = NIL;
1297 resultRelInfo->ri_onConflict = NULL;
1298 resultRelInfo->ri_ReturningSlot = NULL;
1299 resultRelInfo->ri_TrigOldSlot = NULL;
1300 resultRelInfo->ri_TrigNewSlot = NULL;
1301 resultRelInfo->ri_AllNullSlot = NULL;
1302 resultRelInfo->ri_MergeActions[MERGE_WHEN_MATCHED] = NIL;
1305 resultRelInfo->ri_MergeJoinCondition = NULL;
1306
1307 /*
1308 * Only ExecInitPartitionInfo() and ExecInitPartitionDispatchInfo() pass
1309 * non-NULL partition_root_rri. For child relations that are part of the
1310 * initial query rather than being dynamically added by tuple routing,
1311 * this field is filled in ExecInitModifyTable().
1312 */
1313 resultRelInfo->ri_RootResultRelInfo = partition_root_rri;
1314 /* Set by ExecGetRootToChildMap */
1315 resultRelInfo->ri_RootToChildMap = NULL;
1316 resultRelInfo->ri_RootToChildMapValid = false;
1317 /* Set by ExecInitRoutingInfo */
1318 resultRelInfo->ri_PartitionTupleSlot = NULL;
1319 resultRelInfo->ri_ChildToRootMap = NULL;
1320 resultRelInfo->ri_ChildToRootMapValid = false;
1321 resultRelInfo->ri_CopyMultiInsertBuffer = NULL;
1322}
#define MemSet(start, val, len)
Definition: c.h:1023
Instrumentation * InstrAlloc(int n, int instrument_options, bool async_mode)
Definition: instrument.c:31
@ MERGE_WHEN_NOT_MATCHED_BY_TARGET
Definition: primnodes.h:2023
@ MERGE_WHEN_NOT_MATCHED_BY_SOURCE
Definition: primnodes.h:2022
@ MERGE_WHEN_MATCHED
Definition: primnodes.h:2021
Definition: fmgr.h:57
TriggerDesc * trigdesc
Definition: rel.h:117
TupleConversionMap * ri_RootToChildMap
Definition: execnodes.h:606
TupleTableSlot * ri_PartitionTupleSlot
Definition: execnodes.h:619
bool ri_projectNewInfoValid
Definition: execnodes.h:509
OnConflictSetState * ri_onConflict
Definition: execnodes.h:583
List * ri_onConflictArbiterIndexes
Definition: execnodes.h:580
Instrumentation * ri_TrigInstrument
Definition: execnodes.h:524
ExprState * ri_MergeJoinCondition
Definition: execnodes.h:589
RelationPtr ri_IndexRelationDescs
Definition: execnodes.h:486
TupleTableSlot * ri_ReturningSlot
Definition: execnodes.h:527
TupleTableSlot * ri_oldTupleSlot
Definition: execnodes.h:507
bool ri_RootToChildMapValid
Definition: execnodes.h:607
struct CopyMultiInsertBuffer * ri_CopyMultiInsertBuffer
Definition: execnodes.h:622
TriggerDesc * ri_TrigDesc
Definition: execnodes.h:515
TupleTableSlot * ri_AllNullSlot
Definition: execnodes.h:530
Bitmapset * ri_extraUpdatedCols
Definition: execnodes.h:498
ExprState ** ri_GeneratedExprsI
Definition: execnodes.h:566
TupleConversionMap * ri_ChildToRootMap
Definition: execnodes.h:600
void * ri_FdwState
Definition: execnodes.h:536
bool ri_ChildToRootMapValid
Definition: execnodes.h:601
List * ri_MergeActions[NUM_MERGE_MATCH_KINDS]
Definition: execnodes.h:586
TupleTableSlot * ri_newTupleSlot
Definition: execnodes.h:505
ProjectionInfo * ri_projectNew
Definition: execnodes.h:503
NodeTag type
Definition: execnodes.h:474
ProjectionInfo * ri_projectReturning
Definition: execnodes.h:577
ExprState ** ri_GeneratedExprsU
Definition: execnodes.h:567
ExprState ** ri_TrigWhenExprs
Definition: execnodes.h:521
FmgrInfo * ri_TrigFunctions
Definition: execnodes.h:518
bool ri_usesFdwDirectModify
Definition: execnodes.h:539
AttrNumber ri_RowIdAttNo
Definition: execnodes.h:495
IndexInfo ** ri_IndexRelationInfo
Definition: execnodes.h:489
TupleTableSlot * ri_TrigNewSlot
Definition: execnodes.h:529
TupleTableSlot * ri_TrigOldSlot
Definition: execnodes.h:528
int numtriggers
Definition: reltrigger.h:50
TriggerDesc * CopyTriggerDesc(TriggerDesc *trigdesc)
Definition: trigger.c:2090

References CopyTriggerDesc(), GetFdwRoutineForRelation(), InstrAlloc(), IsInplaceUpdateRelation(), MemSet, MERGE_WHEN_MATCHED, MERGE_WHEN_NOT_MATCHED_BY_SOURCE, MERGE_WHEN_NOT_MATCHED_BY_TARGET, NIL, TriggerDesc::numtriggers, palloc0(), RelationData::rd_rel, ResultRelInfo::ri_AllNullSlot, ResultRelInfo::ri_CheckConstraintExprs, ResultRelInfo::ri_ChildToRootMap, ResultRelInfo::ri_ChildToRootMapValid, ResultRelInfo::ri_CopyMultiInsertBuffer, ResultRelInfo::ri_extraUpdatedCols, ResultRelInfo::ri_FdwRoutine, ResultRelInfo::ri_FdwState, ResultRelInfo::ri_GeneratedExprsI, ResultRelInfo::ri_GeneratedExprsU, ResultRelInfo::ri_GenVirtualNotNullConstraintExprs, ResultRelInfo::ri_IndexRelationDescs, ResultRelInfo::ri_IndexRelationInfo, ResultRelInfo::ri_MergeActions, ResultRelInfo::ri_MergeJoinCondition, ResultRelInfo::ri_needLockTagTuple, ResultRelInfo::ri_newTupleSlot, ResultRelInfo::ri_NumIndices, ResultRelInfo::ri_oldTupleSlot, ResultRelInfo::ri_onConflict, ResultRelInfo::ri_onConflictArbiterIndexes, ResultRelInfo::ri_PartitionTupleSlot, ResultRelInfo::ri_projectNew, ResultRelInfo::ri_projectNewInfoValid, ResultRelInfo::ri_projectReturning, ResultRelInfo::ri_RangeTableIndex, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_ReturningSlot, ResultRelInfo::ri_RootResultRelInfo, ResultRelInfo::ri_RootToChildMap, ResultRelInfo::ri_RootToChildMapValid, ResultRelInfo::ri_RowIdAttNo, ResultRelInfo::ri_TrigDesc, ResultRelInfo::ri_TrigFunctions, ResultRelInfo::ri_TrigInstrument, ResultRelInfo::ri_TrigNewSlot, ResultRelInfo::ri_TrigOldSlot, ResultRelInfo::ri_TrigWhenExprs, ResultRelInfo::ri_usesFdwDirectModify, RelationData::trigdesc, and ResultRelInfo::type.

Referenced by ATRewriteTable(), create_edata_for_relation(), ExecGetAncestorResultRels(), ExecGetTriggerResultRel(), ExecInitPartitionDispatchInfo(), ExecInitPartitionInfo(), ExecInitResultRelation(), and ExecuteTruncateGuts().

◆ ReportNotNullViolationError()

static void ReportNotNullViolationError ( ResultRelInfo resultRelInfo,
TupleTableSlot slot,
EState estate,
int  attnum 
)
static

Definition at line 2159 of file execMain.c.

2161{
2162 Bitmapset *modifiedCols;
2163 char *val_desc;
2164 Relation rel = resultRelInfo->ri_RelationDesc;
2165 Relation orig_rel = rel;
2166 TupleDesc tupdesc = RelationGetDescr(rel);
2167 TupleDesc orig_tupdesc = RelationGetDescr(rel);
2168 Form_pg_attribute att = TupleDescAttr(tupdesc, attnum - 1);
2169
2170 Assert(attnum > 0);
2171
2172 /*
2173 * If the tuple has been routed, it's been converted to the partition's
2174 * rowtype, which might differ from the root table's. We must convert it
2175 * back to the root table's rowtype so that val_desc shown error message
2176 * matches the input tuple.
2177 */
2178 if (resultRelInfo->ri_RootResultRelInfo)
2179 {
2180 ResultRelInfo *rootrel = resultRelInfo->ri_RootResultRelInfo;
2181 AttrMap *map;
2182
2183 tupdesc = RelationGetDescr(rootrel->ri_RelationDesc);
2184 /* a reverse map */
2185 map = build_attrmap_by_name_if_req(orig_tupdesc,
2186 tupdesc,
2187 false);
2188
2189 /*
2190 * Partition-specific slot's tupdesc can't be changed, so allocate a
2191 * new one.
2192 */
2193 if (map != NULL)
2194 slot = execute_attr_map_slot(map, slot,
2196 modifiedCols = bms_union(ExecGetInsertedCols(rootrel, estate),
2197 ExecGetUpdatedCols(rootrel, estate));
2198 rel = rootrel->ri_RelationDesc;
2199 }
2200 else
2201 modifiedCols = bms_union(ExecGetInsertedCols(resultRelInfo, estate),
2202 ExecGetUpdatedCols(resultRelInfo, estate));
2203
2205 slot,
2206 tupdesc,
2207 modifiedCols,
2208 64);
2209 ereport(ERROR,
2210 errcode(ERRCODE_NOT_NULL_VIOLATION),
2211 errmsg("null value in column \"%s\" of relation \"%s\" violates not-null constraint",
2212 NameStr(att->attname),
2213 RelationGetRelationName(orig_rel)),
2214 val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
2215 errtablecol(orig_rel, attnum));
2216}
int errtablecol(Relation rel, int attnum)
Definition: relcache.c:6066

References Assert(), attnum, bms_union(), build_attrmap_by_name_if_req(), ereport, errcode(), errdetail(), errmsg(), ERROR, errtablecol(), ExecBuildSlotValueDescription(), ExecGetInsertedCols(), ExecGetUpdatedCols(), execute_attr_map_slot(), MakeTupleTableSlot(), NameStr, RelationGetDescr, RelationGetRelationName, RelationGetRelid, ResultRelInfo::ri_RelationDesc, ResultRelInfo::ri_RootResultRelInfo, TTSOpsVirtual, and TupleDescAttr().

Referenced by ExecConstraints().

◆ standard_ExecutorEnd()

void standard_ExecutorEnd ( QueryDesc queryDesc)

Definition at line 475 of file execMain.c.

476{
477 EState *estate;
478 MemoryContext oldcontext;
479
480 /* sanity checks */
481 Assert(queryDesc != NULL);
482
483 estate = queryDesc->estate;
484
485 Assert(estate != NULL);
486
487 if (estate->es_parallel_workers_to_launch > 0)
490
491 /*
492 * Check that ExecutorFinish was called, unless in EXPLAIN-only mode. This
493 * Assert is needed because ExecutorFinish is new as of 9.1, and callers
494 * might forget to call it.
495 */
496 Assert(estate->es_finished ||
498
499 /*
500 * Switch into per-query memory context to run ExecEndPlan
501 */
502 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
503
504 ExecEndPlan(queryDesc->planstate, estate);
505
506 /* do away with our snapshots */
509
510 /*
511 * Must switch out of context before destroying it
512 */
513 MemoryContextSwitchTo(oldcontext);
514
515 /*
516 * Release EState and per-query memory context. This should release
517 * everything the executor has allocated.
518 */
519 FreeExecutorState(estate);
520
521 /* Reset queryDesc fields that no longer point to anything */
522 queryDesc->tupDesc = NULL;
523 queryDesc->estate = NULL;
524 queryDesc->planstate = NULL;
525 queryDesc->totaltime = NULL;
526}
static void ExecEndPlan(PlanState *planstate, EState *estate)
Definition: execMain.c:1536
#define EXEC_FLAG_EXPLAIN_ONLY
Definition: executor.h:66
int64 PgStat_Counter
Definition: pgstat.h:66
void pgstat_update_parallel_workers_stats(PgStat_Counter workers_to_launch, PgStat_Counter workers_launched)
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:864
int es_parallel_workers_to_launch
Definition: execnodes.h:746
bool es_finished
Definition: execnodes.h:721
int es_parallel_workers_launched
Definition: execnodes.h:748
struct Instrumentation * totaltime
Definition: execdesc.h:55

References Assert(), EState::es_crosscheck_snapshot, EState::es_finished, EState::es_parallel_workers_launched, EState::es_parallel_workers_to_launch, EState::es_query_cxt, EState::es_snapshot, EState::es_top_eflags, QueryDesc::estate, EXEC_FLAG_EXPLAIN_ONLY, ExecEndPlan(), FreeExecutorState(), MemoryContextSwitchTo(), pgstat_update_parallel_workers_stats(), QueryDesc::planstate, QueryDesc::totaltime, QueryDesc::tupDesc, and UnregisterSnapshot().

Referenced by ExecutorEnd(), explain_ExecutorEnd(), and pgss_ExecutorEnd().

◆ standard_ExecutorFinish()

void standard_ExecutorFinish ( QueryDesc queryDesc)

Definition at line 415 of file execMain.c.

416{
417 EState *estate;
418 MemoryContext oldcontext;
419
420 /* sanity checks */
421 Assert(queryDesc != NULL);
422
423 estate = queryDesc->estate;
424
425 Assert(estate != NULL);
427
428 /* This should be run once and only once per Executor instance */
429 Assert(!estate->es_finished);
430
431 /* Switch into per-query memory context */
432 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
433
434 /* Allow instrumentation of Executor overall runtime */
435 if (queryDesc->totaltime)
436 InstrStartNode(queryDesc->totaltime);
437
438 /* Run ModifyTable nodes to completion */
439 ExecPostprocessPlan(estate);
440
441 /* Execute queued AFTER triggers, unless told not to */
442 if (!(estate->es_top_eflags & EXEC_FLAG_SKIP_TRIGGERS))
443 AfterTriggerEndQuery(estate);
444
445 if (queryDesc->totaltime)
446 InstrStopNode(queryDesc->totaltime, 0);
447
448 MemoryContextSwitchTo(oldcontext);
449
450 estate->es_finished = true;
451}
static void ExecPostprocessPlan(EState *estate)
Definition: execMain.c:1490
#define EXEC_FLAG_SKIP_TRIGGERS
Definition: executor.h:71
void InstrStartNode(Instrumentation *instr)
Definition: instrument.c:68
void InstrStopNode(Instrumentation *instr, double nTuples)
Definition: instrument.c:84
void AfterTriggerEndQuery(EState *estate)
Definition: trigger.c:5124

References AfterTriggerEndQuery(), Assert(), EState::es_finished, EState::es_query_cxt, EState::es_top_eflags, QueryDesc::estate, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_SKIP_TRIGGERS, ExecPostprocessPlan(), InstrStartNode(), InstrStopNode(), MemoryContextSwitchTo(), and QueryDesc::totaltime.

Referenced by ExecutorFinish(), explain_ExecutorFinish(), and pgss_ExecutorFinish().

◆ standard_ExecutorRun()

void standard_ExecutorRun ( QueryDesc queryDesc,
ScanDirection  direction,
uint64  count 
)

Definition at line 307 of file execMain.c.

309{
310 EState *estate;
311 CmdType operation;
313 bool sendTuples;
314 MemoryContext oldcontext;
315
316 /* sanity checks */
317 Assert(queryDesc != NULL);
318
319 estate = queryDesc->estate;
320
321 Assert(estate != NULL);
323
324 /* caller must ensure the query's snapshot is active */
326
327 /*
328 * Switch into per-query memory context
329 */
330 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
331
332 /* Allow instrumentation of Executor overall runtime */
333 if (queryDesc->totaltime)
334 InstrStartNode(queryDesc->totaltime);
335
336 /*
337 * extract information from the query descriptor and the query feature.
338 */
339 operation = queryDesc->operation;
340 dest = queryDesc->dest;
341
342 /*
343 * startup tuple receiver, if we will be emitting tuples
344 */
345 estate->es_processed = 0;
346
347 sendTuples = (operation == CMD_SELECT ||
348 queryDesc->plannedstmt->hasReturning);
349
350 if (sendTuples)
351 dest->rStartup(dest, operation, queryDesc->tupDesc);
352
353 /*
354 * Run plan, unless direction is NoMovement.
355 *
356 * Note: pquery.c selects NoMovement if a prior call already reached
357 * end-of-data in the user-specified fetch direction. This is important
358 * because various parts of the executor can misbehave if called again
359 * after reporting EOF. For example, heapam.c would actually restart a
360 * heapscan and return all its data afresh. There is also some doubt
361 * about whether a parallel plan would operate properly if an additional,
362 * necessarily non-parallel execution request occurs after completing a
363 * parallel execution. (That case should work, but it's untested.)
364 */
365 if (!ScanDirectionIsNoMovement(direction))
366 ExecutePlan(queryDesc,
367 operation,
368 sendTuples,
369 count,
370 direction,
371 dest);
372
373 /*
374 * Update es_total_processed to keep track of the number of tuples
375 * processed across multiple ExecutorRun() calls.
376 */
377 estate->es_total_processed += estate->es_processed;
378
379 /*
380 * shutdown tuple receiver, if we started it
381 */
382 if (sendTuples)
383 dest->rShutdown(dest);
384
385 if (queryDesc->totaltime)
386 InstrStopNode(queryDesc->totaltime, estate->es_processed);
387
388 MemoryContextSwitchTo(oldcontext);
389}
static void ExecutePlan(QueryDesc *queryDesc, CmdType operation, bool sendTuples, uint64 numberTuples, ScanDirection direction, DestReceiver *dest)
Definition: execMain.c:1656
#define ScanDirectionIsNoMovement(direction)
Definition: sdir.h:57
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:798
uint64 es_total_processed
Definition: execnodes.h:716
bool hasReturning
Definition: plannodes.h:80
DestReceiver * dest
Definition: execdesc.h:41

References Assert(), CMD_SELECT, generate_unaccent_rules::dest, QueryDesc::dest, EState::es_processed, EState::es_query_cxt, EState::es_snapshot, EState::es_top_eflags, EState::es_total_processed, QueryDesc::estate, EXEC_FLAG_EXPLAIN_ONLY, ExecutePlan(), GetActiveSnapshot(), PlannedStmt::hasReturning, InstrStartNode(), InstrStopNode(), MemoryContextSwitchTo(), QueryDesc::operation, QueryDesc::plannedstmt, ScanDirectionIsNoMovement, QueryDesc::totaltime, and QueryDesc::tupDesc.

Referenced by ExecutorRun(), explain_ExecutorRun(), and pgss_ExecutorRun().

◆ standard_ExecutorStart()

void standard_ExecutorStart ( QueryDesc queryDesc,
int  eflags 
)

Definition at line 141 of file execMain.c.

142{
143 EState *estate;
144 MemoryContext oldcontext;
145
146 /* sanity checks: queryDesc must not be started already */
147 Assert(queryDesc != NULL);
148 Assert(queryDesc->estate == NULL);
149
150 /* caller must ensure the query's snapshot is active */
151 Assert(GetActiveSnapshot() == queryDesc->snapshot);
152
153 /*
154 * If the transaction is read-only, we need to check if any writes are
155 * planned to non-temporary tables. EXPLAIN is considered read-only.
156 *
157 * Don't allow writes in parallel mode. Supporting UPDATE and DELETE
158 * would require (a) storing the combo CID hash in shared memory, rather
159 * than synchronizing it just once at the start of parallelism, and (b) an
160 * alternative to heap_update()'s reliance on xmax for mutual exclusion.
161 * INSERT may have no such troubles, but we forbid it to simplify the
162 * checks.
163 *
164 * We have lower-level defenses in CommandCounterIncrement and elsewhere
165 * against performing unsafe operations in parallel mode, but this gives a
166 * more user-friendly error message.
167 */
168 if ((XactReadOnly || IsInParallelMode()) &&
169 !(eflags & EXEC_FLAG_EXPLAIN_ONLY))
171
172 /*
173 * Build EState, switch into per-query memory context for startup.
174 */
175 estate = CreateExecutorState();
176 queryDesc->estate = estate;
177
178 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
179
180 /*
181 * Fill in external parameters, if any, from queryDesc; and allocate
182 * workspace for internal parameters
183 */
184 estate->es_param_list_info = queryDesc->params;
185
186 if (queryDesc->plannedstmt->paramExecTypes != NIL)
187 {
188 int nParamExec;
189
190 nParamExec = list_length(queryDesc->plannedstmt->paramExecTypes);
192 palloc0(nParamExec * sizeof(ParamExecData));
193 }
194
195 /* We now require all callers to provide sourceText */
196 Assert(queryDesc->sourceText != NULL);
197 estate->es_sourceText = queryDesc->sourceText;
198
199 /*
200 * Fill in the query environment, if any, from queryDesc.
201 */
202 estate->es_queryEnv = queryDesc->queryEnv;
203
204 /*
205 * If non-read-only query, set the command ID to mark output tuples with
206 */
207 switch (queryDesc->operation)
208 {
209 case CMD_SELECT:
210
211 /*
212 * SELECT FOR [KEY] UPDATE/SHARE and modifying CTEs need to mark
213 * tuples
214 */
215 if (queryDesc->plannedstmt->rowMarks != NIL ||
216 queryDesc->plannedstmt->hasModifyingCTE)
217 estate->es_output_cid = GetCurrentCommandId(true);
218
219 /*
220 * A SELECT without modifying CTEs can't possibly queue triggers,
221 * so force skip-triggers mode. This is just a marginal efficiency
222 * hack, since AfterTriggerBeginQuery/AfterTriggerEndQuery aren't
223 * all that expensive, but we might as well do it.
224 */
225 if (!queryDesc->plannedstmt->hasModifyingCTE)
226 eflags |= EXEC_FLAG_SKIP_TRIGGERS;
227 break;
228
229 case CMD_INSERT:
230 case CMD_DELETE:
231 case CMD_UPDATE:
232 case CMD_MERGE:
233 estate->es_output_cid = GetCurrentCommandId(true);
234 break;
235
236 default:
237 elog(ERROR, "unrecognized operation code: %d",
238 (int) queryDesc->operation);
239 break;
240 }
241
242 /*
243 * Copy other important information into the EState
244 */
245 estate->es_snapshot = RegisterSnapshot(queryDesc->snapshot);
247 estate->es_top_eflags = eflags;
248 estate->es_instrument = queryDesc->instrument_options;
249 estate->es_jit_flags = queryDesc->plannedstmt->jitFlags;
250
251 /*
252 * Set up an AFTER-trigger statement context, unless told not to, or
253 * unless it's EXPLAIN-only mode (when ExecutorFinish won't be called).
254 */
257
258 /*
259 * Initialize the plan state tree
260 */
261 InitPlan(queryDesc, eflags);
262
263 MemoryContextSwitchTo(oldcontext);
264}
static void ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
Definition: execMain.c:802
static void InitPlan(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:836
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:822
int es_jit_flags
Definition: execnodes.h:763
const char * es_sourceText
Definition: execnodes.h:677
int jitFlags
Definition: plannodes.h:98
const char * sourceText
Definition: execdesc.h:38
ParamListInfo params
Definition: execdesc.h:42
int instrument_options
Definition: execdesc.h:44
Snapshot snapshot
Definition: execdesc.h:39
QueryEnvironment * queryEnv
Definition: execdesc.h:43
Snapshot crosscheck_snapshot
Definition: execdesc.h:40
void AfterTriggerBeginQuery(void)
Definition: trigger.c:5104
bool XactReadOnly
Definition: xact.c:82
bool IsInParallelMode(void)
Definition: xact.c:1089
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:829

References AfterTriggerBeginQuery(), Assert(), CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_SELECT, CMD_UPDATE, CreateExecutorState(), QueryDesc::crosscheck_snapshot, elog, ERROR, EState::es_crosscheck_snapshot, EState::es_instrument, EState::es_jit_flags, EState::es_output_cid, EState::es_param_exec_vals, EState::es_param_list_info, EState::es_query_cxt, EState::es_queryEnv, EState::es_snapshot, EState::es_sourceText, EState::es_top_eflags, QueryDesc::estate, EXEC_FLAG_EXPLAIN_ONLY, EXEC_FLAG_SKIP_TRIGGERS, ExecCheckXactReadOnly(), GetActiveSnapshot(), GetCurrentCommandId(), PlannedStmt::hasModifyingCTE, InitPlan(), QueryDesc::instrument_options, IsInParallelMode(), PlannedStmt::jitFlags, list_length(), MemoryContextSwitchTo(), NIL, QueryDesc::operation, palloc0(), PlannedStmt::paramExecTypes, QueryDesc::params, QueryDesc::plannedstmt, QueryDesc::queryEnv, RegisterSnapshot(), PlannedStmt::rowMarks, QueryDesc::snapshot, QueryDesc::sourceText, and XactReadOnly.

Referenced by ExecutorStart(), explain_ExecutorStart(), and pgss_ExecutorStart().

Variable Documentation

◆ ExecutorCheckPerms_hook

ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook = NULL

Definition at line 74 of file execMain.c.

Referenced by _PG_init(), and ExecCheckPermissions().

◆ ExecutorEnd_hook

ExecutorEnd_hook_type ExecutorEnd_hook = NULL

Definition at line 71 of file execMain.c.

Referenced by _PG_init(), and ExecutorEnd().

◆ ExecutorFinish_hook

ExecutorFinish_hook_type ExecutorFinish_hook = NULL

Definition at line 70 of file execMain.c.

Referenced by _PG_init(), and ExecutorFinish().

◆ ExecutorRun_hook

ExecutorRun_hook_type ExecutorRun_hook = NULL

Definition at line 69 of file execMain.c.

Referenced by _PG_init(), and ExecutorRun().

◆ ExecutorStart_hook

ExecutorStart_hook_type ExecutorStart_hook = NULL

Definition at line 68 of file execMain.c.

Referenced by _PG_init(), and ExecutorStart().