PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
dependencies.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_statistic_ext.h"
#include "catalog/pg_statistic_ext_data.h"
#include "lib/stringinfo.h"
#include "nodes/nodeFuncs.h"
#include "nodes/nodes.h"
#include "nodes/pathnodes.h"
#include "optimizer/clauses.h"
#include "optimizer/optimizer.h"
#include "parser/parsetree.h"
#include "statistics/extended_stats_internal.h"
#include "statistics/statistics.h"
#include "utils/fmgroids.h"
#include "utils/fmgrprotos.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/selfuncs.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
#include "varatt.h"
Include dependency graph for dependencies.c:

Go to the source code of this file.

Data Structures

struct  DependencyGeneratorData
 

Macros

#define SizeOfHeader   (3 * sizeof(uint32))
 
#define SizeOfItem(natts)    (sizeof(double) + sizeof(AttrNumber) * (1 + (natts)))
 
#define MinSizeOfItem   SizeOfItem(2)
 
#define MinSizeOfItems(ndeps)    (SizeOfHeader + (ndeps) * MinSizeOfItem)
 

Typedefs

typedef struct DependencyGeneratorData DependencyGeneratorData
 
typedef DependencyGeneratorDataDependencyGenerator
 

Functions

static void generate_dependencies_recurse (DependencyGenerator state, int index, AttrNumber start, AttrNumber *current)
 
static void generate_dependencies (DependencyGenerator state)
 
static DependencyGenerator DependencyGenerator_init (int n, int k)
 
static void DependencyGenerator_free (DependencyGenerator state)
 
static AttrNumberDependencyGenerator_next (DependencyGenerator state)
 
static double dependency_degree (StatsBuildData *data, int k, AttrNumber *dependency)
 
static bool dependency_is_fully_matched (MVDependency *dependency, Bitmapset *attnums)
 
static bool dependency_is_compatible_clause (Node *clause, Index relid, AttrNumber *attnum)
 
static bool dependency_is_compatible_expression (Node *clause, Index relid, List *statlist, Node **expr)
 
static MVDependencyfind_strongest_dependency (MVDependencies **dependencies, int ndependencies, Bitmapset *attnums)
 
static Selectivity clauselist_apply_dependencies (PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, MVDependency **dependencies, int ndependencies, AttrNumber *list_attnums, Bitmapset **estimatedclauses)
 
MVDependenciesstatext_dependencies_build (StatsBuildData *data)
 
byteastatext_dependencies_serialize (MVDependencies *dependencies)
 
MVDependenciesstatext_dependencies_deserialize (bytea *data)
 
MVDependenciesstatext_dependencies_load (Oid mvoid, bool inh)
 
Datum pg_dependencies_in (PG_FUNCTION_ARGS)
 
Datum pg_dependencies_out (PG_FUNCTION_ARGS)
 
Datum pg_dependencies_recv (PG_FUNCTION_ARGS)
 
Datum pg_dependencies_send (PG_FUNCTION_ARGS)
 
Selectivity dependencies_clauselist_selectivity (PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses)
 

Macro Definition Documentation

◆ MinSizeOfItem

#define MinSizeOfItem   SizeOfItem(2)

Definition at line 45 of file dependencies.c.

◆ MinSizeOfItems

#define MinSizeOfItems (   ndeps)     (SizeOfHeader + (ndeps) * MinSizeOfItem)

Definition at line 48 of file dependencies.c.

◆ SizeOfHeader

#define SizeOfHeader   (3 * sizeof(uint32))

Definition at line 38 of file dependencies.c.

◆ SizeOfItem

#define SizeOfItem (   natts)     (sizeof(double) + sizeof(AttrNumber) * (1 + (natts)))

Definition at line 41 of file dependencies.c.

Typedef Documentation

◆ DependencyGenerator

Definition at line 65 of file dependencies.c.

◆ DependencyGeneratorData

Function Documentation

◆ clauselist_apply_dependencies()

static Selectivity clauselist_apply_dependencies ( PlannerInfo root,
List clauses,
int  varRelid,
JoinType  jointype,
SpecialJoinInfo sjinfo,
MVDependency **  dependencies,
int  ndependencies,
AttrNumber list_attnums,
Bitmapset **  estimatedclauses 
)
static

Definition at line 1014 of file dependencies.c.

1020{
1021 Bitmapset *attnums;
1022 int i;
1023 int j;
1024 int nattrs;
1025 Selectivity *attr_sel;
1026 int attidx;
1027 int listidx;
1028 ListCell *l;
1030
1031 /*
1032 * Extract the attnums of all implying and implied attributes from all the
1033 * given dependencies. Each of these attributes is expected to have at
1034 * least 1 not-already-estimated compatible clause that we will estimate
1035 * here.
1036 */
1037 attnums = NULL;
1038 for (i = 0; i < ndependencies; i++)
1039 {
1040 for (j = 0; j < dependencies[i]->nattributes; j++)
1041 {
1042 AttrNumber attnum = dependencies[i]->attributes[j];
1043
1044 attnums = bms_add_member(attnums, attnum);
1045 }
1046 }
1047
1048 /*
1049 * Compute per-column selectivity estimates for each of these attributes,
1050 * and mark all the corresponding clauses as estimated.
1051 */
1052 nattrs = bms_num_members(attnums);
1053 attr_sel = (Selectivity *) palloc(sizeof(Selectivity) * nattrs);
1054
1055 attidx = 0;
1056 i = -1;
1057 while ((i = bms_next_member(attnums, i)) >= 0)
1058 {
1059 List *attr_clauses = NIL;
1060 Selectivity simple_sel;
1061
1062 listidx = -1;
1063 foreach(l, clauses)
1064 {
1065 Node *clause = (Node *) lfirst(l);
1066
1067 listidx++;
1068 if (list_attnums[listidx] == i)
1069 {
1070 attr_clauses = lappend(attr_clauses, clause);
1071 *estimatedclauses = bms_add_member(*estimatedclauses, listidx);
1072 }
1073 }
1074
1075 simple_sel = clauselist_selectivity_ext(root, attr_clauses, varRelid,
1076 jointype, sjinfo, false);
1077 attr_sel[attidx++] = simple_sel;
1078 }
1079
1080 /*
1081 * Now combine these selectivities using the dependency information. For
1082 * chains of dependencies such as a -> b -> c, the b -> c dependency will
1083 * come before the a -> b dependency in the array, so we traverse the
1084 * array backwards to ensure such chains are computed in the right order.
1085 *
1086 * As explained above, pairs of selectivities are combined using the
1087 * formula
1088 *
1089 * P(a,b) = f * Min(P(a), P(b)) + (1-f) * P(a) * P(b)
1090 *
1091 * to ensure that the combined selectivity is never greater than either
1092 * individual selectivity.
1093 *
1094 * Where multiple dependencies apply (e.g., a -> b -> c), we use
1095 * conditional probabilities to compute the overall result as follows:
1096 *
1097 * P(a,b,c) = P(c|a,b) * P(a,b) = P(c|a,b) * P(b|a) * P(a)
1098 *
1099 * so we replace the selectivities of all implied attributes with
1100 * conditional probabilities, that are conditional on all their implying
1101 * attributes. The selectivities of all other non-implied attributes are
1102 * left as they are.
1103 */
1104 for (i = ndependencies - 1; i >= 0; i--)
1105 {
1106 MVDependency *dependency = dependencies[i];
1109 double f;
1110
1111 /* Selectivity of all the implying attributes */
1112 s1 = 1.0;
1113 for (j = 0; j < dependency->nattributes - 1; j++)
1114 {
1115 attnum = dependency->attributes[j];
1116 attidx = bms_member_index(attnums, attnum);
1117 s1 *= attr_sel[attidx];
1118 }
1119
1120 /* Original selectivity of the implied attribute */
1121 attnum = dependency->attributes[j];
1122 attidx = bms_member_index(attnums, attnum);
1123 s2 = attr_sel[attidx];
1124
1125 /*
1126 * Replace s2 with the conditional probability s2 given s1, computed
1127 * using the formula P(b|a) = P(a,b) / P(a), which simplifies to
1128 *
1129 * P(b|a) = f * Min(P(a), P(b)) / P(a) + (1-f) * P(b)
1130 *
1131 * where P(a) = s1, the selectivity of the implying attributes, and
1132 * P(b) = s2, the selectivity of the implied attribute.
1133 */
1134 f = dependency->degree;
1135
1136 if (s1 <= s2)
1137 attr_sel[attidx] = f + (1 - f) * s2;
1138 else
1139 attr_sel[attidx] = f * s2 / s1 + (1 - f) * s2;
1140 }
1141
1142 /*
1143 * The overall selectivity of all the clauses on all these attributes is
1144 * then the product of all the original (non-implied) probabilities and
1145 * the new conditional (implied) probabilities.
1146 */
1147 s1 = 1.0;
1148 for (i = 0; i < nattrs; i++)
1149 s1 *= attr_sel[i];
1150
1152
1153 pfree(attr_sel);
1154 bms_free(attnums);
1155
1156 return s1;
1157}
int16 AttrNumber
Definition: attnum.h:21
int bms_next_member(const Bitmapset *a, int prevbit)
Definition: bitmapset.c:1306
void bms_free(Bitmapset *a)
Definition: bitmapset.c:239
int bms_num_members(const Bitmapset *a)
Definition: bitmapset.c:751
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
int bms_member_index(Bitmapset *a, int x)
Definition: bitmapset.c:539
Selectivity clauselist_selectivity_ext(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, bool use_extended_stats)
Definition: clausesel.c:117
int j
Definition: isn.c:73
int i
Definition: isn.c:72
List * lappend(List *list, void *datum)
Definition: list.c:339
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
double Selectivity
Definition: nodes.h:250
int16 attnum
Definition: pg_attribute.h:74
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
char * s1
char * s2
tree ctl root
Definition: radixtree.h:1857
#define CLAMP_PROBABILITY(p)
Definition: selfuncs.h:63
Definition: pg_list.h:54
AttrNumber nattributes
Definition: statistics.h:53
double degree
Definition: statistics.h:52
AttrNumber attributes[FLEXIBLE_ARRAY_MEMBER]
Definition: statistics.h:54
Definition: nodes.h:129

References attnum, MVDependency::attributes, bms_add_member(), bms_free(), bms_member_index(), bms_next_member(), bms_num_members(), CLAMP_PROBABILITY, clauselist_selectivity_ext(), MVDependency::degree, i, j, lappend(), lfirst, MVDependency::nattributes, NIL, palloc(), pfree(), root, s1, and s2.

Referenced by dependencies_clauselist_selectivity().

◆ dependencies_clauselist_selectivity()

Selectivity dependencies_clauselist_selectivity ( PlannerInfo root,
List clauses,
int  varRelid,
JoinType  jointype,
SpecialJoinInfo sjinfo,
RelOptInfo rel,
Bitmapset **  estimatedclauses 
)

Definition at line 1370 of file dependencies.c.

1377{
1378 Selectivity s1 = 1.0;
1379 ListCell *l;
1380 Bitmapset *clauses_attnums = NULL;
1381 AttrNumber *list_attnums;
1382 int listidx;
1383 MVDependencies **func_dependencies;
1384 int nfunc_dependencies;
1385 int total_ndeps;
1386 MVDependency **dependencies;
1387 int ndependencies;
1388 int i;
1389 AttrNumber attnum_offset;
1391
1392 /* unique expressions */
1393 Node **unique_exprs;
1394 int unique_exprs_cnt;
1395
1396 /* check if there's any stats that might be useful for us. */
1397 if (!has_stats_of_kind(rel->statlist, STATS_EXT_DEPENDENCIES))
1398 return 1.0;
1399
1400 list_attnums = (AttrNumber *) palloc(sizeof(AttrNumber) *
1401 list_length(clauses));
1402
1403 /*
1404 * We allocate space as if every clause was a unique expression, although
1405 * that's probably overkill. Some will be simple column references that
1406 * we'll translate to attnums, and there might be duplicates. But it's
1407 * easier and cheaper to just do one allocation than repalloc later.
1408 */
1409 unique_exprs = (Node **) palloc(sizeof(Node *) * list_length(clauses));
1410 unique_exprs_cnt = 0;
1411
1412 /*
1413 * Pre-process the clauses list to extract the attnums seen in each item.
1414 * We need to determine if there's any clauses which will be useful for
1415 * dependency selectivity estimations. Along the way we'll record all of
1416 * the attnums for each clause in a list which we'll reference later so we
1417 * don't need to repeat the same work again. We'll also keep track of all
1418 * attnums seen.
1419 *
1420 * We also skip clauses that we already estimated using different types of
1421 * statistics (we treat them as incompatible).
1422 *
1423 * To handle expressions, we assign them negative attnums, as if it was a
1424 * system attribute (this is fine, as we only allow extended stats on user
1425 * attributes). And then we offset everything by the number of
1426 * expressions, so that we can store the values in a bitmapset.
1427 */
1428 listidx = 0;
1429 foreach(l, clauses)
1430 {
1431 Node *clause = (Node *) lfirst(l);
1433 Node *expr = NULL;
1434
1435 /* ignore clause by default */
1436 list_attnums[listidx] = InvalidAttrNumber;
1437
1438 if (!bms_is_member(listidx, *estimatedclauses))
1439 {
1440 /*
1441 * If it's a simple column reference, just extract the attnum. If
1442 * it's an expression, assign a negative attnum as if it was a
1443 * system attribute.
1444 */
1445 if (dependency_is_compatible_clause(clause, rel->relid, &attnum))
1446 {
1447 list_attnums[listidx] = attnum;
1448 }
1449 else if (dependency_is_compatible_expression(clause, rel->relid,
1450 rel->statlist,
1451 &expr))
1452 {
1453 /* special attnum assigned to this expression */
1455
1456 Assert(expr != NULL);
1457
1458 /* If the expression is duplicate, use the same attnum. */
1459 for (i = 0; i < unique_exprs_cnt; i++)
1460 {
1461 if (equal(unique_exprs[i], expr))
1462 {
1463 /* negative attribute number to expression */
1464 attnum = -(i + 1);
1465 break;
1466 }
1467 }
1468
1469 /* not found in the list, so add it */
1471 {
1472 unique_exprs[unique_exprs_cnt++] = expr;
1473
1474 /* after incrementing the value, to get -1, -2, ... */
1475 attnum = (-unique_exprs_cnt);
1476 }
1477
1478 /* remember which attnum was assigned to this clause */
1479 list_attnums[listidx] = attnum;
1480 }
1481 }
1482
1483 listidx++;
1484 }
1485
1486 Assert(listidx == list_length(clauses));
1487
1488 /*
1489 * How much we need to offset the attnums? If there are no expressions,
1490 * then no offset is needed. Otherwise we need to offset enough for the
1491 * lowest value (-unique_exprs_cnt) to become 1.
1492 */
1493 if (unique_exprs_cnt > 0)
1494 attnum_offset = (unique_exprs_cnt + 1);
1495 else
1496 attnum_offset = 0;
1497
1498 /*
1499 * Now that we know how many expressions there are, we can offset the
1500 * values just enough to build the bitmapset.
1501 */
1502 for (i = 0; i < list_length(clauses); i++)
1503 {
1505
1506 /* ignore incompatible or already estimated clauses */
1507 if (list_attnums[i] == InvalidAttrNumber)
1508 continue;
1509
1510 /* make sure the attnum is in the expected range */
1511 Assert(list_attnums[i] >= (-unique_exprs_cnt));
1512 Assert(list_attnums[i] <= MaxHeapAttributeNumber);
1513
1514 /* make sure the attnum is positive (valid AttrNumber) */
1515 attnum = list_attnums[i] + attnum_offset;
1516
1517 /*
1518 * Either it's a regular attribute, or it's an expression, in which
1519 * case we must not have seen it before (expressions are unique).
1520 *
1521 * XXX Check whether it's a regular attribute has to be done using the
1522 * original attnum, while the second check has to use the value with
1523 * an offset.
1524 */
1525 Assert(AttrNumberIsForUserDefinedAttr(list_attnums[i]) ||
1526 !bms_is_member(attnum, clauses_attnums));
1527
1528 /*
1529 * Remember the offset attnum, both for attributes and expressions.
1530 * We'll pass list_attnums to clauselist_apply_dependencies, which
1531 * uses it to identify clauses in a bitmap. We could also pass the
1532 * offset, but this is more convenient.
1533 */
1534 list_attnums[i] = attnum;
1535
1536 clauses_attnums = bms_add_member(clauses_attnums, attnum);
1537 }
1538
1539 /*
1540 * If there's not at least two distinct attnums and expressions, then
1541 * reject the whole list of clauses. We must return 1.0 so the calling
1542 * function's selectivity is unaffected.
1543 */
1544 if (bms_membership(clauses_attnums) != BMS_MULTIPLE)
1545 {
1546 bms_free(clauses_attnums);
1547 pfree(list_attnums);
1548 return 1.0;
1549 }
1550
1551 /*
1552 * Load all functional dependencies matching at least two parameters. We
1553 * can simply consider all dependencies at once, without having to search
1554 * for the best statistics object.
1555 *
1556 * To not waste cycles and memory, we deserialize dependencies only for
1557 * statistics that match at least two attributes. The array is allocated
1558 * with the assumption that all objects match - we could grow the array to
1559 * make it just the right size, but it's likely wasteful anyway thanks to
1560 * moving the freed chunks to freelists etc.
1561 */
1562 func_dependencies = (MVDependencies **) palloc(sizeof(MVDependencies *) *
1563 list_length(rel->statlist));
1564 nfunc_dependencies = 0;
1565 total_ndeps = 0;
1566
1567 foreach(l, rel->statlist)
1568 {
1570 int nmatched;
1571 int nexprs;
1572 int k;
1573 MVDependencies *deps;
1574
1575 /* skip statistics that are not of the correct type */
1576 if (stat->kind != STATS_EXT_DEPENDENCIES)
1577 continue;
1578
1579 /* skip statistics with mismatching stxdinherit value */
1580 if (stat->inherit != rte->inh)
1581 continue;
1582
1583 /*
1584 * Count matching attributes - we have to undo the attnum offsets. The
1585 * input attribute numbers are not offset (expressions are not
1586 * included in stat->keys, so it's not necessary). But we need to
1587 * offset it before checking against clauses_attnums.
1588 */
1589 nmatched = 0;
1590 k = -1;
1591 while ((k = bms_next_member(stat->keys, k)) >= 0)
1592 {
1594
1595 /* skip expressions */
1597 continue;
1598
1599 /* apply the same offset as above */
1600 attnum += attnum_offset;
1601
1602 if (bms_is_member(attnum, clauses_attnums))
1603 nmatched++;
1604 }
1605
1606 /* count matching expressions */
1607 nexprs = 0;
1608 for (i = 0; i < unique_exprs_cnt; i++)
1609 {
1610 ListCell *lc;
1611
1612 foreach(lc, stat->exprs)
1613 {
1614 Node *stat_expr = (Node *) lfirst(lc);
1615
1616 /* try to match it */
1617 if (equal(stat_expr, unique_exprs[i]))
1618 nexprs++;
1619 }
1620 }
1621
1622 /*
1623 * Skip objects matching fewer than two attributes/expressions from
1624 * clauses.
1625 */
1626 if (nmatched + nexprs < 2)
1627 continue;
1628
1629 deps = statext_dependencies_load(stat->statOid, rte->inh);
1630
1631 /*
1632 * The expressions may be represented by different attnums in the
1633 * stats, we need to remap them to be consistent with the clauses.
1634 * That will make the later steps (e.g. picking the strongest item and
1635 * so on) much simpler and cheaper, because it won't need to care
1636 * about the offset at all.
1637 *
1638 * When we're at it, we can ignore dependencies that are not fully
1639 * matched by clauses (i.e. referencing attributes or expressions that
1640 * are not in the clauses).
1641 *
1642 * We have to do this for all statistics, as long as there are any
1643 * expressions - we need to shift the attnums in all dependencies.
1644 *
1645 * XXX Maybe we should do this always, because it also eliminates some
1646 * of the dependencies early. It might be cheaper than having to walk
1647 * the longer list in find_strongest_dependency later, especially as
1648 * we need to do that repeatedly?
1649 *
1650 * XXX We have to do this even when there are no expressions in
1651 * clauses, otherwise find_strongest_dependency may fail for stats
1652 * with expressions (due to lookup of negative value in bitmap). So we
1653 * need to at least filter out those dependencies. Maybe we could do
1654 * it in a cheaper way (if there are no expr clauses, we can just
1655 * discard all negative attnums without any lookups).
1656 */
1657 if (unique_exprs_cnt > 0 || stat->exprs != NIL)
1658 {
1659 int ndeps = 0;
1660
1661 for (i = 0; i < deps->ndeps; i++)
1662 {
1663 bool skip = false;
1664 MVDependency *dep = deps->deps[i];
1665 int j;
1666
1667 for (j = 0; j < dep->nattributes; j++)
1668 {
1669 int idx;
1670 Node *expr;
1671 AttrNumber unique_attnum = InvalidAttrNumber;
1673
1674 /* undo the per-statistics offset */
1675 attnum = dep->attributes[j];
1676
1677 /*
1678 * For regular attributes we can simply check if it
1679 * matches any clause. If there's no matching clause, we
1680 * can just ignore it. We need to offset the attnum
1681 * though.
1682 */
1684 {
1685 dep->attributes[j] = attnum + attnum_offset;
1686
1687 if (!bms_is_member(dep->attributes[j], clauses_attnums))
1688 {
1689 skip = true;
1690 break;
1691 }
1692
1693 continue;
1694 }
1695
1696 /*
1697 * the attnum should be a valid system attnum (-1, -2,
1698 * ...)
1699 */
1701
1702 /*
1703 * For expressions, we need to do two translations. First
1704 * we have to translate the negative attnum to index in
1705 * the list of expressions (in the statistics object).
1706 * Then we need to see if there's a matching clause. The
1707 * index of the unique expression determines the attnum
1708 * (and we offset it).
1709 */
1710 idx = -(1 + attnum);
1711
1712 /* Is the expression index is valid? */
1713 Assert((idx >= 0) && (idx < list_length(stat->exprs)));
1714
1715 expr = (Node *) list_nth(stat->exprs, idx);
1716
1717 /* try to find the expression in the unique list */
1718 for (int m = 0; m < unique_exprs_cnt; m++)
1719 {
1720 /*
1721 * found a matching unique expression, use the attnum
1722 * (derived from index of the unique expression)
1723 */
1724 if (equal(unique_exprs[m], expr))
1725 {
1726 unique_attnum = -(m + 1) + attnum_offset;
1727 break;
1728 }
1729 }
1730
1731 /*
1732 * Found no matching expression, so we can simply skip
1733 * this dependency, because there's no chance it will be
1734 * fully covered.
1735 */
1736 if (unique_attnum == InvalidAttrNumber)
1737 {
1738 skip = true;
1739 break;
1740 }
1741
1742 /* otherwise remap it to the new attnum */
1743 dep->attributes[j] = unique_attnum;
1744 }
1745
1746 /* if found a matching dependency, keep it */
1747 if (!skip)
1748 {
1749 /* maybe we've skipped something earlier, so move it */
1750 if (ndeps != i)
1751 deps->deps[ndeps] = deps->deps[i];
1752
1753 ndeps++;
1754 }
1755 }
1756
1757 deps->ndeps = ndeps;
1758 }
1759
1760 /*
1761 * It's possible we've removed all dependencies, in which case we
1762 * don't bother adding it to the list.
1763 */
1764 if (deps->ndeps > 0)
1765 {
1766 func_dependencies[nfunc_dependencies] = deps;
1767 total_ndeps += deps->ndeps;
1768 nfunc_dependencies++;
1769 }
1770 }
1771
1772 /* if no matching stats could be found then we've nothing to do */
1773 if (nfunc_dependencies == 0)
1774 {
1775 pfree(func_dependencies);
1776 bms_free(clauses_attnums);
1777 pfree(list_attnums);
1778 pfree(unique_exprs);
1779 return 1.0;
1780 }
1781
1782 /*
1783 * Work out which dependencies we can apply, starting with the
1784 * widest/strongest ones, and proceeding to smaller/weaker ones.
1785 */
1786 dependencies = (MVDependency **) palloc(sizeof(MVDependency *) *
1787 total_ndeps);
1788 ndependencies = 0;
1789
1790 while (true)
1791 {
1792 MVDependency *dependency;
1794
1795 /* the widest/strongest dependency, fully matched by clauses */
1796 dependency = find_strongest_dependency(func_dependencies,
1797 nfunc_dependencies,
1798 clauses_attnums);
1799 if (!dependency)
1800 break;
1801
1802 dependencies[ndependencies++] = dependency;
1803
1804 /* Ignore dependencies using this implied attribute in later loops */
1805 attnum = dependency->attributes[dependency->nattributes - 1];
1806 clauses_attnums = bms_del_member(clauses_attnums, attnum);
1807 }
1808
1809 /*
1810 * If we found applicable dependencies, use them to estimate all
1811 * compatible clauses on attributes that they refer to.
1812 */
1813 if (ndependencies != 0)
1814 s1 = clauselist_apply_dependencies(root, clauses, varRelid, jointype,
1815 sjinfo, dependencies, ndependencies,
1816 list_attnums, estimatedclauses);
1817
1818 /* free deserialized functional dependencies (and then the array) */
1819 for (i = 0; i < nfunc_dependencies; i++)
1820 pfree(func_dependencies[i]);
1821
1822 pfree(dependencies);
1823 pfree(func_dependencies);
1824 bms_free(clauses_attnums);
1825 pfree(list_attnums);
1826 pfree(unique_exprs);
1827
1828 return s1;
1829}
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
#define AttrNumberIsForUserDefinedAttr(attributeNumber)
Definition: attnum.h:41
#define InvalidAttrNumber
Definition: attnum.h:23
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition: bitmapset.c:868
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
BMS_Membership bms_membership(const Bitmapset *a)
Definition: bitmapset.c:781
@ BMS_MULTIPLE
Definition: bitmapset.h:73
#define Assert(condition)
Definition: c.h:812
MVDependencies * statext_dependencies_load(Oid mvoid, bool inh)
Definition: dependencies.c:619
static bool dependency_is_compatible_expression(Node *clause, Index relid, List *statlist, Node **expr)
static bool dependency_is_compatible_clause(Node *clause, Index relid, AttrNumber *attnum)
Definition: dependencies.c:741
static Selectivity clauselist_apply_dependencies(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, MVDependency **dependencies, int ndependencies, AttrNumber *list_attnums, Bitmapset **estimatedclauses)
static MVDependency * find_strongest_dependency(MVDependencies **dependencies, int ndependencies, Bitmapset *attnums)
Definition: dependencies.c:929
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
bool has_stats_of_kind(List *stats, char requiredkind)
#define MaxHeapAttributeNumber
Definition: htup_details.h:48
#define planner_rt_fetch(rti, root)
Definition: pathnodes.h:570
static const struct exclude_list_item skip[]
Definition: pg_checksums.c:107
static int list_length(const List *l)
Definition: pg_list.h:152
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
uint32 ndeps
Definition: statistics.h:61
MVDependency * deps[FLEXIBLE_ARRAY_MEMBER]
Definition: statistics.h:62
Index relid
Definition: pathnodes.h:918
List * statlist
Definition: pathnodes.h:946

References Assert, attnum, AttributeNumberIsValid, MVDependency::attributes, AttrNumberIsForUserDefinedAttr, bms_add_member(), bms_del_member(), bms_free(), bms_is_member(), bms_membership(), BMS_MULTIPLE, bms_next_member(), clauselist_apply_dependencies(), dependency_is_compatible_clause(), dependency_is_compatible_expression(), MVDependencies::deps, equal(), find_strongest_dependency(), has_stats_of_kind(), i, idx(), RangeTblEntry::inh, InvalidAttrNumber, j, lfirst, list_length(), list_nth(), MaxHeapAttributeNumber, MVDependency::nattributes, MVDependencies::ndeps, NIL, palloc(), pfree(), planner_rt_fetch, RelOptInfo::relid, root, s1, skip, statext_dependencies_load(), and RelOptInfo::statlist.

Referenced by statext_clauselist_selectivity().

◆ dependency_degree()

static double dependency_degree ( StatsBuildData data,
int  k,
AttrNumber dependency 
)
static

Definition at line 221 of file dependencies.c.

222{
223 int i,
224 nitems;
227 AttrNumber *attnums_dep;
228
229 /* counters valid within a group */
230 int group_size = 0;
231 int n_violations = 0;
232
233 /* total number of rows supporting (consistent with) the dependency */
234 int n_supporting_rows = 0;
235
236 /* Make sure we have at least two input attributes. */
237 Assert(k >= 2);
238
239 /* sort info for all attributes columns */
240 mss = multi_sort_init(k);
241
242 /*
243 * Translate the array of indexes to regular attnums for the dependency
244 * (we will need this to identify the columns in StatsBuildData).
245 */
246 attnums_dep = (AttrNumber *) palloc(k * sizeof(AttrNumber));
247 for (i = 0; i < k; i++)
248 attnums_dep[i] = data->attnums[dependency[i]];
249
250 /*
251 * Verify the dependency (a,b,...)->z, using a rather simple algorithm:
252 *
253 * (a) sort the data lexicographically
254 *
255 * (b) split the data into groups by first (k-1) columns
256 *
257 * (c) for each group count different values in the last column
258 *
259 * We use the column data types' default sort operators and collations;
260 * perhaps at some point it'd be worth using column-specific collations?
261 */
262
263 /* prepare the sort function for the dimensions */
264 for (i = 0; i < k; i++)
265 {
266 VacAttrStats *colstat = data->stats[dependency[i]];
268
270 if (type->lt_opr == InvalidOid) /* shouldn't happen */
271 elog(ERROR, "cache lookup failed for ordering operator for type %u",
272 colstat->attrtypid);
273
274 /* prepare the sort function for this dimension */
275 multi_sort_add_dimension(mss, i, type->lt_opr, colstat->attrcollid);
276 }
277
278 /*
279 * build an array of SortItem(s) sorted using the multi-sort support
280 *
281 * XXX This relies on all stats entries pointing to the same tuple
282 * descriptor. For now that assumption holds, but it might change in the
283 * future for example if we support statistics on multiple tables.
284 */
285 items = build_sorted_items(data, &nitems, mss, k, attnums_dep);
286
287 /*
288 * Walk through the sorted array, split it into rows according to the
289 * first (k-1) columns. If there's a single value in the last column, we
290 * count the group as 'supporting' the functional dependency. Otherwise we
291 * count it as contradicting.
292 */
293
294 /* start with the first row forming a group */
295 group_size = 1;
296
297 /* loop 1 beyond the end of the array so that we count the final group */
298 for (i = 1; i <= nitems; i++)
299 {
300 /*
301 * Check if the group ended, which may be either because we processed
302 * all the items (i==nitems), or because the i-th item is not equal to
303 * the preceding one.
304 */
305 if (i == nitems ||
306 multi_sort_compare_dims(0, k - 2, &items[i - 1], &items[i], mss) != 0)
307 {
308 /*
309 * If no violations were found in the group then track the rows of
310 * the group as supporting the functional dependency.
311 */
312 if (n_violations == 0)
313 n_supporting_rows += group_size;
314
315 /* Reset counters for the new group */
316 n_violations = 0;
317 group_size = 1;
318 continue;
319 }
320 /* first columns match, but the last one does not (so contradicting) */
321 else if (multi_sort_compare_dim(k - 1, &items[i - 1], &items[i], mss) != 0)
322 n_violations++;
323
324 group_size++;
325 }
326
327 /* Compute the 'degree of validity' as (supporting/total). */
328 return (n_supporting_rows * 1.0 / data->numrows);
329}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
int multi_sort_compare_dims(int start, int end, const SortItem *a, const SortItem *b, MultiSortSupport mss)
int multi_sort_compare_dim(int dim, const SortItem *a, const SortItem *b, MultiSortSupport mss)
SortItem * build_sorted_items(StatsBuildData *data, int *nitems, MultiSortSupport mss, int numattrs, AttrNumber *attnums)
MultiSortSupport multi_sort_init(int ndims)
void multi_sort_add_dimension(MultiSortSupport mss, int sortdim, Oid oper, Oid collation)
for(;;)
#define nitems(x)
Definition: indent.h:31
const void * data
#define InvalidOid
Definition: postgres_ext.h:36
Oid attrtypid
Definition: vacuum.h:126
Oid attrcollid
Definition: vacuum.h:129
static ItemArray items
Definition: test_tidstore.c:48
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition: typcache.c:386
#define TYPECACHE_LT_OPR
Definition: typcache.h:138
const char * type

References Assert, VacAttrStats::attrcollid, VacAttrStats::attrtypid, build_sorted_items(), data, elog, ERROR, for(), i, InvalidOid, items, lookup_type_cache(), multi_sort_add_dimension(), multi_sort_compare_dim(), multi_sort_compare_dims(), multi_sort_init(), nitems, palloc(), type, and TYPECACHE_LT_OPR.

Referenced by statext_dependencies_build().

◆ dependency_is_compatible_clause()

static bool dependency_is_compatible_clause ( Node clause,
Index  relid,
AttrNumber attnum 
)
static

Definition at line 741 of file dependencies.c.

742{
743 Var *var;
744 Node *clause_expr;
745
746 if (IsA(clause, RestrictInfo))
747 {
748 RestrictInfo *rinfo = (RestrictInfo *) clause;
749
750 /* Pseudoconstants are not interesting (they couldn't contain a Var) */
751 if (rinfo->pseudoconstant)
752 return false;
753
754 /* Clauses referencing multiple, or no, varnos are incompatible */
755 if (bms_membership(rinfo->clause_relids) != BMS_SINGLETON)
756 return false;
757
758 clause = (Node *) rinfo->clause;
759 }
760
761 if (is_opclause(clause))
762 {
763 /* If it's an opclause, check for Var = Const or Const = Var. */
764 OpExpr *expr = (OpExpr *) clause;
765
766 /* Only expressions with two arguments are candidates. */
767 if (list_length(expr->args) != 2)
768 return false;
769
770 /* Make sure non-selected argument is a pseudoconstant. */
772 clause_expr = linitial(expr->args);
773 else if (is_pseudo_constant_clause(linitial(expr->args)))
774 clause_expr = lsecond(expr->args);
775 else
776 return false;
777
778 /*
779 * If it's not an "=" operator, just ignore the clause, as it's not
780 * compatible with functional dependencies.
781 *
782 * This uses the function for estimating selectivity, not the operator
783 * directly (a bit awkward, but well ...).
784 *
785 * XXX this is pretty dubious; probably it'd be better to check btree
786 * or hash opclass membership, so as not to be fooled by custom
787 * selectivity functions, and to be more consistent with decisions
788 * elsewhere in the planner.
789 */
790 if (get_oprrest(expr->opno) != F_EQSEL)
791 return false;
792
793 /* OK to proceed with checking "var" */
794 }
795 else if (IsA(clause, ScalarArrayOpExpr))
796 {
797 /* If it's a scalar array operator, check for Var IN Const. */
798 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) clause;
799
800 /*
801 * Reject ALL() variant, we only care about ANY/IN.
802 *
803 * XXX Maybe we should check if all the values are the same, and allow
804 * ALL in that case? Doesn't seem very practical, though.
805 */
806 if (!expr->useOr)
807 return false;
808
809 /* Only expressions with two arguments are candidates. */
810 if (list_length(expr->args) != 2)
811 return false;
812
813 /*
814 * We know it's always (Var IN Const), so we assume the var is the
815 * first argument, and pseudoconstant is the second one.
816 */
818 return false;
819
820 clause_expr = linitial(expr->args);
821
822 /*
823 * If it's not an "=" operator, just ignore the clause, as it's not
824 * compatible with functional dependencies. The operator is identified
825 * simply by looking at which function it uses to estimate
826 * selectivity. That's a bit strange, but it's what other similar
827 * places do.
828 */
829 if (get_oprrest(expr->opno) != F_EQSEL)
830 return false;
831
832 /* OK to proceed with checking "var" */
833 }
834 else if (is_orclause(clause))
835 {
836 BoolExpr *bool_expr = (BoolExpr *) clause;
837 ListCell *lc;
838
839 /* start with no attribute number */
841
842 foreach(lc, bool_expr->args)
843 {
844 AttrNumber clause_attnum;
845
846 /*
847 * Had we found incompatible clause in the arguments, treat the
848 * whole clause as incompatible.
849 */
851 relid, &clause_attnum))
852 return false;
853
855 *attnum = clause_attnum;
856
857 /* ensure all the variables are the same (same attnum) */
858 if (*attnum != clause_attnum)
859 return false;
860 }
861
862 /* the Var is already checked by the recursive call */
863 return true;
864 }
865 else if (is_notclause(clause))
866 {
867 /*
868 * "NOT x" can be interpreted as "x = false", so get the argument and
869 * proceed with seeing if it's a suitable Var.
870 */
871 clause_expr = (Node *) get_notclausearg(clause);
872 }
873 else
874 {
875 /*
876 * A boolean expression "x" can be interpreted as "x = true", so
877 * proceed with seeing if it's a suitable Var.
878 */
879 clause_expr = (Node *) clause;
880 }
881
882 /*
883 * We may ignore any RelabelType node above the operand. (There won't be
884 * more than one, since eval_const_expressions has been applied already.)
885 */
886 if (IsA(clause_expr, RelabelType))
887 clause_expr = (Node *) ((RelabelType *) clause_expr)->arg;
888
889 /* We only support plain Vars for now */
890 if (!IsA(clause_expr, Var))
891 return false;
892
893 /* OK, we know we have a Var */
894 var = (Var *) clause_expr;
895
896 /* Ensure Var is from the correct relation */
897 if (var->varno != relid)
898 return false;
899
900 /* We also better ensure the Var is from the current level */
901 if (var->varlevelsup != 0)
902 return false;
903
904 /* Also ignore system attributes (we don't allow stats on those) */
906 return false;
907
908 *attnum = var->varattno;
909 return true;
910}
@ BMS_SINGLETON
Definition: bitmapset.h:72
bool is_pseudo_constant_clause(Node *clause)
Definition: clauses.c:2087
RegProcedure get_oprrest(Oid opno)
Definition: lsyscache.c:1557
static bool is_orclause(const void *clause)
Definition: nodeFuncs.h:116
static bool is_opclause(const void *clause)
Definition: nodeFuncs.h:76
static bool is_notclause(const void *clause)
Definition: nodeFuncs.h:125
static Expr * get_notclausearg(const void *notclause)
Definition: nodeFuncs.h:134
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define linitial(l)
Definition: pg_list.h:178
#define lsecond(l)
Definition: pg_list.h:183
List * args
Definition: primnodes.h:940
Oid opno
Definition: primnodes.h:818
List * args
Definition: primnodes.h:836
Expr * clause
Definition: pathnodes.h:2575
Definition: primnodes.h:248
AttrNumber varattno
Definition: primnodes.h:260
int varno
Definition: primnodes.h:255
Index varlevelsup
Definition: primnodes.h:280

References OpExpr::args, ScalarArrayOpExpr::args, BoolExpr::args, attnum, AttrNumberIsForUserDefinedAttr, bms_membership(), BMS_SINGLETON, RestrictInfo::clause, dependency_is_compatible_clause(), get_notclausearg(), get_oprrest(), InvalidAttrNumber, is_notclause(), is_opclause(), is_orclause(), is_pseudo_constant_clause(), IsA, lfirst, linitial, list_length(), lsecond, OpExpr::opno, ScalarArrayOpExpr::opno, ScalarArrayOpExpr::useOr, Var::varattno, Var::varlevelsup, and Var::varno.

Referenced by dependencies_clauselist_selectivity(), and dependency_is_compatible_clause().

◆ dependency_is_compatible_expression()

static bool dependency_is_compatible_expression ( Node clause,
Index  relid,
List statlist,
Node **  expr 
)
static

Definition at line 1168 of file dependencies.c.

1169{
1170 ListCell *lc,
1171 *lc2;
1172 Node *clause_expr;
1173
1174 if (IsA(clause, RestrictInfo))
1175 {
1176 RestrictInfo *rinfo = (RestrictInfo *) clause;
1177
1178 /* Pseudoconstants are not interesting (they couldn't contain a Var) */
1179 if (rinfo->pseudoconstant)
1180 return false;
1181
1182 /* Clauses referencing multiple, or no, varnos are incompatible */
1183 if (bms_membership(rinfo->clause_relids) != BMS_SINGLETON)
1184 return false;
1185
1186 clause = (Node *) rinfo->clause;
1187 }
1188
1189 if (is_opclause(clause))
1190 {
1191 /* If it's an opclause, check for Var = Const or Const = Var. */
1192 OpExpr *expr = (OpExpr *) clause;
1193
1194 /* Only expressions with two arguments are candidates. */
1195 if (list_length(expr->args) != 2)
1196 return false;
1197
1198 /* Make sure non-selected argument is a pseudoconstant. */
1200 clause_expr = linitial(expr->args);
1201 else if (is_pseudo_constant_clause(linitial(expr->args)))
1202 clause_expr = lsecond(expr->args);
1203 else
1204 return false;
1205
1206 /*
1207 * If it's not an "=" operator, just ignore the clause, as it's not
1208 * compatible with functional dependencies.
1209 *
1210 * This uses the function for estimating selectivity, not the operator
1211 * directly (a bit awkward, but well ...).
1212 *
1213 * XXX this is pretty dubious; probably it'd be better to check btree
1214 * or hash opclass membership, so as not to be fooled by custom
1215 * selectivity functions, and to be more consistent with decisions
1216 * elsewhere in the planner.
1217 */
1218 if (get_oprrest(expr->opno) != F_EQSEL)
1219 return false;
1220
1221 /* OK to proceed with checking "var" */
1222 }
1223 else if (IsA(clause, ScalarArrayOpExpr))
1224 {
1225 /* If it's a scalar array operator, check for Var IN Const. */
1226 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) clause;
1227
1228 /*
1229 * Reject ALL() variant, we only care about ANY/IN.
1230 *
1231 * FIXME Maybe we should check if all the values are the same, and
1232 * allow ALL in that case? Doesn't seem very practical, though.
1233 */
1234 if (!expr->useOr)
1235 return false;
1236
1237 /* Only expressions with two arguments are candidates. */
1238 if (list_length(expr->args) != 2)
1239 return false;
1240
1241 /*
1242 * We know it's always (Var IN Const), so we assume the var is the
1243 * first argument, and pseudoconstant is the second one.
1244 */
1246 return false;
1247
1248 clause_expr = linitial(expr->args);
1249
1250 /*
1251 * If it's not an "=" operator, just ignore the clause, as it's not
1252 * compatible with functional dependencies. The operator is identified
1253 * simply by looking at which function it uses to estimate
1254 * selectivity. That's a bit strange, but it's what other similar
1255 * places do.
1256 */
1257 if (get_oprrest(expr->opno) != F_EQSEL)
1258 return false;
1259
1260 /* OK to proceed with checking "var" */
1261 }
1262 else if (is_orclause(clause))
1263 {
1264 BoolExpr *bool_expr = (BoolExpr *) clause;
1265
1266 /* start with no expression (we'll use the first match) */
1267 *expr = NULL;
1268
1269 foreach(lc, bool_expr->args)
1270 {
1271 Node *or_expr = NULL;
1272
1273 /*
1274 * Had we found incompatible expression in the arguments, treat
1275 * the whole expression as incompatible.
1276 */
1278 statlist, &or_expr))
1279 return false;
1280
1281 if (*expr == NULL)
1282 *expr = or_expr;
1283
1284 /* ensure all the expressions are the same */
1285 if (!equal(or_expr, *expr))
1286 return false;
1287 }
1288
1289 /* the expression is already checked by the recursive call */
1290 return true;
1291 }
1292 else if (is_notclause(clause))
1293 {
1294 /*
1295 * "NOT x" can be interpreted as "x = false", so get the argument and
1296 * proceed with seeing if it's a suitable Var.
1297 */
1298 clause_expr = (Node *) get_notclausearg(clause);
1299 }
1300 else
1301 {
1302 /*
1303 * A boolean expression "x" can be interpreted as "x = true", so
1304 * proceed with seeing if it's a suitable Var.
1305 */
1306 clause_expr = (Node *) clause;
1307 }
1308
1309 /*
1310 * We may ignore any RelabelType node above the operand. (There won't be
1311 * more than one, since eval_const_expressions has been applied already.)
1312 */
1313 if (IsA(clause_expr, RelabelType))
1314 clause_expr = (Node *) ((RelabelType *) clause_expr)->arg;
1315
1316 /*
1317 * Search for a matching statistics expression.
1318 */
1319 foreach(lc, statlist)
1320 {
1322
1323 /* ignore stats without dependencies */
1324 if (info->kind != STATS_EXT_DEPENDENCIES)
1325 continue;
1326
1327 foreach(lc2, info->exprs)
1328 {
1329 Node *stat_expr = (Node *) lfirst(lc2);
1330
1331 if (equal(clause_expr, stat_expr))
1332 {
1333 *expr = stat_expr;
1334 return true;
1335 }
1336 }
1337 }
1338
1339 return false;
1340}

References OpExpr::args, ScalarArrayOpExpr::args, BoolExpr::args, bms_membership(), BMS_SINGLETON, RestrictInfo::clause, dependency_is_compatible_expression(), equal(), StatisticExtInfo::exprs, get_notclausearg(), get_oprrest(), is_notclause(), is_opclause(), is_orclause(), is_pseudo_constant_clause(), IsA, StatisticExtInfo::kind, lfirst, linitial, list_length(), lsecond, OpExpr::opno, ScalarArrayOpExpr::opno, and ScalarArrayOpExpr::useOr.

Referenced by dependencies_clauselist_selectivity(), and dependency_is_compatible_expression().

◆ dependency_is_fully_matched()

static bool dependency_is_fully_matched ( MVDependency dependency,
Bitmapset attnums 
)
static

Definition at line 595 of file dependencies.c.

596{
597 int j;
598
599 /*
600 * Check that the dependency actually is fully covered by clauses. We have
601 * to translate all attribute numbers, as those are referenced
602 */
603 for (j = 0; j < dependency->nattributes; j++)
604 {
605 int attnum = dependency->attributes[j];
606
607 if (!bms_is_member(attnum, attnums))
608 return false;
609 }
610
611 return true;
612}

References attnum, MVDependency::attributes, bms_is_member(), j, and MVDependency::nattributes.

Referenced by find_strongest_dependency().

◆ DependencyGenerator_free()

static void DependencyGenerator_free ( DependencyGenerator  state)
static

Definition at line 196 of file dependencies.c.

197{
198 pfree(state->dependencies);
199 pfree(state);
200}
Definition: regguts.h:323

References pfree().

Referenced by statext_dependencies_build().

◆ DependencyGenerator_init()

static DependencyGenerator DependencyGenerator_init ( int  n,
int  k 
)
static

Definition at line 173 of file dependencies.c.

174{
176
177 Assert((n >= k) && (k > 0));
178
179 /* allocate the DependencyGenerator state */
181 state->dependencies = (AttrNumber *) palloc(k * sizeof(AttrNumber));
182
183 state->ndependencies = 0;
184 state->current = 0;
185 state->k = k;
186 state->n = n;
187
188 /* now actually pre-generate all the variations */
190
191 return state;
192}
static void generate_dependencies(DependencyGenerator state)
Definition: dependencies.c:157
DependencyGeneratorData * DependencyGenerator
Definition: dependencies.c:65
void * palloc0(Size size)
Definition: mcxt.c:1347

References Assert, generate_dependencies(), palloc(), and palloc0().

Referenced by statext_dependencies_build().

◆ DependencyGenerator_next()

static AttrNumber * DependencyGenerator_next ( DependencyGenerator  state)
static

Definition at line 204 of file dependencies.c.

205{
206 if (state->current == state->ndependencies)
207 return NULL;
208
209 return &state->dependencies[state->k * state->current++];
210}

Referenced by statext_dependencies_build().

◆ find_strongest_dependency()

static MVDependency * find_strongest_dependency ( MVDependencies **  dependencies,
int  ndependencies,
Bitmapset attnums 
)
static

Definition at line 929 of file dependencies.c.

931{
932 int i,
933 j;
934 MVDependency *strongest = NULL;
935
936 /* number of attnums in clauses */
937 int nattnums = bms_num_members(attnums);
938
939 /*
940 * Iterate over the MVDependency items and find the strongest one from the
941 * fully-matched dependencies. We do the cheap checks first, before
942 * matching it against the attnums.
943 */
944 for (i = 0; i < ndependencies; i++)
945 {
946 for (j = 0; j < dependencies[i]->ndeps; j++)
947 {
948 MVDependency *dependency = dependencies[i]->deps[j];
949
950 /*
951 * Skip dependencies referencing more attributes than available
952 * clauses, as those can't be fully matched.
953 */
954 if (dependency->nattributes > nattnums)
955 continue;
956
957 if (strongest)
958 {
959 /* skip dependencies on fewer attributes than the strongest. */
960 if (dependency->nattributes < strongest->nattributes)
961 continue;
962
963 /* also skip weaker dependencies when attribute count matches */
964 if (strongest->nattributes == dependency->nattributes &&
965 strongest->degree > dependency->degree)
966 continue;
967 }
968
969 /*
970 * this dependency is stronger, but we must still check that it's
971 * fully matched to these attnums. We perform this check last as
972 * it's slightly more expensive than the previous checks.
973 */
974 if (dependency_is_fully_matched(dependency, attnums))
975 strongest = dependency; /* save new best match */
976 }
977 }
978
979 return strongest;
980}
static bool dependency_is_fully_matched(MVDependency *dependency, Bitmapset *attnums)
Definition: dependencies.c:595

References bms_num_members(), MVDependency::degree, dependency_is_fully_matched(), MVDependencies::deps, i, j, MVDependency::nattributes, and MVDependencies::ndeps.

Referenced by dependencies_clauselist_selectivity().

◆ generate_dependencies()

static void generate_dependencies ( DependencyGenerator  state)
static

Definition at line 157 of file dependencies.c.

158{
159 AttrNumber *current = (AttrNumber *) palloc0(sizeof(AttrNumber) * state->k);
160
161 generate_dependencies_recurse(state, 0, 0, current);
162
163 pfree(current);
164}
static void generate_dependencies_recurse(DependencyGenerator state, int index, AttrNumber start, AttrNumber *current)
Definition: dependencies.c:91

References generate_dependencies_recurse(), palloc0(), and pfree().

Referenced by DependencyGenerator_init().

◆ generate_dependencies_recurse()

static void generate_dependencies_recurse ( DependencyGenerator  state,
int  index,
AttrNumber  start,
AttrNumber current 
)
static

Definition at line 91 of file dependencies.c.

93{
94 /*
95 * The generator handles the first (k-1) elements differently from the
96 * last element.
97 */
98 if (index < (state->k - 1))
99 {
101
102 /*
103 * The first (k-1) values have to be in ascending order, which we
104 * generate recursively.
105 */
106
107 for (i = start; i < state->n; i++)
108 {
109 current[index] = i;
110 generate_dependencies_recurse(state, (index + 1), (i + 1), current);
111 }
112 }
113 else
114 {
115 int i;
116
117 /*
118 * the last element is the implied value, which does not respect the
119 * ascending order. We just need to check that the value is not in the
120 * first (k-1) elements.
121 */
122
123 for (i = 0; i < state->n; i++)
124 {
125 int j;
126 bool match = false;
127
128 current[index] = i;
129
130 for (j = 0; j < index; j++)
131 {
132 if (current[j] == i)
133 {
134 match = true;
135 break;
136 }
137 }
138
139 /*
140 * If the value is not found in the first part of the dependency,
141 * we're done.
142 */
143 if (!match)
144 {
145 state->dependencies = (AttrNumber *) repalloc(state->dependencies,
146 state->k * (state->ndependencies + 1) * sizeof(AttrNumber));
147 memcpy(&state->dependencies[(state->k * state->ndependencies)],
148 current, state->k * sizeof(AttrNumber));
149 state->ndependencies++;
150 }
151 }
152 }
153}
return str start
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
Definition: type.h:96

References generate_dependencies_recurse(), i, j, repalloc(), and start.

Referenced by generate_dependencies(), and generate_dependencies_recurse().

◆ pg_dependencies_in()

Datum pg_dependencies_in ( PG_FUNCTION_ARGS  )

Definition at line 653 of file dependencies.c.

654{
655 /*
656 * pg_node_list stores the data in binary form and parsing text input is
657 * not needed, so disallow this.
658 */
660 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
661 errmsg("cannot accept a value of type %s", "pg_dependencies")));
662
663 PG_RETURN_VOID(); /* keep compiler quiet */
664}
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_RETURN_VOID()
Definition: fmgr.h:349

References ereport, errcode(), errmsg(), ERROR, and PG_RETURN_VOID.

◆ pg_dependencies_out()

Datum pg_dependencies_out ( PG_FUNCTION_ARGS  )

Definition at line 670 of file dependencies.c.

671{
674 int i,
675 j;
677
680
681 for (i = 0; i < dependencies->ndeps; i++)
682 {
683 MVDependency *dependency = dependencies->deps[i];
684
685 if (i > 0)
687
689 for (j = 0; j < dependency->nattributes; j++)
690 {
691 if (j == dependency->nattributes - 1)
692 appendStringInfoString(&str, " => ");
693 else if (j > 0)
695
696 appendStringInfo(&str, "%d", dependency->attributes[j]);
697 }
698 appendStringInfo(&str, "\": %f", dependency->degree);
699 }
700
702
704}
MVDependencies * statext_dependencies_deserialize(bytea *data)
Definition: dependencies.c:499
#define PG_GETARG_BYTEA_PP(n)
Definition: fmgr.h:308
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
const char * str
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:94
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:179
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:191
void initStringInfo(StringInfo str)
Definition: stringinfo.c:56
Definition: c.h:641

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), MVDependency::attributes, data, MVDependency::degree, MVDependencies::deps, i, initStringInfo(), j, MVDependency::nattributes, MVDependencies::ndeps, PG_GETARG_BYTEA_PP, PG_RETURN_CSTRING, statext_dependencies_deserialize(), and str.

◆ pg_dependencies_recv()

Datum pg_dependencies_recv ( PG_FUNCTION_ARGS  )

Definition at line 710 of file dependencies.c.

711{
713 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
714 errmsg("cannot accept a value of type %s", "pg_dependencies")));
715
716 PG_RETURN_VOID(); /* keep compiler quiet */
717}

References ereport, errcode(), errmsg(), ERROR, and PG_RETURN_VOID.

◆ pg_dependencies_send()

Datum pg_dependencies_send ( PG_FUNCTION_ARGS  )

Definition at line 726 of file dependencies.c.

727{
728 return byteasend(fcinfo);
729}
Datum byteasend(PG_FUNCTION_ARGS)
Definition: varlena.c:490

References byteasend().

◆ statext_dependencies_build()

MVDependencies * statext_dependencies_build ( StatsBuildData data)

Definition at line 348 of file dependencies.c.

349{
350 int i,
351 k;
352
353 /* result */
354 MVDependencies *dependencies = NULL;
355 MemoryContext cxt;
356
357 Assert(data->nattnums >= 2);
358
359 /* tracks memory allocated by dependency_degree calls */
361 "dependency_degree cxt",
363
364 /*
365 * We'll try build functional dependencies starting from the smallest ones
366 * covering just 2 columns, to the largest ones, covering all columns
367 * included in the statistics object. We start from the smallest ones
368 * because we want to be able to skip already implied ones.
369 */
370 for (k = 2; k <= data->nattnums; k++)
371 {
372 AttrNumber *dependency; /* array with k elements */
373
374 /* prepare a DependencyGenerator of variation */
376
377 /* generate all possible variations of k values (out of n) */
378 while ((dependency = DependencyGenerator_next(DependencyGenerator)))
379 {
380 double degree;
381 MVDependency *d;
382 MemoryContext oldcxt;
383
384 /* release memory used by dependency degree calculation */
385 oldcxt = MemoryContextSwitchTo(cxt);
386
387 /* compute how valid the dependency seems */
388 degree = dependency_degree(data, k, dependency);
389
390 MemoryContextSwitchTo(oldcxt);
392
393 /*
394 * if the dependency seems entirely invalid, don't store it
395 */
396 if (degree == 0.0)
397 continue;
398
399 d = (MVDependency *) palloc0(offsetof(MVDependency, attributes)
400 + k * sizeof(AttrNumber));
401
402 /* copy the dependency (and keep the indexes into stxkeys) */
403 d->degree = degree;
404 d->nattributes = k;
405 for (i = 0; i < k; i++)
406 d->attributes[i] = data->attnums[dependency[i]];
407
408 /* initialize the list of dependencies */
409 if (dependencies == NULL)
410 {
411 dependencies
413
414 dependencies->magic = STATS_DEPS_MAGIC;
415 dependencies->type = STATS_DEPS_TYPE_BASIC;
416 dependencies->ndeps = 0;
417 }
418
419 dependencies->ndeps++;
420 dependencies = (MVDependencies *) repalloc(dependencies,
421 offsetof(MVDependencies, deps)
422 + dependencies->ndeps * sizeof(MVDependency *));
423
424 dependencies->deps[dependencies->ndeps - 1] = d;
425 }
426
427 /*
428 * we're done with variations of k elements, so free the
429 * DependencyGenerator
430 */
432 }
433
435
436 return dependencies;
437}
static AttrNumber * DependencyGenerator_next(DependencyGenerator state)
Definition: dependencies.c:204
static void DependencyGenerator_free(DependencyGenerator state)
Definition: dependencies.c:196
static DependencyGenerator DependencyGenerator_init(int n, int k)
Definition: dependencies.c:173
static double dependency_degree(StatsBuildData *data, int k, AttrNumber *dependency)
Definition: dependencies.c:221
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define STATS_DEPS_MAGIC
Definition: statistics.h:43
#define STATS_DEPS_TYPE_BASIC
Definition: statistics.h:44
uint32 magic
Definition: statistics.h:59

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, MVDependency::attributes, CurrentMemoryContext, data, MVDependency::degree, dependency_degree(), DependencyGenerator_free(), DependencyGenerator_init(), DependencyGenerator_next(), MVDependencies::deps, i, if(), MVDependencies::magic, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), MVDependency::nattributes, MVDependencies::ndeps, palloc0(), repalloc(), STATS_DEPS_MAGIC, STATS_DEPS_TYPE_BASIC, and MVDependencies::type.

Referenced by BuildRelationExtStatistics().

◆ statext_dependencies_deserialize()

MVDependencies * statext_dependencies_deserialize ( bytea data)

Definition at line 499 of file dependencies.c.

500{
501 int i;
502 Size min_expected_size;
503 MVDependencies *dependencies;
504 char *tmp;
505
506 if (data == NULL)
507 return NULL;
508
510 elog(ERROR, "invalid MVDependencies size %zu (expected at least %zu)",
512
513 /* read the MVDependencies header */
514 dependencies = (MVDependencies *) palloc0(sizeof(MVDependencies));
515
516 /* initialize pointer to the data part (skip the varlena header) */
517 tmp = VARDATA_ANY(data);
518
519 /* read the header fields and perform basic sanity checks */
520 memcpy(&dependencies->magic, tmp, sizeof(uint32));
521 tmp += sizeof(uint32);
522 memcpy(&dependencies->type, tmp, sizeof(uint32));
523 tmp += sizeof(uint32);
524 memcpy(&dependencies->ndeps, tmp, sizeof(uint32));
525 tmp += sizeof(uint32);
526
527 if (dependencies->magic != STATS_DEPS_MAGIC)
528 elog(ERROR, "invalid dependency magic %d (expected %d)",
529 dependencies->magic, STATS_DEPS_MAGIC);
530
531 if (dependencies->type != STATS_DEPS_TYPE_BASIC)
532 elog(ERROR, "invalid dependency type %d (expected %d)",
533 dependencies->type, STATS_DEPS_TYPE_BASIC);
534
535 if (dependencies->ndeps == 0)
536 elog(ERROR, "invalid zero-length item array in MVDependencies");
537
538 /* what minimum bytea size do we expect for those parameters */
539 min_expected_size = SizeOfItem(dependencies->ndeps);
540
541 if (VARSIZE_ANY_EXHDR(data) < min_expected_size)
542 elog(ERROR, "invalid dependencies size %zu (expected at least %zu)",
543 VARSIZE_ANY_EXHDR(data), min_expected_size);
544
545 /* allocate space for the MCV items */
546 dependencies = repalloc(dependencies, offsetof(MVDependencies, deps)
547 + (dependencies->ndeps * sizeof(MVDependency *)));
548
549 for (i = 0; i < dependencies->ndeps; i++)
550 {
551 double degree;
552 AttrNumber k;
553 MVDependency *d;
554
555 /* degree of validity */
556 memcpy(&degree, tmp, sizeof(double));
557 tmp += sizeof(double);
558
559 /* number of attributes */
560 memcpy(&k, tmp, sizeof(AttrNumber));
561 tmp += sizeof(AttrNumber);
562
563 /* is the number of attributes valid? */
564 Assert((k >= 2) && (k <= STATS_MAX_DIMENSIONS));
565
566 /* now that we know the number of attributes, allocate the dependency */
567 d = (MVDependency *) palloc0(offsetof(MVDependency, attributes)
568 + (k * sizeof(AttrNumber)));
569
570 d->degree = degree;
571 d->nattributes = k;
572
573 /* copy attribute numbers */
574 memcpy(d->attributes, tmp, sizeof(AttrNumber) * d->nattributes);
575 tmp += sizeof(AttrNumber) * d->nattributes;
576
577 dependencies->deps[i] = d;
578
579 /* still within the bytea */
580 Assert(tmp <= ((char *) data + VARSIZE_ANY(data)));
581 }
582
583 /* we should have consumed the whole bytea exactly */
584 Assert(tmp == ((char *) data + VARSIZE_ANY(data)));
585
586 return dependencies;
587}
uint32_t uint32
Definition: c.h:485
size_t Size
Definition: c.h:559
#define SizeOfHeader
Definition: dependencies.c:38
#define SizeOfItem(natts)
Definition: dependencies.c:41
#define STATS_MAX_DIMENSIONS
Definition: statistics.h:19
#define VARSIZE_ANY(PTR)
Definition: varatt.h:311
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317

References Assert, MVDependency::attributes, data, MVDependency::degree, MVDependencies::deps, elog, ERROR, i, MVDependencies::magic, MVDependency::nattributes, MVDependencies::ndeps, palloc0(), repalloc(), SizeOfHeader, SizeOfItem, STATS_DEPS_MAGIC, STATS_DEPS_TYPE_BASIC, STATS_MAX_DIMENSIONS, MVDependencies::type, VARDATA_ANY, VARSIZE_ANY, and VARSIZE_ANY_EXHDR.

Referenced by pg_dependencies_out(), and statext_dependencies_load().

◆ statext_dependencies_load()

MVDependencies * statext_dependencies_load ( Oid  mvoid,
bool  inh 
)

Definition at line 619 of file dependencies.c.

620{
621 MVDependencies *result;
622 bool isnull;
623 Datum deps;
624 HeapTuple htup;
625
626 htup = SearchSysCache2(STATEXTDATASTXOID,
627 ObjectIdGetDatum(mvoid),
628 BoolGetDatum(inh));
629 if (!HeapTupleIsValid(htup))
630 elog(ERROR, "cache lookup failed for statistics object %u", mvoid);
631
632 deps = SysCacheGetAttr(STATEXTDATASTXOID, htup,
633 Anum_pg_statistic_ext_data_stxddependencies, &isnull);
634 if (isnull)
635 elog(ERROR,
636 "requested statistics kind \"%c\" is not yet built for statistics object %u",
637 STATS_EXT_DEPENDENCIES, mvoid);
638
640
641 ReleaseSysCache(htup);
642
643 return result;
644}
#define DatumGetByteaPP(X)
Definition: fmgr.h:291
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
uintptr_t Datum
Definition: postgres.h:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:600
HeapTuple SearchSysCache2(int cacheId, Datum key1, Datum key2)
Definition: syscache.c:232

References BoolGetDatum(), DatumGetByteaPP, elog, ERROR, HeapTupleIsValid, ObjectIdGetDatum(), ReleaseSysCache(), SearchSysCache2(), statext_dependencies_deserialize(), and SysCacheGetAttr().

Referenced by dependencies_clauselist_selectivity().

◆ statext_dependencies_serialize()

bytea * statext_dependencies_serialize ( MVDependencies dependencies)

Definition at line 444 of file dependencies.c.

445{
446 int i;
447 bytea *output;
448 char *tmp;
449 Size len;
450
451 /* we need to store ndeps, with a number of attributes for each one */
453
454 /* and also include space for the actual attribute numbers and degrees */
455 for (i = 0; i < dependencies->ndeps; i++)
456 len += SizeOfItem(dependencies->deps[i]->nattributes);
457
458 output = (bytea *) palloc0(len);
460
461 tmp = VARDATA(output);
462
463 /* Store the base struct values (magic, type, ndeps) */
464 memcpy(tmp, &dependencies->magic, sizeof(uint32));
465 tmp += sizeof(uint32);
466 memcpy(tmp, &dependencies->type, sizeof(uint32));
467 tmp += sizeof(uint32);
468 memcpy(tmp, &dependencies->ndeps, sizeof(uint32));
469 tmp += sizeof(uint32);
470
471 /* store number of attributes and attribute numbers for each dependency */
472 for (i = 0; i < dependencies->ndeps; i++)
473 {
474 MVDependency *d = dependencies->deps[i];
475
476 memcpy(tmp, &d->degree, sizeof(double));
477 tmp += sizeof(double);
478
479 memcpy(tmp, &d->nattributes, sizeof(AttrNumber));
480 tmp += sizeof(AttrNumber);
481
482 memcpy(tmp, d->attributes, sizeof(AttrNumber) * d->nattributes);
483 tmp += sizeof(AttrNumber) * d->nattributes;
484
485 /* protect against overflow */
486 Assert(tmp <= ((char *) output + len));
487 }
488
489 /* make sure we've produced exactly the right amount of data */
490 Assert(tmp == ((char *) output + len));
491
492 return output;
493}
#define VARHDRSZ
Definition: c.h:646
FILE * output
const void size_t len
#define VARDATA(PTR)
Definition: varatt.h:278
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305

References Assert, MVDependency::attributes, MVDependency::degree, MVDependencies::deps, i, len, MVDependencies::magic, MVDependency::nattributes, MVDependencies::ndeps, output, palloc0(), SET_VARSIZE, SizeOfHeader, SizeOfItem, MVDependencies::type, VARDATA, and VARHDRSZ.

Referenced by statext_store().