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 "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/syscache.h"
#include "utils/rel.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 1622 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().

1624 {
1625  List *tlist = NIL;
1626  Index varno = index->rel->relid;
1627  ListCell *indexpr_item;
1628  int i;
1629 
1630  indexpr_item = list_head(index->indexprs);
1631  for (i = 0; i < index->ncolumns; i++)
1632  {
1633  int indexkey = index->indexkeys[i];
1634  Expr *indexvar;
1635 
1636  if (indexkey != 0)
1637  {
1638  /* simple column */
1639  Form_pg_attribute att_tup;
1640 
1641  if (indexkey < 0)
1642  att_tup = SystemAttributeDefinition(indexkey,
1643  heapRelation->rd_rel->relhasoids);
1644  else
1645  att_tup = TupleDescAttr(heapRelation->rd_att, indexkey - 1);
1646 
1647  indexvar = (Expr *) makeVar(varno,
1648  indexkey,
1649  att_tup->atttypid,
1650  att_tup->atttypmod,
1651  att_tup->attcollation,
1652  0);
1653  }
1654  else
1655  {
1656  /* expression column */
1657  if (indexpr_item == NULL)
1658  elog(ERROR, "wrong number of index expressions");
1659  indexvar = (Expr *) lfirst(indexpr_item);
1660  indexpr_item = lnext(indexpr_item);
1661  }
1662 
1663  tlist = lappend(tlist,
1664  makeTargetEntry(indexvar,
1665  i + 1,
1666  NULL,
1667  false));
1668  }
1669  if (indexpr_item != NULL)
1670  elog(ERROR, "wrong number of index expressions");
1671 
1672  return tlist;
1673 }
#define NIL
Definition: pg_list.h:69
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
Form_pg_class rd_rel
Definition: rel.h:114
RelOptInfo * rel
Definition: relation.h:725
#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:187
int ncolumns
Definition: relation.h:733
#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:613
List * lappend(List *list, void *datum)
Definition: list.c:128
unsigned int Index
Definition: c.h:431
TupleDesc rd_att
Definition: rel.h:115
Form_pg_attribute SystemAttributeDefinition(AttrNumber attno, bool relhasoids)
Definition: heap.c:200
#define lfirst(lc)
Definition: pg_list.h:106
int i
int * indexkeys
Definition: relation.h:734
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
List * indexprs
Definition: relation.h:745

◆ build_physical_tlist()

List* build_physical_tlist ( PlannerInfo root,
RelOptInfo rel 
)

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

1503 {
1504  List *tlist = NIL;
1505  Index varno = rel->relid;
1506  RangeTblEntry *rte = planner_rt_fetch(varno, root);
1507  Relation relation;
1508  Query *subquery;
1509  Var *var;
1510  ListCell *l;
1511  int attrno,
1512  numattrs;
1513  List *colvars;
1514 
1515  switch (rte->rtekind)
1516  {
1517  case RTE_RELATION:
1518  /* Assume we already have adequate lock */
1519  relation = heap_open(rte->relid, NoLock);
1520 
1521  numattrs = RelationGetNumberOfAttributes(relation);
1522  for (attrno = 1; attrno <= numattrs; attrno++)
1523  {
1524  Form_pg_attribute att_tup = TupleDescAttr(relation->rd_att,
1525  attrno - 1);
1526 
1527  if (att_tup->attisdropped)
1528  {
1529  /* found a dropped col, so punt */
1530  tlist = NIL;
1531  break;
1532  }
1533 
1534  var = makeVar(varno,
1535  attrno,
1536  att_tup->atttypid,
1537  att_tup->atttypmod,
1538  att_tup->attcollation,
1539  0);
1540 
1541  tlist = lappend(tlist,
1542  makeTargetEntry((Expr *) var,
1543  attrno,
1544  NULL,
1545  false));
1546  }
1547 
1548  heap_close(relation, NoLock);
1549  break;
1550 
1551  case RTE_SUBQUERY:
1552  subquery = rte->subquery;
1553  foreach(l, subquery->targetList)
1554  {
1555  TargetEntry *tle = (TargetEntry *) lfirst(l);
1556 
1557  /*
1558  * A resjunk column of the subquery can be reflected as
1559  * resjunk in the physical tlist; we need not punt.
1560  */
1561  var = makeVarFromTargetEntry(varno, tle);
1562 
1563  tlist = lappend(tlist,
1564  makeTargetEntry((Expr *) var,
1565  tle->resno,
1566  NULL,
1567  tle->resjunk));
1568  }
1569  break;
1570 
1571  case RTE_FUNCTION:
1572  case RTE_TABLEFUNC:
1573  case RTE_VALUES:
1574  case RTE_CTE:
1575  case RTE_NAMEDTUPLESTORE:
1576  /* Not all of these can have dropped cols, but share code anyway */
1577  expandRTE(rte, varno, 0, -1, true /* include dropped */ ,
1578  NULL, &colvars);
1579  foreach(l, colvars)
1580  {
1581  var = (Var *) lfirst(l);
1582 
1583  /*
1584  * A non-Var in expandRTE's output means a dropped column;
1585  * must punt.
1586  */
1587  if (!IsA(var, Var))
1588  {
1589  tlist = NIL;
1590  break;
1591  }
1592 
1593  tlist = lappend(tlist,
1594  makeTargetEntry((Expr *) var,
1595  var->varattno,
1596  NULL,
1597  false));
1598  }
1599  break;
1600 
1601  default:
1602  /* caller error */
1603  elog(ERROR, "unsupported RTE kind %d in build_physical_tlist",
1604  (int) rte->rtekind);
1605  break;
1606  }
1607 
1608  return tlist;
1609 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:564
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:431
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
Var * makeVarFromTargetEntry(Index varno, TargetEntry *tle)
Definition: makefuncs.c:104
#define heap_close(r, l)
Definition: heapam.h:97
Definition: primnodes.h:163
List * targetList
Definition: parsenodes.h:138
bool resjunk
Definition: primnodes.h:1382
#define planner_rt_fetch(rti, root)
Definition: relation.h:328
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
AttrNumber resno
Definition: primnodes.h:1376
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
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:613
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:1290
unsigned int Index
Definition: c.h:431
TupleDesc rd_att
Definition: rel.h:115
#define lfirst(lc)
Definition: pg_list.h:106
RTEKind rtekind
Definition: parsenodes.h:959
Query * subquery
Definition: parsenodes.h:982
#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 930 of file plancat.c.

References get_rel_data_width(), MAXALIGN, RelationData::rd_rel, RelationGetNumberOfBlocks, RELKIND_FOREIGN_TABLE, RELKIND_INDEX, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_TOASTVALUE, rint(), SizeofHeapTupleHeader, and SizeOfPageHeaderData.

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

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

◆ find_partition_scheme()

static PartitionScheme find_partition_scheme ( PlannerInfo root,
Relation  rel 
)
static

Definition at line 1867 of file plancat.c.

References Assert, lappend(), lfirst, palloc(), palloc0(), PlannerInfo::part_schemes, PartitionKeyData::partnatts, PartitionSchemeData::partnatts, PartitionKeyData::partopcintype, PartitionSchemeData::partopcintype, PartitionKeyData::partopfamily, PartitionSchemeData::partopfamily, PartitionKeyData::parttypbyval, PartitionSchemeData::parttypbyval, PartitionKeyData::parttypcoll, PartitionSchemeData::parttypcoll, PartitionKeyData::parttyplen, PartitionSchemeData::parttyplen, RelationGetPartitionKey, PartitionKeyData::strategy, and PartitionSchemeData::strategy.

Referenced by set_relation_partition_info().

1868 {
1869  PartitionKey partkey = RelationGetPartitionKey(relation);
1870  ListCell *lc;
1871  int partnatts;
1872  PartitionScheme part_scheme;
1873 
1874  /* A partitioned table should have a partition key. */
1875  Assert(partkey != NULL);
1876 
1877  partnatts = partkey->partnatts;
1878 
1879  /* Search for a matching partition scheme and return if found one. */
1880  foreach(lc, root->part_schemes)
1881  {
1882  part_scheme = lfirst(lc);
1883 
1884  /* Match partitioning strategy and number of keys. */
1885  if (partkey->strategy != part_scheme->strategy ||
1886  partnatts != part_scheme->partnatts)
1887  continue;
1888 
1889  /* Match the partition key types. */
1890  if (memcmp(partkey->partopfamily, part_scheme->partopfamily,
1891  sizeof(Oid) * partnatts) != 0 ||
1892  memcmp(partkey->partopcintype, part_scheme->partopcintype,
1893  sizeof(Oid) * partnatts) != 0 ||
1894  memcmp(partkey->parttypcoll, part_scheme->parttypcoll,
1895  sizeof(Oid) * partnatts) != 0)
1896  continue;
1897 
1898  /*
1899  * Length and byval information should match when partopcintype
1900  * matches.
1901  */
1902  Assert(memcmp(partkey->parttyplen, part_scheme->parttyplen,
1903  sizeof(int16) * partnatts) == 0);
1904  Assert(memcmp(partkey->parttypbyval, part_scheme->parttypbyval,
1905  sizeof(bool) * partnatts) == 0);
1906 
1907  /* Found matching partition scheme. */
1908  return part_scheme;
1909  }
1910 
1911  /*
1912  * Did not find matching partition scheme. Create one copying relevant
1913  * information from the relcache. We need to copy the contents of the
1914  * array since the relcache entry may not survive after we have closed the
1915  * relation.
1916  */
1917  part_scheme = (PartitionScheme) palloc0(sizeof(PartitionSchemeData));
1918  part_scheme->strategy = partkey->strategy;
1919  part_scheme->partnatts = partkey->partnatts;
1920 
1921  part_scheme->partopfamily = (Oid *) palloc(sizeof(Oid) * partnatts);
1922  memcpy(part_scheme->partopfamily, partkey->partopfamily,
1923  sizeof(Oid) * partnatts);
1924 
1925  part_scheme->partopcintype = (Oid *) palloc(sizeof(Oid) * partnatts);
1926  memcpy(part_scheme->partopcintype, partkey->partopcintype,
1927  sizeof(Oid) * partnatts);
1928 
1929  part_scheme->parttypcoll = (Oid *) palloc(sizeof(Oid) * partnatts);
1930  memcpy(part_scheme->parttypcoll, partkey->parttypcoll,
1931  sizeof(Oid) * partnatts);
1932 
1933  part_scheme->parttyplen = (int16 *) palloc(sizeof(int16) * partnatts);
1934  memcpy(part_scheme->parttyplen, partkey->parttyplen,
1935  sizeof(int16) * partnatts);
1936 
1937  part_scheme->parttypbyval = (bool *) palloc(sizeof(bool) * partnatts);
1938  memcpy(part_scheme->parttypbyval, partkey->parttypbyval,
1939  sizeof(bool) * partnatts);
1940 
1941  /* Add the partitioning scheme to PlannerInfo. */
1942  root->part_schemes = lappend(root->part_schemes, part_scheme);
1943 
1944  return part_scheme;
1945 }
signed short int16
Definition: c.h:301
Oid * partopfamily
Definition: rel.h:61
List * part_schemes
Definition: relation.h:269
char strategy
Definition: rel.h:54
unsigned int Oid
Definition: postgres_ext.h:31
Oid * parttypcoll
Definition: rel.h:74
struct PartitionSchemeData * PartitionScheme
Definition: relation.h:359
int16 * parttyplen
Definition: relation.h:355
List * lappend(List *list, void *datum)
Definition: list.c:128
void * palloc0(Size size)
Definition: mcxt.c:864
int16 partnatts
Definition: rel.h:55
bool * parttypbyval
Definition: rel.h:72
#define Assert(condition)
Definition: c.h:688
#define lfirst(lc)
Definition: pg_list.h:106
int16 * parttyplen
Definition: rel.h:71
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
void * palloc(Size size)
Definition: mcxt.c:835
Oid * partopcintype
Definition: rel.h:62

◆ get_rel_data_width()

static int32 get_rel_data_width ( Relation  rel,
int32 attr_widths 
)
static

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

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

◆ get_relation_constraints()

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

Definition at line 1166 of file plancat.c.

References NullTest::arg, NullTest::argisrow, canonicalize_qual(), constrCheck::ccbin, constrCheck::ccvalid, ChangeVarNodes(), tupleConstr::check, 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, RelationData::rd_att, RelationGetPartitionQual(), RelOptInfo::relid, stringToNode(), and TupleDescAttr.

Referenced by relation_excluded_by_constraints().

1169 {
1170  List *result = NIL;
1171  Index varno = rel->relid;
1172  Relation relation;
1173  TupleConstr *constr;
1174  List *pcqual;
1175 
1176  /*
1177  * We assume the relation has already been safely locked.
1178  */
1179  relation = heap_open(relationObjectId, NoLock);
1180 
1181  constr = relation->rd_att->constr;
1182  if (constr != NULL)
1183  {
1184  int num_check = constr->num_check;
1185  int i;
1186 
1187  for (i = 0; i < num_check; i++)
1188  {
1189  Node *cexpr;
1190 
1191  /*
1192  * If this constraint hasn't been fully validated yet, we must
1193  * ignore it here.
1194  */
1195  if (!constr->check[i].ccvalid)
1196  continue;
1197 
1198  cexpr = stringToNode(constr->check[i].ccbin);
1199 
1200  /*
1201  * Run each expression through const-simplification and
1202  * canonicalization. This is not just an optimization, but is
1203  * necessary, because we will be comparing it to
1204  * similarly-processed qual clauses, and may fail to detect valid
1205  * matches without this. This must match the processing done to
1206  * qual clauses in preprocess_expression()! (We can skip the
1207  * stuff involving subqueries, however, since we don't allow any
1208  * in check constraints.)
1209  */
1210  cexpr = eval_const_expressions(root, cexpr);
1211 
1212  cexpr = (Node *) canonicalize_qual((Expr *) cexpr);
1213 
1214  /* Fix Vars to have the desired varno */
1215  if (varno != 1)
1216  ChangeVarNodes(cexpr, 1, varno, 0);
1217 
1218  /*
1219  * Finally, convert to implicit-AND format (that is, a List) and
1220  * append the resulting item(s) to our output list.
1221  */
1222  result = list_concat(result,
1223  make_ands_implicit((Expr *) cexpr));
1224  }
1225 
1226  /* Add NOT NULL constraints in expression form, if requested */
1227  if (include_notnull && constr->has_not_null)
1228  {
1229  int natts = relation->rd_att->natts;
1230 
1231  for (i = 1; i <= natts; i++)
1232  {
1233  Form_pg_attribute att = TupleDescAttr(relation->rd_att, i - 1);
1234 
1235  if (att->attnotnull && !att->attisdropped)
1236  {
1237  NullTest *ntest = makeNode(NullTest);
1238 
1239  ntest->arg = (Expr *) makeVar(varno,
1240  i,
1241  att->atttypid,
1242  att->atttypmod,
1243  att->attcollation,
1244  0);
1245  ntest->nulltesttype = IS_NOT_NULL;
1246 
1247  /*
1248  * argisrow=false is correct even for a composite column,
1249  * because attnotnull does not represent a SQL-spec IS NOT
1250  * NULL test in such a case, just IS DISTINCT FROM NULL.
1251  */
1252  ntest->argisrow = false;
1253  ntest->location = -1;
1254  result = lappend(result, ntest);
1255  }
1256  }
1257  }
1258  }
1259 
1260  /* Append partition predicates, if any */
1261  pcqual = RelationGetPartitionQual(relation);
1262  if (pcqual)
1263  {
1264  /*
1265  * Run each expression through const-simplification and
1266  * canonicalization similar to check constraints.
1267  */
1268  pcqual = (List *) eval_const_expressions(root, (Node *) pcqual);
1269  pcqual = (List *) canonicalize_qual((Expr *) pcqual);
1270 
1271  /* Fix Vars to have the desired varno */
1272  if (varno != 1)
1273  ChangeVarNodes((Node *) pcqual, 1, varno, 0);
1274 
1275  result = list_concat(result, pcqual);
1276  }
1277 
1278  heap_close(relation, NoLock);
1279 
1280  return result;
1281 }
#define NIL
Definition: pg_list.h:69
void * stringToNode(char *str)
Definition: read.c:38
ConstrCheck * check
Definition: tupdesc.h:40
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
char * ccbin
Definition: tupdesc.h:31
Definition: nodes.h:513
Node * eval_const_expressions(PlannerInfo *root, Node *node)
Definition: clauses.c:2462
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:79
List * make_ands_implicit(Expr *clause)
Definition: clauses.c:381
Expr * arg
Definition: primnodes.h:1187
#define NoLock
Definition: lockdefs.h:34
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
Var * makeVar(Index varno, AttrNumber varattno, Oid vartype, int32 vartypmod, Oid varcollid, Index varlevelsup)
Definition: makefuncs.c:67
Index relid
Definition: relation.h:613
bool has_not_null
Definition: tupdesc.h:43
List * lappend(List *list, void *datum)
Definition: list.c:128
List * RelationGetPartitionQual(Relation rel)
Definition: partition.c:1508
Expr * canonicalize_qual(Expr *qual)
Definition: prepqual.c:286
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
unsigned int Index
Definition: c.h:431
TupleDesc rd_att
Definition: rel.h:115
NullTestType nulltesttype
Definition: primnodes.h:1188
#define makeNode(_type_)
Definition: nodes.h:561
TupleConstr * constr
Definition: tupdesc.h:84
int location
Definition: primnodes.h:1190
bool ccvalid
Definition: tupdesc.h:32
int i
void ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
Definition: rewriteManip.c:607
bool argisrow
Definition: primnodes.h:1189
uint16 num_check
Definition: tupdesc.h:42
Definition: pg_list.h:45

◆ get_relation_data_width()

int32 get_relation_data_width ( Oid  relid,
int32 attr_widths 
)

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

1133 {
1134  int32 result;
1135  Relation relation;
1136 
1137  /* As above, assume relation is already locked */
1138  relation = heap_open(relid, NoLock);
1139 
1140  result = get_rel_data_width(relation, attr_widths);
1141 
1142  heap_close(relation, NoLock);
1143 
1144  return result;
1145 }
#define heap_close(r, l)
Definition: heapam.h:97
signed int int32
Definition: c.h:302
static int32 get_rel_data_width(Relation rel, int32 *attr_widths)
Definition: plancat.c:1090
#define NoLock
Definition: lockdefs.h:34
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290

◆ get_relation_foreign_keys()

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

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

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

◆ get_relation_info()

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

Definition at line 106 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, BTREE_AM_OID, 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, INDOPTION_DESC, INDOPTION_NULLS_FIRST, IndexOptInfo::indpred, IndexOptInfo::indrestrictinfo, InvalidOid, IsSystemRelation(), lcons(), lfirst_oid, list_free(), makeNode, RelOptInfo::max_attr, RelOptInfo::min_attr, IndexOptInfo::ncolumns, NIL, 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, RELKIND_FOREIGN_TABLE, RELKIND_PARTITIONED_INDEX, RELKIND_PARTITIONED_TABLE, 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().

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

◆ get_relation_statistics()

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

Definition at line 1292 of file plancat.c.

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

Referenced by get_relation_info().

1293 {
1294  List *statoidlist;
1295  List *stainfos = NIL;
1296  ListCell *l;
1297 
1298  statoidlist = RelationGetStatExtList(relation);
1299 
1300  foreach(l, statoidlist)
1301  {
1302  Oid statOid = lfirst_oid(l);
1303  Form_pg_statistic_ext staForm;
1304  HeapTuple htup;
1305  Bitmapset *keys = NULL;
1306  int i;
1307 
1308  htup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(statOid));
1309  if (!htup)
1310  elog(ERROR, "cache lookup failed for statistics object %u", statOid);
1311  staForm = (Form_pg_statistic_ext) GETSTRUCT(htup);
1312 
1313  /*
1314  * First, build the array of columns covered. This is ultimately
1315  * wasted if no stats within the object have actually been built, but
1316  * it doesn't seem worth troubling over that case.
1317  */
1318  for (i = 0; i < staForm->stxkeys.dim1; i++)
1319  keys = bms_add_member(keys, staForm->stxkeys.values[i]);
1320 
1321  /* add one StatisticExtInfo for each kind built */
1323  {
1325 
1326  info->statOid = statOid;
1327  info->rel = rel;
1328  info->kind = STATS_EXT_NDISTINCT;
1329  info->keys = bms_copy(keys);
1330 
1331  stainfos = lcons(info, stainfos);
1332  }
1333 
1335  {
1337 
1338  info->statOid = statOid;
1339  info->rel = rel;
1340  info->kind = STATS_EXT_DEPENDENCIES;
1341  info->keys = bms_copy(keys);
1342 
1343  stainfos = lcons(info, stainfos);
1344  }
1345 
1346  ReleaseSysCache(htup);
1347  bms_free(keys);
1348  }
1349 
1350  list_free(statoidlist);
1351 
1352  return stainfos;
1353 }
#define NIL
Definition: pg_list.h:69
#define STATS_EXT_NDISTINCT
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
Bitmapset * bms_copy(const Bitmapset *a)
Definition: bitmapset.c:111
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:815
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:245
#define makeNode(_type_)
Definition: nodes.h:561
#define STATS_EXT_DEPENDENCIES
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:742
List * RelationGetStatExtList(Relation relation)
Definition: relcache.c:4469
Bitmapset * keys
Definition: relation.h:817
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 1798 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().

1799 {
1800  RangeTblEntry *rte = planner_rt_fetch(rti, root);
1801  Relation relation;
1802  TriggerDesc *trigDesc;
1803  bool result = false;
1804 
1805  /* Assume we already have adequate lock */
1806  relation = heap_open(rte->relid, NoLock);
1807 
1808  trigDesc = relation->trigdesc;
1809  switch (event)
1810  {
1811  case CMD_INSERT:
1812  if (trigDesc &&
1813  (trigDesc->trig_insert_after_row ||
1814  trigDesc->trig_insert_before_row))
1815  result = true;
1816  break;
1817  case CMD_UPDATE:
1818  if (trigDesc &&
1819  (trigDesc->trig_update_after_row ||
1820  trigDesc->trig_update_before_row))
1821  result = true;
1822  break;
1823  case CMD_DELETE:
1824  if (trigDesc &&
1825  (trigDesc->trig_delete_after_row ||
1826  trigDesc->trig_delete_before_row))
1827  result = true;
1828  break;
1829  default:
1830  elog(ERROR, "unrecognized CmdType: %d", (int) event);
1831  break;
1832  }
1833 
1834  heap_close(relation, NoLock);
1835  return result;
1836 }
#define heap_close(r, l)
Definition: heapam.h:97
#define planner_rt_fetch(rti, root)
Definition: relation.h:328
#define ERROR
Definition: elog.h:43
TriggerDesc * trigdesc
Definition: rel.h:120
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:1290
#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 1766 of file plancat.c.

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

Referenced by examine_variable().

1767 {
1768  ListCell *ilist;
1769 
1770  foreach(ilist, rel->indexlist)
1771  {
1772  IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
1773 
1774  /*
1775  * Note: ignore partial indexes, since they don't allow us to conclude
1776  * that all attr values are distinct, *unless* they are marked predOK
1777  * which means we know the index's predicate is satisfied by the
1778  * query. We don't take any interest in expressional indexes either.
1779  * Also, a multicolumn unique index doesn't allow us to conclude that
1780  * just the specified attr is unique.
1781  */
1782  if (index->unique &&
1783  index->ncolumns == 1 &&
1784  index->indexkeys[0] == attno &&
1785  (index->indpred == NIL || index->predOK))
1786  return true;
1787  }
1788  return false;
1789 }
#define NIL
Definition: pg_list.h:69
bool predOK
Definition: relation.h:756
bool unique
Definition: relation.h:757
Definition: type.h:89
int ncolumns
Definition: relation.h:733
List * indexlist
Definition: relation.h:622
#define lfirst(lc)
Definition: pg_list.h:106
int * indexkeys
Definition: relation.h:734
List * indpred
Definition: relation.h:746

◆ infer_arbiter_indexes()

List* infer_arbiter_indexes ( PlannerInfo root)

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

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

◆ infer_collation_opclass_match()

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

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

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

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

Referenced by clause_selectivity(), and rowcomparesel().

1728 {
1729  RegProcedure oprjoin = get_oprjoin(operatorid);
1730  float8 result;
1731 
1732  /*
1733  * if the oprjoin procedure is missing for whatever reason, use a
1734  * selectivity of 0.5
1735  */
1736  if (!oprjoin)
1737  return (Selectivity) 0.5;
1738 
1739  result = DatumGetFloat8(OidFunctionCall5Coll(oprjoin,
1740  inputcollid,
1741  PointerGetDatum(root),
1742  ObjectIdGetDatum(operatorid),
1743  PointerGetDatum(args),
1744  Int16GetDatum(jointype),
1745  PointerGetDatum(sjinfo)));
1746 
1747  if (result < 0.0 || result > 1.0)
1748  elog(ERROR, "invalid join selectivity: %f", result);
1749 
1750  return (Selectivity) result;
1751 }
RegProcedure get_oprjoin(Oid opno)
Definition: lsyscache.c:1370
#define PointerGetDatum(X)
Definition: postgres.h:539
regproc RegProcedure
Definition: c.h:461
#define Int16GetDatum(X)
Definition: postgres.h:434
double Selectivity
Definition: nodes.h:643
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
double float8
Definition: c.h:447
#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:1420
#define elog
Definition: elog.h:219

◆ relation_excluded_by_constraints()

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

Definition at line 1367 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, RELKIND_PARTITIONED_TABLE, 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().

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

◆ restriction_selectivity()

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

Definition at line 1685 of file plancat.c.

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

Referenced by clause_selectivity(), and rowcomparesel().

1690 {
1691  RegProcedure oprrest = get_oprrest(operatorid);
1692  float8 result;
1693 
1694  /*
1695  * if the oprrest procedure is missing for whatever reason, use a
1696  * selectivity of 0.5
1697  */
1698  if (!oprrest)
1699  return (Selectivity) 0.5;
1700 
1701  result = DatumGetFloat8(OidFunctionCall4Coll(oprrest,
1702  inputcollid,
1703  PointerGetDatum(root),
1704  ObjectIdGetDatum(operatorid),
1705  PointerGetDatum(args),
1706  Int32GetDatum(varRelid)));
1707 
1708  if (result < 0.0 || result > 1.0)
1709  elog(ERROR, "invalid restriction selectivity: %f", result);
1710 
1711  return (Selectivity) result;
1712 }
#define PointerGetDatum(X)
Definition: postgres.h:539
regproc RegProcedure
Definition: c.h:461
double Selectivity
Definition: nodes.h:643
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
double float8
Definition: c.h:447
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:1390
#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 1955 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().

1957 {
1958  PartitionKey partkey = RelationGetPartitionKey(relation);
1959  int partnatts;
1960  int cnt;
1961  List **partexprs;
1962  ListCell *lc;
1963  Index varno = rel->relid;
1964 
1965  Assert(IS_SIMPLE_REL(rel) && rel->relid > 0);
1966 
1967  /* A partitioned table should have a partition key. */
1968  Assert(partkey != NULL);
1969 
1970  partnatts = partkey->partnatts;
1971  partexprs = (List **) palloc(sizeof(List *) * partnatts);
1972  lc = list_head(partkey->partexprs);
1973 
1974  for (cnt = 0; cnt < partnatts; cnt++)
1975  {
1976  Expr *partexpr;
1977  AttrNumber attno = partkey->partattrs[cnt];
1978 
1979  if (attno != InvalidAttrNumber)
1980  {
1981  /* Single column partition key is stored as a Var node. */
1982  Assert(attno > 0);
1983 
1984  partexpr = (Expr *) makeVar(varno, attno,
1985  partkey->parttypid[cnt],
1986  partkey->parttypmod[cnt],
1987  partkey->parttypcoll[cnt], 0);
1988  }
1989  else
1990  {
1991  if (lc == NULL)
1992  elog(ERROR, "wrong number of partition key expressions");
1993 
1994  /* Re-stamp the expression with given varno. */
1995  partexpr = (Expr *) copyObject(lfirst(lc));
1996  ChangeVarNodes((Node *) partexpr, 1, varno, 0);
1997  lc = lnext(lc);
1998  }
1999 
2000  partexprs[cnt] = list_make1(partexpr);
2001  }
2002 
2003  rel->partexprs = partexprs;
2004 
2005  /*
2006  * A base relation can not have nullable partition key expressions. We
2007  * still allocate array of empty expressions lists to keep partition key
2008  * expression handling code simple. See build_joinrel_partition_info() and
2009  * match_expr_to_partition_keys().
2010  */
2011  rel->nullable_partexprs = (List **) palloc0(sizeof(List *) * partnatts);
2012 }
Definition: nodes.h:513
List * partexprs
Definition: rel.h:58
List ** nullable_partexprs
Definition: relation.h:663
#define IS_SIMPLE_REL(rel)
Definition: relation.h:561
#define list_make1(x1)
Definition: pg_list.h:139
Oid * parttypcoll
Definition: rel.h:74
List ** partexprs
Definition: relation.h:662
#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
Oid * parttypid
Definition: rel.h:69
Index relid
Definition: relation.h:613
void * palloc0(Size size)
Definition: mcxt.c:864
AttrNumber * partattrs
Definition: rel.h:56
int16 partnatts
Definition: rel.h:55
unsigned int Index
Definition: c.h:431
int32 * parttypmod
Definition: rel.h:70
#define Assert(condition)
Definition: c.h:688
#define lfirst(lc)
Definition: pg_list.h:106
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
#define InvalidAttrNumber
Definition: attnum.h:23
void * palloc(Size size)
Definition: mcxt.c:835
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:626
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 1844 of file plancat.c.

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

Referenced by get_relation_info().

1846 {
1847  PartitionDesc partdesc;
1848  PartitionKey partkey;
1849 
1850  Assert(relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
1851 
1852  partdesc = RelationGetPartitionDesc(relation);
1853  partkey = RelationGetPartitionKey(relation);
1854  rel->part_scheme = find_partition_scheme(root, relation);
1855  Assert(partdesc != NULL && rel->part_scheme != NULL);
1856  rel->boundinfo = partition_bounds_copy(partdesc->boundinfo, partkey);
1857  rel->nparts = partdesc->nparts;
1858  set_baserel_partition_key_exprs(relation, rel);
1859 }
Form_pg_class rd_rel
Definition: rel.h:114
PartitionBoundInfo boundinfo
Definition: partition.h:40
int nparts
Definition: relation.h:658
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
struct PartitionBoundInfoData * boundinfo
Definition: relation.h:659
static PartitionScheme find_partition_scheme(PlannerInfo *root, Relation rel)
Definition: plancat.c:1867
#define Assert(condition)
Definition: c.h:688
#define RelationGetPartitionKey(relation)
Definition: rel.h:593
PartitionScheme part_scheme
Definition: relation.h:657
static void set_baserel_partition_key_exprs(Relation relation, RelOptInfo *rel)
Definition: plancat.c:1955
PartitionBoundInfo partition_bounds_copy(PartitionBoundInfo src, PartitionKey key)
Definition: partition.c:860
#define RelationGetPartitionDesc(relation)
Definition: rel.h:641

Variable Documentation

◆ constraint_exclusion

int constraint_exclusion = CONSTRAINT_EXCLUSION_PARTITION

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

Referenced by get_relation_info().