PostgreSQL Source Code  git master
prepunion.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/sysattr.h"
#include "catalog/partition.h"
#include "catalog/pg_inherits_fn.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
#include "optimizer/planner.h"
#include "optimizer/prep.h"
#include "optimizer/tlist.h"
#include "parser/parse_coerce.h"
#include "parser/parsetree.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/selfuncs.h"
Include dependency graph for prepunion.c:

Go to the source code of this file.

Data Structures

struct  adjust_appendrel_attrs_context
 

Functions

static Pathrecurse_set_operations (Node *setOp, PlannerInfo *root, List *colTypes, List *colCollations, bool junkOK, int flag, List *refnames_tlist, List **pTargetList, double *pNumGroups)
 
static Pathgenerate_recursion_path (SetOperationStmt *setOp, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
 
static Pathgenerate_union_path (SetOperationStmt *op, PlannerInfo *root, List *refnames_tlist, List **pTargetList, double *pNumGroups)
 
static Pathgenerate_nonunion_path (SetOperationStmt *op, PlannerInfo *root, List *refnames_tlist, List **pTargetList, double *pNumGroups)
 
static Listrecurse_union_children (Node *setOp, PlannerInfo *root, SetOperationStmt *top_union, List *refnames_tlist, List **tlist_list)
 
static Pathmake_union_unique (SetOperationStmt *op, Path *path, List *tlist, PlannerInfo *root)
 
static bool choose_hashed_setop (PlannerInfo *root, List *groupClauses, Path *input_path, double dNumGroups, double dNumOutputRows, const char *construct)
 
static Listgenerate_setop_tlist (List *colTypes, List *colCollations, int flag, Index varno, bool hack_constants, List *input_tlist, List *refnames_tlist)
 
static Listgenerate_append_tlist (List *colTypes, List *colCollations, bool flag, List *input_tlists, List *refnames_tlist)
 
static Listgenerate_setop_grouplist (SetOperationStmt *op, List *targetlist)
 
static void expand_inherited_rtentry (PlannerInfo *root, RangeTblEntry *rte, Index rti)
 
static void expand_partitioned_rtentry (PlannerInfo *root, RangeTblEntry *parentrte, Index parentRTindex, Relation parentrel, PlanRowMark *top_parentrc, LOCKMODE lockmode, List **appinfos, List **partitioned_child_rels)
 
static void expand_single_inheritance_child (PlannerInfo *root, RangeTblEntry *parentrte, Index parentRTindex, Relation parentrel, PlanRowMark *top_parentrc, Relation childrel, List **appinfos, RangeTblEntry **childrte_p, Index *childRTindex_p)
 
static void make_inh_translation_list (Relation oldrelation, Relation newrelation, Index newvarno, List **translated_vars)
 
static Bitmapsettranslate_col_privs (const Bitmapset *parent_privs, List *translated_vars)
 
static Nodeadjust_appendrel_attrs_mutator (Node *node, adjust_appendrel_attrs_context *context)
 
static Relids adjust_child_relids (Relids relids, int nappinfos, AppendRelInfo **appinfos)
 
static Listadjust_inherited_tlist (List *tlist, AppendRelInfo *context)
 
RelOptInfoplan_set_operations (PlannerInfo *root)
 
void expand_inherited_tables (PlannerInfo *root)
 
Nodeadjust_appendrel_attrs (PlannerInfo *root, Node *node, int nappinfos, AppendRelInfo **appinfos)
 
Relids adjust_child_relids_multilevel (PlannerInfo *root, Relids relids, Relids child_relids, Relids top_parent_relids)
 
Nodeadjust_appendrel_attrs_multilevel (PlannerInfo *root, Node *node, Relids child_relids, Relids top_parent_relids)
 
SpecialJoinInfobuild_child_join_sjinfo (PlannerInfo *root, SpecialJoinInfo *parent_sjinfo, Relids left_relids, Relids right_relids)
 
AppendRelInfo ** find_appinfos_by_relids (PlannerInfo *root, Relids relids, int *nappinfos)
 

Function Documentation

◆ adjust_appendrel_attrs()

Node* adjust_appendrel_attrs ( PlannerInfo root,
Node node,
int  nappinfos,
AppendRelInfo **  appinfos 
)

Definition at line 1946 of file prepunion.c.

References adjust_appendrel_attrs_mutator(), adjust_inherited_tlist(), adjust_appendrel_attrs_context::appinfos, Assert, AppendRelInfo::child_relid, CMD_UPDATE, Query::commandType, IsA, adjust_appendrel_attrs_context::nappinfos, AppendRelInfo::parent_relid, QTW_IGNORE_RC_SUBQUERIES, query_tree_mutator(), Query::resultRelation, adjust_appendrel_attrs_context::root, and Query::targetList.

Referenced by add_child_rel_equivalences(), add_placeholders_to_child_joinrel(), adjust_appendrel_attrs_multilevel(), build_child_join_rel(), build_child_join_sjinfo(), inheritance_planner(), set_append_rel_size(), and try_partition_wise_join().

1948 {
1949  Node *result;
1951 
1952  context.root = root;
1953  context.nappinfos = nappinfos;
1954  context.appinfos = appinfos;
1955 
1956  /* If there's nothing to adjust, don't call this function. */
1957  Assert(nappinfos >= 1 && appinfos != NULL);
1958 
1959  /*
1960  * Must be prepared to start with a Query or a bare expression tree.
1961  */
1962  if (node && IsA(node, Query))
1963  {
1964  Query *newnode;
1965  int cnt;
1966 
1967  newnode = query_tree_mutator((Query *) node,
1969  (void *) &context,
1971  for (cnt = 0; cnt < nappinfos; cnt++)
1972  {
1973  AppendRelInfo *appinfo = appinfos[cnt];
1974 
1975  if (newnode->resultRelation == appinfo->parent_relid)
1976  {
1977  newnode->resultRelation = appinfo->child_relid;
1978  /* Fix tlist resnos too, if it's inherited UPDATE */
1979  if (newnode->commandType == CMD_UPDATE)
1980  newnode->targetList =
1982  appinfo);
1983  break;
1984  }
1985  }
1986 
1987  result = (Node *) newnode;
1988  }
1989  else
1990  result = adjust_appendrel_attrs_mutator(node, &context);
1991 
1992  return result;
1993 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
int resultRelation
Definition: parsenodes.h:120
Definition: nodes.h:512
static List * adjust_inherited_tlist(List *tlist, AppendRelInfo *context)
Definition: prepunion.c:2345
List * targetList
Definition: parsenodes.h:138
#define QTW_IGNORE_RC_SUBQUERIES
Definition: nodeFuncs.h:22
CmdType commandType
Definition: parsenodes.h:110
static Node * adjust_appendrel_attrs_mutator(Node *node, adjust_appendrel_attrs_context *context)
Definition: prepunion.c:1996
#define Assert(condition)
Definition: c.h:680
AppendRelInfo ** appinfos
Definition: prepunion.c:60
Index child_relid
Definition: relation.h:2072
Index parent_relid
Definition: relation.h:2071
Query * query_tree_mutator(Query *query, Node *(*mutator)(), void *context, int flags)
Definition: nodeFuncs.c:3068

◆ adjust_appendrel_attrs_multilevel()

Node* adjust_appendrel_attrs_multilevel ( PlannerInfo root,
Node node,
Relids  child_relids,
Relids  top_parent_relids 
)

Definition at line 2433 of file prepunion.c.

References adjust_appendrel_attrs(), adjust_appendrel_attrs_multilevel(), Assert, bms_add_member(), bms_equal(), bms_num_members(), find_appinfos_by_relids(), AppendRelInfo::parent_relid, and pfree().

Referenced by adjust_appendrel_attrs_multilevel(), and generate_join_implied_equalities_broken().

2436 {
2437  AppendRelInfo **appinfos;
2438  Bitmapset *parent_relids = NULL;
2439  int nappinfos;
2440  int cnt;
2441 
2442  Assert(bms_num_members(child_relids) == bms_num_members(top_parent_relids));
2443 
2444  appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
2445 
2446  /* Construct relids set for the immediate parent of given child. */
2447  for (cnt = 0; cnt < nappinfos; cnt++)
2448  {
2449  AppendRelInfo *appinfo = appinfos[cnt];
2450 
2451  parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
2452  }
2453 
2454  /* Recurse if immediate parent is not the top parent. */
2455  if (!bms_equal(parent_relids, top_parent_relids))
2456  node = adjust_appendrel_attrs_multilevel(root, node, parent_relids,
2457  top_parent_relids);
2458 
2459  /* Now translate for this child */
2460  node = adjust_appendrel_attrs(root, node, nappinfos, appinfos);
2461 
2462  pfree(appinfos);
2463 
2464  return node;
2465 }
Node * adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, Relids child_relids, Relids top_parent_relids)
Definition: prepunion.c:2433
void pfree(void *pointer)
Definition: mcxt.c:936
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:605
Node * adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos, AppendRelInfo **appinfos)
Definition: prepunion.c:1946
AppendRelInfo ** find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
Definition: prepunion.c:2517
#define Assert(condition)
Definition: c.h:680
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
Index parent_relid
Definition: relation.h:2071
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:131

◆ adjust_appendrel_attrs_mutator()

static Node * adjust_appendrel_attrs_mutator ( Node node,
adjust_appendrel_attrs_context context 
)
static

Definition at line 1996 of file prepunion.c.

References adjust_child_relids(), adjust_appendrel_attrs_context::appinfos, ConvertRowtypeExpr::arg, RowExpr::args, Assert, AppendRelInfo::child_relid, AppendRelInfo::child_reltype, RestrictInfo::clause, RestrictInfo::clause_relids, COERCE_IMPLICIT_CAST, Alias::colnames, RowExpr::colnames, ConvertRowtypeExpr::convertformat, copyObject, CurrentOfExpr::cvarno, elog, RangeTblEntry::eref, ERROR, RestrictInfo::eval_cost, expression_tree_mutator(), get_rel_name(), IsA, RestrictInfo::left_bucketsize, RestrictInfo::left_em, RestrictInfo::left_mcvfreq, RestrictInfo::left_relids, list_length(), list_nth(), ConvertRowtypeExpr::location, RowExpr::location, makeNode, adjust_appendrel_attrs_context::nappinfos, NIL, RestrictInfo::norm_selec, RestrictInfo::nullable_relids, OidIsValid, RestrictInfo::orclause, RestrictInfo::outer_relids, RestrictInfo::outer_selec, AppendRelInfo::parent_relid, AppendRelInfo::parent_reloid, AppendRelInfo::parent_reltype, PlannerInfo::parse, PlaceHolderVar::phlevelsup, PlaceHolderVar::phrels, RestrictInfo::required_relids, ConvertRowtypeExpr::resulttype, RestrictInfo::right_bucketsize, RestrictInfo::right_em, RestrictInfo::right_mcvfreq, RestrictInfo::right_relids, adjust_appendrel_attrs_context::root, RowExpr::row_format, RowExpr::row_typeid, rt_fetch, Query::rtable, RangeTblRef::rtindex, JoinExpr::rtindex, RestrictInfo::scansel_cache, QualCost::startup, AppendRelInfo::translated_vars, Var::varattno, Var::varlevelsup, Var::varno, Var::varnoold, and Var::vartype.

Referenced by adjust_appendrel_attrs().

1998 {
1999  AppendRelInfo **appinfos = context->appinfos;
2000  int nappinfos = context->nappinfos;
2001  int cnt;
2002 
2003  if (node == NULL)
2004  return NULL;
2005  if (IsA(node, Var))
2006  {
2007  Var *var = (Var *) copyObject(node);
2008  AppendRelInfo *appinfo = NULL;
2009 
2010  for (cnt = 0; cnt < nappinfos; cnt++)
2011  {
2012  if (var->varno == appinfos[cnt]->parent_relid)
2013  {
2014  appinfo = appinfos[cnt];
2015  break;
2016  }
2017  }
2018 
2019  if (var->varlevelsup == 0 && appinfo)
2020  {
2021  var->varno = appinfo->child_relid;
2022  var->varnoold = appinfo->child_relid;
2023  if (var->varattno > 0)
2024  {
2025  Node *newnode;
2026 
2027  if (var->varattno > list_length(appinfo->translated_vars))
2028  elog(ERROR, "attribute %d of relation \"%s\" does not exist",
2029  var->varattno, get_rel_name(appinfo->parent_reloid));
2030  newnode = copyObject(list_nth(appinfo->translated_vars,
2031  var->varattno - 1));
2032  if (newnode == NULL)
2033  elog(ERROR, "attribute %d of relation \"%s\" does not exist",
2034  var->varattno, get_rel_name(appinfo->parent_reloid));
2035  return newnode;
2036  }
2037  else if (var->varattno == 0)
2038  {
2039  /*
2040  * Whole-row Var: if we are dealing with named rowtypes, we
2041  * can use a whole-row Var for the child table plus a coercion
2042  * step to convert the tuple layout to the parent's rowtype.
2043  * Otherwise we have to generate a RowExpr.
2044  */
2045  if (OidIsValid(appinfo->child_reltype))
2046  {
2047  Assert(var->vartype == appinfo->parent_reltype);
2048  if (appinfo->parent_reltype != appinfo->child_reltype)
2049  {
2051 
2052  r->arg = (Expr *) var;
2053  r->resulttype = appinfo->parent_reltype;
2055  r->location = -1;
2056  /* Make sure the Var node has the right type ID, too */
2057  var->vartype = appinfo->child_reltype;
2058  return (Node *) r;
2059  }
2060  }
2061  else
2062  {
2063  /*
2064  * Build a RowExpr containing the translated variables.
2065  *
2066  * In practice var->vartype will always be RECORDOID here,
2067  * so we need to come up with some suitable column names.
2068  * We use the parent RTE's column names.
2069  *
2070  * Note: we can't get here for inheritance cases, so there
2071  * is no need to worry that translated_vars might contain
2072  * some dummy NULLs.
2073  */
2074  RowExpr *rowexpr;
2075  List *fields;
2076  RangeTblEntry *rte;
2077 
2078  rte = rt_fetch(appinfo->parent_relid,
2079  context->root->parse->rtable);
2080  fields = copyObject(appinfo->translated_vars);
2081  rowexpr = makeNode(RowExpr);
2082  rowexpr->args = fields;
2083  rowexpr->row_typeid = var->vartype;
2084  rowexpr->row_format = COERCE_IMPLICIT_CAST;
2085  rowexpr->colnames = copyObject(rte->eref->colnames);
2086  rowexpr->location = -1;
2087 
2088  return (Node *) rowexpr;
2089  }
2090  }
2091  /* system attributes don't need any other translation */
2092  }
2093  return (Node *) var;
2094  }
2095  if (IsA(node, CurrentOfExpr))
2096  {
2097  CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
2098 
2099  for (cnt = 0; cnt < nappinfos; cnt++)
2100  {
2101  AppendRelInfo *appinfo = appinfos[cnt];
2102 
2103  if (cexpr->cvarno == appinfo->parent_relid)
2104  {
2105  cexpr->cvarno = appinfo->child_relid;
2106  break;
2107  }
2108  }
2109  return (Node *) cexpr;
2110  }
2111  if (IsA(node, RangeTblRef))
2112  {
2113  RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
2114 
2115  for (cnt = 0; cnt < nappinfos; cnt++)
2116  {
2117  AppendRelInfo *appinfo = appinfos[cnt];
2118 
2119  if (rtr->rtindex == appinfo->parent_relid)
2120  {
2121  rtr->rtindex = appinfo->child_relid;
2122  break;
2123  }
2124  }
2125  return (Node *) rtr;
2126  }
2127  if (IsA(node, JoinExpr))
2128  {
2129  /* Copy the JoinExpr node with correct mutation of subnodes */
2130  JoinExpr *j;
2131  AppendRelInfo *appinfo;
2132 
2133  j = (JoinExpr *) expression_tree_mutator(node,
2135  (void *) context);
2136  /* now fix JoinExpr's rtindex (probably never happens) */
2137  for (cnt = 0; cnt < nappinfos; cnt++)
2138  {
2139  appinfo = appinfos[cnt];
2140 
2141  if (j->rtindex == appinfo->parent_relid)
2142  {
2143  j->rtindex = appinfo->child_relid;
2144  break;
2145  }
2146  }
2147  return (Node *) j;
2148  }
2149  if (IsA(node, PlaceHolderVar))
2150  {
2151  /* Copy the PlaceHolderVar node with correct mutation of subnodes */
2152  PlaceHolderVar *phv;
2153 
2154  phv = (PlaceHolderVar *) expression_tree_mutator(node,
2156  (void *) context);
2157  /* now fix PlaceHolderVar's relid sets */
2158  if (phv->phlevelsup == 0)
2159  phv->phrels = adjust_child_relids(phv->phrels, context->nappinfos,
2160  context->appinfos);
2161  return (Node *) phv;
2162  }
2163  /* Shouldn't need to handle planner auxiliary nodes here */
2164  Assert(!IsA(node, SpecialJoinInfo));
2165  Assert(!IsA(node, AppendRelInfo));
2166  Assert(!IsA(node, PlaceHolderInfo));
2167  Assert(!IsA(node, MinMaxAggInfo));
2168 
2169  /*
2170  * We have to process RestrictInfo nodes specially. (Note: although
2171  * set_append_rel_pathlist will hide RestrictInfos in the parent's
2172  * baserestrictinfo list from us, it doesn't hide those in joininfo.)
2173  */
2174  if (IsA(node, RestrictInfo))
2175  {
2176  RestrictInfo *oldinfo = (RestrictInfo *) node;
2177  RestrictInfo *newinfo = makeNode(RestrictInfo);
2178 
2179  /* Copy all flat-copiable fields */
2180  memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
2181 
2182  /* Recursively fix the clause itself */
2183  newinfo->clause = (Expr *)
2184  adjust_appendrel_attrs_mutator((Node *) oldinfo->clause, context);
2185 
2186  /* and the modified version, if an OR clause */
2187  newinfo->orclause = (Expr *)
2188  adjust_appendrel_attrs_mutator((Node *) oldinfo->orclause, context);
2189 
2190  /* adjust relid sets too */
2191  newinfo->clause_relids = adjust_child_relids(oldinfo->clause_relids,
2192  context->nappinfos,
2193  context->appinfos);
2195  context->nappinfos,
2196  context->appinfos);
2197  newinfo->outer_relids = adjust_child_relids(oldinfo->outer_relids,
2198  context->nappinfos,
2199  context->appinfos);
2201  context->nappinfos,
2202  context->appinfos);
2203  newinfo->left_relids = adjust_child_relids(oldinfo->left_relids,
2204  context->nappinfos,
2205  context->appinfos);
2206  newinfo->right_relids = adjust_child_relids(oldinfo->right_relids,
2207  context->nappinfos,
2208  context->appinfos);
2209 
2210  /*
2211  * Reset cached derivative fields, since these might need to have
2212  * different values when considering the child relation. Note we
2213  * don't reset left_ec/right_ec: each child variable is implicitly
2214  * equivalent to its parent, so still a member of the same EC if any.
2215  */
2216  newinfo->eval_cost.startup = -1;
2217  newinfo->norm_selec = -1;
2218  newinfo->outer_selec = -1;
2219  newinfo->left_em = NULL;
2220  newinfo->right_em = NULL;
2221  newinfo->scansel_cache = NIL;
2222  newinfo->left_bucketsize = -1;
2223  newinfo->right_bucketsize = -1;
2224  newinfo->left_mcvfreq = -1;
2225  newinfo->right_mcvfreq = -1;
2226 
2227  return (Node *) newinfo;
2228  }
2229 
2230  /*
2231  * NOTE: we do not need to recurse into sublinks, because they should
2232  * already have been converted to subplans before we see them.
2233  */
2234  Assert(!IsA(node, SubLink));
2235  Assert(!IsA(node, Query));
2236 
2238  (void *) context);
2239 }
QualCost eval_cost
Definition: relation.h:1878
#define NIL
Definition: pg_list.h:69
List * args
Definition: primnodes.h:990
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
Query * parse
Definition: relation.h:155
Index varlevelsup
Definition: primnodes.h:173
Node * expression_tree_mutator(Node *node, Node *(*mutator)(), void *context)
Definition: nodeFuncs.c:2409
Relids required_relids
Definition: relation.h:1859
List * colnames
Definition: primnodes.h:43
Selectivity right_mcvfreq
Definition: relation.h:1905
Expr * orclause
Definition: relation.h:1872
Relids clause_relids
Definition: relation.h:1856
Definition: nodes.h:512
Relids left_relids
Definition: relation.h:1868
AttrNumber varattno
Definition: primnodes.h:168
Definition: primnodes.h:163
#define OidIsValid(objectId)
Definition: c.h:586
List * translated_vars
Definition: relation.h:2099
Oid parent_reltype
Definition: relation.h:2080
Cost startup
Definition: relation.h:45
Relids outer_relids
Definition: relation.h:1862
Selectivity norm_selec
Definition: relation.h:1879
Index varnoold
Definition: primnodes.h:176
List * rtable
Definition: parsenodes.h:135
Relids phrels
Definition: relation.h:1947
#define ERROR
Definition: elog.h:43
List * colnames
Definition: primnodes.h:1006
Oid vartype
Definition: primnodes.h:170
EquivalenceMember * left_em
Definition: relation.h:1891
int location
Definition: primnodes.h:1007
void * list_nth(const List *list, int n)
Definition: list.c:410
Selectivity outer_selec
Definition: relation.h:1882
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
EquivalenceMember * right_em
Definition: relation.h:1892
Expr * clause
Definition: relation.h:1841
Index varno
Definition: primnodes.h:166
Relids nullable_relids
Definition: relation.h:1865
CoercionForm convertformat
Definition: primnodes.h:866
Selectivity left_bucketsize
Definition: relation.h:1902
#define makeNode(_type_)
Definition: nodes.h:560
Relids right_relids
Definition: relation.h:1869
static Node * adjust_appendrel_attrs_mutator(Node *node, adjust_appendrel_attrs_context *context)
Definition: prepunion.c:1996
#define Assert(condition)
Definition: c.h:680
Selectivity left_mcvfreq
Definition: relation.h:1904
Oid row_typeid
Definition: primnodes.h:991
static int list_length(const List *l)
Definition: pg_list.h:89
AppendRelInfo ** appinfos
Definition: prepunion.c:60
Oid child_reltype
Definition: relation.h:2081
Index phlevelsup
Definition: relation.h:1949
Selectivity right_bucketsize
Definition: relation.h:1903
#define elog
Definition: elog.h:219
Index child_relid
Definition: relation.h:2072
Alias * eref
Definition: parsenodes.h:1055
Oid parent_reloid
Definition: relation.h:2106
#define copyObject(obj)
Definition: nodes.h:625
Index parent_relid
Definition: relation.h:2071
CoercionForm row_format
Definition: primnodes.h:1005
int rtindex
Definition: primnodes.h:1463
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1745
List * scansel_cache
Definition: relation.h:1893
static Relids adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
Definition: prepunion.c:2246

◆ adjust_child_relids()

static Relids adjust_child_relids ( Relids  relids,
int  nappinfos,
AppendRelInfo **  appinfos 
)
static

Definition at line 2246 of file prepunion.c.

References bms_add_member(), bms_copy(), bms_del_member(), bms_is_member(), AppendRelInfo::child_relid, and AppendRelInfo::parent_relid.

Referenced by adjust_appendrel_attrs_mutator(), adjust_child_relids_multilevel(), and build_child_join_sjinfo().

2247 {
2248  Bitmapset *result = NULL;
2249  int cnt;
2250 
2251  for (cnt = 0; cnt < nappinfos; cnt++)
2252  {
2253  AppendRelInfo *appinfo = appinfos[cnt];
2254 
2255  /* Remove parent, add child */
2256  if (bms_is_member(appinfo->parent_relid, relids))
2257  {
2258  /* Make a copy if we are changing the set. */
2259  if (!result)
2260  result = bms_copy(relids);
2261 
2262  result = bms_del_member(result, appinfo->parent_relid);
2263  result = bms_add_member(result, appinfo->child_relid);
2264  }
2265  }
2266 
2267  /* If we made any changes, return the modified copy. */
2268  if (result)
2269  return result;
2270 
2271  /* Otherwise, return the original set without modification. */
2272  return relids;
2273 }
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:111
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
Index child_relid
Definition: relation.h:2072
Index parent_relid
Definition: relation.h:2071
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:735
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420

◆ adjust_child_relids_multilevel()

Relids adjust_child_relids_multilevel ( PlannerInfo root,
Relids  relids,
Relids  child_relids,
Relids  top_parent_relids 
)

Definition at line 2281 of file prepunion.c.

References adjust_child_relids(), adjust_child_relids_multilevel(), bms_add_member(), bms_equal(), bms_free(), bms_overlap(), find_appinfos_by_relids(), AppendRelInfo::parent_relid, and pfree().

Referenced by adjust_child_relids_multilevel(), and reparameterize_path_by_child().

2283 {
2284  AppendRelInfo **appinfos;
2285  int nappinfos;
2286  Relids parent_relids = NULL;
2287  Relids result;
2288  Relids tmp_result = NULL;
2289  int cnt;
2290 
2291  /*
2292  * If the given relids set doesn't contain any of the top parent relids,
2293  * it will remain unchanged.
2294  */
2295  if (!bms_overlap(relids, top_parent_relids))
2296  return relids;
2297 
2298  appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
2299 
2300  /* Construct relids set for the immediate parent of the given child. */
2301  for (cnt = 0; cnt < nappinfos; cnt++)
2302  {
2303  AppendRelInfo *appinfo = appinfos[cnt];
2304 
2305  parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
2306  }
2307 
2308  /* Recurse if immediate parent is not the top parent. */
2309  if (!bms_equal(parent_relids, top_parent_relids))
2310  {
2311  tmp_result = adjust_child_relids_multilevel(root, relids,
2312  parent_relids,
2313  top_parent_relids);
2314  relids = tmp_result;
2315  }
2316 
2317  result = adjust_child_relids(relids, nappinfos, appinfos);
2318 
2319  /* Free memory consumed by any intermediate result. */
2320  if (tmp_result)
2321  bms_free(tmp_result);
2322  bms_free(parent_relids);
2323  pfree(appinfos);
2324 
2325  return result;
2326 }
Relids adjust_child_relids_multilevel(PlannerInfo *root, Relids relids, Relids child_relids, Relids top_parent_relids)
Definition: prepunion.c:2281
void pfree(void *pointer)
Definition: mcxt.c:936
AppendRelInfo ** find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
Definition: prepunion.c:2517
void bms_free(Bitmapset *a)
Definition: bitmapset.c:201
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:443
Index parent_relid
Definition: relation.h:2071
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:131
static Relids adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
Definition: prepunion.c:2246

◆ adjust_inherited_tlist()

static List * adjust_inherited_tlist ( List tlist,
AppendRelInfo context 
)
static

Definition at line 2345 of file prepunion.c.

References Assert, elog, ERROR, get_rel_name(), IsA, lappend(), lfirst, list_length(), list_nth(), NIL, OidIsValid, AppendRelInfo::parent_reloid, TargetEntry::resjunk, TargetEntry::resno, AppendRelInfo::translated_vars, and Var::varattno.

Referenced by adjust_appendrel_attrs().

2346 {
2347  bool changed_it = false;
2348  ListCell *tl;
2349  List *new_tlist;
2350  bool more;
2351  int attrno;
2352 
2353  /* This should only happen for an inheritance case, not UNION ALL */
2354  Assert(OidIsValid(context->parent_reloid));
2355 
2356  /* Scan tlist and update resnos to match attnums of child rel */
2357  foreach(tl, tlist)
2358  {
2359  TargetEntry *tle = (TargetEntry *) lfirst(tl);
2360  Var *childvar;
2361 
2362  if (tle->resjunk)
2363  continue; /* ignore junk items */
2364 
2365  /* Look up the translation of this column: it must be a Var */
2366  if (tle->resno <= 0 ||
2367  tle->resno > list_length(context->translated_vars))
2368  elog(ERROR, "attribute %d of relation \"%s\" does not exist",
2369  tle->resno, get_rel_name(context->parent_reloid));
2370  childvar = (Var *) list_nth(context->translated_vars, tle->resno - 1);
2371  if (childvar == NULL || !IsA(childvar, Var))
2372  elog(ERROR, "attribute %d of relation \"%s\" does not exist",
2373  tle->resno, get_rel_name(context->parent_reloid));
2374 
2375  if (tle->resno != childvar->varattno)
2376  {
2377  tle->resno = childvar->varattno;
2378  changed_it = true;
2379  }
2380  }
2381 
2382  /*
2383  * If we changed anything, re-sort the tlist by resno, and make sure
2384  * resjunk entries have resnos above the last real resno. The sort
2385  * algorithm is a bit stupid, but for such a seldom-taken path, small is
2386  * probably better than fast.
2387  */
2388  if (!changed_it)
2389  return tlist;
2390 
2391  new_tlist = NIL;
2392  more = true;
2393  for (attrno = 1; more; attrno++)
2394  {
2395  more = false;
2396  foreach(tl, tlist)
2397  {
2398  TargetEntry *tle = (TargetEntry *) lfirst(tl);
2399 
2400  if (tle->resjunk)
2401  continue; /* ignore junk items */
2402 
2403  if (tle->resno == attrno)
2404  new_tlist = lappend(new_tlist, tle);
2405  else if (tle->resno > attrno)
2406  more = true;
2407  }
2408  }
2409 
2410  foreach(tl, tlist)
2411  {
2412  TargetEntry *tle = (TargetEntry *) lfirst(tl);
2413 
2414  if (!tle->resjunk)
2415  continue; /* here, ignore non-junk items */
2416 
2417  tle->resno = attrno;
2418  new_tlist = lappend(new_tlist, tle);
2419  attrno++;
2420  }
2421 
2422  return new_tlist;
2423 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
AttrNumber varattno
Definition: primnodes.h:168
Definition: primnodes.h:163
#define OidIsValid(objectId)
Definition: c.h:586
List * translated_vars
Definition: relation.h:2099
bool resjunk
Definition: primnodes.h:1382
#define ERROR
Definition: elog.h:43
void * list_nth(const List *list, int n)
Definition: list.c:410
AttrNumber resno
Definition: primnodes.h:1376
List * lappend(List *list, void *datum)
Definition: list.c:128
#define Assert(condition)
Definition: c.h:680
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
#define elog
Definition: elog.h:219
Oid parent_reloid
Definition: relation.h:2106
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1745

◆ build_child_join_sjinfo()

SpecialJoinInfo* build_child_join_sjinfo ( PlannerInfo root,
SpecialJoinInfo parent_sjinfo,
Relids  left_relids,
Relids  right_relids 
)

Definition at line 2473 of file prepunion.c.

References adjust_appendrel_attrs(), adjust_child_relids(), find_appinfos_by_relids(), makeNode, SpecialJoinInfo::min_lefthand, SpecialJoinInfo::min_righthand, pfree(), SpecialJoinInfo::semi_rhs_exprs, SpecialJoinInfo::syn_lefthand, and SpecialJoinInfo::syn_righthand.

Referenced by try_partition_wise_join().

2475 {
2477  AppendRelInfo **left_appinfos;
2478  int left_nappinfos;
2479  AppendRelInfo **right_appinfos;
2480  int right_nappinfos;
2481 
2482  memcpy(sjinfo, parent_sjinfo, sizeof(SpecialJoinInfo));
2483  left_appinfos = find_appinfos_by_relids(root, left_relids,
2484  &left_nappinfos);
2485  right_appinfos = find_appinfos_by_relids(root, right_relids,
2486  &right_nappinfos);
2487 
2488  sjinfo->min_lefthand = adjust_child_relids(sjinfo->min_lefthand,
2489  left_nappinfos, left_appinfos);
2491  right_nappinfos,
2492  right_appinfos);
2493  sjinfo->syn_lefthand = adjust_child_relids(sjinfo->syn_lefthand,
2494  left_nappinfos, left_appinfos);
2496  right_nappinfos,
2497  right_appinfos);
2498  sjinfo->semi_rhs_exprs = (List *) adjust_appendrel_attrs(root,
2499  (Node *) sjinfo->semi_rhs_exprs,
2500  right_nappinfos,
2501  right_appinfos);
2502 
2503  pfree(left_appinfos);
2504  pfree(right_appinfos);
2505 
2506  return sjinfo;
2507 }
Relids min_righthand
Definition: relation.h:2014
Definition: nodes.h:512
Relids syn_lefthand
Definition: relation.h:2015
Relids syn_righthand
Definition: relation.h:2016
void pfree(void *pointer)
Definition: mcxt.c:936
List * semi_rhs_exprs
Definition: relation.h:2024
Node * adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos, AppendRelInfo **appinfos)
Definition: prepunion.c:1946
AppendRelInfo ** find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
Definition: prepunion.c:2517
#define makeNode(_type_)
Definition: nodes.h:560
Definition: pg_list.h:45
Relids min_lefthand
Definition: relation.h:2013
static Relids adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
Definition: prepunion.c:2246

◆ choose_hashed_setop()

static bool choose_hashed_setop ( PlannerInfo root,
List groupClauses,
Path input_path,
double  dNumGroups,
double  dNumOutputRows,
const char *  construct 
)
static

Definition at line 924 of file prepunion.c.

References AGG_HASHED, compare_fractional_path_costs(), cost_agg(), cost_group(), cost_sort(), enable_hashagg, ereport, errcode(), errdetail(), errmsg(), ERROR, grouping_is_hashable(), grouping_is_sortable(), list_length(), MAXALIGN, NIL, Path::pathtarget, Path::rows, SizeofMinimalTupleHeader, Path::startup_cost, Path::total_cost, PlannerInfo::tuple_fraction, PathTarget::width, and work_mem.

Referenced by generate_nonunion_path(), and make_union_unique().

928 {
929  int numGroupCols = list_length(groupClauses);
930  bool can_sort;
931  bool can_hash;
932  Size hashentrysize;
933  Path hashed_p;
934  Path sorted_p;
935  double tuple_fraction;
936 
937  /* Check whether the operators support sorting or hashing */
938  can_sort = grouping_is_sortable(groupClauses);
939  can_hash = grouping_is_hashable(groupClauses);
940  if (can_hash && can_sort)
941  {
942  /* we have a meaningful choice to make, continue ... */
943  }
944  else if (can_hash)
945  return true;
946  else if (can_sort)
947  return false;
948  else
949  ereport(ERROR,
950  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
951  /* translator: %s is UNION, INTERSECT, or EXCEPT */
952  errmsg("could not implement %s", construct),
953  errdetail("Some of the datatypes only support hashing, while others only support sorting.")));
954 
955  /* Prefer sorting when enable_hashagg is off */
956  if (!enable_hashagg)
957  return false;
958 
959  /*
960  * Don't do it if it doesn't look like the hashtable will fit into
961  * work_mem.
962  */
963  hashentrysize = MAXALIGN(input_path->pathtarget->width) + MAXALIGN(SizeofMinimalTupleHeader);
964 
965  if (hashentrysize * dNumGroups > work_mem * 1024L)
966  return false;
967 
968  /*
969  * See if the estimated cost is no more than doing it the other way.
970  *
971  * We need to consider input_plan + hashagg versus input_plan + sort +
972  * group. Note that the actual result plan might involve a SetOp or
973  * Unique node, not Agg or Group, but the cost estimates for Agg and Group
974  * should be close enough for our purposes here.
975  *
976  * These path variables are dummies that just hold cost fields; we don't
977  * make actual Paths for these steps.
978  */
979  cost_agg(&hashed_p, root, AGG_HASHED, NULL,
980  numGroupCols, dNumGroups,
981  NIL,
982  input_path->startup_cost, input_path->total_cost,
983  input_path->rows);
984 
985  /*
986  * Now for the sorted case. Note that the input is *always* unsorted,
987  * since it was made by appending unrelated sub-relations together.
988  */
989  sorted_p.startup_cost = input_path->startup_cost;
990  sorted_p.total_cost = input_path->total_cost;
991  /* XXX cost_sort doesn't actually look at pathkeys, so just pass NIL */
992  cost_sort(&sorted_p, root, NIL, sorted_p.total_cost,
993  input_path->rows, input_path->pathtarget->width,
994  0.0, work_mem, -1.0);
995  cost_group(&sorted_p, root, numGroupCols, dNumGroups,
996  NIL,
997  sorted_p.startup_cost, sorted_p.total_cost,
998  input_path->rows);
999 
1000  /*
1001  * Now make the decision using the top-level tuple fraction. First we
1002  * have to convert an absolute count (LIMIT) into fractional form.
1003  */
1004  tuple_fraction = root->tuple_fraction;
1005  if (tuple_fraction >= 1.0)
1006  tuple_fraction /= dNumOutputRows;
1007 
1008  if (compare_fractional_path_costs(&hashed_p, &sorted_p,
1009  tuple_fraction) < 0)
1010  {
1011  /* Hashed is cheaper, so use it */
1012  return true;
1013  }
1014  return false;
1015 }
#define NIL
Definition: pg_list.h:69
PathTarget * pathtarget
Definition: relation.h:1043
void cost_agg(Path *path, PlannerInfo *root, AggStrategy aggstrategy, const AggClauseCosts *aggcosts, int numGroupCols, double numGroups, List *quals, Cost input_startup_cost, Cost input_total_cost, double input_tuples)
Definition: costsize.c:2038
int errcode(int sqlerrcode)
Definition: elog.c:575
bool grouping_is_hashable(List *groupClause)
Definition: tlist.c:538
double tuple_fraction
Definition: relation.h:294
#define ERROR
Definition: elog.h:43
Cost startup_cost
Definition: relation.h:1053
void cost_group(Path *path, PlannerInfo *root, int numGroupCols, double numGroups, List *quals, Cost input_startup_cost, Cost input_total_cost, double input_tuples)
Definition: costsize.c:2226
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ereport(elevel, rest)
Definition: elog.h:122
#define SizeofMinimalTupleHeader
Definition: htup_details.h:655
void cost_sort(Path *path, PlannerInfo *root, List *pathkeys, Cost input_cost, double tuples, int width, Cost comparison_cost, int sort_mem, double limit_tuples)
Definition: costsize.c:1648
int work_mem
Definition: globals.c:113
Cost total_cost
Definition: relation.h:1054
double rows
Definition: relation.h:1052
int compare_fractional_path_costs(Path *path1, Path *path2, double fraction)
Definition: pathnode.c:117
size_t Size
Definition: c.h:414
static int list_length(const List *l)
Definition: pg_list.h:89
#define MAXALIGN(LEN)
Definition: c.h:633
bool enable_hashagg
Definition: costsize.c:124
int width
Definition: relation.h:975
int errmsg(const char *fmt,...)
Definition: elog.c:797
bool grouping_is_sortable(List *groupClause)
Definition: tlist.c:518

◆ expand_inherited_rtentry()

static void expand_inherited_rtentry ( PlannerInfo root,
RangeTblEntry rte,
Index  rti 
)
static

Definition at line 1388 of file prepunion.c.

References AccessShareLock, PlannerInfo::append_rel_list, Assert, PartitionedChildRelInfo::child_rels, expand_partitioned_rtentry(), expand_single_inheritance_child(), find_all_inheritors(), get_plan_rowmark(), has_subclass(), heap_close, heap_open(), RangeTblEntry::inh, PlanRowMark::isParent, lappend(), lfirst_oid, list_concat(), list_length(), makeNode, PlanRowMark::markType, NIL, NoLock, PartitionedChildRelInfo::parent_relid, parse(), PlannerInfo::parse, PlannerInfo::pcinfo_list, RELATION_IS_OTHER_TEMP, RelationGetPartitionDesc, RangeTblEntry::relid, RangeTblEntry::relkind, RELKIND_PARTITIONED_TABLE, Query::resultRelation, RowExclusiveLock, RowMarkRequiresRowShareLock, PlannerInfo::rowMarks, RowShareLock, RTE_RELATION, RTE_SUBQUERY, and RangeTblEntry::rtekind.

Referenced by expand_inherited_tables().

1389 {
1390  Query *parse = root->parse;
1391  Oid parentOID;
1392  PlanRowMark *oldrc;
1393  Relation oldrelation;
1394  LOCKMODE lockmode;
1395  List *inhOIDs;
1396  ListCell *l;
1397 
1398  /* Does RT entry allow inheritance? */
1399  if (!rte->inh)
1400  return;
1401  /* Ignore any already-expanded UNION ALL nodes */
1402  if (rte->rtekind != RTE_RELATION)
1403  {
1404  Assert(rte->rtekind == RTE_SUBQUERY);
1405  return;
1406  }
1407  /* Fast path for common case of childless table */
1408  parentOID = rte->relid;
1409  if (!has_subclass(parentOID))
1410  {
1411  /* Clear flag before returning */
1412  rte->inh = false;
1413  return;
1414  }
1415 
1416  /*
1417  * The rewriter should already have obtained an appropriate lock on each
1418  * relation named in the query. However, for each child relation we add
1419  * to the query, we must obtain an appropriate lock, because this will be
1420  * the first use of those relations in the parse/rewrite/plan pipeline.
1421  *
1422  * If the parent relation is the query's result relation, then we need
1423  * RowExclusiveLock. Otherwise, if it's accessed FOR UPDATE/SHARE, we
1424  * need RowShareLock; otherwise AccessShareLock. We can't just grab
1425  * AccessShareLock because then the executor would be trying to upgrade
1426  * the lock, leading to possible deadlocks. (This code should match the
1427  * parser and rewriter.)
1428  */
1429  oldrc = get_plan_rowmark(root->rowMarks, rti);
1430  if (rti == parse->resultRelation)
1431  lockmode = RowExclusiveLock;
1432  else if (oldrc && RowMarkRequiresRowShareLock(oldrc->markType))
1433  lockmode = RowShareLock;
1434  else
1435  lockmode = AccessShareLock;
1436 
1437  /* Scan for all members of inheritance set, acquire needed locks */
1438  inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
1439 
1440  /*
1441  * Check that there's at least one descendant, else treat as no-child
1442  * case. This could happen despite above has_subclass() check, if table
1443  * once had a child but no longer does.
1444  */
1445  if (list_length(inhOIDs) < 2)
1446  {
1447  /* Clear flag before returning */
1448  rte->inh = false;
1449  return;
1450  }
1451 
1452  /*
1453  * If parent relation is selected FOR UPDATE/SHARE, we need to mark its
1454  * PlanRowMark as isParent = true, and generate a new PlanRowMark for each
1455  * child.
1456  */
1457  if (oldrc)
1458  oldrc->isParent = true;
1459 
1460  /*
1461  * Must open the parent relation to examine its tupdesc. We need not lock
1462  * it; we assume the rewriter already did.
1463  */
1464  oldrelation = heap_open(parentOID, NoLock);
1465 
1466  /* Scan the inheritance set and expand it */
1467  if (RelationGetPartitionDesc(oldrelation) != NULL)
1468  {
1469  List *partitioned_child_rels = NIL;
1470 
1472 
1473  /*
1474  * If this table has partitions, recursively expand them in the order
1475  * in which they appear in the PartitionDesc.
1476  */
1477  expand_partitioned_rtentry(root, rte, rti, oldrelation, oldrc,
1478  lockmode, &root->append_rel_list,
1479  &partitioned_child_rels);
1480 
1481  /*
1482  * We keep a list of objects in root, each of which maps a root
1483  * partitioned parent RT index to the list of RT indexes of descendant
1484  * partitioned child tables. When creating an Append or a ModifyTable
1485  * path for the parent, we copy the child RT index list verbatim to
1486  * the path so that it could be carried over to the executor so that
1487  * the latter could identify the partitioned child tables.
1488  */
1489  if (rte->inh && partitioned_child_rels != NIL)
1490  {
1491  PartitionedChildRelInfo *pcinfo;
1492 
1494  pcinfo->parent_relid = rti;
1495  pcinfo->child_rels = partitioned_child_rels;
1496  root->pcinfo_list = lappend(root->pcinfo_list, pcinfo);
1497  }
1498  }
1499  else
1500  {
1501  List *appinfos = NIL;
1502  RangeTblEntry *childrte;
1503  Index childRTindex;
1504 
1505  /*
1506  * This table has no partitions. Expand any plain inheritance
1507  * children in the order the OIDs were returned by
1508  * find_all_inheritors.
1509  */
1510  foreach(l, inhOIDs)
1511  {
1512  Oid childOID = lfirst_oid(l);
1513  Relation newrelation;
1514 
1515  /* Open rel if needed; we already have required locks */
1516  if (childOID != parentOID)
1517  newrelation = heap_open(childOID, NoLock);
1518  else
1519  newrelation = oldrelation;
1520 
1521  /*
1522  * It is possible that the parent table has children that are temp
1523  * tables of other backends. We cannot safely access such tables
1524  * (because of buffering issues), and the best thing to do seems
1525  * to be to silently ignore them.
1526  */
1527  if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
1528  {
1529  heap_close(newrelation, lockmode);
1530  continue;
1531  }
1532 
1533  expand_single_inheritance_child(root, rte, rti, oldrelation, oldrc,
1534  newrelation,
1535  &appinfos, &childrte,
1536  &childRTindex);
1537 
1538  /* Close child relations, but keep locks */
1539  if (childOID != parentOID)
1540  heap_close(newrelation, NoLock);
1541  }
1542 
1543  /*
1544  * If all the children were temp tables, pretend it's a
1545  * non-inheritance situation; we don't need Append node in that case.
1546  * The duplicate RTE we added for the parent table is harmless, so we
1547  * don't bother to get rid of it; ditto for the useless PlanRowMark
1548  * node.
1549  */
1550  if (list_length(appinfos) < 2)
1551  rte->inh = false;
1552  else
1554  appinfos);
1555 
1556  }
1557 
1558  heap_close(oldrelation, NoLock);
1559 }
#define NIL
Definition: pg_list.h:69
List * rowMarks
Definition: relation.h:256
Query * parse
Definition: relation.h:155
static void expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte, Index parentRTindex, Relation parentrel, PlanRowMark *top_parentrc, LOCKMODE lockmode, List **appinfos, List **partitioned_child_rels)
Definition: prepunion.c:1569
RowMarkType markType
Definition: plannodes.h:1021
int LOCKMODE
Definition: lockdefs.h:26
int resultRelation
Definition: parsenodes.h:120
#define AccessShareLock
Definition: lockdefs.h:36
List * list_concat(List *list1, List *list2)
Definition: list.c:321
static void expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, Index parentRTindex, Relation parentrel, PlanRowMark *top_parentrc, Relation childrel, List **appinfos, RangeTblEntry **childrte_p, Index *childRTindex_p)
Definition: prepunion.c:1666
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
#define RowMarkRequiresRowShareLock(marktype)
Definition: plannodes.h:974
bool has_subclass(Oid relationId)
Definition: pg_inherits.c:262
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
List * lappend(List *list, void *datum)
Definition: list.c:128
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define RowShareLock
Definition: lockdefs.h:37
List * append_rel_list
Definition: relation.h:252
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
unsigned int Index
Definition: c.h:423
#define makeNode(_type_)
Definition: nodes.h:560
#define Assert(condition)
Definition: c.h:680
List * pcinfo_list
Definition: relation.h:254
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:542
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:951
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:167
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition: preptlist.c:424
bool isParent
Definition: plannodes.h:1025
Definition: pg_list.h:45
#define lfirst_oid(lc)
Definition: pg_list.h:108
#define RelationGetPartitionDesc(relation)
Definition: rel.h:641
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:649

◆ expand_inherited_tables()

void expand_inherited_tables ( PlannerInfo root)

Definition at line 1345 of file prepunion.c.

References expand_inherited_rtentry(), lfirst, list_head(), list_length(), lnext, PlannerInfo::parse, and Query::rtable.

Referenced by subquery_planner().

1346 {
1347  Index nrtes;
1348  Index rti;
1349  ListCell *rl;
1350 
1351  /*
1352  * expand_inherited_rtentry may add RTEs to parse->rtable. The function is
1353  * expected to recursively handle any RTEs that it creates with inh=true.
1354  * So just scan as far as the original end of the rtable list.
1355  */
1356  nrtes = list_length(root->parse->rtable);
1357  rl = list_head(root->parse->rtable);
1358  for (rti = 1; rti <= nrtes; rti++)
1359  {
1360  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);
1361 
1362  expand_inherited_rtentry(root, rte, rti);
1363  rl = lnext(rl);
1364  }
1365 }
Query * parse
Definition: relation.h:155
List * rtable
Definition: parsenodes.h:135
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
static void expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
Definition: prepunion.c:1388
unsigned int Index
Definition: c.h:423
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89

◆ expand_partitioned_rtentry()

static void expand_partitioned_rtentry ( PlannerInfo root,
RangeTblEntry parentrte,
Index  parentRTindex,
Relation  parentrel,
PlanRowMark top_parentrc,
LOCKMODE  lockmode,
List **  appinfos,
List **  partitioned_child_rels 
)
static

Definition at line 1569 of file prepunion.c.

References Assert, check_stack_depth(), expand_single_inheritance_child(), heap_close, heap_open(), i, RangeTblEntry::inh, lappend_int(), NoLock, PartitionDescData::nparts, PartitionDescData::oids, RelationData::rd_rel, RELATION_IS_OTHER_TEMP, RelationGetPartitionDesc, and RELKIND_PARTITIONED_TABLE.

Referenced by expand_inherited_rtentry().

1573 {
1574  int i;
1575  RangeTblEntry *childrte;
1576  Index childRTindex;
1577  bool has_child = false;
1578  PartitionDesc partdesc = RelationGetPartitionDesc(parentrel);
1579 
1581 
1582  /* A partitioned table should always have a partition descriptor. */
1583  Assert(partdesc);
1584 
1585  Assert(parentrte->inh);
1586 
1587  /* First expand the partitioned table itself. */
1588  expand_single_inheritance_child(root, parentrte, parentRTindex, parentrel,
1589  top_parentrc, parentrel,
1590  appinfos, &childrte, &childRTindex);
1591 
1592  /*
1593  * The partitioned table does not have data for itself but still need to
1594  * be locked. Update given list of partitioned children with RTI of this
1595  * partitioned relation.
1596  */
1597  *partitioned_child_rels = lappend_int(*partitioned_child_rels,
1598  childRTindex);
1599 
1600  for (i = 0; i < partdesc->nparts; i++)
1601  {
1602  Oid childOID = partdesc->oids[i];
1603  Relation childrel;
1604 
1605  /* Open rel; we already have required locks */
1606  childrel = heap_open(childOID, NoLock);
1607 
1608  /* As in expand_inherited_rtentry, skip non-local temp tables */
1609  if (RELATION_IS_OTHER_TEMP(childrel))
1610  {
1611  heap_close(childrel, lockmode);
1612  continue;
1613  }
1614 
1615  /* We have a real partition. */
1616  has_child = true;
1617 
1618  expand_single_inheritance_child(root, parentrte, parentRTindex,
1619  parentrel, top_parentrc, childrel,
1620  appinfos, &childrte, &childRTindex);
1621 
1622  /* If this child is itself partitioned, recurse */
1623  if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1624  expand_partitioned_rtentry(root, childrte, childRTindex,
1625  childrel, top_parentrc, lockmode,
1626  appinfos, partitioned_child_rels);
1627 
1628  /* Close child relation, but keep locks */
1629  heap_close(childrel, NoLock);
1630  }
1631 
1632  /*
1633  * If the partitioned table has no partitions or all the partitions are
1634  * temporary tables from other backends, treat this as non-inheritance
1635  * case.
1636  */
1637  if (!has_child)
1638  parentrte->inh = false;
1639 }
static void expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte, Index parentRTindex, Relation parentrel, PlanRowMark *top_parentrc, LOCKMODE lockmode, List **appinfos, List **partitioned_child_rels)
Definition: prepunion.c:1569
static void expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte, Index parentRTindex, Relation parentrel, PlanRowMark *top_parentrc, Relation childrel, List **appinfos, RangeTblEntry **childrte_p, Index *childRTindex_p)
Definition: prepunion.c:1666
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
#define NoLock
Definition: lockdefs.h:34
void check_stack_depth(void)
Definition: postgres.c:3150
List * lappend_int(List *list, int datum)
Definition: list.c:146
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
unsigned int Index
Definition: c.h:423
#define Assert(condition)
Definition: c.h:680
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:542
int i
#define RelationGetPartitionDesc(relation)
Definition: rel.h:641

◆ expand_single_inheritance_child()

static void expand_single_inheritance_child ( PlannerInfo root,
RangeTblEntry parentrte,
Index  parentRTindex,
Relation  parentrel,
PlanRowMark top_parentrc,
Relation  childrel,
List **  appinfos,
RangeTblEntry **  childrte_p,
Index childRTindex_p 
)
static

Definition at line 1666 of file prepunion.c.

References PlanRowMark::allMarkTypes, AppendRelInfo::child_relid, AppendRelInfo::child_reltype, copyObject, RangeTblEntry::inh, RangeTblEntry::insertedCols, PlanRowMark::isParent, lappend(), list_length(), make_inh_translation_list(), makeNode, PlanRowMark::markType, NIL, AppendRelInfo::parent_relid, AppendRelInfo::parent_reloid, AppendRelInfo::parent_reltype, parse(), PlannerInfo::parse, PlanRowMark::prti, RelationData::rd_rel, RelationGetRelid, RangeTblEntry::relid, RangeTblEntry::relkind, RELKIND_PARTITIONED_TABLE, RangeTblEntry::requiredPerms, PlanRowMark::rowmarkId, PlannerInfo::rowMarks, Query::rtable, PlanRowMark::rti, RangeTblEntry::securityQuals, select_rowmark_type(), RangeTblEntry::selectedCols, PlanRowMark::strength, translate_col_privs(), AppendRelInfo::translated_vars, RangeTblEntry::updatedCols, and PlanRowMark::waitPolicy.

Referenced by expand_inherited_rtentry(), and expand_partitioned_rtentry().

1671 {
1672  Query *parse = root->parse;
1673  Oid parentOID = RelationGetRelid(parentrel);
1674  Oid childOID = RelationGetRelid(childrel);
1675  RangeTblEntry *childrte;
1676  Index childRTindex;
1677  AppendRelInfo *appinfo;
1678 
1679  /*
1680  * Build an RTE for the child, and attach to query's rangetable list. We
1681  * copy most fields of the parent's RTE, but replace relation OID and
1682  * relkind, and set inh = false. Also, set requiredPerms to zero since
1683  * all required permissions checks are done on the original RTE. Likewise,
1684  * set the child's securityQuals to empty, because we only want to apply
1685  * the parent's RLS conditions regardless of what RLS properties
1686  * individual children may have. (This is an intentional choice to make
1687  * inherited RLS work like regular permissions checks.) The parent
1688  * securityQuals will be propagated to children along with other base
1689  * restriction clauses, so we don't need to do it here.
1690  */
1691  childrte = copyObject(parentrte);
1692  *childrte_p = childrte;
1693  childrte->relid = childOID;
1694  childrte->relkind = childrel->rd_rel->relkind;
1695  /* A partitioned child will need to be expanded further. */
1696  if (childOID != parentOID &&
1697  childrte->relkind == RELKIND_PARTITIONED_TABLE)
1698  childrte->inh = true;
1699  else
1700  childrte->inh = false;
1701  childrte->requiredPerms = 0;
1702  childrte->securityQuals = NIL;
1703  parse->rtable = lappend(parse->rtable, childrte);
1704  childRTindex = list_length(parse->rtable);
1705  *childRTindex_p = childRTindex;
1706 
1707  /*
1708  * We need an AppendRelInfo if paths will be built for the child RTE. If
1709  * childrte->inh is true, then we'll always need to generate append paths
1710  * for it. If childrte->inh is false, we must scan it if it's not a
1711  * partitioned table; but if it is a partitioned table, then it never has
1712  * any data of its own and need not be scanned.
1713  */
1714  if (childrte->relkind != RELKIND_PARTITIONED_TABLE || childrte->inh)
1715  {
1716  appinfo = makeNode(AppendRelInfo);
1717  appinfo->parent_relid = parentRTindex;
1718  appinfo->child_relid = childRTindex;
1719  appinfo->parent_reltype = parentrel->rd_rel->reltype;
1720  appinfo->child_reltype = childrel->rd_rel->reltype;
1721  make_inh_translation_list(parentrel, childrel, childRTindex,
1722  &appinfo->translated_vars);
1723  appinfo->parent_reloid = parentOID;
1724  *appinfos = lappend(*appinfos, appinfo);
1725 
1726  /*
1727  * Translate the column permissions bitmaps to the child's attnums (we
1728  * have to build the translated_vars list before we can do this). But
1729  * if this is the parent table, leave copyObject's result alone.
1730  *
1731  * Note: we need to do this even though the executor won't run any
1732  * permissions checks on the child RTE. The insertedCols/updatedCols
1733  * bitmaps may be examined for trigger-firing purposes.
1734  */
1735  if (childOID != parentOID)
1736  {
1737  childrte->selectedCols = translate_col_privs(parentrte->selectedCols,
1738  appinfo->translated_vars);
1739  childrte->insertedCols = translate_col_privs(parentrte->insertedCols,
1740  appinfo->translated_vars);
1741  childrte->updatedCols = translate_col_privs(parentrte->updatedCols,
1742  appinfo->translated_vars);
1743  }
1744  }
1745 
1746  /*
1747  * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
1748  */
1749  if (top_parentrc)
1750  {
1751  PlanRowMark *childrc = makeNode(PlanRowMark);
1752 
1753  childrc->rti = childRTindex;
1754  childrc->prti = top_parentrc->rti;
1755  childrc->rowmarkId = top_parentrc->rowmarkId;
1756  /* Reselect rowmark type, because relkind might not match parent */
1757  childrc->markType = select_rowmark_type(childrte,
1758  top_parentrc->strength);
1759  childrc->allMarkTypes = (1 << childrc->markType);
1760  childrc->strength = top_parentrc->strength;
1761  childrc->waitPolicy = top_parentrc->waitPolicy;
1762 
1763  /*
1764  * We mark RowMarks for partitioned child tables as parent RowMarks so
1765  * that the executor ignores them (except their existence means that
1766  * the child tables be locked using appropriate mode).
1767  */
1768  childrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
1769 
1770  /* Include child's rowmark type in top parent's allMarkTypes */
1771  top_parentrc->allMarkTypes |= childrc->allMarkTypes;
1772 
1773  root->rowMarks = lappend(root->rowMarks, childrc);
1774  }
1775 }
#define NIL
Definition: pg_list.h:69
List * rowMarks
Definition: relation.h:256
Query * parse
Definition: relation.h:155
RowMarkType markType
Definition: plannodes.h:1021
RowMarkType select_rowmark_type(RangeTblEntry *rte, LockClauseStrength strength)
Definition: planner.c:2519
List * securityQuals
Definition: parsenodes.h:1064
Index prti
Definition: plannodes.h:1019
static Bitmapset * translate_col_privs(const Bitmapset *parent_privs, List *translated_vars)
Definition: prepunion.c:1892
AclMode requiredPerms
Definition: parsenodes.h:1059
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
Index rowmarkId
Definition: plannodes.h:1020
LockWaitPolicy waitPolicy
Definition: plannodes.h:1024
List * translated_vars
Definition: relation.h:2099
Oid parent_reltype
Definition: relation.h:2080
Bitmapset * selectedCols
Definition: parsenodes.h:1061
List * rtable
Definition: parsenodes.h:135
int allMarkTypes
Definition: plannodes.h:1022
List * lappend(List *list, void *datum)
Definition: list.c:128
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
unsigned int Index
Definition: c.h:423
Bitmapset * updatedCols
Definition: parsenodes.h:1063
#define makeNode(_type_)
Definition: nodes.h:560
LockClauseStrength strength
Definition: plannodes.h:1023
static int list_length(const List *l)
Definition: pg_list.h:89
Oid child_reltype
Definition: relation.h:2081
static void make_inh_translation_list(Relation oldrelation, Relation newrelation, Index newvarno, List **translated_vars)
Definition: prepunion.c:1785
Bitmapset * insertedCols
Definition: parsenodes.h:1062
bool isParent
Definition: plannodes.h:1025
Index child_relid
Definition: relation.h:2072
Oid parent_reloid
Definition: relation.h:2106
#define copyObject(obj)
Definition: nodes.h:625
Index parent_relid
Definition: relation.h:2071
#define RelationGetRelid(relation)
Definition: rel.h:425
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:649

◆ find_appinfos_by_relids()

AppendRelInfo** find_appinfos_by_relids ( PlannerInfo root,
Relids  relids,
int *  nappinfos 
)

Definition at line 2517 of file prepunion.c.

References PlannerInfo::append_rel_list, bms_is_member(), bms_num_members(), AppendRelInfo::child_relid, elog, ERROR, lfirst, and palloc().

Referenced by add_placeholders_to_child_joinrel(), adjust_appendrel_attrs_multilevel(), adjust_child_relids_multilevel(), build_child_join_rel(), build_child_join_sjinfo(), and try_partition_wise_join().

2518 {
2519  ListCell *lc;
2520  AppendRelInfo **appinfos;
2521  int cnt = 0;
2522 
2523  *nappinfos = bms_num_members(relids);
2524  appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * *nappinfos);
2525 
2526  foreach(lc, root->append_rel_list)
2527  {
2528  AppendRelInfo *appinfo = lfirst(lc);
2529 
2530  if (bms_is_member(appinfo->child_relid, relids))
2531  {
2532  appinfos[cnt] = appinfo;
2533  cnt++;
2534 
2535  /* Stop when we have gathered all the AppendRelInfos. */
2536  if (cnt == *nappinfos)
2537  return appinfos;
2538  }
2539  }
2540 
2541  /* Should have found the entries ... */
2542  elog(ERROR, "did not find all requested child rels in append_rel_list");
2543  return NULL; /* not reached */
2544 }
#define ERROR
Definition: elog.h:43
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:605
List * append_rel_list
Definition: relation.h:252
#define lfirst(lc)
Definition: pg_list.h:106
void * palloc(Size size)
Definition: mcxt.c:835
#define elog
Definition: elog.h:219
Index child_relid
Definition: relation.h:2072
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420

◆ generate_append_tlist()

static List * generate_append_tlist ( List colTypes,
List colCollations,
bool  flag,
List input_tlists,
List refnames_tlist 
)
static

Definition at line 1174 of file prepunion.c.

References Assert, TargetEntry::expr, exprType(), exprTypmod(), forthree, INT4OID, InvalidOid, lappend(), lfirst, lfirst_oid, list_head(), list_length(), lnext, makeTargetEntry(), makeVar(), NIL, palloc(), pfree(), pstrdup(), TargetEntry::resjunk, TargetEntry::resname, TargetEntry::resno, and TargetEntry::ressortgroupref.

Referenced by generate_nonunion_path(), generate_recursion_path(), and generate_union_path().

1178 {
1179  List *tlist = NIL;
1180  int resno = 1;
1181  ListCell *curColType;
1182  ListCell *curColCollation;
1183  ListCell *ref_tl_item;
1184  int colindex;
1185  TargetEntry *tle;
1186  Node *expr;
1187  ListCell *tlistl;
1188  int32 *colTypmods;
1189 
1190  /*
1191  * First extract typmods to use.
1192  *
1193  * If the inputs all agree on type and typmod of a particular column, use
1194  * that typmod; else use -1.
1195  */
1196  colTypmods = (int32 *) palloc(list_length(colTypes) * sizeof(int32));
1197 
1198  foreach(tlistl, input_tlists)
1199  {
1200  List *subtlist = (List *) lfirst(tlistl);
1201  ListCell *subtlistl;
1202 
1203  curColType = list_head(colTypes);
1204  colindex = 0;
1205  foreach(subtlistl, subtlist)
1206  {
1207  TargetEntry *subtle = (TargetEntry *) lfirst(subtlistl);
1208 
1209  if (subtle->resjunk)
1210  continue;
1211  Assert(curColType != NULL);
1212  if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))
1213  {
1214  /* If first subplan, copy the typmod; else compare */
1215  int32 subtypmod = exprTypmod((Node *) subtle->expr);
1216 
1217  if (tlistl == list_head(input_tlists))
1218  colTypmods[colindex] = subtypmod;
1219  else if (subtypmod != colTypmods[colindex])
1220  colTypmods[colindex] = -1;
1221  }
1222  else
1223  {
1224  /* types disagree, so force typmod to -1 */
1225  colTypmods[colindex] = -1;
1226  }
1227  curColType = lnext(curColType);
1228  colindex++;
1229  }
1230  Assert(curColType == NULL);
1231  }
1232 
1233  /*
1234  * Now we can build the tlist for the Append.
1235  */
1236  colindex = 0;
1237  forthree(curColType, colTypes, curColCollation, colCollations,
1238  ref_tl_item, refnames_tlist)
1239  {
1240  Oid colType = lfirst_oid(curColType);
1241  int32 colTypmod = colTypmods[colindex++];
1242  Oid colColl = lfirst_oid(curColCollation);
1243  TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);
1244 
1245  Assert(reftle->resno == resno);
1246  Assert(!reftle->resjunk);
1247  expr = (Node *) makeVar(0,
1248  resno,
1249  colType,
1250  colTypmod,
1251  colColl,
1252  0);
1253  tle = makeTargetEntry((Expr *) expr,
1254  (AttrNumber) resno++,
1255  pstrdup(reftle->resname),
1256  false);
1257 
1258  /*
1259  * By convention, all non-resjunk columns in a setop tree have
1260  * ressortgroupref equal to their resno. In some cases the ref isn't
1261  * needed, but this is a cleaner way than modifying the tlist later.
1262  */
1263  tle->ressortgroupref = tle->resno;
1264 
1265  tlist = lappend(tlist, tle);
1266  }
1267 
1268  if (flag)
1269  {
1270  /* Add a resjunk flag column */
1271  /* flag value is shown as copied up from subplan */
1272  expr = (Node *) makeVar(0,
1273  resno,
1274  INT4OID,
1275  -1,
1276  InvalidOid,
1277  0);
1278  tle = makeTargetEntry((Expr *) expr,
1279  (AttrNumber) resno++,
1280  pstrdup("flag"),
1281  true);
1282  tlist = lappend(tlist, tle);
1283  }
1284 
1285  pfree(colTypmods);
1286 
1287  return tlist;
1288 }
#define NIL
Definition: pg_list.h:69
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:276
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition: pg_list.h:203
char * pstrdup(const char *in)
Definition: mcxt.c:1063
#define INT4OID
Definition: pg_type.h:316
Definition: nodes.h:512
unsigned int Oid
Definition: postgres_ext.h:31
char * resname
Definition: primnodes.h:1377
signed int int32
Definition: c.h:294
void pfree(void *pointer)
Definition: mcxt.c:936
bool resjunk
Definition: primnodes.h:1382
char * flag(int b)
Definition: test-ctype.c:33
AttrNumber resno
Definition: primnodes.h:1376
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:237
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
List * lappend(List *list, void *datum)
Definition: list.c:128
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:680
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1375
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
static int list_length(const List *l)
Definition: pg_list.h:89
void * palloc(Size size)
Definition: mcxt.c:835
Index ressortgroupref
Definition: primnodes.h:1378
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ generate_nonunion_path()

static Path * generate_nonunion_path ( SetOperationStmt op,
PlannerInfo root,
List refnames_tlist,
List **  pTargetList,
double *  pNumGroups 
)
static

Definition at line 623 of file prepunion.c.

References SetOperationStmt::all, choose_hashed_setop(), SetOperationStmt::colCollations, SetOperationStmt::colTypes, create_append_path(), create_pathtarget, create_setop_path(), create_sort_path(), elog, ERROR, fetch_upper_rel(), generate_append_tlist(), generate_setop_grouplist(), SetOperationStmt::larg, list_length(), list_make2, make_pathkeys_for_sortclauses(), Min, NIL, SetOperationStmt::op, Path::pathtarget, SetOperationStmt::rarg, recurse_set_operations(), Path::rows, SETOP_EXCEPT, SETOP_HASHED, SETOP_INTERSECT, SETOP_SORTED, SETOPCMD_EXCEPT, SETOPCMD_EXCEPT_ALL, SETOPCMD_INTERSECT, SETOPCMD_INTERSECT_ALL, PlannerInfo::tuple_fraction, and UPPERREL_SETOP.

Referenced by recurse_set_operations().

627 {
628  RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
629  double save_fraction = root->tuple_fraction;
630  Path *lpath,
631  *rpath,
632  *path;
633  List *lpath_tlist,
634  *rpath_tlist,
635  *tlist_list,
636  *tlist,
637  *groupList,
638  *pathlist;
639  double dLeftGroups,
640  dRightGroups,
641  dNumGroups,
642  dNumOutputRows;
643  bool use_hash;
644  SetOpCmd cmd;
645  int firstFlag;
646 
647  /*
648  * Tell children to fetch all tuples.
649  */
650  root->tuple_fraction = 0.0;
651 
652  /* Recurse on children, ensuring their outputs are marked */
653  lpath = recurse_set_operations(op->larg, root,
654  op->colTypes, op->colCollations,
655  false, 0,
656  refnames_tlist,
657  &lpath_tlist,
658  &dLeftGroups);
659  rpath = recurse_set_operations(op->rarg, root,
660  op->colTypes, op->colCollations,
661  false, 1,
662  refnames_tlist,
663  &rpath_tlist,
664  &dRightGroups);
665 
666  /* Undo effects of forcing tuple_fraction to 0 */
667  root->tuple_fraction = save_fraction;
668 
669  /*
670  * For EXCEPT, we must put the left input first. For INTERSECT, either
671  * order should give the same results, and we prefer to put the smaller
672  * input first in order to minimize the size of the hash table in the
673  * hashing case. "Smaller" means the one with the fewer groups.
674  */
675  if (op->op == SETOP_EXCEPT || dLeftGroups <= dRightGroups)
676  {
677  pathlist = list_make2(lpath, rpath);
678  tlist_list = list_make2(lpath_tlist, rpath_tlist);
679  firstFlag = 0;
680  }
681  else
682  {
683  pathlist = list_make2(rpath, lpath);
684  tlist_list = list_make2(rpath_tlist, lpath_tlist);
685  firstFlag = 1;
686  }
687 
688  /*
689  * Generate tlist for Append plan node.
690  *
691  * The tlist for an Append plan isn't important as far as the Append is
692  * concerned, but we must make it look real anyway for the benefit of the
693  * next plan level up. In fact, it has to be real enough that the flag
694  * column is shown as a variable not a constant, else setrefs.c will get
695  * confused.
696  */
697  tlist = generate_append_tlist(op->colTypes, op->colCollations, true,
698  tlist_list, refnames_tlist);
699 
700  *pTargetList = tlist;
701 
702  /*
703  * Append the child results together.
704  */
705  path = (Path *) create_append_path(result_rel, pathlist, NIL,
706  NULL, 0, false, NIL, -1);
707 
708  /* We have to manually jam the right tlist into the path; ick */
709  path->pathtarget = create_pathtarget(root, tlist);
710 
711  /* Identify the grouping semantics */
712  groupList = generate_setop_grouplist(op, tlist);
713 
714  /* punt if nothing to group on (can this happen?) */
715  if (groupList == NIL)
716  return path;
717 
718  /*
719  * Estimate number of distinct groups that we'll need hashtable entries
720  * for; this is the size of the left-hand input for EXCEPT, or the smaller
721  * input for INTERSECT. Also estimate the number of eventual output rows.
722  * In non-ALL cases, we estimate each group produces one output row; in
723  * ALL cases use the relevant relation size. These are worst-case
724  * estimates, of course, but we need to be conservative.
725  */
726  if (op->op == SETOP_EXCEPT)
727  {
728  dNumGroups = dLeftGroups;
729  dNumOutputRows = op->all ? lpath->rows : dNumGroups;
730  }
731  else
732  {
733  dNumGroups = Min(dLeftGroups, dRightGroups);
734  dNumOutputRows = op->all ? Min(lpath->rows, rpath->rows) : dNumGroups;
735  }
736 
737  /*
738  * Decide whether to hash or sort, and add a sort node if needed.
739  */
740  use_hash = choose_hashed_setop(root, groupList, path,
741  dNumGroups, dNumOutputRows,
742  (op->op == SETOP_INTERSECT) ? "INTERSECT" : "EXCEPT");
743 
744  if (!use_hash)
745  path = (Path *) create_sort_path(root,
746  result_rel,
747  path,
749  groupList,
750  tlist),
751  -1.0);
752 
753  /*
754  * Finally, add a SetOp path node to generate the correct output.
755  */
756  switch (op->op)
757  {
758  case SETOP_INTERSECT:
760  break;
761  case SETOP_EXCEPT:
763  break;
764  default:
765  elog(ERROR, "unrecognized set op: %d", (int) op->op);
766  cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */
767  break;
768  }
769  path = (Path *) create_setop_path(root,
770  result_rel,
771  path,
772  cmd,
773  use_hash ? SETOP_HASHED : SETOP_SORTED,
774  groupList,
775  list_length(op->colTypes) + 1,
776  use_hash ? firstFlag : -1,
777  dNumGroups,
778  dNumOutputRows);
779 
780  if (pNumGroups)
781  *pNumGroups = dNumGroups;
782 
783  return path;
784 }
#define list_make2(x1, x2)
Definition: pg_list.h:140
#define NIL
Definition: pg_list.h:69
static List * generate_append_tlist(List *colTypes, List *colCollations, bool flag, List *input_tlists, List *refnames_tlist)
Definition: prepunion.c:1174
PathTarget * pathtarget
Definition: relation.h:1043
SetOpPath * create_setop_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, SetOpCmd cmd, SetOpStrategy strategy, List *distinctList, AttrNumber flagColIdx, int firstFlag, double numGroups, double outputRows)
Definition: pathnode.c:3112
List * make_pathkeys_for_sortclauses(PlannerInfo *root, List *sortclauses, List *tlist)
Definition: pathkeys.c:865
static List * generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
Definition: prepunion.c:1302
#define Min(x, y)
Definition: c.h:812
static bool choose_hashed_setop(PlannerInfo *root, List *groupClauses, Path *input_path, double dNumGroups, double dNumOutputRows, const char *construct)
Definition: prepunion.c:924
double tuple_fraction
Definition: relation.h:294
#define ERROR
Definition: elog.h:43
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1137
#define create_pathtarget(root, tlist)
Definition: tlist.h:69
static Path * recurse_set_operations(Node *setOp, PlannerInfo *root, List *colTypes, List *colCollations, bool junkOK, int flag, List *refnames_tlist, List **pTargetList, double *pNumGroups)
Definition: prepunion.c:262
List * colCollations
Definition: parsenodes.h:1589
SortPath * create_sort_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, double limit_tuples)
Definition: pathnode.c:2598
double rows
Definition: relation.h:1052
AppendPath * create_append_path(RelOptInfo *rel, List *subpaths, List *partial_subpaths, Relids required_outer, int parallel_workers, bool parallel_aware, List *partitioned_rels, double rows)
Definition: pathnode.c:1213
static int list_length(const List *l)
Definition: pg_list.h:89
SetOperation op
Definition: parsenodes.h:1580
SetOpCmd
Definition: nodes.h:782
#define elog
Definition: elog.h:219
Definition: pg_list.h:45

◆ generate_recursion_path()

static Path * generate_recursion_path ( SetOperationStmt setOp,
PlannerInfo root,
List refnames_tlist,
List **  pTargetList 
)
static

Definition at line 441 of file prepunion.c.

References SetOperationStmt::all, Assert, SetOperationStmt::colCollations, SetOperationStmt::colTypes, create_pathtarget, create_recursiveunion_path(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, fetch_upper_rel(), generate_append_tlist(), generate_setop_grouplist(), grouping_is_hashable(), SetOperationStmt::larg, list_make2, NIL, PlannerInfo::non_recursive_path, SetOperationStmt::op, SetOperationStmt::rarg, recurse_set_operations(), Path::rows, SETOP_UNION, UPPERREL_SETOP, and PlannerInfo::wt_param_id.

Referenced by plan_set_operations().

444 {
445  RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
446  Path *path;
447  Path *lpath;
448  Path *rpath;
449  List *lpath_tlist;
450  List *rpath_tlist;
451  List *tlist;
452  List *groupList;
453  double dNumGroups;
454 
455  /* Parser should have rejected other cases */
456  if (setOp->op != SETOP_UNION)
457  elog(ERROR, "only UNION queries can be recursive");
458  /* Worktable ID should be assigned */
459  Assert(root->wt_param_id >= 0);
460 
461  /*
462  * Unlike a regular UNION node, process the left and right inputs
463  * separately without any intention of combining them into one Append.
464  */
465  lpath = recurse_set_operations(setOp->larg, root,
466  setOp->colTypes, setOp->colCollations,
467  false, -1,
468  refnames_tlist,
469  &lpath_tlist,
470  NULL);
471  /* The right path will want to look at the left one ... */
472  root->non_recursive_path = lpath;
473  rpath = recurse_set_operations(setOp->rarg, root,
474  setOp->colTypes, setOp->colCollations,
475  false, -1,
476  refnames_tlist,
477  &rpath_tlist,
478  NULL);
479  root->non_recursive_path = NULL;
480 
481  /*
482  * Generate tlist for RecursiveUnion path node --- same as in Append cases
483  */
484  tlist = generate_append_tlist(setOp->colTypes, setOp->colCollations, false,
485  list_make2(lpath_tlist, rpath_tlist),
486  refnames_tlist);
487 
488  *pTargetList = tlist;
489 
490  /*
491  * If UNION, identify the grouping operators
492  */
493  if (setOp->all)
494  {
495  groupList = NIL;
496  dNumGroups = 0;
497  }
498  else
499  {
500  /* Identify the grouping semantics */
501  groupList = generate_setop_grouplist(setOp, tlist);
502 
503  /* We only support hashing here */
504  if (!grouping_is_hashable(groupList))
505  ereport(ERROR,
506  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
507  errmsg("could not implement recursive UNION"),
508  errdetail("All column datatypes must be hashable.")));
509 
510  /*
511  * For the moment, take the number of distinct groups as equal to the
512  * total input size, ie, the worst case.
513  */
514  dNumGroups = lpath->rows + rpath->rows * 10;
515  }
516 
517  /*
518  * And make the path node.
519  */
520  path = (Path *) create_recursiveunion_path(root,
521  result_rel,
522  lpath,
523  rpath,
524  create_pathtarget(root, tlist),
525  groupList,
526  root->wt_param_id,
527  dNumGroups);
528 
529  return path;
530 }
#define list_make2(x1, x2)
Definition: pg_list.h:140
#define NIL
Definition: pg_list.h:69
static List * generate_append_tlist(List *colTypes, List *colCollations, bool flag, List *input_tlists, List *refnames_tlist)
Definition: prepunion.c:1174
static List * generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
Definition: prepunion.c:1302
int errcode(int sqlerrcode)
Definition: elog.c:575
bool grouping_is_hashable(List *groupClause)
Definition: tlist.c:538
int wt_param_id
Definition: relation.h:311
#define ERROR
Definition: elog.h:43
RecursiveUnionPath * create_recursiveunion_path(PlannerInfo *root, RelOptInfo *rel, Path *leftpath, Path *rightpath, PathTarget *target, List *distinctList, int wtParam, double numGroups)
Definition: pathnode.c:3174
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1137
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define create_pathtarget(root, tlist)
Definition: tlist.h:69
#define ereport(elevel, rest)
Definition: elog.h:122
static Path * recurse_set_operations(Node *setOp, PlannerInfo *root, List *colTypes, List *colCollations, bool junkOK, int flag, List *refnames_tlist, List **pTargetList, double *pNumGroups)
Definition: prepunion.c:262
List * colCollations
Definition: parsenodes.h:1589
#define Assert(condition)
Definition: c.h:680
double rows
Definition: relation.h:1052
struct Path * non_recursive_path
Definition: relation.h:312
SetOperation op
Definition: parsenodes.h:1580
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
Definition: pg_list.h:45

◆ generate_setop_grouplist()

static List * generate_setop_grouplist ( SetOperationStmt op,
List targetlist 
)
static

Definition at line 1302 of file prepunion.c.

References Assert, copyObject, SetOperationStmt::groupClauses, lfirst, list_head(), lnext, TargetEntry::resjunk, TargetEntry::resno, TargetEntry::ressortgroupref, and SortGroupClause::tleSortGroupRef.

Referenced by generate_nonunion_path(), generate_recursion_path(), and make_union_unique().

1303 {
1304  List *grouplist = copyObject(op->groupClauses);
1305  ListCell *lg;
1306  ListCell *lt;
1307 
1308  lg = list_head(grouplist);
1309  foreach(lt, targetlist)
1310  {
1311  TargetEntry *tle = (TargetEntry *) lfirst(lt);
1312  SortGroupClause *sgc;
1313 
1314  if (tle->resjunk)
1315  {
1316  /* resjunk columns should not have sortgrouprefs */
1317  Assert(tle->ressortgroupref == 0);
1318  continue; /* ignore resjunk columns */
1319  }
1320 
1321  /* non-resjunk columns should have sortgroupref = resno */
1322  Assert(tle->ressortgroupref == tle->resno);
1323 
1324  /* non-resjunk columns should have grouping clauses */
1325  Assert(lg != NULL);
1326  sgc = (SortGroupClause *) lfirst(lg);
1327  lg = lnext(lg);
1328  Assert(sgc->tleSortGroupRef == 0);
1329 
1330  sgc->tleSortGroupRef = tle->ressortgroupref;
1331  }
1332  Assert(lg == NULL);
1333  return grouplist;
1334 }
Index tleSortGroupRef
Definition: parsenodes.h:1196
bool resjunk
Definition: primnodes.h:1382
AttrNumber resno
Definition: primnodes.h:1376
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
#define Assert(condition)
Definition: c.h:680
#define lfirst(lc)
Definition: pg_list.h:106
Index ressortgroupref
Definition: primnodes.h:1378
#define copyObject(obj)
Definition: nodes.h:625
Definition: pg_list.h:45

◆ generate_setop_tlist()

static List * generate_setop_tlist ( List colTypes,
List colCollations,
int  flag,
Index  varno,
bool  hack_constants,
List input_tlist,
List refnames_tlist 
)
static

Definition at line 1029 of file prepunion.c.

References Assert, COERCE_IMPLICIT_CAST, coerce_to_common_type(), TargetEntry::expr, exprCollation(), exprType(), exprTypmod(), forthree, Int32GetDatum, INT4OID, InvalidOid, IsA, lappend(), lfirst, lfirst_oid, list_head(), lnext, makeConst(), makeRelabelType(), makeTargetEntry(), makeVar(), NIL, pstrdup(), TargetEntry::resjunk, TargetEntry::resname, TargetEntry::resno, and TargetEntry::ressortgroupref.

Referenced by recurse_set_operations().

1035 {
1036  List *tlist = NIL;
1037  int resno = 1;
1038  ListCell *ctlc,
1039  *cclc,
1040  *itlc,
1041  *rtlc;
1042  TargetEntry *tle;
1043  Node *expr;
1044 
1045  /* there's no forfour() so we must chase one list manually */
1046  rtlc = list_head(refnames_tlist);
1047  forthree(ctlc, colTypes, cclc, colCollations, itlc, input_tlist)
1048  {
1049  Oid colType = lfirst_oid(ctlc);
1050  Oid colColl = lfirst_oid(cclc);
1051  TargetEntry *inputtle = (TargetEntry *) lfirst(itlc);
1052  TargetEntry *reftle = (TargetEntry *) lfirst(rtlc);
1053 
1054  rtlc = lnext(rtlc);
1055 
1056  Assert(inputtle->resno == resno);
1057  Assert(reftle->resno == resno);
1058  Assert(!inputtle->resjunk);
1059  Assert(!reftle->resjunk);
1060 
1061  /*
1062  * Generate columns referencing input columns and having appropriate
1063  * data types and column names. Insert datatype coercions where
1064  * necessary.
1065  *
1066  * HACK: constants in the input's targetlist are copied up as-is
1067  * rather than being referenced as subquery outputs. This is mainly
1068  * to ensure that when we try to coerce them to the output column's
1069  * datatype, the right things happen for UNKNOWN constants. But do
1070  * this only at the first level of subquery-scan plans; we don't want
1071  * phony constants appearing in the output tlists of upper-level
1072  * nodes!
1073  */
1074  if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
1075  expr = (Node *) inputtle->expr;
1076  else
1077  expr = (Node *) makeVar(varno,
1078  inputtle->resno,
1079  exprType((Node *) inputtle->expr),
1080  exprTypmod((Node *) inputtle->expr),
1081  exprCollation((Node *) inputtle->expr),
1082  0);
1083 
1084  if (exprType(expr) != colType)
1085  {
1086  /*
1087  * Note: it's not really cool to be applying coerce_to_common_type
1088  * here; one notable point is that assign_expr_collations never
1089  * gets run on any generated nodes. For the moment that's not a
1090  * problem because we force the correct exposed collation below.
1091  * It would likely be best to make the parser generate the correct
1092  * output tlist for every set-op to begin with, though.
1093  */
1094  expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */
1095  expr,
1096  colType,
1097  "UNION/INTERSECT/EXCEPT");
1098  }
1099 
1100  /*
1101  * Ensure the tlist entry's exposed collation matches the set-op. This
1102  * is necessary because plan_set_operations() reports the result
1103  * ordering as a list of SortGroupClauses, which don't carry collation
1104  * themselves but just refer to tlist entries. If we don't show the
1105  * right collation then planner.c might do the wrong thing in
1106  * higher-level queries.
1107  *
1108  * Note we use RelabelType, not CollateExpr, since this expression
1109  * will reach the executor without any further processing.
1110  */
1111  if (exprCollation(expr) != colColl)
1112  {
1113  expr = (Node *) makeRelabelType((Expr *) expr,
1114  exprType(expr),
1115  exprTypmod(expr),
1116  colColl,
1118  }
1119 
1120  tle = makeTargetEntry((Expr *) expr,
1121  (AttrNumber) resno++,
1122  pstrdup(reftle->resname),
1123  false);
1124 
1125  /*
1126  * By convention, all non-resjunk columns in a setop tree have
1127  * ressortgroupref equal to their resno. In some cases the ref isn't
1128  * needed, but this is a cleaner way than modifying the tlist later.
1129  */
1130  tle->ressortgroupref = tle->resno;
1131 
1132  tlist = lappend(tlist, tle);
1133  }
1134 
1135  if (flag >= 0)
1136  {
1137  /* Add a resjunk flag column */
1138  /* flag value is the given constant */
1139  expr = (Node *) makeConst(INT4OID,
1140  -1,
1141  InvalidOid,
1142  sizeof(int32),
1144  false,
1145  true);
1146  tle = makeTargetEntry((Expr *) expr,
1147  (AttrNumber) resno++,
1148  pstrdup("flag"),
1149  true);
1150  tlist = lappend(tlist, tle);
1151  }
1152 
1153  return tlist;
1154 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:276
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition: pg_list.h:203
char * pstrdup(const char *in)
Definition: mcxt.c:1063
#define INT4OID
Definition: pg_type.h:316
Definition: nodes.h:512
unsigned int Oid
Definition: postgres_ext.h:31
char * resname
Definition: primnodes.h:1377
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:298
signed int int32
Definition: c.h:294
bool resjunk
Definition: primnodes.h:1382
RelabelType * makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat)
Definition: makefuncs.c:401
char * flag(int b)
Definition: test-ctype.c:33
AttrNumber resno
Definition: primnodes.h:1376
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:237
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Node * coerce_to_common_type(ParseState *pstate, Node *node, Oid targetTypeId, const char *context)
List * lappend(List *list, void *datum)
Definition: list.c:128
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:680
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1375
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:720
#define Int32GetDatum(X)
Definition: postgres.h:485
Index ressortgroupref
Definition: primnodes.h:1378
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ generate_union_path()

static Path * generate_union_path ( SetOperationStmt op,
PlannerInfo root,
List refnames_tlist,
List **  pTargetList,
double *  pNumGroups 
)
static

Definition at line 536 of file prepunion.c.

References SetOperationStmt::all, SetOperationStmt::colCollations, SetOperationStmt::colTypes, create_append_path(), create_pathtarget, fetch_upper_rel(), generate_append_tlist(), SetOperationStmt::larg, list_concat(), make_union_unique(), NIL, Path::pathtarget, SetOperationStmt::rarg, recurse_union_children(), Path::rows, PlannerInfo::tuple_fraction, and UPPERREL_SETOP.

Referenced by recurse_set_operations().

540 {
541  RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
542  double save_fraction = root->tuple_fraction;
543  List *pathlist;
544  List *child_tlists1;
545  List *child_tlists2;
546  List *tlist_list;
547  List *tlist;
548  Path *path;
549 
550  /*
551  * If plain UNION, tell children to fetch all tuples.
552  *
553  * Note: in UNION ALL, we pass the top-level tuple_fraction unmodified to
554  * each arm of the UNION ALL. One could make a case for reducing the
555  * tuple fraction for later arms (discounting by the expected size of the
556  * earlier arms' results) but it seems not worth the trouble. The normal
557  * case where tuple_fraction isn't already zero is a LIMIT at top level,
558  * and passing it down as-is is usually enough to get the desired result
559  * of preferring fast-start plans.
560  */
561  if (!op->all)
562  root->tuple_fraction = 0.0;
563 
564  /*
565  * If any of my children are identical UNION nodes (same op, all-flag, and
566  * colTypes) then they can be merged into this node so that we generate
567  * only one Append and unique-ification for the lot. Recurse to find such
568  * nodes and compute their children's paths.
569  */
570  pathlist = list_concat(recurse_union_children(op->larg, root,
571  op, refnames_tlist,
572  &child_tlists1),
573  recurse_union_children(op->rarg, root,
574  op, refnames_tlist,
575  &child_tlists2));
576  tlist_list = list_concat(child_tlists1, child_tlists2);
577 
578  /*
579  * Generate tlist for Append plan node.
580  *
581  * The tlist for an Append plan isn't important as far as the Append is
582  * concerned, but we must make it look real anyway for the benefit of the
583  * next plan level up.
584  */
585  tlist = generate_append_tlist(op->colTypes, op->colCollations, false,
586  tlist_list, refnames_tlist);
587 
588  *pTargetList = tlist;
589 
590  /*
591  * Append the child results together.
592  */
593  path = (Path *) create_append_path(result_rel, pathlist, NIL,
594  NULL, 0, false, NIL, -1);
595  /* We have to manually jam the right tlist into the path; ick */
596  path->pathtarget = create_pathtarget(root, tlist);
597 
598  /*
599  * For UNION ALL, we just need the Append path. For UNION, need to add
600  * node(s) to remove duplicates.
601  */
602  if (!op->all)
603  path = make_union_unique(op, path, tlist, root);
604 
605  /*
606  * Estimate number of groups if caller wants it. For now we just assume
607  * the output is unique --- this is certainly true for the UNION case, and
608  * we want worst-case estimates anyway.
609  */
610  if (pNumGroups)
611  *pNumGroups = path->rows;
612 
613  /* Undo effects of possibly forcing tuple_fraction to 0 */
614  root->tuple_fraction = save_fraction;
615 
616  return path;
617 }
#define NIL
Definition: pg_list.h:69
static List * generate_append_tlist(List *colTypes, List *colCollations, bool flag, List *input_tlists, List *refnames_tlist)
Definition: prepunion.c:1174
PathTarget * pathtarget
Definition: relation.h:1043
static List * recurse_union_children(Node *setOp, PlannerInfo *root, SetOperationStmt *top_union, List *refnames_tlist, List **tlist_list)
Definition: prepunion.c:800
static Path * make_union_unique(SetOperationStmt *op, Path *path, List *tlist, PlannerInfo *root)
Definition: prepunion.c:857
List * list_concat(List *list1, List *list2)
Definition: list.c:321
double tuple_fraction
Definition: relation.h:294
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1137
#define create_pathtarget(root, tlist)
Definition: tlist.h:69
List * colCollations
Definition: parsenodes.h:1589
double rows
Definition: relation.h:1052
AppendPath * create_append_path(RelOptInfo *rel, List *subpaths, List *partial_subpaths, Relids required_outer, int parallel_workers, bool parallel_aware, List *partitioned_rels, double rows)
Definition: pathnode.c:1213
Definition: pg_list.h:45

◆ make_inh_translation_list()

static void make_inh_translation_list ( Relation  oldrelation,
Relation  newrelation,
Index  newvarno,
List **  translated_vars 
)
static

Definition at line 1785 of file prepunion.c.

References elog, ERROR, lappend(), makeVar(), NameStr, tupleDesc::natts, NIL, RelationGetDescr, RelationGetRelationName, and TupleDescAttr.

Referenced by expand_single_inheritance_child().

1788 {
1789  List *vars = NIL;
1790  TupleDesc old_tupdesc = RelationGetDescr(oldrelation);
1791  TupleDesc new_tupdesc = RelationGetDescr(newrelation);
1792  int oldnatts = old_tupdesc->natts;
1793  int newnatts = new_tupdesc->natts;
1794  int old_attno;
1795 
1796  for (old_attno = 0; old_attno < oldnatts; old_attno++)
1797  {
1798  Form_pg_attribute att;
1799  char *attname;
1800  Oid atttypid;
1801  int32 atttypmod;
1802  Oid attcollation;
1803  int new_attno;
1804 
1805  att = TupleDescAttr(old_tupdesc, old_attno);
1806  if (att->attisdropped)
1807  {
1808  /* Just put NULL into this list entry */
1809  vars = lappend(vars, NULL);
1810  continue;
1811  }
1812  attname = NameStr(att->attname);
1813  atttypid = att->atttypid;
1814  atttypmod = att->atttypmod;
1815  attcollation = att->attcollation;
1816 
1817  /*
1818  * When we are generating the "translation list" for the parent table
1819  * of an inheritance set, no need to search for matches.
1820  */
1821  if (oldrelation == newrelation)
1822  {
1823  vars = lappend(vars, makeVar(newvarno,
1824  (AttrNumber) (old_attno + 1),
1825  atttypid,
1826  atttypmod,
1827  attcollation,
1828  0));
1829  continue;
1830  }
1831 
1832  /*
1833  * Otherwise we have to search for the matching column by name.
1834  * There's no guarantee it'll have the same column position, because
1835  * of cases like ALTER TABLE ADD COLUMN and multiple inheritance.
1836  * However, in simple cases it will be the same column number, so try
1837  * that before we go groveling through all the columns.
1838  *
1839  * Note: the test for (att = ...) != NULL cannot fail, it's just a
1840  * notational device to include the assignment into the if-clause.
1841  */
1842  if (old_attno < newnatts &&
1843  (att = TupleDescAttr(new_tupdesc, old_attno)) != NULL &&
1844  !att->attisdropped && att->attinhcount != 0 &&
1845  strcmp(attname, NameStr(att->attname)) == 0)
1846  new_attno = old_attno;
1847  else
1848  {
1849  for (new_attno = 0; new_attno < newnatts; new_attno++)
1850  {
1851  att = TupleDescAttr(new_tupdesc, new_attno);
1852  if (!att->attisdropped && att->attinhcount != 0 &&
1853  strcmp(attname, NameStr(att->attname)) == 0)
1854  break;
1855  }
1856  if (new_attno >= newnatts)
1857  elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
1858  attname, RelationGetRelationName(newrelation));
1859  }
1860 
1861  /* Found it, check type and collation match */
1862  if (atttypid != att->atttypid || atttypmod != att->atttypmod)
1863  elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type",
1864  attname, RelationGetRelationName(newrelation));
1865  if (attcollation != att->attcollation)
1866  elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's collation",
1867  attname, RelationGetRelationName(newrelation));
1868 
1869  vars = lappend(vars, makeVar(newvarno,
1870  (AttrNumber) (new_attno + 1),
1871  atttypid,
1872  atttypmod,
1873  attcollation,
1874  0));
1875  }
1876 
1877  *translated_vars = vars;
1878 }
#define NIL
Definition: pg_list.h:69
#define RelationGetDescr(relation)
Definition: rel.h:437
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
unsigned int Oid
Definition: postgres_ext.h:31
int natts
Definition: tupdesc.h:79
signed int int32
Definition: c.h:294
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:445
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
List * lappend(List *list, void *datum)
Definition: list.c:128
#define NameStr(name)
Definition: c.h:557
#define elog
Definition: elog.h:219
Definition: regcomp.c:224
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21

◆ make_union_unique()

static Path * make_union_unique ( SetOperationStmt op,
Path path,
List tlist,
PlannerInfo root 
)
static

Definition at line 857 of file prepunion.c.

References AGG_HASHED, AGGSPLIT_SIMPLE, choose_hashed_setop(), create_agg_path(), create_pathtarget, create_sort_path(), create_upper_unique_path(), fetch_upper_rel(), generate_setop_grouplist(), list_length(), make_pathkeys_for_sortclauses(), NIL, Path::pathkeys, Path::pathtarget, Path::rows, and UPPERREL_SETOP.

Referenced by generate_union_path().

859 {
860  RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
861  List *groupList;
862  double dNumGroups;
863 
864  /* Identify the grouping semantics */
865  groupList = generate_setop_grouplist(op, tlist);
866 
867  /* punt if nothing to group on (can this happen?) */
868  if (groupList == NIL)
869  return path;
870 
871  /*
872  * XXX for the moment, take the number of distinct groups as equal to the
873  * total input size, ie, the worst case. This is too conservative, but we
874  * don't want to risk having the hashtable overrun memory; also, it's not
875  * clear how to get a decent estimate of the true size. One should note
876  * as well the propensity of novices to write UNION rather than UNION ALL
877  * even when they don't expect any duplicates...
878  */
879  dNumGroups = path->rows;
880 
881  /* Decide whether to hash or sort */
882  if (choose_hashed_setop(root, groupList, path,
883  dNumGroups, dNumGroups,
884  "UNION"))
885  {
886  /* Hashed aggregate plan --- no sort needed */
887  path = (Path *) create_agg_path(root,
888  result_rel,
889  path,
890  create_pathtarget(root, tlist),
891  AGG_HASHED,
893  groupList,
894  NIL,
895  NULL,
896  dNumGroups);
897  }
898  else
899  {
900  /* Sort and Unique */
901  path = (Path *) create_sort_path(root,
902  result_rel,
903  path,
905  groupList,
906  tlist),
907  -1.0);
908  /* We have to manually jam the right tlist into the path; ick */
909  path->pathtarget = create_pathtarget(root, tlist);
910  path = (Path *) create_upper_unique_path(root,
911  result_rel,
912  path,
913  list_length(path->pathkeys),
914  dNumGroups);
915  }
916 
917  return path;
918 }
#define NIL
Definition: pg_list.h:69
PathTarget * pathtarget
Definition: relation.h:1043
List * make_pathkeys_for_sortclauses(PlannerInfo *root, List *sortclauses, List *tlist)
Definition: pathkeys.c:865
UpperUniquePath * create_upper_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, int numCols, double numGroups)
Definition: pathnode.c:2701
static List * generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
Definition: prepunion.c:1302
static bool choose_hashed_setop(PlannerInfo *root, List *groupClauses, Path *input_path, double dNumGroups, double dNumOutputRows, const char *construct)
Definition: prepunion.c:924
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1137
AggPath * create_agg_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, PathTarget *target, AggStrategy aggstrategy, AggSplit aggsplit, List *groupClause, List *qual, const AggClauseCosts *aggcosts, double numGroups)
Definition: pathnode.c:2753
#define create_pathtarget(root, tlist)
Definition: tlist.h:69
SortPath * create_sort_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, double limit_tuples)
Definition: pathnode.c:2598
List * pathkeys
Definition: relation.h:1056
double rows
Definition: relation.h:1052
static int list_length(const List *l)
Definition: pg_list.h:89
Definition: pg_list.h:45

◆ plan_set_operations()

RelOptInfo* plan_set_operations ( PlannerInfo root)

Definition at line 143 of file prepunion.c.

References add_path(), Assert, castNode, create_upper_paths_hook, Query::distinctClause, fetch_upper_rel(), FromExpr::fromlist, generate_recursion_path(), Query::groupClause, PlannerInfo::hasRecursion, Query::havingQual, IsA, Query::jointree, SetOperationStmt::larg, NIL, parse(), PlannerInfo::parse, PlannerInfo::processed_tlist, FromExpr::quals, recurse_set_operations(), set_cheapest(), Query::setOperations, setup_simple_rel_arrays(), PlannerInfo::simple_rte_array, RangeTblEntry::subquery, Query::targetList, UPPERREL_SETOP, and Query::windowClause.

Referenced by grouping_planner().

144 {
145  Query *parse = root->parse;
147  Node *node;
148  RangeTblEntry *leftmostRTE;
149  Query *leftmostQuery;
150  RelOptInfo *setop_rel;
151  Path *path;
152  List *top_tlist;
153 
154  Assert(topop);
155 
156  /* check for unsupported stuff */
157  Assert(parse->jointree->fromlist == NIL);
158  Assert(parse->jointree->quals == NULL);
159  Assert(parse->groupClause == NIL);
160  Assert(parse->havingQual == NULL);
161  Assert(parse->windowClause == NIL);
162  Assert(parse->distinctClause == NIL);
163 
164  /*
165  * We'll need to build RelOptInfos for each of the leaf subqueries, which
166  * are RTE_SUBQUERY rangetable entries in this Query. Prepare the index
167  * arrays for that.
168  */
170 
171  /*
172  * Find the leftmost component Query. We need to use its column names for
173  * all generated tlists (else SELECT INTO won't work right).
174  */
175  node = topop->larg;
176  while (node && IsA(node, SetOperationStmt))
177  node = ((SetOperationStmt *) node)->larg;
178  Assert(node && IsA(node, RangeTblRef));
179  leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex];
180  leftmostQuery = leftmostRTE->subquery;
181  Assert(leftmostQuery != NULL);
182 
183  /*
184  * We return our results in the (SETOP, NULL) upperrel. For the moment,
185  * this is also the parent rel of all Paths in the setop tree; we may well
186  * change that in future.
187  */
188  setop_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
189 
190  /*
191  * We don't currently worry about setting setop_rel's consider_parallel
192  * flag, nor about allowing FDWs to contribute paths to it.
193  */
194 
195  /*
196  * If the topmost node is a recursive union, it needs special processing.
197  */
198  if (root->hasRecursion)
199  {
200  path = generate_recursion_path(topop, root,
201  leftmostQuery->targetList,
202  &top_tlist);
203  }
204  else
205  {
206  /*
207  * Recurse on setOperations tree to generate paths for set ops. The
208  * final output path should have just the column types shown as the
209  * output from the top-level node, plus possibly resjunk working
210  * columns (we can rely on upper-level nodes to deal with that).
211  */
212  path = recurse_set_operations((Node *) topop, root,
213  topop->colTypes, topop->colCollations,
214  true, -1,
215  leftmostQuery->targetList,
216  &top_tlist,
217  NULL);
218  }
219 
220  /* Must return the built tlist into root->processed_tlist. */
221  root->processed_tlist = top_tlist;
222 
223  /* Add only the final path to the SETOP upperrel. */
224  add_path(setop_rel, path);
225 
226  /* Let extensions possibly add some more paths */
228  (*create_upper_paths_hook) (root, UPPERREL_SETOP,
229  NULL, setop_rel);
230 
231  /* Select cheapest path */
232  set_cheapest(setop_rel);
233 
234  return setop_rel;
235 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
Query * parse
Definition: relation.h:155
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:422
FromExpr * jointree
Definition: parsenodes.h:136
static Path * generate_recursion_path(SetOperationStmt *setOp, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition: prepunion.c:441
#define castNode(_type_, nodeptr)
Definition: nodes.h:581
Definition: nodes.h:512
List * fromlist
Definition: primnodes.h:1478
create_upper_paths_hook_type create_upper_paths_hook
Definition: planner.c:70
bool hasRecursion
Definition: relation.h:308
Node * quals
Definition: primnodes.h:1479
List * windowClause
Definition: parsenodes.h:152
List * targetList
Definition: parsenodes.h:138
List * distinctClause
Definition: parsenodes.h:154
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1137
static Path * recurse_set_operations(Node *setOp, PlannerInfo *root, List *colTypes, List *colCollations, bool junkOK, int flag, List *refnames_tlist, List **pTargetList, double *pNumGroups)
Definition: prepunion.c:262
RangeTblEntry ** simple_rte_array
Definition: relation.h:188
void set_cheapest(RelOptInfo *parent_rel)
Definition: pathnode.c:244
#define Assert(condition)
Definition: c.h:680
void setup_simple_rel_arrays(PlannerInfo *root)
Definition: relnode.c:67
Node * setOperations
Definition: parsenodes.h:163
Query * subquery
Definition: parsenodes.h:974
List * groupClause
Definition: parsenodes.h:146
Node * havingQual
Definition: parsenodes.h:150
List * processed_tlist
Definition: relation.h:284
Definition: pg_list.h:45
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:649

◆ recurse_set_operations()

static Path * recurse_set_operations ( Node setOp,
PlannerInfo root,
List colTypes,
List colCollations,
bool  junkOK,
int  flag,
List refnames_tlist,
List **  pTargetList,
double *  pNumGroups 
)
static

Definition at line 262 of file prepunion.c.

References apply_projection_to_path(), Assert, build_simple_rel(), create_pathtarget, create_subqueryscan_path(), Query::distinctClause, elog, ERROR, estimate_num_groups(), fetch_upper_rel(), generate_nonunion_path(), generate_setop_tlist(), generate_union_path(), get_cheapest_fractional_path(), get_tlist_exprs(), PlannerInfo::glob, Query::groupClause, Query::groupingSets, Query::hasAggs, PlannerInfo::hasHavingQual, IsA, NIL, nodeTag, SetOperationStmt::op, Path::parent, PlannerInfo::plan_params, PlannerInfo::processed_tlist, Path::rows, RangeTblRef::rtindex, set_subquery_size_estimates(), SETOP_UNION, PlannerInfo::simple_rte_array, subpath(), RangeTblEntry::subquery, subquery_planner(), RelOptInfo::subroot, Query::targetList, tlist_same_collations(), tlist_same_datatypes(), PlannerInfo::tuple_fraction, and UPPERREL_FINAL.

Referenced by generate_nonunion_path(), generate_recursion_path(), plan_set_operations(), and recurse_union_children().

268 {
269  if (IsA(setOp, RangeTblRef))
270  {
271  RangeTblRef *rtr = (RangeTblRef *) setOp;
272  RangeTblEntry *rte = root->simple_rte_array[rtr->rtindex];
273  Query *subquery = rte->subquery;
274  RelOptInfo *rel;
275  PlannerInfo *subroot;
276  RelOptInfo *final_rel;
277  Path *subpath;
278  Path *path;
279  List *tlist;
280 
281  Assert(subquery != NULL);
282 
283  /*
284  * We need to build a RelOptInfo for each leaf subquery. This isn't
285  * used for much here, but it carries the subroot data structures
286  * forward to setrefs.c processing.
287  */
288  rel = build_simple_rel(root, rtr->rtindex, NULL);
289 
290  /* plan_params should not be in use in current query level */
291  Assert(root->plan_params == NIL);
292 
293  /* Generate a subroot and Paths for the subquery */
294  subroot = rel->subroot = subquery_planner(root->glob, subquery,
295  root,
296  false,
297  root->tuple_fraction);
298 
299  /*
300  * It should not be possible for the primitive query to contain any
301  * cross-references to other primitive queries in the setop tree.
302  */
303  if (root->plan_params)
304  elog(ERROR, "unexpected outer reference in set operation subquery");
305 
306  /*
307  * Mark rel with estimated output rows, width, etc. Note that we have
308  * to do this before generating outer-query paths, else
309  * cost_subqueryscan is not happy.
310  */
311  set_subquery_size_estimates(root, rel);
312 
313  /*
314  * For the moment, we consider only a single Path for the subquery.
315  * This should change soon (make it look more like
316  * set_subquery_pathlist).
317  */
318  final_rel = fetch_upper_rel(subroot, UPPERREL_FINAL, NULL);
319  subpath = get_cheapest_fractional_path(final_rel,
320  root->tuple_fraction);
321 
322  /*
323  * Stick a SubqueryScanPath atop that.
324  *
325  * We don't bother to determine the subquery's output ordering since
326  * it won't be reflected in the set-op result anyhow; so just label
327  * the SubqueryScanPath with nil pathkeys. (XXX that should change
328  * soon too, likely.)
329  */
330  path = (Path *) create_subqueryscan_path(root, rel, subpath,
331  NIL, NULL);
332 
333  /*
334  * Figure out the appropriate target list, and update the
335  * SubqueryScanPath with the PathTarget form of that.
336  */
337  tlist = generate_setop_tlist(colTypes, colCollations,
338  flag,
339  rtr->rtindex,
340  true,
341  subroot->processed_tlist,
342  refnames_tlist);
343 
344  path = apply_projection_to_path(root, rel, path,
345  create_pathtarget(root, tlist));
346 
347  /* Return the fully-fledged tlist to caller, too */
348  *pTargetList = tlist;
349 
350  /*
351  * Estimate number of groups if caller wants it. If the subquery used
352  * grouping or aggregation, its output is probably mostly unique
353  * anyway; otherwise do statistical estimation.
354  *
355  * XXX you don't really want to know about this: we do the estimation
356  * using the subquery's original targetlist expressions, not the
357  * subroot->processed_tlist which might seem more appropriate. The
358  * reason is that if the subquery is itself a setop, it may return a
359  * processed_tlist containing "varno 0" Vars generated by
360  * generate_append_tlist, and those would confuse estimate_num_groups
361  * mightily. We ought to get rid of the "varno 0" hack, but that
362  * requires a redesign of the parsetree representation of setops, so
363  * that there can be an RTE corresponding to each setop's output.
364  */
365  if (pNumGroups)
366  {
367  if (subquery->groupClause || subquery->groupingSets ||
368  subquery->distinctClause ||
369  subroot->hasHavingQual || subquery->hasAggs)
370  *pNumGroups = subpath->rows;
371  else
372  *pNumGroups = estimate_num_groups(subroot,
373  get_tlist_exprs(subquery->targetList, false),
374  subpath->rows,
375  NULL);
376  }
377 
378  return (Path *) path;
379  }
380  else if (IsA(setOp, SetOperationStmt))
381  {
382  SetOperationStmt *op = (SetOperationStmt *) setOp;
383  Path *path;
384 
385  /* UNIONs are much different from INTERSECT/EXCEPT */
386  if (op->op == SETOP_UNION)
387  path = generate_union_path(op, root,
388  refnames_tlist,
389  pTargetList,
390  pNumGroups);
391  else
392  path = generate_nonunion_path(op, root,
393  refnames_tlist,
394  pTargetList,
395  pNumGroups);
396 
397  /*
398  * If necessary, add a Result node to project the caller-requested
399  * output columns.
400  *
401  * XXX you don't really want to know about this: setrefs.c will apply
402  * fix_upper_expr() to the Result node's tlist. This would fail if the
403  * Vars generated by generate_setop_tlist() were not exactly equal()
404  * to the corresponding tlist entries of the subplan. However, since
405  * the subplan was generated by generate_union_plan() or
406  * generate_nonunion_plan(), and hence its tlist was generated by
407  * generate_append_tlist(), this will work. We just tell
408  * generate_setop_tlist() to use varno 0.
409  */
410  if (flag >= 0 ||
411  !tlist_same_datatypes(*pTargetList, colTypes, junkOK) ||
412  !tlist_same_collations(*pTargetList, colCollations, junkOK))
413  {
414  *pTargetList = generate_setop_tlist(colTypes, colCollations,
415  flag,
416  0,
417  false,
418  *pTargetList,
419  refnames_tlist);
420  path = apply_projection_to_path(root,
421  path->parent,
422  path,
423  create_pathtarget(root,
424  *pTargetList));
425  }
426  return path;
427  }
428  else
429  {
430  elog(ERROR, "unrecognized node type: %d",
431  (int) nodeTag(setOp));
432  *pTargetList = NIL;
433  return NULL; /* keep compiler quiet */
434  }
435 }
Path * apply_projection_to_path(PlannerInfo *root, RelOptInfo *rel, Path *path, PathTarget *target)
Definition: pathnode.c:2442
void set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel)
Definition: costsize.c:4761
#define NIL
Definition: pg_list.h:69
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset)
Definition: selfuncs.c:3398
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
bool tlist_same_datatypes(List *tlist, List *colTypes, bool junkOK)
Definition: tlist.c:251
SubqueryScanPath * create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, Relids required_outer)
Definition: pathnode.c:1841
List * plan_params
Definition: relation.h:169
static Path * generate_union_path(SetOperationStmt *op, PlannerInfo *root, List *refnames_tlist, List **pTargetList, double *pNumGroups)
Definition: prepunion.c:536
bool hasAggs
Definition: parsenodes.h:123
static Path * generate_nonunion_path(SetOperationStmt *op, PlannerInfo *root, List *refnames_tlist, List **pTargetList, double *pNumGroups)
Definition: prepunion.c:623
List * groupingSets
Definition: parsenodes.h:148
List * targetList
Definition: parsenodes.h:138
PlannerInfo * subroot
Definition: relation.h:627
double tuple_fraction
Definition: relation.h:294
List * distinctClause
Definition: parsenodes.h:154
#define ERROR
Definition: elog.h:43
RelOptInfo * parent
Definition: relation.h:1042
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1137
PlannerGlobal * glob
Definition: relation.h:157
char * flag(int b)
Definition: test-ctype.c:33
#define create_pathtarget(root, tlist)
Definition: tlist.h:69
RelOptInfo * build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
Definition: relnode.c:96
RangeTblEntry ** simple_rte_array
Definition: relation.h:188
List * get_tlist_exprs(List *tlist, bool includeJunk)
Definition: tlist.c:166
#define Assert(condition)
Definition: c.h:680
double rows
Definition: relation.h:1052
SetOperation op
Definition: parsenodes.h:1580
#define nodeTag(nodeptr)
Definition: nodes.h:517
Query * subquery
Definition: parsenodes.h:974
List * groupClause
Definition: parsenodes.h:146
bool hasHavingQual
Definition: relation.h:305
bool tlist_same_collations(List *tlist, List *colCollations, bool junkOK)
Definition: tlist.c:285
#define elog
Definition: elog.h:219
List * processed_tlist
Definition: relation.h:284
Definition: pg_list.h:45
PlannerInfo * subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, bool hasRecursion, double tuple_fraction)
Definition: planner.c:517
Datum subpath(PG_FUNCTION_ARGS)
Definition: ltree_op.c:234
Path * get_cheapest_fractional_path(RelOptInfo *rel, double tuple_fraction)
Definition: planner.c:5873
static List * generate_setop_tlist(List *colTypes, List *colCollations, int flag, Index varno, bool hack_constants, List *input_tlist, List *refnames_tlist)
Definition: prepunion.c:1029

◆ recurse_union_children()

static List * recurse_union_children ( Node setOp,
PlannerInfo root,
SetOperationStmt top_union,
List refnames_tlist,
List **  tlist_list 
)
static

Definition at line 800 of file prepunion.c.

References SetOperationStmt::all, SetOperationStmt::colCollations, SetOperationStmt::colTypes, equal(), IsA, SetOperationStmt::larg, list_concat(), list_make1, SetOperationStmt::op, SetOperationStmt::rarg, and recurse_set_operations().

Referenced by generate_union_path().

804 {
805  List *result;
806  List *child_tlist;
807 
808  if (IsA(setOp, SetOperationStmt))
809  {
810  SetOperationStmt *op = (SetOperationStmt *) setOp;
811 
812  if (op->op == top_union->op &&
813  (op->all == top_union->all || op->all) &&
814  equal(op->colTypes, top_union->colTypes))
815  {
816  /* Same UNION, so fold children into parent's subpath list */
817  List *child_tlists1;
818  List *child_tlists2;
819 
820  result = list_concat(recurse_union_children(op->larg, root,
821  top_union,
822  refnames_tlist,
823  &child_tlists1),
824  recurse_union_children(op->rarg, root,
825  top_union,
826  refnames_tlist,
827  &child_tlists2));
828  *tlist_list = list_concat(child_tlists1, child_tlists2);
829  return result;
830  }
831  }
832 
833  /*
834  * Not same, so plan this child separately.
835  *
836  * Note we disallow any resjunk columns in child results. This is
837  * necessary since the Append node that implements the union won't do any
838  * projection, and upper levels will get confused if some of our output
839  * tuples have junk and some don't. This case only arises when we have an
840  * EXCEPT or INTERSECT as child, else there won't be resjunk anyway.
841  */
842  result = list_make1(recurse_set_operations(setOp, root,
843  top_union->colTypes,
844  top_union->colCollations,
845  false, -1,
846  refnames_tlist,
847  &child_tlist,
848  NULL));
849  *tlist_list = list_make1(child_tlist);
850  return result;
851 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:563
static List * recurse_union_children(Node *setOp, PlannerInfo *root, SetOperationStmt *top_union, List *refnames_tlist, List **tlist_list)
Definition: prepunion.c:800
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2984
List * list_concat(List *list1, List *list2)
Definition: list.c:321
#define list_make1(x1)
Definition: pg_list.h:139
static Path * recurse_set_operations(Node *setOp, PlannerInfo *root, List *colTypes, List *colCollations, bool junkOK, int flag, List *refnames_tlist, List **pTargetList, double *pNumGroups)
Definition: prepunion.c:262
List * colCollations
Definition: parsenodes.h:1589
SetOperation op
Definition: parsenodes.h:1580
Definition: pg_list.h:45

◆ translate_col_privs()

static Bitmapset * translate_col_privs ( const Bitmapset parent_privs,
List translated_vars 
)
static

Definition at line 1892 of file prepunion.c.

References bms_add_member(), bms_is_member(), FirstLowInvalidHeapAttributeNumber, InvalidAttrNumber, lfirst_node, and Var::varattno.

Referenced by expand_single_inheritance_child().

1894 {
1895  Bitmapset *child_privs = NULL;
1896  bool whole_row;
1897  int attno;
1898  ListCell *lc;
1899 
1900  /* System attributes have the same numbers in all tables */
1901  for (attno = FirstLowInvalidHeapAttributeNumber + 1; attno < 0; attno++)
1902  {
1904  parent_privs))
1905  child_privs = bms_add_member(child_privs,
1907  }
1908 
1909  /* Check if parent has whole-row reference */
1911  parent_privs);
1912 
1913  /* And now translate the regular user attributes, using the vars list */
1914  attno = InvalidAttrNumber;
1915  foreach(lc, translated_vars)
1916  {
1917  Var *var = lfirst_node(Var, lc);
1918 
1919  attno++;
1920  if (var == NULL) /* ignore dropped columns */
1921  continue;
1922  if (whole_row ||
1924  parent_privs))
1925  child_privs = bms_add_member(child_privs,
1927  }
1928 
1929  return child_privs;
1930 }
AttrNumber varattno
Definition: primnodes.h:168
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
Definition: primnodes.h:163
#define lfirst_node(type, lc)
Definition: pg_list.h:109
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
#define InvalidAttrNumber
Definition: attnum.h:23
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420