本节介绍table_tuple_insert和ExecInsert函数。
//src/include/utils/rel.h
typedef struct RelationData
{
TupleDesc rd_att;
const struct TableAmRoutine *rd_tableam;
} RelationData;
//src/include/access/tupdesc.h
typedef struct TupleDescData
{
int natts;
Oid tdtypeid;
int32 tdtypmod;
int tdrefcount;
TupleConstr *constr;
FormData_pg_attribute attrs[FLEXIBLE_ARRAY_MEMBER];
} TupleDescData;
typedef struct TupleDescData *TupleDesc;
//src/include/nodes/parsenodes.h
typedef enum WCOKind
{
WCO_VIEW_CHECK,
WCO_RLS_INSERT_CHECK,
WCO_RLS_UPDATE_CHECK,
WCO_RLS_CONFLICT_CHECK
} WCOKind;
//src/include/nodes/nodes.h
typedef enum OnConflictAction
{
ONCONFLICT_NONE,
ONCONFLICT_NOTHING,
ONCONFLICT_UPDATE
} OnConflictAction;
//src/include/access/tableam.h
static inline void
table_tuple_insert(Relation rel, TupleTableSlot *slot, CommandId cid,
int options, struct BulkInsertStateData *bistate)
{
rel->rd_tableam->tuple_insert(rel, slot, cid, options,
bistate);
}
//src/backend/executor/nodeModifyTable.c
ExecMaterializeSlot(slot);
resultRelInfo = estate->es_result_relation_info;
resultRelationDesc = resultRelInfo->ri_RelationDesc;
if (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_insert_before_row)
{
if (!ExecBRInsertTriggers(estate, resultRelInfo, slot))
return NULL;
}
if (resultRelInfo->ri_TrigDesc &&
resultRelInfo->ri_TrigDesc->trig_insert_instead_row)
{
if (!ExecIRInsertTriggers(estate, resultRelInfo, slot))
return NULL;
}
else if (resultRelInfo->ri_FdwRoutine)
{
if (resultRelationDesc->rd_att->constr &&
resultRelationDesc->rd_att->constr->has_generated_stored)
ExecComputeStoredGenerated(estate, slot);
slot = resultRelInfo->ri_FdwRoutine->ExecForeignInsert(estate,
resultRelInfo,
slot,
planSlot);
if (slot == NULL)
return NULL;
slot->tts_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
}
else
{
slot->tts_tableOid = RelationGetRelid(resultRelationDesc);
if (resultRelationDesc->rd_att->constr &&
resultRelationDesc->rd_att->constr->has_generated_stored)
ExecComputeStoredGenerated(estate, slot);、
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)
{
arbiterIndexes = resultRelInfo->ri_onConflictArbiterIndexes;
vlock:
specConflict = false;
if (!ExecCheckIndexConstraints(slot, estate, &conflictTid,
arbiterIndexes))
{
if (onconflict == ONCONFLICT_UPDATE)
{
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,
ExecGetReturningSlot(estate, resultRelInfo));
InstrCountTuples2(&mtstate->ps, 1);
return NULL;
}
}
specToken = SpeculativeInsertionLockAcquire(GetCurrentTransactionId());
table_tuple_insert_speculative(resultRelationDesc, slot,
estate->es_output_cid,
0,
NULL,
specToken);
recheckIndexes = ExecInsertIndexTuples(slot, estate, true,
&specConflict,
arbiterIndexes);
table_tuple_complete_speculative(resultRelationDesc, slot,
specToken, !specConflict);
SpeculativeInsertionLockRelease(GetCurrentTransactionId());
if (specConflict)
{
list_free(recheckIndexes);
goto vlock;
}
}
else
{
table_tuple_insert(resultRelationDesc, slot,
estate->es_output_cid,
0, NULL);
if (resultRelInfo->ri_NumIndices > 0)
recheckIndexes = ExecInsertIndexTuples(slot, estate, false, NULL,
NIL);
}
}
if (canSetTag)
{
(estate->es_processed)++;
setLastTid(&slot->tts_tid);
}
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,
slot,
NULL,
mtstate->mt_transition_capture);
ar_insert_trig_tcs = NULL;
}
ExecARInsertTriggers(estate, resultRelInfo, slot, 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;