PostgreSQL Source Code  git master
plancat.c File Reference
#include "postgres.h"
#include <math.h>
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/nbtree.h"
#include "access/sysattr.h"
#include "access/transam.h"
#include "access/xlog.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/partition.h"
#include "catalog/pg_am.h"
#include "catalog/pg_statistic_ext.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/plancat.h"
#include "optimizer/predtest.h"
#include "optimizer/prep.h"
#include "partitioning/partbounds.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 int32 get_rel_data_width (Relation rel, int32 *attr_widths)
 
static Listget_relation_constraints (PlannerInfo *root, Oid relationObjectId, RelOptInfo *rel, bool include_notnull)
 
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)
 
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_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)
 
bool has_unique_index (RelOptInfo *rel, AttrNumber attno)
 
bool has_row_triggers (PlannerInfo *root, Index rti, CmdType event)
 

Variables

int constraint_exclusion = CONSTRAINT_EXCLUSION_PARTITION
 
get_relation_info_hook_type get_relation_info_hook = NULL
 

Function Documentation

◆ build_index_tlist()

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

Definition at line 1649 of file plancat.c.

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

Referenced by get_relation_info().

1651 {
1652  List *tlist = NIL;
1653  Index varno = index->rel->relid;
1654  ListCell *indexpr_item;
1655  int i;
1656 
1657  indexpr_item = list_head(index->indexprs);
1658  for (i = 0; i < index->ncolumns; i++)
1659  {
1660  int indexkey = index->indexkeys[i];
1661  Expr *indexvar;
1662 
1663  if (indexkey != 0)
1664  {
1665  /* simple column */
1666  Form_pg_attribute att_tup;
1667 
1668  if (indexkey < 0)
1669  att_tup = SystemAttributeDefinition(indexkey,
1670  heapRelation->rd_rel->relhasoids);
1671  else
1672  att_tup = TupleDescAttr(heapRelation->rd_att, indexkey - 1);
1673 
1674  indexvar = (Expr *) makeVar(varno,
1675  indexkey,
1676  att_tup->atttypid,
1677  att_tup->atttypmod,
1678  att_tup->attcollation,
1679  0);
1680  }
1681  else
1682  {
1683  /* expression column */
1684  if (indexpr_item == NULL)
1685  elog(ERROR, "wrong number of index expressions");
1686  indexvar = (Expr *) lfirst(indexpr_item);
1687  indexpr_item = lnext(indexpr_item);
1688  }
1689 
1690  tlist = lappend(tlist,
1691  makeTargetEntry(indexvar,
1692  i + 1,
1693  NULL,
1694  false));
1695  }
1696  if (indexpr_item != NULL)
1697  elog(ERROR, "wrong number of index expressions");
1698 
1699  return tlist;
1700 }
#define NIL
Definition: pg_list.h:69
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
Form_pg_class rd_rel
Definition: rel.h:84
RelOptInfo * rel
Definition: relation.h:743
#define ERROR
Definition: elog.h:43
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
int ncolumns
Definition: relation.h:751
#define lnext(lc)
Definition: pg_list.h:105
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:237
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Index relid
Definition: relation.h:628
List * lappend(List *list, void *datum)
Definition: list.c:128
unsigned int Index
Definition: c.h:442
TupleDesc rd_att
Definition: rel.h:85
Form_pg_attribute SystemAttributeDefinition(AttrNumber attno, bool relhasoids)
Definition: heap.c:203
#define lfirst(lc)
Definition: pg_list.h:106
int i
int * indexkeys
Definition: relation.h:753
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
List * indexprs
Definition: relation.h:765

◆ build_physical_tlist()

List* build_physical_tlist ( PlannerInfo root,
RelOptInfo rel 
)

Definition at line 1529 of file plancat.c.

References elog, ERROR, expandRTE(), heap_close, heap_open(), 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_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, RangeTblEntry::subquery, Query::targetList, and TupleDescAttr.

Referenced by create_scan_plan().

1530 {
1531  List *tlist = NIL;
1532  Index varno = rel->relid;
1533  RangeTblEntry *rte = planner_rt_fetch(varno, root);
1534  Relation relation;
1535  Query *subquery;
1536  Var *var;
1537  ListCell *l;
1538  int attrno,
1539  numattrs;
1540  List *colvars;
1541 
1542  switch (rte->rtekind)
1543  {
1544  case RTE_RELATION:
1545  /* Assume we already have adequate lock */
1546  relation = heap_open(rte->relid, NoLock);
1547 
1548  numattrs = RelationGetNumberOfAttributes(relation);
1549  for (attrno = 1; attrno <= numattrs; attrno++)
1550  {
1551  Form_pg_attribute att_tup = TupleDescAttr(relation->rd_att,
1552  attrno - 1);
1553 
1554  if (att_tup->attisdropped || att_tup->atthasmissing)
1555  {
1556  /* found a dropped or missing col, so punt */
1557  tlist = NIL;
1558  break;
1559  }
1560 
1561  var = makeVar(varno,
1562  attrno,
1563  att_tup->atttypid,
1564  att_tup->atttypmod,
1565  att_tup->attcollation,
1566  0);
1567 
1568  tlist = lappend(tlist,
1569  makeTargetEntry((Expr *) var,
1570  attrno,
1571  NULL,
1572  false));
1573  }
1574 
1575  heap_close(relation, NoLock);
1576  break;
1577 
1578  case RTE_SUBQUERY:
1579  subquery = rte->subquery;
1580  foreach(l, subquery->targetList)
1581  {
1582  TargetEntry *tle = (TargetEntry *) lfirst(l);
1583 
1584  /*
1585  * A resjunk column of the subquery can be reflected as
1586  * resjunk in the physical tlist; we need not punt.
1587  */
1588  var = makeVarFromTargetEntry(varno, tle);
1589 
1590  tlist = lappend(tlist,
1591  makeTargetEntry((Expr *) var,
1592  tle->resno,
1593  NULL,
1594  tle->resjunk));
1595  }
1596  break;
1597 
1598  case RTE_FUNCTION:
1599  case RTE_TABLEFUNC:
1600  case RTE_VALUES:
1601  case RTE_CTE:
1602  case RTE_NAMEDTUPLESTORE:
1603  /* Not all of these can have dropped cols, but share code anyway */
1604  expandRTE(rte, varno, 0, -1, true /* include dropped */ ,
1605  NULL, &colvars);
1606  foreach(l, colvars)
1607  {
1608  var = (Var *) lfirst(l);
1609 
1610  /*
1611  * A non-Var in expandRTE's output means a dropped column;
1612  * must punt.
1613  */
1614  if (!IsA(var, Var))
1615  {
1616  tlist = NIL;
1617  break;
1618  }
1619 
1620  tlist = lappend(tlist,
1621  makeTargetEntry((Expr *) var,
1622  var->varattno,
1623  NULL,
1624  false));
1625  }
1626  break;
1627 
1628  default:
1629  /* caller error */
1630  elog(ERROR, "unsupported RTE kind %d in build_physical_tlist",
1631  (int) rte->rtekind);
1632  break;
1633  }
1634 
1635  return tlist;
1636 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:413
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
Var * makeVarFromTargetEntry(Index varno, TargetEntry *tle)
Definition: makefuncs.c:104
#define heap_close(r, l)
Definition: heapam.h:97
Definition: primnodes.h:164
List * targetList
Definition: parsenodes.h:140
bool resjunk
Definition: primnodes.h:1383
#define planner_rt_fetch(rti, root)
Definition: relation.h:332
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
AttrNumber resno
Definition: primnodes.h:1377
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
TargetEntry * makeTargetEntry(Expr *expr, AttrNumber resno, char *resname, bool resjunk)
Definition: makefuncs.c:237
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Index relid
Definition: relation.h:628
List * lappend(List *list, void *datum)
Definition: list.c:128
void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, int location, bool include_dropped, List **colnames, List **colvars)
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
unsigned int Index
Definition: c.h:442
TupleDesc rd_att
Definition: rel.h:85
#define lfirst(lc)
Definition: pg_list.h:106
RTEKind rtekind
Definition: parsenodes.h:962
Query * subquery
Definition: parsenodes.h:985
#define elog
Definition: elog.h:219
Definition: pg_list.h:45

◆ estimate_rel_size()

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

Definition at line 939 of file plancat.c.

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

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

941 {
942  BlockNumber curpages;
944  double reltuples;
946  double density;
947 
948  switch (rel->rd_rel->relkind)
949  {
950  case RELKIND_RELATION:
951  case RELKIND_INDEX:
952  case RELKIND_MATVIEW:
953  case RELKIND_TOASTVALUE:
954  /* it has storage, ok to call the smgr */
955  curpages = RelationGetNumberOfBlocks(rel);
956 
957  /*
958  * HACK: if the relation has never yet been vacuumed, use a
959  * minimum size estimate of 10 pages. The idea here is to avoid
960  * assuming a newly-created table is really small, even if it
961  * currently is, because that may not be true once some data gets
962  * loaded into it. Once a vacuum or analyze cycle has been done
963  * on it, it's more reasonable to believe the size is somewhat
964  * stable.
965  *
966  * (Note that this is only an issue if the plan gets cached and
967  * used again after the table has been filled. What we're trying
968  * to avoid is using a nestloop-type plan on a table that has
969  * grown substantially since the plan was made. Normally,
970  * autovacuum/autoanalyze will occur once enough inserts have
971  * happened and cause cached-plan invalidation; but that doesn't
972  * happen instantaneously, and it won't happen at all for cases
973  * such as temporary tables.)
974  *
975  * We approximate "never vacuumed" by "has relpages = 0", which
976  * means this will also fire on genuinely empty relations. Not
977  * great, but fortunately that's a seldom-seen case in the real
978  * world, and it shouldn't degrade the quality of the plan too
979  * much anyway to err in this direction.
980  *
981  * There are two exceptions wherein we don't apply this heuristic.
982  * One is if the table has inheritance children. Totally empty
983  * parent tables are quite common, so we should be willing to
984  * believe that they are empty. Also, we don't apply the 10-page
985  * minimum to indexes.
986  */
987  if (curpages < 10 &&
988  rel->rd_rel->relpages == 0 &&
989  !rel->rd_rel->relhassubclass &&
990  rel->rd_rel->relkind != RELKIND_INDEX)
991  curpages = 10;
992 
993  /* report estimated # pages */
994  *pages = curpages;
995  /* quick exit if rel is clearly empty */
996  if (curpages == 0)
997  {
998  *tuples = 0;
999  *allvisfrac = 0;
1000  break;
1001  }
1002  /* coerce values in pg_class to more desirable types */
1003  relpages = (BlockNumber) rel->rd_rel->relpages;
1004  reltuples = (double) rel->rd_rel->reltuples;
1005  relallvisible = (BlockNumber) rel->rd_rel->relallvisible;
1006 
1007  /*
1008  * If it's an index, discount the metapage while estimating the
1009  * number of tuples. This is a kluge because it assumes more than
1010  * it ought to about index structure. Currently it's OK for
1011  * btree, hash, and GIN indexes but suspect for GiST indexes.
1012  */
1013  if (rel->rd_rel->relkind == RELKIND_INDEX &&
1014  relpages > 0)
1015  {
1016  curpages--;
1017  relpages--;
1018  }
1019 
1020  /* estimate number of tuples from previous tuple density */
1021  if (relpages > 0)
1022  density = reltuples / (double) relpages;
1023  else
1024  {
1025  /*
1026  * When we have no data because the relation was truncated,
1027  * estimate tuple width from attribute datatypes. We assume
1028  * here that the pages are completely full, which is OK for
1029  * tables (since they've presumably not been VACUUMed yet) but
1030  * is probably an overestimate for indexes. Fortunately
1031  * get_relation_info() can clamp the overestimate to the
1032  * parent table's size.
1033  *
1034  * Note: this code intentionally disregards alignment
1035  * considerations, because (a) that would be gilding the lily
1036  * considering how crude the estimate is, and (b) it creates
1037  * platform dependencies in the default plans which are kind
1038  * of a headache for regression testing.
1039  */
1040  int32 tuple_width;
1041 
1042  tuple_width = get_rel_data_width(rel, attr_widths);
1043  tuple_width += MAXALIGN(SizeofHeapTupleHeader);
1044  tuple_width += sizeof(ItemIdData);
1045  /* note: integer division is intentional here */
1046  density = (BLCKSZ - SizeOfPageHeaderData) / tuple_width;
1047  }
1048  *tuples = rint(density * (double) curpages);
1049 
1050  /*
1051  * We use relallvisible as-is, rather than scaling it up like we
1052  * do for the pages and tuples counts, on the theory that any
1053  * pages added since the last VACUUM are most likely not marked
1054  * all-visible. But costsize.c wants it converted to a fraction.
1055  */
1056  if (relallvisible == 0 || curpages <= 0)
1057  *allvisfrac = 0;
1058  else if ((double) relallvisible >= curpages)
1059  *allvisfrac = 1;
1060  else
1061  *allvisfrac = (double) relallvisible / curpages;
1062  break;
1063  case RELKIND_SEQUENCE:
1064  /* Sequences always have a known size */
1065  *pages = 1;
1066  *tuples = 1;
1067  *allvisfrac = 0;
1068  break;
1069  case RELKIND_FOREIGN_TABLE:
1070  /* Just use whatever's in pg_class */
1071  *pages = rel->rd_rel->relpages;
1072  *tuples = rel->rd_rel->reltuples;
1073  *allvisfrac = 0;
1074  break;
1075  default:
1076  /* else it has no disk storage; probably shouldn't get here? */
1077  *pages = 0;
1078  *tuples = 0;
1079  *allvisfrac = 0;
1080  break;
1081  }
1082 }
#define SizeofHeapTupleHeader
Definition: htup_details.h:181
int32 relallvisible
Definition: pg_class.h:45
uint32 BlockNumber
Definition: block.h:31
#define SizeOfPageHeaderData
Definition: bufpage.h:212
Form_pg_class rd_rel
Definition: rel.h:84
int32 relpages
Definition: pg_class.h:43
signed int int32
Definition: c.h:313
static int32 get_rel_data_width(Relation rel, int32 *attr_widths)
Definition: plancat.c:1099
struct ItemIdData ItemIdData
double rint(double x)
Definition: rint.c:22
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
#define MAXALIGN(LEN)
Definition: c.h:652
float4 reltuples
Definition: pg_class.h:44

◆ find_partition_scheme()

static PartitionScheme find_partition_scheme ( PlannerInfo root,
Relation  rel 
)
static

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

1896 {
1897  PartitionKey partkey = RelationGetPartitionKey(relation);
1898  ListCell *lc;
1899  int partnatts,
1900  i;
1901  PartitionScheme part_scheme;
1902 
1903  /* A partitioned table should have a partition key. */
1904  Assert(partkey != NULL);
1905 
1906  partnatts = partkey->partnatts;
1907 
1908  /* Search for a matching partition scheme and return if found one. */
1909  foreach(lc, root->part_schemes)
1910  {
1911  part_scheme = lfirst(lc);
1912 
1913  /* Match partitioning strategy and number of keys. */
1914  if (partkey->strategy != part_scheme->strategy ||
1915  partnatts != part_scheme->partnatts)
1916  continue;
1917 
1918  /* Match partition key type properties. */
1919  if (memcmp(partkey->partopfamily, part_scheme->partopfamily,
1920  sizeof(Oid) * partnatts) != 0 ||
1921  memcmp(partkey->partopcintype, part_scheme->partopcintype,
1922  sizeof(Oid) * partnatts) != 0 ||
1923  memcmp(partkey->partcollation, part_scheme->partcollation,
1924  sizeof(Oid) * partnatts) != 0)
1925  continue;
1926 
1927  /*
1928  * Length and byval information should match when partopcintype
1929  * matches.
1930  */
1931  Assert(memcmp(partkey->parttyplen, part_scheme->parttyplen,
1932  sizeof(int16) * partnatts) == 0);
1933  Assert(memcmp(partkey->parttypbyval, part_scheme->parttypbyval,
1934  sizeof(bool) * partnatts) == 0);
1935 
1936  /*
1937  * If partopfamily and partopcintype matched, must have the same
1938  * partition comparison functions. Note that we cannot reliably
1939  * Assert the equality of function structs themselves for they might
1940  * be different across PartitionKey's, so just Assert for the function
1941  * OIDs.
1942  */
1943 #ifdef USE_ASSERT_CHECKING
1944  for (i = 0; i < partkey->partnatts; i++)
1945  Assert(partkey->partsupfunc[i].fn_oid ==
1946  part_scheme->partsupfunc[i].fn_oid);
1947 #endif
1948 
1949  /* Found matching partition scheme. */
1950  return part_scheme;
1951  }
1952 
1953  /*
1954  * Did not find matching partition scheme. Create one copying relevant
1955  * information from the relcache. We need to copy the contents of the
1956  * array since the relcache entry may not survive after we have closed the
1957  * relation.
1958  */
1959  part_scheme = (PartitionScheme) palloc0(sizeof(PartitionSchemeData));
1960  part_scheme->strategy = partkey->strategy;
1961  part_scheme->partnatts = partkey->partnatts;
1962 
1963  part_scheme->partopfamily = (Oid *) palloc(sizeof(Oid) * partnatts);
1964  memcpy(part_scheme->partopfamily, partkey->partopfamily,
1965  sizeof(Oid) * partnatts);
1966 
1967  part_scheme->partopcintype = (Oid *) palloc(sizeof(Oid) * partnatts);
1968  memcpy(part_scheme->partopcintype, partkey->partopcintype,
1969  sizeof(Oid) * partnatts);
1970 
1971  part_scheme->partcollation = (Oid *) palloc(sizeof(Oid) * partnatts);
1972  memcpy(part_scheme->partcollation, partkey->partcollation,
1973  sizeof(Oid) * partnatts);
1974 
1975  part_scheme->parttyplen = (int16 *) palloc(sizeof(int16) * partnatts);
1976  memcpy(part_scheme->parttyplen, partkey->parttyplen,
1977  sizeof(int16) * partnatts);
1978 
1979  part_scheme->parttypbyval = (bool *) palloc(sizeof(bool) * partnatts);
1980  memcpy(part_scheme->parttypbyval, partkey->parttypbyval,
1981  sizeof(bool) * partnatts);
1982 
1983  part_scheme->partsupfunc = (FmgrInfo *)
1984  palloc(sizeof(FmgrInfo) * partnatts);
1985  for (i = 0; i < partnatts; i++)
1986  fmgr_info_copy(&part_scheme->partsupfunc[i], &partkey->partsupfunc[i],
1988 
1989  /* Add the partitioning scheme to PlannerInfo. */
1990  root->part_schemes = lappend(root->part_schemes, part_scheme);
1991 
1992  return part_scheme;
1993 }
signed short int16
Definition: c.h:312
Definition: fmgr.h:56
Oid * partopfamily
Definition: partcache.h:33
FmgrInfo * partsupfunc
Definition: partcache.h:35
List * part_schemes
Definition: relation.h:270
unsigned int Oid
Definition: postgres_ext.h:31
struct PartitionSchemeData * PartitionScheme
Definition: relation.h:366
int16 * parttyplen
Definition: relation.h:359
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:609
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
List * lappend(List *list, void *datum)
Definition: list.c:128
FmgrInfo * partsupfunc
Definition: relation.h:363
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:699
#define lfirst(lc)
Definition: pg_list.h:106
int16 * parttyplen
Definition: partcache.h:43
#define RelationGetPartitionKey(relation)
Definition: rel.h:589
void * palloc(Size size)
Definition: mcxt.c:924
Oid * partopcintype
Definition: partcache.h:34
int i

◆ get_rel_data_width()

static int32 get_rel_data_width ( Relation  rel,
int32 attr_widths 
)
static

Definition at line 1099 of file plancat.c.

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

Referenced by estimate_rel_size(), and get_relation_data_width().

1100 {
1101  int32 tuple_width = 0;
1102  int i;
1103 
1104  for (i = 1; i <= RelationGetNumberOfAttributes(rel); i++)
1105  {
1106  Form_pg_attribute att = TupleDescAttr(rel->rd_att, i - 1);
1107  int32 item_width;
1108 
1109  if (att->attisdropped)
1110  continue;
1111 
1112  /* use previously cached data, if any */
1113  if (attr_widths != NULL && attr_widths[i] > 0)
1114  {
1115  tuple_width += attr_widths[i];
1116  continue;
1117  }
1118 
1119  /* This should match set_rel_width() in costsize.c */
1120  item_width = get_attavgwidth(RelationGetRelid(rel), i);
1121  if (item_width <= 0)
1122  {
1123  item_width = get_typavgwidth(att->atttypid, att->atttypmod);
1124  Assert(item_width > 0);
1125  }
1126  if (attr_widths != NULL)
1127  attr_widths[i] = item_width;
1128  tuple_width += item_width;
1129  }
1130 
1131  return tuple_width;
1132 }
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:413
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
signed int int32
Definition: c.h:313
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
TupleDesc rd_att
Definition: rel.h:85
int32 get_typavgwidth(Oid typid, int32 typmod)
Definition: lsyscache.c:2332
#define Assert(condition)
Definition: c.h:699
int i
int32 get_attavgwidth(Oid relid, AttrNumber attnum)
Definition: lsyscache.c:2846
#define RelationGetRelid(relation)
Definition: rel.h:407

◆ get_relation_constraints()

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

Definition at line 1175 of file plancat.c.

References NullTest::arg, NullTest::argisrow, canonicalize_qual(), constrCheck::ccbin, constrCheck::ccvalid, ChangeVarNodes(), tupleConstr::check, CMD_SELECT, Query::commandType, tupleDesc::constr, eval_const_expressions(), tupleConstr::has_not_null, heap_close, heap_open(), i, IS_NOT_NULL, lappend(), list_concat(), NullTest::location, make_ands_implicit(), makeNode, makeVar(), tupleDesc::natts, NIL, NoLock, NullTest::nulltesttype, tupleConstr::num_check, PlannerInfo::parse, RelationData::rd_att, RelationGetPartitionQual(), RelOptInfo::relid, stringToNode(), and TupleDescAttr.

Referenced by relation_excluded_by_constraints().

1178 {
1179  List *result = NIL;
1180  Index varno = rel->relid;
1181  Relation relation;
1182  TupleConstr *constr;
1183 
1184  /*
1185  * We assume the relation has already been safely locked.
1186  */
1187  relation = heap_open(relationObjectId, NoLock);
1188 
1189  constr = relation->rd_att->constr;
1190  if (constr != NULL)
1191  {
1192  int num_check = constr->num_check;
1193  int i;
1194 
1195  for (i = 0; i < num_check; i++)
1196  {
1197  Node *cexpr;
1198 
1199  /*
1200  * If this constraint hasn't been fully validated yet, we must
1201  * ignore it here.
1202  */
1203  if (!constr->check[i].ccvalid)
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  * Append partition predicates, if any.
1270  *
1271  * For selects, partition pruning uses the parent table's partition bound
1272  * descriptor, instead of constraint exclusion which is driven by the
1273  * individual partition's partition constraint.
1274  */
1275  if (root->parse->commandType != CMD_SELECT)
1276  {
1277  List *pcqual = RelationGetPartitionQual(relation);
1278 
1279  if (pcqual)
1280  {
1281  /*
1282  * Run the partition quals through const-simplification similar to
1283  * check constraints. We skip canonicalize_qual, though, because
1284  * partition quals should be in canonical form already; also,
1285  * since the qual is in implicit-AND format, we'd have to
1286  * explicitly convert it to explicit-AND format and back again.
1287  */
1288  pcqual = (List *) eval_const_expressions(root, (Node *) pcqual);
1289 
1290  /* Fix Vars to have the desired varno */
1291  if (varno != 1)
1292  ChangeVarNodes((Node *) pcqual, 1, varno, 0);
1293 
1294  result = list_concat(result, pcqual);
1295  }
1296  }
1297 
1298  heap_close(relation, NoLock);
1299 
1300  return result;
1301 }
#define NIL
Definition: pg_list.h:69
void * stringToNode(char *str)
Definition: read.c:39
Query * parse
Definition: relation.h:158
ConstrCheck * check
Definition: tupdesc.h:42
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:93
char * ccbin
Definition: tupdesc.h:33
Definition: nodes.h:517
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2460
List * list_concat(List *list1, List *list2)
Definition: list.c:321
#define heap_close(r, l)
Definition: heapam.h:97
int natts
Definition: tupdesc.h:82
List * make_ands_implicit(Expr *clause)
Definition: clauses.c:379
Expr * arg
Definition: primnodes.h:1188
#define NoLock
Definition: lockdefs.h:34
Expr * canonicalize_qual(Expr *qual, bool is_check)
Definition: prepqual.c:291
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:197
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Index relid
Definition: relation.h:628
bool has_not_null
Definition: tupdesc.h:46
List * lappend(List *list, void *datum)
Definition: list.c:128
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
unsigned int Index
Definition: c.h:442
TupleDesc rd_att
Definition: rel.h:85
NullTestType nulltesttype
Definition: primnodes.h:1189
CmdType commandType
Definition: parsenodes.h:112
#define makeNode(_type_)
Definition: nodes.h:565
TupleConstr * constr
Definition: tupdesc.h:87
int location
Definition: primnodes.h:1191
bool ccvalid
Definition: tupdesc.h:34
int i
List * RelationGetPartitionQual(Relation rel)
Definition: partcache.c:799
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
bool argisrow
Definition: primnodes.h:1190
uint16 num_check
Definition: tupdesc.h:45
Definition: pg_list.h:45

◆ get_relation_data_width()

int32 get_relation_data_width ( Oid  relid,
int32 attr_widths 
)

Definition at line 1141 of file plancat.c.

References get_rel_data_width(), heap_close, heap_open(), and NoLock.

Referenced by plan_cluster_use_sort(), and set_rel_width().

1142 {
1143  int32 result;
1144  Relation relation;
1145 
1146  /* As above, assume relation is already locked */
1147  relation = heap_open(relid, NoLock);
1148 
1149  result = get_rel_data_width(relation, attr_widths);
1150 
1151  heap_close(relation, NoLock);
1152 
1153  return result;
1154 }
#define heap_close(r, l)
Definition: heapam.h:97
signed int int32
Definition: c.h:313
static int32 get_rel_data_width(Relation rel, int32 *attr_widths)
Definition: plancat.c:1099
#define NoLock
Definition: lockdefs.h:34
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294

◆ get_relation_foreign_keys()

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

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

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

◆ get_relation_info()

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

Definition at line 108 of file plancat.c.

References _bt_getrootheight(), AccessShareLock, 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, heap_close, heap_open(), HeapTupleHeaderGetXmin, IndexOptInfo::hypothetical, i, IgnoreSystemIndexes, IndexOptInfo::immediate, index_can_return(), index_close(), index_open(), IndexOptInfo::indexcollations, IndexIsValid, 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(), PlannerInfo::parse, IndexOptInfo::predOK, RelationData::rd_amroutine, RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_indextuple, RelationData::rd_indoption, RelationData::rd_opcintype, RelationData::rd_opfamily, RelationData::rd_rel, RecoveryInProgress(), IndexOptInfo::rel, RelOptInfo::rel_parallel_workers, IndexOptInfo::relam, RelationGetForm, RelationGetIndexExpressions(), RelationGetIndexList(), RelationGetIndexPredicate(), RelationGetNumberOfAttributes, RelationGetNumberOfBlocks, RelationGetParallelWorkers, RelationGetRelid, RelationNeedsWAL, RelOptInfo::relid, RelOptInfo::reltablespace, IndexOptInfo::reltablespace, Query::resultRelation, IndexOptInfo::reverse_sort, RowExclusiveLock, RelOptInfo::serverid, set_relation_partition_info(), IndexOptInfo::sortopfamily, RelOptInfo::statlist, HeapTupleData::t_data, TransactionIdPrecedes(), TransactionXmin, PlannerGlobal::transientPlan, IndexOptInfo::tree_height, RelOptInfo::tuples, IndexOptInfo::tuples, and IndexOptInfo::unique.

Referenced by build_simple_rel().

110 {
111  Index varno = rel->relid;
112  Relation relation;
113  bool hasindex;
114  List *indexinfos = NIL;
115 
116  /*
117  * We need not lock the relation since it was already locked, either by
118  * the rewriter or when expand_inherited_rtentry() added it to the query's
119  * rangetable.
120  */
121  relation = heap_open(relationObjectId, NoLock);
122 
123  /* Temporary and unlogged relations are inaccessible during recovery. */
124  if (!RelationNeedsWAL(relation) && RecoveryInProgress())
125  ereport(ERROR,
126  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
127  errmsg("cannot access temporary or unlogged relations during recovery")));
128 
130  rel->max_attr = RelationGetNumberOfAttributes(relation);
131  rel->reltablespace = RelationGetForm(relation)->reltablespace;
132 
133  Assert(rel->max_attr >= rel->min_attr);
134  rel->attr_needed = (Relids *)
135  palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids));
136  rel->attr_widths = (int32 *)
137  palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32));
138 
139  /*
140  * Estimate relation size --- unless it's an inheritance parent, in which
141  * case the size will be computed later in set_append_rel_pathlist, and we
142  * must leave it zero for now to avoid bollixing the total_table_pages
143  * calculation.
144  */
145  if (!inhparent)
146  estimate_rel_size(relation, rel->attr_widths - rel->min_attr,
147  &rel->pages, &rel->tuples, &rel->allvisfrac);
148 
149  /* Retrieve the parallel_workers reloption, or -1 if not set. */
151 
152  /*
153  * Make list of indexes. Ignore indexes on system catalogs if told to.
154  * Don't bother with indexes for an inheritance parent, either.
155  */
156  if (inhparent ||
157  (IgnoreSystemIndexes && IsSystemRelation(relation)))
158  hasindex = false;
159  else
160  hasindex = relation->rd_rel->relhasindex;
161 
162  if (hasindex)
163  {
164  List *indexoidlist;
165  ListCell *l;
166  LOCKMODE lmode;
167 
168  indexoidlist = RelationGetIndexList(relation);
169 
170  /*
171  * For each index, we get the same type of lock that the executor will
172  * need, and do not release it. This saves a couple of trips to the
173  * shared lock manager while not creating any real loss of
174  * concurrency, because no schema changes could be happening on the
175  * index while we hold lock on the parent rel, and neither lock type
176  * blocks any other kind of index operation.
177  */
178  if (rel->relid == root->parse->resultRelation)
179  lmode = RowExclusiveLock;
180  else
181  lmode = AccessShareLock;
182 
183  foreach(l, indexoidlist)
184  {
185  Oid indexoid = lfirst_oid(l);
186  Relation indexRelation;
188  IndexAmRoutine *amroutine;
189  IndexOptInfo *info;
190  int ncolumns,
191  nkeycolumns;
192  int i;
193 
194  /*
195  * Extract info from the relation descriptor for the index.
196  */
197  indexRelation = index_open(indexoid, lmode);
198  index = indexRelation->rd_index;
199 
200  /*
201  * Ignore invalid indexes, since they can't safely be used for
202  * queries. Note that this is OK because the data structure we
203  * are constructing is only used by the planner --- the executor
204  * still needs to insert into "invalid" indexes, if they're marked
205  * IndexIsReady.
206  */
207  if (!IndexIsValid(index))
208  {
209  index_close(indexRelation, NoLock);
210  continue;
211  }
212 
213  /*
214  * Ignore partitioned indexes, since they are not usable for
215  * queries.
216  */
217  if (indexRelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
218  {
219  index_close(indexRelation, NoLock);
220  continue;
221  }
222 
223  /*
224  * If the index is valid, but cannot yet be used, ignore it; but
225  * mark the plan we are generating as transient. See
226  * src/backend/access/heap/README.HOT for discussion.
227  */
228  if (index->indcheckxmin &&
231  {
232  root->glob->transientPlan = true;
233  index_close(indexRelation, NoLock);
234  continue;
235  }
236 
237  info = makeNode(IndexOptInfo);
238 
239  info->indexoid = index->indexrelid;
240  info->reltablespace =
241  RelationGetForm(indexRelation)->reltablespace;
242  info->rel = rel;
243  info->ncolumns = ncolumns = index->indnatts;
244  info->nkeycolumns = nkeycolumns = index->indnkeyatts;
245 
246  info->indexkeys = (int *) palloc(sizeof(int) * ncolumns);
247  info->indexcollations = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
248  info->opfamily = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
249  info->opcintype = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
250  info->canreturn = (bool *) palloc(sizeof(bool) * ncolumns);
251 
252  for (i = 0; i < ncolumns; i++)
253  {
254  info->indexkeys[i] = index->indkey.values[i];
255  info->canreturn[i] = index_can_return(indexRelation, i + 1);
256  }
257 
258  for (i = 0; i < nkeycolumns; i++)
259  {
260  info->opfamily[i] = indexRelation->rd_opfamily[i];
261  info->opcintype[i] = indexRelation->rd_opcintype[i];
262  info->indexcollations[i] = indexRelation->rd_indcollation[i];
263  }
264 
265  info->relam = indexRelation->rd_rel->relam;
266 
267  /* We copy just the fields we need, not all of rd_amroutine */
268  amroutine = indexRelation->rd_amroutine;
269  info->amcanorderbyop = amroutine->amcanorderbyop;
270  info->amoptionalkey = amroutine->amoptionalkey;
271  info->amsearcharray = amroutine->amsearcharray;
272  info->amsearchnulls = amroutine->amsearchnulls;
273  info->amcanparallel = amroutine->amcanparallel;
274  info->amhasgettuple = (amroutine->amgettuple != NULL);
275  info->amhasgetbitmap = (amroutine->amgetbitmap != NULL);
276  info->amcostestimate = amroutine->amcostestimate;
277  Assert(info->amcostestimate != NULL);
278 
279  /*
280  * Fetch the ordering information for the index, if any.
281  */
282  if (info->relam == BTREE_AM_OID)
283  {
284  /*
285  * If it's a btree index, we can use its opfamily OIDs
286  * directly as the sort ordering opfamily OIDs.
287  */
288  Assert(amroutine->amcanorder);
289 
290  info->sortopfamily = info->opfamily;
291  info->reverse_sort = (bool *) palloc(sizeof(bool) * nkeycolumns);
292  info->nulls_first = (bool *) palloc(sizeof(bool) * nkeycolumns);
293 
294  for (i = 0; i < nkeycolumns; i++)
295  {
296  int16 opt = indexRelation->rd_indoption[i];
297 
298  info->reverse_sort[i] = (opt & INDOPTION_DESC) != 0;
299  info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0;
300  }
301  }
302  else if (amroutine->amcanorder)
303  {
304  /*
305  * Otherwise, identify the corresponding btree opfamilies by
306  * trying to map this index's "<" operators into btree. Since
307  * "<" uniquely defines the behavior of a sort order, this is
308  * a sufficient test.
309  *
310  * XXX This method is rather slow and also requires the
311  * undesirable assumption that the other index AM numbers its
312  * strategies the same as btree. It'd be better to have a way
313  * to explicitly declare the corresponding btree opfamily for
314  * each opfamily of the other index type. But given the lack
315  * of current or foreseeable amcanorder index types, it's not
316  * worth expending more effort on now.
317  */
318  info->sortopfamily = (Oid *) palloc(sizeof(Oid) * nkeycolumns);
319  info->reverse_sort = (bool *) palloc(sizeof(bool) * nkeycolumns);
320  info->nulls_first = (bool *) palloc(sizeof(bool) * nkeycolumns);
321 
322  for (i = 0; i < nkeycolumns; i++)
323  {
324  int16 opt = indexRelation->rd_indoption[i];
325  Oid ltopr;
326  Oid btopfamily;
327  Oid btopcintype;
328  int16 btstrategy;
329 
330  info->reverse_sort[i] = (opt & INDOPTION_DESC) != 0;
331  info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0;
332 
333  ltopr = get_opfamily_member(info->opfamily[i],
334  info->opcintype[i],
335  info->opcintype[i],
337  if (OidIsValid(ltopr) &&
339  &btopfamily,
340  &btopcintype,
341  &btstrategy) &&
342  btopcintype == info->opcintype[i] &&
343  btstrategy == BTLessStrategyNumber)
344  {
345  /* Successful mapping */
346  info->sortopfamily[i] = btopfamily;
347  }
348  else
349  {
350  /* Fail ... quietly treat index as unordered */
351  info->sortopfamily = NULL;
352  info->reverse_sort = NULL;
353  info->nulls_first = NULL;
354  break;
355  }
356  }
357  }
358  else
359  {
360  info->sortopfamily = NULL;
361  info->reverse_sort = NULL;
362  info->nulls_first = NULL;
363  }
364 
365  /*
366  * Fetch the index expressions and predicate, if any. We must
367  * modify the copies we obtain from the relcache to have the
368  * correct varno for the parent relation, so that they match up
369  * correctly against qual clauses.
370  */
371  info->indexprs = RelationGetIndexExpressions(indexRelation);
372  info->indpred = RelationGetIndexPredicate(indexRelation);
373  if (info->indexprs && varno != 1)
374  ChangeVarNodes((Node *) info->indexprs, 1, varno, 0);
375  if (info->indpred && varno != 1)
376  ChangeVarNodes((Node *) info->indpred, 1, varno, 0);
377 
378  /* Build targetlist using the completed indexprs data */
379  info->indextlist = build_index_tlist(root, info, relation);
380 
381  info->indrestrictinfo = NIL; /* set later, in indxpath.c */
382  info->predOK = false; /* set later, in indxpath.c */
383  info->unique = index->indisunique;
384  info->immediate = index->indimmediate;
385  info->hypothetical = false;
386 
387  /*
388  * Estimate the index size. If it's not a partial index, we lock
389  * the number-of-tuples estimate to equal the parent table; if it
390  * is partial then we have to use the same methods as we would for
391  * a table, except we can be sure that the index is not larger
392  * than the table.
393  */
394  if (info->indpred == NIL)
395  {
396  info->pages = RelationGetNumberOfBlocks(indexRelation);
397  info->tuples = rel->tuples;
398  }
399  else
400  {
401  double allvisfrac; /* dummy */
402 
403  estimate_rel_size(indexRelation, NULL,
404  &info->pages, &info->tuples, &allvisfrac);
405  if (info->tuples > rel->tuples)
406  info->tuples = rel->tuples;
407  }
408 
409  if (info->relam == BTREE_AM_OID)
410  {
411  /* For btrees, get tree height while we have the index open */
412  info->tree_height = _bt_getrootheight(indexRelation);
413  }
414  else
415  {
416  /* For other index types, just set it to "unknown" for now */
417  info->tree_height = -1;
418  }
419 
420  index_close(indexRelation, NoLock);
421 
422  indexinfos = lcons(info, indexinfos);
423  }
424 
425  list_free(indexoidlist);
426  }
427 
428  rel->indexlist = indexinfos;
429 
430  rel->statlist = get_relation_statistics(rel, relation);
431 
432  /* Grab foreign-table info using the relcache, while we have it */
433  if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
434  {
436  rel->fdwroutine = GetFdwRoutineForRelation(relation, true);
437  }
438  else
439  {
440  rel->serverid = InvalidOid;
441  rel->fdwroutine = NULL;
442  }
443 
444  /* Collect info about relation's foreign keys, if relevant */
445  get_relation_foreign_keys(root, rel, relation, inhparent);
446 
447  /*
448  * Collect info about relation's partitioning scheme, if any. Only
449  * inheritance parents may be partitioned.
450  */
451  if (inhparent && relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
452  set_relation_partition_info(root, rel, relation);
453 
454  heap_close(relation, NoLock);
455 
456  /*
457  * Allow a plugin to editorialize on the info we obtained from the
458  * catalogs. Actions might include altering the assumed relation size,
459  * removing an index, or adding a hypothetical index to the indexlist.
460  */
462  (*get_relation_info_hook) (root, relationObjectId, inhparent, rel);
463 }
signed short int16
Definition: c.h:312
#define NIL
Definition: pg_list.h:69
Query * parse
Definition: relation.h:158
List * statlist
Definition: relation.h:638
int16 * rd_indoption
Definition: rel.h:158
bool predOK
Definition: relation.h:776
static List * get_relation_statistics(RelOptInfo *rel, Relation relation)
Definition: plancat.c:1312
Oid * indexcollations
Definition: relation.h:755
Relids * attr_needed
Definition: relation.h:633
bool IsSystemRelation(Relation relation)
Definition: catalog.c:63
#define IndexIsValid(indexForm)
Definition: pg_index.h:85
amgettuple_function amgettuple
Definition: amapi.h:219
int _bt_getrootheight(Relation rel)
Definition: nbtpage.c:594
int LOCKMODE
Definition: lockdefs.h:26
bool amcanorderbyop
Definition: amapi.h:174
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:413
List * indextlist
Definition: relation.h:768
#define RelationGetForm(relation)
Definition: rel.h:401
double tuples
Definition: relation.h:640
Oid reltablespace
Definition: relation.h:629
int resultRelation
Definition: parsenodes.h:122
#define AccessShareLock
Definition: lockdefs.h:36
Definition: nodes.h:517
Oid * sortopfamily
Definition: relation.h:758
int errcode(int sqlerrcode)
Definition: elog.c:575
Oid reltablespace
Definition: relation.h:742
bool IgnoreSystemIndexes
Definition: miscinit.c:75
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
bool hypothetical
Definition: relation.h:779
#define heap_close(r, l)
Definition: heapam.h:97
bool immediate
Definition: relation.h:778
double tuples
Definition: relation.h:747
Form_pg_class rd_rel
Definition: rel.h:84
unsigned int Oid
Definition: postgres_ext.h:31
bool RecoveryInProgress(void)
Definition: xlog.c:7939
int tree_height
Definition: relation.h:748
#define OidIsValid(objectId)
Definition: c.h:605
bool amoptionalkey
Definition: amapi.h:182
struct IndexAmRoutine * rd_amroutine
Definition: rel.h:153
double allvisfrac
Definition: relation.h:641
signed int int32
Definition: c.h:313
List * RelationGetIndexPredicate(Relation relation)
Definition: relcache.c:4608
struct HeapTupleData * rd_indextuple
Definition: rel.h:133
TransactionId TransactionXmin
Definition: snapmgr.c:164
bool unique
Definition: relation.h:777
HeapTupleHeader t_data
Definition: htup.h:68
Definition: type.h:89
BlockNumber pages
Definition: relation.h:746
bool index_can_return(Relation indexRelation, int attno)
Definition: indexam.c:783
Form_pg_index rd_index
Definition: rel.h:131
RelOptInfo * rel
Definition: relation.h:743
bool amoptionalkey
Definition: relation.h:783
amgetbitmap_function amgetbitmap
Definition: amapi.h:220
Oid * rd_indcollation
Definition: rel.h:165
#define ERROR
Definition: elog.h:43
amcostestimate_function amcostestimate
Definition: amapi.h:213
#define NoLock
Definition: lockdefs.h:34
bool amcanorderbyop
Definition: relation.h:782
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:4546
PlannerGlobal * glob
Definition: relation.h:160
#define RowExclusiveLock
Definition: lockdefs.h:38
struct FdwRoutine * fdwroutine
Definition: relation.h:651
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:1871
get_relation_info_hook_type get_relation_info_hook
Definition: plancat.c:59
Oid * rd_opfamily
Definition: rel.h:154
void estimate_rel_size(Relation rel, int32 *attr_widths, BlockNumber *pages, double *tuples, double *allvisfrac)
Definition: plancat.c:939
void(* amcostestimate)()
Definition: relation.h:790
int ncolumns
Definition: relation.h:751
#define ereport(elevel, rest)
Definition: elog.h:122
bool amhasgetbitmap
Definition: relation.h:787
bool amcanparallel
Definition: amapi.h:194
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
Index relid
Definition: relation.h:628
Bitmapset * Relids
Definition: relation.h:29
Oid serverid
Definition: relation.h:647
FormData_pg_index * Form_pg_index
Definition: pg_index.h:66
bool amsearchnulls
Definition: amapi.h:186
List * indrestrictinfo
Definition: relation.h:770
void * palloc0(Size size)
Definition: mcxt.c:955
int rel_parallel_workers
Definition: relation.h:644
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
unsigned int Index
Definition: c.h:442
List * indexlist
Definition: relation.h:637
bool amsearcharray
Definition: amapi.h:184
bool amhasgettuple
Definition: relation.h:786
#define InvalidOid
Definition: postgres_ext.h:36
List * lcons(void *datum, List *list)
Definition: list.c:259
#define makeNode(_type_)
Definition: nodes.h:565
BlockNumber pages
Definition: relation.h:639
#define Assert(condition)
Definition: c.h:699
static void get_relation_foreign_keys(PlannerInfo *root, RelOptInfo *rel, Relation relation, bool inhparent)
Definition: plancat.c:476
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:318
Oid GetForeignServerIdByRelId(Oid relid)
Definition: foreign.c:308
bool get_ordering_op_properties(Oid opno, Oid *opfamily, Oid *opcintype, int16 *strategy)
Definition: lsyscache.c:204
bool amsearcharray
Definition: relation.h:784
bool amcanorder
Definition: amapi.h:172
int nkeycolumns
Definition: relation.h:752
#define RelationNeedsWAL(relation)
Definition: rel.h:510
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4190
Oid * opcintype
Definition: relation.h:757
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:176
Oid * opfamily
Definition: relation.h:756
AttrNumber max_attr
Definition: relation.h:632
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
FdwRoutine * GetFdwRoutineForRelation(Relation relation, bool makecopy)
Definition: foreign.c:395
void list_free(List *list)
Definition: list.c:1133
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:317
static List * build_index_tlist(PlannerInfo *root, IndexOptInfo *index, Relation heapRelation)
Definition: plancat.c:1649
int * indexkeys
Definition: relation.h:753
Oid indexoid
Definition: relation.h:741
bool * canreturn
Definition: relation.h:761
bool amsearchnulls
Definition: relation.h:785
Oid * rd_opcintype
Definition: rel.h:155
bool * nulls_first
Definition: relation.h:760
bool * reverse_sort
Definition: relation.h:759
#define BTLessStrategyNumber
Definition: stratnum.h:29
List * indpred
Definition: relation.h:766
int32 * attr_widths
Definition: relation.h:634
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:407
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:150
bool amcanparallel
Definition: relation.h:788
#define lfirst_oid(lc)
Definition: pg_list.h:108
List * indexprs
Definition: relation.h:765
bool transientPlan
Definition: relation.h:128
AttrNumber min_attr
Definition: relation.h:631

◆ get_relation_statistics()

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

Definition at line 1312 of file plancat.c.

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

Referenced by get_relation_info().

1313 {
1314  List *statoidlist;
1315  List *stainfos = NIL;
1316  ListCell *l;
1317 
1318  statoidlist = RelationGetStatExtList(relation);
1319 
1320  foreach(l, statoidlist)
1321  {
1322  Oid statOid = lfirst_oid(l);
1323  Form_pg_statistic_ext staForm;
1324  HeapTuple htup;
1325  Bitmapset *keys = NULL;
1326  int i;
1327 
1328  htup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statOid));
1329  if (!htup)
1330  elog(ERROR, "cache lookup failed for statistics object %u", statOid);
1331  staForm = (Form_pg_statistic_ext) GETSTRUCT(htup);
1332 
1333  /*
1334  * First, build the array of columns covered. This is ultimately
1335  * wasted if no stats within the object have actually been built, but
1336  * it doesn't seem worth troubling over that case.
1337  */
1338  for (i = 0; i < staForm->stxkeys.dim1; i++)
1339  keys = bms_add_member(keys, staForm->stxkeys.values[i]);
1340 
1341  /* add one StatisticExtInfo for each kind built */
1342  if (statext_is_kind_built(htup, STATS_EXT_NDISTINCT))
1343  {
1345 
1346  info->statOid = statOid;
1347  info->rel = rel;
1348  info->kind = STATS_EXT_NDISTINCT;
1349  info->keys = bms_copy(keys);
1350 
1351  stainfos = lcons(info, stainfos);
1352  }
1353 
1354  if (statext_is_kind_built(htup, STATS_EXT_DEPENDENCIES))
1355  {
1357 
1358  info->statOid = statOid;
1359  info->rel = rel;
1360  info->kind = STATS_EXT_DEPENDENCIES;
1361  info->keys = bms_copy(keys);
1362 
1363  stainfos = lcons(info, stainfos);
1364  }
1365 
1366  ReleaseSysCache(htup);
1367  bms_free(keys);
1368  }
1369 
1370  list_free(statoidlist);
1371 
1372  return stainfos;
1373 }
#define NIL
Definition: pg_list.h:69
#define GETSTRUCT(TUP)
Definition: htup_details.h:673
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:133
bool statext_is_kind_built(HeapTuple htup, char type)
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
RelOptInfo * rel
Definition: relation.h:835
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1112
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1160
List * lcons(void *datum, List *list)
Definition: list.c:259
void bms_free(Bitmapset *a)
Definition: bitmapset.c:267
#define makeNode(_type_)
Definition: nodes.h:565
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:764
List * RelationGetStatExtList(Relation relation)
Definition: relcache.c:4330
Bitmapset * keys
Definition: relation.h:837
void list_free(List *list)
Definition: list.c:1133
int i
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
FormData_pg_statistic_ext * Form_pg_statistic_ext
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ has_row_triggers()

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

Definition at line 1825 of file plancat.c.

References CMD_DELETE, CMD_INSERT, CMD_UPDATE, elog, ERROR, heap_close, heap_open(), NoLock, planner_rt_fetch, RangeTblEntry::relid, 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().

1826 {
1827  RangeTblEntry *rte = planner_rt_fetch(rti, root);
1828  Relation relation;
1829  TriggerDesc *trigDesc;
1830  bool result = false;
1831 
1832  /* Assume we already have adequate lock */
1833  relation = heap_open(rte->relid, NoLock);
1834 
1835  trigDesc = relation->trigdesc;
1836  switch (event)
1837  {
1838  case CMD_INSERT:
1839  if (trigDesc &&
1840  (trigDesc->trig_insert_after_row ||
1841  trigDesc->trig_insert_before_row))
1842  result = true;
1843  break;
1844  case CMD_UPDATE:
1845  if (trigDesc &&
1846  (trigDesc->trig_update_after_row ||
1847  trigDesc->trig_update_before_row))
1848  result = true;
1849  break;
1850  case CMD_DELETE:
1851  if (trigDesc &&
1852  (trigDesc->trig_delete_after_row ||
1853  trigDesc->trig_delete_before_row))
1854  result = true;
1855  break;
1856  default:
1857  elog(ERROR, "unrecognized CmdType: %d", (int) event);
1858  break;
1859  }
1860 
1861  heap_close(relation, NoLock);
1862  return result;
1863 }
#define heap_close(r, l)
Definition: heapam.h:97
#define planner_rt_fetch(rti, root)
Definition: relation.h:332
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:90
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
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1294
#define elog
Definition: elog.h:219
bool trig_delete_before_row
Definition: reltrigger.h:65

◆ has_unique_index()

bool has_unique_index ( RelOptInfo rel,
AttrNumber  attno 
)

Definition at line 1793 of file plancat.c.

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

Referenced by examine_variable().

1794 {
1795  ListCell *ilist;
1796 
1797  foreach(ilist, rel->indexlist)
1798  {
1799  IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
1800 
1801  /*
1802  * Note: ignore partial indexes, since they don't allow us to conclude
1803  * that all attr values are distinct, *unless* they are marked predOK
1804  * which means we know the index's predicate is satisfied by the
1805  * query. We don't take any interest in expressional indexes either.
1806  * Also, a multicolumn unique index doesn't allow us to conclude that
1807  * just the specified attr is unique.
1808  */
1809  if (index->unique &&
1810  index->nkeycolumns == 1 &&
1811  index->indexkeys[0] == attno &&
1812  (index->indpred == NIL || index->predOK))
1813  return true;
1814  }
1815  return false;
1816 }
#define NIL
Definition: pg_list.h:69
bool predOK
Definition: relation.h:776
bool unique
Definition: relation.h:777
Definition: type.h:89
List * indexlist
Definition: relation.h:637
#define lfirst(lc)
Definition: pg_list.h:106
int nkeycolumns
Definition: relation.h:752
int * indexkeys
Definition: relation.h:753
List * indpred
Definition: relation.h:766

◆ infer_arbiter_indexes()

List* infer_arbiter_indexes ( PlannerInfo root)

Definition at line 589 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(), heap_close, heap_open(), index_close(), index_open(), IndexIsValid, 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(), Query::resultRelation, RowExclusiveLock, rt_fetch, Query::rtable, and Var::varattno.

Referenced by make_modifytable().

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

◆ infer_collation_opclass_match()

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

Definition at line 857 of file plancat.c.

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

Referenced by infer_arbiter_indexes().

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

◆ join_selectivity()

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

Definition at line 1749 of file plancat.c.

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

Referenced by clause_selectivity(), and rowcomparesel().

1755 {
1756  RegProcedure oprjoin = get_oprjoin(operatorid);
1757  float8 result;
1758 
1759  /*
1760  * if the oprjoin procedure is missing for whatever reason, use a
1761  * selectivity of 0.5
1762  */
1763  if (!oprjoin)
1764  return (Selectivity) 0.5;
1765 
1766  result = DatumGetFloat8(OidFunctionCall5Coll(oprjoin,
1767  inputcollid,
1768  PointerGetDatum(root),
1769  ObjectIdGetDatum(operatorid),
1770  PointerGetDatum(args),
1771  Int16GetDatum(jointype),
1772  PointerGetDatum(sjinfo)));
1773 
1774  if (result < 0.0 || result > 1.0)
1775  elog(ERROR, "invalid join selectivity: %f", result);
1776 
1777  return (Selectivity) result;
1778 }
RegProcedure get_oprjoin(Oid opno)
Definition: lsyscache.c:1370
#define PointerGetDatum(X)
Definition: postgres.h:539
regproc RegProcedure
Definition: c.h:472
#define Int16GetDatum(X)
Definition: postgres.h:434
double Selectivity
Definition: nodes.h:647
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
double float8
Definition: c.h:458
#define DatumGetFloat8(X)
Definition: postgres.h:711
Datum OidFunctionCall5Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5)
Definition: fmgr.c:1510
#define elog
Definition: elog.h:219

◆ relation_excluded_by_constraints()

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

Definition at line 1387 of file plancat.c.

References Assert, RelOptInfo::baserestrictinfo, RestrictInfo::clause, constraint_exclusion, CONSTRAINT_EXCLUSION_OFF, CONSTRAINT_EXCLUSION_PARTITION, contain_mutable_functions(), DatumGetBool, get_relation_constraints(), PlannerInfo::hasInheritedTarget, RangeTblEntry::inh, 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().

1389 {
1390  List *safe_restrictions;
1391  List *constraint_pred;
1392  List *safe_constraints;
1393  ListCell *lc;
1394 
1395  /* As of now, constraint exclusion works only with simple relations. */
1396  Assert(IS_SIMPLE_REL(rel));
1397 
1398  /*
1399  * Regardless of the setting of constraint_exclusion, detect
1400  * constant-FALSE-or-NULL restriction clauses. Because const-folding will
1401  * reduce "anything AND FALSE" to just "FALSE", any such case should
1402  * result in exactly one baserestrictinfo entry. This doesn't fire very
1403  * often, but it seems cheap enough to be worth doing anyway. (Without
1404  * this, we'd miss some optimizations that 9.5 and earlier found via much
1405  * more roundabout methods.)
1406  */
1407  if (list_length(rel->baserestrictinfo) == 1)
1408  {
1410  Expr *clause = rinfo->clause;
1411 
1412  if (clause && IsA(clause, Const) &&
1413  (((Const *) clause)->constisnull ||
1414  !DatumGetBool(((Const *) clause)->constvalue)))
1415  return true;
1416  }
1417 
1418  /* Skip further tests if constraint exclusion is disabled for the rel */
1421  !(rel->reloptkind == RELOPT_OTHER_MEMBER_REL ||
1422  (root->hasInheritedTarget &&
1423  rel->reloptkind == RELOPT_BASEREL &&
1424  rel->relid == root->parse->resultRelation))))
1425  return false;
1426 
1427  /*
1428  * Check for self-contradictory restriction clauses. We dare not make
1429  * deductions with non-immutable functions, but any immutable clauses that
1430  * are self-contradictory allow us to conclude the scan is unnecessary.
1431  *
1432  * Note: strip off RestrictInfo because predicate_refuted_by() isn't
1433  * expecting to see any in its predicate argument.
1434  */
1435  safe_restrictions = NIL;
1436  foreach(lc, rel->baserestrictinfo)
1437  {
1438  RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
1439 
1440  if (!contain_mutable_functions((Node *) rinfo->clause))
1441  safe_restrictions = lappend(safe_restrictions, rinfo->clause);
1442  }
1443 
1444  /*
1445  * We can use weak refutation here, since we're comparing restriction
1446  * clauses with restriction clauses.
1447  */
1448  if (predicate_refuted_by(safe_restrictions, safe_restrictions, true))
1449  return true;
1450 
1451  /*
1452  * Only plain relations have constraints. In a partitioning hierarchy,
1453  * but not with regular table inheritance, it's OK to assume that any
1454  * constraints that hold for the parent also hold for every child; for
1455  * instance, table inheritance allows the parent to have constraints
1456  * marked NO INHERIT, but table partitioning does not. We choose to check
1457  * whether the partitioning parents can be excluded here; doing so
1458  * consumes some cycles, but potentially saves us the work of excluding
1459  * each child individually.
1460  */
1461  if (rte->rtekind != RTE_RELATION ||
1462  (rte->inh && rte->relkind != RELKIND_PARTITIONED_TABLE))
1463  return false;
1464 
1465  /*
1466  * OK to fetch the constraint expressions. Include "col IS NOT NULL"
1467  * expressions for attnotnull columns, in case we can refute those.
1468  */
1469  constraint_pred = get_relation_constraints(root, rte->relid, rel, true);
1470 
1471  /*
1472  * We do not currently enforce that CHECK constraints contain only
1473  * immutable functions, so it's necessary to check here. We daren't draw
1474  * conclusions from plan-time evaluation of non-immutable functions. Since
1475  * they're ANDed, we can just ignore any mutable constraints in the list,
1476  * and reason about the rest.
1477  */
1478  safe_constraints = NIL;
1479  foreach(lc, constraint_pred)
1480  {
1481  Node *pred = (Node *) lfirst(lc);
1482 
1483  if (!contain_mutable_functions(pred))
1484  safe_constraints = lappend(safe_constraints, pred);
1485  }
1486 
1487  /*
1488  * The constraints are effectively ANDed together, so we can just try to
1489  * refute the entire collection at once. This may allow us to make proofs
1490  * that would fail if we took them individually.
1491  *
1492  * Note: we use rel->baserestrictinfo, not safe_restrictions as might seem
1493  * an obvious optimization. Some of the clauses might be OR clauses that
1494  * have volatile and nonvolatile subclauses, and it's OK to make
1495  * deductions with the nonvolatile parts.
1496  *
1497  * We need strong refutation because we have to prove that the constraints
1498  * would yield false, not just NULL.
1499  */
1500  if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo, false))
1501  return true;
1502 
1503  return false;
1504 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
Query * parse
Definition: relation.h:158
RelOptKind reloptkind
Definition: relation.h:597
List * baserestrictinfo
Definition: relation.h:660
int constraint_exclusion
Definition: plancat.c:56
int resultRelation
Definition: parsenodes.h:122
Definition: nodes.h:517
#define IS_SIMPLE_REL(rel)
Definition: relation.h:573
#define linitial(l)
Definition: pg_list.h:111
bool predicate_refuted_by(List *predicate_list, List *clause_list, bool weak)
Definition: predtest.c:219
#define DatumGetBool(X)
Definition: postgres.h:376
Index relid
Definition: relation.h:628
List * lappend(List *list, void *datum)
Definition: list.c:128
Expr * clause
Definition: relation.h:1868
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
bool hasInheritedTarget
Definition: relation.h:301
static int list_length(const List *l)
Definition: pg_list.h:89
RTEKind rtekind
Definition: parsenodes.h:962
bool contain_mutable_functions(Node *clause)
Definition: clauses.c:879
Definition: pg_list.h:45
static List * get_relation_constraints(PlannerInfo *root, Oid relationObjectId, RelOptInfo *rel, bool include_notnull)
Definition: plancat.c:1175

◆ restriction_selectivity()

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

Definition at line 1712 of file plancat.c.

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

Referenced by clause_selectivity(), and rowcomparesel().

1717 {
1718  RegProcedure oprrest = get_oprrest(operatorid);
1719  float8 result;
1720 
1721  /*
1722  * if the oprrest procedure is missing for whatever reason, use a
1723  * selectivity of 0.5
1724  */
1725  if (!oprrest)
1726  return (Selectivity) 0.5;
1727 
1728  result = DatumGetFloat8(OidFunctionCall4Coll(oprrest,
1729  inputcollid,
1730  PointerGetDatum(root),
1731  ObjectIdGetDatum(operatorid),
1732  PointerGetDatum(args),
1733  Int32GetDatum(varRelid)));
1734 
1735  if (result < 0.0 || result > 1.0)
1736  elog(ERROR, "invalid restriction selectivity: %f", result);
1737 
1738  return (Selectivity) result;
1739 }
#define PointerGetDatum(X)
Definition: postgres.h:539
regproc RegProcedure
Definition: c.h:472
double Selectivity
Definition: nodes.h:647
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
double float8
Definition: c.h:458
RegProcedure get_oprrest(Oid opno)
Definition: lsyscache.c:1346
#define DatumGetFloat8(X)
Definition: postgres.h:711
Datum OidFunctionCall4Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4)
Definition: fmgr.c:1480
#define Int32GetDatum(X)
Definition: postgres.h:462
#define elog
Definition: elog.h:219

◆ set_baserel_partition_key_exprs()

static void set_baserel_partition_key_exprs ( Relation  relation,
RelOptInfo rel 
)
static

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

2005 {
2006  PartitionKey partkey = RelationGetPartitionKey(relation);
2007  int partnatts;
2008  int cnt;
2009  List **partexprs;
2010  ListCell *lc;
2011  Index varno = rel->relid;
2012 
2013  Assert(IS_SIMPLE_REL(rel) && rel->relid > 0);
2014 
2015  /* A partitioned table should have a partition key. */
2016  Assert(partkey != NULL);
2017 
2018  partnatts = partkey->partnatts;
2019  partexprs = (List **) palloc(sizeof(List *) * partnatts);
2020  lc = list_head(partkey->partexprs);
2021 
2022  for (cnt = 0; cnt < partnatts; cnt++)
2023  {
2024  Expr *partexpr;
2025  AttrNumber attno = partkey->partattrs[cnt];
2026 
2027  if (attno != InvalidAttrNumber)
2028  {
2029  /* Single column partition key is stored as a Var node. */
2030  Assert(attno > 0);
2031 
2032  partexpr = (Expr *) makeVar(varno, attno,
2033  partkey->parttypid[cnt],
2034  partkey->parttypmod[cnt],
2035  partkey->parttypcoll[cnt], 0);
2036  }
2037  else
2038  {
2039  if (lc == NULL)
2040  elog(ERROR, "wrong number of partition key expressions");
2041 
2042  /* Re-stamp the expression with given varno. */
2043  partexpr = (Expr *) copyObject(lfirst(lc));
2044  ChangeVarNodes((Node *) partexpr, 1, varno, 0);
2045  lc = lnext(lc);
2046  }
2047 
2048  partexprs[cnt] = list_make1(partexpr);
2049  }
2050 
2051  rel->partexprs = partexprs;
2052 
2053  /*
2054  * A base relation can not have nullable partition key expressions. We
2055  * still allocate array of empty expressions lists to keep partition key
2056  * expression handling code simple. See build_joinrel_partition_info() and
2057  * match_expr_to_partition_keys().
2058  */
2059  rel->nullable_partexprs = (List **) palloc0(sizeof(List *) * partnatts);
2060 }
Definition: nodes.h:517
List * partexprs
Definition: partcache.h:30
List ** nullable_partexprs
Definition: relation.h:679
#define IS_SIMPLE_REL(rel)
Definition: relation.h:573
#define list_make1(x1)
Definition: pg_list.h:139
Oid * parttypcoll
Definition: partcache.h:46
List ** partexprs
Definition: relation.h:678
#define ERROR
Definition: elog.h:43
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
#define lnext(lc)
Definition: pg_list.h:105
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Index relid
Definition: relation.h:628
void * palloc0(Size size)
Definition: mcxt.c:955
AttrNumber * partattrs
Definition: partcache.h:28
unsigned int Index
Definition: c.h:442
int32 * parttypmod
Definition: partcache.h:42
#define Assert(condition)
Definition: c.h:699
#define lfirst(lc)
Definition: pg_list.h:106
#define RelationGetPartitionKey(relation)
Definition: rel.h:589
#define InvalidAttrNumber
Definition: attnum.h:23
void * palloc(Size size)
Definition: mcxt.c:924
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
#define elog
Definition: elog.h:219
#define copyObject(obj)
Definition: nodes.h:630
Definition: pg_list.h:45
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 1871 of file plancat.c.

References Assert, PartitionDescData::boundinfo, RelOptInfo::boundinfo, find_partition_scheme(), PartitionDescData::nparts, RelOptInfo::nparts, RelOptInfo::part_scheme, partition_bounds_copy(), RelOptInfo::partition_qual, RelationData::rd_rel, RelationGetPartitionDesc, RelationGetPartitionKey, RelationGetPartitionQual(), and set_baserel_partition_key_exprs().

Referenced by get_relation_info().

1873 {
1874  PartitionDesc partdesc;
1875  PartitionKey partkey;
1876 
1877  Assert(relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
1878 
1879  partdesc = RelationGetPartitionDesc(relation);
1880  partkey = RelationGetPartitionKey(relation);
1881  rel->part_scheme = find_partition_scheme(root, relation);
1882  Assert(partdesc != NULL && rel->part_scheme != NULL);
1883  rel->boundinfo = partition_bounds_copy(partdesc->boundinfo, partkey);
1884  rel->nparts = partdesc->nparts;
1885  set_baserel_partition_key_exprs(relation, rel);
1886  rel->partition_qual = RelationGetPartitionQual(relation);
1887 }
Form_pg_class rd_rel
Definition: rel.h:84
PartitionBoundInfo boundinfo
Definition: partition.h:30
int nparts
Definition: relation.h:673
PartitionBoundInfo partition_bounds_copy(PartitionBoundInfo src, PartitionKey key)
Definition: partbounds.c:217
struct PartitionBoundInfoData * boundinfo
Definition: relation.h:674
static PartitionScheme find_partition_scheme(PlannerInfo *root, Relation rel)
Definition: plancat.c:1895
#define Assert(condition)
Definition: c.h:699
#define RelationGetPartitionKey(relation)
Definition: rel.h:589
List * RelationGetPartitionQual(Relation rel)
Definition: partcache.c:799
PartitionScheme part_scheme
Definition: relation.h:672
static void set_baserel_partition_key_exprs(Relation relation, RelOptInfo *rel)
Definition: plancat.c:2003
List * partition_qual
Definition: relation.h:675
#define RelationGetPartitionDesc(relation)
Definition: rel.h:595

Variable Documentation

◆ constraint_exclusion

int constraint_exclusion = CONSTRAINT_EXCLUSION_PARTITION

Definition at line 56 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 59 of file plancat.c.

Referenced by get_relation_info().