PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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

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

Definition at line 1943 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().

1945 {
1946  Node *result;
1948 
1949  context.root = root;
1950  context.nappinfos = nappinfos;
1951  context.appinfos = appinfos;
1952 
1953  /* If there's nothing to adjust, don't call this function. */
1954  Assert(nappinfos >= 1 && appinfos != NULL);
1955 
1956  /*
1957  * Must be prepared to start with a Query or a bare expression tree.
1958  */
1959  if (node && IsA(node, Query))
1960  {
1961  Query *newnode;
1962  int cnt;
1963 
1964  newnode = query_tree_mutator((Query *) node,
1966  (void *) &context,
1968  for (cnt = 0; cnt < nappinfos; cnt++)
1969  {
1970  AppendRelInfo *appinfo = appinfos[cnt];
1971 
1972  if (newnode->resultRelation == appinfo->parent_relid)
1973  {
1974  newnode->resultRelation = appinfo->child_relid;
1975  /* Fix tlist resnos too, if it's inherited UPDATE */
1976  if (newnode->commandType == CMD_UPDATE)
1977  newnode->targetList =
1979  appinfo);
1980  break;
1981  }
1982  }
1983 
1984  result = (Node *) newnode;
1985  }
1986  else
1987  result = adjust_appendrel_attrs_mutator(node, &context);
1988 
1989  return result;
1990 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
int resultRelation
Definition: parsenodes.h:120
Definition: nodes.h:510
static List * adjust_inherited_tlist(List *tlist, AppendRelInfo *context)
Definition: prepunion.c:2342
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:1993
#define Assert(condition)
Definition: c.h:681
AppendRelInfo ** appinfos
Definition: prepunion.c:60
Index child_relid
Definition: relation.h:2066
Index parent_relid
Definition: relation.h:2065
Query * query_tree_mutator(Query *query, Node *(*mutator)(), void *context, int flags)
Definition: nodeFuncs.c:3068
Node* adjust_appendrel_attrs_multilevel ( PlannerInfo root,
Node node,
Relids  child_relids,
Relids  top_parent_relids 
)

Definition at line 2430 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().

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

Definition at line 1993 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().

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

Definition at line 2243 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().

2244 {
2245  Bitmapset *result = NULL;
2246  int cnt;
2247 
2248  for (cnt = 0; cnt < nappinfos; cnt++)
2249  {
2250  AppendRelInfo *appinfo = appinfos[cnt];
2251 
2252  /* Remove parent, add child */
2253  if (bms_is_member(appinfo->parent_relid, relids))
2254  {
2255  /* Make a copy if we are changing the set. */
2256  if (!result)
2257  result = bms_copy(relids);
2258 
2259  result = bms_del_member(result, appinfo->parent_relid);
2260  result = bms_add_member(result, appinfo->child_relid);
2261  }
2262  }
2263 
2264  /* If we made any changes, return the modified copy. */
2265  if (result)
2266  return result;
2267 
2268  /* Otherwise, return the original set without modification. */
2269  return relids;
2270 }
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:2066
Index parent_relid
Definition: relation.h:2065
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
Relids adjust_child_relids_multilevel ( PlannerInfo root,
Relids  relids,
Relids  child_relids,
Relids  top_parent_relids 
)

Definition at line 2278 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().

2280 {
2281  AppendRelInfo **appinfos;
2282  int nappinfos;
2283  Relids parent_relids = NULL;
2284  Relids result;
2285  Relids tmp_result = NULL;
2286  int cnt;
2287 
2288  /*
2289  * If the given relids set doesn't contain any of the top parent relids,
2290  * it will remain unchanged.
2291  */
2292  if (!bms_overlap(relids, top_parent_relids))
2293  return relids;
2294 
2295  appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
2296 
2297  /* Construct relids set for the immediate parent of the given child. */
2298  for (cnt = 0; cnt < nappinfos; cnt++)
2299  {
2300  AppendRelInfo *appinfo = appinfos[cnt];
2301 
2302  parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
2303  }
2304 
2305  /* Recurse if immediate parent is not the top parent. */
2306  if (!bms_equal(parent_relids, top_parent_relids))
2307  {
2308  tmp_result = adjust_child_relids_multilevel(root, relids,
2309  parent_relids,
2310  top_parent_relids);
2311  relids = tmp_result;
2312  }
2313 
2314  result = adjust_child_relids(relids, nappinfos, appinfos);
2315 
2316  /* Free memory consumed by any intermediate result. */
2317  if (tmp_result)
2318  bms_free(tmp_result);
2319  bms_free(parent_relids);
2320  pfree(appinfos);
2321 
2322  return result;
2323 }
Relids adjust_child_relids_multilevel(PlannerInfo *root, Relids relids, Relids child_relids, Relids top_parent_relids)
Definition: prepunion.c:2278
void pfree(void *pointer)
Definition: mcxt.c:949
AppendRelInfo ** find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
Definition: prepunion.c:2514
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:2065
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:2243
static List * adjust_inherited_tlist ( List tlist,
AppendRelInfo context 
)
static

Definition at line 2342 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().

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

Definition at line 2470 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().

2472 {
2474  AppendRelInfo **left_appinfos;
2475  int left_nappinfos;
2476  AppendRelInfo **right_appinfos;
2477  int right_nappinfos;
2478 
2479  memcpy(sjinfo, parent_sjinfo, sizeof(SpecialJoinInfo));
2480  left_appinfos = find_appinfos_by_relids(root, left_relids,
2481  &left_nappinfos);
2482  right_appinfos = find_appinfos_by_relids(root, right_relids,
2483  &right_nappinfos);
2484 
2485  sjinfo->min_lefthand = adjust_child_relids(sjinfo->min_lefthand,
2486  left_nappinfos, left_appinfos);
2488  right_nappinfos,
2489  right_appinfos);
2490  sjinfo->syn_lefthand = adjust_child_relids(sjinfo->syn_lefthand,
2491  left_nappinfos, left_appinfos);
2493  right_nappinfos,
2494  right_appinfos);
2495  sjinfo->semi_rhs_exprs = (List *) adjust_appendrel_attrs(root,
2496  (Node *) sjinfo->semi_rhs_exprs,
2497  right_nappinfos,
2498  right_appinfos);
2499 
2500  pfree(left_appinfos);
2501  pfree(right_appinfos);
2502 
2503  return sjinfo;
2504 }
Relids min_righthand
Definition: relation.h:2008
Definition: nodes.h:510
Relids syn_lefthand
Definition: relation.h:2009
Relids syn_righthand
Definition: relation.h:2010
void pfree(void *pointer)
Definition: mcxt.c:949
List * semi_rhs_exprs
Definition: relation.h:2018
Node * adjust_appendrel_attrs(PlannerInfo *root, Node *node, int nappinfos, AppendRelInfo **appinfos)
Definition: prepunion.c:1943
AppendRelInfo ** find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
Definition: prepunion.c:2514
#define makeNode(_type_)
Definition: nodes.h:558
Definition: pg_list.h:45
Relids min_lefthand
Definition: relation.h:2007
static Relids adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
Definition: prepunion.c:2243
static bool choose_hashed_setop ( PlannerInfo root,
List groupClauses,
Path input_path,
double  dNumGroups,
double  dNumOutputRows,
const char *  construct 
)
static

Definition at line 923 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().

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

Definition at line 1385 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().

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

Definition at line 1342 of file prepunion.c.

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

Referenced by subquery_planner().

1343 {
1344  Index nrtes;
1345  Index rti;
1346  ListCell *rl;
1347 
1348  /*
1349  * expand_inherited_rtentry may add RTEs to parse->rtable. The function is
1350  * expected to recursively handle any RTEs that it creates with inh=true.
1351  * So just scan as far as the original end of the rtable list.
1352  */
1353  nrtes = list_length(root->parse->rtable);
1354  rl = list_head(root->parse->rtable);
1355  for (rti = 1; rti <= nrtes; rti++)
1356  {
1357  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);
1358 
1359  expand_inherited_rtentry(root, rte, rti);
1360  rl = lnext(rl);
1361  }
1362 }
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:1385
unsigned int Index
Definition: c.h:359
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
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 1566 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().

1570 {
1571  int i;
1572  RangeTblEntry *childrte;
1573  Index childRTindex;
1574  bool has_child = false;
1575  PartitionDesc partdesc = RelationGetPartitionDesc(parentrel);
1576 
1578 
1579  /* A partitioned table should always have a partition descriptor. */
1580  Assert(partdesc);
1581 
1582  Assert(parentrte->inh);
1583 
1584  /* First expand the partitioned table itself. */
1585  expand_single_inheritance_child(root, parentrte, parentRTindex, parentrel,
1586  top_parentrc, parentrel,
1587  appinfos, &childrte, &childRTindex);
1588 
1589  /*
1590  * The partitioned table does not have data for itself but still need to
1591  * be locked. Update given list of partitioned children with RTI of this
1592  * partitioned relation.
1593  */
1594  *partitioned_child_rels = lappend_int(*partitioned_child_rels,
1595  childRTindex);
1596 
1597  for (i = 0; i < partdesc->nparts; i++)
1598  {
1599  Oid childOID = partdesc->oids[i];
1600  Relation childrel;
1601 
1602  /* Open rel; we already have required locks */
1603  childrel = heap_open(childOID, NoLock);
1604 
1605  /* As in expand_inherited_rtentry, skip non-local temp tables */
1606  if (RELATION_IS_OTHER_TEMP(childrel))
1607  {
1608  heap_close(childrel, lockmode);
1609  continue;
1610  }
1611 
1612  /* We have a real partition. */
1613  has_child = true;
1614 
1615  expand_single_inheritance_child(root, parentrte, parentRTindex,
1616  parentrel, top_parentrc, childrel,
1617  appinfos, &childrte, &childRTindex);
1618 
1619  /* If this child is itself partitioned, recurse */
1620  if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1621  expand_partitioned_rtentry(root, childrte, childRTindex,
1622  childrel, top_parentrc, lockmode,
1623  appinfos, partitioned_child_rels);
1624 
1625  /* Close child relation, but keep locks */
1626  heap_close(childrel, NoLock);
1627  }
1628 
1629  /*
1630  * If the partitioned table has no partitions or all the partitions are
1631  * temporary tables from other backends, treat this as non-inheritance
1632  * case.
1633  */
1634  if (!has_child)
1635  parentrte->inh = false;
1636 }
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:1566
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:1663
#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:359
#define Assert(condition)
Definition: c.h:681
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:533
int i
#define RelationGetPartitionDesc(relation)
Definition: rel.h:632
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 1663 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().

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

Definition at line 2514 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().

2515 {
2516  ListCell *lc;
2517  AppendRelInfo **appinfos;
2518  int cnt = 0;
2519 
2520  *nappinfos = bms_num_members(relids);
2521  appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * *nappinfos);
2522 
2523  foreach(lc, root->append_rel_list)
2524  {
2525  AppendRelInfo *appinfo = lfirst(lc);
2526 
2527  if (bms_is_member(appinfo->child_relid, relids))
2528  {
2529  appinfos[cnt] = appinfo;
2530  cnt++;
2531 
2532  /* Stop when we have gathered all the AppendRelInfos. */
2533  if (cnt == *nappinfos)
2534  return appinfos;
2535  }
2536  }
2537 
2538  /* Should have found the entries ... */
2539  elog(ERROR, "did not find all requested child rels in append_rel_list");
2540  return NULL; /* not reached */
2541 }
#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:848
#define elog
Definition: elog.h:219
Index child_relid
Definition: relation.h:2066
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:420
static List * generate_append_tlist ( List colTypes,
List colCollations,
bool  flag,
List input_tlists,
List refnames_tlist 
)
static

Definition at line 1171 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().

1175 {
1176  List *tlist = NIL;
1177  int resno = 1;
1178  ListCell *curColType;
1179  ListCell *curColCollation;
1180  ListCell *ref_tl_item;
1181  int colindex;
1182  TargetEntry *tle;
1183  Node *expr;
1184  ListCell *tlistl;
1185  int32 *colTypmods;
1186 
1187  /*
1188  * First extract typmods to use.
1189  *
1190  * If the inputs all agree on type and typmod of a particular column, use
1191  * that typmod; else use -1.
1192  */
1193  colTypmods = (int32 *) palloc(list_length(colTypes) * sizeof(int32));
1194 
1195  foreach(tlistl, input_tlists)
1196  {
1197  List *subtlist = (List *) lfirst(tlistl);
1198  ListCell *subtlistl;
1199 
1200  curColType = list_head(colTypes);
1201  colindex = 0;
1202  foreach(subtlistl, subtlist)
1203  {
1204  TargetEntry *subtle = (TargetEntry *) lfirst(subtlistl);
1205 
1206  if (subtle->resjunk)
1207  continue;
1208  Assert(curColType != NULL);
1209  if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))
1210  {
1211  /* If first subplan, copy the typmod; else compare */
1212  int32 subtypmod = exprTypmod((Node *) subtle->expr);
1213 
1214  if (tlistl == list_head(input_tlists))
1215  colTypmods[colindex] = subtypmod;
1216  else if (subtypmod != colTypmods[colindex])
1217  colTypmods[colindex] = -1;
1218  }
1219  else
1220  {
1221  /* types disagree, so force typmod to -1 */
1222  colTypmods[colindex] = -1;
1223  }
1224  curColType = lnext(curColType);
1225  colindex++;
1226  }
1227  Assert(curColType == NULL);
1228  }
1229 
1230  /*
1231  * Now we can build the tlist for the Append.
1232  */
1233  colindex = 0;
1234  forthree(curColType, colTypes, curColCollation, colCollations,
1235  ref_tl_item, refnames_tlist)
1236  {
1237  Oid colType = lfirst_oid(curColType);
1238  int32 colTypmod = colTypmods[colindex++];
1239  Oid colColl = lfirst_oid(curColCollation);
1240  TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);
1241 
1242  Assert(reftle->resno == resno);
1243  Assert(!reftle->resjunk);
1244  expr = (Node *) makeVar(0,
1245  resno,
1246  colType,
1247  colTypmod,
1248  colColl,
1249  0);
1250  tle = makeTargetEntry((Expr *) expr,
1251  (AttrNumber) resno++,
1252  pstrdup(reftle->resname),
1253  false);
1254 
1255  /*
1256  * By convention, all non-resjunk columns in a setop tree have
1257  * ressortgroupref equal to their resno. In some cases the ref isn't
1258  * needed, but this is a cleaner way than modifying the tlist later.
1259  */
1260  tle->ressortgroupref = tle->resno;
1261 
1262  tlist = lappend(tlist, tle);
1263  }
1264 
1265  if (flag)
1266  {
1267  /* Add a resjunk flag column */
1268  /* flag value is shown as copied up from subplan */
1269  expr = (Node *) makeVar(0,
1270  resno,
1271  INT4OID,
1272  -1,
1273  InvalidOid,
1274  0);
1275  tle = makeTargetEntry((Expr *) expr,
1276  (AttrNumber) resno++,
1277  pstrdup("flag"),
1278  true);
1279  tlist = lappend(tlist, tle);
1280  }
1281 
1282  pfree(colTypmods);
1283 
1284  return tlist;
1285 }
#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:1076
#define INT4OID
Definition: pg_type.h:316
Definition: nodes.h:510
unsigned int Oid
Definition: postgres_ext.h:31
char * resname
Definition: primnodes.h:1370
signed int int32
Definition: c.h:246
void pfree(void *pointer)
Definition: mcxt.c:949
bool resjunk
Definition: primnodes.h:1375
char * flag(int b)
Definition: test-ctype.c:33
AttrNumber resno
Definition: primnodes.h:1369
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:235
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:681
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1368
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:848
Index ressortgroupref
Definition: primnodes.h:1371
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
#define lfirst_oid(lc)
Definition: pg_list.h:108
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, NULL, 0, NIL);
706 
707  /* We have to manually jam the right tlist into the path; ick */
708  path->pathtarget = create_pathtarget(root, tlist);
709 
710  /* Identify the grouping semantics */
711  groupList = generate_setop_grouplist(op, tlist);
712 
713  /* punt if nothing to group on (can this happen?) */
714  if (groupList == NIL)
715  return path;
716 
717  /*
718  * Estimate number of distinct groups that we'll need hashtable entries
719  * for; this is the size of the left-hand input for EXCEPT, or the smaller
720  * input for INTERSECT. Also estimate the number of eventual output rows.
721  * In non-ALL cases, we estimate each group produces one output row; in
722  * ALL cases use the relevant relation size. These are worst-case
723  * estimates, of course, but we need to be conservative.
724  */
725  if (op->op == SETOP_EXCEPT)
726  {
727  dNumGroups = dLeftGroups;
728  dNumOutputRows = op->all ? lpath->rows : dNumGroups;
729  }
730  else
731  {
732  dNumGroups = Min(dLeftGroups, dRightGroups);
733  dNumOutputRows = op->all ? Min(lpath->rows, rpath->rows) : dNumGroups;
734  }
735 
736  /*
737  * Decide whether to hash or sort, and add a sort node if needed.
738  */
739  use_hash = choose_hashed_setop(root, groupList, path,
740  dNumGroups, dNumOutputRows,
741  (op->op == SETOP_INTERSECT) ? "INTERSECT" : "EXCEPT");
742 
743  if (!use_hash)
744  path = (Path *) create_sort_path(root,
745  result_rel,
746  path,
748  groupList,
749  tlist),
750  -1.0);
751 
752  /*
753  * Finally, add a SetOp path node to generate the correct output.
754  */
755  switch (op->op)
756  {
757  case SETOP_INTERSECT:
759  break;
760  case SETOP_EXCEPT:
762  break;
763  default:
764  elog(ERROR, "unrecognized set op: %d", (int) op->op);
765  cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */
766  break;
767  }
768  path = (Path *) create_setop_path(root,
769  result_rel,
770  path,
771  cmd,
772  use_hash ? SETOP_HASHED : SETOP_SORTED,
773  groupList,
774  list_length(op->colTypes) + 1,
775  use_hash ? firstFlag : -1,
776  dNumGroups,
777  dNumOutputRows);
778 
779  if (pNumGroups)
780  *pNumGroups = dNumGroups;
781 
782  return path;
783 }
#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:1171
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:3017
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:1299
#define Min(x, y)
Definition: c.h:812
AppendPath * create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer, int parallel_workers, List *partitioned_rels)
Definition: pathnode.c:1211
static bool choose_hashed_setop(PlannerInfo *root, List *groupClauses, Path *input_path, double dNumGroups, double dNumOutputRows, const char *construct)
Definition: prepunion.c:923
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:1138
#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:1583
SortPath * create_sort_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath, List *pathkeys, double limit_tuples)
Definition: pathnode.c:2521
double rows
Definition: relation.h:1052
static int list_length(const List *l)
Definition: pg_list.h:89
SetOperation op
Definition: parsenodes.h:1574
SetOpCmd
Definition: nodes.h:780
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
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:1171
static List * generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
Definition: prepunion.c:1299
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:3079
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1138
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:1583
#define Assert(condition)
Definition: c.h:681
double rows
Definition: relation.h:1052
struct Path * non_recursive_path
Definition: relation.h:312
SetOperation op
Definition: parsenodes.h:1574
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
static List * generate_setop_grouplist ( SetOperationStmt op,
List targetlist 
)
static

Definition at line 1299 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().

1300 {
1301  List *grouplist = copyObject(op->groupClauses);
1302  ListCell *lg;
1303  ListCell *lt;
1304 
1305  lg = list_head(grouplist);
1306  foreach(lt, targetlist)
1307  {
1308  TargetEntry *tle = (TargetEntry *) lfirst(lt);
1309  SortGroupClause *sgc;
1310 
1311  if (tle->resjunk)
1312  {
1313  /* resjunk columns should not have sortgrouprefs */
1314  Assert(tle->ressortgroupref == 0);
1315  continue; /* ignore resjunk columns */
1316  }
1317 
1318  /* non-resjunk columns should have sortgroupref = resno */
1319  Assert(tle->ressortgroupref == tle->resno);
1320 
1321  /* non-resjunk columns should have grouping clauses */
1322  Assert(lg != NULL);
1323  sgc = (SortGroupClause *) lfirst(lg);
1324  lg = lnext(lg);
1325  Assert(sgc->tleSortGroupRef == 0);
1326 
1327  sgc->tleSortGroupRef = tle->ressortgroupref;
1328  }
1329  Assert(lg == NULL);
1330  return grouplist;
1331 }
Index tleSortGroupRef
Definition: parsenodes.h:1190
bool resjunk
Definition: primnodes.h:1375
AttrNumber resno
Definition: primnodes.h:1369
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:681
#define lfirst(lc)
Definition: pg_list.h:106
Index ressortgroupref
Definition: primnodes.h:1371
#define copyObject(obj)
Definition: nodes.h:623
Definition: pg_list.h:45
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 1026 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().

1032 {
1033  List *tlist = NIL;
1034  int resno = 1;
1035  ListCell *ctlc,
1036  *cclc,
1037  *itlc,
1038  *rtlc;
1039  TargetEntry *tle;
1040  Node *expr;
1041 
1042  /* there's no forfour() so we must chase one list manually */
1043  rtlc = list_head(refnames_tlist);
1044  forthree(ctlc, colTypes, cclc, colCollations, itlc, input_tlist)
1045  {
1046  Oid colType = lfirst_oid(ctlc);
1047  Oid colColl = lfirst_oid(cclc);
1048  TargetEntry *inputtle = (TargetEntry *) lfirst(itlc);
1049  TargetEntry *reftle = (TargetEntry *) lfirst(rtlc);
1050 
1051  rtlc = lnext(rtlc);
1052 
1053  Assert(inputtle->resno == resno);
1054  Assert(reftle->resno == resno);
1055  Assert(!inputtle->resjunk);
1056  Assert(!reftle->resjunk);
1057 
1058  /*
1059  * Generate columns referencing input columns and having appropriate
1060  * data types and column names. Insert datatype coercions where
1061  * necessary.
1062  *
1063  * HACK: constants in the input's targetlist are copied up as-is
1064  * rather than being referenced as subquery outputs. This is mainly
1065  * to ensure that when we try to coerce them to the output column's
1066  * datatype, the right things happen for UNKNOWN constants. But do
1067  * this only at the first level of subquery-scan plans; we don't want
1068  * phony constants appearing in the output tlists of upper-level
1069  * nodes!
1070  */
1071  if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
1072  expr = (Node *) inputtle->expr;
1073  else
1074  expr = (Node *) makeVar(varno,
1075  inputtle->resno,
1076  exprType((Node *) inputtle->expr),
1077  exprTypmod((Node *) inputtle->expr),
1078  exprCollation((Node *) inputtle->expr),
1079  0);
1080 
1081  if (exprType(expr) != colType)
1082  {
1083  /*
1084  * Note: it's not really cool to be applying coerce_to_common_type
1085  * here; one notable point is that assign_expr_collations never
1086  * gets run on any generated nodes. For the moment that's not a
1087  * problem because we force the correct exposed collation below.
1088  * It would likely be best to make the parser generate the correct
1089  * output tlist for every set-op to begin with, though.
1090  */
1091  expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */
1092  expr,
1093  colType,
1094  "UNION/INTERSECT/EXCEPT");
1095  }
1096 
1097  /*
1098  * Ensure the tlist entry's exposed collation matches the set-op. This
1099  * is necessary because plan_set_operations() reports the result
1100  * ordering as a list of SortGroupClauses, which don't carry collation
1101  * themselves but just refer to tlist entries. If we don't show the
1102  * right collation then planner.c might do the wrong thing in
1103  * higher-level queries.
1104  *
1105  * Note we use RelabelType, not CollateExpr, since this expression
1106  * will reach the executor without any further processing.
1107  */
1108  if (exprCollation(expr) != colColl)
1109  {
1110  expr = (Node *) makeRelabelType((Expr *) expr,
1111  exprType(expr),
1112  exprTypmod(expr),
1113  colColl,
1115  }
1116 
1117  tle = makeTargetEntry((Expr *) expr,
1118  (AttrNumber) resno++,
1119  pstrdup(reftle->resname),
1120  false);
1121 
1122  /*
1123  * By convention, all non-resjunk columns in a setop tree have
1124  * ressortgroupref equal to their resno. In some cases the ref isn't
1125  * needed, but this is a cleaner way than modifying the tlist later.
1126  */
1127  tle->ressortgroupref = tle->resno;
1128 
1129  tlist = lappend(tlist, tle);
1130  }
1131 
1132  if (flag >= 0)
1133  {
1134  /* Add a resjunk flag column */
1135  /* flag value is the given constant */
1136  expr = (Node *) makeConst(INT4OID,
1137  -1,
1138  InvalidOid,
1139  sizeof(int32),
1141  false,
1142  true);
1143  tle = makeTargetEntry((Expr *) expr,
1144  (AttrNumber) resno++,
1145  pstrdup("flag"),
1146  true);
1147  tlist = lappend(tlist, tle);
1148  }
1149 
1150  return tlist;
1151 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
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:1076
#define INT4OID
Definition: pg_type.h:316
Definition: nodes.h:510
unsigned int Oid
Definition: postgres_ext.h:31
char * resname
Definition: primnodes.h:1370
Const * makeConst(Oid consttype, int32 consttypmod, Oid constcollid, int constlen, Datum constvalue, bool constisnull, bool constbyval)
Definition: makefuncs.c:296
signed int int32
Definition: c.h:246
bool resjunk
Definition: primnodes.h:1375
RelabelType * makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, Oid rcollid, CoercionForm rformat)
Definition: makefuncs.c:399
char * flag(int b)
Definition: test-ctype.c:33
AttrNumber resno
Definition: primnodes.h:1369
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:235
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:681
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1368
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:1371
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
#define lfirst_oid(lc)
Definition: pg_list.h:108
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, NULL, 0, NIL);
594 
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:1171
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:799
static Path * make_union_unique(SetOperationStmt *op, Path *path, List *tlist, PlannerInfo *root)
Definition: prepunion.c:856
List * list_concat(List *list1, List *list2)
Definition: list.c:321
AppendPath * create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer, int parallel_workers, List *partitioned_rels)
Definition: pathnode.c:1211
double tuple_fraction
Definition: relation.h:294
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1138
#define create_pathtarget(root, tlist)
Definition: tlist.h:69
List * colCollations
Definition: parsenodes.h:1583
double rows
Definition: relation.h:1052
Definition: pg_list.h:45
static void make_inh_translation_list ( Relation  oldrelation,
Relation  newrelation,
Index  newvarno,
List **  translated_vars 
)
static

Definition at line 1782 of file prepunion.c.

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

Referenced by expand_single_inheritance_child().

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

Definition at line 856 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().

858 {
859  RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
860  List *groupList;
861  double dNumGroups;
862 
863  /* Identify the grouping semantics */
864  groupList = generate_setop_grouplist(op, tlist);
865 
866  /* punt if nothing to group on (can this happen?) */
867  if (groupList == NIL)
868  return path;
869 
870  /*
871  * XXX for the moment, take the number of distinct groups as equal to the
872  * total input size, ie, the worst case. This is too conservative, but we
873  * don't want to risk having the hashtable overrun memory; also, it's not
874  * clear how to get a decent estimate of the true size. One should note
875  * as well the propensity of novices to write UNION rather than UNION ALL
876  * even when they don't expect any duplicates...
877  */
878  dNumGroups = path->rows;
879 
880  /* Decide whether to hash or sort */
881  if (choose_hashed_setop(root, groupList, path,
882  dNumGroups, dNumGroups,
883  "UNION"))
884  {
885  /* Hashed aggregate plan --- no sort needed */
886  path = (Path *) create_agg_path(root,
887  result_rel,
888  path,
889  create_pathtarget(root, tlist),
890  AGG_HASHED,
892  groupList,
893  NIL,
894  NULL,
895  dNumGroups);
896  }
897  else
898  {
899  /* Sort and Unique */
900  path = (Path *) create_sort_path(root,
901  result_rel,
902  path,
904  groupList,
905  tlist),
906  -1.0);
907  /* We have to manually jam the right tlist into the path; ick */
908  path->pathtarget = create_pathtarget(root, tlist);
909  path = (Path *) create_upper_unique_path(root,
910  result_rel,
911  path,
912  list_length(path->pathkeys),
913  dNumGroups);
914  }
915 
916  return path;
917 }
#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:2623
static List * generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
Definition: prepunion.c:1299
static bool choose_hashed_setop(PlannerInfo *root, List *groupClauses, Path *input_path, double dNumGroups, double dNumOutputRows, const char *construct)
Definition: prepunion.c:923
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:1138
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:2675
#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:2521
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
RelOptInfo* plan_set_operations ( PlannerInfo root)

Definition at line 143 of file prepunion.c.

References add_path(), Assert, castNode, SetOperationStmt::colCollations, SetOperationStmt::colTypes, 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:561
Query * parse
Definition: relation.h:155
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:420
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:579
Definition: nodes.h:510
List * fromlist
Definition: primnodes.h:1471
create_upper_paths_hook_type create_upper_paths_hook
Definition: planner.c:69
bool hasRecursion
Definition: relation.h:308
Node * quals
Definition: primnodes.h:1472
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:1138
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:242
List * colCollations
Definition: parsenodes.h:1583
#define Assert(condition)
Definition: c.h:681
void setup_simple_rel_arrays(PlannerInfo *root)
Definition: relnode.c:67
Node * setOperations
Definition: parsenodes.h:163
Query * subquery
Definition: parsenodes.h:968
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
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:2378
void set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel)
Definition: costsize.c:4553
#define NIL
Definition: pg_list.h:69
double estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows, List **pgset)
Definition: selfuncs.c:3360
#define IsA(nodeptr, _type_)
Definition: nodes.h:561
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:1777
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:1138
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:681
double rows
Definition: relation.h:1052
SetOperation op
Definition: parsenodes.h:1574
#define nodeTag(nodeptr)
Definition: nodes.h:515
Query * subquery
Definition: parsenodes.h:968
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:508
Datum subpath(PG_FUNCTION_ARGS)
Definition: ltree_op.c:234
Path * get_cheapest_fractional_path(RelOptInfo *rel, double tuple_fraction)
Definition: planner.c:5844
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:1026
static List * recurse_union_children ( Node setOp,
PlannerInfo root,
SetOperationStmt top_union,
List refnames_tlist,
List **  tlist_list 
)
static

Definition at line 799 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().

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

Definition at line 1889 of file prepunion.c.

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

Referenced by expand_single_inheritance_child().

1891 {
1892  Bitmapset *child_privs = NULL;
1893  bool whole_row;
1894  int attno;
1895  ListCell *lc;
1896 
1897  /* System attributes have the same numbers in all tables */
1898  for (attno = FirstLowInvalidHeapAttributeNumber + 1; attno < 0; attno++)
1899  {
1901  parent_privs))
1902  child_privs = bms_add_member(child_privs,
1904  }
1905 
1906  /* Check if parent has whole-row reference */
1908  parent_privs);
1909 
1910  /* And now translate the regular user attributes, using the vars list */
1911  attno = InvalidAttrNumber;
1912  foreach(lc, translated_vars)
1913  {
1914  Var *var = lfirst_node(Var, lc);
1915 
1916  attno++;
1917  if (var == NULL) /* ignore dropped columns */
1918  continue;
1919  if (whole_row ||
1921  parent_privs))
1922  child_privs = bms_add_member(child_privs,
1924  }
1925 
1926  return child_privs;
1927 }
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