PostgreSQL中获取Tuple的分区键值函数是什么
发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,这篇文章主要介绍"PostgreSQL中获取Tuple的分区键值函数是什么",在日常操作中,相信很多人在PostgreSQL中获取Tuple的分区键值函数是什么问题上存在疑惑,小编查阅了各式资料,整理
千家信息网最后更新 2025年01月19日PostgreSQL中获取Tuple的分区键值函数是什么
这篇文章主要介绍"PostgreSQL中获取Tuple的分区键值函数是什么",在日常操作中,相信很多人在PostgreSQL中获取Tuple的分区键值函数是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"PostgreSQL中获取Tuple的分区键值函数是什么"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
一、数据结构
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 voidFormPartitionKeyDatum(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 Datumslot_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 voidslot_getsomeattrs(TupleTableSlot *slot, int attnum){ if (slot->tts_nvalid < attnum) slot_getsomeattrs_int(slot, attnum);}/* * slot_getsomeattrs_int - workhorse for slot_getsomeattrs() * slot_getsomeattrs_int - slot_getsomeattrs()函数的实际实现 */voidslot_getsomeattrs_int(TupleTableSlot *slot, int attnum){ /* Check for caller errors */ //检查调用者输入参数是否有误 Assert(slot->tts_nvalid < attnum); /* slot_getsomeattr checked */ Assert(attnum > 0); //attnum参数判断 if (unlikely(attnum > slot->tts_tupleDescriptor->natts)) elog(ERROR, "invalid attribute number %d", attnum); /* Fetch as many attributes as possible from the underlying tuple. */ //从元组中获取尽可能多的属性。 slot->tts_ops->getsomeattrs(slot, attnum); /* * If the underlying tuple doesn't have enough attributes, tuple descriptor * must have the missing attributes. * 如果底层元组没有足够的属性,那么元组描述符必须具有缺少的属性。 */ if (unlikely(slot->tts_nvalid < attnum)) { slot_getmissingattrs(slot, slot->tts_nvalid, attnum); slot->tts_nvalid = attnum; }}
三、跟踪分析
测试脚本如下
-- Hash Partitiondrop table if exists t_hash_partition;create table t_hash_partition (c1 int not null,c2 varchar(40),c3 varchar(40)) partition by hash(c1);create table t_hash_partition_1 partition of t_hash_partition for values with (modulus 6,remainder 0);create table t_hash_partition_2 partition of t_hash_partition for values with (modulus 6,remainder 1);create table t_hash_partition_3 partition of t_hash_partition for values with (modulus 6,remainder 2);create table t_hash_partition_4 partition of t_hash_partition for values with (modulus 6,remainder 3);create table t_hash_partition_5 partition of t_hash_partition for values with (modulus 6,remainder 4);create table t_hash_partition_6 partition of t_hash_partition for values with (modulus 6,remainder 5);insert into t_hash_partition(c1,c2,c3) VALUES(20,'HASH0','HAHS0');
启动gdb,设置断点
(gdb) b FormPartitionKeyDatumBreakpoint 5 at 0x6e30d2: file execPartition.c, line 1087.(gdb) b slot_getattrBreakpoint 6 at 0x489d9b: file heaptuple.c, line 1510.(gdb) cContinuing.Breakpoint 5, FormPartitionKeyDatum (pd=0x2e1bfa0, slot=0x2e1b8a0, estate=0x2e1aeb8, values=0x7fff4e2407a0, isnull=0x7fff4e240780) at execPartition.c:10871087 if (pd->key->partexprs != NIL && pd->keystate == NIL)
循环,根据分区键获取相应的键值
1087 if (pd->key->partexprs != NIL && pd->keystate == NIL)(gdb) n1097 partexpr_item = list_head(pd->keystate);(gdb) 1098 for (i = 0; i < pd->key->partnatts; i++)(gdb) 1100 AttrNumber keycol = pd->key->partattrs[i];(gdb) 1104 if (keycol != 0)(gdb) 1107 datum = slot_getattr(slot, keycol, &isNull);
进入函数slot_getattr
(gdb) stepBreakpoint 6, slot_getattr (slot=0x2e1b8a0, attnum=1, isnull=0x7fff4e240735) at heaptuple.c:15101510 HeapTuple tuple = slot->tts_tuple;
获取结果,分区键值为20
...(gdb) p *isnull$31 = false(gdb) p slot->tts_values[attnum - 1]$32 = 20
返回到FormPartitionKeyDatum函数中
(gdb) n1593 }(gdb) FormPartitionKeyDatum (pd=0x2e1bfa0, slot=0x2e1b8a0, estate=0x2e1aeb8, values=0x7fff4e2407a0, isnull=0x7fff4e240780) at execPartition.c:11191119 values[i] = datum;
完成调用
1119 values[i] = datum;(gdb) n1120 isnull[i] = isNull;(gdb) 1098 for (i = 0; i < pd->key->partnatts; i++)(gdb) 1123 if (partexpr_item != NULL)(gdb) 1125 }(gdb) ExecFindPartition (resultRelInfo=0x2e1b108, pd=0x2e1c5b8, slot=0x2e1b8a0, estate=0x2e1aeb8) at execPartition.c:282282 if (partdesc->nparts == 0)
到此,关于"PostgreSQL中获取Tuple的分区键值函数是什么"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!
索引
数组
表达式
函数
信息
状态
结果
目标
更新
属性
结构
触发器
分区表
参数
格式
路由
检查
数据
标记
学习
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
什么是时空数据库
服务器备案认证步骤
软件设计师网络安全协议
华硕服务器主板卡b2后重启
浙大网络安全冠军
新倩女幽魂装备强化数据库
数字资源数据库有什么
苏州网站建设软件开发
指纹仪怎么接数据库
网络安全是一种精神
无法打开网页因为服务器停止运行
河南搜客网络技术有限公司
南京客莱美网络技术
万里开源数据库华为
软件开发学习什么好呢
网络安全关系你我他手抄报
地平线5未找到服务器
杭州升珀网络技术学院有限公司
软件开发系统合同范本
软件开发行业财务处罚
软件开发岗薪资待遇
魔域怎么用数据库注册账号
网络安全隐私原因
蓝创科技互联网
服务器变软路由
网络安全宣传用品
快橙如何登陆服务器
数据库增删改语句
潮流网络技术有限公司面试
浪潮服务器光盘启动