Sorry for the delay in my response. On Wed, May 29, 2024 at 9:34 AM Ashutosh Bapat <ashutosh.bapat....@gmail.com> wrote: > > Documenting some comments from todays' patch review session
I forgot to mention back then that both of the suggestions below came from Tom Lane. > 1. Instead of a nested hash table, it might be better to use a flat hash > table to save more memory. Done. It indeed saves memory without impacting planning time. > 2. new comm_rinfo member in RestrictInfo may have problems when copying > RestrictInfo or translating it. Instead commuted versions may be tracked > outside RestrictInfo After commit 767c598954bbf72e0535f667e2e0667765604b2a, repameterization of parent paths for child relation happen at the time of creating the plan. This reduces the number of child paths produced by reparameterization and also reduces the number of RestrictInfos that get translated during reparameterization. During reparameterization commuted parent RestrictInfos are required to be translated to child RestrictInfos. Before the commit, this led to translating the same commuted parent RestrictInfo multiple times. After the commit, only one path gets reparameterized for a given parent and child pair. Hence we do not produce multiple copies of the same commuted child RestrictInfo. Hence we don't need to keep track of commuted child RestrictInfos anymore. Removed that portion of code from the patches. I made detailed memory consumption measurements with this patch for number of partitions changed from 0 (unpartitioned) to 1000 and for 2 to 5-way joins. They are available in the spreadsheet at [1]. The raw measurement data is in the first sheet named "pwj_mem_measurements raw numbers". The averages over multiple runs are in second sheet named "avg_numbers". Rest of the sheet represent the averages in more consumable manner. Please note that the averages make sense only for planning time since the memory consumption remains same with every run. Also note that EXPLAIN now reports planning memory consumption in kB. Any changes to memory consumption below 1kB are not reported and hence not noticed. Here are some observations. 1. When partitionwise join is not enabled, no changes to planner's memory consumption are observed. See sheet named "pwj disabled, planning memory". 2. When partitionwise join is enabled, upto 17% (206MB) memory is saved by the patch in case of 5-way self-join with 1000 partitions. This is the maximum memory saving observed. The amount of memory saved increases with the number of joins and number of partitions. See sheet with name "pwj enabled, planning memory" 3. After commit 767c598954bbf72e0535f667e2e0667765604b2a, we do not translate a parent RestrictInfo multiple times for the same parent-child pair in case of a *2-way partitionwise join*. But we still consume memory in saving the child RestrictInfo in the hash table. Hence in case of 2-way join we see increased memory consumption with the patch compared to master. The memory consumption increases by 13kb, 23kB, 76kB and 146kB for 10, 100, 500, 1000 partitions respectively. This increase is smaller compared to the overall memory saving. In order to avoid this memory increase, we will need to avoid using hash table for 2-way join. We will need to know whether there will be more than one partitionwise join before translating the RestrictInfos for the first partitionwise join. This is hard to achieve in all the cases since the decision to use partitionwise join happens at the time of creating paths for a given join relation, which itself is computed on the fly. We may choose some heuristics which take into account the number of partitioned tables in the query, their partition schemes, and the quals in the query to decide whether or not to track the translated child RestrictInfos. But that will make the code more complex, but more importantly the heuristics may not be able to keep up if we start using partitionwise join as an optimization strategy for more cases (e.g. asymmetric partitionwise join [2]). The attached patch looks like a good tradeoff to me. But other opinions might vary. Suggestions are welcome. 4. There is no noticeable change in the planning time. I ran the same experiment multiple times. The planning time variations from each experiment do not show any noticeable pattern suggesting increase or decrease in the planning time with the patch. A note about the code: I have added all the structures and functions dealing with the RestrictInfo hash table at the end of restrictinfo.c. I have not come across a C file in PostgreSQL code base where private structures are defined in the middle the file; usually they are defined at the beginning of the file. But I have chosen it that way here since it makes it easy to document the hash table and the functions at one place at the beginning of this code section. I am open to suggestions which make the documentation easy while placing the structures at the beginning of the file. [1] https://docs.google.com/spreadsheets/d/1CEjRWZ02vuR8fSwhYaNugewtX8f0kIm5pLoRA95f3s8/edit?usp=sharing [2] https://www.postgresql.org/message-id/flat/CAOP8fzaVL_2SCJayLL9kj5pCA46PJOXXjuei6-3aFUV45j4LJQ%40mail.gmail.com -- Best Wishes, Ashutosh Bapat
From c98b9efdca5e9201df3aa233c3e49f8e344b22b4 Mon Sep 17 00:00:00 2001 From: Ashutosh Bapat <ashutosh.bapat@enterprisedb.com> Date: Mon, 4 Sep 2023 14:56:21 +0530 Subject: [PATCH 1/2] Avoid translating RestrictInfo repeatedly RestrictInfo for the child relations (including the child join relations) are obtained by translating RestrictInfo applicable to the parent rel. Since these translations are not tracked, the same RestrictInfo may get translated multiple times for the same parent and child pair. When using partitionwise join this can happen as many times as the number of possible join orders between the partitioned tables and as many times a parent path is reparameterized for a child if a clause is used in such a path. Repeated translations are avoided by saving them in a hash table hanging off of PlannerInfo. RestrictInfo::rinfo_serial and RestrictInfo::required_relids are used to compute hash key since they together identify a RestrictInfo uniquely. Two functions find_child_rinfo() and add_child_rinfo() are used to search a RestrictInfo for a given tanslation and add a child RestrictInfo respectively. Ashutosh Bapat --- src/backend/optimizer/path/equivclass.c | 18 +- src/backend/optimizer/path/joinrels.c | 7 +- src/backend/optimizer/util/pathnode.c | 113 +++++++++- src/backend/optimizer/util/relnode.c | 7 +- src/backend/optimizer/util/restrictinfo.c | 256 +++++++++++++++++++++- src/include/nodes/pathnodes.h | 6 + src/include/optimizer/restrictinfo.h | 10 + src/tools/pgindent/typedefs.list | 3 + 8 files changed, 400 insertions(+), 20 deletions(-) diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index d871396e20..bb1f6c13c1 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -27,6 +27,7 @@ #include "optimizer/optimizer.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" +#include "optimizer/cost.h" #include "optimizer/planmain.h" #include "optimizer/restrictinfo.h" #include "rewrite/rewriteManip.h" @@ -1900,10 +1901,6 @@ create_join_clause(PlannerInfo *root, rinfo->clause_relids = bms_add_members(rinfo->clause_relids, rightem->em_relids); - /* If it's a child clause, copy the parent's rinfo_serial */ - if (parent_rinfo) - rinfo->rinfo_serial = parent_rinfo->rinfo_serial; - /* Mark the clause as redundant, or not */ rinfo->parent_ec = parent_ec; @@ -1922,6 +1919,19 @@ create_join_clause(PlannerInfo *root, MemoryContextSwitchTo(oldcontext); + if (parent_rinfo) + { + /* Copy parent's rinfo_serial to child RestrictInfo. */ + rinfo->rinfo_serial = parent_rinfo->rinfo_serial; + + /* + * We have obtained a translation through EC machinery. Paritionwise + * join will require the same translation. + */ + if (enable_partitionwise_join) + add_restrictinfo(root, rinfo); + } + return rinfo; } diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 7db5e30eef..2aebdf0078 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -19,6 +19,7 @@ #include "optimizer/joininfo.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" +#include "optimizer/restrictinfo.h" #include "partitioning/partbounds.h" #include "utils/memutils.h" @@ -1651,10 +1652,8 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2, * Construct restrictions applicable to the child join from those * applicable to the parent join. */ - child_restrictlist = - (List *) adjust_appendrel_attrs(root, - (Node *) parent_restrictlist, - nappinfos, appinfos); + child_restrictlist = get_child_restrictinfos(root, parent_restrictlist, + nappinfos, appinfos); /* Find or construct the child join's RelOptInfo */ child_joinrel = joinrel->part_rels[cnt_parts]; diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 54e042a8a5..a01ef273a5 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -26,6 +26,7 @@ #include "optimizer/pathnode.h" #include "optimizer/paths.h" #include "optimizer/planmain.h" +#include "optimizer/restrictinfo.h" #include "optimizer/tlist.h" #include "parser/parsetree.h" #include "utils/memutils.h" @@ -4080,6 +4081,78 @@ reparameterize_path(PlannerInfo *root, Path *path, return NULL; } +/* + * build_child_iclauses_multilevel + * Translate IndexClause list applicable to the given top parent relation to + * that applicable to the given child relation where the child relation may + * be several levels below the top parent in the partition hierarchy. + * + * This is similar to adjust_appendrel_attrs_multilevel() for IndexClause + * except that it uses translated RestrictInfos if already available. + */ +static List * +build_child_iclauses_multilevel(PlannerInfo *root, + List *parent_iclauselist, + RelOptInfo *childrel, + RelOptInfo *top_parent) +{ + List *child_iclauses = NIL; + + foreach_node(IndexClause, iclause, parent_iclauselist) + { + List *rinfo_list = NIL; + List *child_rinfo_list; + IndexClause *child_iclause = makeNode(IndexClause); + ListCell *lcp; + ListCell *lcc; + List *indexquals; + + memcpy(child_iclause, iclause, sizeof(IndexClause)); + + /* + * Collect RestrictInfos to be translated. That's all there's to + * translate in an IndexClause. + */ + rinfo_list = lappend(rinfo_list, iclause->rinfo); + rinfo_list = list_concat(rinfo_list, iclause->indexquals); + + child_rinfo_list = get_child_restrictinfos_multilevel(root, rinfo_list, + childrel, top_parent); + child_iclause->rinfo = linitial(child_rinfo_list); + child_iclause->indexquals = NIL; + indexquals = list_delete_first(child_rinfo_list); + + /* + * indexquals of parent indexclause may have commuted RestrictInfos. + * Commute the child indexquals accordingly. + */ + forboth(lcc, indexquals, lcp, iclause->indexquals) + { + RestrictInfo *child_rinfo = lfirst_node(RestrictInfo, lcc); + RestrictInfo *rinfo = lfirst_node(RestrictInfo, lcp); + Relids child_left_relids; + + child_left_relids = adjust_child_relids_multilevel(root, rinfo->left_relids, + childrel, top_parent); + if (!bms_equal(child_left_relids, child_rinfo->left_relids)) + { + OpExpr *clause = castNode(OpExpr, rinfo->clause); + + Assert(bms_equal(child_left_relids, child_rinfo->right_relids)); + + child_rinfo = commute_restrictinfo(child_rinfo, clause->opno); + } + + child_iclause->indexquals = lappend(child_iclause->indexquals, child_rinfo); + } + + list_free(rinfo_list); + child_iclauses = lappend(child_iclauses, child_iclause); + } + + return child_iclauses; +} + /* * reparameterize_path_by_child * Given a path parameterized by the parent of the given child relation, @@ -4182,7 +4255,10 @@ do { \ IndexPath *ipath = (IndexPath *) path; ADJUST_CHILD_ATTRS(ipath->indexinfo->indrestrictinfo); - ADJUST_CHILD_ATTRS(ipath->indexclauses); + ipath->indexclauses = + build_child_iclauses_multilevel(root, + ipath->indexclauses, + child_rel, child_rel->top_parent); new_path = (Path *) ipath; } break; @@ -4261,7 +4337,11 @@ do { \ REPARAMETERIZE_CHILD_PATH(jpath->outerjoinpath); REPARAMETERIZE_CHILD_PATH(jpath->innerjoinpath); - ADJUST_CHILD_ATTRS(jpath->joinrestrictinfo); + jpath->joinrestrictinfo = + get_child_restrictinfos_multilevel(root, + jpath->joinrestrictinfo, + child_rel, + child_rel->top_parent); new_path = (Path *) npath; } break; @@ -4273,8 +4353,16 @@ do { \ REPARAMETERIZE_CHILD_PATH(jpath->outerjoinpath); REPARAMETERIZE_CHILD_PATH(jpath->innerjoinpath); - ADJUST_CHILD_ATTRS(jpath->joinrestrictinfo); - ADJUST_CHILD_ATTRS(mpath->path_mergeclauses); + jpath->joinrestrictinfo = + get_child_restrictinfos_multilevel(root, + jpath->joinrestrictinfo, + child_rel, + child_rel->top_parent); + mpath->path_mergeclauses = + get_child_restrictinfos_multilevel(root, + mpath->path_mergeclauses, + child_rel, + child_rel->top_parent); new_path = (Path *) mpath; } break; @@ -4286,8 +4374,16 @@ do { \ REPARAMETERIZE_CHILD_PATH(jpath->outerjoinpath); REPARAMETERIZE_CHILD_PATH(jpath->innerjoinpath); - ADJUST_CHILD_ATTRS(jpath->joinrestrictinfo); - ADJUST_CHILD_ATTRS(hpath->path_hashclauses); + jpath->joinrestrictinfo = + get_child_restrictinfos_multilevel(root, + jpath->joinrestrictinfo, + child_rel, + child_rel->top_parent); + hpath->path_hashclauses = + get_child_restrictinfos_multilevel(root, + hpath->path_hashclauses, + child_rel, + child_rel->top_parent); new_path = (Path *) hpath; } break; @@ -4364,7 +4460,10 @@ do { \ new_ppi->ppi_req_outer = bms_copy(required_outer); new_ppi->ppi_rows = old_ppi->ppi_rows; new_ppi->ppi_clauses = old_ppi->ppi_clauses; - ADJUST_CHILD_ATTRS(new_ppi->ppi_clauses); + new_ppi->ppi_clauses = + get_child_restrictinfos_multilevel(root, + new_ppi->ppi_clauses, child_rel, + child_rel->top_parent); new_ppi->ppi_serials = bms_copy(old_ppi->ppi_serials); rel->ppilist = lappend(rel->ppilist, new_ppi); diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index d7266e4cdb..fb86728b71 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -961,10 +961,9 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel, nappinfos, appinfos); /* Construct joininfo list. */ - joinrel->joininfo = (List *) adjust_appendrel_attrs(root, - (Node *) parent_joinrel->joininfo, - nappinfos, - appinfos); + joinrel->joininfo = get_child_restrictinfos(root, + parent_joinrel->joininfo, + nappinfos, appinfos); /* * Lateral relids referred in child join will be same as that referred in diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c index 0b406e9334..854b429ae4 100644 --- a/src/backend/optimizer/util/restrictinfo.c +++ b/src/backend/optimizer/util/restrictinfo.c @@ -16,10 +16,11 @@ #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" +#include "optimizer/appendinfo.h" #include "optimizer/clauses.h" #include "optimizer/optimizer.h" #include "optimizer/restrictinfo.h" - +#include "common/hashfn.h" static RestrictInfo *make_restrictinfo_internal(PlannerInfo *root, Expr *clause, @@ -362,6 +363,7 @@ commute_restrictinfo(RestrictInfo *rinfo, Oid comm_op) OpExpr *newclause; OpExpr *clause = castNode(OpExpr, rinfo->clause); + clause = castNode(OpExpr, rinfo->clause); Assert(list_length(clause->args) == 2); /* flat-copy all the fields of clause ... */ @@ -685,3 +687,255 @@ join_clause_is_movable_into(RestrictInfo *rinfo, return true; } + +/* ---------------------------------------------------------------------------- + * RestrictInfo hash table interface. + * + * RestrictInfos applicable to a child relation are obtained by translating the + * corresponding RestrictInfos applicable to the parent relation. The same + * parent RestictInfo appears in restrictlist or joininfo list of many parent + * join relations and thus may get translated multiple times producing multiple + * instances of the same child RestrictInfo. In order to avoid that we save the + * translated child RestrictInfos in a hash table. RestrictInfo::rinfo_serial + * is unique for every parent RestrictInfo. RestrictInfo::required_relids + * identifies the child relation to which the RestrictInfo is applicable. + * Together they uniquely identify a given translated RestictInfo. Hence + * together they are used as a key into the hash table. + * ---------------------------------------------------------------------------- + */ + +/* + * Hash key for RestrictInfo hash table. + */ +typedef struct +{ + int rinfo_serial; /* Same as RestrictInfo::rinfo_serial */ + Relids required_relids; /* Same as RestrictInfo::required_relids */ +} rinfo_tab_key; + +/* Hash table entry for RestrictInfo hash table. */ +typedef struct rinfo_tab_entry +{ + rinfo_tab_key key; /* Key must be first. */ + RestrictInfo *rinfo; +} rinfo_tab_entry; + +/* + * rinfo_tab_key_hash + * Computes hash of RestrictInfo hash table key. + */ +static uint32 +rinfo_tab_key_hash(const void *key, Size size) +{ + rinfo_tab_key *rtabkey = (rinfo_tab_key *) key; + uint32 result; + + Assert(sizeof(rinfo_tab_key) == size); + + /* Combine hashes of all components of the key. */ + result = hash_bytes_uint32(rtabkey->rinfo_serial); + result = hash_combine(result, bms_hash_value(rtabkey->required_relids)); + + return result; +} + +/* + * rinfo_tab_key_match + * Match function for RestrictInfo hash table. + */ +static int +rinfo_tab_key_match(const void *key1, const void *key2, Size size) +{ + rinfo_tab_key *rtabkey1 = (rinfo_tab_key *) key1; + rinfo_tab_key *rtabkey2 = (rinfo_tab_key *) key2; + int result; + + Assert(sizeof(rinfo_tab_key) == size); + + result = rtabkey1->rinfo_serial - rtabkey2->rinfo_serial; + if (result) + return result; + + return !bms_equal(rtabkey1->required_relids, rtabkey2->required_relids); +} + +/* + * get_restrictinfo_table + * Returns the RestrictInfo hash table from PlannerInfo, creating it if + * necessary. + */ +static HTAB * +get_restrictinfo_table(PlannerInfo *root) +{ + if (!root->rinfo_hash) + { + HASHCTL hash_ctl = {0}; + + hash_ctl.keysize = sizeof(rinfo_tab_key); + hash_ctl.entrysize = sizeof(rinfo_tab_entry); + hash_ctl.hcxt = root->planner_cxt; + hash_ctl.hash = rinfo_tab_key_hash; + hash_ctl.match = rinfo_tab_key_match; + + root->rinfo_hash = hash_create("restrictinfo hash table", + 1000, + &hash_ctl, + HASH_ELEM | HASH_CONTEXT | HASH_FUNCTION | HASH_COMPARE); + } + + return root->rinfo_hash; +} + +/* + * add_restrictinfo + * Add the given RestrictInfo to the RestrictInfo hash table. + * + * The given RestrictInfo should not be present in the hash table. If it does, + * multiple instances of the same RestrictInfo may have been created. This + * function is a good place to flag that. + */ +extern void +add_restrictinfo(PlannerInfo *root, RestrictInfo *rinfo) +{ + HTAB *rinfo_hash = get_restrictinfo_table(root); + rinfo_tab_key key; + rinfo_tab_entry *rinfo_entry; + bool found; + + key.rinfo_serial = rinfo->rinfo_serial; + key.required_relids = rinfo->required_relids; + rinfo_entry = hash_search(rinfo_hash, &key, HASH_ENTER, &found); + + Assert(!found); + rinfo_entry->rinfo = rinfo; +} + +/* + * find_restrictinfo + * Return the child RestrictInfo with given rinfo_serial and + * required_relids from RestrictInfo hash table. + * + * The function returns NULL if it does not find the required RestrictInfo in + * the hash table. + */ +RestrictInfo * +find_restrictinfo(PlannerInfo *root, int rinfo_serial, Relids required_relids) +{ + HTAB *rinfo_hash = get_restrictinfo_table(root); + rinfo_tab_entry *rinfo_entry; + rinfo_tab_key key; + + key.rinfo_serial = rinfo_serial; + key.required_relids = required_relids; + rinfo_entry = hash_search(rinfo_hash, &key, + HASH_FIND, + NULL); + return (rinfo_entry ? rinfo_entry->rinfo : NULL); +} + +/* + * get_child_restrictinfos + * Returns list of child RestrictInfos obtained by + * translating the given parent RestrictInfos according to the given + * AppendRelInfos. + * + * If a required translated RestrictInfo is available in the RestrictInfo hash + * table, the function includes the available child RestrictInfo to the list. + * Otherwise, it translates the corresponding parent RestrictInfo and adds it to + * the RestrictInfo hash table. + */ +List * +get_child_restrictinfos(PlannerInfo *root, List *parent_restrictinfos, + int nappinfos, AppendRelInfo **appinfos) +{ + List *child_clauselist = NIL; + + foreach_node(RestrictInfo, parent_rinfo, parent_restrictinfos) + { + Relids child_req_relids; + RestrictInfo *child_rinfo = NULL; + + child_req_relids = adjust_child_relids(parent_rinfo->required_relids, + nappinfos, appinfos); + + if (bms_equal(child_req_relids, parent_rinfo->required_relids)) + { + /* + * If no relid was translated, child's RestrictInfo is same as + * that of parent. + */ + child_rinfo = parent_rinfo; + } + else + { + child_rinfo = find_restrictinfo(root, parent_rinfo->rinfo_serial, child_req_relids); + + /* + * This function may be called thousands of times when there are + * thousands of partitions involved. We won't require the + * translated child relids further. Hence free those to avoid + * accumulating huge amounts of memory. + */ + bms_free(child_req_relids); + } + + if (!child_rinfo) + { + child_rinfo = castNode(RestrictInfo, + adjust_appendrel_attrs(root, (Node *) parent_rinfo, + nappinfos, appinfos)); + add_restrictinfo(root, child_rinfo); + } + + child_clauselist = lappend(child_clauselist, child_rinfo); + } + + return child_clauselist; +} + +/* + * get_child_restrictinfos_multilevel + * Similar to get_child_restrictinfos() but for translations through multiple + * levels of partitioning hierarchy. + * + * This function is similar to adjust_appendrel_attrs_multilevel() except that + * this function makes use of RestrictInfo hash table. + */ +List * +get_child_restrictinfos_multilevel(PlannerInfo *root, List *parent_clauselist, + RelOptInfo *child_rel, RelOptInfo *top_parent) +{ + AppendRelInfo **appinfos; + int nappinfos; + List *tmp_clauselist = parent_clauselist; + List *child_clauselist; + + /* Recursively traverse up the partition hierarchy. */ + if (child_rel->parent != top_parent) + { + if (child_rel->parent) + { + tmp_clauselist = get_child_restrictinfos_multilevel(root, + parent_clauselist, + child_rel->parent, + top_parent); + } + else + elog(ERROR, "child_rel is not a child of top_parent"); + } + + appinfos = find_appinfos_by_relids(root, child_rel->relids, &nappinfos); + child_clauselist = get_child_restrictinfos(root, tmp_clauselist, + nappinfos, appinfos); + + /* + * This function will be called thousands of times, if there are thousands + * of partitions involved. Free temporary objects created in this function + * to avoid accumulating huge memory. + */ + pfree(appinfos); + if (tmp_clauselist != parent_clauselist) + list_free(tmp_clauselist); + + return child_clauselist; +} diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index 14ccfc1ac1..d11de3775f 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -553,6 +553,12 @@ struct PlannerInfo /* Does this query modify any partition key columns? */ bool partColsUpdated; + + /* + * Hash table to save translated RestrictInfos while planning + * partitionwise join. + */ + struct HTAB *rinfo_hash pg_node_attr(read_write_ignore); }; diff --git a/src/include/optimizer/restrictinfo.h b/src/include/optimizer/restrictinfo.h index 1b42c832c5..c0624ad8c8 100644 --- a/src/include/optimizer/restrictinfo.h +++ b/src/include/optimizer/restrictinfo.h @@ -47,5 +47,15 @@ extern bool join_clause_is_movable_to(RestrictInfo *rinfo, RelOptInfo *baserel); extern bool join_clause_is_movable_into(RestrictInfo *rinfo, Relids currentrelids, Relids current_and_outer); +extern RestrictInfo *find_restrictinfo(PlannerInfo *root, int rinfo_serial, + Relids child_required_relids); +extern void add_restrictinfo(PlannerInfo *root, RestrictInfo *child_rinfo); +extern List *get_child_restrictinfos(PlannerInfo *root, + List *parent_restrictinfos, + int nappinfos, AppendRelInfo **appinfos); +extern List *get_child_restrictinfos_multilevel(PlannerInfo *root, + List *parent_clauselist, + RelOptInfo *child_rel, + RelOptInfo *top_parent); #endif /* RESTRICTINFO_H */ diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 547d14b3e7..bac0792834 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -395,6 +395,7 @@ CheckPointStmt CheckpointStatsData CheckpointerRequest CheckpointerShmemStruct +ChildRinfoTabEntry Chromosome CkptSortItem CkptTsStatus @@ -3864,6 +3865,8 @@ rewind_source rewrite_event rf_context rfile +rinfo_tab_entry +rinfo_tab_key rm_detail_t role_auth_extra rolename_hash -- 2.34.1