这篇文章主要介绍“postgresql中ExecInsert函数的实现逻辑是什么”,在日常操作中,相信很多人在Postgresql中ExecInsert函数的实现逻辑是什么问题上存在疑惑,小编查阅了各式资料
这篇文章主要介绍“postgresql中ExecInsert函数的实现逻辑是什么”,在日常操作中,相信很多人在Postgresql中ExecInsert函数的实现逻辑是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PostgreSQL中ExecInsert函数的实现逻辑是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
按惯例,首先看看ExecInsert函数使用的数据结构、宏定义以及依赖的函数等。
数据结构/宏定义
1、ModifyTableState
typedef struct PlanState
{
nodeTag type;
Plan *plan;
EState *state;
ExecProcNodeMtd ExecProcNode;
ExecProcNodeMtd ExecProcNodeReal;
Instrumentation *instrument;
WorkerInstrumentation *worker_instrument;
ExprState *qual;
struct PlanState *lefttree;
struct PlanState *righttree;
List *initPlan;
List *subPlan;
Bitmapset *chgParam;
TupleTableSlot *ps_ResultTupleSlot;
ExprContext *ps_ExprContext;
ProjectionInfo *ps_ProjInfo;
TupleDesc scandesc;
} PlanState;
typedef struct ModifyTableState
{
PlanState ps;
CmdType operation;
bool canSetTag;
bool mt_done;
PlanState **mt_plans;
int mt_nplans;
int mt_whichplan;
ResultRelInfo *resultRelInfo;
ResultRelInfo *rootResultRelInfo;
List **mt_arowmarks;
EPQState mt_epqstate;
bool fireBSTriggers;
TupleTableSlot *mt_existing;
List *mt_excludedtlist;
TupleTableSlot *mt_conflproj;
struct PartitionTupleRouting *mt_partition_tuple_routing;
struct TransitionCaptureState *mt_transition_capture;
struct TransitionCaptureState *mt_oc_transition_capture;
TupleConversionMap **mt_per_subplan_tupconv_maps;
} ModifyTableState;
2、TupleTableSlot
typedef struct TupleTableSlot
{
NodeTag type;
bool tts_isempty;
bool tts_shouldFree;
bool tts_shouldFreeMin;
#define FIELDNO_TUPLETABLESLOT_SLOW 4
bool tts_slow;
#define FIELDNO_TUPLETABLESLOT_TUPLE 5
HeapTuple tts_tuple;
#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 6
TupleDesc tts_tupleDescriptor;
MemoryContext tts_mcxt;
Buffer tts_buffer;
#define FIELDNO_TUPLETABLESLOT_NVALID 9
int tts_nvalid;
#define FIELDNO_TUPLETABLESLOT_VALUES 10
Datum *tts_values;
#define FIELDNO_TUPLETABLESLOT_ISNULL 11
bool *tts_isnull;
MinimalTuple tts_mintuple;
HeapTupleData tts_minhdr;
#define FIELDNO_TUPLETABLESLOT_OFF 14
uint32 tts_off;
bool tts_fixedTupleDescriptor;
} TupleTableSlot;
3、EState
typedef struct EState
{
NodeTag type;
ScanDirection es_direction;
Snapshot es_snapshot;
Snapshot es_crosscheck_snapshot;
List *es_range_table;
PlannedStmt *es_plannedstmt;
const char *es_sourceText;
JunkFilter *es_junkFilter;
CommandId es_output_cid;
ResultRelInfo *es_result_relations;
int es_num_result_relations;
ResultRelInfo *es_result_relation_info;
ResultRelInfo *es_root_result_relations;
int es_num_root_result_relations;
List *es_tuple_routing_result_relations;
List *es_trig_target_relations;
TupleTableSlot *es_trig_tuple_slot;
TupleTableSlot *es_trig_oldtup_slot;
TupleTableSlot *es_trig_newtup_slot;
ParamListInfo es_param_list_info;
ParamExecData *es_param_exec_vals;
QueryEnvironment *es_queryEnv;
MemoryContext es_query_cxt;
List *es_tupleTable;
List *es_rowMarks;
uint64 es_processed;
Oid es_lastoid;
int es_top_eflags;
int es_instrument;
bool es_finished;
List *es_exprcontexts;
List *es_subplanstates;
List *es_auxmodifytables;
ExprContext *es_per_tuple_exprcontext;
HeapTuple *es_epQtuple;
bool *es_epqTupleSet;
bool *es_epqScanDone;
bool es_use_parallel_mode;
struct dsa_area *es_query_dsa;
int es_jit_flags;
struct JitContext *es_jit;
} EState;
4、ResultRelInfo
typedef struct ResultRelInfo
{
NodeTag type;
Index ri_RangeTableIndex;
Relation ri_RelationDesc;
int ri_NumIndices;
RelationPtr ri_IndexRelationDescs;
IndexInfo **ri_IndexRelationInfo;
TriggerDesc *ri_TrigDesc;
FmgrInfo *ri_TrigFunctions;
ExprState **ri_TrigWhenExprs;
Instrumentation *ri_TrigInstrument;
struct FdwRoutine *ri_FdwRoutine;
void *ri_FdwState;
bool ri_usesFdwDirectModify;
List *ri_WithCheckOptions;
List *ri_WithCheckOptionExprs;
ExprState **ri_ConstraintExprs;
JunkFilter *ri_junkFilter;
List *ri_returningList;
ProjectionInfo *ri_projectReturning;
List *ri_onConflictArbiterIndexes;
OnConflictSetState *ri_onConflict;
List *ri_PartitionCheck;
ExprState *ri_PartitionCheckExpr;
Relation ri_PartitionRoot;
bool ri_PartitionReadyForRouting;
} ResultRelInfo;
5、List
typedef struct ListCell ListCell;
typedef struct List
{
NodeTag type;
int length;
ListCell *head;
ListCell *tail;
} List;
struct ListCell
{
uNIOn
{
void *ptr_value;
int int_value;
Oid oid_value;
} data;
ListCell *next;
};
6、TransitionCaptureState
typedef struct TransitionCaptureState
{
bool tcs_delete_old_table;
bool tcs_update_old_table;
bool tcs_update_new_table;
bool tcs_insert_new_table;
TupleConversionMap *tcs_map;
HeapTuple tcs_original_insert_tuple;
struct AfterTriggersTableData *tcs_private;
} TransitionCaptureState;
*7、ModifyTable *
typedef struct ModifyTable
{
Plan plan;
CmdType operation;
bool canSetTag;
Index nominalRelation;
List *partitioned_rels;
bool partColsUpdated;
List *resultRelations;
int resultRelIndex;
int rootResultRelIndex;
List *plans;
List *withCheckOptionLists;
List *returningLists;
List *fdwPrivLists;
Bitmapset *fdwDirectModifyPlans;
List *rowMarks;
int epqParam;
OnConflictAction onConflictAction;
List *arbiterIndexes;
List *onConflictSet;
Node *onConflictWhere;
Index exclRelRTI;
List *exclRelTlist;
} ModifyTable;
8、OnConflictAction
typedef enum OnConflictAction
{
ONCONFLICT_NONE,
ONCONFLICT_NOTHING,
ONCONFLICT_UPDATE
} OnConflictAction;
8、MemoryContext
typedef struct MemoryContextData
{
NodeTag type;
bool isReset;
bool allowInCritSection;
const MemoryContextMethods *methods;
MemoryContext parent;
MemoryContext firstchild;
MemoryContext prevchild;
MemoryContext nextchild;
const char *name;
const char *ident;
MemoryContextCallback *reset_cbs;
} MemoryContextData;
typedef struct MemoryContextData *MemoryContext;
依赖的函数
1、ExecMaterializeSlot
HeapTuple
ExecMaterializeSlot(TupleTableSlot *slot)
{
MemoryContext oldContext;
Assert(slot != NULL);
Assert(!slot->tts_isempty);
if (slot->tts_tuple && slot->tts_shouldFree)
return slot->tts_tuple;
oldContext = MemoryContextSwitchTo(slot->tts_mcxt);//内存上下文切换至slot->tts_mcxt
slot->tts_tuple = ExecCopySlotTuple(slot);
slot->tts_shouldFree = true;
MemoryContextSwitchTo(oldContext);//内存上下文切换回原来
if (BufferIsValid(slot->tts_buffer))
ReleaseBuffer(slot->tts_buffer);
slot->tts_buffer = InvalidBuffer;
slot->tts_nvalid = 0;
if (!slot->tts_shouldFreeMin)
slot->tts_mintuple = NULL;
return slot->tts_tuple;
}
#ifndef FRONTEND
static inline MemoryContext
MemoryContextSwitchTo(MemoryContext context)
{
MemoryContext old = CurrentMemoryContext;
CurrentMemoryContext = context;
return old;
}
#endif
2、HeapTupleSetOid
#define HeapTupleSetOid(tuple, oid) \
HeapTupleHeaderSetOid((tuple)->t_data, (oid))
3、ExecBRInsertTriggers
TupleTableSlot *
ExecBRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
TupleTableSlot *slot)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
HeapTuple slottuple = ExecMaterializeSlot(slot);
HeapTuple newtuple = slottuple;
HeapTuple oldtuple;
TriggerData LocTriggerData;
int i;
LocTriggerData.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
TRIGGER_EVENT_ROW |
TRIGGER_EVENT_BEFORE;
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_newtuple = NULL;
LocTriggerData.tg_oldtable = NULL;
LocTriggerData.tg_newtable = NULL;
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
for (i = 0; i < trigdesc->numtriggers; i++)
{
Trigger *trigger = &trigdesc->triggers[i];
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
TRIGGER_TYPE_ROW,
TRIGGER_TYPE_BEFORE,
TRIGGER_TYPE_INSERT))
continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
NULL, NULL, newtuple))
continue;
LocTriggerData.tg_trigtuple = oldtuple = newtuple;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
i,
relinfo->ri_TrigFunctions,
relinfo->ri_TrigInstrument,
GetPerTupleMemoryContext(estate));
if (oldtuple != newtuple && oldtuple != slottuple)
heap_freetuple(oldtuple);
if (newtuple == NULL)
return NULL;
}
if (newtuple != slottuple)
{
TupleTableSlot *newslot = estate->es_trig_tuple_slot;
TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
if (newslot->tts_tupleDescriptor != tupdesc)
ExecSetSlotDescriptor(newslot, tupdesc);
ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
slot = newslot;
}
return slot;
}
4、ExecIRInsertTriggers
TupleTableSlot *
ExecIRInsertTriggers(EState *estate, ResultRelInfo *relinfo,
TupleTableSlot *slot)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
HeapTuple slottuple = ExecMaterializeSlot(slot);
HeapTuple newtuple = slottuple;
HeapTuple oldtuple;
TriggerData LocTriggerData;
int i;
LocTriggerData.type = T_TriggerData;
LocTriggerData.tg_event = TRIGGER_EVENT_INSERT |
TRIGGER_EVENT_ROW |
TRIGGER_EVENT_INSTEAD;
LocTriggerData.tg_relation = relinfo->ri_RelationDesc;
LocTriggerData.tg_newtuple = NULL;
LocTriggerData.tg_oldtable = NULL;
LocTriggerData.tg_newtable = NULL;
LocTriggerData.tg_newtuplebuf = InvalidBuffer;
for (i = 0; i < trigdesc->numtriggers; i++)
{
Trigger *trigger = &trigdesc->triggers[i];
if (!TRIGGER_TYPE_MATCHES(trigger->tgtype,
TRIGGER_TYPE_ROW,
TRIGGER_TYPE_INSTEAD,
TRIGGER_TYPE_INSERT))
continue;
if (!TriggerEnabled(estate, relinfo, trigger, LocTriggerData.tg_event,
NULL, NULL, newtuple))
continue;
LocTriggerData.tg_trigtuple = oldtuple = newtuple;
LocTriggerData.tg_trigtuplebuf = InvalidBuffer;
LocTriggerData.tg_trigger = trigger;
newtuple = ExecCallTriggerFunc(&LocTriggerData,
i,
relinfo->ri_TrigFunctions,
relinfo->ri_TrigInstrument,
GetPerTupleMemoryContext(estate));
if (oldtuple != newtuple && oldtuple != slottuple)
heap_freetuple(oldtuple);
if (newtuple == NULL)
return NULL;
}
if (newtuple != slottuple)
{
TupleTableSlot *newslot = estate->es_trig_tuple_slot;
TupleDesc tupdesc = RelationGetDescr(relinfo->ri_RelationDesc);
if (newslot->tts_tupleDescriptor != tupdesc)
ExecSetSlotDescriptor(newslot, tupdesc);
ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);
slot = newslot;
}
return slot;
}
5、ExecForeignInsert
-- 函数指针
typedef TupleTableSlot *(*ExecForeignInsert_function) (EState *estate,
ResultRelInfo *rinfo,
TupleTableSlot *slot,
TupleTableSlot *planSlot);
ExecForeignInsert_function ExecForeignInsert;
6、RelationGetRelid
#define RelationGetRelid(relation) ((relation)->rd_id)
7、ExecWithCheckOptions
void
ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate)
{
Relation rel = resultRelInfo->ri_RelationDesc;
TupleDesc tupdesc = RelationGetDescr(rel);
ExprContext *econtext;
ListCell *l1,
*l2;
econtext = GetPerTupleExprContext(estate);
econtext->ecxt_scantuple = slot;
forboth(l1, resultRelInfo->ri_WithCheckOptions,
l2, resultRelInfo->ri_WithCheckOptionExprs)
{
WithCheckOption *wco = (WithCheckOption *) lfirst(l1);
ExprState *wcoExpr = (ExprState *) lfirst(l2);
if (wco->kind != kind)
continue;
if (!ExecQual(wcoExpr, econtext))
{
char *val_desc;
Bitmapset *modifiedCols;
Bitmapset *insertedCols;
Bitmapset *updatedCols;
switch (wco->kind)
{
case WCO_VIEW_CHECK:
if (resultRelInfo->ri_PartitionRoot)
{
HeapTuple tuple = ExecFetchSlotTuple(slot);
TupleDesc old_tupdesc = RelationGetDescr(rel);
TupleConversionMap *map;
rel = resultRelInfo->ri_PartitionRoot;
tupdesc = RelationGetDescr(rel);
map = convert_tuples_by_name(old_tupdesc, tupdesc,
gettext_noop("could not convert row type"));
if (map != NULL)
{
tuple = do_convert_tuple(tuple, map);
ExecSetSlotDescriptor(slot, tupdesc);
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
}
}
insertedCols = GetInsertedColumns(resultRelInfo, estate);
updatedCols = GetUpdatedColumns(resultRelInfo, estate);
modifiedCols = bms_union(insertedCols, updatedCols);
val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
slot,
tupdesc,
modifiedCols,
64);
ereport(ERROR,
(errcode(ERRCODE_WITH_CHECK_OPTION_VIOLATION),
errmsg("new row violates check option for view \"%s\"",
wco->relname),
val_desc ? errdetail("Failing row contains %s.",
val_desc) : 0));
break;
case WCO_RLS_INSERT_CHECK:
case WCO_RLS_UPDATE_CHECK:
if (wco->polname != NULL)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("new row violates row-level security policy \"%s\" for table \"%s\"",
wco->polname, wco->relname)));
else
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("new row violates row-level security policy for table \"%s\"",
wco->relname)));
break;
case WCO_RLS_CONFLICT_CHECK:
if (wco->polname != NULL)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("new row violates row-level security policy \"%s\" (USING expression) for table \"%s\"",
wco->polname, wco->relname)));
else
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("new row violates row-level security policy (USING expression) for table \"%s\"",
wco->relname)));
break;
default:
elog(ERROR, "unrecognized WCO kind: %u", wco->kind);
break;
}
}
}
}
8、ExecConstraints
void
ExecConstraints(ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate)
{
Relation rel = resultRelInfo->ri_RelationDesc;
TupleDesc tupdesc = RelationGetDescr(rel);
TupleConstr *constr = tupdesc->constr;
Bitmapset *modifiedCols;
Bitmapset *insertedCols;
Bitmapset *updatedCols;
Assert(constr || resultRelInfo->ri_PartitionCheck);
if (constr && constr->has_not_null)
{
int natts = tupdesc->natts;
int attrChk;
for (attrChk = 1; attrChk <= natts; attrChk++)
{
FORM_pg_attribute att = TupleDescAttr(tupdesc, attrChk - 1);
if (att->attnotnull && slot_attisnull(slot, attrChk))
{
char *val_desc;
Relation orig_rel = rel;
TupleDesc orig_tupdesc = RelationGetDescr(rel);
if (resultRelInfo->ri_PartitionRoot)
{
HeapTuple tuple = ExecFetchSlotTuple(slot);
TupleConversionMap *map;
rel = resultRelInfo->ri_PartitionRoot;
tupdesc = RelationGetDescr(rel);
map = convert_tuples_by_name(orig_tupdesc, tupdesc,
gettext_noop("could not convert row type"));
if (map != NULL)
{
tuple = do_convert_tuple(tuple, map);
ExecSetSlotDescriptor(slot, tupdesc);
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
}
}
insertedCols = GetInsertedColumns(resultRelInfo, estate);
updatedCols = GetUpdatedColumns(resultRelInfo, estate);
modifiedCols = bms_union(insertedCols, updatedCols);
val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
slot,
tupdesc,
modifiedCols,
64);
ereport(ERROR,
(errcode(ERRCODE_NOT_NULL_VIOLATION),
errmsg("null value in column \"%s\" violates not-null constraint",
NameStr(att->attname)),
val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
errtablecol(orig_rel, attrChk)));
}
}
}
if (constr && constr->num_check > 0)
{
const char *failed;
if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL)
{
char *val_desc;
Relation orig_rel = rel;
if (resultRelInfo->ri_PartitionRoot)
{
HeapTuple tuple = ExecFetchSlotTuple(slot);
TupleDesc old_tupdesc = RelationGetDescr(rel);
TupleConversionMap *map;
rel = resultRelInfo->ri_PartitionRoot;
tupdesc = RelationGetDescr(rel);
map = convert_tuples_by_name(old_tupdesc, tupdesc,
gettext_noop("could not convert row type"));
if (map != NULL)
{
tuple = do_convert_tuple(tuple, map);
ExecSetSlotDescriptor(slot, tupdesc);
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
}
}
insertedCols = GetInsertedColumns(resultRelInfo, estate);
updatedCols = GetUpdatedColumns(resultRelInfo, estate);
modifiedCols = bms_union(insertedCols, updatedCols);
val_desc = ExecBuildSlotValueDescription(RelationGetRelid(rel),
slot,
tupdesc,
modifiedCols,
64);
ereport(ERROR,
(errcode(ERRCODE_CHECK_VIOLATION),
errmsg("new row for relation \"%s\" violates check constraint \"%s\"",
RelationGetRelationName(orig_rel), failed),
val_desc ? errdetail("Failing row contains %s.", val_desc) : 0,
errtableconstraint(orig_rel, failed)));
}
}
}
9、ExecPartitionCheck
bool
ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
EState *estate, bool emitError)
{
ExprContext *econtext;
bool success;
if (resultRelInfo->ri_PartitionCheckExpr == NULL)
{
List *qual = resultRelInfo->ri_PartitionCheck;
resultRelInfo->ri_PartitionCheckExpr = ExecPrepareCheck(qual, estate);
}
econtext = GetPerTupleExprContext(estate);
econtext->ecxt_scantuple = slot;
success = ExecCheck(resultRelInfo->ri_PartitionCheckExpr, econtext);
if (!success && emitError)
ExecPartitionCheckEmitError(resultRelInfo, slot, estate);
return success;
}
10、ExecCheckIndexConstraints
bool
ExecCheckIndexConstraints(TupleTableSlot *slot,
EState *estate, ItemPointer conflictTid,
List *arbiterIndexes)
{
ResultRelInfo *resultRelInfo;
int i;
int numIndices;
RelationPtr relationDescs;
Relation heapRelation;
IndexInfo **indexInfoArray;
ExprContext *econtext;
Datum values[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS];
ItemPointerData invalidItemPtr;
bool checkedIndex = false;
ItemPointerSetInvalid(conflictTid);
ItemPointerSetInvalid(&invalidItemPtr);
resultRelInfo = estate->es_result_relation_info;
numIndices = resultRelInfo->ri_NumIndices;
relationDescs = resultRelInfo->ri_IndexRelationDescs;
indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
heapRelation = resultRelInfo->ri_RelationDesc;
econtext = GetPerTupleExprContext(estate);
econtext->ecxt_scantuple = slot;
for (i = 0; i < numIndices; i++)
{
Relation indexRelation = relationDescs[i];
IndexInfo *indexInfo;
bool satisfiesConstraint;
if (indexRelation == NULL)
continue;
indexInfo = indexInfoArray[i];
if (!indexInfo->ii_Unique && !indexInfo->ii_ExclusionOps)
continue;
if (!indexInfo->ii_ReadyForInserts)
continue;
if (arbiterIndexes != NIL &&
!list_member_oid(arbiterIndexes,
indexRelation->rd_index->indexrelid))
continue;
if (!indexRelation->rd_index->indimmediate)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("ON CONFLICT does not support deferrable unique constraints/exclusion constraints as arbiters"),
errtableconstraint(heapRelation,
RelationGetRelationName(indexRelation))));
checkedIndex = true;
if (indexInfo->ii_Predicate != NIL)
{
ExprState *predicate;
predicate = indexInfo->ii_PredicateState;
if (predicate == NULL)
{
predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
indexInfo->ii_PredicateState = predicate;
}
if (!ExecQual(predicate, econtext))
continue;
}
FormIndexDatum(indexInfo,
slot,
estate,
values,
isnull);
satisfiesConstraint =
check_exclusion_or_unique_constraint(heapRelation, indexRelation,
indexInfo, &invalidItemPtr,
values, isnull, estate, false,
CEOUC_WAIT, true,
conflictTid);
if (!satisfiesConstraint)
return false;
}
if (arbiterIndexes != NIL && !checkedIndex)
elog(ERROR, "unexpected failure to find arbiter index");
return true;
}
11、ExecOnConflictUpdate
static bool
ExecOnConflictUpdate(ModifyTableState *mtstate,
ResultRelInfo *resultRelInfo,
ItemPointer conflictTid,
TupleTableSlot *planSlot,
TupleTableSlot *excludedSlot,
EState *estate,
bool canSetTag,
TupleTableSlot **returning)
{
ExprContext *econtext = mtstate->ps.ps_ExprContext;
Relation relation = resultRelInfo->ri_RelationDesc;
ExprState *onConflictSetWhere = resultRelInfo->ri_onConflict->oc_WhereClause;
HeapTupleData tuple;
HeapUpdateFailureData hufd;
LockTupleMode lockmode;
HTSU_Result test;
Buffer buffer;
lockmode = ExecUpdateLockMode(estate, resultRelInfo);
tuple.t_self = *conflictTid;
test = heap_lock_tuple(relation, &tuple, estate->es_output_cid,
lockmode, LockWaitBlock, false, &buffer,
&hufd);
switch (test)
{
case HeapTupleMayBeUpdated:
break;
case HeapTupleInvisible:
if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple.t_data)))
ereport(ERROR,
(errcode(ERRCODE_CARDINALITY_VIOLATION),
errmsg("ON CONFLICT DO UPDATE command cannot affect row a second time"),
errhint("Ensure that no rows proposed for insertion within the same command have duplicate constrained values.")));
elog(ERROR, "attempted to lock invisible tuple");
break;
case HeapTupleSelfUpdated:
elog(ERROR, "unexpected self-updated tuple");
break;
case HeapTupleUpdated:
if (IsolationUsesXactSnapshot())
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));
Assert(!ItemPointerIndicatesMovedPartitions(&hufd.ctid));
ReleaseBuffer(buffer);
return false;
default:
elog(ERROR, "unrecognized heap_lock_tuple status: %u", test);
}
ResetExprContext(econtext);
ExecCheckHeapTupleVisible(estate, &tuple, buffer);
ExecStoreTuple(&tuple, mtstate->mt_existing, buffer, false);
econtext->ecxt_scantuple = mtstate->mt_existing;
econtext->ecxt_innertuple = excludedSlot;
econtext->ecxt_outertuple = NULL;
if (!ExecQual(onConflictSetWhere, econtext))
{
ReleaseBuffer(buffer);
InstrCountFiltered1(&mtstate->ps, 1);
return true;
}
if (resultRelInfo->ri_WithCheckOptions != NIL)
{
ExecWithCheckOptions(WCO_RLS_CONFLICT_CHECK, resultRelInfo,
mtstate->mt_existing,
mtstate->ps.state);
}
ExecProject(resultRelInfo->ri_onConflict->oc_ProjInfo);
*returning = ExecUpdate(mtstate, &tuple.t_self, NULL,
mtstate->mt_conflproj, planSlot,
&mtstate->mt_epqstate, mtstate->ps.state,
canSetTag);
ReleaseBuffer(buffer);
return true;
}
12、InstrCountTuples2
#define InstrCountTuples2(node, delta) \
do { \
if (((PlanState *)(node))->instrument) \
((PlanState *)(node))->instrument->ntuples2 += (delta); \
} while (0)
13、ExecCheckTIDVisible
static void
ExecCheckTIDVisible(EState *estate,
ResultRelInfo *relinfo,
ItemPointer tid)
{
Relation rel = relinfo->ri_RelationDesc;
Buffer buffer;
HeapTupleData tuple;
if (!IsolationUsesXactSnapshot())
return;
tuple.t_self = *tid;
if (!heap_fetch(rel, SnapshotAny, &tuple, &buffer, false, NULL))
elog(ERROR, "failed to fetch conflicting tuple for ON CONFLICT");
ExecCheckHeapTupleVisible(estate, &tuple, buffer);
ReleaseBuffer(buffer);
}
14、SpeculativeInsertionLockAcquire
uint32
SpeculativeInsertionLockAcquire(TransactionId xid)
{
LOCKTAG tag;
speculativeInsertionToken++;
if (speculativeInsertionToken == 0)
speculativeInsertionToken = 1;
SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
(void) LockAcquire(&tag, ExclusiveLock, false, false);
return speculativeInsertionToken;
}
15、HeapTupleHeaderSetSpeculativeToken
#define HeapTupleHeaderSetSpeculativeToken(tup, token) \
( \
ItemPointerSet(&(tup)->t_ctid, token, SpecTokenOffsetNumber) \
)
16、heap_insert
//上一节已介绍
17、ExecInsertIndexTuples
List *
ExecInsertIndexTuples(TupleTableSlot *slot,
ItemPointer tupleid,
EState *estate,
bool noDupErr,
bool *specConflict,
List *arbiterIndexes)
{
List *result = NIL;
ResultRelInfo *resultRelInfo;
int i;
int numIndices;
RelationPtr relationDescs;
Relation heapRelation;
IndexInfo **indexInfoArray;
ExprContext *econtext;
Datum values[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS];
resultRelInfo = estate->es_result_relation_info;
numIndices = resultRelInfo->ri_NumIndices;
relationDescs = resultRelInfo->ri_IndexRelationDescs;
indexInfoArray = resultRelInfo->ri_IndexRelationInfo;
heapRelation = resultRelInfo->ri_RelationDesc;
econtext = GetPerTupleExprContext(estate);
econtext->ecxt_scantuple = slot;
for (i = 0; i < numIndices; i++)
{
Relation indexRelation = relationDescs[i];
IndexInfo *indexInfo;
bool applyNoDupErr;
IndexUniqueCheck checkUnique;
bool satisfiesConstraint;
if (indexRelation == NULL)
continue;
indexInfo = indexInfoArray[i];
if (!indexInfo->ii_ReadyForInserts)
continue;
if (indexInfo->ii_Predicate != NIL)
{
ExprState *predicate;
predicate = indexInfo->ii_PredicateState;
if (predicate == NULL)
{
predicate = ExecPrepareQual(indexInfo->ii_Predicate, estate);
indexInfo->ii_PredicateState = predicate;
}
if (!ExecQual(predicate, econtext))
continue;
}
FormIndexDatum(indexInfo,
slot,
estate,
values,
isnull);
applyNoDupErr = noDupErr &&
(arbiterIndexes == NIL ||
list_member_oid(arbiterIndexes,
indexRelation->rd_index->indexrelid));
if (!indexRelation->rd_index->indisunique)
checkUnique = UNIQUE_CHECK_NO;
else if (applyNoDupErr)
checkUnique = UNIQUE_CHECK_PARTIAL;
else if (indexRelation->rd_index->indimmediate)
checkUnique = UNIQUE_CHECK_YES;
else
checkUnique = UNIQUE_CHECK_PARTIAL;
satisfiesConstraint =
index_insert(indexRelation,
values,
isnull,
tupleid,
heapRelation,
checkUnique,
indexInfo);
if (indexInfo->ii_ExclusionOps != NULL)
{
bool violationOK;
CEOUC_WAIT_MODE waitMode;
if (applyNoDupErr)
{
violationOK = true;
waitMode = CEOUC_LIVELOCK_PREVENTING_WAIT;
}
else if (!indexRelation->rd_index->indimmediate)
{
violationOK = true;
waitMode = CEOUC_NOWAIT;
}
else
{
violationOK = false;
waitMode = CEOUC_WAIT;
}
satisfiesConstraint =
check_exclusion_or_unique_constraint(heapRelation,
indexRelation, indexInfo,
tupleid, values, isnull,
estate, false,
waitMode, violationOK, NULL);
}
if ((checkUnique == UNIQUE_CHECK_PARTIAL ||
indexInfo->ii_ExclusionOps != NULL) &&
!satisfiesConstraint)
{
result = lappend_oid(result, RelationGetRelid(indexRelation));
if (indexRelation->rd_index->indimmediate && specConflict)
*specConflict = true;
}
}
return result;
}
18、heap_finish_speculative
void
heap_finish_speculative(Relation relation, HeapTuple tuple)
{
Buffer buffer;
Page page;
OffsetNumber offnum;
ItemId lp = NULL;
HeapTupleHeader htup;
buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&(tuple->t_self)));
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
page = (Page) BufferGetPage(buffer);
offnum = ItemPointerGetOffsetNumber(&(tuple->t_self));
if (PageGetMaxOffsetNumber(page) >= offnum)
lp = PageGetItemId(page, offnum);
if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
elog(ERROR, "invalid lp");
htup = (HeapTupleHeader) PageGetItem(page, lp);
StaticAssertStmt(MaxOffsetNumber < SpecTokenOffsetNumber,
"invalid speculative token constant");
START_CRIT_SECTION();
Assert(HeapTupleHeaderIsSpeculative(tuple->t_data));
MarkBufferDirty(buffer);
htup->t_ctid = tuple->t_self;
if (RelationNeedsWAL(relation))
{
xl_heap_confirm xlrec;
XLogRecPtr recptr;
xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
XLogBeginInsert();
XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
XLogReGISterData((char *) &xlrec, SizeOfHeapConfirm);
XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_CONFIRM);
PageSetLSN(page, recptr);
}
END_CRIT_SECTION();
UnlockReleaseBuffer(buffer);
}
19、heap_abort_speculative
void
heap_abort_speculative(Relation relation, HeapTuple tuple)
{
TransactionId xid = GetCurrentTransactionId();
ItemPointer tid = &(tuple->t_self);
ItemId lp;
HeapTupleData tp;
Page page;
BlockNumber block;
Buffer buffer;
Assert(ItemPointerIsValid(tid));
block = ItemPointerGetBlockNumber(tid);
buffer = ReadBuffer(relation, block);
page = BufferGetPage(buffer);
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
Assert(!PageIsAllVisible(page));
lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
Assert(ItemIdIsNormal(lp));
tp.t_tableOid = RelationGetRelid(relation);
tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
tp.t_len = ItemIdGetLength(lp);
tp.t_self = *tid;
if (tp.t_data->t_choice.t_heap.t_xmin != xid)
elog(ERROR, "attempted to kill a tuple inserted by another transaction");
if (!(IsToastRelation(relation) || HeapTupleHeaderIsSpeculative(tp.t_data)))
elog(ERROR, "attempted to kill a non-speculative tuple");
Assert(!HeapTupleHeaderIsHeapOnly(tp.t_data));
START_CRIT_SECTION();
Assert(TransactionIdIsValid(RecentGlobalXmin));
PageSetPrunable(page, RecentGlobalXmin);
tp.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);
tp.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
HeapTupleHeaderSetXmin(tp.t_data, InvalidTransactionId);
tp.t_data->t_ctid = tp.t_self;
MarkBufferDirty(buffer);
if (RelationNeedsWAL(relation))
{
xl_heap_delete xlrec;
XLogRecPtr recptr;
xlrec.flags = XLH_DELETE_IS_SUPER;
xlrec.infobits_set = compute_infobits(tp.t_data->t_infomask,
tp.t_data->t_infomask2);
xlrec.offnum = ItemPointerGetOffsetNumber(&tp.t_self);
xlrec.xmax = xid;
XLogBeginInsert();
XLogRegisterData((char *) &xlrec, SizeOfHeapDelete);
XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_DELETE);
PageSetLSN(page, recptr);
}
END_CRIT_SECTION();
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
if (HeapTupleHasExternal(&tp))
{
Assert(!IsToastRelation(relation));
toast_delete(relation, &tp, true);
}
ReleaseBuffer(buffer);
pgstat_count_heap_delete(relation);
}
20、SpeculativeInsertionLockRelease
void
SpeculativeInsertionLockRelease(TransactionId xid)
{
LOCKTAG tag;
SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
LockRelease(&tag, ExclusiveLock, false);
}
21、list_free
void
list_free(List *list)
{
list_free_private(list, false);
}
static void
list_free_private(List *list, bool deep)
{
ListCell *cell;
check_list_invariants(list);
cell = list_head(list);
while (cell != NULL)
{
ListCell *tmp = cell;
cell = lnext(cell);
if (deep)
pfree(lfirst(tmp));
pfree(tmp);
}
if (list)
pfree(list);
}
22、setLastTid
void
setLastTid(const ItemPointer tid)
{
Current_last_tid = *tid;
}
23、ExecARUpdateTriggers
void
ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
ItemPointer tupleid,
HeapTuple fdw_trigtuple,
HeapTuple newtuple,
List *recheckIndexes,
TransitionCaptureState *transition_capture)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
if ((trigdesc && trigdesc->trig_update_after_row) ||
(transition_capture &&
(transition_capture->tcs_update_old_table ||
transition_capture->tcs_update_new_table)))
{
HeapTuple trigtuple;
if (fdw_trigtuple == NULL && ItemPointerIsValid(tupleid))
trigtuple = GetTupleForTrigger(estate,
NULL,
relinfo,
tupleid,
LockTupleExclusive,
NULL);
else
trigtuple = fdw_trigtuple;
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_UPDATE,
true, trigtuple, newtuple, recheckIndexes,
GetUpdatedColumns(relinfo, estate),
transition_capture);
if (trigtuple != fdw_trigtuple)
heap_freetuple(trigtuple);
}
}
24、ExecARInsertTriggers
void
ExecARInsertTriggers(EState *estate, ResultRelInfo *relinfo,
HeapTuple trigtuple, List *recheckIndexes,
TransitionCaptureState *transition_capture)
{
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
if ((trigdesc && trigdesc->trig_insert_after_row) ||
(transition_capture && transition_capture->tcs_insert_new_table))
AfterTriggerSaveEvent(estate, relinfo, TRIGGER_EVENT_INSERT,
true, NULL, trigtuple,
recheckIndexes, NULL,
transition_capture);
}
25、ExecProcessReturning
static TupleTableSlot *
ExecProcessReturning(ResultRelInfo *resultRelInfo,
TupleTableSlot *tupleSlot,
TupleTableSlot *planSlot)
{
ProjectionInfo *projectReturning = resultRelInfo->ri_projectReturning;
ExprContext *econtext = projectReturning->pi_exprContext;
ResetExprContext(econtext);
if (tupleSlot)
econtext->ecxt_scantuple = tupleSlot;
else
{
HeapTuple tuple;
Assert(!TupIsNull(econtext->ecxt_scantuple));
tuple = ExecMaterializeSlot(econtext->ecxt_scantuple);
tuple->t_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
}
econtext->ecxt_outertuple = planSlot;
return ExecProject(projectReturning);
}
这部分源码需要二次解读(2018-8-6 Mark)
static TupleTableSlot *
ExecInsert(ModifyTableState *mtstate,
TupleTableSlot *slot,
TupleTableSlot *planSlot,
EState *estate,
bool canSetTag)
{
HeapTuple tuple;//要插入的tuple
ResultRelInfo *resultRelInfo;//执行更新操作时Relation相关的所有信息
Relation resultRelationDesc;//目标Relation信息
Oid newId;//数据表Oid
List *recheckIndexes = NIL;//需要检查的Index的列表
TupleTableSlot *result = NULL;//结果Tuple对应的Slot
TransitionCaptureState *ar_insert_trig_tcs;//TODO
ModifyTable *node = (ModifyTable *) mtstate->ps.plan;//更新表Node
OnConflictAction onconflict = node->onConflictAction;//冲突处理
tuple = ExecMaterializeSlot(slot);//"物化"Tuple
//获取Relation相关信息
resultRelInfo = estate->es_result_relation_info;
resultRelationDesc = resultRelInfo->ri_RelationDesc;
//设置Oid为InvalidOid(0),在heap_insert时会更新Oid
if (resultRelationDesc->rd_rel->relhasoids)
HeapTupleSetOid(tuple, InvalidOid);
//触发器-TODO
if (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_insert_before_row)
{
slot = ExecBRInsertTriggers(estate, resultRelInfo, slot);
if (slot == NULL)
return NULL;
tuple = ExecMaterializeSlot(slot);
}
//触发器-TODO
if (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_insert_instead_row)
{
slot = ExecIRInsertTriggers(estate, resultRelInfo, slot);
if (slot == NULL)
return NULL;
tuple = ExecMaterializeSlot(slot);
newId = InvalidOid;
}
else if (resultRelInfo->ri_FdwRoutine)//FDW-TODO
{
slot = resultRelInfo->ri_FdwRoutine->ExecForeignInsert(estate,
resultRelInfo,
slot,
planSlot);
if (slot == NULL)
return NULL;
tuple = ExecMaterializeSlot(slot);
tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
newId = InvalidOid;
}
else//正常数据表
{
WCOKind wco_kind;//With Check Option类型
//获取RelationID
tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
//With Check Option类型:Update OR Insert?
wco_kind = (mtstate->operation == CMD_UPDATE) ?
WCO_RLS_UPDATE_CHECK : WCO_RLS_INSERT_CHECK;
//执行检查
if (resultRelInfo->ri_WithCheckOptions != NIL)
ExecWithCheckOptions(wco_kind, resultRelInfo, slot, estate);
//检查约束
if (resultRelationDesc->rd_att->constr)
ExecConstraints(resultRelInfo, slot, estate);
//分区表
if (resultRelInfo->ri_PartitionCheck &&
(resultRelInfo->ri_PartitionRoot == NULL ||
(resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_insert_before_row)))
ExecPartitionCheck(resultRelInfo, slot, estate, true);
//索引检查
if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0)
{
uint32 specToken;//Token
ItemPointerData conflictTid;//数据行指针
bool specConflict;//冲突声明
List *arbiterIndexes;//相关索引
arbiterIndexes = resultRelInfo->ri_onConflictArbiterIndexes;
vlock:
specConflict = false;
if (!ExecCheckIndexConstraints(slot, estate, &conflictTid,
arbiterIndexes))
{
if (onconflict == ONCONFLICT_UPDATE)
{
TupleTableSlot *returning = NULL;
if (ExecOnConflictUpdate(mtstate, resultRelInfo,
&conflictTid, planSlot, slot,
estate, canSetTag, &returning))
{
InstrCountTuples2(&mtstate->ps, 1);
return returning;
}
else
Goto vlock;
}
else
{
Assert(onconflict == ONCONFLICT_NOTHING);
ExecCheckTIDVisible(estate, resultRelInfo, &conflictTid);
InstrCountTuples2(&mtstate->ps, 1);
return NULL;
}
}
specToken = SpeculativeInsertionLockAcquire(GetCurrentTransactionId());
HeapTupleHeaderSetSpeculativeToken(tuple->t_data, specToken);
newId = heap_insert(resultRelationDesc, tuple,
estate->es_output_cid,
HEAP_INSERT_SPECULATIVE,
NULL);
recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
estate, true, &specConflict,
arbiterIndexes);
if (!specConflict)
heap_finish_speculative(resultRelationDesc, tuple);
else
heap_abort_speculative(resultRelationDesc, tuple);
SpeculativeInsertionLockRelease(GetCurrentTransactionId());
if (specConflict)
{
list_free(recheckIndexes);
goto vlock;
}
}
else//无需Index检查
{
newId = heap_insert(resultRelationDesc, tuple,
estate->es_output_cid,
0, NULL);//插入数据
if (resultRelInfo->ri_NumIndices > 0)
recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
estate, false, NULL,
NIL);//索引
}
}
if (canSetTag)
{
(estate->es_processed)++;
estate->es_lastoid = newId;
setLastTid(&(tuple->t_self));
}
//触发器-TODO
ar_insert_trig_tcs = mtstate->mt_transition_capture;
if (mtstate->operation == CMD_UPDATE && mtstate->mt_transition_capture
&& mtstate->mt_transition_capture->tcs_update_new_table)
{
ExecARUpdateTriggers(estate, resultRelInfo, NULL,
NULL,
tuple,
NULL,
mtstate->mt_transition_capture);
ar_insert_trig_tcs = NULL;
}
ExecARInsertTriggers(estate, resultRelInfo, tuple, recheckIndexes,
ar_insert_trig_tcs);
list_free(recheckIndexes);
if (resultRelInfo->ri_WithCheckOptions != NIL)
ExecWithCheckOptions(WCO_VIEW_CHECK, resultRelInfo, slot, estate);
if (resultRelInfo->ri_projectReturning)
result = ExecProcessReturning(resultRelInfo, slot, planSlot);
return result;
}
添加主键,插入测试数据:
testdb=# -- 获取pid
testdb=# select pg_backend_pid();
pg_backend_pid
----------------
1527
(1 row)
testdb=#
testdb=# -- 添加主键
testdb=# alter table t_insert add constraint pk_t_insert primary key(id);
ALTER TABLE
testdb=# insert into t_insert values(12,'12','12','12');
(挂起)
启动gdb
[root@localhost ~]# gdb -p 1527
GNU gdb (GDB) Red Hat Enterprise linux 7.6.1-100.el7
Copyright (C) 2013 Free Software Foundation, Inc.
...
(gdb) b ExecInsert
Breakpoint 1 at 0x6c0227: file nodeModifyTable.c, line 273.
#查看输入参数
(gdb) p *mtstate
$1 = {ps = {type = T_ModifyTableState, plan = 0x1257fa0, state = 0x130bf80, ExecProcNode = 0x6c2485 <ExecModifyTable>, ExecProcNodeReal = 0x6c2485 <ExecModifyTable>, instrument = 0x0,
worker_instrument = 0x0, qual = 0x0, lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x130d1e0, ps_ExprContext = 0x0, ps_ProjInfo = 0x0,
scandesc = 0x0}, operation = CMD_INSERT, canSetTag = true, mt_done = false, mt_plans = 0x130c4e0, mt_nplans = 1, mt_whichplan = 0, resultRelInfo = 0x130c1c0, rootResultRelInfo = 0x0,
mt_arowmarks = 0x130c4f8, mt_epqstate = {estate = 0x0, planstate = 0x0, origslot = 0x130c950, plan = 0x132de88, arowMarks = 0x0, epqParam = 0}, fireBSTriggers = false, mt_existing = 0x0,
mt_excludedtlist = 0x0, mt_conflproj = 0x0, mt_partition_tuple_routing = 0x0, mt_transition_capture = 0x0, mt_oc_transition_capture = 0x0, mt_per_subplan_tupconv_maps = 0x0}
(gdb) p *(mtstate->ps->plan)
$2 = {type = T_ModifyTable, startup_cost = 0, total_cost = 0.01, plan_rows = 1, plan_width = 136, parallel_aware = false, parallel_safe = false, plan_node_id = 0, targetlist = 0x0, qual = 0x0,
lefttree = 0x0, righttree = 0x0, initPlan = 0x0, extParam = 0x0, allParam = 0x0}
(gdb) p *(mtstate->ps->state)
$3 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x1309fa0, es_crosscheck_snapshot = 0x0, es_range_table = 0x132e1f8, es_plannedstmt = 0x1258420,
es_sourceText = 0x1256ef0 "insert into t_insert values(12,'12','12','12');", es_junkFilter = 0x0, es_output_cid = 0, es_result_relations = 0x130c1c0, es_num_result_relations = 1,
es_result_relation_info = 0x130c1c0, es_root_result_relations = 0x0, es_num_root_result_relations = 0, es_tuple_routing_result_relations = 0x0, es_trig_target_relations = 0x0,
es_trig_tuple_slot = 0x130d290, es_trig_oldtup_slot = 0x0, es_trig_newtup_slot = 0x0, es_param_list_info = 0x0, es_param_exec_vals = 0x130c190, es_queryEnv = 0x0, es_query_cxt = 0x130be70,
es_tupleTable = 0x130c810, es_rowMarks = 0x0, es_processed = 0, es_lastoid = 0, es_top_eflags = 0, es_instrument = 0, es_finished = false, es_exprcontexts = 0x130c7b0, es_subplanstates = 0x0,
es_auxmodifytables = 0x0, es_per_tuple_exprcontext = 0x0, es_epqTuple = 0x0, es_epqTupleSet = 0x0, es_epqScanDone = 0x0, es_use_parallel_mode = false, es_query_dsa = 0x0, es_jit_flags = 0,
es_jit = 0x0}
(gdb) p *(mtstate->ps->ps_ResultTupleSlot)
$4 = {type = T_TupleTableSlot, tts_isempty = true, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false, tts_tuple = 0x0, tts_tupleDescriptor = 0x130d1b0, tts_mcxt = 0x130be70,
tts_buffer = 0, tts_nvalid = 0, tts_values = 0x130d240, tts_isnull = 0x130d240, tts_mintuple = 0x0, tts_minhdr = {t_len = 0, t_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 0},
t_tableOid = 0, t_data = 0x0}, tts_off = 0, tts_fixedTupleDescriptor = true}
(gdb) p *(mtstate->ps->ps_ResultTupleSlot->tts_tupleDescriptor)
$5 = {natts = 0, tdtypeid = 2249, tdtypmod = -1, tdhasoid = false, tdrefcount = -1, constr = 0x0, attrs = 0x130d1d0}
(gdb) p *(mtstate->ps->ps_ResultTupleSlot->tts_tupleDescriptor->attrs)
$6 = {attrelid = 128, attname = {
data = "\000\000\000\000p\276\060\001\000\000\000\000\b\000\000\000\001", '\000' <repeats 11 times>, "\260\321\060\001\000\000\000\000p\276\060\001", '\000' <repeats 12 times>, "@\322\060\001\000\000\000\000@\322\060\001"}, atttypid = 0, attstattarget = 0, attlen = 0, attnum = 0, attndims = 0, attcacheoff = 0, atttypmod = 0, attbyval = false, attstorage = 0 '\000', attalign = 0 '\000',
attnotnull = false, atthasdef = false, atthasmissing = false, attidentity = 0 '\000', attisdropped = false, attislocal = false, attinhcount = 0, attcollation = 1}
$7 = (PlanState *) 0x130c560
(gdb) p **(mtstate->mt_plans)
$8 = {type = T_ResultState, plan = 0x132de88, state = 0x130bf80, ExecProcNode = 0x6c5094 <ExecResult>, ExecProcNodeReal = 0x6c5094 <ExecResult>, instrument = 0x0, worker_instrument = 0x0, qual = 0x0,
lefttree = 0x0, righttree = 0x0, initPlan = 0x0, subPlan = 0x0, chgParam = 0x0, ps_ResultTupleSlot = 0x130c950, ps_ExprContext = 0x130c670, ps_ProjInfo = 0x130c700, scandesc = 0x0}
(gdb) p **(mtstate->resultRelInfo)
Structure has no component named operator*.
(gdb) p *(mtstate->resultRelInfo)
$9 = {type = T_ResultRelInfo, ri_RangeTableIndex = 1, ri_RelationDesc = 0x7f2af957d9e8, ri_NumIndices = 1, ri_IndexRelationDescs = 0x130c7e0, ri_IndexRelationInfo = 0x130c7f8, ri_TrigDesc = 0x0,
ri_TrigFunctions = 0x0, ri_TrigWhenExprs = 0x0, ri_TrigInstrument = 0x0, ri_FdwRoutine = 0x0, ri_FdwState = 0x0, ri_usesFdwDirectModify = false, ri_WithCheckOptions = 0x0,
ri_WithCheckOptionExprs = 0x0, ri_ConstraintExprs = 0x0, ri_junkFilter = 0x0, ri_returningList = 0x0, ri_projectReturning = 0x0, ri_onConflictArbiterIndexes = 0x0, ri_onConflict = 0x0,
ri_PartitionCheck = 0x0, ri_PartitionCheckExpr = 0x0, ri_PartitionRoot = 0x0, ri_PartitionReadyForRouting = false}
(gdb) p *(mtstate->resultRelInfo->ri_RelationDesc)
$10 = {rd_node = {spcNode = 1663, dbNode = 16477, relNode = 26731}, rd_smgr = 0x0, rd_refcnt = 1, rd_backend = -1, rd_islocaltemp = false, rd_isnailed = false, rd_isvalid = true,
rd_indexvalid = 1 '\001', rd_statvalid = false, rd_createSubid = 0, rd_newRelfilenodeSubid = 0, rd_rel = 0x7f2af94c31a8, rd_att = 0x7f2af957f6e8, rd_id = 26731, rd_lockInfo = {lockRelId = {
relId = 26731, dbId = 16477}}, rd_rules = 0x0, rd_rulescxt = 0x0, trigdesc = 0x0, rd_rsdesc = 0x0, rd_fkeylist = 0x0, rd_fkeyvalid = false, rd_parTKEycxt = 0x0, rd_partkey = 0x0, rd_pdcxt = 0x0,
rd_partdesc = 0x0, rd_partcheck = 0x0, rd_indexlist = 0x7f2af94c2818, rd_oidindex = 0, rd_pkindex = 26737, rd_replidindex = 26737, rd_statlist = 0x0, rd_indexattr = 0x0, rd_projindexattr = 0x0,
rd_keyattr = 0x0, rd_pkattr = 0x0, rd_idattr = 0x0, rd_projidx = 0x0, rd_pubactions = 0x0, rd_options = 0x0, rd_index = 0x0, rd_indextuple = 0x0, rd_amhandler = 0, rd_indexcxt = 0x0,
rd_amroutine = 0x0, rd_opfamily = 0x0, rd_opcintype = 0x0, rd_support = 0x0, rd_supportinfo = 0x0, rd_indoption = 0x0, rd_indexprs = 0x0, rd_indpred = 0x0, rd_exclops = 0x0, rd_exclprocs = 0x0,
rd_exclstrats = 0x0, rd_amcache = 0x0, rd_indcollation = 0x0, rd_fdwroutine = 0x0, rd_toastoid = 0, pgstat_info = 0x12d5850}
(gdb)
#第2个参数slot
(gdb) p *slot
$11 = {type = T_TupleTableSlot, tts_isempty = false, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false, tts_tuple = 0x0, tts_tupleDescriptor = 0x130cb70, tts_mcxt = 0x130be70,
tts_buffer = 0, tts_nvalid = 4, tts_values = 0x130c9b0, tts_isnull = 0x130c9d0, tts_mintuple = 0x0, tts_minhdr = {t_len = 0, t_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 0},
t_tableOid = 0, t_data = 0x0}, tts_off = 0, tts_fixedTupleDescriptor = true}
(gdb) p *(slot->tts_tupleDescriptor)
$12 = {natts = 4, tdtypeid = 2249, tdtypmod = -1, tdhasoid = false, tdrefcount = -1, constr = 0x0, attrs = 0x130cb90}
(gdb) p *(slot->tts_values)
$13 = 12
(gdb) p *(slot->tts_isnull)
$14 = false
#参数planSlot
(gdb) p *planSlot
$15 = {type = T_TupleTableSlot, tts_isempty = false, tts_shouldFree = false, tts_shouldFreeMin = false, tts_slow = false, tts_tuple = 0x0, tts_tupleDescriptor = 0x130cb70, tts_mcxt = 0x130be70,
tts_buffer = 0, tts_nvalid = 4, tts_values = 0x130c9b0, tts_isnull = 0x130c9d0, tts_mintuple = 0x0, tts_minhdr = {t_len = 0, t_self = {ip_blkid = {bi_hi = 0, bi_lo = 0}, ip_posid = 0},
t_tableOid = 0, t_data = 0x0}, tts_off = 0, tts_fixedTupleDescriptor = true}
(gdb) p *(planSlot->tts_mcxt)
$16 = {type = T_AllocSetContext, isReset = false, allowInCritSection = false, methods = 0xb8c720 <AllocSetMethods>, parent = 0x131f150, firstchild = 0x130fe90, prevchild = 0x0, nextchild = 0x0,
name = 0xb1a840 "ExecutorState", ident = 0x0, reset_cbs = 0x0}
#参数estate
(gdb) p *estate
$17 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x1309fa0, es_crosscheck_snapshot = 0x0, es_range_table = 0x132e1f8, es_plannedstmt = 0x1258420,
es_sourceText = 0x1256ef0 "insert into t_insert values(12,'12','12','12');", es_junkFilter = 0x0, es_output_cid = 0, es_result_relations = 0x130c1c0, es_num_result_relations = 1,
es_result_relation_info = 0x130c1c0, es_root_result_relations = 0x0, es_num_root_result_relations = 0, es_tuple_routing_result_relations = 0x0, es_trig_target_relations = 0x0,
es_trig_tuple_slot = 0x130d290, es_trig_oldtup_slot = 0x0, es_trig_newtup_slot = 0x0, es_param_list_info = 0x0, es_param_exec_vals = 0x130c190, es_queryEnv = 0x0, es_query_cxt = 0x130be70,
es_tupleTable = 0x130c810, es_rowMarks = 0x0, es_processed = 0, es_lastoid = 0, es_top_eflags = 0, es_instrument = 0, es_finished = false, es_exprcontexts = 0x130c7b0, es_subplanstates = 0x0,
es_auxmodifytables = 0x0, es_per_tuple_exprcontext = 0x0, es_epqTuple = 0x0, es_epqTupleSet = 0x0, es_epqScanDone = 0x0, es_use_parallel_mode = false, es_query_dsa = 0x0, es_jit_flags = 0,
es_jit = 0x0}
(gdb) p *(estate->es_snapshot)
$18 = {satisfies = 0x9f73fc <HeapTupleSatisfiesmvcC>, xmin = 1612861, xmax = 1612861, xip = 0x0, xcnt = 0, subxip = 0x0, subxcnt = 0, suboverflowed = false, takenDuringRecovery = false, copied = true,
curcid = 0, speculativeToken = 0, active_count = 1, regd_count = 2, ph_node = {first_child = 0xe7bac0 <CatalogSnapshotData+64>, next_sibling = 0x0, prev_or_parent = 0x0}, whenTaken = 0, lsn = 0}
(gdb)
#参数canSetTag
(gdb) p canSetTag
$19 = true
#进入函数内部
(gdb) next
274 TupleTableSlot *result = NULL;
(gdb)
276 ModifyTable *node = (ModifyTable *) mtstate->ps.plan;
(gdb) p *node
$20 = {plan = {type = 1005513616, startup_cost = 3.502247076882698e-317, total_cost = 9.8678822363083824e-317, plan_rows = 4.1888128009757547e-314, plan_width = 3, parallel_aware = 253,
parallel_safe = 127, plan_node_id = 10076823, targetlist = 0x686b0000405d, qual = 0x130c2d0, lefttree = 0x0, righttree = 0x130c1c0, initPlan = 0x6c2485 <ExecModifyTable>, extParam = 0x0,
allParam = 0x7ffd3beeeb50}, operation = 6923989, canSetTag = false, nominalRelation = 4183284200, partitioned_rels = 0x130c1c0, partColsUpdated = 128, resultRelations = 0x1257fa0,
resultRelIndex = 19974480, rootResultRelIndex = 0, plans = 0x0, withCheckOptionLists = 0x33beeeb50, returningLists = 0x130bf80, fdwPrivLists = 0x0, fdwDirectModifyPlans = 0x130c2d0, rowMarks = 0x0,
epqParam = 0, onConflictAction = ONCONFLICT_NONE, arbiterIndexes = 0x130c950, onConflictSet = 0x0, onConflictWhere = 0x130c560, exclRelRTI = 19972544, exclRelTlist = 0x0}
(gdb)
(gdb) p onconflict
$21 = ONCONFLICT_NONE
...
(gdb) next
289 resultRelationDesc = resultRelInfo->ri_RelationDesc;
(gdb) p *resultRelInfo
$26 = {type = T_ResultRelInfo, ri_RangeTableIndex = 1, ri_RelationDesc = 0x7f2af957d9e8, ri_NumIndices = 1, ri_IndexRelationDescs = 0x130c7e0, ri_IndexRelationInfo = 0x130c7f8, ri_TrigDesc = 0x0,
ri_TrigFunctions = 0x0, ri_TrigWhenExprs = 0x0, ri_TrigInstrument = 0x0, ri_FdwRoutine = 0x0, ri_FdwState = 0x0, ri_usesFdwDirectModify = false, ri_WithCheckOptions = 0x0,
ri_WithCheckOptionExprs = 0x0, ri_ConstraintExprs = 0x0, ri_junkFilter = 0x0, ri_returningList = 0x0, ri_projectReturning = 0x0, ri_onConflictArbiterIndexes = 0x0, ri_onConflict = 0x0,
ri_PartitionCheck = 0x0, ri_PartitionCheckExpr = 0x0, ri_PartitionRoot = 0x0, ri_PartitionReadyForRouting = false}
(gdb) p *(tuple->t_data)
$27 = {t_choice = {t_heap = {t_xmin = 244, t_xmax = 4294967295, t_field3 = {t_cid = 2249, t_xvac = 2249}}, t_datum = {datum_len_ = 244, datum_typmod = -1, datum_typeid = 2249}}, t_ctid = {ip_blkid = {
bi_hi = 65535, bi_lo = 65535}, ip_posid = 0}, t_infomask2 = 4, t_infomask = 2, t_hoff = 24 '\030', t_bits = 0x130d36f ""}
(gdb) p *(tuple)
$28 = {t_len = 61, t_self = {ip_blkid = {bi_hi = 65535, bi_lo = 65535}, ip_posid = 0}, t_tableOid = 0, t_data = 0x130d358}
(gdb)
(gdb) p *resultRelationDesc
$29 = {rd_node = {spcNode = 1663, dbNode = 16477, relNode = 26731}, rd_smgr = 0x0, rd_refcnt = 1, rd_backend = -1, rd_islocaltemp = false, rd_isnailed = false, rd_isvalid = true,
rd_indexvalid = 1 '\001', rd_statvalid = false, rd_createSubid = 0, rd_newRelfilenodeSubid = 0, rd_rel = 0x7f2af94c31a8, rd_att = 0x7f2af957f6e8, rd_id = 26731, rd_lockInfo = {lockRelId = {
relId = 26731, dbId = 16477}}, rd_rules = 0x0, rd_rulescxt = 0x0, trigdesc = 0x0, rd_rsdesc = 0x0, rd_fkeylist = 0x0, rd_fkeyvalid = false, rd_partkeycxt = 0x0, rd_partkey = 0x0, rd_pdcxt = 0x0,
rd_partdesc = 0x0, rd_partcheck = 0x0, rd_indexlist = 0x7f2af94c2818, rd_oidindex = 0, rd_pkindex = 26737, rd_replidindex = 26737, rd_statlist = 0x0, rd_indexattr = 0x0, rd_projindexattr = 0x0,
rd_keyattr = 0x0, rd_pkattr = 0x0, rd_idattr = 0x0, rd_projidx = 0x0, rd_pubactions = 0x0, rd_options = 0x0, rd_index = 0x0, rd_indextuple = 0x0, rd_amhandler = 0, rd_indexcxt = 0x0,
rd_amroutine = 0x0, rd_opfamily = 0x0, rd_opcintype = 0x0, rd_support = 0x0, rd_supportinfo = 0x0, rd_indoption = 0x0, rd_indexprs = 0x0, rd_indpred = 0x0, rd_exclops = 0x0, rd_exclprocs = 0x0,
rd_exclstrats = 0x0, rd_amcache = 0x0, rd_indcollation = 0x0, rd_fdwroutine = 0x0, rd_toastoid = 0, pgstat_info = 0x12d5850}
#以上,获取了Relation相关的信息
#没有触发器,无需执行触发器相关逻辑
#进入正常数据表的处理逻辑 line 373行
(gdb) next
315 if (resultRelInfo->ri_TrigDesc &&
(gdb) next
328 if (resultRelInfo->ri_TrigDesc &&
(gdb)
341 else if (resultRelInfo->ri_FdwRoutine)
(gdb)
373 tuple->t_tableOid = RelationGetRelid(resultRelationDesc);
(gdb) next
384 wco_kind = (mtstate->operation == CMD_UPDATE) ?
(gdb) next
391 if (resultRelInfo->ri_WithCheckOptions != NIL)
(gdb) p tuple->t_tableOid
$31 = 26731
(gdb) p wco_kind
$32 = WCO_RLS_INSERT_CHECK
#检查约束
(gdb) next
397 if (resultRelationDesc->rd_att->constr)
(gdb)
398 ExecConstraints(resultRelInfo, slot, estate);
(gdb)
#非分区表,无需检查
#进入正常数据插入逻辑
411 if (onconflict != ONCONFLICT_NONE && resultRelInfo->ri_NumIndices > 0)
(gdb)
529 newId = heap_insert(resultRelationDesc, tuple,
(gdb) p resultRelInfo->ri_NumIndices
$33 = 1
(gdb) p onconflict
$34 = ONCONFLICT_NONE
(gdb)
(gdb) next
534 if (resultRelInfo->ri_NumIndices > 0)
(gdb) p newId
$35 = 0
(gdb) next
535 recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
(gdb)
541 if (canSetTag)
(gdb)
543 (estate->es_processed)++;
(gdb)
544 estate->es_lastoid = newId;
(gdb)
545 setLastTid(&(tuple->t_self));
(gdb)
554 ar_insert_trig_tcs = mtstate->mt_transition_capture;
(gdb)
555 if (mtstate->operation == CMD_UPDATE && mtstate->mt_transition_capture
(gdb)
572 ExecARInsertTriggers(estate, resultRelInfo, tuple, recheckIndexes,
(gdb)
575 list_free(recheckIndexes);
(gdb)
589 if (resultRelInfo->ri_WithCheckOptions != NIL)
(gdb)
593 if (resultRelInfo->ri_projectReturning)
(gdb)
596 return result;
(gdb)
597 }
#DONE!
到此,关于“PostgreSQL中ExecInsert函数的实现逻辑是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!
--结束END--
本文标题: PostgreSQL中ExecInsert函数的实现逻辑是什么
本文链接: https://lsjlt.com/news/65082.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-10-23
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0