PostgreSQL Source Code  git master
plancat.c File Reference
#include "postgres.h"
#include <math.h>
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/nbtree.h"
#include "access/tableam.h"
#include "access/sysattr.h"
#include "access/table.h"
#include "access/transam.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/pg_am.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_statistic_ext.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/supportnodes.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/optimizer.h"
#include "optimizer/plancat.h"
#include "optimizer/prep.h"
#include "partitioning/partdesc.h"
#include "parser/parse_relation.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
#include "statistics/statistics.h"
#include "storage/bufmgr.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/partcache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
#include "utils/snapmgr.h"
Include dependency graph for plancat.c:

Go to the source code of this file.

Functions

static void get_relation_foreign_keys (PlannerInfo *root, RelOptInfo *rel, Relation relation, bool inhparent)
 
static bool infer_collation_opclass_match (InferenceElem *elem, Relation idxRel, List *idxExprs)
 
static Listget_relation_constraints (PlannerInfo *root, Oid relationObjectId, RelOptInfo *rel, bool include_noinherit, bool include_notnull, bool include_partition)
 
static Listbuild_index_tlist (PlannerInfo *root, IndexOptInfo *index, Relation heapRelation)
 
static Listget_relation_statistics (RelOptInfo *rel, Relation relation)
 
static void set_relation_partition_info (PlannerInfo *root, RelOptInfo *rel, Relation relation)
 
static PartitionScheme find_partition_scheme (PlannerInfo *root, Relation rel)
 
static void set_baserel_partition_key_exprs (Relation relation, RelOptInfo *rel)
 
static void set_baserel_partition_constraint (Relation relation, RelOptInfo *rel)
 
void get_relation_info (PlannerInfo *root, Oid relationObjectId, bool inhparent, RelOptInfo *rel)
 
Listinfer_arbiter_indexes (PlannerInfo *root)
 
void estimate_rel_size (Relation rel, int32 *attr_widths, BlockNumber *pages, double *tuples, double *allvisfrac)
 
int32 get_rel_data_width (Relation rel, int32 *attr_widths)
 
int32 get_relation_data_width (Oid relid, int32 *attr_widths)
 
bool relation_excluded_by_constraints (PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
 
Listbuild_physical_tlist (PlannerInfo *root, RelOptInfo *rel)
 
Selectivity restriction_selectivity (PlannerInfo *root, Oid operatorid, List *args, Oid inputcollid, int varRelid)
 
Selectivity join_selectivity (PlannerInfo *root, Oid operatorid, List *args, Oid inputcollid, JoinType jointype, SpecialJoinInfo *sjinfo)
 
Selectivity function_selectivity (PlannerInfo *root, Oid funcid, List *args, Oid inputcollid, bool is_join, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo)
 
void add_function_cost (PlannerInfo *root, Oid funcid, Node *node, QualCost *cost)
 
double get_function_rows (PlannerInfo *root, Oid funcid, Node *node)
 
bool has_unique_index (RelOptInfo *rel, AttrNumber attno)
 
bool has_row_triggers (PlannerInfo *root, Index rti, CmdType event)
 
bool has_stored_generated_columns (PlannerInfo *root, Index rti)
 

Variables

int constraint_exclusion = CONSTRAINT_EXCLUSION_PARTITION
 
get_relation_info_hook_type get_relation_info_hook = NULL
 

Function Documentation

◆ add_function_cost()

void add_function_cost ( PlannerInfo root,
Oid  funcid,
Node node,
QualCost cost 
)

Definition at line 1906 of file plancat.c.

References cpu_operator_cost, DatumGetPointer, elog, ERROR, SupportRequestCost::funcid, GETSTRUCT, HeapTupleIsValid, SupportRequestCost::node, ObjectIdGetDatum, OidFunctionCall1, OidIsValid, QualCost::per_tuple, SupportRequestCost::per_tuple, PointerGetDatum, PROCOID, ReleaseSysCache(), SupportRequestCost::root, SearchSysCache1(), QualCost::startup, SupportRequestCost::startup, T_SupportRequestCost, and SupportRequestCost::type.

Referenced by cost_qual_eval_walker(), cost_windowagg(), and get_agg_clause_costs_walker().

1908 {
1909  HeapTuple proctup;
1910  Form_pg_proc procform;
1911 
1912  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1913  if (!HeapTupleIsValid(proctup))
1914  elog(ERROR, "cache lookup failed for function %u", funcid);
1915  procform = (Form_pg_proc) GETSTRUCT(proctup);
1916 
1917  if (OidIsValid(procform->prosupport))
1918  {
1919  SupportRequestCost req;
1920  SupportRequestCost *sresult;
1921 
1922  req.type = T_SupportRequestCost;
1923  req.root = root;
1924  req.funcid = funcid;
1925  req.node = node;
1926 
1927  /* Initialize cost fields so that support function doesn't have to */
1928  req.startup = 0;
1929  req.per_tuple = 0;
1930 
1931  sresult = (SupportRequestCost *)
1932  DatumGetPointer(OidFunctionCall1(procform->prosupport,
1933  PointerGetDatum(&req)));
1934 
1935  if (sresult == &req)
1936  {
1937  /* Success, so accumulate support function's estimate into *cost */
1938  cost->startup += req.startup;
1939  cost->per_tuple += req.per_tuple;
1940  ReleaseSysCache(proctup);
1941  return;
1942  }
1943  }
1944 
1945  /* No support function, or it failed, so rely on procost */
1946  cost->per_tuple += procform->procost * cpu_operator_cost;
1947 
1948  ReleaseSysCache(proctup);
1949 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define PointerGetDatum(X)
Definition: postgres.h:556
#define OidIsValid(objectId)
Definition: c.h:638
Cost startup
Definition: pathnodes.h:45
Cost per_tuple
Definition: pathnodes.h:46
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:655
double cpu_operator_cost
Definition: costsize.c:114
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:134
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
struct PlannerInfo * root
Definition: supportnodes.h:136
#define DatumGetPointer(X)
Definition: postgres.h:549
#define elog(elevel,...)
Definition: elog.h:226

◆ build_index_tlist()

static List * build_index_tlist ( PlannerInfo root,
IndexOptInfo index,
Relation  heapRelation 
)
static

Definition at line 1702 of file plancat.c.

References elog, ERROR, FormData_pg_attribute, i, IndexOptInfo::indexkeys, IndexOptInfo::indexprs, lappend(), lfirst, list_head(), lnext(), makeTargetEntry(), makeVar(), IndexOptInfo::ncolumns, NIL, RelationData::rd_att, IndexOptInfo::rel, RelOptInfo::relid, SystemAttributeDefinition(), and TupleDescAttr.

Referenced by get_relation_info().

1704 {
1705  List *tlist = NIL;
1706  Index varno = index->rel->relid;
1707  ListCell *indexpr_item;
1708  int i;
1709 
1710  indexpr_item = list_head(index->indexprs);
1711  for (i = 0; i < index->ncolumns; i++)
1712  {
1713  int indexkey = index->indexkeys[i];
1714  Expr *indexvar;
1715 
1716  if (indexkey != 0)
1717  {
1718  /* simple column */
1719  const FormData_pg_attribute *att_tup;
1720 
1721  if (indexkey < 0)
1722  att_tup = SystemAttributeDefinition(indexkey);
1723  else
1724  att_tup = TupleDescAttr(heapRelation->rd_att, indexkey - 1);
1725 
1726  indexvar = (Expr *) makeVar(varno,
1727  indexkey,
1728  att_tup->atttypid,
1729  att_tup->atttypmod,
1730  att_tup->attcollation,
1731  0);
1732  }
1733  else
1734  {
1735  /* expression column */
1736  if (indexpr_item == NULL)
1737  elog(ERROR, "wrong number of index expressions");
1738  indexvar = (Expr *) lfirst(indexpr_item);
1739  indexpr_item = lnext(index->indexprs, indexpr_item);
1740  }
1741 
1742  tlist = lappend(tlist,
1743  makeTargetEntry(indexvar,
1744  i + 1,
1745  NULL,
1746  false));
1747  }
1748  if (indexpr_item != NULL)
1749  elog(ERROR, "wrong number of index expressions");
1750 
1751  return tlist;
1752 }
#define NIL
Definition: pg_list.h:65
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:321
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
const FormData_pg_attribute * SystemAttributeDefinition(AttrNumber attno)
Definition: heap.c:250
RelOptInfo * rel
Definition: pathnodes.h:791
#define ERROR
Definition: elog.h:43
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:236
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
Index relid
Definition: pathnodes.h:669
List * lappend(List *list, void *datum)
Definition: list.c:321
unsigned int Index
Definition: c.h:475
TupleDesc rd_att
Definition: rel.h:84
FormData_pg_attribute
Definition: pg_attribute.h:184
#define lfirst(lc)
Definition: pg_list.h:190
#define elog(elevel,...)
Definition: elog.h:226
int i
int * indexkeys
Definition: pathnodes.h:801
Definition: pg_list.h:50
List * indexprs
Definition: pathnodes.h:813

◆ build_physical_tlist()

List* build_physical_tlist ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 1581 of file plancat.c.

References elog, ERROR, expandRTE(), IsA, lappend(), lfirst, makeTargetEntry(), makeVar(), makeVarFromTargetEntry(), NIL, NoLock, planner_rt_fetch, RelationData::rd_att, RelationGetNumberOfAttributes, RelOptInfo::relid, RangeTblEntry::relid, TargetEntry::resjunk, TargetEntry::resno, RTE_CTE, RTE_FUNCTION, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_RESULT, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, RangeTblEntry::subquery, table_close(), table_open(), Query::targetList, and TupleDescAttr.

Referenced by create_scan_plan().

1582 {
1583  List *tlist = NIL;
1584  Index varno = rel->relid;
1585  RangeTblEntry *rte = planner_rt_fetch(varno, root);
1586  Relation relation;
1587  Query *subquery;
1588  Var *var;
1589  ListCell *l;
1590  int attrno,
1591  numattrs;
1592  List *colvars;
1593 
1594  switch (rte->rtekind)
1595  {
1596  case RTE_RELATION:
1597  /* Assume we already have adequate lock */
1598  relation = table_open(rte->relid, NoLock);
1599 
1600  numattrs = RelationGetNumberOfAttributes(relation);
1601  for (attrno = 1; attrno <= numattrs; attrno++)
1602  {
1603  Form_pg_attribute att_tup = TupleDescAttr(relation->rd_att,
1604  attrno - 1);
1605 
1606  if (att_tup->attisdropped || att_tup->atthasmissing)
1607  {
1608  /* found a dropped or missing col, so punt */
1609  tlist = NIL;
1610  break;
1611  }
1612 
1613  var = makeVar(varno,
1614  attrno,
1615  att_tup->atttypid,
1616  att_tup->atttypmod,
1617  att_tup->attcollation,
1618  0);
1619 
1620  tlist = lappend(tlist,
1621  makeTargetEntry((Expr *) var,
1622  attrno,
1623  NULL,
1624  false));
1625  }
1626 
1627  table_close(relation, NoLock);
1628  break;
1629 
1630  case RTE_SUBQUERY:
1631  subquery = rte->subquery;
1632  foreach(l, subquery->targetList)
1633  {
1634  TargetEntry *tle = (TargetEntry *) lfirst(l);
1635 
1636  /*
1637  * A resjunk column of the subquery can be reflected as
1638  * resjunk in the physical tlist; we need not punt.
1639  */
1640  var = makeVarFromTargetEntry(varno, tle);
1641 
1642  tlist = lappend(tlist,
1643  makeTargetEntry((Expr *) var,
1644  tle->resno,
1645  NULL,
1646  tle->resjunk));
1647  }
1648  break;
1649 
1650  case RTE_FUNCTION:
1651  case RTE_TABLEFUNC:
1652  case RTE_VALUES:
1653  case RTE_CTE:
1654  case RTE_NAMEDTUPLESTORE:
1655  case RTE_RESULT:
1656  /* Not all of these can have dropped cols, but share code anyway */
1657  expandRTE(rte, varno, 0, -1, true /* include dropped */ ,
1658  NULL, &colvars);
1659  foreach(l, colvars)
1660  {
1661  var = (Var *) lfirst(l);
1662 
1663  /*
1664  * A non-Var in expandRTE's output means a dropped column;
1665  * must punt.
1666  */
1667  if (!IsA(var, Var))
1668  {
1669  tlist = NIL;
1670  break;
1671  }
1672 
1673  tlist = lappend(tlist,
1674  makeTargetEntry((Expr *) var,
1675  var->varattno,
1676  NULL,
1677  false));
1678  }
1679  break;
1680 
1681  default:
1682  /* caller error */
1683  elog(ERROR, "unsupported RTE kind %d in build_physical_tlist",
1684  (int) rte->rtekind);
1685  break;
1686  }
1687 
1688  return tlist;
1689 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:422
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Var * makeVarFromTargetEntry(Index varno, TargetEntry *tle)
Definition: makefuncs.c:103
Definition: primnodes.h:167
List * targetList
Definition: parsenodes.h:140
bool resjunk
Definition: primnodes.h:1400
#define ERROR
Definition: elog.h:43
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:371
#define NoLock
Definition: lockdefs.h:34
AttrNumber resno
Definition: primnodes.h:1394
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:236
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
Index relid
Definition: pathnodes.h:669
List * lappend(List *list, void *datum)
Definition: list.c:321
void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, int location, bool include_dropped, List **colnames, List **colvars)
unsigned int Index
Definition: c.h:475
TupleDesc rd_att
Definition: rel.h:84
#define lfirst(lc)
Definition: pg_list.h:190
RTEKind rtekind
Definition: parsenodes.h:974
Query * subquery
Definition: parsenodes.h:1009
#define elog(elevel,...)
Definition: elog.h:226
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50

◆ estimate_rel_size()

void estimate_rel_size ( Relation  rel,
int32 attr_widths,
BlockNumber pages,
double *  tuples,
double *  allvisfrac 
)

Definition at line 947 of file plancat.c.

References get_rel_data_width(), MAXALIGN, RelationData::rd_rel, relallvisible, RelationGetNumberOfBlocks, relpages, reltuples, rint(), SizeofHeapTupleHeader, SizeOfPageHeaderData, and table_relation_estimate_size().

Referenced by get_relation_info(), hashbuild(), and plan_create_index_workers().

949 {
950  BlockNumber curpages;
952  double reltuples;
954  double density;
955 
956  switch (rel->rd_rel->relkind)
957  {
958  case RELKIND_RELATION:
959  case RELKIND_MATVIEW:
960  case RELKIND_TOASTVALUE:
961  table_relation_estimate_size(rel, attr_widths, pages, tuples,
962  allvisfrac);
963  break;
964 
965  case RELKIND_INDEX:
966 
967  /*
968  * XXX: It'd probably be good to move this into a callback,
969  * individual index types e.g. know if they have a metapage.
970  */
971 
972  /* it has storage, ok to call the smgr */
973  curpages = RelationGetNumberOfBlocks(rel);
974 
975  /* coerce values in pg_class to more desirable types */
976  relpages = (BlockNumber) rel->rd_rel->relpages;
977  reltuples = (double) rel->rd_rel->reltuples;
978  relallvisible = (BlockNumber) rel->rd_rel->relallvisible;
979 
980  /* report estimated # pages */
981  *pages = curpages;
982  /* quick exit if rel is clearly empty */
983  if (curpages == 0)
984  {
985  *tuples = 0;
986  *allvisfrac = 0;
987  break;
988  }
989  /* coerce values in pg_class to more desirable types */
990  relpages = (BlockNumber) rel->rd_rel->relpages;
991  reltuples = (double) rel->rd_rel->reltuples;
992  relallvisible = (BlockNumber) rel->rd_rel->relallvisible;
993 
994  /*
995  * Discount the metapage while estimating the number of tuples.
996  * This is a kluge because it assumes more than it ought to about
997  * index structure. Currently it's OK for btree, hash, and GIN
998  * indexes but suspect for GiST indexes.
999  */
1000  if (relpages > 0)
1001  {
1002  curpages--;
1003  relpages--;
1004  }
1005 
1006  /* estimate number of tuples from previous tuple density */
1007  if (relpages > 0)
1008  density = reltuples / (double) relpages;
1009  else
1010  {
1011  /*
1012  * When we have no data because the relation was truncated,
1013  * estimate tuple width from attribute datatypes. We assume
1014  * here that the pages are completely full, which is OK for
1015  * tables (since they've presumably not been VACUUMed yet) but
1016  * is probably an overestimate for indexes. Fortunately
1017  * get_relation_info() can clamp the overestimate to the
1018  * parent table's size.
1019  *
1020  * Note: this code intentionally disregards alignment
1021  * considerations, because (a) that would be gilding the lily
1022  * considering how crude the estimate is, and (b) it creates
1023  * platform dependencies in the default plans which are kind
1024  * of a headache for regression testing.
1025  *
1026  * XXX: Should this logic be more index specific?
1027  */
1028  int32 tuple_width;
1029 
1030  tuple_width = get_rel_data_width(rel, attr_widths);
1031  tuple_width += MAXALIGN(SizeofHeapTupleHeader);
1032  tuple_width += sizeof(ItemIdData);
1033  /* note: integer division is intentional here */
1034  density = (BLCKSZ - SizeOfPageHeaderData) / tuple_width;
1035  }
1036  *tuples = rint(density * (double) curpages);
1037 
1038  /*
1039  * We use relallvisible as-is, rather than scaling it up like we
1040  * do for the pages and tuples counts, on the theory that any
1041  * pages added since the last VACUUM are most likely not marked
1042  * all-visible. But costsize.c wants it converted to a fraction.
1043  */
1044  if (relallvisible == 0 || curpages <= 0)
1045  *allvisfrac = 0;
1046  else if ((double) relallvisible >= curpages)
1047  *allvisfrac = 1;
1048  else
1049  *allvisfrac = (double) relallvisible / curpages;
1050  break;
1051 
1052  case RELKIND_SEQUENCE:
1053  /* Sequences always have a known size */
1054  *pages = 1;
1055  *tuples = 1;
1056  *allvisfrac = 0;
1057  break;
1058  case RELKIND_FOREIGN_TABLE:
1059  /* Just use whatever's in pg_class */
1060  *pages = rel->rd_rel->relpages;
1061  *tuples = rel->rd_rel->reltuples;
1062  *allvisfrac = 0;
1063  break;
1064  default:
1065  /* else it has no disk storage; probably shouldn't get here? */
1066  *pages = 0;
1067  *tuples = 0;
1068  *allvisfrac = 0;
1069  break;
1070  }
1071 }
static void table_relation_estimate_size(Relation rel, int32 *attr_widths, BlockNumber *pages, double *tuples, double *allvisfrac)
Definition: tableam.h:1617
#define SizeofHeapTupleHeader
Definition: htup_details.h:184
int32 relallvisible
Definition: pg_class.h:66
uint32 BlockNumber
Definition: block.h:31
#define SizeOfPageHeaderData
Definition: bufpage.h:216
Form_pg_class rd_rel
Definition: rel.h:83
int32 relpages
Definition: pg_class.h:60
signed int int32
Definition: c.h:346
struct ItemIdData ItemIdData
double rint(double x)
Definition: rint.c:21
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:198
#define MAXALIGN(LEN)
Definition: c.h:685
int32 get_rel_data_width(Relation rel, int32 *attr_widths)
Definition: plancat.c:1088
float4 reltuples
Definition: pg_class.h:63

◆ find_partition_scheme()

static PartitionScheme find_partition_scheme ( PlannerInfo root,
Relation  rel 
)
static

Definition at line 2148 of file plancat.c.

References Assert, CurrentMemoryContext, fmgr_info_copy(), FmgrInfo::fn_oid, i, lappend(), lfirst, palloc(), palloc0(), PlannerInfo::part_schemes, PartitionKeyData::partcollation, PartitionSchemeData::partcollation, PartitionKeyData::partnatts, PartitionSchemeData::partnatts, PartitionKeyData::partopcintype, PartitionSchemeData::partopcintype, PartitionKeyData::partopfamily, PartitionSchemeData::partopfamily, PartitionKeyData::partsupfunc, PartitionSchemeData::partsupfunc, PartitionKeyData::parttypbyval, PartitionSchemeData::parttypbyval, PartitionKeyData::parttyplen, PartitionSchemeData::parttyplen, RelationGetPartitionKey, PartitionKeyData::strategy, and PartitionSchemeData::strategy.

Referenced by set_relation_partition_info().

2149 {
2150  PartitionKey partkey = RelationGetPartitionKey(relation);
2151  ListCell *lc;
2152  int partnatts,
2153  i;
2154  PartitionScheme part_scheme;
2155 
2156  /* A partitioned table should have a partition key. */
2157  Assert(partkey != NULL);
2158 
2159  partnatts = partkey->partnatts;
2160 
2161  /* Search for a matching partition scheme and return if found one. */
2162  foreach(lc, root->part_schemes)
2163  {
2164  part_scheme = lfirst(lc);
2165 
2166  /* Match partitioning strategy and number of keys. */
2167  if (partkey->strategy != part_scheme->strategy ||
2168  partnatts != part_scheme->partnatts)
2169  continue;
2170 
2171  /* Match partition key type properties. */
2172  if (memcmp(partkey->partopfamily, part_scheme->partopfamily,
2173  sizeof(Oid) * partnatts) != 0 ||
2174  memcmp(partkey->partopcintype, part_scheme->partopcintype,
2175  sizeof(Oid) * partnatts) != 0 ||
2176  memcmp(partkey->partcollation, part_scheme->partcollation,
2177  sizeof(Oid) * partnatts) != 0)
2178  continue;
2179 
2180  /*
2181  * Length and byval information should match when partopcintype
2182  * matches.
2183  */
2184  Assert(memcmp(partkey->parttyplen, part_scheme->parttyplen,
2185  sizeof(int16) * partnatts) == 0);
2186  Assert(memcmp(partkey->parttypbyval, part_scheme->parttypbyval,
2187  sizeof(bool) * partnatts) == 0);
2188 
2189  /*
2190  * If partopfamily and partopcintype matched, must have the same
2191  * partition comparison functions. Note that we cannot reliably
2192  * Assert the equality of function structs themselves for they might
2193  * be different across PartitionKey's, so just Assert for the function
2194  * OIDs.
2195  */
2196 #ifdef USE_ASSERT_CHECKING
2197  for (i = 0; i < partkey->partnatts; i++)
2198  Assert(partkey->partsupfunc[i].fn_oid ==
2199  part_scheme->partsupfunc[i].fn_oid);
2200 #endif
2201 
2202  /* Found matching partition scheme. */
2203  return part_scheme;
2204  }
2205 
2206  /*
2207  * Did not find matching partition scheme. Create one copying relevant
2208  * information from the relcache. We need to copy the contents of the
2209  * array since the relcache entry may not survive after we have closed the
2210  * relation.
2211  */
2212  part_scheme = (PartitionScheme) palloc0(sizeof(PartitionSchemeData));
2213  part_scheme->strategy = partkey->strategy;
2214  part_scheme->partnatts = partkey->partnatts;
2215 
2216  part_scheme->partopfamily = (Oid *) palloc(sizeof(Oid) * partnatts);
2217  memcpy(part_scheme->partopfamily, partkey->partopfamily,
2218  sizeof(Oid) * partnatts);
2219 
2220  part_scheme->partopcintype = (Oid *) palloc(sizeof(Oid) * partnatts);
2221  memcpy(part_scheme->partopcintype, partkey->partopcintype,
2222  sizeof(Oid) * partnatts);
2223 
2224  part_scheme->partcollation = (Oid *) palloc(sizeof(Oid) * partnatts);
2225  memcpy(part_scheme->partcollation, partkey->partcollation,
2226  sizeof(Oid) * partnatts);
2227 
2228  part_scheme->parttyplen = (int16 *) palloc(sizeof(int16) * partnatts);
2229  memcpy(part_scheme->parttyplen, partkey->parttyplen,
2230  sizeof(int16) * partnatts);
2231 
2232  part_scheme->parttypbyval = (bool *) palloc(sizeof(bool) * partnatts);
2233  memcpy(part_scheme->parttypbyval, partkey->parttypbyval,
2234  sizeof(bool) * partnatts);
2235 
2236  part_scheme->partsupfunc = (FmgrInfo *)
2237  palloc(sizeof(FmgrInfo) * partnatts);
2238  for (i = 0; i < partnatts; i++)
2239  fmgr_info_copy(&part_scheme->partsupfunc[i], &partkey->partsupfunc[i],
2241 
2242  /* Add the partitioning scheme to PlannerInfo. */
2243  root->part_schemes = lappend(root->part_schemes, part_scheme);
2244 
2245  return part_scheme;
2246 }
signed short int16
Definition: c.h:345
Definition: fmgr.h:56
Oid * partopfamily
Definition: partcache.h:33
FmgrInfo * partsupfunc
Definition: partcache.h:35
List * part_schemes
Definition: pathnodes.h:303
unsigned int Oid
Definition: postgres_ext.h:31
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:610
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
struct PartitionSchemeData * PartitionScheme
Definition: pathnodes.h:405
List * lappend(List *list, void *datum)
Definition: list.c:321
Oid * partcollation
Definition: partcache.h:38
void * palloc0(Size size)
Definition: mcxt.c:955
Oid fn_oid
Definition: fmgr.h:59
bool * parttypbyval
Definition: partcache.h:44
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
int16 * parttyplen
Definition: partcache.h:43
struct FmgrInfo * partsupfunc
Definition: pathnodes.h:402
#define RelationGetPartitionKey(relation)
Definition: rel.h:597
void * palloc(Size size)
Definition: mcxt.c:924
Oid * partopcintype
Definition: partcache.h:34
int i

◆ function_selectivity()

Selectivity function_selectivity ( PlannerInfo root,
Oid  funcid,
List args,
Oid  inputcollid,
bool  is_join,
int  varRelid,
JoinType  jointype,
SpecialJoinInfo sjinfo 
)

Definition at line 1844 of file plancat.c.

References SupportRequestSelectivity::args, generate_unaccent_rules::args, DatumGetPointer, elog, ERROR, SupportRequestSelectivity::funcid, get_func_support(), SupportRequestSelectivity::inputcollid, SupportRequestSelectivity::is_join, SupportRequestSelectivity::jointype, OidFunctionCall1, PointerGetDatum, SupportRequestSelectivity::root, SupportRequestSelectivity::selectivity, SupportRequestSelectivity::sjinfo, T_SupportRequestSelectivity, SupportRequestSelectivity::type, and SupportRequestSelectivity::varRelid.

Referenced by clause_selectivity().

1852 {
1853  RegProcedure prosupport = get_func_support(funcid);
1855  SupportRequestSelectivity *sresult;
1856 
1857  /*
1858  * If no support function is provided, use our historical default
1859  * estimate, 0.3333333. This seems a pretty unprincipled choice, but
1860  * Postgres has been using that estimate for function calls since 1992.
1861  * The hoariness of this behavior suggests that we should not be in too
1862  * much hurry to use another value.
1863  */
1864  if (!prosupport)
1865  return (Selectivity) 0.3333333;
1866 
1868  req.root = root;
1869  req.funcid = funcid;
1870  req.args = args;
1871  req.inputcollid = inputcollid;
1872  req.is_join = is_join;
1873  req.varRelid = varRelid;
1874  req.jointype = jointype;
1875  req.sjinfo = sjinfo;
1876  req.selectivity = -1; /* to catch failure to set the value */
1877 
1878  sresult = (SupportRequestSelectivity *)
1879  DatumGetPointer(OidFunctionCall1(prosupport,
1880  PointerGetDatum(&req)));
1881 
1882  /* If support function fails, use default */
1883  if (sresult != &req)
1884  return (Selectivity) 0.3333333;
1885 
1886  if (req.selectivity < 0.0 || req.selectivity > 1.0)
1887  elog(ERROR, "invalid function selectivity: %f", req.selectivity);
1888 
1889  return (Selectivity) req.selectivity;
1890 }
#define PointerGetDatum(X)
Definition: postgres.h:556
regproc RegProcedure
Definition: c.h:505
double Selectivity
Definition: nodes.h:658
#define ERROR
Definition: elog.h:43
struct PlannerInfo * root
Definition: supportnodes.h:96
struct SpecialJoinInfo * sjinfo
Definition: supportnodes.h:103
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:655
RegProcedure get_func_support(Oid funcid)
Definition: lsyscache.c:1660
#define DatumGetPointer(X)
Definition: postgres.h:549
#define elog(elevel,...)
Definition: elog.h:226

◆ get_function_rows()

double get_function_rows ( PlannerInfo root,
Oid  funcid,
Node node 
)

Definition at line 1967 of file plancat.c.

References Assert, DatumGetPointer, elog, ERROR, SupportRequestRows::funcid, GETSTRUCT, HeapTupleIsValid, SupportRequestRows::node, ObjectIdGetDatum, OidFunctionCall1, OidIsValid, PointerGetDatum, PROCOID, ReleaseSysCache(), SupportRequestRows::root, SupportRequestRows::rows, SearchSysCache1(), T_SupportRequestRows, and SupportRequestRows::type.

Referenced by expression_returns_set_rows().

1968 {
1969  HeapTuple proctup;
1970  Form_pg_proc procform;
1971  double result;
1972 
1973  proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
1974  if (!HeapTupleIsValid(proctup))
1975  elog(ERROR, "cache lookup failed for function %u", funcid);
1976  procform = (Form_pg_proc) GETSTRUCT(proctup);
1977 
1978  Assert(procform->proretset); /* else caller error */
1979 
1980  if (OidIsValid(procform->prosupport))
1981  {
1982  SupportRequestRows req;
1983  SupportRequestRows *sresult;
1984 
1985  req.type = T_SupportRequestRows;
1986  req.root = root;
1987  req.funcid = funcid;
1988  req.node = node;
1989 
1990  req.rows = 0; /* just for sanity */
1991 
1992  sresult = (SupportRequestRows *)
1993  DatumGetPointer(OidFunctionCall1(procform->prosupport,
1994  PointerGetDatum(&req)));
1995 
1996  if (sresult == &req)
1997  {
1998  /* Success */
1999  ReleaseSysCache(proctup);
2000  return req.rows;
2001  }
2002  }
2003 
2004  /* No support function, or it failed, so rely on prorows */
2005  result = procform->prorows;
2006 
2007  ReleaseSysCache(proctup);
2008 
2009  return result;
2010 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define PointerGetDatum(X)
Definition: postgres.h:556
#define OidIsValid(objectId)
Definition: c.h:638
struct PlannerInfo * root
Definition: supportnodes.h:163
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define OidFunctionCall1(functionId, arg1)
Definition: fmgr.h:655
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
FormData_pg_proc * Form_pg_proc
Definition: pg_proc.h:134
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define Assert(condition)
Definition: c.h:732
#define DatumGetPointer(X)
Definition: postgres.h:549
#define elog(elevel,...)
Definition: elog.h:226

◆ get_rel_data_width()

int32 get_rel_data_width ( Relation  rel,
int32 attr_widths 
)

Definition at line 1088 of file plancat.c.

References Assert, get_attavgwidth(), get_typavgwidth(), i, RelationData::rd_att, RelationGetNumberOfAttributes, RelationGetRelid, and TupleDescAttr.

Referenced by estimate_rel_size(), get_relation_data_width(), and table_block_relation_estimate_size().

1089 {
1090  int32 tuple_width = 0;
1091  int i;
1092 
1093  for (i = 1; i <= RelationGetNumberOfAttributes(rel); i++)
1094  {
1095  Form_pg_attribute att = TupleDescAttr(rel->rd_att, i - 1);
1096  int32 item_width;
1097 
1098  if (att->attisdropped)
1099  continue;
1100 
1101  /* use previously cached data, if any */
1102  if (attr_widths != NULL && attr_widths[i] > 0)
1103  {
1104  tuple_width += attr_widths[i];
1105  continue;
1106  }
1107 
1108  /* This should match set_rel_width() in costsize.c */
1109  item_width = get_attavgwidth(RelationGetRelid(rel), i);
1110  if (item_width <= 0)
1111  {
1112  item_width = get_typavgwidth(att->atttypid, att->atttypmod);
1113  Assert(item_width > 0);
1114  }
1115  if (attr_widths != NULL)
1116  attr_widths[i] = item_width;
1117  tuple_width += item_width;
1118  }
1119 
1120  return tuple_width;
1121 }
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:422
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
signed int int32
Definition: c.h:346
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
TupleDesc rd_att
Definition: rel.h:84
int32 get_typavgwidth(Oid typid, int32 typmod)
Definition: lsyscache.c:2356
#define Assert(condition)
Definition: c.h:732
int i
int32 get_attavgwidth(Oid relid, AttrNumber attnum)
Definition: lsyscache.c:2870
#define RelationGetRelid(relation)
Definition: rel.h:416

◆ get_relation_constraints()

static List * get_relation_constraints ( PlannerInfo root,
Oid  relationObjectId,
RelOptInfo rel,
bool  include_noinherit,
bool  include_notnull,
bool  include_partition 
)
static

Definition at line 1170 of file plancat.c.

References NullTest::arg, NullTest::argisrow, canonicalize_qual(), ConstrCheck::ccbin, ConstrCheck::ccnoinherit, ConstrCheck::ccvalid, ChangeVarNodes(), TupleConstr::check, TupleDescData::constr, eval_const_expressions(), TupleConstr::has_not_null, i, IS_NOT_NULL, lappend(), list_concat(), NullTest::location, make_ands_implicit(), makeNode, makeVar(), TupleDescData::natts, NIL, NoLock, NullTest::nulltesttype, TupleConstr::num_check, RelOptInfo::partition_qual, RelationData::rd_att, RelationData::rd_rel, RelOptInfo::relid, set_baserel_partition_constraint(), stringToNode(), table_close(), table_open(), and TupleDescAttr.

Referenced by relation_excluded_by_constraints().

1175 {
1176  List *result = NIL;
1177  Index varno = rel->relid;
1178  Relation relation;
1179  TupleConstr *constr;
1180 
1181  /*
1182  * We assume the relation has already been safely locked.
1183  */
1184  relation = table_open(relationObjectId, NoLock);
1185 
1186  constr = relation->rd_att->constr;
1187  if (constr != NULL)
1188  {
1189  int num_check = constr->num_check;
1190  int i;
1191 
1192  for (i = 0; i < num_check; i++)
1193  {
1194  Node *cexpr;
1195 
1196  /*
1197  * If this constraint hasn't been fully validated yet, we must
1198  * ignore it here. Also ignore if NO INHERIT and we weren't told
1199  * that that's safe.
1200  */
1201  if (!constr->check[i].ccvalid)
1202  continue;
1203  if (constr->check[i].ccnoinherit && !include_noinherit)
1204  continue;
1205 
1206  cexpr = stringToNode(constr->check[i].ccbin);
1207 
1208  /*
1209  * Run each expression through const-simplification and
1210  * canonicalization. This is not just an optimization, but is
1211  * necessary, because we will be comparing it to
1212  * similarly-processed qual clauses, and may fail to detect valid
1213  * matches without this. This must match the processing done to
1214  * qual clauses in preprocess_expression()! (We can skip the
1215  * stuff involving subqueries, however, since we don't allow any
1216  * in check constraints.)
1217  */
1218  cexpr = eval_const_expressions(root, cexpr);
1219 
1220  cexpr = (Node *) canonicalize_qual((Expr *) cexpr, true);
1221 
1222  /* Fix Vars to have the desired varno */
1223  if (varno != 1)
1224  ChangeVarNodes(cexpr, 1, varno, 0);
1225 
1226  /*
1227  * Finally, convert to implicit-AND format (that is, a List) and
1228  * append the resulting item(s) to our output list.
1229  */
1230  result = list_concat(result,
1231  make_ands_implicit((Expr *) cexpr));
1232  }
1233 
1234  /* Add NOT NULL constraints in expression form, if requested */
1235  if (include_notnull && constr->has_not_null)
1236  {
1237  int natts = relation->rd_att->natts;
1238 
1239  for (i = 1; i <= natts; i++)
1240  {
1241  Form_pg_attribute att = TupleDescAttr(relation->rd_att, i - 1);
1242 
1243  if (att->attnotnull && !att->attisdropped)
1244  {
1245  NullTest *ntest = makeNode(NullTest);
1246 
1247  ntest->arg = (Expr *) makeVar(varno,
1248  i,
1249  att->atttypid,
1250  att->atttypmod,
1251  att->attcollation,
1252  0);
1253  ntest->nulltesttype = IS_NOT_NULL;
1254 
1255  /*
1256  * argisrow=false is correct even for a composite column,
1257  * because attnotnull does not represent a SQL-spec IS NOT
1258  * NULL test in such a case, just IS DISTINCT FROM NULL.
1259  */
1260  ntest->argisrow = false;
1261  ntest->location = -1;
1262  result = lappend(result, ntest);
1263  }
1264  }
1265  }
1266  }
1267 
1268  /*
1269  * Add partitioning constraints, if requested.
1270  */
1271  if (include_partition && relation->rd_rel->relispartition)
1272  {
1273  /* make sure rel->partition_qual is set */
1274  set_baserel_partition_constraint(relation, rel);
1275  result = list_concat(result, rel->partition_qual);
1276  }
1277 
1278  table_close(relation, NoLock);
1279 
1280  return result;
1281 }
#define NIL
Definition: pg_list.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
Definition: nodes.h:525
List * list_concat(List *list1, const List *list2)
Definition: list.c:515
void * stringToNode(const char *str)
Definition: read.c:89
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2253
Form_pg_class rd_rel
Definition: rel.h:83
Expr * arg
Definition: primnodes.h:1205
#define NoLock
Definition: lockdefs.h:34
TupleConstr * constr
Definition: tupdesc.h:85
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:292
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
Index relid
Definition: pathnodes.h:669
List * lappend(List *list, void *datum)
Definition: list.c:321
List * make_ands_implicit(Expr *clause)
Definition: makefuncs.c:716
unsigned int Index
Definition: c.h:475
TupleDesc rd_att
Definition: rel.h:84
NullTestType nulltesttype
Definition: primnodes.h:1206
uint16 num_check
Definition: tupdesc.h:43
static void set_baserel_partition_constraint(Relation relation, RelOptInfo *rel)
Definition: plancat.c:2323
#define makeNode(_type_)
Definition: nodes.h:573
int location
Definition: primnodes.h:1208
int i
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
bool argisrow
Definition: primnodes.h:1207
ConstrCheck * check
Definition: tupdesc.h:40
bool ccvalid
Definition: tupdesc.h:32
List * partition_qual
Definition: pathnodes.h:721
bool has_not_null
Definition: tupdesc.h:44
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
char * ccbin
Definition: tupdesc.h:31
bool ccnoinherit
Definition: tupdesc.h:33

◆ get_relation_data_width()

int32 get_relation_data_width ( Oid  relid,
int32 attr_widths 
)

Definition at line 1130 of file plancat.c.

References get_rel_data_width(), NoLock, table_close(), and table_open().

Referenced by plan_cluster_use_sort(), and set_rel_width().

1131 {
1132  int32 result;
1133  Relation relation;
1134 
1135  /* As above, assume relation is already locked */
1136  relation = table_open(relid, NoLock);
1137 
1138  result = get_rel_data_width(relation, attr_widths);
1139 
1140  table_close(relation, NoLock);
1141 
1142  return result;
1143 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
signed int int32
Definition: c.h:346
#define NoLock
Definition: lockdefs.h:34
int32 get_rel_data_width(Relation rel, int32 *attr_widths)
Definition: plancat.c:1088
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

◆ get_relation_foreign_keys()

static void get_relation_foreign_keys ( PlannerInfo root,
RelOptInfo rel,
Relation  relation,
bool  inhparent 
)
static

Definition at line 486 of file plancat.c.

References Assert, ForeignKeyOptInfo::con_relid, ForeignKeyCacheInfo::confkey, ForeignKeyOptInfo::confkey, ForeignKeyCacheInfo::confrelid, ForeignKeyCacheInfo::conkey, ForeignKeyOptInfo::conkey, ForeignKeyCacheInfo::conpfeqop, ForeignKeyOptInfo::conpfeqop, ForeignKeyCacheInfo::conrelid, ForeignKeyOptInfo::eclass, PlannerInfo::fkey_list, RangeTblEntry::inh, lappend(), lfirst, list_length(), makeNode, ForeignKeyCacheInfo::nkeys, ForeignKeyOptInfo::nkeys, ForeignKeyOptInfo::nmatched_ec, ForeignKeyOptInfo::nmatched_rcols, ForeignKeyOptInfo::nmatched_ri, PlannerInfo::parse, ForeignKeyOptInfo::ref_relid, RelationGetFKeyList(), RelationGetRelid, RelOptInfo::relid, RangeTblEntry::relid, RELOPT_BASEREL, RelOptInfo::reloptkind, ForeignKeyOptInfo::rinfos, Query::rtable, RTE_RELATION, and RangeTblEntry::rtekind.

Referenced by get_relation_info().

488 {
489  List *rtable = root->parse->rtable;
490  List *cachedfkeys;
491  ListCell *lc;
492 
493  /*
494  * If it's not a baserel, we don't care about its FKs. Also, if the query
495  * references only a single relation, we can skip the lookup since no FKs
496  * could satisfy the requirements below.
497  */
498  if (rel->reloptkind != RELOPT_BASEREL ||
499  list_length(rtable) < 2)
500  return;
501 
502  /*
503  * If it's the parent of an inheritance tree, ignore its FKs. We could
504  * make useful FK-based deductions if we found that all members of the
505  * inheritance tree have equivalent FK constraints, but detecting that
506  * would require code that hasn't been written.
507  */
508  if (inhparent)
509  return;
510 
511  /*
512  * Extract data about relation's FKs from the relcache. Note that this
513  * list belongs to the relcache and might disappear in a cache flush, so
514  * we must not do any further catalog access within this function.
515  */
516  cachedfkeys = RelationGetFKeyList(relation);
517 
518  /*
519  * Figure out which FKs are of interest for this query, and create
520  * ForeignKeyOptInfos for them. We want only FKs that reference some
521  * other RTE of the current query. In queries containing self-joins,
522  * there might be more than one other RTE for a referenced table, and we
523  * should make a ForeignKeyOptInfo for each occurrence.
524  *
525  * Ideally, we would ignore RTEs that correspond to non-baserels, but it's
526  * too hard to identify those here, so we might end up making some useless
527  * ForeignKeyOptInfos. If so, match_foreign_keys_to_quals() will remove
528  * them again.
529  */
530  foreach(lc, cachedfkeys)
531  {
532  ForeignKeyCacheInfo *cachedfk = (ForeignKeyCacheInfo *) lfirst(lc);
533  Index rti;
534  ListCell *lc2;
535 
536  /* conrelid should always be that of the table we're considering */
537  Assert(cachedfk->conrelid == RelationGetRelid(relation));
538 
539  /* Scan to find other RTEs matching confrelid */
540  rti = 0;
541  foreach(lc2, rtable)
542  {
543  RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
544  ForeignKeyOptInfo *info;
545 
546  rti++;
547  /* Ignore if not the correct table */
548  if (rte->rtekind != RTE_RELATION ||
549  rte->relid != cachedfk->confrelid)
550  continue;
551  /* Ignore if it's an inheritance parent; doesn't really match */
552  if (rte->inh)
553  continue;
554  /* Ignore self-referential FKs; we only care about joins */
555  if (rti == rel->relid)
556  continue;
557 
558  /* OK, let's make an entry */
559  info = makeNode(ForeignKeyOptInfo);
560  info->con_relid = rel->relid;
561  info->ref_relid = rti;
562  info->nkeys = cachedfk->nkeys;
563  memcpy(info->conkey, cachedfk->conkey, sizeof(info->conkey));
564  memcpy(info->confkey, cachedfk->confkey, sizeof(info->confkey));
565  memcpy(info->conpfeqop, cachedfk->conpfeqop, sizeof(info->conpfeqop));
566  /* zero out fields to be filled by match_foreign_keys_to_quals */
567  info->nmatched_ec = 0;
568  info->nmatched_rcols = 0;
569  info->nmatched_ri = 0;
570  memset(info->eclass, 0, sizeof(info->eclass));
571  memset(info->rinfos, 0, sizeof(info->rinfos));
572 
573  root->fkey_list = lappend(root->fkey_list, info);
574  }
575  }
576 }
Query * parse
Definition: pathnodes.h:177
RelOptKind reloptkind
Definition: pathnodes.h:638
AttrNumber conkey[INDEX_MAX_KEYS]
Definition: rel.h:230
List * fkey_list
Definition: pathnodes.h:294
List * rtable
Definition: parsenodes.h:137
Oid conpfeqop[INDEX_MAX_KEYS]
Definition: pathnodes.h:859
Index relid
Definition: pathnodes.h:669
List * lappend(List *list, void *datum)
Definition: list.c:321
struct EquivalenceClass * eclass[INDEX_MAX_KEYS]
Definition: pathnodes.h:866
AttrNumber conkey[INDEX_MAX_KEYS]
Definition: pathnodes.h:857
unsigned int Index
Definition: c.h:475
#define makeNode(_type_)
Definition: nodes.h:573
Oid conpfeqop[INDEX_MAX_KEYS]
Definition: rel.h:232
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
RTEKind rtekind
Definition: parsenodes.h:974
List * RelationGetFKeyList(Relation relation)
Definition: relcache.c:4239
AttrNumber confkey[INDEX_MAX_KEYS]
Definition: rel.h:231
Definition: pg_list.h:50
AttrNumber confkey[INDEX_MAX_KEYS]
Definition: pathnodes.h:858
#define RelationGetRelid(relation)
Definition: rel.h:416
List * rinfos[INDEX_MAX_KEYS]
Definition: pathnodes.h:868

◆ get_relation_info()

void get_relation_info ( PlannerInfo root,
Oid  relationObjectId,
bool  inhparent,
RelOptInfo rel 
)

Definition at line 114 of file plancat.c.

References _bt_getrootheight(), RelOptInfo::allvisfrac, IndexAmRoutine::amcanorder, IndexAmRoutine::amcanorderbyop, IndexOptInfo::amcanorderbyop, IndexAmRoutine::amcanparallel, IndexOptInfo::amcanparallel, IndexAmRoutine::amcostestimate, IndexOptInfo::amcostestimate, IndexAmRoutine::amgetbitmap, IndexAmRoutine::amgettuple, IndexOptInfo::amhasgetbitmap, IndexOptInfo::amhasgettuple, IndexAmRoutine::amoptionalkey, IndexOptInfo::amoptionalkey, IndexAmRoutine::amsearcharray, IndexOptInfo::amsearcharray, IndexAmRoutine::amsearchnulls, IndexOptInfo::amsearchnulls, Assert, RelOptInfo::attr_needed, RelOptInfo::attr_widths, BTLessStrategyNumber, build_index_tlist(), IndexOptInfo::canreturn, ChangeVarNodes(), ereport, errcode(), errmsg(), ERROR, estimate_rel_size(), RelOptInfo::fdwroutine, FirstLowInvalidHeapAttributeNumber, get_opfamily_member(), get_ordering_op_properties(), get_relation_foreign_keys(), get_relation_info_hook, get_relation_statistics(), GetFdwRoutineForRelation(), GetForeignServerIdByRelId(), PlannerInfo::glob, HeapTupleHeaderGetXmin, IndexOptInfo::hypothetical, i, IgnoreSystemIndexes, IndexOptInfo::immediate, index_can_return(), index_close(), index_open(), IndexOptInfo::indexcollations, IndexOptInfo::indexkeys, RelOptInfo::indexlist, IndexOptInfo::indexoid, IndexOptInfo::indexprs, IndexOptInfo::indextlist, IndexOptInfo::indpred, IndexOptInfo::indrestrictinfo, InvalidOid, IsSystemRelation(), lcons(), lfirst_oid, list_free(), makeNode, RelOptInfo::max_attr, RelOptInfo::min_attr, IndexOptInfo::ncolumns, NIL, IndexOptInfo::nkeycolumns, NoLock, IndexOptInfo::nulls_first, OidIsValid, IndexOptInfo::opcintype, IndexOptInfo::opfamily, RelOptInfo::pages, IndexOptInfo::pages, palloc(), palloc0(), IndexOptInfo::predOK, RelationData::rd_indam, RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_indextuple, RelationData::rd_indoption, RelationData::rd_opcintype, RelationData::rd_opfamily, RelationData::rd_rel, RelationData::rd_tableam, RecoveryInProgress(), IndexOptInfo::rel, RelOptInfo::rel_parallel_workers, IndexOptInfo::relam, RelationGetForm, RelationGetIndexExpressions(), RelationGetIndexList(), RelationGetIndexPredicate(), RelationGetNumberOfAttributes, RelationGetNumberOfBlocks, RelationGetParallelWorkers, RelationGetRelid, RelationNeedsWAL, RelOptInfo::relid, RangeTblEntry::rellockmode, RelOptInfo::reltablespace, IndexOptInfo::reltablespace, IndexOptInfo::reverse_sort, TableAmRoutine::scan_bitmap_next_block, RelOptInfo::serverid, set_relation_partition_info(), PlannerInfo::simple_rte_array, IndexOptInfo::sortopfamily, RelOptInfo::statlist, HeapTupleData::t_data, table_close(), table_open(), TransactionIdPrecedes(), TransactionXmin, PlannerGlobal::transientPlan, IndexOptInfo::tree_height, RelOptInfo::tuples, IndexOptInfo::tuples, and IndexOptInfo::unique.

Referenced by build_simple_rel().

116 {
117  Index varno = rel->relid;
118  Relation relation;
119  bool hasindex;
120  List *indexinfos = NIL;
121 
122  /*
123  * We need not lock the relation since it was already locked, either by
124  * the rewriter or when expand_inherited_rtentry() added it to the query's
125  * rangetable.
126  */
127  relation = table_open(relationObjectId, NoLock);
128 
129  /* Temporary and unlogged relations are inaccessible during recovery. */
130  if (!RelationNeedsWAL(relation) && RecoveryInProgress())
131  ereport(ERROR,
132  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
133  errmsg("cannot access temporary or unlogged relations during recovery")));
134 
136  rel->max_attr = RelationGetNumberOfAttributes(relation);
137  rel->reltablespace = RelationGetForm(relation)->reltablespace;
138 
139  Assert(rel->max_attr >= rel->min_attr);
140  rel->attr_needed = (Relids *)
141  palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids));
142  rel->attr_widths = (int32 *)
143  palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));
144 
145  /*
146  * Estimate relation size --- unless it's an inheritance parent, in which
147  * case the size we want is not the rel's own size but the size of its
148  * inheritance tree. That will be computed in set_append_rel_size().
149  */
150  if (!inhparent)
151  estimate_rel_size(relation, rel->attr_widths - rel->min_attr,
152  &rel->pages, &rel->tuples, &rel->allvisfrac);
153 
154  /* Retrieve the parallel_workers reloption, or -1 if not set. */
156 
157  /*
158  * Make list of indexes. Ignore indexes on system catalogs if told to.
159  * Don't bother with indexes for an inheritance parent, either.
160  */
161  if (inhparent ||
162  (IgnoreSystemIndexes && IsSystemRelation(relation)))
163  hasindex = false;
164  else
165  hasindex = relation->rd_rel->relhasindex;
166 
167  if (hasindex)
168  {
169  List *indexoidlist;
170  LOCKMODE lmode;
171  ListCell *l;
172 
173  indexoidlist = RelationGetIndexList(relation);
174 
175  /*
176  * For each index, we get the same type of lock that the executor will
177  * need, and do not release it. This saves a couple of trips to the
178  * shared lock manager while not creating any real loss of
179  * concurrency, because no schema changes could be happening on the
180  * index while we hold lock on the parent rel, and no lock type used
181  * for queries blocks any other kind of index operation.
182  */
183  lmode = root->simple_rte_array[varno]->rellockmode;
184 
185  foreach(l, indexoidlist)
186  {
187  Oid indexoid = lfirst_oid(l);
188  Relation indexRelation;
190  IndexAmRoutine *amroutine;
191  IndexOptInfo *info;
192  int ncolumns,
193  nkeycolumns;
194  int i;
195 
196  /*
197  * Extract info from the relation descriptor for the index.
198  */
199  indexRelation = index_open(indexoid, lmode);
200  index = indexRelation->rd_index;
201 
202  /*
203  * Ignore invalid indexes, since they can't safely be used for
204  * queries. Note that this is OK because the data structure we
205  * are constructing is only used by the planner --- the executor
206  * still needs to insert into "invalid" indexes, if they're marked
207  * indisready.
208  */
209  if (!index->indisvalid)
210  {
211  index_close(indexRelation, NoLock);
212  continue;
213  }
214 
215  /*
216  * Ignore partitioned indexes, since they are not usable for
217  * queries.
218  */
219  if (indexRelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
220  {
221  index_close(indexRelation, NoLock);
222  continue;
223  }
224 
225  /*
226  * If the index is valid, but cannot yet be used, ignore it; but
227  * mark the plan we are generating as transient. See
228  * src/backend/access/heap/README.HOT for discussion.
229  */
230  if (index->indcheckxmin &&
233  {
234  root->glob->transientPlan = true;
235  index_close(indexRelation, NoLock);
236  continue;
237  }
238 
239  info = makeNode(IndexOptInfo);
240 
241  info->indexoid = index->indexrelid;
242  info->reltablespace =
243  RelationGetForm(indexRelation)->reltablespace;
244  info->rel = rel;
245  info->ncolumns = ncolumns = index->indnatts;
246  info->nkeycolumns = nkeycolumns = index->indnkeyatts;
247 
248  info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);
249  info->indexcollations = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
250  info->opfamily = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
251  info->opcintype = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
252  info->canreturn = (bool *) palloc(sizeof(bool) * ncolumns);
253 
254  for (i = 0; i < ncolumns; i++)
255  {
256  info->indexkeys[i] = index->indkey.values[i];
257  info->canreturn[i] = index_can_return(indexRelation, i + 1);
258  }
259 
260  for (i = 0; i < nkeycolumns; i++)
261  {
262  info->opfamily[i] = indexRelation->rd_opfamily[i];
263  info->opcintype[i] = indexRelation->rd_opcintype[i];
264  info->indexcollations[i] = indexRelation->rd_indcollation[i];
265  }
266 
267  info->relam = indexRelation->rd_rel->relam;
268 
269  /* We copy just the fields we need, not all of rd_indam */
270  amroutine = indexRelation->rd_indam;
271  info->amcanorderbyop = amroutine->amcanorderbyop;
272  info->amoptionalkey = amroutine->amoptionalkey;
273  info->amsearcharray = amroutine->amsearcharray;
274  info->amsearchnulls = amroutine->amsearchnulls;
275  info->amcanparallel = amroutine->amcanparallel;
276  info->amhasgettuple = (amroutine->amgettuple != NULL);
277  info->amhasgetbitmap = amroutine->amgetbitmap != NULL &&
278  relation->rd_tableam->scan_bitmap_next_block != NULL;
279  info->amcostestimate = amroutine->amcostestimate;
280  Assert(info->amcostestimate != NULL);
281 
282  /*
283  * Fetch the ordering information for the index, if any.
284  */
285  if (info->relam == BTREE_AM_OID)
286  {
287  /*
288  * If it's a btree index, we can use its opfamily OIDs
289  * directly as the sort ordering opfamily OIDs.
290  */
291  Assert(amroutine->amcanorder);
292 
293  info->sortopfamily = info->opfamily;
294  info->reverse_sort = (bool *) palloc(sizeof(bool) * nkeycolumns);
295  info->nulls_first = (bool *) palloc(sizeof(bool) * nkeycolumns);
296 
297  for (i = 0; i < nkeycolumns; i++)
298  {
299  int16 opt = indexRelation->rd_indoption[i];
300 
301  info->reverse_sort[i] = (opt & INDOPTION_DESC) != 0;
302  info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0;
303  }
304  }
305  else if (amroutine->amcanorder)
306  {
307  /*
308  * Otherwise, identify the corresponding btree opfamilies by
309  * trying to map this index's "<" operators into btree. Since
310  * "<" uniquely defines the behavior of a sort order, this is
311  * a sufficient test.
312  *
313  * XXX This method is rather slow and also requires the
314  * undesirable assumption that the other index AM numbers its
315  * strategies the same as btree. It'd be better to have a way
316  * to explicitly declare the corresponding btree opfamily for
317  * each opfamily of the other index type. But given the lack
318  * of current or foreseeable amcanorder index types, it's not
319  * worth expending more effort on now.
320  */
321  info->sortopfamily = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
322  info->reverse_sort = (bool *) palloc(sizeof(bool) * nkeycolumns);
323  info->nulls_first = (bool *) palloc(sizeof(bool) * nkeycolumns);
324 
325  for (i = 0; i < nkeycolumns; i++)
326  {
327  int16 opt = indexRelation->rd_indoption[i];
328  Oid ltopr;
329  Oid btopfamily;
330  Oid btopcintype;
331  int16 btstrategy;
332 
333  info->reverse_sort[i] = (opt & INDOPTION_DESC) != 0;
334  info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0;
335 
336  ltopr = get_opfamily_member(info->opfamily[i],
337  info->opcintype[i],
338  info->opcintype[i],
340  if (OidIsValid(ltopr) &&
342  &btopfamily,
343  &btopcintype,
344  &btstrategy) &&
345  btopcintype == info->opcintype[i] &&
346  btstrategy == BTLessStrategyNumber)
347  {
348  /* Successful mapping */
349  info->sortopfamily[i] = btopfamily;
350  }
351  else
352  {
353  /* Fail ... quietly treat index as unordered */
354  info->sortopfamily = NULL;
355  info->reverse_sort = NULL;
356  info->nulls_first = NULL;
357  break;
358  }
359  }
360  }
361  else
362  {
363  info->sortopfamily = NULL;
364  info->reverse_sort = NULL;
365  info->nulls_first = NULL;
366  }
367 
368  /*
369  * Fetch the index expressions and predicate, if any. We must
370  * modify the copies we obtain from the relcache to have the
371  * correct varno for the parent relation, so that they match up
372  * correctly against qual clauses.
373  */
374  info->indexprs = RelationGetIndexExpressions(indexRelation);
375  info->indpred = RelationGetIndexPredicate(indexRelation);
376  if (info->indexprs && varno != 1)
377  ChangeVarNodes((Node *) info->indexprs, 1, varno, 0);
378  if (info->indpred && varno != 1)
379  ChangeVarNodes((Node *) info->indpred, 1, varno, 0);
380 
381  /* Build targetlist using the completed indexprs data */
382  info->indextlist = build_index_tlist(root, info, relation);
383 
384  info->indrestrictinfo = NIL; /* set later, in indxpath.c */
385  info->predOK = false; /* set later, in indxpath.c */
386  info->unique = index->indisunique;
387  info->immediate = index->indimmediate;
388  info->hypothetical = false;
389 
390  /*
391  * Estimate the index size. If it's not a partial index, we lock
392  * the number-of-tuples estimate to equal the parent table; if it
393  * is partial then we have to use the same methods as we would for
394  * a table, except we can be sure that the index is not larger
395  * than the table.
396  */
397  if (info->indpred == NIL)
398  {
399  info->pages = RelationGetNumberOfBlocks(indexRelation);
400  info->tuples = rel->tuples;
401  }
402  else
403  {
404  double allvisfrac; /* dummy */
405 
406  estimate_rel_size(indexRelation, NULL,
407  &info->pages, &info->tuples, &allvisfrac);
408  if (info->tuples > rel->tuples)
409  info->tuples = rel->tuples;
410  }
411 
412  if (info->relam == BTREE_AM_OID)
413  {
414  /* For btrees, get tree height while we have the index open */
415  info->tree_height = _bt_getrootheight(indexRelation);
416  }
417  else
418  {
419  /* For other index types, just set it to "unknown" for now */
420  info->tree_height = -1;
421  }
422 
423  index_close(indexRelation, NoLock);
424 
425  /*
426  * We've historically used lcons() here. It'd make more sense to
427  * use lappend(), but that causes the planner to change behavior
428  * in cases where two indexes seem equally attractive. For now,
429  * stick with lcons() --- few tables should have so many indexes
430  * that the O(N^2) behavior of lcons() is really a problem.
431  */
432  indexinfos = lcons(info, indexinfos);
433  }
434 
435  list_free(indexoidlist);
436  }
437 
438  rel->indexlist = indexinfos;
439 
440  rel->statlist = get_relation_statistics(rel, relation);
441 
442  /* Grab foreign-table info using the relcache, while we have it */
443  if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
444  {
446  rel->fdwroutine = GetFdwRoutineForRelation(relation, true);
447  }
448  else
449  {
450  rel->serverid = InvalidOid;
451  rel->fdwroutine = NULL;
452  }
453 
454  /* Collect info about relation's foreign keys, if relevant */
455  get_relation_foreign_keys(root, rel, relation, inhparent);
456 
457  /*
458  * Collect info about relation's partitioning scheme, if any. Only
459  * inheritance parents may be partitioned.
460  */
461  if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
462  set_relation_partition_info(root, rel, relation);
463 
464  table_close(relation, NoLock);
465 
466  /*
467  * Allow a plugin to editorialize on the info we obtained from the
468  * catalogs. Actions might include altering the assumed relation size,
469  * removing an index, or adding a hypothetical index to the indexlist.
470  */
472  (*get_relation_info_hook) (root, relationObjectId, inhparent, rel);
473 }
signed short int16
Definition: c.h:345
#define NIL
Definition: pg_list.h:65
struct IndexAmRoutine * rd_indam
Definition: rel.h:157
List * statlist
Definition: pathnodes.h:679
int16 * rd_indoption
Definition: rel.h:162
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
static List * get_relation_statistics(RelOptInfo *rel, Relation relation)
Definition: plancat.c:1292
Oid * indexcollations
Definition: pathnodes.h:803
Relids * attr_needed
Definition: pathnodes.h:674
bool IsSystemRelation(Relation relation)
Definition: catalog.c:70
amgettuple_function amgettuple
Definition: amapi.h:223
int _bt_getrootheight(Relation rel)
Definition: nbtpage.c:584
int LOCKMODE
Definition: lockdefs.h:26
bool amcanorderbyop
Definition: amapi.h:177
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:422
List * indextlist
Definition: pathnodes.h:816
#define RelationGetForm(relation)
Definition: rel.h:410
double tuples
Definition: pathnodes.h:681
Oid reltablespace
Definition: pathnodes.h:670
Definition: nodes.h:525
Oid * sortopfamily
Definition: pathnodes.h:806
int errcode(int sqlerrcode)
Definition: elog.c:570
Oid reltablespace
Definition: pathnodes.h:790
bool IgnoreSystemIndexes
Definition: miscinit.c:77
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
bool hypothetical
Definition: pathnodes.h:827
bool immediate
Definition: pathnodes.h:826
double tuples
Definition: pathnodes.h:795
Form_pg_class rd_rel
Definition: rel.h:83
unsigned int Oid
Definition: postgres_ext.h:31
bool RecoveryInProgress(void)
Definition: xlog.c:7898
int tree_height
Definition: pathnodes.h:796
#define OidIsValid(objectId)
Definition: c.h:638
bool amoptionalkey
Definition: amapi.h:185
double allvisfrac
Definition: pathnodes.h:682
signed int int32
Definition: c.h:346
List * RelationGetIndexPredicate(Relation relation)
Definition: relcache.c:4644
struct HeapTupleData * rd_indextuple
Definition: rel.h:145
TransactionId TransactionXmin
Definition: snapmgr.c:166
HeapTupleHeader t_data
Definition: htup.h:68
Definition: type.h:89
BlockNumber pages
Definition: pathnodes.h:794
bool index_can_return(Relation indexRelation, int attno)
Definition: indexam.c:722
Form_pg_index rd_index
Definition: rel.h:143
RelOptInfo * rel
Definition: pathnodes.h:791
bool amoptionalkey
Definition: pathnodes.h:831
amgetbitmap_function amgetbitmap
Definition: amapi.h:224
Oid * rd_indcollation
Definition: rel.h:168
#define ERROR
Definition: elog.h:43
bool(* scan_bitmap_next_block)(TableScanDesc scan, struct TBMIterateResult *tbmres)
Definition: tableam.h:641
amcostestimate_function amcostestimate
Definition: amapi.h:216
#define NoLock
Definition: lockdefs.h:34
bool amcanorderbyop
Definition: pathnodes.h:830
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:4582
PlannerGlobal * glob
Definition: pathnodes.h:179
struct FdwRoutine * fdwroutine
Definition: pathnodes.h:694
Oid get_opfamily_member(Oid opfamily, Oid lefttype, Oid righttype, int16 strategy)
Definition: lsyscache.c:163
static void set_relation_partition_info(PlannerInfo *root, RelOptInfo *rel, Relation relation)
Definition: plancat.c:2122
get_relation_info_hook_type get_relation_info_hook
Definition: plancat.c:61
Oid * rd_opfamily
Definition: rel.h:158
void estimate_rel_size(Relation rel, int32 *attr_widths, BlockNumber *pages, double *tuples, double *allvisfrac)
Definition: plancat.c:947
void(* amcostestimate)()
Definition: pathnodes.h:838
#define ereport(elevel, rest)
Definition: elog.h:141
bool amhasgetbitmap
Definition: pathnodes.h:835
bool amcanparallel
Definition: amapi.h:197
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
Index relid
Definition: pathnodes.h:669
RangeTblEntry ** simple_rte_array
Definition: pathnodes.h:209
Oid serverid
Definition: pathnodes.h:690
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
bool amsearchnulls
Definition: amapi.h:189
List * indrestrictinfo
Definition: pathnodes.h:818
void * palloc0(Size size)
Definition: mcxt.c:955
int rel_parallel_workers
Definition: pathnodes.h:687
const struct TableAmRoutine * rd_tableam
Definition: rel.h:140
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:198
unsigned int Index
Definition: c.h:475
List * indexlist
Definition: pathnodes.h:678
bool amsearcharray
Definition: amapi.h:187
bool amhasgettuple
Definition: pathnodes.h:834
#define InvalidOid
Definition: postgres_ext.h:36
List * lcons(void *datum, List *list)
Definition: list.c:453
#define makeNode(_type_)
Definition: nodes.h:573
BlockNumber pages
Definition: pathnodes.h:680
#define Assert(condition)
Definition: c.h:732
static void get_relation_foreign_keys(PlannerInfo *root, RelOptInfo *rel, Relation relation, bool inhparent)
Definition: plancat.c:486
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:313
Oid GetForeignServerIdByRelId(Oid relid)
Definition: foreign.c:340
bool get_ordering_op_properties(Oid opno, Oid *opfamily, Oid *opcintype, int16 *strategy)
Definition: lsyscache.c:204
bool amsearcharray
Definition: pathnodes.h:832
bool amcanorder
Definition: amapi.h:175
int nkeycolumns
Definition: pathnodes.h:800
#define RelationNeedsWAL(relation)
Definition: rel.h:518
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4348
Oid * opcintype
Definition: pathnodes.h:805
Bitmapset * Relids
Definition: pathnodes.h:28
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:152
Oid * opfamily
Definition: pathnodes.h:804
AttrNumber max_attr
Definition: pathnodes.h:673
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:784
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:427
void list_free(List *list)
Definition: list.c:1373
int i
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
#define RelationGetParallelWorkers(relation, defaultpw)
Definition: rel.h:326
static List * build_index_tlist(PlannerInfo *root, IndexOptInfo *index, Relation heapRelation)
Definition: plancat.c:1702
int * indexkeys
Definition: pathnodes.h:801
bool * canreturn
Definition: pathnodes.h:809
bool amsearchnulls
Definition: pathnodes.h:833
Oid * rd_opcintype
Definition: rel.h:159
bool * nulls_first
Definition: pathnodes.h:808
bool * reverse_sort
Definition: pathnodes.h:807
#define BTLessStrategyNumber
Definition: stratnum.h:29
List * indpred
Definition: pathnodes.h:814
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
int32 * attr_widths
Definition: pathnodes.h:675
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:416
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:126
bool amcanparallel
Definition: pathnodes.h:836
#define lfirst_oid(lc)
Definition: pg_list.h:192
List * indexprs
Definition: pathnodes.h:813
bool transientPlan
Definition: pathnodes.h:137
AttrNumber min_attr
Definition: pathnodes.h:672

◆ get_relation_statistics()

static List * get_relation_statistics ( RelOptInfo rel,
Relation  relation 
)
static

Definition at line 1292 of file plancat.c.

References bms_add_member(), bms_copy(), bms_free(), elog, ERROR, GETSTRUCT, HeapTupleIsValid, i, StatisticExtInfo::keys, StatisticExtInfo::kind, lappend(), lfirst_oid, list_free(), makeNode, NIL, ObjectIdGetDatum, StatisticExtInfo::rel, RelationGetStatExtList(), ReleaseSysCache(), SearchSysCache1(), statext_is_kind_built(), STATEXTDATASTXOID, STATEXTOID, and StatisticExtInfo::statOid.

Referenced by get_relation_info().

1293 {
1294  List *statoidlist;
1295  List *stainfos = NIL;
1296  ListCell *l;
1297 
1298  statoidlist = RelationGetStatExtList(relation);
1299 
1300  foreach(l, statoidlist)
1301  {
1302  Oid statOid = lfirst_oid(l);
1303  Form_pg_statistic_ext staForm;
1304  HeapTuple htup;
1305  HeapTuple dtup;
1306  Bitmapset *keys = NULL;
1307  int i;
1308 
1309  htup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statOid));
1310  if (!HeapTupleIsValid(htup))
1311  elog(ERROR, "cache lookup failed for statistics object %u", statOid);
1312  staForm = (Form_pg_statistic_ext) GETSTRUCT(htup);
1313 
1315  if (!HeapTupleIsValid(dtup))
1316  elog(ERROR, "cache lookup failed for statistics object %u", statOid);
1317 
1318  /*
1319  * First, build the array of columns covered. This is ultimately
1320  * wasted if no stats within the object have actually been built, but
1321  * it doesn't seem worth troubling over that case.
1322  */
1323  for (i = 0; i < staForm->stxkeys.dim1; i++)
1324  keys = bms_add_member(keys, staForm->stxkeys.values[i]);
1325 
1326  /* add one StatisticExtInfo for each kind built */
1327  if (statext_is_kind_built(dtup, STATS_EXT_NDISTINCT))
1328  {
1330 
1331  info->statOid = statOid;
1332  info->rel = rel;
1333  info->kind = STATS_EXT_NDISTINCT;
1334  info->keys = bms_copy(keys);
1335 
1336  stainfos = lappend(stainfos, info);
1337  }
1338 
1339  if (statext_is_kind_built(dtup, STATS_EXT_DEPENDENCIES))
1340  {
1342 
1343  info->statOid = statOid;
1344  info->rel = rel;
1345  info->kind = STATS_EXT_DEPENDENCIES;
1346  info->keys = bms_copy(keys);
1347 
1348  stainfos = lappend(stainfos, info);
1349  }
1350 
1351  if (statext_is_kind_built(dtup, STATS_EXT_MCV))
1352  {
1354 
1355  info->statOid = statOid;
1356  info->rel = rel;
1357  info->kind = STATS_EXT_MCV;
1358  info->keys = bms_copy(keys);
1359 
1360  stainfos = lappend(stainfos, info);
1361  }
1362 
1363  ReleaseSysCache(htup);
1364  ReleaseSysCache(dtup);
1365  bms_free(keys);
1366  }
1367 
1368  list_free(statoidlist);
1369 
1370  return stainfos;
1371 }
#define NIL
Definition: pg_list.h:65
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:74
bool statext_is_kind_built(HeapTuple htup, char type)
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
RelOptInfo * rel
Definition: pathnodes.h:883
List * lappend(List *list, void *datum)
Definition: list.c:321
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1124
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1172
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define makeNode(_type_)
Definition: nodes.h:573
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
List * RelationGetStatExtList(Relation relation)
Definition: relcache.c:4467
Bitmapset * keys
Definition: pathnodes.h:885
void list_free(List *list)
Definition: list.c:1373
#define elog(elevel,...)
Definition: elog.h:226
int i
Definition: pg_list.h:50
FormData_pg_statistic_ext * Form_pg_statistic_ext
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ has_row_triggers()

bool has_row_triggers ( PlannerInfo root,
Index  rti,
CmdType  event 
)

Definition at line 2057 of file plancat.c.

References CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog, ERROR, NoLock, planner_rt_fetch, RangeTblEntry::relid, table_close(), table_open(), TriggerDesc::trig_delete_after_row, TriggerDesc::trig_delete_before_row, TriggerDesc::trig_insert_after_row, TriggerDesc::trig_insert_before_row, TriggerDesc::trig_update_after_row, TriggerDesc::trig_update_before_row, and RelationData::trigdesc.

Referenced by make_modifytable().

2058 {
2059  RangeTblEntry *rte = planner_rt_fetch(rti, root);
2060  Relation relation;
2061  TriggerDesc *trigDesc;
2062  bool result = false;
2063 
2064  /* Assume we already have adequate lock */
2065  relation = table_open(rte->relid, NoLock);
2066 
2067  trigDesc = relation->trigdesc;
2068  switch (event)
2069  {
2070  case CMD_INSERT:
2071  if (trigDesc &&
2072  (trigDesc->trig_insert_after_row ||
2073  trigDesc->trig_insert_before_row))
2074  result = true;
2075  break;
2076  case CMD_UPDATE:
2077  if (trigDesc &&
2078  (trigDesc->trig_update_after_row ||
2079  trigDesc->trig_update_before_row))
2080  result = true;
2081  break;
2082  case CMD_DELETE:
2083  if (trigDesc &&
2084  (trigDesc->trig_delete_after_row ||
2085  trigDesc->trig_delete_before_row))
2086  result = true;
2087  break;
2088  default:
2089  elog(ERROR, "unrecognized CmdType: %d", (int) event);
2090  break;
2091  }
2092 
2093  table_close(relation, NoLock);
2094  return result;
2095 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define ERROR
Definition: elog.h:43
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:371
TriggerDesc * trigdesc
Definition: rel.h:89
bool trig_delete_after_row
Definition: reltrigger.h:66
#define NoLock
Definition: lockdefs.h:34
bool trig_update_before_row
Definition: reltrigger.h:60
bool trig_insert_after_row
Definition: reltrigger.h:56
bool trig_update_after_row
Definition: reltrigger.h:61
bool trig_insert_before_row
Definition: reltrigger.h:55
#define elog(elevel,...)
Definition: elog.h:226
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
bool trig_delete_before_row
Definition: reltrigger.h:65

◆ has_stored_generated_columns()

bool has_stored_generated_columns ( PlannerInfo root,
Index  rti 
)

Definition at line 2098 of file plancat.c.

References TupleDescData::constr, TupleConstr::has_generated_stored, heap_close, heap_open, NoLock, planner_rt_fetch, RelationGetDescr, and RangeTblEntry::relid.

Referenced by make_modifytable().

2099 {
2100  RangeTblEntry *rte = planner_rt_fetch(rti, root);
2101  Relation relation;
2102  TupleDesc tupdesc;
2103  bool result = false;
2104 
2105  /* Assume we already have adequate lock */
2106  relation = heap_open(rte->relid, NoLock);
2107 
2108  tupdesc = RelationGetDescr(relation);
2109  result = tupdesc->constr && tupdesc->constr->has_generated_stored;
2110 
2111  heap_close(relation, NoLock);
2112 
2113  return result;
2114 }
#define RelationGetDescr(relation)
Definition: rel.h:442
bool has_generated_stored
Definition: tupdesc.h:45
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:371
#define NoLock
Definition: lockdefs.h:34
TupleConstr * constr
Definition: tupdesc.h:85
#define heap_close(r, l)
Definition: table.h:36
#define heap_open(r, l)
Definition: table.h:33

◆ has_unique_index()

bool has_unique_index ( RelOptInfo rel,
AttrNumber  attno 
)

Definition at line 2025 of file plancat.c.

References IndexOptInfo::indexkeys, RelOptInfo::indexlist, IndexOptInfo::indpred, lfirst, NIL, IndexOptInfo::nkeycolumns, IndexOptInfo::predOK, and IndexOptInfo::unique.

Referenced by examine_variable().

2026 {
2027  ListCell *ilist;
2028 
2029  foreach(ilist, rel->indexlist)
2030  {
2031  IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
2032 
2033  /*
2034  * Note: ignore partial indexes, since they don't allow us to conclude
2035  * that all attr values are distinct, *unless* they are marked predOK
2036  * which means we know the index's predicate is satisfied by the
2037  * query. We don't take any interest in expressional indexes either.
2038  * Also, a multicolumn unique index doesn't allow us to conclude that
2039  * just the specified attr is unique.
2040  */
2041  if (index->unique &&
2042  index->nkeycolumns == 1 &&
2043  index->indexkeys[0] == attno &&
2044  (index->indpred == NIL || index->predOK))
2045  return true;
2046  }
2047  return false;
2048 }
#define NIL
Definition: pg_list.h:65
Definition: type.h:89
List * indexlist
Definition: pathnodes.h:678
#define lfirst(lc)
Definition: pg_list.h:190
int nkeycolumns
Definition: pathnodes.h:800
int * indexkeys
Definition: pathnodes.h:801
List * indpred
Definition: pathnodes.h:814

◆ infer_arbiter_indexes()

List* infer_arbiter_indexes ( PlannerInfo root)

Definition at line 599 of file plancat.c.

References OnConflictExpr::action, OnConflictExpr::arbiterElems, OnConflictExpr::arbiterWhere, bms_add_member(), bms_equal(), OnConflictExpr::constraint, ereport, errcode(), errmsg(), ERROR, InferenceElem::expr, FirstLowInvalidHeapAttributeNumber, get_constraint_index(), index_close(), index_open(), infer_collation_opclass_match(), InferenceElem::infercollid, InferenceElem::inferopclass, InvalidOid, IsA, lappend(), lappend_oid(), lfirst, lfirst_oid, list_difference(), list_free(), list_member(), next, NIL, NoLock, Query::onConflict, ONCONFLICT_UPDATE, PlannerInfo::parse, predicate_implied_by(), RelationData::rd_index, RelationGetIndexExpressions(), RelationGetIndexList(), RelationGetIndexPredicate(), RangeTblEntry::relid, RangeTblEntry::rellockmode, Query::resultRelation, rt_fetch, Query::rtable, table_close(), table_open(), and Var::varattno.

Referenced by make_modifytable().

600 {
601  OnConflictExpr *onconflict = root->parse->onConflict;
602 
603  /* Iteration state */
604  RangeTblEntry *rte;
605  Relation relation;
606  Oid indexOidFromConstraint = InvalidOid;
607  List *indexList;
608  ListCell *l;
609 
610  /* Normalized inference attributes and inference expressions: */
611  Bitmapset *inferAttrs = NULL;
612  List *inferElems = NIL;
613 
614  /* Results */
615  List *results = NIL;
616 
617  /*
618  * Quickly return NIL for ON CONFLICT DO NOTHING without an inference
619  * specification or named constraint. ON CONFLICT DO UPDATE statements
620  * must always provide one or the other (but parser ought to have caught
621  * that already).
622  */
623  if (onconflict->arbiterElems == NIL &&
624  onconflict->constraint == InvalidOid)
625  return NIL;
626 
627  /*
628  * We need not lock the relation since it was already locked, either by
629  * the rewriter or when expand_inherited_rtentry() added it to the query's
630  * rangetable.
631  */
632  rte = rt_fetch(root->parse->resultRelation, root->parse->rtable);
633 
634  relation = table_open(rte->relid, NoLock);
635 
636  /*
637  * Build normalized/BMS representation of plain indexed attributes, as
638  * well as a separate list of expression items. This simplifies matching
639  * the cataloged definition of indexes.
640  */
641  foreach(l, onconflict->arbiterElems)
642  {
643  InferenceElem *elem = (InferenceElem *) lfirst(l);
644  Var *var;
645  int attno;
646 
647  if (!IsA(elem->expr, Var))
648  {
649  /* If not a plain Var, just shove it in inferElems for now */
650  inferElems = lappend(inferElems, elem->expr);
651  continue;
652  }
653 
654  var = (Var *) elem->expr;
655  attno = var->varattno;
656 
657  if (attno == 0)
658  ereport(ERROR,
659  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
660  errmsg("whole row unique index inference specifications are not supported")));
661 
662  inferAttrs = bms_add_member(inferAttrs,
664  }
665 
666  /*
667  * Lookup named constraint's index. This is not immediately returned
668  * because some additional sanity checks are required.
669  */
670  if (onconflict->constraint != InvalidOid)
671  {
672  indexOidFromConstraint = get_constraint_index(onconflict->constraint);
673 
674  if (indexOidFromConstraint == InvalidOid)
675  ereport(ERROR,
676  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
677  errmsg("constraint in ON CONFLICT clause has no associated index")));
678  }
679 
680  /*
681  * Using that representation, iterate through the list of indexes on the
682  * target relation to try and find a match
683  */
684  indexList = RelationGetIndexList(relation);
685 
686  foreach(l, indexList)
687  {
688  Oid indexoid = lfirst_oid(l);
689  Relation idxRel;
690  Form_pg_index idxForm;
691  Bitmapset *indexedAttrs;
692  List *idxExprs;
693  List *predExprs;
694  AttrNumber natt;
695  ListCell *el;
696 
697  /*
698  * Extract info from the relation descriptor for the index. Obtain
699  * the same lock type that the executor will ultimately use.
700  *
701  * Let executor complain about !indimmediate case directly, because
702  * enforcement needs to occur there anyway when an inference clause is
703  * omitted.
704  */
705  idxRel = index_open(indexoid, rte->rellockmode);
706  idxForm = idxRel->rd_index;
707 
708  if (!idxForm->indisvalid)
709  goto next;
710 
711  /*
712  * Note that we do not perform a check against indcheckxmin (like e.g.
713  * get_relation_info()) here to eliminate candidates, because
714  * uniqueness checking only cares about the most recently committed
715  * tuple versions.
716  */
717 
718  /*
719  * Look for match on "ON constraint_name" variant, which may not be
720  * unique constraint. This can only be a constraint name.
721  */
722  if (indexOidFromConstraint == idxForm->indexrelid)
723  {
724  if (!idxForm->indisunique && onconflict->action == ONCONFLICT_UPDATE)
725  ereport(ERROR,
726  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
727  errmsg("ON CONFLICT DO UPDATE not supported with exclusion constraints")));
728 
729  results = lappend_oid(results, idxForm->indexrelid);
730  list_free(indexList);
731  index_close(idxRel, NoLock);
732  table_close(relation, NoLock);
733  return results;
734  }
735  else if (indexOidFromConstraint != InvalidOid)
736  {
737  /* No point in further work for index in named constraint case */
738  goto next;
739  }
740 
741  /*
742  * Only considering conventional inference at this point (not named
743  * constraints), so index under consideration can be immediately
744  * skipped if it's not unique
745  */
746  if (!idxForm->indisunique)
747  goto next;
748 
749  /* Build BMS representation of plain (non expression) index attrs */
750  indexedAttrs = NULL;
751  for (natt = 0; natt < idxForm->indnkeyatts; natt++)
752  {
753  int attno = idxRel->rd_index->indkey.values[natt];
754 
755  if (attno != 0)
756  indexedAttrs = bms_add_member(indexedAttrs,
758  }
759 
760  /* Non-expression attributes (if any) must match */
761  if (!bms_equal(indexedAttrs, inferAttrs))
762  goto next;
763 
764  /* Expression attributes (if any) must match */
765  idxExprs = RelationGetIndexExpressions(idxRel);
766  foreach(el, onconflict->arbiterElems)
767  {
768  InferenceElem *elem = (InferenceElem *) lfirst(el);
769 
770  /*
771  * Ensure that collation/opclass aspects of inference expression
772  * element match. Even though this loop is primarily concerned
773  * with matching expressions, it is a convenient point to check
774  * this for both expressions and ordinary (non-expression)
775  * attributes appearing as inference elements.
776  */
777  if (!infer_collation_opclass_match(elem, idxRel, idxExprs))
778  goto next;
779 
780  /*
781  * Plain Vars don't factor into count of expression elements, and
782  * the question of whether or not they satisfy the index
783  * definition has already been considered (they must).
784  */
785  if (IsA(elem->expr, Var))
786  continue;
787 
788  /*
789  * Might as well avoid redundant check in the rare cases where
790  * infer_collation_opclass_match() is required to do real work.
791  * Otherwise, check that element expression appears in cataloged
792  * index definition.
793  */
794  if (elem->infercollid != InvalidOid ||
795  elem->inferopclass != InvalidOid ||
796  list_member(idxExprs, elem->expr))
797  continue;
798 
799  goto next;
800  }
801 
802  /*
803  * Now that all inference elements were matched, ensure that the
804  * expression elements from inference clause are not missing any
805  * cataloged expressions. This does the right thing when unique
806  * indexes redundantly repeat the same attribute, or if attributes
807  * redundantly appear multiple times within an inference clause.
808  */
809  if (list_difference(idxExprs, inferElems) != NIL)
810  goto next;
811 
812  /*
813  * If it's a partial index, its predicate must be implied by the ON
814  * CONFLICT's WHERE clause.
815  */
816  predExprs = RelationGetIndexPredicate(idxRel);
817 
818  if (!predicate_implied_by(predExprs, (List *) onconflict->arbiterWhere, false))
819  goto next;
820 
821  results = lappend_oid(results, idxForm->indexrelid);
822 next:
823  index_close(idxRel, NoLock);
824  }
825 
826  list_free(indexList);
827  table_close(relation, NoLock);
828 
829  if (results == NIL)
830  ereport(ERROR,
831  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
832  errmsg("there is no unique or exclusion constraint matching the ON CONFLICT specification")));
833 
834  return results;
835 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Query * parse
Definition: pathnodes.h:177
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
static int32 next
Definition: blutils.c:213
OnConflictExpr * onConflict
Definition: parsenodes.h:144
int resultRelation
Definition: parsenodes.h:122
static bool infer_collation_opclass_match(InferenceElem *elem, Relation idxRel, List *idxExprs)
Definition: plancat.c:865
int errcode(int sqlerrcode)
Definition: elog.c:570
AttrNumber varattno
Definition: primnodes.h:172
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:167
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
List * RelationGetIndexPredicate(Relation relation)
Definition: relcache.c:4644
List * arbiterElems
Definition: primnodes.h:1515
Form_pg_index rd_index
Definition: rel.h:143
List * rtable
Definition: parsenodes.h:137
#define ERROR
Definition: elog.h:43
bool list_member(const List *list, const void *datum)
Definition: list.c:613
#define NoLock
Definition: lockdefs.h:34
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:4582
#define ereport(elevel, rest)
Definition: elog.h:141
#define rt_fetch(rangetable_index, rangetable)
Definition: parsetree.h:31
List * lappend(List *list, void *datum)
Definition: list.c:321
OnConflictAction action
Definition: primnodes.h:1512
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
#define InvalidOid
Definition: postgres_ext.h:36
#define lfirst(lc)
Definition: pg_list.h:190
List * list_difference(const List *list1, const List *list2)
Definition: list.c:1073
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:736
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4348
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:152
Node * arbiterWhere
Definition: primnodes.h:1517
int errmsg(const char *fmt,...)
Definition: elog.c:784
void list_free(List *list)
Definition: list.c:1373
Oid get_constraint_index(Oid constraintId)
Definition: pg_depend.c:806
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
bool predicate_implied_by(List *predicate_list, List *clause_list, bool weak)
Definition: predtest.c:151
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:126
#define lfirst_oid(lc)
Definition: pg_list.h:192
bool bms_equal(const Bitmapset *a, const Bitmapset *b)
Definition: bitmapset.c:94

◆ infer_collation_opclass_match()

static bool infer_collation_opclass_match ( InferenceElem elem,
Relation  idxRel,
List idxExprs 
)
static

Definition at line 865 of file plancat.c.

References equal(), InferenceElem::expr, get_opclass_family(), get_opclass_input_type(), InferenceElem::infercollid, InferenceElem::inferopclass, InvalidOid, IsA, list_nth(), TupleDescData::natts, RelationData::rd_att, RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_opcintype, and RelationData::rd_opfamily.

Referenced by infer_arbiter_indexes().

867 {
868  AttrNumber natt;
869  Oid inferopfamily = InvalidOid; /* OID of opclass opfamily */
870  Oid inferopcinputtype = InvalidOid; /* OID of opclass input type */
871  int nplain = 0; /* # plain attrs observed */
872 
873  /*
874  * If inference specification element lacks collation/opclass, then no
875  * need to check for exact match.
876  */
877  if (elem->infercollid == InvalidOid && elem->inferopclass == InvalidOid)
878  return true;
879 
880  /*
881  * Lookup opfamily and input type, for matching indexes
882  */
883  if (elem->inferopclass)
884  {
885  inferopfamily = get_opclass_family(elem->inferopclass);
886  inferopcinputtype = get_opclass_input_type(elem->inferopclass);
887  }
888 
889  for (natt = 1; natt <= idxRel->rd_att->natts; natt++)
890  {
891  Oid opfamily = idxRel->rd_opfamily[natt - 1];
892  Oid opcinputtype = idxRel->rd_opcintype[natt - 1];
893  Oid collation = idxRel->rd_indcollation[natt - 1];
894  int attno = idxRel->rd_index->indkey.values[natt - 1];
895 
896  if (attno != 0)
897  nplain++;
898 
899  if (elem->inferopclass != InvalidOid &&
900  (inferopfamily != opfamily || inferopcinputtype != opcinputtype))
901  {
902  /* Attribute needed to match opclass, but didn't */
903  continue;
904  }
905 
906  if (elem->infercollid != InvalidOid &&
907  elem->infercollid != collation)
908  {
909  /* Attribute needed to match collation, but didn't */
910  continue;
911  }
912 
913  /* If one matching index att found, good enough -- return true */
914  if (IsA(elem->expr, Var))
915  {
916  if (((Var *) elem->expr)->varattno == attno)
917  return true;
918  }
919  else if (attno == 0)
920  {
921  Node *nattExpr = list_nth(idxExprs, (natt - 1) - nplain);
922 
923  /*
924  * Note that unlike routines like match_index_to_operand() we
925  * don't need to care about RelabelType. Neither the index
926  * definition nor the inference clause should contain them.
927  */
928  if (equal(elem->expr, nattExpr))
929  return true;
930  }
931  }
932 
933  return false;
934 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:3008
Definition: nodes.h:525
unsigned int Oid
Definition: postgres_ext.h:31
Definition: primnodes.h:167
Form_pg_index rd_index
Definition: rel.h:143
Oid * rd_indcollation
Definition: rel.h:168
static void * list_nth(const List *list, int n)
Definition: pg_list.h:277
Oid * rd_opfamily
Definition: rel.h:158
TupleDesc rd_att
Definition: rel.h:84
#define InvalidOid
Definition: postgres_ext.h:36
Oid get_opclass_family(Oid opclass)
Definition: lsyscache.c:1019
Oid * rd_opcintype
Definition: rel.h:159
int16 AttrNumber
Definition: attnum.h:21
Oid get_opclass_input_type(Oid opclass)
Definition: lsyscache.c:1041

◆ join_selectivity()

Selectivity join_selectivity ( PlannerInfo root,
Oid  operatorid,
List args,
Oid  inputcollid,
JoinType  jointype,
SpecialJoinInfo sjinfo 
)

Definition at line 1803 of file plancat.c.

References DatumGetFloat8, elog, ERROR, get_oprjoin(), Int16GetDatum, ObjectIdGetDatum, OidFunctionCall5Coll(), and PointerGetDatum.

Referenced by clause_selectivity(), rowcomparesel(), and test_support_func().

1809 {
1810  RegProcedure oprjoin = get_oprjoin(operatorid);
1811  float8 result;
1812 
1813  /*
1814  * if the oprjoin procedure is missing for whatever reason, use a
1815  * selectivity of 0.5
1816  */
1817  if (!oprjoin)
1818  return (Selectivity) 0.5;
1819 
1820  result = DatumGetFloat8(OidFunctionCall5Coll(oprjoin,
1821  inputcollid,
1822  PointerGetDatum(root),
1823  ObjectIdGetDatum(operatorid),
1824  PointerGetDatum(args),
1825  Int16GetDatum(jointype),
1826  PointerGetDatum(sjinfo)));
1827 
1828  if (result < 0.0 || result > 1.0)
1829  elog(ERROR, "invalid join selectivity: %f", result);
1830 
1831  return (Selectivity) result;
1832 }
RegProcedure get_oprjoin(Oid opno)
Definition: lsyscache.c:1383
#define PointerGetDatum(X)
Definition: postgres.h:556
regproc RegProcedure
Definition: c.h:505
#define Int16GetDatum(X)
Definition: postgres.h:451
double Selectivity
Definition: nodes.h:658
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
double float8
Definition: c.h:491
#define DatumGetFloat8(X)
Definition: postgres.h:728
Datum OidFunctionCall5Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5)
Definition: fmgr.c:1454
#define elog(elevel,...)
Definition: elog.h:226

◆ relation_excluded_by_constraints()

bool relation_excluded_by_constraints ( PlannerInfo root,
RelOptInfo rel,
RangeTblEntry rte 
)

Definition at line 1385 of file plancat.c.

References Assert, RelOptInfo::baserestrictinfo, RestrictInfo::clause, constraint_exclusion, CONSTRAINT_EXCLUSION_OFF, CONSTRAINT_EXCLUSION_ON, CONSTRAINT_EXCLUSION_PARTITION, contain_mutable_functions(), DatumGetBool, get_relation_constraints(), RangeTblEntry::inh, INHKIND_NONE, PlannerInfo::inhTargetKind, IS_SIMPLE_REL, IsA, lappend(), lfirst, linitial, list_length(), NIL, PlannerInfo::parse, predicate_refuted_by(), RelOptInfo::relid, RangeTblEntry::relid, RangeTblEntry::relkind, RELOPT_BASEREL, RELOPT_OTHER_MEMBER_REL, RelOptInfo::reloptkind, Query::resultRelation, RTE_RELATION, and RangeTblEntry::rtekind.

Referenced by set_append_rel_size(), and set_rel_size().

1387 {
1388  bool include_noinherit;
1389  bool include_notnull;
1390  bool include_partition = false;
1391  List *safe_restrictions;
1392  List *constraint_pred;
1393  List *safe_constraints;
1394  ListCell *lc;
1395 
1396  /* As of now, constraint exclusion works only with simple relations. */
1397  Assert(IS_SIMPLE_REL(rel));
1398 
1399  /*
1400  * If there are no base restriction clauses, we have no hope of proving
1401  * anything below, so fall out quickly.
1402  */
1403  if (rel->baserestrictinfo == NIL)
1404  return false;
1405 
1406  /*
1407  * Regardless of the setting of constraint_exclusion, detect
1408  * constant-FALSE-or-NULL restriction clauses. Because const-folding will
1409  * reduce "anything AND FALSE" to just "FALSE", any such case should
1410  * result in exactly one baserestrictinfo entry. This doesn't fire very
1411  * often, but it seems cheap enough to be worth doing anyway. (Without
1412  * this, we'd miss some optimizations that 9.5 and earlier found via much
1413  * more roundabout methods.)
1414  */
1415  if (list_length(rel->baserestrictinfo) == 1)
1416  {
1418  Expr *clause = rinfo->clause;
1419 
1420  if (clause && IsA(clause, Const) &&
1421  (((Const *) clause)->constisnull ||
1422  !DatumGetBool(((Const *) clause)->constvalue)))
1423  return true;
1424  }
1425 
1426  /*
1427  * Skip further tests, depending on constraint_exclusion.
1428  */
1429  switch (constraint_exclusion)
1430  {
1432  /* In 'off' mode, never make any further tests */
1433  return false;
1434 
1436 
1437  /*
1438  * When constraint_exclusion is set to 'partition' we only handle
1439  * appendrel members. Normally, they are RELOPT_OTHER_MEMBER_REL
1440  * relations, but we also consider inherited target relations as
1441  * appendrel members for the purposes of constraint exclusion
1442  * (since, indeed, they were appendrel members earlier in
1443  * inheritance_planner).
1444  *
1445  * In both cases, partition pruning was already applied, so there
1446  * is no need to consider the rel's partition constraints here.
1447  */
1448  if (rel->reloptkind == RELOPT_OTHER_MEMBER_REL ||
1449  (rel->relid == root->parse->resultRelation &&
1450  root->inhTargetKind != INHKIND_NONE))
1451  break; /* appendrel member, so process it */
1452  return false;
1453 
1455 
1456  /*
1457  * In 'on' mode, always apply constraint exclusion. If we are
1458  * considering a baserel that is a partition (i.e., it was
1459  * directly named rather than expanded from a parent table), then
1460  * its partition constraints haven't been considered yet, so
1461  * include them in the processing here.
1462  */
1463  if (rel->reloptkind == RELOPT_BASEREL &&
1464  !(rel->relid == root->parse->resultRelation &&
1465  root->inhTargetKind != INHKIND_NONE))
1466  include_partition = true;
1467  break; /* always try to exclude */
1468  }
1469 
1470  /*
1471  * Check for self-contradictory restriction clauses. We dare not make
1472  * deductions with non-immutable functions, but any immutable clauses that
1473  * are self-contradictory allow us to conclude the scan is unnecessary.
1474  *
1475  * Note: strip off RestrictInfo because predicate_refuted_by() isn't
1476  * expecting to see any in its predicate argument.
1477  */
1478  safe_restrictions = NIL;
1479  foreach(lc, rel->baserestrictinfo)
1480  {
1481  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1482 
1483  if (!contain_mutable_functions((Node *) rinfo->clause))
1484  safe_restrictions = lappend(safe_restrictions, rinfo->clause);
1485  }
1486 
1487  /*
1488  * We can use weak refutation here, since we're comparing restriction
1489  * clauses with restriction clauses.
1490  */
1491  if (predicate_refuted_by(safe_restrictions, safe_restrictions, true))
1492  return true;
1493 
1494  /*
1495  * Only plain relations have constraints, so stop here for other rtekinds.
1496  */
1497  if (rte->rtekind != RTE_RELATION)
1498  return false;
1499 
1500  /*
1501  * If we are scanning just this table, we can use NO INHERIT constraints,
1502  * but not if we're scanning its children too. (Note that partitioned
1503  * tables should never have NO INHERIT constraints; but it's not necessary
1504  * for us to assume that here.)
1505  */
1506  include_noinherit = !rte->inh;
1507 
1508  /*
1509  * Currently, attnotnull constraints must be treated as NO INHERIT unless
1510  * this is a partitioned table. In future we might track their
1511  * inheritance status more accurately, allowing this to be refined.
1512  */
1513  include_notnull = (!rte->inh || rte->relkind == RELKIND_PARTITIONED_TABLE);
1514 
1515  /*
1516  * Fetch the appropriate set of constraint expressions.
1517  */
1518  constraint_pred = get_relation_constraints(root, rte->relid, rel,
1519  include_noinherit,
1520  include_notnull,
1521  include_partition);
1522 
1523  /*
1524  * We do not currently enforce that CHECK constraints contain only
1525  * immutable functions, so it's necessary to check here. We daren't draw
1526  * conclusions from plan-time evaluation of non-immutable functions. Since
1527  * they're ANDed, we can just ignore any mutable constraints in the list,
1528  * and reason about the rest.
1529  */
1530  safe_constraints = NIL;
1531  foreach(lc, constraint_pred)
1532  {
1533  Node *pred = (Node *) lfirst(lc);
1534 
1535  if (!contain_mutable_functions(pred))
1536  safe_constraints = lappend(safe_constraints, pred);
1537  }
1538 
1539  /*
1540  * The constraints are effectively ANDed together, so we can just try to
1541  * refute the entire collection at once. This may allow us to make proofs
1542  * that would fail if we took them individually.
1543  *
1544  * Note: we use rel->baserestrictinfo, not safe_restrictions as might seem
1545  * an obvious optimization. Some of the clauses might be OR clauses that
1546  * have volatile and nonvolatile subclauses, and it's OK to make
1547  * deductions with the nonvolatile parts.
1548  *
1549  * We need strong refutation because we have to prove that the constraints
1550  * would yield false, not just NULL.
1551  */
1552  if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo, false))
1553  return true;
1554 
1555  return false;
1556 }
#define NIL
Definition: pg_list.h:65
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
Query * parse
Definition: pathnodes.h:177
RelOptKind reloptkind
Definition: pathnodes.h:638
List * baserestrictinfo
Definition: pathnodes.h:703
int constraint_exclusion
Definition: plancat.c:58
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:525
#define IS_SIMPLE_REL(rel)
Definition: pathnodes.h:614
#define linitial(l)
Definition: pg_list.h:195
bool predicate_refuted_by(List *predicate_list, List *clause_list, bool weak)
Definition: predtest.c:221
#define DatumGetBool(X)
Definition: postgres.h:393
Index relid
Definition: pathnodes.h:669
List * lappend(List *list, void *datum)
Definition: list.c:321
Expr * clause
Definition: pathnodes.h:1943
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
InheritanceKind inhTargetKind
Definition: pathnodes.h:340
static int list_length(const List *l)
Definition: pg_list.h:169
RTEKind rtekind
Definition: parsenodes.h:974
static List * get_relation_constraints(PlannerInfo *root, Oid relationObjectId, RelOptInfo *rel, bool include_noinherit, bool include_notnull, bool include_partition)
Definition: plancat.c:1170
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:645
Definition: pg_list.h:50

◆ restriction_selectivity()

Selectivity restriction_selectivity ( PlannerInfo root,
Oid  operatorid,
List args,
Oid  inputcollid,
int  varRelid 
)

Definition at line 1764 of file plancat.c.

References DatumGetFloat8, elog, ERROR, get_oprrest(), Int32GetDatum, ObjectIdGetDatum, OidFunctionCall4Coll(), and PointerGetDatum.

Referenced by clause_selectivity(), rowcomparesel(), and test_support_func().

1769 {
1770  RegProcedure oprrest = get_oprrest(operatorid);
1771  float8 result;
1772 
1773  /*
1774  * if the oprrest procedure is missing for whatever reason, use a
1775  * selectivity of 0.5
1776  */
1777  if (!oprrest)
1778  return (Selectivity) 0.5;
1779 
1780  result = DatumGetFloat8(OidFunctionCall4Coll(oprrest,
1781  inputcollid,
1782  PointerGetDatum(root),
1783  ObjectIdGetDatum(operatorid),
1784  PointerGetDatum(args),
1785  Int32GetDatum(varRelid)));
1786 
1787  if (result < 0.0 || result > 1.0)
1788  elog(ERROR, "invalid restriction selectivity: %f", result);
1789 
1790  return (Selectivity) result;
1791 }
#define PointerGetDatum(X)
Definition: postgres.h:556
regproc RegProcedure
Definition: c.h:505
double Selectivity
Definition: nodes.h:658
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
double float8
Definition: c.h:491
RegProcedure get_oprrest(Oid opno)
Definition: lsyscache.c:1359
#define DatumGetFloat8(X)
Definition: postgres.h:728
Datum OidFunctionCall4Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4)
Definition: fmgr.c:1443
#define Int32GetDatum(X)
Definition: postgres.h:479
#define elog(elevel,...)
Definition: elog.h:226

◆ set_baserel_partition_constraint()

static void set_baserel_partition_constraint ( Relation  relation,
RelOptInfo rel 
)
static

Definition at line 2323 of file plancat.c.

References ChangeVarNodes(), expression_planner(), RelOptInfo::partition_qual, RelationGetPartitionQual(), and RelOptInfo::relid.

Referenced by get_relation_constraints(), and set_relation_partition_info().

2324 {
2325  List *partconstr;
2326 
2327  if (rel->partition_qual) /* already done */
2328  return;
2329 
2330  /*
2331  * Run the partition quals through const-simplification similar to check
2332  * constraints. We skip canonicalize_qual, though, because partition
2333  * quals should be in canonical form already; also, since the qual is in
2334  * implicit-AND format, we'd have to explicitly convert it to explicit-AND
2335  * format and back again.
2336  */
2337  partconstr = RelationGetPartitionQual(relation);
2338  if (partconstr)
2339  {
2340  partconstr = (List *) expression_planner((Expr *) partconstr);
2341  if (rel->relid != 1)
2342  ChangeVarNodes((Node *) partconstr, 1, rel->relid, 0);
2343  rel->partition_qual = partconstr;
2344  }
2345 }
Expr * expression_planner(Expr *expr)
Definition: planner.c:6046
Definition: nodes.h:525
Index relid
Definition: pathnodes.h:669
List * RelationGetPartitionQual(Relation rel)
Definition: partcache.c:256
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
List * partition_qual
Definition: pathnodes.h:721
Definition: pg_list.h:50

◆ set_baserel_partition_key_exprs()

static void set_baserel_partition_key_exprs ( Relation  relation,
RelOptInfo rel 
)
static

Definition at line 2256 of file plancat.c.

References Assert, ChangeVarNodes(), copyObject, elog, ERROR, InvalidAttrNumber, IS_SIMPLE_REL, lfirst, list_head(), list_make1, lnext(), makeVar(), RelOptInfo::nullable_partexprs, palloc(), palloc0(), PartitionKeyData::partattrs, PartitionKeyData::partexprs, RelOptInfo::partexprs, PartitionKeyData::partnatts, PartitionKeyData::parttypcoll, PartitionKeyData::parttypid, PartitionKeyData::parttypmod, RelationGetPartitionKey, and RelOptInfo::relid.

Referenced by set_relation_partition_info().

2258 {
2259  PartitionKey partkey = RelationGetPartitionKey(relation);
2260  int partnatts;
2261  int cnt;
2262  List **partexprs;
2263  ListCell *lc;
2264  Index varno = rel->relid;
2265 
2266  Assert(IS_SIMPLE_REL(rel) && rel->relid > 0);
2267 
2268  /* A partitioned table should have a partition key. */
2269  Assert(partkey != NULL);
2270 
2271  partnatts = partkey->partnatts;
2272  partexprs = (List **) palloc(sizeof(List *) * partnatts);
2273  lc = list_head(partkey->partexprs);
2274 
2275  for (cnt = 0; cnt < partnatts; cnt++)
2276  {
2277  Expr *partexpr;
2278  AttrNumber attno = partkey->partattrs[cnt];
2279 
2280  if (attno != InvalidAttrNumber)
2281  {
2282  /* Single column partition key is stored as a Var node. */
2283  Assert(attno > 0);
2284 
2285  partexpr = (Expr *) makeVar(varno, attno,
2286  partkey->parttypid[cnt],
2287  partkey->parttypmod[cnt],
2288  partkey->parttypcoll[cnt], 0);
2289  }
2290  else
2291  {
2292  if (lc == NULL)
2293  elog(ERROR, "wrong number of partition key expressions");
2294 
2295  /* Re-stamp the expression with given varno. */
2296  partexpr = (Expr *) copyObject(lfirst(lc));
2297  ChangeVarNodes((Node *) partexpr, 1, varno, 0);
2298  lc = lnext(partkey->partexprs, lc);
2299  }
2300 
2301  partexprs[cnt] = list_make1(partexpr);
2302  }
2303 
2304  rel->partexprs = partexprs;
2305 
2306  /*
2307  * A base relation can not have nullable partition key expressions. We
2308  * still allocate array of empty expressions lists to keep partition key
2309  * expression handling code simple. See build_joinrel_partition_info() and
2310  * match_expr_to_partition_keys().
2311  */
2312  rel->nullable_partexprs = (List **) palloc0(sizeof(List *) * partnatts);
2313 }
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:321
Definition: nodes.h:525
List * partexprs
Definition: partcache.h:30
List ** nullable_partexprs
Definition: pathnodes.h:725
#define IS_SIMPLE_REL(rel)
Definition: pathnodes.h:614
#define list_make1(x1)
Definition: pg_list.h:227
Oid * parttypcoll
Definition: partcache.h:46
List ** partexprs
Definition: pathnodes.h:724
#define ERROR
Definition: elog.h:43
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:66
Index relid
Definition: pathnodes.h:669
void * palloc0(Size size)
Definition: mcxt.c:955
AttrNumber * partattrs
Definition: partcache.h:28
unsigned int Index
Definition: c.h:475
int32 * parttypmod
Definition: partcache.h:42
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
#define RelationGetPartitionKey(relation)
Definition: rel.h:597
#define InvalidAttrNumber
Definition: attnum.h:23
void * palloc(Size size)
Definition: mcxt.c:924
#define elog(elevel,...)
Definition: elog.h:226
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
#define copyObject(obj)
Definition: nodes.h:641
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21

◆ set_relation_partition_info()

static void set_relation_partition_info ( PlannerInfo root,
RelOptInfo rel,
Relation  relation 
)
static

Definition at line 2122 of file plancat.c.

References Assert, PartitionDescData::boundinfo, RelOptInfo::boundinfo, CreatePartitionDirectory(), CurrentMemoryContext, find_partition_scheme(), PlannerInfo::glob, PartitionDescData::nparts, RelOptInfo::nparts, RelOptInfo::part_scheme, PlannerGlobal::partition_directory, PartitionDirectoryLookup(), set_baserel_partition_constraint(), and set_baserel_partition_key_exprs().

Referenced by get_relation_info().

2124 {
2125  PartitionDesc partdesc;
2126 
2127  /* Create the PartitionDirectory infrastructure if we didn't already */
2128  if (root->glob->partition_directory == NULL)
2129  root->glob->partition_directory =
2131 
2133  relation);
2134  rel->part_scheme = find_partition_scheme(root, relation);
2135  Assert(partdesc != NULL && rel->part_scheme != NULL);
2136  rel->boundinfo = partdesc->boundinfo;
2137  rel->nparts = partdesc->nparts;
2138  set_baserel_partition_key_exprs(relation, rel);
2139  set_baserel_partition_constraint(relation, rel);
2140 }
PartitionDirectory CreatePartitionDirectory(MemoryContext mcxt)
Definition: partdesc.c:242
PartitionBoundInfo boundinfo
Definition: partdesc.h:29
PlannerGlobal * glob
Definition: pathnodes.h:179
int nparts
Definition: pathnodes.h:719
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
struct PartitionBoundInfoData * boundinfo
Definition: pathnodes.h:720
static void set_baserel_partition_constraint(Relation relation, RelOptInfo *rel)
Definition: plancat.c:2323
static PartitionScheme find_partition_scheme(PlannerInfo *root, Relation rel)
Definition: plancat.c:2148
#define Assert(condition)
Definition: c.h:732
PartitionScheme part_scheme
Definition: pathnodes.h:718
PartitionDesc PartitionDirectoryLookup(PartitionDirectory pdir, Relation rel)
Definition: partdesc.c:274
static void set_baserel_partition_key_exprs(Relation relation, RelOptInfo *rel)
Definition: plancat.c:2256
PartitionDirectory partition_directory
Definition: pathnodes.h:147

Variable Documentation

◆ constraint_exclusion

int constraint_exclusion = CONSTRAINT_EXCLUSION_PARTITION

Definition at line 58 of file plancat.c.

Referenced by relation_excluded_by_constraints().

◆ get_relation_info_hook

get_relation_info_hook_type get_relation_info_hook = NULL

Definition at line 61 of file plancat.c.

Referenced by get_relation_info().