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/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 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_relid_set (Relids relids, Index oldrelid, Index newrelid)
 
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, AppendRelInfo *appinfo)
 
Nodeadjust_appendrel_attrs_multilevel (PlannerInfo *root, Node *node, RelOptInfo *child_rel)
 

Function Documentation

Node* adjust_appendrel_attrs ( PlannerInfo root,
Node node,
AppendRelInfo appinfo 
)

Definition at line 1782 of file prepunion.c.

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

Referenced by add_child_rel_equivalences(), adjust_appendrel_attrs_multilevel(), inheritance_planner(), and set_append_rel_size().

1783 {
1784  Node *result;
1786 
1787  context.root = root;
1788  context.appinfo = appinfo;
1789 
1790  /*
1791  * Must be prepared to start with a Query or a bare expression tree.
1792  */
1793  if (node && IsA(node, Query))
1794  {
1795  Query *newnode;
1796 
1797  newnode = query_tree_mutator((Query *) node,
1799  (void *) &context,
1801  if (newnode->resultRelation == appinfo->parent_relid)
1802  {
1803  newnode->resultRelation = appinfo->child_relid;
1804  /* Fix tlist resnos too, if it's inherited UPDATE */
1805  if (newnode->commandType == CMD_UPDATE)
1806  newnode->targetList =
1808  appinfo);
1809  }
1810  result = (Node *) newnode;
1811  }
1812  else
1813  result = adjust_appendrel_attrs_mutator(node, &context);
1814 
1815  return result;
1816 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
int resultRelation
Definition: parsenodes.h:120
Definition: nodes.h:509
return result
Definition: formatting.c:1618
static List * adjust_inherited_tlist(List *tlist, AppendRelInfo *context)
Definition: prepunion.c:2061
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:1819
Index child_relid
Definition: relation.h:1975
Index parent_relid
Definition: relation.h:1974
Query * query_tree_mutator(Query *query, Node *(*mutator)(), void *context, int flags)
Definition: nodeFuncs.c:3089
Node* adjust_appendrel_attrs_multilevel ( PlannerInfo root,
Node node,
RelOptInfo child_rel 
)

Definition at line 2149 of file prepunion.c.

References adjust_appendrel_attrs(), adjust_appendrel_attrs_multilevel(), Assert, find_base_rel(), find_childrel_appendrelinfo(), IS_OTHER_REL, AppendRelInfo::parent_relid, RELOPT_BASEREL, and RelOptInfo::reloptkind.

Referenced by adjust_appendrel_attrs_multilevel(), and generate_join_implied_equalities_broken().

2151 {
2152  AppendRelInfo *appinfo = find_childrel_appendrelinfo(root, child_rel);
2153  RelOptInfo *parent_rel = find_base_rel(root, appinfo->parent_relid);
2154 
2155  /* If parent is also a child, first recurse to apply its translations */
2156  if (IS_OTHER_REL(parent_rel))
2157  node = adjust_appendrel_attrs_multilevel(root, node, parent_rel);
2158  else
2159  Assert(parent_rel->reloptkind == RELOPT_BASEREL);
2160  /* Now translate for this child */
2161  return adjust_appendrel_attrs(root, node, appinfo);
2162 }
RelOptKind reloptkind
Definition: relation.h:521
#define IS_OTHER_REL(rel)
Definition: relation.h:515
AppendRelInfo * find_childrel_appendrelinfo(PlannerInfo *root, RelOptInfo *rel)
Definition: relnode.c:970
Node * adjust_appendrel_attrs(PlannerInfo *root, Node *node, AppendRelInfo *appinfo)
Definition: prepunion.c:1782
#define Assert(condition)
Definition: c.h:675
Node * adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node, RelOptInfo *child_rel)
Definition: prepunion.c:2149
RelOptInfo * find_base_rel(PlannerInfo *root, int relid)
Definition: relnode.c:243
Index parent_relid
Definition: relation.h:1974
static Node * adjust_appendrel_attrs_mutator ( Node node,
adjust_appendrel_attrs_context context 
)
static

Definition at line 1819 of file prepunion.c.

References adjust_relid_set(), adjust_appendrel_attrs_context::appinfo, 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_relids, list_length(), list_nth(), ConvertRowtypeExpr::location, RowExpr::location, makeNode, NIL, RestrictInfo::norm_selec, NULL, 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_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().

1821 {
1822  AppendRelInfo *appinfo = context->appinfo;
1823 
1824  if (node == NULL)
1825  return NULL;
1826  if (IsA(node, Var))
1827  {
1828  Var *var = (Var *) copyObject(node);
1829 
1830  if (var->varlevelsup == 0 &&
1831  var->varno == appinfo->parent_relid)
1832  {
1833  var->varno = appinfo->child_relid;
1834  var->varnoold = appinfo->child_relid;
1835  if (var->varattno > 0)
1836  {
1837  Node *newnode;
1838 
1839  if (var->varattno > list_length(appinfo->translated_vars))
1840  elog(ERROR, "attribute %d of relation \"%s\" does not exist",
1841  var->varattno, get_rel_name(appinfo->parent_reloid));
1842  newnode = copyObject(list_nth(appinfo->translated_vars,
1843  var->varattno - 1));
1844  if (newnode == NULL)
1845  elog(ERROR, "attribute %d of relation \"%s\" does not exist",
1846  var->varattno, get_rel_name(appinfo->parent_reloid));
1847  return newnode;
1848  }
1849  else if (var->varattno == 0)
1850  {
1851  /*
1852  * Whole-row Var: if we are dealing with named rowtypes, we
1853  * can use a whole-row Var for the child table plus a coercion
1854  * step to convert the tuple layout to the parent's rowtype.
1855  * Otherwise we have to generate a RowExpr.
1856  */
1857  if (OidIsValid(appinfo->child_reltype))
1858  {
1859  Assert(var->vartype == appinfo->parent_reltype);
1860  if (appinfo->parent_reltype != appinfo->child_reltype)
1861  {
1863 
1864  r->arg = (Expr *) var;
1865  r->resulttype = appinfo->parent_reltype;
1867  r->location = -1;
1868  /* Make sure the Var node has the right type ID, too */
1869  var->vartype = appinfo->child_reltype;
1870  return (Node *) r;
1871  }
1872  }
1873  else
1874  {
1875  /*
1876  * Build a RowExpr containing the translated variables.
1877  *
1878  * In practice var->vartype will always be RECORDOID here,
1879  * so we need to come up with some suitable column names.
1880  * We use the parent RTE's column names.
1881  *
1882  * Note: we can't get here for inheritance cases, so there
1883  * is no need to worry that translated_vars might contain
1884  * some dummy NULLs.
1885  */
1886  RowExpr *rowexpr;
1887  List *fields;
1888  RangeTblEntry *rte;
1889 
1890  rte = rt_fetch(appinfo->parent_relid,
1891  context->root->parse->rtable);
1892  fields = copyObject(appinfo->translated_vars);
1893  rowexpr = makeNode(RowExpr);
1894  rowexpr->args = fields;
1895  rowexpr->row_typeid = var->vartype;
1896  rowexpr->row_format = COERCE_IMPLICIT_CAST;
1897  rowexpr->colnames = copyObject(rte->eref->colnames);
1898  rowexpr->location = -1;
1899 
1900  return (Node *) rowexpr;
1901  }
1902  }
1903  /* system attributes don't need any other translation */
1904  }
1905  return (Node *) var;
1906  }
1907  if (IsA(node, CurrentOfExpr))
1908  {
1909  CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node);
1910 
1911  if (cexpr->cvarno == appinfo->parent_relid)
1912  cexpr->cvarno = appinfo->child_relid;
1913  return (Node *) cexpr;
1914  }
1915  if (IsA(node, RangeTblRef))
1916  {
1917  RangeTblRef *rtr = (RangeTblRef *) copyObject(node);
1918 
1919  if (rtr->rtindex == appinfo->parent_relid)
1920  rtr->rtindex = appinfo->child_relid;
1921  return (Node *) rtr;
1922  }
1923  if (IsA(node, JoinExpr))
1924  {
1925  /* Copy the JoinExpr node with correct mutation of subnodes */
1926  JoinExpr *j;
1927 
1928  j = (JoinExpr *) expression_tree_mutator(node,
1930  (void *) context);
1931  /* now fix JoinExpr's rtindex (probably never happens) */
1932  if (j->rtindex == appinfo->parent_relid)
1933  j->rtindex = appinfo->child_relid;
1934  return (Node *) j;
1935  }
1936  if (IsA(node, PlaceHolderVar))
1937  {
1938  /* Copy the PlaceHolderVar node with correct mutation of subnodes */
1939  PlaceHolderVar *phv;
1940 
1941  phv = (PlaceHolderVar *) expression_tree_mutator(node,
1943  (void *) context);
1944  /* now fix PlaceHolderVar's relid sets */
1945  if (phv->phlevelsup == 0)
1946  phv->phrels = adjust_relid_set(phv->phrels,
1947  appinfo->parent_relid,
1948  appinfo->child_relid);
1949  return (Node *) phv;
1950  }
1951  /* Shouldn't need to handle planner auxiliary nodes here */
1952  Assert(!IsA(node, SpecialJoinInfo));
1953  Assert(!IsA(node, AppendRelInfo));
1954  Assert(!IsA(node, PlaceHolderInfo));
1955  Assert(!IsA(node, MinMaxAggInfo));
1956 
1957  /*
1958  * We have to process RestrictInfo nodes specially. (Note: although
1959  * set_append_rel_pathlist will hide RestrictInfos in the parent's
1960  * baserestrictinfo list from us, it doesn't hide those in joininfo.)
1961  */
1962  if (IsA(node, RestrictInfo))
1963  {
1964  RestrictInfo *oldinfo = (RestrictInfo *) node;
1965  RestrictInfo *newinfo = makeNode(RestrictInfo);
1966 
1967  /* Copy all flat-copiable fields */
1968  memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
1969 
1970  /* Recursively fix the clause itself */
1971  newinfo->clause = (Expr *)
1972  adjust_appendrel_attrs_mutator((Node *) oldinfo->clause, context);
1973 
1974  /* and the modified version, if an OR clause */
1975  newinfo->orclause = (Expr *)
1976  adjust_appendrel_attrs_mutator((Node *) oldinfo->orclause, context);
1977 
1978  /* adjust relid sets too */
1979  newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids,
1980  appinfo->parent_relid,
1981  appinfo->child_relid);
1982  newinfo->required_relids = adjust_relid_set(oldinfo->required_relids,
1983  appinfo->parent_relid,
1984  appinfo->child_relid);
1985  newinfo->outer_relids = adjust_relid_set(oldinfo->outer_relids,
1986  appinfo->parent_relid,
1987  appinfo->child_relid);
1988  newinfo->nullable_relids = adjust_relid_set(oldinfo->nullable_relids,
1989  appinfo->parent_relid,
1990  appinfo->child_relid);
1991  newinfo->left_relids = adjust_relid_set(oldinfo->left_relids,
1992  appinfo->parent_relid,
1993  appinfo->child_relid);
1994  newinfo->right_relids = adjust_relid_set(oldinfo->right_relids,
1995  appinfo->parent_relid,
1996  appinfo->child_relid);
1997 
1998  /*
1999  * Reset cached derivative fields, since these might need to have
2000  * different values when considering the child relation. Note we
2001  * don't reset left_ec/right_ec: each child variable is implicitly
2002  * equivalent to its parent, so still a member of the same EC if any.
2003  */
2004  newinfo->eval_cost.startup = -1;
2005  newinfo->norm_selec = -1;
2006  newinfo->outer_selec = -1;
2007  newinfo->left_em = NULL;
2008  newinfo->right_em = NULL;
2009  newinfo->scansel_cache = NIL;
2010  newinfo->left_bucketsize = -1;
2011  newinfo->right_bucketsize = -1;
2012 
2013  return (Node *) newinfo;
2014  }
2015 
2016  /*
2017  * NOTE: we do not need to recurse into sublinks, because they should
2018  * already have been converted to subplans before we see them.
2019  */
2020  Assert(!IsA(node, SubLink));
2021  Assert(!IsA(node, Query));
2022 
2024  (void *) context);
2025 }
QualCost eval_cost
Definition: relation.h:1783
#define NIL
Definition: pg_list.h:69
List * args
Definition: primnodes.h:985
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Query * parse
Definition: relation.h:154
Index varlevelsup
Definition: primnodes.h:173
Node * expression_tree_mutator(Node *node, Node *(*mutator)(), void *context)
Definition: nodeFuncs.c:2431
Relids required_relids
Definition: relation.h:1764
List * colnames
Definition: primnodes.h:43
Expr * orclause
Definition: relation.h:1777
Relids clause_relids
Definition: relation.h:1761
Definition: nodes.h:509
Relids left_relids
Definition: relation.h:1773
AttrNumber varattno
Definition: primnodes.h:168
static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid)
Definition: prepunion.c:2031
Definition: primnodes.h:163
#define OidIsValid(objectId)
Definition: c.h:538
List * translated_vars
Definition: relation.h:2002
Oid parent_reltype
Definition: relation.h:1983
Cost startup
Definition: relation.h:45
Relids outer_relids
Definition: relation.h:1767
Selectivity norm_selec
Definition: relation.h:1784
Index varnoold
Definition: primnodes.h:176
List * rtable
Definition: parsenodes.h:135
Relids phrels
Definition: relation.h:1850
#define ERROR
Definition: elog.h:43
List * colnames
Definition: primnodes.h:998
Oid vartype
Definition: primnodes.h:170
EquivalenceMember * left_em
Definition: relation.h:1796
int location
Definition: primnodes.h:999
void * list_nth(const List *list, int n)
Definition: list.c:410
Selectivity outer_selec
Definition: relation.h:1787
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
EquivalenceMember * right_em
Definition: relation.h:1797
Expr * clause
Definition: relation.h:1746
Index varno
Definition: primnodes.h:166
Relids nullable_relids
Definition: relation.h:1770
CoercionForm convertformat
Definition: primnodes.h:861
Selectivity left_bucketsize
Definition: relation.h:1807
#define makeNode(_type_)
Definition: nodes.h:557
Relids right_relids
Definition: relation.h:1774
static Node * adjust_appendrel_attrs_mutator(Node *node, adjust_appendrel_attrs_context *context)
Definition: prepunion.c:1819
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
Oid row_typeid
Definition: primnodes.h:986
static int list_length(const List *l)
Definition: pg_list.h:89
Oid child_reltype
Definition: relation.h:1984
Index phlevelsup
Definition: relation.h:1852
Selectivity right_bucketsize
Definition: relation.h:1808
#define elog
Definition: elog.h:219
Index child_relid
Definition: relation.h:1975
Alias * eref
Definition: parsenodes.h:1015
Oid parent_reloid
Definition: relation.h:2009
#define copyObject(obj)
Definition: nodes.h:621
Index parent_relid
Definition: relation.h:1974
CoercionForm row_format
Definition: primnodes.h:997
int rtindex
Definition: primnodes.h:1455
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
List * scansel_cache
Definition: relation.h:1798
static List * adjust_inherited_tlist ( List tlist,
AppendRelInfo context 
)
static

Definition at line 2061 of file prepunion.c.

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

Referenced by adjust_appendrel_attrs().

2062 {
2063  bool changed_it = false;
2064  ListCell *tl;
2065  List *new_tlist;
2066  bool more;
2067  int attrno;
2068 
2069  /* This should only happen for an inheritance case, not UNION ALL */
2070  Assert(OidIsValid(context->parent_reloid));
2071 
2072  /* Scan tlist and update resnos to match attnums of child rel */
2073  foreach(tl, tlist)
2074  {
2075  TargetEntry *tle = (TargetEntry *) lfirst(tl);
2076  Var *childvar;
2077 
2078  if (tle->resjunk)
2079  continue; /* ignore junk items */
2080 
2081  /* Look up the translation of this column: it must be a Var */
2082  if (tle->resno <= 0 ||
2083  tle->resno > list_length(context->translated_vars))
2084  elog(ERROR, "attribute %d of relation \"%s\" does not exist",
2085  tle->resno, get_rel_name(context->parent_reloid));
2086  childvar = (Var *) list_nth(context->translated_vars, tle->resno - 1);
2087  if (childvar == NULL || !IsA(childvar, Var))
2088  elog(ERROR, "attribute %d of relation \"%s\" does not exist",
2089  tle->resno, get_rel_name(context->parent_reloid));
2090 
2091  if (tle->resno != childvar->varattno)
2092  {
2093  tle->resno = childvar->varattno;
2094  changed_it = true;
2095  }
2096  }
2097 
2098  /*
2099  * If we changed anything, re-sort the tlist by resno, and make sure
2100  * resjunk entries have resnos above the last real resno. The sort
2101  * algorithm is a bit stupid, but for such a seldom-taken path, small is
2102  * probably better than fast.
2103  */
2104  if (!changed_it)
2105  return tlist;
2106 
2107  new_tlist = NIL;
2108  more = true;
2109  for (attrno = 1; more; attrno++)
2110  {
2111  more = false;
2112  foreach(tl, tlist)
2113  {
2114  TargetEntry *tle = (TargetEntry *) lfirst(tl);
2115 
2116  if (tle->resjunk)
2117  continue; /* ignore junk items */
2118 
2119  if (tle->resno == attrno)
2120  new_tlist = lappend(new_tlist, tle);
2121  else if (tle->resno > attrno)
2122  more = true;
2123  }
2124  }
2125 
2126  foreach(tl, tlist)
2127  {
2128  TargetEntry *tle = (TargetEntry *) lfirst(tl);
2129 
2130  if (!tle->resjunk)
2131  continue; /* here, ignore non-junk items */
2132 
2133  tle->resno = attrno;
2134  new_tlist = lappend(new_tlist, tle);
2135  attrno++;
2136  }
2137 
2138  return new_tlist;
2139 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
AttrNumber varattno
Definition: primnodes.h:168
Definition: primnodes.h:163
#define OidIsValid(objectId)
Definition: c.h:538
List * translated_vars
Definition: relation.h:2002
bool resjunk
Definition: primnodes.h:1374
#define ERROR
Definition: elog.h:43
void * list_nth(const List *list, int n)
Definition: list.c:410
AttrNumber resno
Definition: primnodes.h:1368
List * lappend(List *list, void *datum)
Definition: list.c:128
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#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:2009
Definition: pg_list.h:45
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
static Relids adjust_relid_set ( Relids  relids,
Index  oldrelid,
Index  newrelid 
)
static

Definition at line 2031 of file prepunion.c.

References bms_add_member(), bms_copy(), bms_del_member(), and bms_is_member().

Referenced by adjust_appendrel_attrs_mutator().

2032 {
2033  if (bms_is_member(oldrelid, relids))
2034  {
2035  /* Ensure we have a modifiable copy */
2036  relids = bms_copy(relids);
2037  /* Remove old, add new */
2038  relids = bms_del_member(relids, oldrelid);
2039  relids = bms_add_member(relids, newrelid);
2040  }
2041  return relids;
2042 }
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:111
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:698
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
static bool choose_hashed_setop ( PlannerInfo root,
List groupClauses,
Path input_path,
double  dNumGroups,
double  dNumOutputRows,
const char *  construct 
)
static

Definition at line 909 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, NULL, 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().

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

Definition at line 1367 of file prepunion.c.

References AccessShareLock, PlanRowMark::allMarkTypes, PlannerInfo::append_rel_list, Assert, AppendRelInfo::child_relid, PartitionedChildRelInfo::child_rels, AppendRelInfo::child_reltype, copyObject, find_all_inheritors(), get_plan_rowmark(), has_subclass(), heap_close, heap_open(), RangeTblEntry::inh, RangeTblEntry::insertedCols, PlanRowMark::isParent, lappend(), lappend_int(), lfirst_oid, list_concat(), list_length(), make_inh_translation_list(), makeNode, PlanRowMark::markType, NIL, NoLock, NULL, AppendRelInfo::parent_relid, PartitionedChildRelInfo::parent_relid, AppendRelInfo::parent_reloid, AppendRelInfo::parent_reltype, parse(), PlannerInfo::parse, PlannerInfo::pcinfo_list, PlanRowMark::prti, RelationData::rd_rel, RELATION_IS_OTHER_TEMP, RangeTblEntry::relid, RangeTblEntry::relkind, RELKIND_PARTITIONED_TABLE, RangeTblEntry::requiredPerms, Query::resultRelation, RowExclusiveLock, PlanRowMark::rowmarkId, RowMarkRequiresRowShareLock, PlannerInfo::rowMarks, RowShareLock, Query::rtable, RTE_RELATION, RTE_SUBQUERY, RangeTblEntry::rtekind, 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_tables().

1368 {
1369  Query *parse = root->parse;
1370  Oid parentOID;
1371  PlanRowMark *oldrc;
1372  Relation oldrelation;
1373  LOCKMODE lockmode;
1374  List *inhOIDs;
1375  List *appinfos;
1376  ListCell *l;
1377  bool need_append;
1378  PartitionedChildRelInfo *pcinfo;
1379  List *partitioned_child_rels = NIL;
1380 
1381  /* Does RT entry allow inheritance? */
1382  if (!rte->inh)
1383  return;
1384  /* Ignore any already-expanded UNION ALL nodes */
1385  if (rte->rtekind != RTE_RELATION)
1386  {
1387  Assert(rte->rtekind == RTE_SUBQUERY);
1388  return;
1389  }
1390  /* Fast path for common case of childless table */
1391  parentOID = rte->relid;
1392  if (!has_subclass(parentOID))
1393  {
1394  /* Clear flag before returning */
1395  rte->inh = false;
1396  return;
1397  }
1398 
1399  /*
1400  * The rewriter should already have obtained an appropriate lock on each
1401  * relation named in the query. However, for each child relation we add
1402  * to the query, we must obtain an appropriate lock, because this will be
1403  * the first use of those relations in the parse/rewrite/plan pipeline.
1404  *
1405  * If the parent relation is the query's result relation, then we need
1406  * RowExclusiveLock. Otherwise, if it's accessed FOR UPDATE/SHARE, we
1407  * need RowShareLock; otherwise AccessShareLock. We can't just grab
1408  * AccessShareLock because then the executor would be trying to upgrade
1409  * the lock, leading to possible deadlocks. (This code should match the
1410  * parser and rewriter.)
1411  */
1412  oldrc = get_plan_rowmark(root->rowMarks, rti);
1413  if (rti == parse->resultRelation)
1414  lockmode = RowExclusiveLock;
1415  else if (oldrc && RowMarkRequiresRowShareLock(oldrc->markType))
1416  lockmode = RowShareLock;
1417  else
1418  lockmode = AccessShareLock;
1419 
1420  /* Scan for all members of inheritance set, acquire needed locks */
1421  inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
1422 
1423  /*
1424  * Check that there's at least one descendant, else treat as no-child
1425  * case. This could happen despite above has_subclass() check, if table
1426  * once had a child but no longer does.
1427  */
1428  if (list_length(inhOIDs) < 2)
1429  {
1430  /* Clear flag before returning */
1431  rte->inh = false;
1432  return;
1433  }
1434 
1435  /*
1436  * If parent relation is selected FOR UPDATE/SHARE, we need to mark its
1437  * PlanRowMark as isParent = true, and generate a new PlanRowMark for each
1438  * child.
1439  */
1440  if (oldrc)
1441  oldrc->isParent = true;
1442 
1443  /*
1444  * Must open the parent relation to examine its tupdesc. We need not lock
1445  * it; we assume the rewriter already did.
1446  */
1447  oldrelation = heap_open(parentOID, NoLock);
1448 
1449  /* Scan the inheritance set and expand it */
1450  appinfos = NIL;
1451  need_append = false;
1452  foreach(l, inhOIDs)
1453  {
1454  Oid childOID = lfirst_oid(l);
1455  Relation newrelation;
1456  RangeTblEntry *childrte;
1457  Index childRTindex;
1458  AppendRelInfo *appinfo;
1459 
1460  /* Open rel if needed; we already have required locks */
1461  if (childOID != parentOID)
1462  newrelation = heap_open(childOID, NoLock);
1463  else
1464  newrelation = oldrelation;
1465 
1466  /*
1467  * It is possible that the parent table has children that are temp
1468  * tables of other backends. We cannot safely access such tables
1469  * (because of buffering issues), and the best thing to do seems to be
1470  * to silently ignore them.
1471  */
1472  if (childOID != parentOID && RELATION_IS_OTHER_TEMP(newrelation))
1473  {
1474  heap_close(newrelation, lockmode);
1475  continue;
1476  }
1477 
1478  /*
1479  * Build an RTE for the child, and attach to query's rangetable list.
1480  * We copy most fields of the parent's RTE, but replace relation OID
1481  * and relkind, and set inh = false. Also, set requiredPerms to zero
1482  * since all required permissions checks are done on the original RTE.
1483  * Likewise, set the child's securityQuals to empty, because we only
1484  * want to apply the parent's RLS conditions regardless of what RLS
1485  * properties individual children may have. (This is an intentional
1486  * choice to make inherited RLS work like regular permissions checks.)
1487  * The parent securityQuals will be propagated to children along with
1488  * other base restriction clauses, so we don't need to do it here.
1489  */
1490  childrte = copyObject(rte);
1491  childrte->relid = childOID;
1492  childrte->relkind = newrelation->rd_rel->relkind;
1493  childrte->inh = false;
1494  childrte->requiredPerms = 0;
1495  childrte->securityQuals = NIL;
1496  parse->rtable = lappend(parse->rtable, childrte);
1497  childRTindex = list_length(parse->rtable);
1498 
1499  /*
1500  * Build an AppendRelInfo for this parent and child, unless the child
1501  * is a partitioned table.
1502  */
1503  if (childrte->relkind != RELKIND_PARTITIONED_TABLE)
1504  {
1505  need_append = true;
1506  appinfo = makeNode(AppendRelInfo);
1507  appinfo->parent_relid = rti;
1508  appinfo->child_relid = childRTindex;
1509  appinfo->parent_reltype = oldrelation->rd_rel->reltype;
1510  appinfo->child_reltype = newrelation->rd_rel->reltype;
1511  make_inh_translation_list(oldrelation, newrelation, childRTindex,
1512  &appinfo->translated_vars);
1513  appinfo->parent_reloid = parentOID;
1514  appinfos = lappend(appinfos, appinfo);
1515 
1516  /*
1517  * Translate the column permissions bitmaps to the child's attnums
1518  * (we have to build the translated_vars list before we can do
1519  * this). But if this is the parent table, leave copyObject's
1520  * result alone.
1521  *
1522  * Note: we need to do this even though the executor won't run any
1523  * permissions checks on the child RTE. The
1524  * insertedCols/updatedCols bitmaps may be examined for
1525  * trigger-firing purposes.
1526  */
1527  if (childOID != parentOID)
1528  {
1530  appinfo->translated_vars);
1532  appinfo->translated_vars);
1533  childrte->updatedCols = translate_col_privs(rte->updatedCols,
1534  appinfo->translated_vars);
1535  }
1536  }
1537  else
1538  partitioned_child_rels = lappend_int(partitioned_child_rels,
1539  childRTindex);
1540 
1541  /*
1542  * Build a PlanRowMark if parent is marked FOR UPDATE/SHARE.
1543  */
1544  if (oldrc)
1545  {
1546  PlanRowMark *newrc = makeNode(PlanRowMark);
1547 
1548  newrc->rti = childRTindex;
1549  newrc->prti = rti;
1550  newrc->rowmarkId = oldrc->rowmarkId;
1551  /* Reselect rowmark type, because relkind might not match parent */
1552  newrc->markType = select_rowmark_type(childrte, oldrc->strength);
1553  newrc->allMarkTypes = (1 << newrc->markType);
1554  newrc->strength = oldrc->strength;
1555  newrc->waitPolicy = oldrc->waitPolicy;
1556 
1557  /*
1558  * We mark RowMarks for partitioned child tables as parent RowMarks
1559  * so that the executor ignores them (except their existence means
1560  * that the child tables be locked using appropriate mode).
1561  */
1562  newrc->isParent = (childrte->relkind == RELKIND_PARTITIONED_TABLE);
1563 
1564  /* Include child's rowmark type in parent's allMarkTypes */
1565  oldrc->allMarkTypes |= newrc->allMarkTypes;
1566 
1567  root->rowMarks = lappend(root->rowMarks, newrc);
1568  }
1569 
1570  /* Close child relations, but keep locks */
1571  if (childOID != parentOID)
1572  heap_close(newrelation, NoLock);
1573  }
1574 
1575  heap_close(oldrelation, NoLock);
1576 
1577  /*
1578  * If all the children were temp tables or a partitioned parent did not
1579  * have any leaf partitions, pretend it's a non-inheritance situation; we
1580  * don't need Append node in that case. The duplicate RTE we added for
1581  * the parent table is harmless, so we don't bother to get rid of it;
1582  * ditto for the useless PlanRowMark node.
1583  */
1584  if (!need_append)
1585  {
1586  /* Clear flag before returning */
1587  rte->inh = false;
1588  return;
1589  }
1590 
1591  /*
1592  * We keep a list of objects in root, each of which maps a partitioned
1593  * parent RT index to the list of RT indexes of its partitioned child
1594  * tables. When creating an Append or a ModifyTable path for the parent,
1595  * we copy the child RT index list verbatim to the path so that it could
1596  * be carried over to the executor so that the latter could identify
1597  * the partitioned child tables.
1598  */
1599  if (partitioned_child_rels != NIL)
1600  {
1602 
1604  pcinfo->parent_relid = rti;
1605  pcinfo->child_rels = partitioned_child_rels;
1606  root->pcinfo_list = lappend(root->pcinfo_list, pcinfo);
1607  }
1608 
1609  /* Otherwise, OK to add to root->append_rel_list */
1610  root->append_rel_list = list_concat(root->append_rel_list, appinfos);
1611 }
#define NIL
Definition: pg_list.h:69
List * rowMarks
Definition: relation.h:255
Query * parse
Definition: relation.h:154
RowMarkType markType
Definition: plannodes.h:1001
int LOCKMODE
Definition: lockdefs.h:26
RowMarkType select_rowmark_type(RangeTblEntry *rte, LockClauseStrength strength)
Definition: planner.c:2425
List * securityQuals
Definition: parsenodes.h:1024
int resultRelation
Definition: parsenodes.h:120
#define AccessShareLock
Definition: lockdefs.h:36
Index prti
Definition: plannodes.h:999
List * list_concat(List *list1, List *list2)
Definition: list.c:321
static Bitmapset * translate_col_privs(const Bitmapset *parent_privs, List *translated_vars)
Definition: prepunion.c:1728
AclMode requiredPerms
Definition: parsenodes.h:1019
#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
Index rowmarkId
Definition: plannodes.h:1000
LockWaitPolicy waitPolicy
Definition: plannodes.h:1004
List * translated_vars
Definition: relation.h:2002
#define RowMarkRequiresRowShareLock(marktype)
Definition: plannodes.h:954
Oid parent_reltype
Definition: relation.h:1983
Bitmapset * selectedCols
Definition: parsenodes.h:1021
bool has_subclass(Oid relationId)
Definition: pg_inherits.c:272
List * rtable
Definition: parsenodes.h:135
#define NoLock
Definition: lockdefs.h:34
#define RowExclusiveLock
Definition: lockdefs.h:38
int allMarkTypes
Definition: plannodes.h:1002
List * lappend_int(List *list, int datum)
Definition: list.c:146
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:251
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1284
unsigned int Index
Definition: c.h:365
Bitmapset * updatedCols
Definition: parsenodes.h:1023
Index rti
Definition: plannodes.h:998
#define makeNode(_type_)
Definition: nodes.h:557
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
List * pcinfo_list
Definition: relation.h:253
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:534
LockClauseStrength strength
Definition: plannodes.h:1003
static int list_length(const List *l)
Definition: pg_list.h:89
Oid child_reltype
Definition: relation.h:1984
static void make_inh_translation_list(Relation oldrelation, Relation newrelation, Index newvarno, List **translated_vars)
Definition: prepunion.c:1621
RTEKind rtekind
Definition: parsenodes.h:928
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:167
Bitmapset * insertedCols
Definition: parsenodes.h:1022
PlanRowMark * get_plan_rowmark(List *rowmarks, Index rtindex)
Definition: preptlist.c:401
bool isParent
Definition: plannodes.h:1005
Index child_relid
Definition: relation.h:1975
Oid parent_reloid
Definition: relation.h:2009
#define copyObject(obj)
Definition: nodes.h:621
Index parent_relid
Definition: relation.h:1974
Definition: pg_list.h:45
#define lfirst_oid(lc)
Definition: pg_list.h:108
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 1328 of file prepunion.c.

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

Referenced by subquery_planner().

1329 {
1330  Index nrtes;
1331  Index rti;
1332  ListCell *rl;
1333 
1334  /*
1335  * expand_inherited_rtentry may add RTEs to parse->rtable; there is no
1336  * need to scan them since they can't have inh=true. So just scan as far
1337  * as the original end of the rtable list.
1338  */
1339  nrtes = list_length(root->parse->rtable);
1340  rl = list_head(root->parse->rtable);
1341  for (rti = 1; rti <= nrtes; rti++)
1342  {
1343  RangeTblEntry *rte = (RangeTblEntry *) lfirst(rl);
1344 
1345  expand_inherited_rtentry(root, rte, rti);
1346  rl = lnext(rl);
1347  }
1348 }
Query * parse
Definition: relation.h:154
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:1367
unsigned int Index
Definition: c.h:365
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
static List * generate_append_tlist ( List colTypes,
List colCollations,
bool  flag,
List input_tlists,
List refnames_tlist 
)
static

Definition at line 1157 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, NULL, palloc(), pfree(), pstrdup(), TargetEntry::resjunk, TargetEntry::resname, TargetEntry::resno, and TargetEntry::ressortgroupref.

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

1161 {
1162  List *tlist = NIL;
1163  int resno = 1;
1164  ListCell *curColType;
1165  ListCell *curColCollation;
1166  ListCell *ref_tl_item;
1167  int colindex;
1168  TargetEntry *tle;
1169  Node *expr;
1170  ListCell *tlistl;
1171  int32 *colTypmods;
1172 
1173  /*
1174  * First extract typmods to use.
1175  *
1176  * If the inputs all agree on type and typmod of a particular column, use
1177  * that typmod; else use -1.
1178  */
1179  colTypmods = (int32 *) palloc(list_length(colTypes) * sizeof(int32));
1180 
1181  foreach(tlistl, input_tlists)
1182  {
1183  List *subtlist = (List *) lfirst(tlistl);
1184  ListCell *subtlistl;
1185 
1186  curColType = list_head(colTypes);
1187  colindex = 0;
1188  foreach(subtlistl, subtlist)
1189  {
1190  TargetEntry *subtle = (TargetEntry *) lfirst(subtlistl);
1191 
1192  if (subtle->resjunk)
1193  continue;
1194  Assert(curColType != NULL);
1195  if (exprType((Node *) subtle->expr) == lfirst_oid(curColType))
1196  {
1197  /* If first subplan, copy the typmod; else compare */
1198  int32 subtypmod = exprTypmod((Node *) subtle->expr);
1199 
1200  if (tlistl == list_head(input_tlists))
1201  colTypmods[colindex] = subtypmod;
1202  else if (subtypmod != colTypmods[colindex])
1203  colTypmods[colindex] = -1;
1204  }
1205  else
1206  {
1207  /* types disagree, so force typmod to -1 */
1208  colTypmods[colindex] = -1;
1209  }
1210  curColType = lnext(curColType);
1211  colindex++;
1212  }
1213  Assert(curColType == NULL);
1214  }
1215 
1216  /*
1217  * Now we can build the tlist for the Append.
1218  */
1219  colindex = 0;
1220  forthree(curColType, colTypes, curColCollation, colCollations,
1221  ref_tl_item, refnames_tlist)
1222  {
1223  Oid colType = lfirst_oid(curColType);
1224  int32 colTypmod = colTypmods[colindex++];
1225  Oid colColl = lfirst_oid(curColCollation);
1226  TargetEntry *reftle = (TargetEntry *) lfirst(ref_tl_item);
1227 
1228  Assert(reftle->resno == resno);
1229  Assert(!reftle->resjunk);
1230  expr = (Node *) makeVar(0,
1231  resno,
1232  colType,
1233  colTypmod,
1234  colColl,
1235  0);
1236  tle = makeTargetEntry((Expr *) expr,
1237  (AttrNumber) resno++,
1238  pstrdup(reftle->resname),
1239  false);
1240 
1241  /*
1242  * By convention, all non-resjunk columns in a setop tree have
1243  * ressortgroupref equal to their resno. In some cases the ref isn't
1244  * needed, but this is a cleaner way than modifying the tlist later.
1245  */
1246  tle->ressortgroupref = tle->resno;
1247 
1248  tlist = lappend(tlist, tle);
1249  }
1250 
1251  if (flag)
1252  {
1253  /* Add a resjunk flag column */
1254  /* flag value is shown as copied up from subplan */
1255  expr = (Node *) makeVar(0,
1256  resno,
1257  INT4OID,
1258  -1,
1259  InvalidOid,
1260  0);
1261  tle = makeTargetEntry((Expr *) expr,
1262  (AttrNumber) resno++,
1263  pstrdup("flag"),
1264  true);
1265  tlist = lappend(tlist, tle);
1266  }
1267 
1268  pfree(colTypmods);
1269 
1270  return tlist;
1271 }
#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:189
char * pstrdup(const char *in)
Definition: mcxt.c:1077
#define INT4OID
Definition: pg_type.h:316
Definition: nodes.h:509
unsigned int Oid
Definition: postgres_ext.h:31
char * resname
Definition: primnodes.h:1369
signed int int32
Definition: c.h:256
void pfree(void *pointer)
Definition: mcxt.c:950
bool resjunk
Definition: primnodes.h:1374
char * flag(int b)
Definition: test-ctype.c:33
AttrNumber resno
Definition: primnodes.h:1368
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 NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1367
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:849
Index ressortgroupref
Definition: primnodes.h:1370
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 609 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, NULL, 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().

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

Definition at line 427 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, NULL, SetOperationStmt::op, SetOperationStmt::rarg, recurse_set_operations(), Path::rows, SETOP_UNION, UPPERREL_SETOP, and PlannerInfo::wt_param_id.

Referenced by plan_set_operations().

430 {
431  RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
432  Path *path;
433  Path *lpath;
434  Path *rpath;
435  List *lpath_tlist;
436  List *rpath_tlist;
437  List *tlist;
438  List *groupList;
439  double dNumGroups;
440 
441  /* Parser should have rejected other cases */
442  if (setOp->op != SETOP_UNION)
443  elog(ERROR, "only UNION queries can be recursive");
444  /* Worktable ID should be assigned */
445  Assert(root->wt_param_id >= 0);
446 
447  /*
448  * Unlike a regular UNION node, process the left and right inputs
449  * separately without any intention of combining them into one Append.
450  */
451  lpath = recurse_set_operations(setOp->larg, root,
452  setOp->colTypes, setOp->colCollations,
453  false, -1,
454  refnames_tlist,
455  &lpath_tlist,
456  NULL);
457  /* The right path will want to look at the left one ... */
458  root->non_recursive_path = lpath;
459  rpath = recurse_set_operations(setOp->rarg, root,
460  setOp->colTypes, setOp->colCollations,
461  false, -1,
462  refnames_tlist,
463  &rpath_tlist,
464  NULL);
465  root->non_recursive_path = NULL;
466 
467  /*
468  * Generate tlist for RecursiveUnion path node --- same as in Append cases
469  */
470  tlist = generate_append_tlist(setOp->colTypes, setOp->colCollations, false,
471  list_make2(lpath_tlist, rpath_tlist),
472  refnames_tlist);
473 
474  *pTargetList = tlist;
475 
476  /*
477  * If UNION, identify the grouping operators
478  */
479  if (setOp->all)
480  {
481  groupList = NIL;
482  dNumGroups = 0;
483  }
484  else
485  {
486  /* Identify the grouping semantics */
487  groupList = generate_setop_grouplist(setOp, tlist);
488 
489  /* We only support hashing here */
490  if (!grouping_is_hashable(groupList))
491  ereport(ERROR,
492  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
493  errmsg("could not implement recursive UNION"),
494  errdetail("All column datatypes must be hashable.")));
495 
496  /*
497  * For the moment, take the number of distinct groups as equal to the
498  * total input size, ie, the worst case.
499  */
500  dNumGroups = lpath->rows + rpath->rows * 10;
501  }
502 
503  /*
504  * And make the path node.
505  */
506  path = (Path *) create_recursiveunion_path(root,
507  result_rel,
508  lpath,
509  rpath,
510  create_pathtarget(root, tlist),
511  groupList,
512  root->wt_param_id,
513  dNumGroups);
514 
515  return path;
516 }
#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:1157
static List * generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
Definition: prepunion.c:1285
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:307
#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:3071
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:919
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:248
List * colCollations
Definition: parsenodes.h:1549
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
double rows
Definition: relation.h:963
struct Path * non_recursive_path
Definition: relation.h:308
SetOperation op
Definition: parsenodes.h:1540
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
Definition: relation.h:946
static List * generate_setop_grouplist ( SetOperationStmt op,
List targetlist 
)
static

Definition at line 1285 of file prepunion.c.

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

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

1286 {
1287  List *grouplist = copyObject(op->groupClauses);
1288  ListCell *lg;
1289  ListCell *lt;
1290 
1291  lg = list_head(grouplist);
1292  foreach(lt, targetlist)
1293  {
1294  TargetEntry *tle = (TargetEntry *) lfirst(lt);
1295  SortGroupClause *sgc;
1296 
1297  if (tle->resjunk)
1298  {
1299  /* resjunk columns should not have sortgrouprefs */
1300  Assert(tle->ressortgroupref == 0);
1301  continue; /* ignore resjunk columns */
1302  }
1303 
1304  /* non-resjunk columns should have sortgroupref = resno */
1305  Assert(tle->ressortgroupref == tle->resno);
1306 
1307  /* non-resjunk columns should have grouping clauses */
1308  Assert(lg != NULL);
1309  sgc = (SortGroupClause *) lfirst(lg);
1310  lg = lnext(lg);
1311  Assert(sgc->tleSortGroupRef == 0);
1312 
1313  sgc->tleSortGroupRef = tle->ressortgroupref;
1314  }
1315  Assert(lg == NULL);
1316  return grouplist;
1317 }
Index tleSortGroupRef
Definition: parsenodes.h:1156
bool resjunk
Definition: primnodes.h:1374
AttrNumber resno
Definition: primnodes.h:1368
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
Index ressortgroupref
Definition: primnodes.h:1370
#define copyObject(obj)
Definition: nodes.h:621
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 1012 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, NULL, pstrdup(), TargetEntry::resjunk, TargetEntry::resname, TargetEntry::resno, and TargetEntry::ressortgroupref.

Referenced by recurse_set_operations().

1018 {
1019  List *tlist = NIL;
1020  int resno = 1;
1021  ListCell *ctlc,
1022  *cclc,
1023  *itlc,
1024  *rtlc;
1025  TargetEntry *tle;
1026  Node *expr;
1027 
1028  /* there's no forfour() so we must chase one list manually */
1029  rtlc = list_head(refnames_tlist);
1030  forthree(ctlc, colTypes, cclc, colCollations, itlc, input_tlist)
1031  {
1032  Oid colType = lfirst_oid(ctlc);
1033  Oid colColl = lfirst_oid(cclc);
1034  TargetEntry *inputtle = (TargetEntry *) lfirst(itlc);
1035  TargetEntry *reftle = (TargetEntry *) lfirst(rtlc);
1036 
1037  rtlc = lnext(rtlc);
1038 
1039  Assert(inputtle->resno == resno);
1040  Assert(reftle->resno == resno);
1041  Assert(!inputtle->resjunk);
1042  Assert(!reftle->resjunk);
1043 
1044  /*
1045  * Generate columns referencing input columns and having appropriate
1046  * data types and column names. Insert datatype coercions where
1047  * necessary.
1048  *
1049  * HACK: constants in the input's targetlist are copied up as-is
1050  * rather than being referenced as subquery outputs. This is mainly
1051  * to ensure that when we try to coerce them to the output column's
1052  * datatype, the right things happen for UNKNOWN constants. But do
1053  * this only at the first level of subquery-scan plans; we don't want
1054  * phony constants appearing in the output tlists of upper-level
1055  * nodes!
1056  */
1057  if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
1058  expr = (Node *) inputtle->expr;
1059  else
1060  expr = (Node *) makeVar(varno,
1061  inputtle->resno,
1062  exprType((Node *) inputtle->expr),
1063  exprTypmod((Node *) inputtle->expr),
1064  exprCollation((Node *) inputtle->expr),
1065  0);
1066 
1067  if (exprType(expr) != colType)
1068  {
1069  /*
1070  * Note: it's not really cool to be applying coerce_to_common_type
1071  * here; one notable point is that assign_expr_collations never
1072  * gets run on any generated nodes. For the moment that's not a
1073  * problem because we force the correct exposed collation below.
1074  * It would likely be best to make the parser generate the correct
1075  * output tlist for every set-op to begin with, though.
1076  */
1077  expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */
1078  expr,
1079  colType,
1080  "UNION/INTERSECT/EXCEPT");
1081  }
1082 
1083  /*
1084  * Ensure the tlist entry's exposed collation matches the set-op. This
1085  * is necessary because plan_set_operations() reports the result
1086  * ordering as a list of SortGroupClauses, which don't carry collation
1087  * themselves but just refer to tlist entries. If we don't show the
1088  * right collation then planner.c might do the wrong thing in
1089  * higher-level queries.
1090  *
1091  * Note we use RelabelType, not CollateExpr, since this expression
1092  * will reach the executor without any further processing.
1093  */
1094  if (exprCollation(expr) != colColl)
1095  {
1096  expr = (Node *) makeRelabelType((Expr *) expr,
1097  exprType(expr),
1098  exprTypmod(expr),
1099  colColl,
1101  }
1102 
1103  tle = makeTargetEntry((Expr *) expr,
1104  (AttrNumber) resno++,
1105  pstrdup(reftle->resname),
1106  false);
1107 
1108  /*
1109  * By convention, all non-resjunk columns in a setop tree have
1110  * ressortgroupref equal to their resno. In some cases the ref isn't
1111  * needed, but this is a cleaner way than modifying the tlist later.
1112  */
1113  tle->ressortgroupref = tle->resno;
1114 
1115  tlist = lappend(tlist, tle);
1116  }
1117 
1118  if (flag >= 0)
1119  {
1120  /* Add a resjunk flag column */
1121  /* flag value is the given constant */
1122  expr = (Node *) makeConst(INT4OID,
1123  -1,
1124  InvalidOid,
1125  sizeof(int32),
1127  false,
1128  true);
1129  tle = makeTargetEntry((Expr *) expr,
1130  (AttrNumber) resno++,
1131  pstrdup("flag"),
1132  true);
1133  tlist = lappend(tlist, tle);
1134  }
1135 
1136  return tlist;
1137 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:276
#define forthree(cell1, list1, cell2, list2, cell3, list3)
Definition: pg_list.h:189
char * pstrdup(const char *in)
Definition: mcxt.c:1077
#define INT4OID
Definition: pg_type.h:316
Definition: nodes.h:509
unsigned int Oid
Definition: postgres_ext.h:31
char * resname
Definition: primnodes.h:1369
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:256
bool resjunk
Definition: primnodes.h:1374
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:1368
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 NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
Expr * expr
Definition: primnodes.h:1367
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
Oid exprCollation(const Node *expr)
Definition: nodeFuncs.c:748
#define Int32GetDatum(X)
Definition: postgres.h:485
Index ressortgroupref
Definition: primnodes.h:1370
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 522 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, NULL, Path::pathtarget, SetOperationStmt::rarg, recurse_union_children(), Path::rows, PlannerInfo::tuple_fraction, and UPPERREL_SETOP.

Referenced by recurse_set_operations().

526 {
527  RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
528  double save_fraction = root->tuple_fraction;
529  List *pathlist;
530  List *child_tlists1;
531  List *child_tlists2;
532  List *tlist_list;
533  List *tlist;
534  Path *path;
535 
536  /*
537  * If plain UNION, tell children to fetch all tuples.
538  *
539  * Note: in UNION ALL, we pass the top-level tuple_fraction unmodified to
540  * each arm of the UNION ALL. One could make a case for reducing the
541  * tuple fraction for later arms (discounting by the expected size of the
542  * earlier arms' results) but it seems not worth the trouble. The normal
543  * case where tuple_fraction isn't already zero is a LIMIT at top level,
544  * and passing it down as-is is usually enough to get the desired result
545  * of preferring fast-start plans.
546  */
547  if (!op->all)
548  root->tuple_fraction = 0.0;
549 
550  /*
551  * If any of my children are identical UNION nodes (same op, all-flag, and
552  * colTypes) then they can be merged into this node so that we generate
553  * only one Append and unique-ification for the lot. Recurse to find such
554  * nodes and compute their children's paths.
555  */
556  pathlist = list_concat(recurse_union_children(op->larg, root,
557  op, refnames_tlist,
558  &child_tlists1),
559  recurse_union_children(op->rarg, root,
560  op, refnames_tlist,
561  &child_tlists2));
562  tlist_list = list_concat(child_tlists1, child_tlists2);
563 
564  /*
565  * Generate tlist for Append plan node.
566  *
567  * The tlist for an Append plan isn't important as far as the Append is
568  * concerned, but we must make it look real anyway for the benefit of the
569  * next plan level up.
570  */
571  tlist = generate_append_tlist(op->colTypes, op->colCollations, false,
572  tlist_list, refnames_tlist);
573 
574  *pTargetList = tlist;
575 
576  /*
577  * Append the child results together.
578  */
579  path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
580 
581  /* We have to manually jam the right tlist into the path; ick */
582  path->pathtarget = create_pathtarget(root, tlist);
583 
584  /*
585  * For UNION ALL, we just need the Append path. For UNION, need to add
586  * node(s) to remove duplicates.
587  */
588  if (!op->all)
589  path = make_union_unique(op, path, tlist, root);
590 
591  /*
592  * Estimate number of groups if caller wants it. For now we just assume
593  * the output is unique --- this is certainly true for the UNION case, and
594  * we want worst-case estimates anyway.
595  */
596  if (pNumGroups)
597  *pNumGroups = path->rows;
598 
599  /* Undo effects of possibly forcing tuple_fraction to 0 */
600  root->tuple_fraction = save_fraction;
601 
602  return path;
603 }
#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:1157
PathTarget * pathtarget
Definition: relation.h:953
static List * recurse_union_children(Node *setOp, PlannerInfo *root, SetOperationStmt *top_union, List *refnames_tlist, List **tlist_list)
Definition: prepunion.c:785
static Path * make_union_unique(SetOperationStmt *op, Path *path, List *tlist, PlannerInfo *root)
Definition: prepunion.c:842
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:1203
double tuple_fraction
Definition: relation.h:290
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:919
#define create_pathtarget(root, tlist)
Definition: tlist.h:69
List * colCollations
Definition: parsenodes.h:1549
#define NULL
Definition: c.h:229
double rows
Definition: relation.h:963
Definition: pg_list.h:45
Definition: relation.h:946
static void make_inh_translation_list ( Relation  oldrelation,
Relation  newrelation,
Index  newvarno,
List **  translated_vars 
)
static

Definition at line 1621 of file prepunion.c.

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

Referenced by expand_inherited_rtentry().

1624 {
1625  List *vars = NIL;
1626  TupleDesc old_tupdesc = RelationGetDescr(oldrelation);
1627  TupleDesc new_tupdesc = RelationGetDescr(newrelation);
1628  int oldnatts = old_tupdesc->natts;
1629  int newnatts = new_tupdesc->natts;
1630  int old_attno;
1631 
1632  for (old_attno = 0; old_attno < oldnatts; old_attno++)
1633  {
1634  Form_pg_attribute att;
1635  char *attname;
1636  Oid atttypid;
1637  int32 atttypmod;
1638  Oid attcollation;
1639  int new_attno;
1640 
1641  att = old_tupdesc->attrs[old_attno];
1642  if (att->attisdropped)
1643  {
1644  /* Just put NULL into this list entry */
1645  vars = lappend(vars, NULL);
1646  continue;
1647  }
1648  attname = NameStr(att->attname);
1649  atttypid = att->atttypid;
1650  atttypmod = att->atttypmod;
1651  attcollation = att->attcollation;
1652 
1653  /*
1654  * When we are generating the "translation list" for the parent table
1655  * of an inheritance set, no need to search for matches.
1656  */
1657  if (oldrelation == newrelation)
1658  {
1659  vars = lappend(vars, makeVar(newvarno,
1660  (AttrNumber) (old_attno + 1),
1661  atttypid,
1662  atttypmod,
1663  attcollation,
1664  0));
1665  continue;
1666  }
1667 
1668  /*
1669  * Otherwise we have to search for the matching column by name.
1670  * There's no guarantee it'll have the same column position, because
1671  * of cases like ALTER TABLE ADD COLUMN and multiple inheritance.
1672  * However, in simple cases it will be the same column number, so try
1673  * that before we go groveling through all the columns.
1674  *
1675  * Note: the test for (att = ...) != NULL cannot fail, it's just a
1676  * notational device to include the assignment into the if-clause.
1677  */
1678  if (old_attno < newnatts &&
1679  (att = new_tupdesc->attrs[old_attno]) != NULL &&
1680  !att->attisdropped && att->attinhcount != 0 &&
1681  strcmp(attname, NameStr(att->attname)) == 0)
1682  new_attno = old_attno;
1683  else
1684  {
1685  for (new_attno = 0; new_attno < newnatts; new_attno++)
1686  {
1687  att = new_tupdesc->attrs[new_attno];
1688  if (!att->attisdropped && att->attinhcount != 0 &&
1689  strcmp(attname, NameStr(att->attname)) == 0)
1690  break;
1691  }
1692  if (new_attno >= newnatts)
1693  elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
1694  attname, RelationGetRelationName(newrelation));
1695  }
1696 
1697  /* Found it, check type and collation match */
1698  if (atttypid != att->atttypid || atttypmod != att->atttypmod)
1699  elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's type",
1700  attname, RelationGetRelationName(newrelation));
1701  if (attcollation != att->attcollation)
1702  elog(ERROR, "attribute \"%s\" of relation \"%s\" does not match parent's collation",
1703  attname, RelationGetRelationName(newrelation));
1704 
1705  vars = lappend(vars, makeVar(newvarno,
1706  (AttrNumber) (new_attno + 1),
1707  atttypid,
1708  atttypmod,
1709  attcollation,
1710  0));
1711  }
1712 
1713  *translated_vars = vars;
1714 }
#define NIL
Definition: pg_list.h:69
#define RelationGetDescr(relation)
Definition: rel.h:429
Form_pg_attribute * attrs
Definition: tupdesc.h:74
unsigned int Oid
Definition: postgres_ext.h:31
int natts
Definition: tupdesc.h:73
signed int int32
Definition: c.h:256
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:437
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 NULL
Definition: c.h:229
#define NameStr(name)
Definition: c.h:499
#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 842 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, NULL, Path::pathkeys, Path::pathtarget, Path::rows, and UPPERREL_SETOP.

Referenced by generate_union_path().

844 {
845  RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
846  List *groupList;
847  double dNumGroups;
848 
849  /* Identify the grouping semantics */
850  groupList = generate_setop_grouplist(op, tlist);
851 
852  /* punt if nothing to group on (can this happen?) */
853  if (groupList == NIL)
854  return path;
855 
856  /*
857  * XXX for the moment, take the number of distinct groups as equal to the
858  * total input size, ie, the worst case. This is too conservative, but we
859  * don't want to risk having the hashtable overrun memory; also, it's not
860  * clear how to get a decent estimate of the true size. One should note
861  * as well the propensity of novices to write UNION rather than UNION ALL
862  * even when they don't expect any duplicates...
863  */
864  dNumGroups = path->rows;
865 
866  /* Decide whether to hash or sort */
867  if (choose_hashed_setop(root, groupList, path,
868  dNumGroups, dNumGroups,
869  "UNION"))
870  {
871  /* Hashed aggregate plan --- no sort needed */
872  path = (Path *) create_agg_path(root,
873  result_rel,
874  path,
875  create_pathtarget(root, tlist),
876  AGG_HASHED,
878  groupList,
879  NIL,
880  NULL,
881  dNumGroups);
882  }
883  else
884  {
885  /* Sort and Unique */
886  path = (Path *) create_sort_path(root,
887  result_rel,
888  path,
890  groupList,
891  tlist),
892  -1.0);
893  /* We have to manually jam the right tlist into the path; ick */
894  path->pathtarget = create_pathtarget(root, tlist);
895  path = (Path *) create_upper_unique_path(root,
896  result_rel,
897  path,
898  list_length(path->pathkeys),
899  dNumGroups);
900  }
901 
902  return path;
903 }
#define NIL
Definition: pg_list.h:69
PathTarget * pathtarget
Definition: relation.h:953
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:2615
static List * generate_setop_grouplist(SetOperationStmt *op, List *targetlist)
Definition: prepunion.c:1285
static bool choose_hashed_setop(PlannerInfo *root, List *groupClauses, Path *input_path, double dNumGroups, double dNumOutputRows, const char *construct)
Definition: prepunion.c:909
RelOptInfo * fetch_upper_rel(PlannerInfo *root, UpperRelationKind kind, Relids relids)
Definition: relnode.c:919
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:2667
#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:2513
List * pathkeys
Definition: relation.h:967
#define NULL
Definition: c.h:229
double rows
Definition: relation.h:963
static int list_length(const List *l)
Definition: pg_list.h:89
Definition: pg_list.h:45
Definition: relation.h:946
RelOptInfo* plan_set_operations ( PlannerInfo root)

Definition at line 129 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, NULL, 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().

130 {
131  Query *parse = root->parse;
133  Node *node;
134  RangeTblEntry *leftmostRTE;
135  Query *leftmostQuery;
136  RelOptInfo *setop_rel;
137  Path *path;
138  List *top_tlist;
139 
140  Assert(topop);
141 
142  /* check for unsupported stuff */
143  Assert(parse->jointree->fromlist == NIL);
144  Assert(parse->jointree->quals == NULL);
145  Assert(parse->groupClause == NIL);
146  Assert(parse->havingQual == NULL);
147  Assert(parse->windowClause == NIL);
148  Assert(parse->distinctClause == NIL);
149 
150  /*
151  * We'll need to build RelOptInfos for each of the leaf subqueries, which
152  * are RTE_SUBQUERY rangetable entries in this Query. Prepare the index
153  * arrays for that.
154  */
156 
157  /*
158  * Find the leftmost component Query. We need to use its column names for
159  * all generated tlists (else SELECT INTO won't work right).
160  */
161  node = topop->larg;
162  while (node && IsA(node, SetOperationStmt))
163  node = ((SetOperationStmt *) node)->larg;
164  Assert(node && IsA(node, RangeTblRef));
165  leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex];
166  leftmostQuery = leftmostRTE->subquery;
167  Assert(leftmostQuery != NULL);
168 
169  /*
170  * We return our results in the (SETOP, NULL) upperrel. For the moment,
171  * this is also the parent rel of all Paths in the setop tree; we may well
172  * change that in future.
173  */
174  setop_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
175 
176  /*
177  * We don't currently worry about setting setop_rel's consider_parallel
178  * flag, nor about allowing FDWs to contribute paths to it.
179  */
180 
181  /*
182  * If the topmost node is a recursive union, it needs special processing.
183  */
184  if (root->hasRecursion)
185  {
186  path = generate_recursion_path(topop, root,
187  leftmostQuery->targetList,
188  &top_tlist);
189  }
190  else
191  {
192  /*
193  * Recurse on setOperations tree to generate paths for set ops. The
194  * final output path should have just the column types shown as the
195  * output from the top-level node, plus possibly resjunk working
196  * columns (we can rely on upper-level nodes to deal with that).
197  */
198  path = recurse_set_operations((Node *) topop, root,
199  topop->colTypes, topop->colCollations,
200  true, -1,
201  leftmostQuery->targetList,
202  &top_tlist,
203  NULL);
204  }
205 
206  /* Must return the built tlist into root->processed_tlist. */
207  root->processed_tlist = top_tlist;
208 
209  /* Add only the final path to the SETOP upperrel. */
210  add_path(setop_rel, path);
211 
212  /* Let extensions possibly add some more paths */
214  (*create_upper_paths_hook) (root, UPPERREL_SETOP,
215  NULL, setop_rel);
216 
217  /* Select cheapest path */
218  set_cheapest(setop_rel);
219 
220  return setop_rel;
221 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
Query * parse
Definition: relation.h:154
void add_path(RelOptInfo *parent_rel, Path *new_path)
Definition: pathnode.c:412
FromExpr * jointree
Definition: parsenodes.h:136
static Path * generate_recursion_path(SetOperationStmt *setOp, PlannerInfo *root, List *refnames_tlist, List **pTargetList)
Definition: prepunion.c:427
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
Definition: nodes.h:509
List * fromlist
Definition: primnodes.h:1470
create_upper_paths_hook_type create_upper_paths_hook
Definition: planner.c:69
bool hasRecursion
Definition: relation.h:304
Node * quals
Definition: primnodes.h:1471
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:919
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:248
RangeTblEntry ** simple_rte_array
Definition: relation.h:187
void set_cheapest(RelOptInfo *parent_rel)
Definition: pathnode.c:234
List * colCollations
Definition: parsenodes.h:1549
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
void setup_simple_rel_arrays(PlannerInfo *root)
Definition: relnode.c:62
Node * setOperations
Definition: parsenodes.h:163
Query * subquery
Definition: parsenodes.h:946
List * groupClause
Definition: parsenodes.h:146
Node * havingQual
Definition: parsenodes.h:150
List * processed_tlist
Definition: relation.h:280
Definition: pg_list.h:45
Definition: relation.h:946
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 248 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, NULL, 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().

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

Definition at line 785 of file prepunion.c.

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

Referenced by generate_union_path().

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

Definition at line 1728 of file prepunion.c.

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

Referenced by expand_inherited_rtentry().

1730 {
1731  Bitmapset *child_privs = NULL;
1732  bool whole_row;
1733  int attno;
1734  ListCell *lc;
1735 
1736  /* System attributes have the same numbers in all tables */
1737  for (attno = FirstLowInvalidHeapAttributeNumber + 1; attno < 0; attno++)
1738  {
1740  parent_privs))
1741  child_privs = bms_add_member(child_privs,
1743  }
1744 
1745  /* Check if parent has whole-row reference */
1747  parent_privs);
1748 
1749  /* And now translate the regular user attributes, using the vars list */
1750  attno = InvalidAttrNumber;
1751  foreach(lc, translated_vars)
1752  {
1753  Var *var = lfirst_node(Var, lc);
1754 
1755  attno++;
1756  if (var == NULL) /* ignore dropped columns */
1757  continue;
1758  if (whole_row ||
1760  parent_privs))
1761  child_privs = bms_add_member(child_privs,
1763  }
1764 
1765  return child_privs;
1766 }
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
#define NULL
Definition: c.h:229
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