Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Which function in PostgreSQL finds the appropriate partition for heap tuple

2025-04-13 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)05/31 Report--

This article introduces the knowledge of "which function in PostgreSQL finds the right partition for heap tuple". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

I. data structure

ModifyTable

ModifyTable Node

Apply the rows generated by the subplan to the result table by inserting, updating, or deleting.

/ *-* ModifyTable node-* Apply rows produced by subplan (s) to result table (s), * by inserting, updating, or deleting. * apply the rows generated by the subplan to the result table 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. * if the originally named target table is a partitioned table, both nominalRelation and rootRelation contain the RT index of the partitioned root, which is not mentioned separately in the plan. * otherwise, the root relationship is zero. However, a nominal relationship is always set, nominalRelation because the rel that EXPLAIN should declare is an INSERT/UPDATE/DELETE target relationship. * * 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. * Note that rowMarks and epqParam are assumed to be valid for all subplans; * they cannot contain any information that changes in the subplan. *-* / typedef struct ModifyTable {Plan plan; CmdType operation; / * operation type; do you need to set tag?do we set the command tag/es_processed for INSERT, UPDATE, or DELETE * / bool canSetTag; / *? * / Index nominalRelation; / * for the parent RT index of EXPLAIN Parent RT index for use of EXPLAIN * / Index rootRelation; / * Root Root RT index (if the target is a partitioned table); Root RT index, if target is partitioned * / bool partColsUpdated; / * updated the partitioning keyword in the hierarchy; some part key in hierarchy updated * / List * resultRelations; / * RT index integer linked list; integer list of RT indexes * / int resultRelIndex / * Index of the first resultRel in the planned linked list; index of first resultRel in plan's list * / int rootResultRelIndex; / * partitioned table root index; index of the partitioned table root * / List * plans; / * generate the planned linked list of the source data; plan (s) producing source data * / List * withCheckOptionLists; / * the WCO linked list that each target table has Per-target-table WCO lists * / List * returningLists; / * RETURNING linked list for each target table; per-target-table RETURNING tlists * / List * fdwPrivLists; / * FDW private data linked list for each target table; per-target-table FDW private data lists * / Bitmapset * fdwDirectModifyPlans; / * FDW DM plan index bitmap; indices of FDW DM plans * / List * rowMarks; / * rowMarks linked list PlanRowMarks (non-locking only) * / int epqParam; / * EvalPlanQual parses the parameter ID;ID of Param for EvalPlanQual re-eval * / OnConflictAction onConflictAction; / * ON CONFLICT action * / List * arbiterIndexes; / * conflict arbiter index table; 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; / * projection list with pseudo relations excluded; tlist of the EXCLUDED pseudo relation * /} ModifyTable

ResultRelInfo

ResultRelInfo structure

Whenever we update an existing relationship, we must update the index on the relationship and perhaps trigger the trigger. ResultRelInfo holds all the information needed about the result relationship, including the index.

/ * * ResultRelInfo * ResultRelInfo structure * * 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. * whenever we update an existing relationship, we must update the index on the relationship and perhaps trigger the trigger. * ResultRelInfo keeps all the information needed about the result relationship, including the index. * * 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. * generally, ResultRelInfo refers to the table in the query scope table; * ri_RangeTableIndex is the RT index, and ri_RelationDesc is just a copy of the related es_relations [] entries. * but sometimes, in ResultRelInfos used only for triggers, ri_RangeTableIndex is zero (NULL), and ri_RelationDesc is a relcache pointer that needs to be closed and opened separately. * for more information, please see ExecGetTriggerResultRel structure. * / typedef struct ResultRelInfo {NodeTag type; / * result relation's range table index, or 0 if not in range table * / / RTE index Index ri_RangeTableIndex; / * relation descriptor for result relation * / / result / descriptor of the target relation Relation ri_RelationDesc; / * # of indices existing on result relation * / / number of indexes in the target relationship int ri_NumIndices / * array of relation descriptors for indices * / / the relational descriptor array of the index (the index is regarded as a relation) RelationPtr ri_IndexRelationDescs; / * array of key/attr info for indices * / / the key / attribute array of the index IndexInfo * * ri_IndexRelationInfo; / * triggers to be fired, if any * / / triggered index TriggerDesc * ri_TrigDesc / * cached lookup info for trigger functions * / / trigger function (cache) FmgrInfo * ri_TrigFunctions; / * array of trigger WHEN expr states * / / trigger array of WHEN expression status ExprState * * ri_TrigWhenExprs; / * optional runtime measurements for triggers * / / optional trigger runtime metric Instrumentation * ri_TrigInstrument / * FDW callback functions, if foreign table * / / FDW callback function struct FdwRoutine * ri_FdwRoutine; / * available to save private state of FDW * / / can be used to store the private status of FDW void * ri_FdwState; / * true when modifying foreign table directly * / T bool ri_usesFdwDirectModify when updating FDW directly / * list of WithCheckOption's to be checked * / / WithCheckOption linked list List * ri_WithCheckOptions; / * list of WithCheckOption expr states * / / WithCheckOption expression linked list List * ri_WithCheckOptionExprs; / * array of constraint-checking expr states * / / constraint check expression status array ExprState * * ri_ConstraintExprs / * for removing junk attributes from tuples * / / used to remove junk attributes from the tuple JunkFilter * ri_junkFilter; / * list of RETURNING expressions * / / RETURNING expression linked list List * ri_returningList; / * for computing a RETURNING list * / / used to calculate RETURNING linked list ProjectionInfo * ri_projectReturning / * list of arbiter indexes to use to check conflicts * / / list used to check conflicting arbitrator indexes List * ri_onConflictArbiterIndexes; / * ON CONFLICT evaluation state * / / ON CONFLICT parsing status OnConflictSetState * ri_onConflict; / * partition check expression * / / Partition check expression linked list List * ri_PartitionCheck / * partition check expression state * / / Partition check expression status ExprState * ri_PartitionCheckExpr; / * relation descriptor for root partitioned table * / / Partition root root table descriptor Relation ri_PartitionRoot; / * Additional information specific to partition tuple routing * / additional partition tuple routing information struct PartitionRoutingInfo * ri_PartitionInfo;} ResultRelInfo

PartitionRoutingInfo

PartitionRoutingInfo structure

Partition routing information, which is used to route tuples to the result relationship information of the table partition.

/ * * PartitionRoutingInfo * PartitionRoutingInfo-Partition routing information * * Additional result relation information specific to routing tuples to a * table partition. * result relationship information used to route tuples to table partitions. * / typedef struct PartitionRoutingInfo {/ * * Map for converting tuples in root partitioned table format into * partition format, or NULL if no conversion is required. * mapping, which is used to convert tuples in root partition table format to partition format, or to NULL if no conversion is required. * / TupleConversionMap * pi_RootToPartitionMap; / * * Map for converting tuples in partition format into the root partitioned * table format, or NULL if no conversion is required. * mapping, which is used to convert tuples in partition format to root partition table format, or to NULL if no conversion is required. * / TupleConversionMap * pi_PartitionToRootMap; / * * Slot to store tuples in partition format, or NULL when no translation * is required between root and partition. * store the slot of the tuple in partition format. NULL when no conversion is required between the root partition and the partition. * / TupleTableSlot * pi_PartitionTupleSlot;} PartitionRoutingInfo

TupleConversionMap

TupleConversionMap structure, which is used to store tuple transformation mapping information.

Typedef struct TupleConversionMap {TupleDesc indesc; / * descriptor of source line type; descriptor of tupdesc for source rowtype * / TupleDesc outdesc; / * result line type; index information of tupdesc for result rowtype * / AttrNumber * attrMap; / * input field. 0 represents NULL;indexes of input fields, or 0 for null * / Datum * invalues; / * destructs the workspace of source data Whether workspace for deconstructing source * / bool * inisnull; / / is the workspace of the construction result of NULL tag array Datum * outvalues; / *; workspace for constructing result * / bool * outisnull; / / null tag} TupleConversionMap; II. Source code interpretation

The ExecFindPartition function finds the target partition (leaf partition) for the tuple contained in * slot in the partition tree rooted at the parent node.

/ * * ExecFindPartition-- Find a leaf partition in the partition tree rooted * at parent, for the heap tuple contained in * slot * ExecFindPartition-- find the target partition (leaf partition) * * estate must be non-NULL; we'll need it to compute any expressions in the * partition key (s) * estate for the heap tuple contained in * slot in the partition tree rooted at the parent node. Estate cannot be NULL. You need to use it to evaluate the expressions * * If no leaf partition is found, this routine errors out with the appropriate * error message, else it returns the leaf partition sequence number * as an index into the array of (ResultRelInfos of) all leaf partitions in * the partition tree on the partition key. If the target partition is not found, this routine will output the appropriate error message, otherwise it will return the target partition sequence number of the array (ResultRelInfos) of all the leaf partitions in the partition tree as an index. * / intExecFindPartition (ResultRelInfo * resultRelInfo, PartitionDispatch * pd, TupleTableSlot * slot, EState * estate) {int result;// result index number Datum values [section _ MAX_KEYS]; / / value type Datum bool isnull [part _ MAX_KEYS]; / / null? Relation rel;// relation PartitionDispatch dispatch;// ExprContext * ecxt = GetPerTupleExprContext (estate); / / expression context TupleTableSlot * ecxt_scantuple_old = ecxt- > ecxt_scantuple;// original tuple slot TupleTableSlot * myslot = NULL;// temporary variable MemoryContext oldcxt;// original memory context HeapTuple tuple / / tuple / * use per-tuple context here to avoid leaking memory * / / use each tuple context to avoid memory leaks oldcxt = MemoryContextSwitchTo (GetPerTupleMemoryContext (estate)); / * First check the root table's partition constraint, if any. No point in * routing the tuple if it doesn't belong in the root table itself. * first check the partition constraints of the root table, if any. If the tuple does not belong to the root table itself, it is not necessary to route it. * / if (resultRelInfo- > ri_PartitionCheck) ExecPartitionCheck (resultRelInfo, slot, estate, true); / * start with the root partitioned table * / / start from the root partition table tuple = ExecFetchSlotTuple (slot); / / get tuple dispatch = pd [0]; / / root while (true) {PartitionDesc partdesc;// partition descriptor TupleConversionMap * map = dispatch- > tupmap;// transformation map int cur_index =-1 / / current index rel = dispatch- > reldesc;//relation partdesc = RelationGetPartitionDesc (rel); / / get the rel descriptor / * * Convert the tuple to this parent's layout, if different from the * current relation. * convert tuple to parent's layout if the tuple is different from the current relationship. * / myslot = dispatch- > tupslot; if (myslot! = NULL & & map! = NULL) {tuple = do_convert_tuple (tuple, map); ExecStoreTuple (tuple, myslot, InvalidBuffer, true); slot = myslot;} / * * Extract partition key from tuple. Expression evaluation machinery * that FormPartitionKeyDatum () invokes expects ecxt_scantuple to * point to the correct tuple slot. The slot might have changed from * what was used for the parent table if the table of the current * partitioning level has different tuple descriptor from the parent. * So update ecxt_scantuple accordingly. * extract the partition key from the tuple. The expression evaluation mechanism of the FormPartitionKeyDatum () call expects ecxt_scantuple to point to the correct tuple slot. * if the current partition-level table has different tuple descriptors from the parent table, slot may have changed the slot used by the parent table. * therefore update the ecxt_scantuple accordingly. * / ecxt- > ecxt_scantuple = slot; FormPartitionKeyDatum (dispatch, slot, estate, values, isnull); / * * Nothing for get_partition_for_tuple () to do if there are no * partitions to begin with. * if there is no partition, exit (no need to call get_partition_for_tuple) * / if (partdesc- > nparts = = 0) {result =-1; break;} / / call get_partition_for_tuple cur_index = get_partition_for_tuple (rel, values, isnull); / * cur_index

< 0 means we failed to find a partition of this parent. * cur_index >

= 0 means we either found the leaf partition, or the * next parent to find a partition of. * cur_index

< 0表示未能找到该父节点的分区。 * cur_index >

= 0 means either the leaf partition or the next parent partition is found. * / if (cur_index

< 0) { result = -1; break;//找不到,退出 } else if (dispatch->

Indexes [cur _ index] > = 0) {result = dispatch- > indexes [cur _ index]; / * success! * / break;// found it, exit the loop} else {/ * move down one level * / move to the next layer to find dispatch = pd [- dispatch- > indexes [cur _ index]] / * Release the dedicated slot, if it was used. Create a copy of * the tuple first, for the next iteration. * / if (slot = = myslot) {tuple = ExecCopySlotTuple (myslot); ExecClearTuple (myslot);} / * Release the tuple in the lowest parent's dedicated slot. * / / release the tuple corresponding to the dedicated slot at the lowest parent. If (slot = = myslot) ExecClearTuple (myslot) / * A partition was not found. * / / partition if not found (result

< 0) { char *val_desc; val_desc = ExecBuildSlotPartitionKeyDescription(rel, values, isnull, 64); Assert(OidIsValid(RelationGetRelid(rel))); ereport(ERROR, (errcode(ERRCODE_CHECK_VIOLATION), errmsg("no partition of relation \"%s\" found for row", RelationGetRelationName(rel)), val_desc ? errdetail("Partition key of the failing row contains %s.", val_desc) : 0)); } MemoryContextSwitchTo(oldcxt); ecxt->

Ecxt_scantuple = ecxt_scantuple_old; return result;} / * * get_partition_for_tuple * Finds partition of relation which accepts the partition key specified * in values and isnull * get_partition_for_tuple * find the relational partition with the specified partition key in values and isnull * * Return value is index of the partition (> = 0 and)

< partdesc->

Nparts) if one * found or-1 if none found. * the return value is the index of the partition (> = 0 and

< partdesc->

Nparts), * returns a value if a partition is found, or-1 if it is not found. * / static intget_partition_for_tuple (Relation relation, Datum * values, bool * isnull) {int bound_offset; int part_index =-1; PartitionKey key = RelationGetPartitionKey (relation); PartitionDesc partdesc = RelationGetPartitionDesc (relation); PartitionBoundInfo boundinfo = partdesc- > boundinfo; / * Route as appropriate based on partitioning strategy. * / / routing switch based on partition policy (key- > strategy) {case PARTITION_STRATEGY_HASH://HASH partition {int greatest_modulus; uint64 rowHash; greatest_modulus = get_hash_partition_greatest_modulus (boundinfo) RowHash = compute_partition_hash_value (key- > partnatts, key- > partsupfunc, values, isnull); part_index = boundinfo- > indexes [rowHash% greatest_modulus];} break Case PARTITION_STRATEGY_LIST:// list partition if (isnull [0]) {if (partition_bound_accepts_nulls (boundinfo)) part_index = boundinfo- > null_index;} else {bool equal = false Bound_offset = partition_list_bsearch (key- > partsupfunc, key- > partcollation, boundinfo, values [0], & equal) If (bound_offset > = 0 & & equal) part_index = boundinfo- > indexes [bound _ offset];} break; case PARTITION_STRATEGY_RANGE:// range partition {bool equal = false, range_partkey_has_null = false Int I; / * No range includes NULL, so this will be accepted by the * default partition if there is one, and otherwise rejected. * No range contains a null value, so the default partition will accept the value (if it exists), otherwise it will be rejected. * / for (I = 0; I

< key->

Partnatts; iTunes +) {if (isnull [I]) {range_partkey_has_null = true; break }} if (! range_partkey_has_null) {bound_offset = partition_range_datum_bsearch (key- > partsupfunc, key- > partcollation) Boundinfo, key- > partnatts, values & equal) / * * The bound at bound_offset is less than or equal to the * tuple value, so the bound at offset+1 is the upper * bound of the partition we're looking for, if there * actually exists one. * the boundary of bound_offset is less than or equal to the tuple value, so the boundary of offset+1 is the upper bound of the partition we are looking for, if any. * / part_index = boundinfo- > indexes [bound _ offset + 1];}} break; default: elog (ERROR, "unexpected partition strategy:% d", (int) key- > strategy); / / other partitions are not supported} / * * part_index

< 0 means we failed to find a partition of this parent. Use * the default partition, if there is one. * part_index < 0表示没有找到这个父节点的分区。如存在分区,则使用默认分区。 */ if (part_index < 0) part_index = boundinfo->

Default_index; return part_index;}

Dependent function

/ * get_hash_partition_greatest_modulus * * Returns the greatest modulus of the hash partition bound. The greatest * modulus will be at the end of the datums array because hash partitions are * arranged in the ascending order of their moduli and remainders. * returns the maximum modulus of the boundary of the hash partition. * the maximum modulus will be at the end of the datums array because the hash partitions are arranged in ascending order of their modules and remainder. * / intget_hash_partition_greatest_modulus (PartitionBoundInfo bound) {Assert (bound & & bound- > strategy = = PARTITION_STRATEGY_HASH); Assert (bound- > datums & & bound- > ndatums > 0); Assert (bound- > data [bound-> ndatums-1] [0]) > 0); return DatumGetInt32 (bound- > data [bound-> ndatums-1] [0]);} / * compute_partition_hash_value * * Compute the hash value for given partition key values. * given the partition key value, calculate the corresponding hash value * / uint64compute_partition_hash_value (int partnatts, FmgrInfo * partsupfunc, Datum * values, bool * isnull) {int I; uint64 rowHash = 0 uint64 rowHash / return result Datum seed = UInt64GetDatum (HASH_PARTITION_SEED); for (I = 0; I

< partnatts; i++) { /* Nulls are just ignored */ if (!isnull[i]) { //不为NULL Datum hash; Assert(OidIsValid(partsupfunc[i].fn_oid)); /* * Compute hash for each datum value by calling respective * datatype-specific hash functions of each partition key * attribute. * 通过调用每个分区键属性的特定于数据类型的哈希函数,计算每个数据值的哈希值。 */ hash = FunctionCall2(&partsupfunc[i], values[i], seed); /* Form a single 64-bit hash value */ //组合成一个单独的64bit哈希值 rowHash = hash_combine64(rowHash, DatumGetUInt64(hash)); } } return rowHash;}/* * Combine two 64-bit hash values, resulting in another hash value, using the * same kind of technique as hash_combine(). Testing shows that this also * produces good bit mixing. * 使用与hash_combine()相同的技术组合两个64位哈希值,生成另一个哈希值。 * 测试表明,该方法也能产生良好的混合效果。 */static inline uint64hash_combine64(uint64 a, uint64 b){ /* 0x49a0f4dd15e5a8e3 is 64bit random data */ a ^= b + UINT64CONST(0x49a0f4dd15e5a8e3) + (a >

7); return a;} / / function call macro definition with two parameters # define FunctionCall2 (flinfo, arg1, arg2)\ FunctionCall2Coll (flinfo, InvalidOid, arg1, arg2) 3. Tracking analysis

The test script is as follows

-- Hash Partitiondrop table if exists tincture hashworthy partitionalist 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); create table t_hash_partition_2 partition of t_hash_partition for values with (modulus 6); create table t_hash_partition_3 partition of t_hash_partition for values with (modulus 6) Create table t_hash_partition_4 partition of t_hash_partition for values with (modulus 6); create table t_hash_partition_5 partition of t_hash_partition for values with (modulus 6); create table t_hash_partition_6 partition of t_hash_partition for values with (modulus 6); insert into t_hash_partition (c1, c2, and c3); VALUES (0meme, HASH0, HASH0')

Start gdb, set breakpoints, and enter ExecFindPartition

(gdb) b ExecFindPartitionBreakpoint 1 at 0x6e19e7: file execPartition.c, line 227. (gdb) cContinuing.Breakpoint 1, ExecFindPartition (resultRelInfo=0x14299a8, pd=0x142ae58, slot=0x142a140, estate=0x1429758) at execPartition.c:227227 ExprContext * ecxt = GetPerTupleExprContext (estate)

Initialize variables, switch memory context

227 ExprContext * ecxt = GetPerTupleExprContext (estate); (gdb) n228 TupleTableSlot * ecxt_scantuple_old = ecxt- > ecxt_scantuple; (gdb) 229 TupleTableSlot * myslot = NULL; (gdb) 234 oldcxt = MemoryContextSwitchTo (GetPerTupleMemoryContext (estate)); (gdb) p ecxt_scantuple_old$1 = (TupleTableSlot *) 0x0

Extract tuple, get dispatch

(gdb) n244 tuple = ExecFetchSlotTuple (slot); (gdb) 245 dispatch = pd [0]; (gdb) n249 TupleConversionMap * map = dispatch- > tupmap; (gdb) p * tuple$2 = {t_len = 40, t_self = {ip_blkid = {bi_hi = 65535, bi_lo = 65535}, ip_posid = 0}, t_tableOid = 0, t_data = 0x142b158} (gdb)

View dispatcher dispatch information

(gdb) p * dispatch$3 = {reldesc = 0x7fbfa6900950, key = 0x1489860, keystate = 0x0, partdesc = 0x149b130, tupslot = 0x0, tupmap = 0x0, indexes = 0x142ade8} (gdb) p * dispatch- > reldesc$4 = {rd_node = {spcNode = 1663, dbNode = 16402, relNode = 16986}, rd_smgr = 0x0, rd_refcnt = 1, rd_backend =-1, rd_islocaltemp = false, rd_isnailed = false, rd_isvalid = true, rd_indexvalid = 0'\ 000, rd_statvalid = false, false = 0, rd_createSubid = 0 Rd_rel = 0x7fbfa6900b68, rd_att = 0x7fbfa6900c80, rd_id = 16986, rd_lockInfo = {lockRelId = {relId = 16986, dbId = 16402}}, rd_rules = 0x0, rd_rulescxt = 0x0, trigdesc = 0x0, rd_rsdesc = 0x0, rd_fkeylist = 0x0, rd_fkeyvalid = false, rd_partkeycxt = 0x1489710, rd_partkey = 0x1489860, rd_pdcxt = 0x149afe0, rd_partdesc = 0x149b130, rd_partcheck = 0x0, rd_indexlist = 0x0, rd_oidindex = 0, rd_pkindex = 0, rd_replidindex = 0 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 = rd_indoption, 0x0 = 0x0, 0x0 = rd_indexprs Rd_exclops = 0x0, rd_exclprocs = 0x0, rd_exclstrats = 0x0, rd_amcache = 0x0, rd_indcollation = 0x0, rd_fdwroutine = 0x0, rd_toastoid = 0 Pgstat_info = 0x0}-testdb=# select relname from pg_class where oid=16986 Relname-t_hash_partition-> hash partition table (1 row)-(gdb) p * dispatch- > key$5 = {strategy = 104h' Partnatts = 1, partattrs = 0x14898f8, partexprs = 0x0, partopfamily = 0x1489918, partopcintype = 0x1489938, partsupfunc = 0x1489958, partcollation = 0x14899b0, parttypid = 0x14899d0, parttypmod = 0x14899f0, parttyplen = 0x1489a10, parttypbyval = 0x1489a30, parttypalign = 0x1489a50 "i177\ 177\ 177\ 177\ 177\ 177\ b", parttypcoll = 0x1489a70} (gdb) p * dispatch- > partdesc$6 = {nparts = 6, oids = 0x149b168, boundinfo = 0x149b1a0} (gdb) p * dispatch- > partdesc- > partdesc- > partdesc- = {partdesc- = 104hitch, boundinfo$8 = 6, strategy = strategy, strategy =, strategy = Null_index =-1, default_index =-1} (gdb) p * dispatch- > partdesc- > boundinfo- > datums$9 = (Datum *) 0x149b2c0 (gdb) p * * dispatch- > partdesc- > boundinfo- > datums$10 = 6 (gdb) p * dispatch- > indexes$15 = 0

The oids in the partition descriptor (corresponding to tasking hashworthy partitionals 1-> 6, respectively)

(gdb) p dispatch- > partdesc- > oids [0] $11 = 16989 (gdb) p dispatch- > partdesc- > oids [1] $12 = 16992... (gdb) p dispatch- > partdesc- > oids [5] $13 = 17004

Index information

(gdb) p dispatch- > indexes [0] $16 = 0... (gdb) p dispatch- > indexes [5] $18 = 5

Set current index (- 1), get relation information, get partition descriptor

(gdb) n250 int cur_index =-1; (gdb) 252 rel = dispatch- > reldesc; (gdb) 253 partdesc = RelationGetPartitionDesc (rel); (gdb) 259 myslot = dispatch- > tupslot; (gdb) p * partdesc$19 = {nparts = 6, oids = 0x149b168, boundinfo = 0x149b1a0} (gdb)

Myslot is NULL

(gdb) n260 if (myslot! = NULL & & map! = NULL) (gdb) p myslot$20 = (TupleTableSlot *) 0x0

Extract the partition key from the tuple

(gdb) n275 ecxt- > ecxt_scantuple = slot; (gdb) 276 FormPartitionKeyDatum (dispatch, slot, estate, values, isnull) (gdb) 282 if (partdesc- > nparts = 0) (gdb) p * partdesc$21 = {nparts = 6, oids = 0x149b168, boundinfo = 0x149b1a0} (gdb) p * slot$22 = {type = T_TupleTableSlot, tts_isempty = false, tts_shouldFree = true, tts_shouldFreeMin = false, tts_slow = false, tts_tuple = 0x142b140, tts_tupleDescriptor = 0x1429f28, tts_mcxt = 0x1429640, tts_buffer = 0, tts_nvalid = 1, tts_values = 0x142a1a0, tts_isnull = 0x142a1b8, tts_mintuple = tts_mintuple 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 = 4, tts_fixedTupleDescriptor = true} (gdb) p values$23 = {0, 7152626, 21144656, 21144128, 7141053, 21143088, 21144128, 16372128, 140722434628688, 0,0,0,21143872, 1407224324324141056, 21144128,0,21143088, 21141056, 7152279, 0,7421941, 2114141056, 21143088,21143088,2161430776 140722434628800, 7422189, 21143872, 140722434628839, 21143088,21144128} (gdb) p isnull$24 = {false, 91,186,126,252,127, false, false, 208,166,71, false, 2, false} (gdb) p * estate$25 = {type = T_EState, es_direction = ForwardScanDirection, es_snapshot = 0x1451ee0, es_crosscheck_snapshot = 0x0, es_range_table = 0x14a71c0, es_plannedstmt = 0x14a72b8, es_sourceText = 0x13acec8 "insert into t_hash_partition (c1Je c2JC 3) VALUES (0) 'HASH0','HAHS0') ", es_junkFilter = 0x0, es_output_cid = 0, es_result_relations = 0x14299a8, es_num_result_relations = 1, es_result_relation_info = 0x14299a8, 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 = 0x142afc0, es_trig_oldtup_slot = 0x0, es_trig_newtup_slot = 0x0, es_param_list_info = 0x0 Es_param_exec_vals = 0x1429970, es_queryEnv = 0x0, es_query_cxt = 0x1429640, es_tupleTable = 0x142a200, es_rowMarks = 0x0, es_processed = 0, es_lastoid = 0, es_top_eflags = 0, es_instrument = 0, es_finished = false, es_exprcontexts = 0x1429ef0, es_subplanstates = 0x0, es_auxmodifytables = 0x0, es_per_tuple_exprcontext = 0x142b080, 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, es_jit_worker_instr = 0x0} (gdb)

Enter the get_partition_for_tuple function

(gdb) n288 cur_index = get_partition_for_tuple (rel, values, isnull); (gdb) stepget_partition_for_tuple (relation=0x7fbfa6900950, values=0x7ffc7eba5bb0, isnull=0x7ffc7eba5b90) at execPartition.c:11391139 int part_index =-1; (gdb)

Get_partition_for_tuple- > get the partition key

1139 int part_index =-1; (gdb) n1140 PartitionKey key = RelationGetPartitionKey (relation); (gdb) 1141 PartitionDesc partdesc = RelationGetPartitionDesc (relation) (gdb) p key$26 = (PartitionKey) 0x1489860 (gdb) p * key$27 = {strategy = 104hype, partnatts = 1, partattrs = 0x14898f8, partexprs = 0x0, partopfamily = 0x1489918, partopcintype = 0x1489938, partsupfunc = 0x1489958, partcollation = 0x14899b0, parttypid = 0x14899d0, parttypmod = 0x14899f0, parttyplen = 0x1489a10, parttypbyval = 0x1489a30, parttypalign = 0x1489a50 "i177\ 177\ 177\ 177\ 177\ 177", parttypcoll = 0x1489a70}

Get_partition_for_tuple- > get partition descriptor & partition boundary information

(gdb) n1142 PartitionBoundInfo boundinfo = partdesc- > boundinfo; (gdb) 1145 switch (key- > strategy) (gdb) p * partdesc$28 = {nparts = 6, oids = 0x149b168, boundinfo = 0x149b1a0} (gdb) p * boundinfo$29 = {strategy = 104 'hacks, ndatums = 6, datums = 0x149b1f8, kind = 0x0, indexes = 0x149b288, null_index =-1, default_index =-1}

Get_partition_for_tuple- > enter the Hash partition processing branch

(gdb) n1152 greatest_modulus = get_hash_partition_greatest_modulus (boundinfo); (gdb) p key- > strategy$30 = 104h'

Get_partition_for_tuple- > calculate the number of modules & row hash value to get the partition number (index)

(gdb) n1153 rowHash = compute_partition_hash_value (key- > partnatts, (gdb) n1157 part_index = boundinfo- > indexes [rowHash% greatest_modulus]; (gdb) 1159 break; (gdb) p part_index$31 = 2 (gdb)

Get_partition_for_tuple- > return

(gdb) n1228 if (part_index

< 0)(gdb) 1231 return part_index;(gdb) 1232 }(gdb) ExecFindPartition (resultRelInfo=0x14299a8, pd=0x142ae58, slot=0x142a140, estate=0x1429758) at execPartition.c:295295 if (cur_index < 0)(gdb) 已取得分区信息(分区索引编号=2) (gdb) n300 else if (dispatch->

Indexes [cur _ index] > = 0) (gdb) 302 result = dispatch- > indexes [cur _ index]; (gdb) p dispatch- > indexes [cur _ index] $32 = 2 (gdb) n304 break; (gdb) 324 if (slot = = myslot) (gdb) 328 if (result)

< 0)(gdb) 342 MemoryContextSwitchTo(oldcxt);(gdb) 343 ecxt->

Ecxt_scantuple = ecxt_scantuple_old; (gdb) 345 return result; (gdb)

Complete the function call

(gdb) n346} (gdb) ExecPrepareTupleRouting (mtstate=0x1429ac0, estate=0x1429758, proute=0x142a7a8, targetRelInfo=0x14299a8, slot=0x142a140) at nodeModifyTable.c:17161716 Assert (partidx > = 0 & & partidx

< proute->

Num_partitions); "which function in PostgreSQL finds the right partition for heap tuple" is introduced here, thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report