共计 10312 个字符,预计需要花费 26 分钟才能阅读完成。
这篇文章主要介绍“PostgreSQL 中获取 Tuple 的分区键值函数是什么”,在日常操作中,相信很多人在 PostgreSQL 中获取 Tuple 的分区键值函数是什么问题上存在疑惑,丸趣 TV 小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PostgreSQL 中获取 Tuple 的分区键值函数是什么”的疑惑有所帮助!接下来,请跟着丸趣 TV 小编一起来学习吧!
一、数据结构
ModifyTable
通过插入、更新或删除,将子计划生成的行应用到结果表。
/* ----------------
* ModifyTable node -
* Apply rows produced by subplan(s) to result table(s),
* by inserting, updating, or deleting.
* 通过插入、更新或删除,将子计划生成的行应用到结果表。 *
* If the originally named target table is a partitioned table, both
* nominalRelation and rootRelation contain the RT index of the partition
* root, which is not otherwise mentioned in the plan. Otherwise rootRelation
* is zero. However, nominalRelation will always be set, as it s the rel that
* EXPLAIN should claim is the INSERT/UPDATE/DELETE target.
* 如果最初命名的目标表是分区表,则 nominalRelation 和 rootRelation 都包含分区根的 RT 索引,计划中没有另外提到这个索引。 * 否则,根关系为零。但是,总是会设置名义关系,nominalRelation 因为 EXPLAIN 应该声明的 rel 是 INSERT/UPDATE/DELETE 目标关系。 *
* Note that rowMarks and epqParam are presumed to be valid for all the
* subplan(s); they can t contain any info that varies across subplans.
* 注意,rowMarks 和 epqParam 被假定对所有子计划有效;
* 它们不能包含任何在子计划中变化的信息。 * ----------------
*/
typedef struct ModifyTable
Plan plan;
CmdType operation; /* 操作类型;INSERT, UPDATE, or DELETE */
bool canSetTag; /* 是否需要设置 tag?do we set the command tag/es_processed? */
Index nominalRelation; /* 用于 EXPLAIN 的父 RT 索引;Parent RT index for use of EXPLAIN */
Index rootRelation; /* 根 Root RT 索引(如目标为分区表);Root RT index, if target is partitioned */
bool partColsUpdated; /* 更新了层次结构中的分区关键字;some part key in hierarchy updated */
List *resultRelations; /* RT 索引的整型链表;integer list of RT indexes */
int resultRelIndex; /* 计划链表中第一个 resultRel 的索引;index of first resultRel in plan s list */
int rootResultRelIndex; /* 分区表根索引;index of the partitioned table root */
List *plans; /* 生成源数据的计划链表;plan(s) producing source data */
List *withCheckOptionLists; /* 每一个目标表均具备的 WCO 链表;per-target-table WCO lists */
List *returningLists; /* 每一个目标表均具备的 RETURNING 链表;per-target-table RETURNING tlists */
List *fdwPrivLists; /* 每一个目标表的 FDW 私有数据链表;per-target-table FDW private data lists */
Bitmapset *fdwDirectModifyPlans; /* FDW DM 计划索引位图;indices of FDW DM plans */
List *rowMarks; /* rowMarks 链表;PlanRowMarks (non-locking only) */
int epqParam; /* EvalPlanQual 再解析使用的参数 ID;ID of Param for EvalPlanQual re-eval */
OnConflictAction onConflictAction; /* ON CONFLICT action */
List *arbiterIndexes; /* 冲突仲裁器索引表;List of ON CONFLICT arbiter index OIDs */
List *onConflictSet; /* SET for INSERT ON CONFLICT DO UPDATE */
Node *onConflictWhere; /* WHERE for ON CONFLICT UPDATE */
Index exclRelRTI; /* RTI of the EXCLUDED pseudo relation */
List *exclRelTlist; /* 已排除伪关系的投影列链表;tlist of the EXCLUDED pseudo relation */
} ModifyTable;
ResultRelInfo
ResultRelInfo 结构体
每当更新一个现有的关系时,我们必须更新关系上的索引,也许还需要触发触发器。ResultRelInfo 保存关于结果关系所需的所有信息,包括索引。
/*
* ResultRelInfo
* ResultRelInfo 结构体
*
* Whenever we update an existing relation, we have to update indexes on the
* relation, and perhaps also fire triggers. ResultRelInfo holds all the
* information needed about a result relation, including indexes.
* 每当更新一个现有的关系时,我们必须更新关系上的索引,也许还需要触发触发器。 * ResultRelInfo 保存关于结果关系所需的所有信息,包括索引。 *
* Normally, a ResultRelInfo refers to a table that is in the query s
* range table; then ri_RangeTableIndex is the RT index and ri_RelationDesc
* is just a copy of the relevant es_relations[] entry. But sometimes,
* in ResultRelInfos used only for triggers, ri_RangeTableIndex is zero
* and ri_RelationDesc is a separately-opened relcache pointer that needs
* to be separately closed. See ExecGetTriggerResultRel.
* 通常,ResultRelInfo 是指查询范围表中的表;
* ri_RangeTableIndex 是 RT 索引,而 ri_RelationDesc 只是相关 es_relations[]条目的副本。 * 但有时,在只用于触发器的 ResultRelInfos 中,ri_RangeTableIndex 为零(NULL), * 而 ri_RelationDesc 是一个需要单独关闭单独打开的 relcache 指针。 * 具体可参考 ExecGetTriggerResultRel 结构体。 */
typedef struct ResultRelInfo
NodeTag type;
/* result relation s range table index, or 0 if not in range table */
//RTE 索引
Index ri_RangeTableIndex;
/* relation descriptor for result relation */
// 结果 / 目标 relation 的描述符
Relation ri_RelationDesc;
/* # of indices existing on result relation */
// 目标关系中索引数目
int ri_NumIndices;
/* array of relation descriptors for indices */
// 索引的关系描述符数组(索引视为一个 relation)
RelationPtr ri_IndexRelationDescs;
/* array of key/attr info for indices */
// 索引的键 / 属性数组
IndexInfo **ri_IndexRelationInfo;
/* triggers to be fired, if any */
// 触发的索引
TriggerDesc *ri_TrigDesc;
/* cached lookup info for trigger functions */
// 触发器函数(缓存)
FmgrInfo *ri_TrigFunctions;
/* array of trigger WHEN expr states */
//WHEN 表达式状态的触发器数组
ExprState **ri_TrigWhenExprs;
/* optional runtime measurements for triggers */
// 可选的触发器运行期度量器
Instrumentation *ri_TrigInstrument;
/* FDW callback functions, if foreign table */
//FDW 回调函数
struct FdwRoutine *ri_FdwRoutine;
/* available to save private state of FDW */
// 可用于存储 FDW 的私有状态
void *ri_FdwState;
/* true when modifying foreign table directly */
// 直接更新 FDW 时为 T
bool ri_usesFdwDirectModify;
/* list of WithCheckOption s to be checked */
//WithCheckOption 链表
List *ri_WithCheckOptions;
/* list of WithCheckOption expr states */
//WithCheckOption 表达式链表
List *ri_WithCheckOptionExprs;
/* array of constraint-checking expr states */
// 约束检查表达式状态数组
ExprState **ri_ConstraintExprs;
/* for removing junk attributes from tuples */
// 用于从元组中删除 junk 属性
JunkFilter *ri_junkFilter;
/* list of RETURNING expressions */
//RETURNING 表达式链表
List *ri_returningList;
/* for computing a RETURNING list */
// 用于计算 RETURNING 链表
ProjectionInfo *ri_projectReturning;
/* list of arbiter indexes to use to check conflicts */
// 用于检查冲突的仲裁器索引的列表
List *ri_onConflictArbiterIndexes;
/* ON CONFLICT evaluation state */
//ON CONFLICT 解析状态
OnConflictSetState *ri_onConflict;
/* partition check expression */
// 分区检查表达式链表
List *ri_PartitionCheck;
/* partition check expression state */
// 分区检查表达式状态
ExprState *ri_PartitionCheckExpr;
/* relation descriptor for root partitioned table */
// 分区 root 根表描述符
Relation ri_PartitionRoot;
/* Additional information specific to partition tuple routing */
// 额外的分区元组路由信息
struct PartitionRoutingInfo *ri_PartitionInfo;
} ResultRelInfo;
PartitionRoutingInfo
PartitionRoutingInfo 结构体
分区路由信息, 用于将元组路由到表分区的结果关系信息。
/*
* PartitionRoutingInfo
* PartitionRoutingInfo - 分区路由信息
*
* Additional result relation information specific to routing tuples to a
* table partition.
* 用于将元组路由到表分区的结果关系信息。 */
typedef struct PartitionRoutingInfo
/*
* Map for converting tuples in root partitioned table format into
* partition format, or NULL if no conversion is required.
* 映射,用于将根分区表格式的元组转换为分区格式,如果不需要转换,则转换为 NULL。 */
TupleConversionMap *pi_RootToPartitionMap;
/*
* Map for converting tuples in partition format into the root partitioned
* table format, or NULL if no conversion is required.
* 映射,用于将分区格式的元组转换为根分区表格式,如果不需要转换,则转换为 NULL。 */
TupleConversionMap *pi_PartitionToRootMap;
/*
* Slot to store tuples in partition format, or NULL when no translation
* is required between root and partition.
* 以分区格式存储元组的 slot. 在根分区和分区之间不需要转换时为 NULL。 */
TupleTableSlot *pi_PartitionTupleSlot;
} PartitionRoutingInfo;
TupleConversionMap
TupleConversionMap 结构体, 用于存储元组转换映射信息.
typedef struct TupleConversionMap
TupleDesc indesc; /* 源行类型的描述符;tupdesc for source rowtype */
TupleDesc outdesc; /* 结果行类型的描述符;tupdesc for result rowtype */
AttrNumber *attrMap; /* 输入字段的索引信息,0 表示 NULL;indexes of input fields, or 0 for null */
Datum *invalues; /* 析构源数据的工作空间;workspace for deconstructing source */
bool *inisnull; // 是否为 NULL 标记数组
Datum *outvalues; /* 构造结果的工作空间;workspace for constructing result */
bool *outisnull; //null 标记
} TupleConversionMap;
二、源码解读
FormPartitionKeyDatum 函数获取 Tuple 的分区键值, 返回键值 values[]数组和是否为 null 标记 isnull[]数组.
/* ----------------
* FormPartitionKeyDatum
* Construct values[] and isnull[] arrays for the partition key
* of a tuple.
* 构造 values[]数组和 isnull[]数组
*
* pd Partition dispatch object of the partitioned table
* pd 分区表的分区分发器 (dispatch) 对象
*
* slot Heap tuple from which to extract partition key
* slot 从其中提前分区键的 heap tuple
*
* estate executor state for evaluating any partition key
* expressions (must be non-NULL)
* estate 解析分区键表达式 (必须非 NULL) 的执行器状态
*
* values Array of partition key Datums (output area)
* 分区键 Datums 数组(输出参数)
* isnull Array of is-null indicators (output area)
* is-null 标记数组(输出参数)
*
* the ecxt_scantuple slot of estate s per-tuple expr context must point to
* the heap tuple passed in.
* estate 的 per-tuple 上下文的 ecxt_scantuple 必须指向传入的 heap tuple
* ----------------
*/
static void
FormPartitionKeyDatum(PartitionDispatch pd,
TupleTableSlot *slot,
EState *estate,
Datum *values,
bool *isnull)
ListCell *partexpr_item;
int i;
if (pd- key- partexprs != NIL pd- keystate == NIL)
{
/* Check caller has set up context correctly */
// 检查调用者是否已正确配置内存上下文
Assert(estate != NULL
GetPerTupleExprContext(estate)- ecxt_scantuple == slot);
/* First time through, set up expression evaluation state */
// 第一次进入, 配置表达式解析器状态
pd- keystate = ExecPrepareExprList(pd- key- partexprs, estate);
}
partexpr_item = list_head(pd- keystate);// 获取分区键表达式状态
for (i = 0; i pd- key- partnatts; i++)// 循环遍历分区键
{
AttrNumber keycol = pd- key- partattrs[i];// 分区键属性编号
Datum datum;// typedef uintptr_t Datum;sizeof(Datum) == sizeof(void *) == 4 or 8
bool isNull;// 是否 null
if (keycol != 0)// 编号不为 0
{
/* Plain column; get the value directly from the heap tuple */
// 扁平列, 直接从堆元组中提取值
datum = slot_getattr(slot, keycol, isNull);
}
else
{
/* Expression; need to evaluate it */
// 表达式, 需要解析
if (partexpr_item == NULL)// 分区键表达式状态为 NULL, 报错
elog(ERROR, wrong number of partition key expressions
// 获取表达式值
datum = ExecEvalExprSwitchContext((ExprState *) lfirst(partexpr_item),
GetPerTupleExprContext(estate),
isNull);
// 切换至下一个
partexpr_item = lnext(partexpr_item);
}
values[i] = datum;// 赋值
isnull[i] = isNull;
}
if (partexpr_item != NULL)// 参数设置有误? 报错
elog(ERROR, wrong number of partition key expressions
* slot_getattr - fetch one attribute of the slot s contents.
* slot_getattr - 提取 slot 中的某个属性值
*/
static inline Datum
slot_getattr(TupleTableSlot *slot, int attnum,
bool *isnull)
AssertArg(attnum 0);
if (attnum slot- tts_nvalid)
slot_getsomeattrs(slot, attnum);
*isnull = slot- tts_isnull[attnum - 1];
return slot- tts_values[attnum - 1];
* This function forces the entries of the slot s Datum/isnull arrays to be
* valid at least up through the attnum th entry.
* 这个函数强制 slot 的 Datum/isnull 数组的条目至少在 attnum 的第一个条目上是有效的。
*/
static inline void
slot_getsomeattrs(TupleTableSlot *slot, int attnum)
if (slot- tts_nvalid attnum)
slot_getsomeattrs_int(slot, attnum);
正文完