iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >PostgreSQL中ExecInsert函数的实现逻辑是什么
  • 271
分享到

PostgreSQL中ExecInsert函数的实现逻辑是什么

2024-04-02 19:04:59 271人浏览 独家记忆
摘要

这篇文章主要介绍“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://www.lsjlt.com/news/65082.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作