PostgreSQL Source Code git master
Loading...
Searching...
No Matches
execMain.c File Reference
#include "postgres.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "access/tableam.h"
#include "access/tupconvert.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/instrument.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, ModifyTable *mtnode)
 
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 charExecRelCheck (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)
 
charExecBuildSlotValueDescription (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,
ModifyTable mtnode 
)

Definition at line 1065 of file execMain.c.

1068{
1069 Relation resultRel = resultRelInfo->ri_RelationDesc;
1070 FdwRoutine *fdwroutine;
1071
1072 /* Expect a fully-formed ResultRelInfo from InitResultRelInfo(). */
1073 Assert(resultRelInfo->ri_needLockTagTuple ==
1074 IsInplaceUpdateRelation(resultRel));
1075
1076 switch (resultRel->rd_rel->relkind)
1077 {
1078 case RELKIND_RELATION:
1080
1081 /*
1082 * For MERGE, check that the target relation supports each action.
1083 * For other operations, just check the operation itself.
1084 */
1085 if (operation == CMD_MERGE)
1087 CheckCmdReplicaIdentity(resultRel, action->commandType);
1088 else
1090
1091 /*
1092 * For INSERT ON CONFLICT DO UPDATE, additionally check that the
1093 * target relation supports UPDATE.
1094 */
1095 if (onConflictAction == ONCONFLICT_UPDATE)
1097 break;
1098 case RELKIND_SEQUENCE:
1099 ereport(ERROR,
1101 errmsg("cannot change sequence \"%s\"",
1102 RelationGetRelationName(resultRel))));
1103 break;
1104 case RELKIND_TOASTVALUE:
1105 ereport(ERROR,
1107 errmsg("cannot change TOAST relation \"%s\"",
1108 RelationGetRelationName(resultRel))));
1109 break;
1110 case RELKIND_VIEW:
1111
1112 /*
1113 * Okay only if there's a suitable INSTEAD OF trigger. Otherwise,
1114 * complain, but omit errdetail because we haven't got the
1115 * information handy (and given that it really shouldn't happen,
1116 * it's not worth great exertion to get).
1117 */
1120 NULL);
1121 break;
1122 case RELKIND_MATVIEW:
1124 ereport(ERROR,
1126 errmsg("cannot change materialized view \"%s\"",
1127 RelationGetRelationName(resultRel))));
1128 break;
1130 /* We don't support FOR PORTION OF FDW queries. */
1131 if (mtnode && mtnode->forPortionOf)
1132 ereport(ERROR,
1134 errmsg("foreign tables don't support FOR PORTION OF"),
1135 errdetail("\"%s\" is a foreign table.",
1136 RelationGetRelationName(resultRel)));
1137
1138 /* Okay only if the FDW supports it */
1139 fdwroutine = resultRelInfo->ri_FdwRoutine;
1140 switch (operation)
1141 {
1142 case CMD_INSERT:
1143 if (fdwroutine->ExecForeignInsert == NULL)
1144 ereport(ERROR,
1146 errmsg("cannot insert into foreign table \"%s\"",
1147 RelationGetRelationName(resultRel))));
1148 if (fdwroutine->IsForeignRelUpdatable != NULL &&
1149 (fdwroutine->IsForeignRelUpdatable(resultRel) & (1 << CMD_INSERT)) == 0)
1150 ereport(ERROR,
1152 errmsg("foreign table \"%s\" does not allow inserts",
1153 RelationGetRelationName(resultRel))));
1154 break;
1155 case CMD_UPDATE:
1156 if (fdwroutine->ExecForeignUpdate == NULL)
1157 ereport(ERROR,
1159 errmsg("cannot update foreign table \"%s\"",
1160 RelationGetRelationName(resultRel))));
1161 if (fdwroutine->IsForeignRelUpdatable != NULL &&
1162 (fdwroutine->IsForeignRelUpdatable(resultRel) & (1 << CMD_UPDATE)) == 0)
1163 ereport(ERROR,
1165 errmsg("foreign table \"%s\" does not allow updates",
1166 RelationGetRelationName(resultRel))));
1167 break;
1168 case CMD_DELETE:
1169 if (fdwroutine->ExecForeignDelete == NULL)
1170 ereport(ERROR,
1172 errmsg("cannot delete from foreign table \"%s\"",
1173 RelationGetRelationName(resultRel))));
1174 if (fdwroutine->IsForeignRelUpdatable != NULL &&
1175 (fdwroutine->IsForeignRelUpdatable(resultRel) & (1 << CMD_DELETE)) == 0)
1176 ereport(ERROR,
1178 errmsg("foreign table \"%s\" does not allow deletes",
1179 RelationGetRelationName(resultRel))));
1180 break;
1181 default:
1182 elog(ERROR, "unrecognized CmdType: %d", (int) operation);
1183 break;
1184 }
1185 break;
1186 case RELKIND_PROPGRAPH:
1187 ereport(ERROR,
1189 errmsg("cannot change property graph \"%s\"",
1190 RelationGetRelationName(resultRel))));
1191 break;
1192 default:
1193 ereport(ERROR,
1195 errmsg("cannot change relation \"%s\"",
1196 RelationGetRelationName(resultRel))));
1197 break;
1198 }
1199
1200 /*
1201 * Conflict log tables are managed by the system to record logical
1202 * replication conflicts. We allow DELETE and TRUNCATE to permit users to
1203 * manually prune these logs, but manual data insertion or modification
1204 * (INSERT, UPDATE, MERGE) is prohibited to maintain the integrity of the
1205 * system-generated logs.
1206 *
1207 * Since TRUNCATE is handled as a separate utility command, we only need
1208 * to explicitly permit CMD_DELETE here.
1209 */
1212 ereport(ERROR,
1214 errmsg("cannot modify or insert data into conflict log table \"%s\"",
1215 RelationGetRelationName(resultRel)),
1216 errdetail("Conflict log tables are system-managed and only support cleanup using DELETE or TRUNCATE.")));
1217}
#define Assert(condition)
Definition c.h:1002
bool IsConflictLogTableNamespace(Oid namespaceId)
Definition catalog.c:290
bool IsInplaceUpdateRelation(Relation relation)
Definition catalog.c:185
static DataChecksumsWorkerOperation operation
int errcode(int sqlerrcode)
Definition elog.c:875
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
void CheckCmdReplicaIdentity(Relation rel, CmdType cmd)
bool MatViewIncrementalMaintenanceIsEnabled(void)
Definition matview.c:953
@ ONCONFLICT_UPDATE
Definition nodes.h:428
@ CMD_MERGE
Definition nodes.h:277
@ CMD_INSERT
Definition nodes.h:275
@ CMD_DELETE
Definition nodes.h:276
@ CMD_UPDATE
Definition nodes.h:274
static char * errmsg
#define foreach_node(type, var, lst)
Definition pg_list.h:528
static int fb(int x)
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationGetNamespace(relation)
Definition rel.h:557
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:236
ExecForeignUpdate_function ExecForeignUpdate
Definition fdwapi.h:239
ExecForeignDelete_function ExecForeignDelete
Definition fdwapi.h:240
IsForeignRelUpdatable_function IsForeignRelUpdatable
Definition fdwapi.h:244
Form_pg_class rd_rel
Definition rel.h:111
bool ri_needLockTagTuple
Definition execnodes.h:546
Relation ri_RelationDesc
Definition execnodes.h:514
struct FdwRoutine * ri_FdwRoutine
Definition execnodes.h:567

References Assert, CheckCmdReplicaIdentity(), CMD_DELETE, CMD_INSERT, CMD_MERGE, CMD_UPDATE, elog, ereport, errcode(), errdetail(), errmsg, ERROR, error_view_not_updatable(), FdwRoutine::ExecForeignDelete, FdwRoutine::ExecForeignInsert, FdwRoutine::ExecForeignUpdate, fb(), foreach_node, IsConflictLogTableNamespace(), FdwRoutine::IsForeignRelUpdatable, IsInplaceUpdateRelation(), MatViewIncrementalMaintenanceIsEnabled(), ONCONFLICT_UPDATE, operation, RelationData::rd_rel, RelationGetNamespace, 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 1226 of file execMain.c.

1227{
1228 FdwRoutine *fdwroutine;
1229
1230 switch (rel->rd_rel->relkind)
1231 {
1232 case RELKIND_RELATION:
1234 /* OK */
1235 break;
1236 case RELKIND_SEQUENCE:
1237 /* Must disallow this because we don't vacuum sequences */
1238 ereport(ERROR,
1240 errmsg("cannot lock rows in sequence \"%s\"",
1242 break;
1243 case RELKIND_TOASTVALUE:
1244 /* We could allow this, but there seems no good reason to */
1245 ereport(ERROR,
1247 errmsg("cannot lock rows in TOAST relation \"%s\"",
1249 break;
1250 case RELKIND_VIEW:
1251 /* Should not get here; planner should have expanded the view */
1252 ereport(ERROR,
1254 errmsg("cannot lock rows in view \"%s\"",
1256 break;
1257 case RELKIND_MATVIEW:
1258 /* Allow referencing a matview, but not actual locking clauses */
1259 if (markType != ROW_MARK_REFERENCE)
1260 ereport(ERROR,
1262 errmsg("cannot lock rows in materialized view \"%s\"",
1264 break;
1266 /* Okay only if the FDW supports it */
1267 fdwroutine = GetFdwRoutineForRelation(rel, false);
1268 if (fdwroutine->RefetchForeignRow == NULL)
1269 ereport(ERROR,
1271 errmsg("cannot lock rows in foreign table \"%s\"",
1273 break;
1274 case RELKIND_PROPGRAPH:
1275 /* Should not get here; rewriter should have expanded the graph */
1276 ereport(ERROR,
1278 errmsg_internal("cannot lock rows in property graph \"%s\"",
1280 break;
1281 default:
1282 ereport(ERROR,
1284 errmsg("cannot lock rows in relation \"%s\"",
1286 break;
1287 }
1288
1289 /*
1290 * Conflict log tables are managed by the system to record logical
1291 * replication conflicts.
1292 */
1294 ereport(ERROR,
1296 errmsg("cannot lock rows in the conflict log table \"%s\"",
1298}
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition foreign.c:474
@ ROW_MARK_REFERENCE
Definition plannodes.h:1561
RefetchForeignRow_function RefetchForeignRow
Definition fdwapi.h:252

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

Referenced by InitPlan().

◆ EvalPlanQual()

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

Definition at line 2715 of file execMain.c.

2717{
2718 TupleTableSlot *slot;
2720
2721 Assert(rti > 0);
2722
2723 /*
2724 * Need to run a recheck subquery. Initialize or reinitialize EPQ state.
2725 */
2726 EvalPlanQualBegin(epqstate);
2727
2728 /*
2729 * Callers will often use the EvalPlanQualSlot to store the tuple to avoid
2730 * an unnecessary copy.
2731 */
2732 testslot = EvalPlanQualSlot(epqstate, relation, rti);
2733 if (testslot != inputslot)
2734 ExecCopySlot(testslot, inputslot);
2735
2736 /*
2737 * Mark that an EPQ tuple is available for this relation. (If there is
2738 * more than one result relation, the others remain marked as having no
2739 * tuple available.)
2740 */
2741 epqstate->relsubs_done[rti - 1] = false;
2742 epqstate->relsubs_blocked[rti - 1] = false;
2743
2744 /*
2745 * Run the EPQ query. We assume it will return at most one tuple.
2746 */
2747 slot = EvalPlanQualNext(epqstate);
2748
2749 /*
2750 * If we got a tuple, force the slot to materialize the tuple so that it
2751 * is not dependent on any local state in the EPQ query (in particular,
2752 * it's highly likely that the slot contains references to any pass-by-ref
2753 * datums that may be present in copyTuple). As with the next step, this
2754 * is to guard against early re-use of the EPQ query.
2755 */
2756 if (!TupIsNull(slot))
2757 ExecMaterializeSlot(slot);
2758
2759 /*
2760 * Clear out the test tuple, and mark that no tuple is available here.
2761 * This is needed in case the EPQ state is re-used to test a tuple for a
2762 * different target relation.
2763 */
2765 epqstate->relsubs_blocked[rti - 1] = true;
2766
2767 return slot;
2768}
TupleTableSlot * EvalPlanQualSlot(EPQState *epqstate, Relation relation, Index rti)
Definition execMain.c:2842
void EvalPlanQualBegin(EPQState *epqstate)
Definition execMain.c:2997
TupleTableSlot * EvalPlanQualNext(EPQState *epqstate)
Definition execMain.c:2981
bool * relsubs_blocked
Definition execnodes.h:1395
bool * relsubs_done
Definition execnodes.h:1386
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:476
#define TupIsNull(slot)
Definition tuptable.h:325
static TupleTableSlot * ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
Definition tuptable.h:544
static void ExecMaterializeSlot(TupleTableSlot *slot)
Definition tuptable.h:495

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

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

◆ EvalPlanQualBegin()

void EvalPlanQualBegin ( EPQState epqstate)

Definition at line 2997 of file execMain.c.

2998{
2999 EState *parentestate = epqstate->parentestate;
3000 EState *recheckestate = epqstate->recheckestate;
3001
3002 if (recheckestate == NULL)
3003 {
3004 /* First time through, so create a child EState */
3005 EvalPlanQualStart(epqstate, epqstate->plan);
3006 }
3007 else
3008 {
3009 /*
3010 * We already have a suitable child EPQ tree, so just reset it.
3011 */
3012 Index rtsize = parentestate->es_range_table_size;
3014
3015 /*
3016 * Reset the relsubs_done[] flags to equal relsubs_blocked[], so that
3017 * the EPQ run will never attempt to fetch tuples from blocked target
3018 * relations.
3019 */
3020 memcpy(epqstate->relsubs_done, epqstate->relsubs_blocked,
3021 rtsize * sizeof(bool));
3022
3023 /* Recopy current values of parent parameters */
3024 if (parentestate->es_plannedstmt->paramExecTypes != NIL)
3025 {
3026 int i;
3027
3028 /*
3029 * Force evaluation of any InitPlan outputs that could be needed
3030 * by the subplan, just in case they got reset since
3031 * EvalPlanQualStart (see comments therein).
3032 */
3033 ExecSetParamPlanMulti(rcplanstate->plan->extParam,
3034 GetPerTupleExprContext(parentestate));
3035
3036 i = list_length(parentestate->es_plannedstmt->paramExecTypes);
3037
3038 while (--i >= 0)
3039 {
3040 /* copy value if any, but not execPlan link */
3041 recheckestate->es_param_exec_vals[i].value =
3042 parentestate->es_param_exec_vals[i].value;
3043 recheckestate->es_param_exec_vals[i].isnull =
3044 parentestate->es_param_exec_vals[i].isnull;
3045 }
3046 }
3047
3048 /*
3049 * Mark child plan tree as needing rescan at all scan nodes. The
3050 * first ExecProcNode will take care of actually doing the rescan.
3051 */
3052 rcplanstate->chgParam = bms_add_member(rcplanstate->chgParam,
3053 epqstate->epqParam);
3054 }
3055}
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:799
unsigned int Index
Definition c.h:757
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
static void EvalPlanQualStart(EPQState *epqstate, Plan *planTree)
Definition execMain.c:3064
#define GetPerTupleExprContext(estate)
Definition executor.h:665
int i
Definition isn.c:77
void ExecSetParamPlanMulti(const Bitmapset *params, ExprContext *econtext)
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
Plan * plan
Definition execnodes.h:1358
int epqParam
Definition execnodes.h:1341
EState * parentestate
Definition execnodes.h:1340
EState * recheckestate
Definition execnodes.h:1372
PlanState * recheckplanstate
Definition execnodes.h:1397
PlannedStmt * es_plannedstmt
Definition execnodes.h:706
ParamExecData * es_param_exec_vals
Definition execnodes.h:742
Index es_range_table_size
Definition execnodes.h:700
bool isnull
Definition params.h:149
Datum value
Definition params.h:148
List * paramExecTypes
Definition plannodes.h:150

References bms_add_member(), EPQState::epqParam, EState::es_param_exec_vals, EState::es_plannedstmt, EState::es_range_table_size, EvalPlanQualStart(), ExecSetParamPlanMulti(), fb(), GetPerTupleExprContext, i, ParamExecData::isnull, list_length(), memcpy(), NIL, PlannedStmt::paramExecTypes, EPQState::parentestate, 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 3245 of file execMain.c.

3246{
3247 EState *estate = epqstate->recheckestate;
3248 Index rtsize;
3249 MemoryContext oldcontext;
3250 ListCell *l;
3251
3253
3254 /*
3255 * We may have a tuple table, even if EPQ wasn't started, because we allow
3256 * use of EvalPlanQualSlot() without calling EvalPlanQualBegin().
3257 */
3258 if (epqstate->tuple_table != NIL)
3259 {
3260 memset(epqstate->relsubs_slot, 0,
3261 rtsize * sizeof(TupleTableSlot *));
3262 ExecResetTupleTable(epqstate->tuple_table, true);
3263 epqstate->tuple_table = NIL;
3264 }
3265
3266 /* EPQ wasn't started, nothing further to do */
3267 if (estate == NULL)
3268 return;
3269
3270 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
3271
3272 ExecEndNode(epqstate->recheckplanstate);
3273
3274 foreach(l, estate->es_subplanstates)
3275 {
3277
3279 }
3280
3281 /* throw away the per-estate tuple table, some node may have used it */
3282 ExecResetTupleTable(estate->es_tupleTable, false);
3283
3284 /* Close any result and trigger target relations attached to this EState */
3286
3287 MemoryContextSwitchTo(oldcontext);
3288
3289 /*
3290 * NULLify the partition directory before freeing the executor state.
3291 * Since EvalPlanQualStart() just borrowed the parent EState's directory,
3292 * we'd better leave it up to the parent to delete it.
3293 */
3294 estate->es_partition_directory = NULL;
3295
3296 FreeExecutorState(estate);
3297
3298 /* Mark EPQState idle */
3299 epqstate->origslot = NULL;
3300 epqstate->recheckestate = NULL;
3301 epqstate->recheckplanstate = NULL;
3302 epqstate->relsubs_rowmark = NULL;
3303 epqstate->relsubs_done = NULL;
3304 epqstate->relsubs_blocked = NULL;
3305}
void ExecCloseResultRelations(EState *estate)
Definition execMain.c:1641
void ExecEndNode(PlanState *node)
void ExecResetTupleTable(List *tupleTable, bool shouldFree)
void FreeExecutorState(EState *estate)
Definition execUtils.c:197
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
#define lfirst(lc)
Definition pg_list.h:172
ExecAuxRowMark ** relsubs_rowmark
Definition execnodes.h:1379
TupleTableSlot * origslot
Definition execnodes.h:1367
TupleTableSlot ** relsubs_slot
Definition execnodes.h:1351
List * tuple_table
Definition execnodes.h:1350
MemoryContext es_query_cxt
Definition execnodes.h:747
List * es_tupleTable
Definition execnodes.h:749
PartitionDirectory es_partition_directory
Definition execnodes.h:729
List * es_subplanstates
Definition execnodes.h:762

References EState::es_partition_directory, EState::es_query_cxt, EState::es_range_table_size, EState::es_subplanstates, EState::es_tupleTable, ExecCloseResultRelations(), ExecEndNode(), ExecResetTupleTable(), fb(), 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 2870 of file execMain.c.

2871{
2872 ExecAuxRowMark *earm = epqstate->relsubs_rowmark[rti - 1];
2874 Datum datum;
2875 bool isNull;
2876
2877 Assert(earm != NULL);
2878 Assert(epqstate->origslot != NULL);
2879
2880 erm = earm->rowmark;
2881
2882 if (RowMarkRequiresRowShareLock(erm->markType))
2883 elog(ERROR, "EvalPlanQual doesn't support locking rowmarks");
2884
2885 /* if child rel, must check whether it produced this row */
2886 if (erm->rti != erm->prti)
2887 {
2888 Oid tableoid;
2889
2890 datum = ExecGetJunkAttribute(epqstate->origslot,
2891 earm->toidAttNo,
2892 &isNull);
2893 /* non-locked rels could be on the inside of outer joins */
2894 if (isNull)
2895 return false;
2896
2897 tableoid = DatumGetObjectId(datum);
2898
2899 Assert(OidIsValid(erm->relid));
2900 if (tableoid != erm->relid)
2901 {
2902 /* this child is inactive right now */
2903 return false;
2904 }
2905 }
2906
2907 if (erm->markType == ROW_MARK_REFERENCE)
2908 {
2909 Assert(erm->relation != NULL);
2910
2911 /* fetch the tuple's ctid */
2912 datum = ExecGetJunkAttribute(epqstate->origslot,
2913 earm->ctidAttNo,
2914 &isNull);
2915 /* non-locked rels could be on the inside of outer joins */
2916 if (isNull)
2917 return false;
2918
2919 /* fetch requests on foreign tables must be passed to their FDW */
2920 if (erm->relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
2921 {
2922 FdwRoutine *fdwroutine;
2923 bool updated = false;
2924
2925 fdwroutine = GetFdwRoutineForRelation(erm->relation, false);
2926 /* this should have been checked already, but let's be safe */
2927 if (fdwroutine->RefetchForeignRow == NULL)
2928 ereport(ERROR,
2930 errmsg("cannot lock rows in foreign table \"%s\"",
2931 RelationGetRelationName(erm->relation))));
2932
2933 fdwroutine->RefetchForeignRow(epqstate->recheckestate,
2934 erm,
2935 datum,
2936 slot,
2937 &updated);
2938 if (TupIsNull(slot))
2939 elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
2940
2941 /*
2942 * Ideally we'd insist on updated == false here, but that assumes
2943 * that FDWs can track that exactly, which they might not be able
2944 * to. So just ignore the flag.
2945 */
2946 return true;
2947 }
2948 else
2949 {
2950 /* ordinary table, fetch the tuple */
2951 if (!table_tuple_fetch_row_version(erm->relation,
2953 SnapshotAny, slot))
2954 elog(ERROR, "failed to fetch tuple for EvalPlanQual recheck");
2955 return true;
2956 }
2957 }
2958 else
2959 {
2960 Assert(erm->markType == ROW_MARK_COPY);
2961
2962 /* fetch the whole-row Var for the relation */
2963 datum = ExecGetJunkAttribute(epqstate->origslot,
2964 earm->wholeAttNo,
2965 &isNull);
2966 /* non-locked rels could be on the inside of outer joins */
2967 if (isNull)
2968 return false;
2969
2970 ExecStoreHeapTupleDatum(datum, slot);
2971 return true;
2972 }
2973}
#define OidIsValid(objectId)
Definition c.h:917
void ExecStoreHeapTupleDatum(Datum data, TupleTableSlot *slot)
static Datum ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno, bool *isNull)
Definition executor.h:226
#define RowMarkRequiresRowShareLock(marktype)
Definition plannodes.h:1565
@ ROW_MARK_COPY
Definition plannodes.h:1562
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
unsigned int Oid
#define SnapshotAny
Definition snapmgr.h:33
static bool table_tuple_fetch_row_version(Relation rel, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot)
Definition tableam.h:1344

References Assert, DatumGetObjectId(), DatumGetPointer(), elog, ereport, errcode(), errmsg, ERROR, ExecGetJunkAttribute(), ExecStoreHeapTupleDatum(), fb(), GetFdwRoutineForRelation(), OidIsValid, EPQState::origslot, EPQState::recheckestate, FdwRoutine::RefetchForeignRow, RelationGetRelationName, EPQState::relsubs_rowmark, ROW_MARK_COPY, ROW_MARK_REFERENCE, RowMarkRequiresRowShareLock, SnapshotAny, table_tuple_fetch_row_version(), and TupIsNull.

Referenced by ExecScanFetch().

◆ EvalPlanQualInit()

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

Definition at line 2784 of file execMain.c.

2787{
2788 Index rtsize = parentestate->es_range_table_size;
2789
2790 /* initialize data not changing over EPQState's lifetime */
2791 epqstate->parentestate = parentestate;
2792 epqstate->epqParam = epqParam;
2793 epqstate->resultRelations = resultRelations;
2794
2795 /*
2796 * Allocate space to reference a slot for each potential rti - do so now
2797 * rather than in EvalPlanQualBegin(), as done for other dynamically
2798 * allocated resources, so EvalPlanQualSlot() can be used to hold tuples
2799 * that *may* need EPQ later, without forcing the overhead of
2800 * EvalPlanQualBegin().
2801 */
2802 epqstate->tuple_table = NIL;
2804
2805 /* ... and remember data that EvalPlanQualBegin will need */
2806 epqstate->plan = subplan;
2807 epqstate->arowMarks = auxrowmarks;
2808
2809 /* ... and mark the EPQ state inactive */
2810 epqstate->origslot = NULL;
2811 epqstate->recheckestate = NULL;
2812 epqstate->recheckplanstate = NULL;
2813 epqstate->relsubs_rowmark = NULL;
2814 epqstate->relsubs_done = NULL;
2815 epqstate->relsubs_blocked = NULL;
2816}
#define palloc0_array(type, count)
Definition fe_memutils.h:92
List * resultRelations
Definition execnodes.h:1342
List * arowMarks
Definition execnodes.h:1359

References EPQState::arowMarks, EPQState::epqParam, EState::es_range_table_size, fb(), NIL, EPQState::origslot, palloc0_array, 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 2981 of file execMain.c.

2982{
2983 MemoryContext oldcontext;
2984 TupleTableSlot *slot;
2985
2986 oldcontext = MemoryContextSwitchTo(epqstate->recheckestate->es_query_cxt);
2987 slot = ExecProcNode(epqstate->recheckplanstate);
2988 MemoryContextSwitchTo(oldcontext);
2989
2990 return slot;
2991}
static TupleTableSlot * ExecProcNode(PlanState *node)
Definition executor.h:322

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 2825 of file execMain.c.

2826{
2827 /* If we have a live EPQ query, shut it down */
2828 EvalPlanQualEnd(epqstate);
2829 /* And set/change the plan pointer */
2830 epqstate->plan = subplan;
2831 /* The rowmarks depend on the plan, too */
2832 epqstate->arowMarks = auxrowmarks;
2833}
void EvalPlanQualEnd(EPQState *epqstate)
Definition execMain.c:3245

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

Referenced by ExecInitModifyTable().

◆ EvalPlanQualSlot()

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

Definition at line 2842 of file execMain.c.

2844{
2845 TupleTableSlot **slot;
2846
2847 Assert(relation);
2848 Assert(rti > 0 && rti <= epqstate->parentestate->es_range_table_size);
2849 slot = &epqstate->relsubs_slot[rti - 1];
2850
2851 if (*slot == NULL)
2852 {
2853 MemoryContext oldcontext;
2854
2855 oldcontext = MemoryContextSwitchTo(epqstate->parentestate->es_query_cxt);
2856 *slot = table_slot_create(relation, &epqstate->tuple_table);
2857 MemoryContextSwitchTo(oldcontext);
2858 }
2859
2860 return *slot;
2861}
TupleTableSlot * table_slot_create(Relation relation, List **reglist)
Definition tableam.c:92

References Assert, EState::es_query_cxt, fb(), 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 3064 of file execMain.c.

3065{
3066 EState *parentestate = epqstate->parentestate;
3067 Index rtsize = parentestate->es_range_table_size;
3069 MemoryContext oldcontext;
3070 ListCell *l;
3071
3073
3074 oldcontext = MemoryContextSwitchTo(rcestate->es_query_cxt);
3075
3076 /* signal that this is an EState for executing EPQ */
3077 rcestate->es_epq_active = epqstate;
3078
3079 /*
3080 * Child EPQ EStates share the parent's copy of unchanging state such as
3081 * the snapshot, rangetable, and external Param info. They need their own
3082 * copies of local state, including a tuple table, es_param_exec_vals,
3083 * result-rel info, etc.
3084 */
3085 rcestate->es_direction = ForwardScanDirection;
3086 rcestate->es_snapshot = parentestate->es_snapshot;
3087 rcestate->es_crosscheck_snapshot = parentestate->es_crosscheck_snapshot;
3088 rcestate->es_range_table = parentestate->es_range_table;
3089 rcestate->es_range_table_size = parentestate->es_range_table_size;
3090 rcestate->es_relations = parentestate->es_relations;
3091 rcestate->es_rowmarks = parentestate->es_rowmarks;
3092 rcestate->es_rteperminfos = parentestate->es_rteperminfos;
3093 rcestate->es_plannedstmt = parentestate->es_plannedstmt;
3094 rcestate->es_junkFilter = parentestate->es_junkFilter;
3095 rcestate->es_output_cid = parentestate->es_output_cid;
3096 rcestate->es_queryEnv = parentestate->es_queryEnv;
3097
3098 /*
3099 * ResultRelInfos needed by subplans are initialized from scratch when the
3100 * subplans themselves are initialized.
3101 */
3102 rcestate->es_result_relations = NULL;
3103 /* es_trig_target_relations must NOT be copied */
3104 rcestate->es_top_eflags = parentestate->es_top_eflags;
3105 rcestate->es_instrument = parentestate->es_instrument;
3106 /* es_auxmodifytables must NOT be copied */
3107
3108 /*
3109 * The external param list is simply shared from parent. The internal
3110 * param workspace has to be local state, but we copy the initial values
3111 * from the parent, so as to have access to any param values that were
3112 * already set from other parts of the parent's plan tree.
3113 */
3114 rcestate->es_param_list_info = parentestate->es_param_list_info;
3115 if (parentestate->es_plannedstmt->paramExecTypes != NIL)
3116 {
3117 int i;
3118
3119 /*
3120 * Force evaluation of any InitPlan outputs that could be needed by
3121 * the subplan. (With more complexity, maybe we could postpone this
3122 * till the subplan actually demands them, but it doesn't seem worth
3123 * the trouble; this is a corner case already, since usually the
3124 * InitPlans would have been evaluated before reaching EvalPlanQual.)
3125 *
3126 * This will not touch output params of InitPlans that occur somewhere
3127 * within the subplan tree, only those that are attached to the
3128 * ModifyTable node or above it and are referenced within the subplan.
3129 * That's OK though, because the planner would only attach such
3130 * InitPlans to a lower-level SubqueryScan node, and EPQ execution
3131 * will not descend into a SubqueryScan.
3132 *
3133 * The EState's per-output-tuple econtext is sufficiently short-lived
3134 * for this, since it should get reset before there is any chance of
3135 * doing EvalPlanQual again.
3136 */
3138 GetPerTupleExprContext(parentestate));
3139
3140 /* now make the internal param workspace ... */
3141 i = list_length(parentestate->es_plannedstmt->paramExecTypes);
3142 rcestate->es_param_exec_vals = palloc0_array(ParamExecData, i);
3143 /* ... and copy down all values, whether really needed or not */
3144 while (--i >= 0)
3145 {
3146 /* copy value if any, but not execPlan link */
3147 rcestate->es_param_exec_vals[i].value =
3148 parentestate->es_param_exec_vals[i].value;
3149 rcestate->es_param_exec_vals[i].isnull =
3150 parentestate->es_param_exec_vals[i].isnull;
3151 }
3152 }
3153
3154 /*
3155 * Copy es_unpruned_relids so that pruned relations are ignored by
3156 * ExecInitLockRows() and ExecInitModifyTable() when initializing the plan
3157 * trees below.
3158 */
3159 rcestate->es_unpruned_relids = parentestate->es_unpruned_relids;
3160
3161 /*
3162 * Also make the PartitionPruneInfo and the results of pruning available.
3163 * These need to match exactly so that we initialize all the same Append
3164 * and MergeAppend subplans as the parent did.
3165 */
3166 rcestate->es_part_prune_infos = parentestate->es_part_prune_infos;
3167 rcestate->es_part_prune_states = parentestate->es_part_prune_states;
3168 rcestate->es_part_prune_results = parentestate->es_part_prune_results;
3169
3170 /* We'll also borrow the es_partition_directory from the parent state */
3171 rcestate->es_partition_directory = parentestate->es_partition_directory;
3172
3173 /*
3174 * Initialize private state information for each SubPlan. We must do this
3175 * before running ExecInitNode on the main query tree, since
3176 * ExecInitSubPlan expects to be able to find these entries. Some of the
3177 * SubPlans might not be used in the part of the plan tree we intend to
3178 * run, but since it's not easy to tell which, we just initialize them
3179 * all.
3180 */
3181 Assert(rcestate->es_subplanstates == NIL);
3182 foreach(l, parentestate->es_plannedstmt->subplans)
3183 {
3184 Plan *subplan = (Plan *) lfirst(l);
3186
3187 subplanstate = ExecInitNode(subplan, rcestate, 0);
3188 rcestate->es_subplanstates = lappend(rcestate->es_subplanstates,
3189 subplanstate);
3190 }
3191
3192 /*
3193 * Build an RTI indexed array of rowmarks, so that
3194 * EvalPlanQualFetchRowMark() can efficiently access the to be fetched
3195 * rowmark.
3196 */
3198 foreach(l, epqstate->arowMarks)
3199 {
3201
3202 epqstate->relsubs_rowmark[earm->rowmark->rti - 1] = earm;
3203 }
3204
3205 /*
3206 * Initialize per-relation EPQ tuple states. Result relations, if any,
3207 * get marked as blocked; others as not-fetched.
3208 */
3209 epqstate->relsubs_done = palloc_array(bool, rtsize);
3210 epqstate->relsubs_blocked = palloc0_array(bool, rtsize);
3211
3212 foreach(l, epqstate->resultRelations)
3213 {
3214 int rtindex = lfirst_int(l);
3215
3216 Assert(rtindex > 0 && rtindex <= rtsize);
3217 epqstate->relsubs_blocked[rtindex - 1] = true;
3218 }
3219
3220 memcpy(epqstate->relsubs_done, epqstate->relsubs_blocked,
3221 rtsize * sizeof(bool));
3222
3223 /*
3224 * Initialize the private state information for all the nodes in the part
3225 * of the plan tree we need to run. This opens files, allocates storage
3226 * and leaves us ready to start processing tuples.
3227 */
3228 epqstate->recheckplanstate = ExecInitNode(planTree, rcestate, 0);
3229
3230 MemoryContextSwitchTo(oldcontext);
3231}
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
EState * CreateExecutorState(void)
Definition execUtils.c:90
#define palloc_array(type, count)
Definition fe_memutils.h:91
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:707
int es_top_eflags
Definition execnodes.h:756
int es_instrument
Definition execnodes.h:757
QueryEnvironment * es_queryEnv
Definition execnodes.h:744
List * es_range_table
Definition execnodes.h:699
List * es_rteperminfos
Definition execnodes.h:705
Bitmapset * es_unpruned_relids
Definition execnodes.h:710
List * es_part_prune_states
Definition execnodes.h:708
ParamListInfo es_param_list_info
Definition execnodes.h:741
ExecRowMark ** es_rowmarks
Definition execnodes.h:703
Relation * es_relations
Definition execnodes.h:701
CommandId es_output_cid
Definition execnodes.h:719
Snapshot es_snapshot
Definition execnodes.h:697
JunkFilter * es_junkFilter
Definition execnodes.h:716
List * es_part_prune_results
Definition execnodes.h:709
Snapshot es_crosscheck_snapshot
Definition execnodes.h:698
Bitmapset * extParam
Definition plannodes.h:255
List * subplans
Definition plannodes.h:129

References EPQState::arowMarks, Assert, CreateExecutorState(), EState::es_crosscheck_snapshot, 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_queryEnv, EState::es_range_table, EState::es_range_table_size, EState::es_relations, EState::es_rowmarks, EState::es_rteperminfos, EState::es_snapshot, EState::es_top_eflags, EState::es_unpruned_relids, ExecInitNode(), ExecSetParamPlanMulti(), Plan::extParam, fb(), ForwardScanDirection, GetPerTupleExprContext, i, ParamExecData::isnull, lappend(), lfirst, lfirst_int, list_length(), memcpy(), MemoryContextSwitchTo(), NIL, palloc0_array, palloc_array, PlannedStmt::paramExecTypes, EPQState::parentestate, EPQState::recheckestate, EPQState::recheckplanstate, EPQState::relsubs_blocked, EPQState::relsubs_done, EPQState::relsubs_rowmark, EPQState::resultRelations, PlannedStmt::subplans, and ParamExecData::value.

Referenced by EvalPlanQualBegin().

◆ ExecBuildAuxRowMark()

ExecAuxRowMark * ExecBuildAuxRowMark ( ExecRowMark erm,
List targetlist 
)

Definition at line 2645 of file execMain.c.

2646{
2648 char resname[32];
2649
2650 aerm->rowmark = erm;
2651
2652 /* Look up the resjunk columns associated with this rowmark */
2653 if (erm->markType != ROW_MARK_COPY)
2654 {
2655 /* need ctid for all methods other than COPY */
2656 snprintf(resname, sizeof(resname), "ctid%u", erm->rowmarkId);
2657 aerm->ctidAttNo = ExecFindJunkAttributeInTlist(targetlist,
2658 resname);
2659 if (!AttributeNumberIsValid(aerm->ctidAttNo))
2660 elog(ERROR, "could not find junk %s column", resname);
2661 }
2662 else
2663 {
2664 /* need wholerow if COPY */
2665 snprintf(resname, sizeof(resname), "wholerow%u", erm->rowmarkId);
2666 aerm->wholeAttNo = ExecFindJunkAttributeInTlist(targetlist,
2667 resname);
2668 if (!AttributeNumberIsValid(aerm->wholeAttNo))
2669 elog(ERROR, "could not find junk %s column", resname);
2670 }
2671
2672 /* if child rel, need tableoid */
2673 if (erm->rti != erm->prti)
2674 {
2675 snprintf(resname, sizeof(resname), "tableoid%u", erm->rowmarkId);
2676 aerm->toidAttNo = ExecFindJunkAttributeInTlist(targetlist,
2677 resname);
2678 if (!AttributeNumberIsValid(aerm->toidAttNo))
2679 elog(ERROR, "could not find junk %s column", resname);
2680 }
2681
2682 return aerm;
2683}
#define AttributeNumberIsValid(attributeNumber)
Definition attnum.h:34
AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
Definition execJunk.c:222
#define palloc0_object(type)
Definition fe_memutils.h:90
#define snprintf
Definition port.h:261

References AttributeNumberIsValid, elog, ERROR, ExecFindJunkAttributeInTlist(), fb(), palloc0_object, ROW_MARK_COPY, and snprintf.

Referenced by ExecInitLockRows(), and ExecInitModifyTable().

◆ ExecBuildSlotValueDescription()

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

Definition at line 2457 of file execMain.c.

2462{
2465 bool write_comma = false;
2466 bool write_comma_collist = false;
2467 int i;
2469 bool table_perm = false;
2470 bool any_perm = false;
2471
2472 /*
2473 * Check if RLS is enabled and should be active for the relation; if so,
2474 * then don't return anything. Otherwise, go through normal permission
2475 * checks.
2476 */
2477 if (check_enable_rls(reloid, InvalidOid, true) == RLS_ENABLED)
2478 return NULL;
2479
2481
2483
2484 /*
2485 * Check if the user has permissions to see the row. Table-level SELECT
2486 * allows access to all columns. If the user does not have table-level
2487 * SELECT then we check each column and include those the user has SELECT
2488 * rights on. Additionally, we always include columns the user provided
2489 * data for.
2490 */
2492 if (aclresult != ACLCHECK_OK)
2493 {
2494 /* Set up the buffer for the column list */
2497 }
2498 else
2499 table_perm = any_perm = true;
2500
2501 /* Make sure the tuple is fully deconstructed */
2502 slot_getallattrs(slot);
2503
2504 for (i = 0; i < tupdesc->natts; i++)
2505 {
2506 bool column_perm = false;
2507 char *val;
2508 int vallen;
2509 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
2510
2511 /* ignore dropped columns */
2512 if (att->attisdropped)
2513 continue;
2514
2515 if (!table_perm)
2516 {
2517 /*
2518 * No table-level SELECT, so need to make sure they either have
2519 * SELECT rights on the column or that they have provided the data
2520 * for the column. If not, omit this column from the error
2521 * message.
2522 */
2523 aclresult = pg_attribute_aclcheck(reloid, att->attnum,
2527 {
2528 column_perm = any_perm = true;
2529
2532 else
2533 write_comma_collist = true;
2534
2535 appendStringInfoString(&collist, NameStr(att->attname));
2536 }
2537 }
2538
2539 if (table_perm || column_perm)
2540 {
2541 if (att->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
2542 val = "virtual";
2543 else if (slot->tts_isnull[i])
2544 val = "null";
2545 else
2546 {
2547 Oid foutoid;
2548 bool typisvarlena;
2549
2550 getTypeOutputInfo(att->atttypid,
2551 &foutoid, &typisvarlena);
2553 }
2554
2555 if (write_comma)
2557 else
2558 write_comma = true;
2559
2560 /* truncate if needed */
2561 vallen = strlen(val);
2562 if (vallen <= maxfieldlen)
2563 appendBinaryStringInfo(&buf, val, vallen);
2564 else
2565 {
2566 vallen = pg_mbcliplen(val, vallen, maxfieldlen);
2567 appendBinaryStringInfo(&buf, val, vallen);
2568 appendStringInfoString(&buf, "...");
2569 }
2570 }
2571 }
2572
2573 /* If we end up with zero columns being returned, then return NULL. */
2574 if (!any_perm)
2575 return NULL;
2576
2578
2579 if (!table_perm)
2580 {
2583
2584 return collist.data;
2585 }
2586
2587 return buf.data;
2588}
AclResult
Definition acl.h:183
@ ACLCHECK_OK
Definition acl.h:184
AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mode)
Definition aclchk.c:3934
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition aclchk.c:4105
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:510
#define NameStr(name)
Definition c.h:894
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition fmgr.c:1764
long val
Definition informix.c:689
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition lsyscache.c:3215
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition mbutils.c:1212
Oid GetUserId(void)
Definition miscinit.c:470
#define ACL_SELECT
Definition parsenodes.h:77
FormData_pg_attribute * Form_pg_attribute
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define InvalidOid
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:133
Datum * tts_values
Definition tuptable.h:131
#define FirstLowInvalidHeapAttributeNumber
Definition sysattr.h:27
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:178
static void slot_getallattrs(TupleTableSlot *slot)
Definition tuptable.h:390

References ACL_SELECT, ACLCHECK_OK, appendBinaryStringInfo(), appendStringInfoChar(), appendStringInfoString(), bms_is_member(), buf, check_enable_rls(), fb(), 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 ExecConstraints(), ExecPartitionCheckEmitError(), ExecWithCheckOptions(), get_tuple_desc(), and ReportNotNullViolationError().

◆ ExecCheckOneRelPerms()

bool ExecCheckOneRelPerms ( RTEPermissionInfo perminfo)

Definition at line 657 of file execMain.c.

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

References ACL_INSERT, ACL_SELECT, ACL_UPDATE, ACLCHECK_OK, ACLMASK_ALL, ACLMASK_ANY, Assert, bms_is_empty, bms_next_member(), ExecCheckPermissionsModified(), fb(), FirstLowInvalidHeapAttributeNumber, GetUserId(), InvalidAttrNumber, OidIsValid, pg_attribute_aclcheck(), pg_attribute_aclcheck_all(), and pg_class_aclmask().

Referenced by ExecCheckPermissions(), and subquery_planner().

◆ ExecCheckPermissions()

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

Definition at line 593 of file execMain.c.

595{
596 ListCell *l;
597 bool result = true;
598
599#ifdef USE_ASSERT_CHECKING
601
602 /* Check that rteperminfos is consistent with rangeTable */
603 foreach(l, rangeTable)
604 {
606
607 if (rte->perminfoindex != 0)
608 {
609 /* Sanity checks */
610
611 /*
612 * Only relation RTEs and subquery RTEs that were once relation
613 * RTEs (views, property graphs) have their perminfoindex set.
614 */
615 Assert(rte->rtekind == RTE_RELATION ||
616 (rte->rtekind == RTE_SUBQUERY &&
617 (rte->relkind == RELKIND_VIEW || rte->relkind == RELKIND_PROPGRAPH)));
618
619 (void) getRTEPermissionInfo(rteperminfos, rte);
620 /* Many-to-one mapping not allowed */
621 Assert(!bms_is_member(rte->perminfoindex, indexset));
622 indexset = bms_add_member(indexset, rte->perminfoindex);
623 }
624 }
625
626 /* All rteperminfos are referenced */
627 Assert(bms_num_members(indexset) == list_length(rteperminfos));
628#endif
629
630 foreach(l, rteperminfos)
631 {
633
634 Assert(OidIsValid(perminfo->relid));
636 if (!result)
637 {
638 if (ereport_on_violation)
641 get_rel_name(perminfo->relid));
642 return false;
643 }
644 }
645
647 result = (*ExecutorCheckPerms_hook) (rangeTable, rteperminfos,
648 ereport_on_violation);
649 return result;
650}
@ ACLCHECK_NO_PRIV
Definition acl.h:185
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
int bms_num_members(const Bitmapset *a)
Definition bitmapset.c:744
uint32 result
ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook
Definition execMain.c:76
bool ExecCheckOneRelPerms(RTEPermissionInfo *perminfo)
Definition execMain.c:657
char * get_rel_name(Oid relid)
Definition lsyscache.c:2234
char get_rel_relkind(Oid relid)
Definition lsyscache.c:2309
ObjectType get_relkind_objtype(char relkind)
RTEPermissionInfo * getRTEPermissionInfo(List *rteperminfos, RangeTblEntry *rte)
@ RTE_SUBQUERY
@ RTE_RELATION
#define lfirst_node(type, lc)
Definition pg_list.h:176

References aclcheck_error(), ACLCHECK_NO_PRIV, Assert, bms_add_member(), bms_is_member(), bms_num_members(), ExecCheckOneRelPerms(), ExecutorCheckPerms_hook, fb(), get_rel_name(), get_rel_relkind(), get_relkind_objtype(), getRTEPermissionInfo(), lfirst_node, list_length(), OidIsValid, result, RTE_RELATION, and RTE_SUBQUERY.

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

◆ ExecCheckPermissionsModified()

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

Definition at line 766 of file execMain.c.

768{
769 int col = -1;
770
771 /*
772 * When the query doesn't explicitly update any columns, allow the query
773 * if we have permission on any column of the rel. This is to handle
774 * SELECT FOR UPDATE as well as possible corner cases in UPDATE.
775 */
777 {
778 if (pg_attribute_aclcheck_all(relOid, userid, requiredPerms,
780 return false;
781 }
782
783 while ((col = bms_next_member(modifiedCols, col)) >= 0)
784 {
785 /* bit #s are offset by FirstLowInvalidHeapAttributeNumber */
787
788 if (attno == InvalidAttrNumber)
789 {
790 /* whole-row reference can't happen here */
791 elog(ERROR, "whole-row update is not implemented");
792 }
793 else
794 {
795 if (pg_attribute_aclcheck(relOid, attno, userid,
796 requiredPerms) != ACLCHECK_OK)
797 return false;
798 }
799 }
800 return true;
801}

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

Referenced by ExecCheckOneRelPerms().

◆ ExecCheckXactReadOnly()

static void ExecCheckXactReadOnly ( PlannedStmt plannedstmt)
static

Definition at line 813 of file execMain.c.

814{
815 ListCell *l;
816
817 /*
818 * Fail if write permissions are requested in parallel mode for table
819 * (temp or non-temp), otherwise fail for any non-temp table.
820 */
821 foreach(l, plannedstmt->permInfos)
822 {
824
825 if ((perminfo->requiredPerms & (~ACL_SELECT)) == 0)
826 continue;
827
829 continue;
830
832 }
833
834 if (plannedstmt->commandType != CMD_SELECT || plannedstmt->hasModifyingCTE)
836}
Oid get_rel_namespace(Oid relid)
Definition lsyscache.c:2258
bool isTempNamespace(Oid namespaceId)
Definition namespace.c:3721
@ CMD_SELECT
Definition nodes.h:273
Definition nodes.h:133
bool hasModifyingCTE
Definition plannodes.h:81
List * permInfos
Definition plannodes.h:118
CmdType commandType
Definition plannodes.h:66
void PreventCommandIfReadOnly(const char *cmdname)
Definition utility.c:409
void PreventCommandIfParallelMode(const char *cmdname)
Definition utility.c:427
static const char * CreateCommandName(Node *parsetree)
Definition utility.h:103

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

Referenced by standard_ExecutorStart().

◆ ExecCloseRangeTableRelations()

void ExecCloseRangeTableRelations ( EState estate)

Definition at line 1701 of file execMain.c.

1702{
1703 int i;
1704
1705 for (i = 0; i < estate->es_range_table_size; i++)
1706 {
1707 if (estate->es_relations[i])
1708 table_close(estate->es_relations[i], NoLock);
1709 }
1710}
#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 1641 of file execMain.c.

1642{
1643 ListCell *l;
1644
1645 /*
1646 * close indexes of result relation(s) if any. (Rels themselves are
1647 * closed in ExecCloseRangeTableRelations())
1648 *
1649 * In addition, close the stub RTs that may be in each resultrel's
1650 * ri_ancestorResultRels.
1651 */
1652 foreach(l, estate->es_opened_result_relations)
1653 {
1654 ResultRelInfo *resultRelInfo = lfirst(l);
1655 ListCell *lc;
1656
1657 ExecCloseIndices(resultRelInfo);
1658 foreach(lc, resultRelInfo->ri_ancestorResultRels)
1659 {
1661
1662 /*
1663 * Ancestors with RTI > 0 (should only be the root ancestor) are
1664 * closed by ExecCloseRangeTableRelations.
1665 */
1666 if (rInfo->ri_RangeTableIndex > 0)
1667 continue;
1668
1669 table_close(rInfo->ri_RelationDesc, NoLock);
1670 }
1671 }
1672
1673 /* Close any relations that have been opened by ExecGetTriggerResultRel(). */
1674 foreach(l, estate->es_trig_target_relations)
1675 {
1676 ResultRelInfo *resultRelInfo = (ResultRelInfo *) lfirst(l);
1677
1678 /*
1679 * Assert this is a "dummy" ResultRelInfo, see above. Otherwise we
1680 * might be issuing a duplicate close against a Relation opened by
1681 * ExecGetRangeTableRelation.
1682 */
1683 Assert(resultRelInfo->ri_RangeTableIndex == 0);
1684
1685 /*
1686 * Since ExecGetTriggerResultRel doesn't call ExecOpenIndices for
1687 * these rels, we needn't call ExecCloseIndices either.
1688 */
1689 Assert(resultRelInfo->ri_NumIndices == 0);
1690
1691 table_close(resultRelInfo->ri_RelationDesc, NoLock);
1692 }
1693}
void ExecCloseIndices(ResultRelInfo *resultRelInfo)
List * es_trig_target_relations
Definition execnodes.h:738
List * es_opened_result_relations
Definition execnodes.h:725
Index ri_RangeTableIndex
Definition execnodes.h:511
List * ri_ancestorResultRels
Definition execnodes.h:665

References Assert, EState::es_opened_result_relations, EState::es_trig_target_relations, ExecCloseIndices(), fb(), 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 2046 of file execMain.c.

2048{
2049 Relation rel = resultRelInfo->ri_RelationDesc;
2050 TupleDesc tupdesc = RelationGetDescr(rel);
2051 TupleConstr *constr = tupdesc->constr;
2054
2055 Assert(constr); /* we should not be called otherwise */
2056
2057 /*
2058 * Verify not-null constraints.
2059 *
2060 * Not-null constraints on virtual generated columns are collected and
2061 * checked separately below.
2062 */
2063 if (constr->has_not_null)
2064 {
2065 for (AttrNumber attnum = 1; attnum <= tupdesc->natts; attnum++)
2066 {
2067 Form_pg_attribute att = TupleDescAttr(tupdesc, attnum - 1);
2068
2069 if (att->attnotnull && att->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
2071 else if (att->attnotnull && slot_attisnull(slot, attnum))
2072 ReportNotNullViolationError(resultRelInfo, slot, estate, attnum);
2073 }
2074 }
2075
2076 /*
2077 * Verify not-null constraints on virtual generated column, if any.
2078 */
2080 {
2082
2083 attnum = ExecRelGenVirtualNotNull(resultRelInfo, slot, estate,
2086 ReportNotNullViolationError(resultRelInfo, slot, estate, attnum);
2087 }
2088
2089 /*
2090 * Verify check constraints.
2091 */
2092 if (rel->rd_rel->relchecks > 0)
2093 {
2094 const char *failed;
2095
2096 if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL)
2097 {
2098 char *val_desc;
2099 Relation orig_rel = rel;
2100
2101 /*
2102 * If the tuple has been routed, it's been converted to the
2103 * partition's rowtype, which might differ from the root table's.
2104 * We must convert it back to the root table's rowtype so that
2105 * val_desc shown error message matches the input tuple.
2106 */
2107 if (resultRelInfo->ri_RootResultRelInfo)
2108 {
2109 ResultRelInfo *rootrel = resultRelInfo->ri_RootResultRelInfo;
2111 AttrMap *map;
2112
2113 tupdesc = RelationGetDescr(rootrel->ri_RelationDesc);
2114 /* a reverse map */
2116 tupdesc,
2117 false);
2118
2119 /*
2120 * Partition-specific slot's tupdesc can't be changed, so
2121 * allocate a new one.
2122 */
2123 if (map != NULL)
2124 slot = execute_attr_map_slot(map, slot,
2125 MakeTupleTableSlot(tupdesc, &TTSOpsVirtual, 0));
2127 ExecGetUpdatedCols(rootrel, estate));
2128 rel = rootrel->ri_RelationDesc;
2129 }
2130 else
2131 modifiedCols = bms_union(ExecGetInsertedCols(resultRelInfo, estate),
2132 ExecGetUpdatedCols(resultRelInfo, estate));
2134 slot,
2135 tupdesc,
2137 64);
2138 ereport(ERROR,
2140 errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
2142 val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
2143 errtableconstraint(orig_rel, failed)));
2144 }
2145 }
2146}
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
static void ReportNotNullViolationError(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, int attnum)
Definition execMain.c:2225
char * ExecBuildSlotValueDescription(Oid reloid, TupleTableSlot *slot, TupleDesc tupdesc, Bitmapset *modifiedCols, int maxfieldlen)
Definition execMain.c:2457
AttrNumber ExecRelGenVirtualNotNull(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, List *notnull_virtual_attrs)
Definition execMain.c:2160
static const char * ExecRelCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate)
Definition execMain.c:1844
const TupleTableSlotOps TTSOpsVirtual
Definition execTuples.c:84
TupleTableSlot * MakeTupleTableSlot(TupleDesc tupleDesc, const TupleTableSlotOps *tts_ops, uint16 flags)
Bitmapset * ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
Definition execUtils.c:1387
Bitmapset * ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition execUtils.c:1408
List * lappend_int(List *list, int datum)
Definition list.c:357
int16 attnum
#define RelationGetRelid(relation)
Definition rel.h:516
#define RelationGetDescr(relation)
Definition rel.h:542
int errtableconstraint(Relation rel, const char *conname)
Definition relcache.c:6136
Definition pg_list.h:54
struct ResultRelInfo * ri_RootResultRelInfo
Definition execnodes.h:655
bool has_not_null
Definition tupdesc.h:45
TupleConstr * constr
Definition tupdesc.h:159
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:403

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(), fb(), 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 1602 of file execMain.c.

1603{
1604 ListCell *l;
1605
1606 /*
1607 * shut down the node-type-specific query processing
1608 */
1609 ExecEndNode(planstate);
1610
1611 /*
1612 * for subplans too
1613 */
1614 foreach(l, estate->es_subplanstates)
1615 {
1617
1619 }
1620
1621 /*
1622 * destroy the executor's tuple table. Actually we only care about
1623 * releasing buffer pins and tupdesc refcounts; there's no need to pfree
1624 * the TupleTableSlots, since the containing memory context is about to go
1625 * away anyway.
1626 */
1627 ExecResetTupleTable(estate->es_tupleTable, false);
1628
1629 /*
1630 * Close any Relations that have been opened for range table entries or
1631 * result relations.
1632 */
1635}
void ExecCloseRangeTableRelations(EState *estate)
Definition execMain.c:1701

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

Referenced by standard_ExecutorEnd().

◆ ExecFindRowMark()

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

Definition at line 2622 of file execMain.c.

2623{
2624 if (rti > 0 && rti <= estate->es_range_table_size &&
2625 estate->es_rowmarks != NULL)
2626 {
2627 ExecRowMark *erm = estate->es_rowmarks[rti - 1];
2628
2629 if (erm)
2630 return erm;
2631 }
2632 if (!missing_ok)
2633 elog(ERROR, "failed to find ExecRowMark for rangetable index %u", rti);
2634 return NULL;
2635}

References elog, ERROR, EState::es_rowmarks, and fb().

Referenced by ExecInitLockRows(), and ExecInitModifyTable().

◆ ExecGetAncestorResultRels()

List * ExecGetAncestorResultRels ( EState estate,
ResultRelInfo resultRelInfo 
)

Definition at line 1496 of file execMain.c.

1497{
1499 Relation partRel = resultRelInfo->ri_RelationDesc;
1501
1502 if (!partRel->rd_rel->relispartition)
1503 elog(ERROR, "cannot find ancestors of a non-partition result relation");
1505 rootRelOid = RelationGetRelid(rootRelInfo->ri_RelationDesc);
1506 if (resultRelInfo->ri_ancestorResultRels == NIL)
1507 {
1508 ListCell *lc;
1511
1512 foreach(lc, oids)
1513 {
1517
1518 /*
1519 * Ignore the root ancestor here, and use ri_RootResultRelInfo
1520 * (below) for it instead. Also, we stop climbing up the
1521 * hierarchy when we find the table that was mentioned in the
1522 * query.
1523 */
1524 if (ancOid == rootRelOid)
1525 break;
1526
1527 /*
1528 * All ancestors up to the root target relation must have been
1529 * locked by the planner or AcquireExecutorLocks().
1530 */
1533
1534 /* dummy rangetable index */
1536 estate->es_instrument);
1538 }
1540 resultRelInfo->ri_ancestorResultRels = ancResultRels;
1541 }
1542
1543 /* We must have found some ancestor */
1544 Assert(resultRelInfo->ri_ancestorResultRels != NIL);
1545
1546 return resultRelInfo->ri_ancestorResultRels;
1547}
void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, ResultRelInfo *partition_root_rri, int instrument_options)
Definition execMain.c:1308
#define makeNode(_type_)
Definition nodes.h:159
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, fb(), 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 1409 of file execMain.c.

1411{
1413 ListCell *l;
1414 Relation rel;
1415 MemoryContext oldcontext;
1416
1417 /*
1418 * Before creating a new ResultRelInfo, check if we've already made and
1419 * cached one for this relation. We must ensure that the given
1420 * 'rootRelInfo' matches the one stored in the cached ResultRelInfo as
1421 * trigger handling for partitions can result in mixed requirements for
1422 * what ri_RootResultRelInfo is set to.
1423 */
1424
1425 /* Search through the query result relations */
1426 foreach(l, estate->es_opened_result_relations)
1427 {
1428 rInfo = lfirst(l);
1429 if (RelationGetRelid(rInfo->ri_RelationDesc) == relid &&
1430 rInfo->ri_RootResultRelInfo == rootRelInfo)
1431 return rInfo;
1432 }
1433
1434 /*
1435 * Search through the result relations that were created during tuple
1436 * routing, if any.
1437 */
1438 foreach(l, estate->es_tuple_routing_result_relations)
1439 {
1440 rInfo = (ResultRelInfo *) lfirst(l);
1441 if (RelationGetRelid(rInfo->ri_RelationDesc) == relid &&
1442 rInfo->ri_RootResultRelInfo == rootRelInfo)
1443 return rInfo;
1444 }
1445
1446 /* Nope, but maybe we already made an extra ResultRelInfo for it */
1447 foreach(l, estate->es_trig_target_relations)
1448 {
1449 rInfo = (ResultRelInfo *) lfirst(l);
1450 if (RelationGetRelid(rInfo->ri_RelationDesc) == relid &&
1451 rInfo->ri_RootResultRelInfo == rootRelInfo)
1452 return rInfo;
1453 }
1454 /* Nope, so we need a new one */
1455
1456 /*
1457 * Open the target relation's relcache entry. We assume that an
1458 * appropriate lock is still held by the backend from whenever the trigger
1459 * event got queued, so we need take no new lock here. Also, we need not
1460 * recheck the relkind, so no need for CheckValidResultRel.
1461 */
1462 rel = table_open(relid, NoLock);
1463
1464 /*
1465 * Make the new entry in the right context.
1466 */
1467 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
1470 rel,
1471 0, /* dummy rangetable index */
1473 estate->es_instrument);
1474 estate->es_trig_target_relations =
1476 MemoryContextSwitchTo(oldcontext);
1477
1478 /*
1479 * Currently, we don't need any index information in ResultRelInfos used
1480 * only for triggers, so no need to call ExecOpenIndices.
1481 */
1482
1483 return rInfo;
1484}
List * es_tuple_routing_result_relations
Definition execnodes.h:735

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

Referenced by afterTriggerInvokeEvents().

◆ ExecPartitionCheck()

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

Definition at line 1922 of file execMain.c.

1924{
1925 ExprContext *econtext;
1926 bool success;
1927
1928 /*
1929 * If first time through, build expression state tree for the partition
1930 * check expression. (In the corner case where the partition check
1931 * expression is empty, ie there's a default partition and nothing else,
1932 * we'll be fooled into executing this code each time through. But it's
1933 * pretty darn cheap in that case, so we don't worry about it.)
1934 */
1935 if (resultRelInfo->ri_PartitionCheckExpr == NULL)
1936 {
1937 /*
1938 * Ensure that the qual tree and prepared expression are in the
1939 * query-lifespan context.
1940 */
1942 List *qual = RelationGetPartitionQual(resultRelInfo->ri_RelationDesc);
1943
1944 resultRelInfo->ri_PartitionCheckExpr = ExecPrepareCheck(qual, estate);
1946 }
1947
1948 /*
1949 * We will use the EState's per-tuple context for evaluating constraint
1950 * expressions (creating it if it's not already there).
1951 */
1952 econtext = GetPerTupleExprContext(estate);
1953
1954 /* Arrange for econtext's scan tuple to be the tuple under test */
1955 econtext->ecxt_scantuple = slot;
1956
1957 /*
1958 * As in case of the cataloged constraints, we treat a NULL result as
1959 * success here, not a failure.
1960 */
1961 success = ExecCheck(resultRelInfo->ri_PartitionCheckExpr, econtext);
1962
1963 /* if asked to emit error, don't actually return on failure */
1964 if (!success && emitError)
1965 ExecPartitionCheckEmitError(resultRelInfo, slot, estate);
1966
1967 return success;
1968}
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:1975
static bool success
Definition initdb.c:188
List * RelationGetPartitionQual(Relation rel)
Definition partcache.c:277
TupleTableSlot * ecxt_scantuple
Definition execnodes.h:287
ExprState * ri_PartitionCheckExpr
Definition execnodes.h:629

References ExprContext::ecxt_scantuple, EState::es_query_cxt, ExecCheck(), ExecPartitionCheckEmitError(), ExecPrepareCheck(), fb(), 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 1975 of file execMain.c.

1978{
1980 TupleDesc tupdesc;
1981 char *val_desc;
1983
1984 /*
1985 * If the tuple has been routed, it's been converted to the partition's
1986 * rowtype, which might differ from the root table's. We must convert it
1987 * back to the root table's rowtype so that val_desc in the error message
1988 * matches the input tuple.
1989 */
1990 if (resultRelInfo->ri_RootResultRelInfo)
1991 {
1992 ResultRelInfo *rootrel = resultRelInfo->ri_RootResultRelInfo;
1994 AttrMap *map;
1995
1996 root_relid = RelationGetRelid(rootrel->ri_RelationDesc);
1997 tupdesc = RelationGetDescr(rootrel->ri_RelationDesc);
1998
2000 /* a reverse map */
2001 map = build_attrmap_by_name_if_req(old_tupdesc, tupdesc, false);
2002
2003 /*
2004 * Partition-specific slot's tupdesc can't be changed, so allocate a
2005 * new one.
2006 */
2007 if (map != NULL)
2008 slot = execute_attr_map_slot(map, slot,
2009 MakeTupleTableSlot(tupdesc, &TTSOpsVirtual, 0));
2011 ExecGetUpdatedCols(rootrel, estate));
2012 }
2013 else
2014 {
2016 tupdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
2017 modifiedCols = bms_union(ExecGetInsertedCols(resultRelInfo, estate),
2018 ExecGetUpdatedCols(resultRelInfo, estate));
2019 }
2020
2022 slot,
2023 tupdesc,
2025 64);
2026 ereport(ERROR,
2028 errmsg("new row for relation \"%s\" violates partition constraint",
2030 val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
2031 errtable(resultRelInfo->ri_RelationDesc)));
2032}
int errtable(Relation rel)
Definition relcache.c:6082

References bms_union(), build_attrmap_by_name_if_req(), ereport, errcode(), errdetail(), errmsg, ERROR, errtable(), ExecBuildSlotValueDescription(), ExecGetInsertedCols(), ExecGetUpdatedCols(), execute_attr_map_slot(), fb(), 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 1556 of file execMain.c.

1557{
1558 ListCell *lc;
1559
1560 /*
1561 * Make sure nodes run forward.
1562 */
1564
1565 /*
1566 * Run any secondary ModifyTable nodes to completion, in case the main
1567 * query did not fetch all rows from them. (We do this to ensure that
1568 * such nodes have predictable results.)
1569 */
1570 foreach(lc, estate->es_auxmodifytables)
1571 {
1572 PlanState *ps = (PlanState *) lfirst(lc);
1573
1574 for (;;)
1575 {
1576 TupleTableSlot *slot;
1577
1578 /* Reset the per-output-tuple exprcontext each time */
1580
1581 slot = ExecProcNode(ps);
1582
1583 if (TupIsNull(slot))
1584 break;
1585 }
1586 }
1587}
#define ResetPerTupleExprContext(estate)
Definition executor.h:674
struct parser_state ps
ScanDirection es_direction
Definition execnodes.h:696
List * es_auxmodifytables
Definition execnodes.h:764

References EState::es_auxmodifytables, EState::es_direction, ExecProcNode(), fb(), 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 1844 of file execMain.c.

1846{
1847 Relation rel = resultRelInfo->ri_RelationDesc;
1848 int ncheck = rel->rd_att->constr->num_check;
1849 ConstrCheck *check = rel->rd_att->constr->check;
1850 ExprContext *econtext;
1852
1853 /*
1854 * CheckNNConstraintFetch let this pass with only a warning, but now we
1855 * should fail rather than possibly failing to enforce an important
1856 * constraint.
1857 */
1858 if (ncheck != rel->rd_rel->relchecks)
1859 elog(ERROR, "%d pg_constraint record(s) missing for relation \"%s\"",
1860 rel->rd_rel->relchecks - ncheck, RelationGetRelationName(rel));
1861
1862 /*
1863 * If first time through for this result relation, build expression
1864 * nodetrees for rel's constraint expressions. Keep them in the per-query
1865 * memory context so they'll survive throughout the query.
1866 */
1867 if (resultRelInfo->ri_CheckConstraintExprs == NULL)
1868 {
1870 resultRelInfo->ri_CheckConstraintExprs = palloc0_array(ExprState *, ncheck);
1871 for (int i = 0; i < ncheck; i++)
1872 {
1874
1875 /* Skip not enforced constraint */
1876 if (!check[i].ccenforced)
1877 continue;
1878
1879 checkconstr = stringToNode(check[i].ccbin);
1881 resultRelInfo->ri_CheckConstraintExprs[i] =
1883 }
1885 }
1886
1887 /*
1888 * We will use the EState's per-tuple context for evaluating constraint
1889 * expressions (creating it if it's not already there).
1890 */
1891 econtext = GetPerTupleExprContext(estate);
1892
1893 /* Arrange for econtext's scan tuple to be the tuple under test */
1894 econtext->ecxt_scantuple = slot;
1895
1896 /* And evaluate the constraints */
1897 for (int i = 0; i < ncheck; i++)
1898 {
1900
1901 /*
1902 * NOTE: SQL specifies that a NULL result from a constraint expression
1903 * is not to be treated as a failure. Therefore, use ExecCheck not
1904 * ExecQual.
1905 */
1906 if (checkconstr && !ExecCheck(checkconstr, econtext))
1907 return check[i].ccname;
1908 }
1909
1910 /* NULL result means no error */
1911 return NULL;
1912}
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:589
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(), fb(), 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 2160 of file execMain.c.

2162{
2163 Relation rel = resultRelInfo->ri_RelationDesc;
2164 ExprContext *econtext;
2166
2167 /*
2168 * We implement this by building a NullTest node for each virtual
2169 * generated column, which we cache in resultRelInfo, and running those
2170 * through ExecCheck().
2171 */
2172 if (resultRelInfo->ri_GenVirtualNotNullConstraintExprs == NULL)
2173 {
2177
2179 {
2182
2183 /* "generated_expression IS NOT NULL" check. */
2186 nnulltest->nulltesttype = IS_NOT_NULL;
2187 nnulltest->argisrow = false;
2188 nnulltest->location = -1;
2189
2190 resultRelInfo->ri_GenVirtualNotNullConstraintExprs[i] =
2191 ExecPrepareExpr((Expr *) nnulltest, estate);
2192 }
2194 }
2195
2196 /*
2197 * We will use the EState's per-tuple context for evaluating virtual
2198 * generated column not null constraint expressions (creating it if it's
2199 * not already there).
2200 */
2201 econtext = GetPerTupleExprContext(estate);
2202
2203 /* Arrange for econtext's scan tuple to be the tuple under test */
2204 econtext->ecxt_scantuple = slot;
2205
2206 /* And evaluate the check constraints for virtual generated column */
2208 {
2210 ExprState *exprstate = resultRelInfo->ri_GenVirtualNotNullConstraintExprs[i];
2211
2212 Assert(exprstate != NULL);
2213 if (!ExecCheck(exprstate, econtext))
2214 return attnum;
2215 }
2216
2217 /* InvalidAttrNumber result means no error */
2218 return InvalidAttrNumber;
2219}
#define foreach_current_index(var_or_cell)
Definition pg_list.h:435
#define foreach_int(var, lst)
Definition pg_list.h:502
@ IS_NOT_NULL
Definition primnodes.h:1973
Node * build_generation_expression(Relation rel, int attrno)
ExprState ** ri_GenVirtualNotNullConstraintExprs
Definition execnodes.h:595

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

Referenced by ATRewriteTable(), and ExecConstraints().

◆ ExecUpdateLockMode()

LockTupleMode ExecUpdateLockMode ( EState estate,
ResultRelInfo relinfo 
)

Definition at line 2596 of file execMain.c.

2597{
2599 Bitmapset *updatedCols;
2600
2601 /*
2602 * Compute lock mode to use. If columns that are part of the key have not
2603 * been modified, then we can use a weaker lock, allowing for better
2604 * concurrency.
2605 */
2606 updatedCols = ExecGetAllUpdatedCols(relinfo, estate);
2607 keyCols = RelationGetIndexAttrBitmap(relinfo->ri_RelationDesc,
2609
2610 if (bms_overlap(keyCols, updatedCols))
2611 return LockTupleExclusive;
2612
2614}
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:575
Bitmapset * ExecGetAllUpdatedCols(ResultRelInfo *relinfo, EState *estate)
Definition execUtils.c:1444
@ LockTupleExclusive
Definition lockoptions.h:59
@ LockTupleNoKeyExclusive
Definition lockoptions.h:57
Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Definition relcache.c:5313
@ INDEX_ATTR_BITMAP_KEY
Definition relcache.h:70

References bms_overlap(), ExecGetAllUpdatedCols(), fb(), INDEX_ATTR_BITMAP_KEY, LockTupleExclusive, LockTupleNoKeyExclusive, and RelationGetIndexAttrBitmap().

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 1722 of file execMain.c.

1728{
1729 EState *estate = queryDesc->estate;
1730 PlanState *planstate = queryDesc->planstate;
1731 bool use_parallel_mode;
1732 TupleTableSlot *slot;
1734
1735 /*
1736 * initialize local variables
1737 */
1739
1740 /*
1741 * Set the direction.
1742 */
1743 estate->es_direction = direction;
1744
1745 /*
1746 * Set up parallel mode if appropriate.
1747 *
1748 * Parallel mode only supports complete execution of a plan. If we've
1749 * already partially executed it, or if the caller asks us to exit early,
1750 * we must force the plan to run without parallelism.
1751 */
1752 if (queryDesc->already_executed || numberTuples != 0)
1753 use_parallel_mode = false;
1754 else
1756 queryDesc->already_executed = true;
1757
1761
1762 /*
1763 * Loop until we've processed the proper number of tuples from the plan.
1764 */
1765 for (;;)
1766 {
1767 /* Reset the per-output-tuple exprcontext */
1769
1770 /*
1771 * Execute the plan and obtain a tuple
1772 */
1773 slot = ExecProcNode(planstate);
1774
1775 /*
1776 * if the tuple is null, then we assume there is nothing more to
1777 * process so we just end the loop...
1778 */
1779 if (TupIsNull(slot))
1780 break;
1781
1782 /*
1783 * If we have a junk filter, then project a new tuple with the junk
1784 * removed.
1785 *
1786 * Store this new "clean" tuple in the junkfilter's resultSlot.
1787 * (Formerly, we stored it back over the "dirty" tuple, which is WRONG
1788 * because that tuple slot has the wrong descriptor.)
1789 */
1790 if (estate->es_junkFilter != NULL)
1791 slot = ExecFilterJunk(estate->es_junkFilter, slot);
1792
1793 /*
1794 * If we are supposed to send the tuple somewhere, do so. (In
1795 * practice, this is probably always the case at this point.)
1796 */
1797 if (sendTuples)
1798 {
1799 /*
1800 * If we are not able to send the tuple, we assume the destination
1801 * has closed and no more tuples can be sent. If that's the case,
1802 * end the loop.
1803 */
1804 if (!dest->receiveSlot(slot, dest))
1805 break;
1806 }
1807
1808 /*
1809 * Count tuples processed, if this is a SELECT. (For other operation
1810 * types, the ModifyTable plan node must count the appropriate
1811 * events.)
1812 */
1813 if (operation == CMD_SELECT)
1814 (estate->es_processed)++;
1815
1816 /*
1817 * check our tuple count.. if we've processed the proper number then
1818 * quit, else loop again and process more tuples. Zero numberTuples
1819 * means no limit.
1820 */
1823 break;
1824 }
1825
1826 /*
1827 * If we know we won't need to back up, we can release resources at this
1828 * point.
1829 */
1830 if (!(estate->es_top_eflags & EXEC_FLAG_BACKWARD))
1831 ExecShutdownNode(planstate);
1832
1835}
uint64_t uint64
Definition c.h:684
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition execJunk.c:247
void ExecShutdownNode(PlanState *node)
#define EXEC_FLAG_BACKWARD
Definition executor.h:70
uint64 es_processed
Definition execnodes.h:751
bool es_use_parallel_mode
Definition execnodes.h:781
bool parallelModeNeeded
Definition plannodes.h:93
EState * estate
Definition execdesc.h:50
bool already_executed
Definition execdesc.h:54
PlannedStmt * plannedstmt
Definition execdesc.h:37
PlanState * planstate
Definition execdesc.h:51
void ExitParallelMode(void)
Definition xact.c:1094
void EnterParallelMode(void)
Definition xact.c:1081

References QueryDesc::already_executed, CMD_SELECT, 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(), fb(), operation, PlannedStmt::parallelModeNeeded, QueryDesc::plannedstmt, QueryDesc::planstate, ResetPerTupleExprContext, and TupIsNull.

Referenced by standard_ExecutorRun().

◆ ExecutorEnd()

void ExecutorEnd ( QueryDesc queryDesc)

Definition at line 477 of file execMain.c.

478{
480 (*ExecutorEnd_hook) (queryDesc);
481 else
482 standard_ExecutorEnd(queryDesc);
483}
ExecutorEnd_hook_type ExecutorEnd_hook
Definition execMain.c:73
void standard_ExecutorEnd(QueryDesc *queryDesc)
Definition execMain.c:486

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 417 of file execMain.c.

418{
420 (*ExecutorFinish_hook) (queryDesc);
421 else
422 standard_ExecutorFinish(queryDesc);
423}
ExecutorFinish_hook_type ExecutorFinish_hook
Definition execMain.c:72
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition execMain.c:426

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 547 of file execMain.c.

548{
549 EState *estate;
550 MemoryContext oldcontext;
551
552 /* sanity checks */
553 Assert(queryDesc != NULL);
554
555 estate = queryDesc->estate;
556
557 Assert(estate != NULL);
558
559 /* It's probably not sensible to rescan updating queries */
560 Assert(queryDesc->operation == CMD_SELECT);
561
562 /*
563 * Switch into per-query memory context
564 */
565 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
566
567 /*
568 * rescan plan
569 */
570 ExecReScan(queryDesc->planstate);
571
572 MemoryContextSwitchTo(oldcontext);
573}
void ExecReScan(PlanState *node)
Definition execAmi.c:78
CmdType operation
Definition execdesc.h:36

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

Referenced by DoPortalRewind(), and PersistHoldablePortal().

◆ ExecutorRun()

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

Definition at line 308 of file execMain.c.

310{
312 (*ExecutorRun_hook) (queryDesc, direction, count);
313 else
314 standard_ExecutorRun(queryDesc, direction, count);
315}
ExecutorRun_hook_type ExecutorRun_hook
Definition execMain.c:71
void standard_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
Definition execMain.c:318

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 124 of file execMain.c.

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

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 2294 of file execMain.c.

2296{
2297 Relation rel = resultRelInfo->ri_RelationDesc;
2298 TupleDesc tupdesc = RelationGetDescr(rel);
2299 ExprContext *econtext;
2300 ListCell *l1,
2301 *l2;
2302
2303 /*
2304 * We will use the EState's per-tuple context for evaluating constraint
2305 * expressions (creating it if it's not already there).
2306 */
2307 econtext = GetPerTupleExprContext(estate);
2308
2309 /* Arrange for econtext's scan tuple to be the tuple under test */
2310 econtext->ecxt_scantuple = slot;
2311
2312 /* Check each of the constraints */
2313 forboth(l1, resultRelInfo->ri_WithCheckOptions,
2314 l2, resultRelInfo->ri_WithCheckOptionExprs)
2315 {
2317 ExprState *wcoExpr = (ExprState *) lfirst(l2);
2318
2319 /*
2320 * Skip any WCOs which are not the kind we are looking for at this
2321 * time.
2322 */
2323 if (wco->kind != kind)
2324 continue;
2325
2326 /*
2327 * WITH CHECK OPTION checks are intended to ensure that the new tuple
2328 * is visible (in the case of a view) or that it passes the
2329 * 'with-check' policy (in the case of row security). If the qual
2330 * evaluates to NULL or FALSE, then the new tuple won't be included in
2331 * the view or doesn't pass the 'with-check' policy for the table.
2332 */
2333 if (!ExecQual(wcoExpr, econtext))
2334 {
2335 char *val_desc;
2337
2338 switch (wco->kind)
2339 {
2340 /*
2341 * For WITH CHECK OPTIONs coming from views, we might be
2342 * able to provide the details on the row, depending on
2343 * the permissions on the relation (that is, if the user
2344 * could view it directly anyway). For RLS violations, we
2345 * don't include the data since we don't know if the user
2346 * should be able to view the tuple as that depends on the
2347 * USING policy.
2348 */
2349 case WCO_VIEW_CHECK:
2350 /* See the comment in ExecConstraints(). */
2351 if (resultRelInfo->ri_RootResultRelInfo)
2352 {
2353 ResultRelInfo *rootrel = resultRelInfo->ri_RootResultRelInfo;
2355 AttrMap *map;
2356
2357 tupdesc = RelationGetDescr(rootrel->ri_RelationDesc);
2358 /* a reverse map */
2360 tupdesc,
2361 false);
2362
2363 /*
2364 * Partition-specific slot's tupdesc can't be changed,
2365 * so allocate a new one.
2366 */
2367 if (map != NULL)
2368 slot = execute_attr_map_slot(map, slot,
2369 MakeTupleTableSlot(tupdesc, &TTSOpsVirtual, 0));
2370
2372 ExecGetUpdatedCols(rootrel, estate));
2373 rel = rootrel->ri_RelationDesc;
2374 }
2375 else
2376 modifiedCols = bms_union(ExecGetInsertedCols(resultRelInfo, estate),
2377 ExecGetUpdatedCols(resultRelInfo, estate));
2379 slot,
2380 tupdesc,
2382 64);
2383
2384 ereport(ERROR,
2386 errmsg("new row violates check option for view \"%s\"",
2387 wco->relname),
2388 val_desc ? errdetail("Failing row contains %s.",
2389 val_desc) : 0));
2390 break;
2393 if (wco->polname != NULL)
2394 ereport(ERROR,
2396 errmsg("new row violates row-level security policy \"%s\" for table \"%s\"",
2397 wco->polname, wco->relname)));
2398 else
2399 ereport(ERROR,
2401 errmsg("new row violates row-level security policy for table \"%s\"",
2402 wco->relname)));
2403 break;
2406 if (wco->polname != NULL)
2407 ereport(ERROR,
2409 errmsg("target row violates row-level security policy \"%s\" (USING expression) for table \"%s\"",
2410 wco->polname, wco->relname)));
2411 else
2412 ereport(ERROR,
2414 errmsg("target row violates row-level security policy (USING expression) for table \"%s\"",
2415 wco->relname)));
2416 break;
2418 if (wco->polname != NULL)
2419 ereport(ERROR,
2421 errmsg("new row violates row-level security policy \"%s\" (USING expression) for table \"%s\"",
2422 wco->polname, wco->relname)));
2423 else
2424 ereport(ERROR,
2426 errmsg("new row violates row-level security policy (USING expression) for table \"%s\"",
2427 wco->relname)));
2428 break;
2429 default:
2430 elog(ERROR, "unrecognized WCO kind: %u", wco->kind);
2431 break;
2432 }
2433 }
2434 }
2435}
static bool ExecQual(ExprState *state, ExprContext *econtext)
Definition executor.h:527
@ WCO_RLS_MERGE_UPDATE_CHECK
@ WCO_RLS_CONFLICT_CHECK
@ WCO_RLS_INSERT_CHECK
@ WCO_VIEW_CHECK
@ WCO_RLS_UPDATE_CHECK
@ WCO_RLS_MERGE_DELETE_CHECK
#define forboth(cell1, list1, cell2, list2)
Definition pg_list.h:550
List * ri_WithCheckOptions
Definition execnodes.h:583
List * ri_WithCheckOptionExprs
Definition execnodes.h:586

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(), fb(), forboth, GetPerTupleExprContext, lfirst, MakeTupleTableSlot(), RelationGetDescr, RelationGetRelid, 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(), ExecOnConflictSelect(), ExecOnConflictUpdate(), ExecUpdateAct(), and ExecUpdateEpilogue().

◆ InitPlan()

static void InitPlan ( QueryDesc queryDesc,
int  eflags 
)
static

Definition at line 847 of file execMain.c.

848{
849 CmdType operation = queryDesc->operation;
850 PlannedStmt *plannedstmt = queryDesc->plannedstmt;
851 Plan *plan = plannedstmt->planTree;
852 List *rangeTable = plannedstmt->rtable;
853 EState *estate = queryDesc->estate;
854 PlanState *planstate;
856 ListCell *l;
857 int i;
858
859 /*
860 * Do permissions checks
861 */
862 ExecCheckPermissions(rangeTable, plannedstmt->permInfos, true);
863
864 /*
865 * initialize the node's execution state
866 */
867 ExecInitRangeTable(estate, rangeTable, plannedstmt->permInfos,
868 bms_copy(plannedstmt->unprunableRelids));
869
870 estate->es_plannedstmt = plannedstmt;
871 estate->es_part_prune_infos = plannedstmt->partPruneInfos;
872
873 /*
874 * Perform runtime "initial" pruning to identify which child subplans,
875 * corresponding to the children of plan nodes that contain
876 * PartitionPruneInfo such as Append, will not be executed. The results,
877 * which are bitmapsets of indexes of the child subplans that will be
878 * executed, are saved in es_part_prune_results. These results correspond
879 * to each PartitionPruneInfo entry, and the es_part_prune_results list is
880 * parallel to es_part_prune_infos.
881 */
882 ExecDoInitialPruning(estate);
883
884 /*
885 * Next, build the ExecRowMark array from the PlanRowMark(s), if any.
886 */
887 if (plannedstmt->rowMarks)
888 {
889 estate->es_rowmarks = (ExecRowMark **)
891 foreach(l, plannedstmt->rowMarks)
892 {
893 PlanRowMark *rc = (PlanRowMark *) lfirst(l);
894 RangeTblEntry *rte = exec_rt_fetch(rc->rti, estate);
895 Oid relid;
896 Relation relation;
898
899 /* ignore "parent" rowmarks; they are irrelevant at runtime */
900 if (rc->isParent)
901 continue;
902
903 /*
904 * Also ignore rowmarks belonging to child tables that have been
905 * pruned in ExecDoInitialPruning().
906 */
907 if (rte->rtekind == RTE_RELATION &&
908 !bms_is_member(rc->rti, estate->es_unpruned_relids))
909 continue;
910
911 /* get relation's OID (will produce InvalidOid if subquery) */
912 relid = rte->relid;
913
914 /* open relation, if we need to access it for this mark type */
915 switch (rc->markType)
916 {
919 case ROW_MARK_SHARE:
922 relation = ExecGetRangeTableRelation(estate, rc->rti, false);
923 break;
924 case ROW_MARK_COPY:
925 /* no physical table access is required */
926 relation = NULL;
927 break;
928 default:
929 elog(ERROR, "unrecognized markType: %d", rc->markType);
930 relation = NULL; /* keep compiler quiet */
931 break;
932 }
933
934 /* Check that relation is a legal target for marking */
935 if (relation)
936 CheckValidRowMarkRel(relation, rc->markType);
937
939 erm->relation = relation;
940 erm->relid = relid;
941 erm->rti = rc->rti;
942 erm->prti = rc->prti;
943 erm->rowmarkId = rc->rowmarkId;
944 erm->markType = rc->markType;
945 erm->strength = rc->strength;
946 erm->waitPolicy = rc->waitPolicy;
947 erm->ermActive = false;
948 ItemPointerSetInvalid(&(erm->curCtid));
949 erm->ermExtra = NULL;
950
951 Assert(erm->rti > 0 && erm->rti <= estate->es_range_table_size &&
952 estate->es_rowmarks[erm->rti - 1] == NULL);
953
954 estate->es_rowmarks[erm->rti - 1] = erm;
955 }
956 }
957
958 /*
959 * Initialize the executor's tuple table to empty.
960 */
961 estate->es_tupleTable = NIL;
962
963 /* signal that this EState is not used for EPQ */
964 estate->es_epq_active = NULL;
965
966 /*
967 * Initialize private state information for each SubPlan. We must do this
968 * before running ExecInitNode on the main query tree, since
969 * ExecInitSubPlan expects to be able to find these entries.
970 */
971 Assert(estate->es_subplanstates == NIL);
972 i = 1; /* subplan indices count from 1 */
973 foreach(l, plannedstmt->subplans)
974 {
975 Plan *subplan = (Plan *) lfirst(l);
977 int sp_eflags;
978
979 /*
980 * A subplan will never need to do BACKWARD scan nor MARK/RESTORE. If
981 * it is a parameterless subplan (not initplan), we suggest that it be
982 * prepared to handle REWIND efficiently; otherwise there is no need.
983 */
984 sp_eflags = eflags
986 if (bms_is_member(i, plannedstmt->rewindPlanIDs))
988
989 subplanstate = ExecInitNode(subplan, estate, sp_eflags);
990
991 estate->es_subplanstates = lappend(estate->es_subplanstates,
993
994 i++;
995 }
996
997 /*
998 * Initialize the private state information for all the nodes in the query
999 * tree. This opens files, allocates storage and leaves us ready to start
1000 * processing tuples.
1001 */
1002 planstate = ExecInitNode(plan, estate, eflags);
1003
1004 /*
1005 * Get the tuple descriptor describing the type of tuples to return.
1006 */
1007 tupType = ExecGetResultType(planstate);
1008
1009 /*
1010 * Initialize the junk filter if needed. SELECT queries need a filter if
1011 * there are any junk attrs in the top-level tlist.
1012 */
1013 if (operation == CMD_SELECT)
1014 {
1015 bool junk_filter_needed = false;
1016 ListCell *tlist;
1017
1018 foreach(tlist, plan->targetlist)
1019 {
1020 TargetEntry *tle = (TargetEntry *) lfirst(tlist);
1021
1022 if (tle->resjunk)
1023 {
1024 junk_filter_needed = true;
1025 break;
1026 }
1027 }
1028
1030 {
1031 JunkFilter *j;
1032 TupleTableSlot *slot;
1033
1034 slot = ExecInitExtraTupleSlot(estate, NULL, &TTSOpsVirtual);
1035 j = ExecInitJunkFilter(planstate->plan->targetlist,
1036 slot);
1037 estate->es_junkFilter = j;
1038
1039 /* Want to return the cleaned tuple type */
1041 }
1042 }
1043
1044 queryDesc->tupDesc = tupType;
1045 queryDesc->planstate = planstate;
1046}
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:1226
bool ExecCheckPermissions(List *rangeTable, List *rteperminfos, bool ereport_on_violation)
Definition execMain.c:593
void ExecDoInitialPruning(EState *estate)
TupleTableSlot * ExecInitExtraTupleSlot(EState *estate, TupleDesc tupledesc, const TupleTableSlotOps *tts_ops)
TupleDesc ExecGetResultType(PlanState *planstate)
Definition execUtils.c:500
Relation ExecGetRangeTableRelation(EState *estate, Index rti, bool isResultRel)
Definition execUtils.c:851
void ExecInitRangeTable(EState *estate, List *rangeTable, List *permInfos, Bitmapset *unpruned_relids)
Definition execUtils.c:799
#define EXEC_FLAG_REWIND
Definition executor.h:69
static RangeTblEntry * exec_rt_fetch(Index rti, EState *estate)
Definition executor.h:708
#define EXEC_FLAG_MARK
Definition executor.h:71
#define palloc_object(type)
Definition fe_memutils.h:89
int j
Definition isn.c:78
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition itemptr.h:184
CmdType
Definition nodes.h:271
#define plan(x)
Definition pg_regress.c:164
@ ROW_MARK_SHARE
Definition plannodes.h:1559
@ ROW_MARK_EXCLUSIVE
Definition plannodes.h:1557
@ ROW_MARK_NOKEYEXCLUSIVE
Definition plannodes.h:1558
@ ROW_MARK_KEYSHARE
Definition plannodes.h:1560
struct EPQState * es_epq_active
Definition execnodes.h:779
TupleDesc jf_cleanTupType
Definition execnodes.h:433
LockClauseStrength strength
Definition plannodes.h:1621
RowMarkType markType
Definition plannodes.h:1617
LockWaitPolicy waitPolicy
Definition plannodes.h:1623
Index rowmarkId
Definition plannodes.h:1615
Plan * plan
Definition execnodes.h:1202
List * targetlist
Definition plannodes.h:235
struct Plan * planTree
Definition plannodes.h:99
List * rowMarks
Definition plannodes.h:138
Bitmapset * rewindPlanIDs
Definition plannodes.h:135
Bitmapset * unprunableRelids
Definition plannodes.h:113
List * rtable
Definition plannodes.h:107
List * partPruneInfos
Definition plannodes.h:104
TupleDesc tupDesc
Definition execdesc.h:49

References Assert, bms_copy(), bms_is_member(), CheckValidRowMarkRel(), CMD_SELECT, elog, 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(), fb(), i, PlanRowMark::isParent, ItemPointerSetInvalid(), j, JunkFilter::jf_cleanTupType, lappend(), lfirst, PlanRowMark::markType, NIL, operation, QueryDesc::operation, palloc0_array, palloc_object, PlannedStmt::partPruneInfos, PlannedStmt::permInfos, PlanState::plan, plan, QueryDesc::plannedstmt, QueryDesc::planstate, PlannedStmt::planTree, PlanRowMark::prti, ExecRowMark::relid, PlannedStmt::rewindPlanIDs, ROW_MARK_COPY, ROW_MARK_EXCLUSIVE, ROW_MARK_KEYSHARE, ROW_MARK_NOKEYEXCLUSIVE, ROW_MARK_REFERENCE, ROW_MARK_SHARE, PlanRowMark::rowmarkId, PlannedStmt::rowMarks, PlannedStmt::rtable, RTE_RELATION, PlanRowMark::rti, PlanRowMark::strength, PlannedStmt::subplans, Plan::targetlist, TTSOpsVirtual, QueryDesc::tupDesc, PlannedStmt::unprunableRelids, 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 1308 of file execMain.c.

1313{
1314 MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));
1315 resultRelInfo->type = T_ResultRelInfo;
1316 resultRelInfo->ri_RangeTableIndex = resultRelationIndex;
1317 resultRelInfo->ri_RelationDesc = resultRelationDesc;
1318 resultRelInfo->ri_NumIndices = 0;
1319 resultRelInfo->ri_IndexRelationDescs = NULL;
1320 resultRelInfo->ri_IndexRelationInfo = NULL;
1321 resultRelInfo->ri_needLockTagTuple =
1323 /* make a copy so as not to depend on relcache info not changing... */
1324 resultRelInfo->ri_TrigDesc = CopyTriggerDesc(resultRelationDesc->trigdesc);
1325 if (resultRelInfo->ri_TrigDesc)
1326 {
1327 int n = resultRelInfo->ri_TrigDesc->numtriggers;
1328
1329 resultRelInfo->ri_TrigFunctions = (FmgrInfo *)
1331 resultRelInfo->ri_TrigWhenExprs = (ExprState **)
1333 if (instrument_options)
1334 resultRelInfo->ri_TrigInstrument = InstrAllocTrigger(n, instrument_options);
1335 }
1336 else
1337 {
1338 resultRelInfo->ri_TrigFunctions = NULL;
1339 resultRelInfo->ri_TrigWhenExprs = NULL;
1340 resultRelInfo->ri_TrigInstrument = NULL;
1341 }
1342 if (resultRelationDesc->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1344 else
1345 resultRelInfo->ri_FdwRoutine = NULL;
1346
1347 /* The following fields are set later if needed */
1348 resultRelInfo->ri_RowIdAttNo = 0;
1349 resultRelInfo->ri_extraUpdatedCols = NULL;
1350 resultRelInfo->ri_projectNew = NULL;
1351 resultRelInfo->ri_newTupleSlot = NULL;
1352 resultRelInfo->ri_oldTupleSlot = NULL;
1353 resultRelInfo->ri_projectNewInfoValid = false;
1354 resultRelInfo->ri_FdwState = NULL;
1355 resultRelInfo->ri_usesFdwDirectModify = false;
1356 resultRelInfo->ri_CheckConstraintExprs = NULL;
1358 resultRelInfo->ri_GeneratedExprsI = NULL;
1359 resultRelInfo->ri_GeneratedExprsU = NULL;
1360 resultRelInfo->ri_projectReturning = NULL;
1361 resultRelInfo->ri_onConflictArbiterIndexes = NIL;
1362 resultRelInfo->ri_onConflict = NULL;
1363 resultRelInfo->ri_forPortionOf = NULL;
1364 resultRelInfo->ri_ReturningSlot = NULL;
1365 resultRelInfo->ri_TrigOldSlot = NULL;
1366 resultRelInfo->ri_TrigNewSlot = NULL;
1367 resultRelInfo->ri_AllNullSlot = NULL;
1368 resultRelInfo->ri_MergeActions[MERGE_WHEN_MATCHED] = NIL;
1371 resultRelInfo->ri_MergeJoinCondition = NULL;
1372
1373 /*
1374 * Only ExecInitPartitionInfo() and ExecInitPartitionDispatchInfo() pass
1375 * non-NULL partition_root_rri. For child relations that are part of the
1376 * initial query rather than being dynamically added by tuple routing,
1377 * this field is filled in ExecInitModifyTable().
1378 */
1380 /* Set by ExecGetRootToChildMap */
1381 resultRelInfo->ri_RootToChildMap = NULL;
1382 resultRelInfo->ri_RootToChildMapValid = false;
1383 /* Set by ExecInitRoutingInfo */
1384 resultRelInfo->ri_PartitionTupleSlot = NULL;
1385 resultRelInfo->ri_ChildToRootMap = NULL;
1386 resultRelInfo->ri_ChildToRootMapValid = false;
1387 resultRelInfo->ri_CopyMultiInsertBuffer = NULL;
1388}
#define MemSet(start, val, len)
Definition c.h:1166
TriggerInstrumentation * InstrAllocTrigger(int n, int instrument_options)
Definition instrument.c:253
@ MERGE_WHEN_NOT_MATCHED_BY_TARGET
Definition primnodes.h:2019
@ MERGE_WHEN_NOT_MATCHED_BY_SOURCE
Definition primnodes.h:2018
@ MERGE_WHEN_MATCHED
Definition primnodes.h:2017
TupleConversionMap * ri_RootToChildMap
Definition execnodes.h:643
OnConflictActionState * ri_onConflict
Definition execnodes.h:617
TupleTableSlot * ri_PartitionTupleSlot
Definition execnodes.h:656
bool ri_projectNewInfoValid
Definition execnodes.h:543
List * ri_onConflictArbiterIndexes
Definition execnodes.h:614
ExprState * ri_MergeJoinCondition
Definition execnodes.h:623
RelationPtr ri_IndexRelationDescs
Definition execnodes.h:520
TupleTableSlot * ri_ReturningSlot
Definition execnodes.h:561
TupleTableSlot * ri_oldTupleSlot
Definition execnodes.h:541
bool ri_RootToChildMapValid
Definition execnodes.h:644
struct CopyMultiInsertBuffer * ri_CopyMultiInsertBuffer
Definition execnodes.h:659
TriggerDesc * ri_TrigDesc
Definition execnodes.h:549
TupleTableSlot * ri_AllNullSlot
Definition execnodes.h:564
ForPortionOfState * ri_forPortionOf
Definition execnodes.h:626
Bitmapset * ri_extraUpdatedCols
Definition execnodes.h:532
ExprState ** ri_GeneratedExprsI
Definition execnodes.h:600
TupleConversionMap * ri_ChildToRootMap
Definition execnodes.h:637
void * ri_FdwState
Definition execnodes.h:570
bool ri_ChildToRootMapValid
Definition execnodes.h:638
List * ri_MergeActions[NUM_MERGE_MATCH_KINDS]
Definition execnodes.h:620
TupleTableSlot * ri_newTupleSlot
Definition execnodes.h:539
ProjectionInfo * ri_projectNew
Definition execnodes.h:537
NodeTag type
Definition execnodes.h:508
ProjectionInfo * ri_projectReturning
Definition execnodes.h:611
ExprState ** ri_GeneratedExprsU
Definition execnodes.h:601
ExprState ** ri_TrigWhenExprs
Definition execnodes.h:555
FmgrInfo * ri_TrigFunctions
Definition execnodes.h:552
bool ri_usesFdwDirectModify
Definition execnodes.h:573
AttrNumber ri_RowIdAttNo
Definition execnodes.h:529
IndexInfo ** ri_IndexRelationInfo
Definition execnodes.h:523
TupleTableSlot * ri_TrigNewSlot
Definition execnodes.h:563
TriggerInstrumentation * ri_TrigInstrument
Definition execnodes.h:558
TupleTableSlot * ri_TrigOldSlot
Definition execnodes.h:562
int numtriggers
Definition reltrigger.h:50
TriggerDesc * CopyTriggerDesc(TriggerDesc *trigdesc)
Definition trigger.c:2117

References CopyTriggerDesc(), fb(), GetFdwRoutineForRelation(), InstrAllocTrigger(), IsInplaceUpdateRelation(), MemSet, MERGE_WHEN_MATCHED, MERGE_WHEN_NOT_MATCHED_BY_SOURCE, MERGE_WHEN_NOT_MATCHED_BY_TARGET, NIL, TriggerDesc::numtriggers, palloc0_array, 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_forPortionOf, 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, and ResultRelInfo::type.

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

◆ ReportNotNullViolationError()

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

Definition at line 2225 of file execMain.c.

2227{
2229 char *val_desc;
2230 Relation rel = resultRelInfo->ri_RelationDesc;
2231 Relation orig_rel = rel;
2232 TupleDesc tupdesc = RelationGetDescr(rel);
2234 Form_pg_attribute att = TupleDescAttr(tupdesc, attnum - 1);
2235
2236 Assert(attnum > 0);
2237
2238 /*
2239 * If the tuple has been routed, it's been converted to the partition's
2240 * rowtype, which might differ from the root table's. We must convert it
2241 * back to the root table's rowtype so that val_desc shown error message
2242 * matches the input tuple.
2243 */
2244 if (resultRelInfo->ri_RootResultRelInfo)
2245 {
2246 ResultRelInfo *rootrel = resultRelInfo->ri_RootResultRelInfo;
2247 AttrMap *map;
2248
2249 tupdesc = RelationGetDescr(rootrel->ri_RelationDesc);
2250 /* a reverse map */
2252 tupdesc,
2253 false);
2254
2255 /*
2256 * Partition-specific slot's tupdesc can't be changed, so allocate a
2257 * new one.
2258 */
2259 if (map != NULL)
2260 slot = execute_attr_map_slot(map, slot,
2261 MakeTupleTableSlot(tupdesc, &TTSOpsVirtual, 0));
2263 ExecGetUpdatedCols(rootrel, estate));
2264 rel = rootrel->ri_RelationDesc;
2265 }
2266 else
2267 modifiedCols = bms_union(ExecGetInsertedCols(resultRelInfo, estate),
2268 ExecGetUpdatedCols(resultRelInfo, estate));
2269
2271 slot,
2272 tupdesc,
2274 64);
2275 ereport(ERROR,
2277 errmsg("null value in column \"%s\" of relation \"%s\" violates not-null constraint",
2278 NameStr(att->attname),
2280 val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
2282}
int errtablecol(Relation rel, int attnum)
Definition relcache.c:6099

References Assert, attnum, bms_union(), build_attrmap_by_name_if_req(), ereport, errcode(), errdetail(), errmsg, ERROR, errtablecol(), ExecBuildSlotValueDescription(), ExecGetInsertedCols(), ExecGetUpdatedCols(), execute_attr_map_slot(), fb(), 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 486 of file execMain.c.

487{
488 EState *estate;
489 MemoryContext oldcontext;
490
491 /* sanity checks */
492 Assert(queryDesc != NULL);
493
494 estate = queryDesc->estate;
495
496 Assert(estate != NULL);
497
498 if (estate->es_parallel_workers_to_launch > 0)
501
502 /*
503 * Check that ExecutorFinish was called, unless in EXPLAIN-only mode. This
504 * Assert is needed because ExecutorFinish is new as of 9.1, and callers
505 * might forget to call it.
506 */
507 Assert(estate->es_finished ||
509
510 /*
511 * Switch into per-query memory context to run ExecEndPlan
512 */
513 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
514
515 ExecEndPlan(queryDesc->planstate, estate);
516
517 /* do away with our snapshots */
520
521 /*
522 * Must switch out of context before destroying it
523 */
524 MemoryContextSwitchTo(oldcontext);
525
526 /*
527 * Release EState and per-query memory context. This should release
528 * everything the executor has allocated.
529 */
530 FreeExecutorState(estate);
531
532 /* Reset queryDesc fields that no longer point to anything */
533 queryDesc->tupDesc = NULL;
534 queryDesc->estate = NULL;
535 queryDesc->planstate = NULL;
536 queryDesc->query_instr = NULL;
537}
static void ExecEndPlan(PlanState *planstate, EState *estate)
Definition execMain.c:1602
#define EXEC_FLAG_EXPLAIN_ONLY
Definition executor.h:67
int64 PgStat_Counter
Definition pgstat.h:71
void pgstat_update_parallel_workers_stats(PgStat_Counter workers_to_launch, PgStat_Counter workers_launched)
void UnregisterSnapshot(Snapshot snapshot)
Definition snapmgr.c:866
int es_parallel_workers_to_launch
Definition execnodes.h:783
bool es_finished
Definition execnodes.h:758
int es_parallel_workers_launched
Definition execnodes.h:785
struct Instrumentation * query_instr
Definition execdesc.h:57

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(), fb(), FreeExecutorState(), MemoryContextSwitchTo(), pgstat_update_parallel_workers_stats(), QueryDesc::planstate, QueryDesc::query_instr, QueryDesc::tupDesc, and UnregisterSnapshot().

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

◆ standard_ExecutorFinish()

void standard_ExecutorFinish ( QueryDesc queryDesc)

Definition at line 426 of file execMain.c.

427{
428 EState *estate;
429 MemoryContext oldcontext;
430
431 /* sanity checks */
432 Assert(queryDesc != NULL);
433
434 estate = queryDesc->estate;
435
436 Assert(estate != NULL);
438
439 /* This should be run once and only once per Executor instance */
440 Assert(!estate->es_finished);
441
442 /* Switch into per-query memory context */
443 oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
444
445 /* Allow instrumentation of Executor overall runtime */
446 if (queryDesc->query_instr)
447 InstrStart(queryDesc->query_instr);
448
449 /* Run ModifyTable nodes to completion */
450 ExecPostprocessPlan(estate);
451
452 /* Execute queued AFTER triggers, unless told not to */
453 if (!(estate->es_top_eflags & EXEC_FLAG_SKIP_TRIGGERS))
454 AfterTriggerEndQuery(estate);
455
456 if (queryDesc->query_instr)
457 InstrStop(queryDesc->query_instr);
458
459 MemoryContextSwitchTo(oldcontext);
460
461 estate->es_finished = true;
462}
static void ExecPostprocessPlan(EState *estate)
Definition execMain.c:1556
#define EXEC_FLAG_SKIP_TRIGGERS
Definition executor.h:72
void InstrStart(Instrumentation *instr)
Definition instrument.c:53
void InstrStop(Instrumentation *instr)
Definition instrument.c:103
void AfterTriggerEndQuery(EState *estate)
Definition trigger.c:5186

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(), fb(), InstrStart(), InstrStop(), MemoryContextSwitchTo(), and QueryDesc::query_instr.

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

◆ standard_ExecutorRun()

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

Definition at line 318 of file execMain.c.

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

References Assert, CMD_SELECT, 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(), fb(), GetActiveSnapshot(), PlannedStmt::hasReturning, InstrStart(), InstrStop(), MemoryContextSwitchTo(), operation, QueryDesc::operation, QueryDesc::plannedstmt, QueryDesc::query_instr, ScanDirectionIsNoMovement, and QueryDesc::tupDesc.

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

◆ standard_ExecutorStart()

void standard_ExecutorStart ( QueryDesc queryDesc,
int  eflags 
)

Definition at line 143 of file execMain.c.

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

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(), fb(), GetActiveSnapshot(), GetCurrentCommandId(), PlannedStmt::hasModifyingCTE, InitPlan(), InstrAlloc(), QueryDesc::instrument_options, IsInParallelMode(), PlannedStmt::jitFlags, list_length(), MemoryContextSwitchTo(), NIL, QueryDesc::operation, palloc0_array, PlannedStmt::paramExecTypes, QueryDesc::params, QueryDesc::plannedstmt, QueryDesc::query_instr, QueryDesc::query_instr_options, 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 76 of file execMain.c.

Referenced by _PG_init(), and ExecCheckPermissions().

◆ ExecutorEnd_hook

ExecutorEnd_hook_type ExecutorEnd_hook = NULL

Definition at line 73 of file execMain.c.

Referenced by _PG_init(), and ExecutorEnd().

◆ ExecutorFinish_hook

ExecutorFinish_hook_type ExecutorFinish_hook = NULL

Definition at line 72 of file execMain.c.

Referenced by _PG_init(), and ExecutorFinish().

◆ ExecutorRun_hook

ExecutorRun_hook_type ExecutorRun_hook = NULL

Definition at line 71 of file execMain.c.

Referenced by _PG_init(), and ExecutorRun().

◆ ExecutorStart_hook

ExecutorStart_hook_type ExecutorStart_hook = NULL

Definition at line 70 of file execMain.c.

Referenced by _PG_init(), and ExecutorStart().