PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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 "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/optimizer.h"
#include "parser/parsetree.h"
#include "statistics/extended_stats_internal.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/selfuncs.h"
#include "utils/syscache.h"
#include "utils/typcache.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)
 
void statext_dependencies_free (MVDependencies *dependencies)
 
bool statext_dependencies_validate (const MVDependencies *dependencies, const int2vector *stxkeys, int numexprs, int elevel)
 
MVDependenciesstatext_dependencies_load (Oid mvoid, bool inh)
 
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 39 of file dependencies.c.

◆ MinSizeOfItems

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

Definition at line 42 of file dependencies.c.

50{
51 int k; /* size of the dependency */
52 int n; /* number of possible attributes */
53 int current; /* next dependency to return (index) */
54 AttrNumber ndependencies; /* number of dependencies generated */
55 AttrNumber *dependencies; /* array of pre-generated dependencies */
57
59
61 int index, AttrNumber start, AttrNumber *current);
66static double dependency_degree(StatsBuildData *data, int k, AttrNumber *dependency);
67static bool dependency_is_fully_matched(MVDependency *dependency,
68 Bitmapset *attnums);
69static bool dependency_is_compatible_clause(Node *clause, Index relid,
71static bool dependency_is_compatible_expression(Node *clause, Index relid,
72 List *statlist, Node **expr);
74 int ndependencies, Bitmapset *attnums);
76 int varRelid, JoinType jointype,
77 SpecialJoinInfo *sjinfo,
78 MVDependency **dependencies,
79 int ndependencies,
82
83static void
85 AttrNumber start, AttrNumber *current)
86{
87 /*
88 * The generator handles the first (k-1) elements differently from the
89 * last element.
90 */
91 if (index < (state->k - 1))
92 {
94
95 /*
96 * The first (k-1) values have to be in ascending order, which we
97 * generate recursively.
98 */
99
100 for (i = start; i < state->n; i++)
101 {
102 current[index] = i;
103 generate_dependencies_recurse(state, (index + 1), (i + 1), current);
104 }
105 }
106 else
107 {
108 int i;
109
110 /*
111 * the last element is the implied value, which does not respect the
112 * ascending order. We just need to check that the value is not in the
113 * first (k-1) elements.
114 */
115
116 for (i = 0; i < state->n; i++)
117 {
118 int j;
119 bool match = false;
120
121 current[index] = i;
122
123 for (j = 0; j < index; j++)
124 {
125 if (current[j] == i)
126 {
127 match = true;
128 break;
129 }
130 }
131
132 /*
133 * If the value is not found in the first part of the dependency,
134 * we're done.
135 */
136 if (!match)
137 {
138 state->dependencies = (AttrNumber *) repalloc(state->dependencies,
139 state->k * (state->ndependencies + 1) * sizeof(AttrNumber));
140 memcpy(&state->dependencies[(state->k * state->ndependencies)],
141 current, state->k * sizeof(AttrNumber));
142 state->ndependencies++;
143 }
144 }
145 }
146}
147
148/* generate all dependencies (k-permutations of n elements) */
149static void
151{
153
154 generate_dependencies_recurse(state, 0, 0, current);
155
156 pfree(current);
157}
158
159/*
160 * initialize the DependencyGenerator of variations, and prebuild the variations
161 *
162 * This pre-builds all the variations. We could also generate them in
163 * DependencyGenerator_next(), but this seems simpler.
164 */
166DependencyGenerator_init(int n, int k)
167{
169
170 Assert((n >= k) && (k > 0));
171
172 /* allocate the DependencyGenerator state */
174 state->dependencies = palloc_array(AttrNumber, k);
175
176 state->ndependencies = 0;
177 state->current = 0;
178 state->k = k;
179 state->n = n;
180
181 /* now actually pre-generate all the variations */
183
184 return state;
185}
186
187/* free the DependencyGenerator state */
188static void
190{
191 pfree(state->dependencies);
192 pfree(state);
193}
194
195/* generate next combination */
196static AttrNumber *
198{
199 if (state->current == state->ndependencies)
200 return NULL;
201
202 return &state->dependencies[state->k * state->current++];
203}
204
205
206/*
207 * validates functional dependency on the data
208 *
209 * An actual work horse of detecting functional dependencies. Given a variation
210 * of k attributes, it checks that the first (k-1) are sufficient to determine
211 * the last one.
212 */
213static double
215{
216 int i,
217 nitems;
221
222 /* counters valid within a group */
223 int group_size = 0;
224 int n_violations = 0;
225
226 /* total number of rows supporting (consistent with) the dependency */
227 int n_supporting_rows = 0;
228
229 /* Make sure we have at least two input attributes. */
230 Assert(k >= 2);
231
232 /* sort info for all attributes columns */
233 mss = multi_sort_init(k);
234
235 /*
236 * Translate the array of indexes to regular attnums for the dependency
237 * (we will need this to identify the columns in StatsBuildData).
238 */
240 for (i = 0; i < k; i++)
241 attnums_dep[i] = data->attnums[dependency[i]];
242
243 /*
244 * Verify the dependency (a,b,...)->z, using a rather simple algorithm:
245 *
246 * (a) sort the data lexicographically
247 *
248 * (b) split the data into groups by first (k-1) columns
249 *
250 * (c) for each group count different values in the last column
251 *
252 * We use the column data types' default sort operators and collations;
253 * perhaps at some point it'd be worth using column-specific collations?
254 */
255
256 /* prepare the sort function for the dimensions */
257 for (i = 0; i < k; i++)
258 {
259 VacAttrStats *colstat = data->stats[dependency[i]];
261
263 if (type->lt_opr == InvalidOid) /* shouldn't happen */
264 elog(ERROR, "cache lookup failed for ordering operator for type %u",
265 colstat->attrtypid);
266
267 /* prepare the sort function for this dimension */
268 multi_sort_add_dimension(mss, i, type->lt_opr, colstat->attrcollid);
269 }
270
271 /*
272 * build an array of SortItem(s) sorted using the multi-sort support
273 *
274 * XXX This relies on all stats entries pointing to the same tuple
275 * descriptor. For now that assumption holds, but it might change in the
276 * future for example if we support statistics on multiple tables.
277 */
279
280 /*
281 * Walk through the sorted array, split it into rows according to the
282 * first (k-1) columns. If there's a single value in the last column, we
283 * count the group as 'supporting' the functional dependency. Otherwise we
284 * count it as contradicting.
285 */
286
287 /* start with the first row forming a group */
288 group_size = 1;
289
290 /* loop 1 beyond the end of the array so that we count the final group */
291 for (i = 1; i <= nitems; i++)
292 {
293 /*
294 * Check if the group ended, which may be either because we processed
295 * all the items (i==nitems), or because the i-th item is not equal to
296 * the preceding one.
297 */
298 if (i == nitems ||
299 multi_sort_compare_dims(0, k - 2, &items[i - 1], &items[i], mss) != 0)
300 {
301 /*
302 * If no violations were found in the group then track the rows of
303 * the group as supporting the functional dependency.
304 */
305 if (n_violations == 0)
307
308 /* Reset counters for the new group */
309 n_violations = 0;
310 group_size = 1;
311 continue;
312 }
313 /* first columns match, but the last one does not (so contradicting) */
314 else if (multi_sort_compare_dim(k - 1, &items[i - 1], &items[i], mss) != 0)
315 n_violations++;
316
317 group_size++;
318 }
319
320 /* Compute the 'degree of validity' as (supporting/total). */
321 return (n_supporting_rows * 1.0 / data->numrows);
322}
323
324/*
325 * detects functional dependencies between groups of columns
326 *
327 * Generates all possible subsets of columns (variations) and computes
328 * the degree of validity for each one. For example when creating statistics
329 * on three columns (a,b,c) there are 9 possible dependencies
330 *
331 * two columns three columns
332 * ----------- -------------
333 * (a) -> b (a,b) -> c
334 * (a) -> c (a,c) -> b
335 * (b) -> a (b,c) -> a
336 * (b) -> c
337 * (c) -> a
338 * (c) -> b
339 */
342{
343 int i,
344 k;
345
346 /* result */
347 MVDependencies *dependencies = NULL;
348 MemoryContext cxt;
349
350 Assert(data->nattnums >= 2);
351
352 /* tracks memory allocated by dependency_degree calls */
354 "dependency_degree cxt",
356
357 /*
358 * We'll try build functional dependencies starting from the smallest ones
359 * covering just 2 columns, to the largest ones, covering all columns
360 * included in the statistics object. We start from the smallest ones
361 * because we want to be able to skip already implied ones.
362 */
363 for (k = 2; k <= data->nattnums; k++)
364 {
365 AttrNumber *dependency; /* array with k elements */
366
367 /* prepare a DependencyGenerator of variation */
369
370 /* generate all possible variations of k values (out of n) */
371 while ((dependency = DependencyGenerator_next(DependencyGenerator)))
372 {
373 double degree;
374 MVDependency *d;
376
377 /* release memory used by dependency degree calculation */
379
380 /* compute how valid the dependency seems */
381 degree = dependency_degree(data, k, dependency);
382
385
386 /*
387 * if the dependency seems entirely invalid, don't store it
388 */
389 if (degree == 0.0)
390 continue;
391
392 d = (MVDependency *) palloc0(offsetof(MVDependency, attributes)
393 + k * sizeof(AttrNumber));
394
395 /* copy the dependency (and keep the indexes into stxkeys) */
396 d->degree = degree;
397 d->nattributes = k;
398 for (i = 0; i < k; i++)
399 d->attributes[i] = data->attnums[dependency[i]];
400
401 /* initialize the list of dependencies */
402 if (dependencies == NULL)
403 {
404 dependencies = palloc0_object(MVDependencies);
405
406 dependencies->magic = STATS_DEPS_MAGIC;
407 dependencies->type = STATS_DEPS_TYPE_BASIC;
408 dependencies->ndeps = 0;
409 }
410
411 dependencies->ndeps++;
412 dependencies = (MVDependencies *) repalloc(dependencies,
414 + dependencies->ndeps * sizeof(MVDependency *));
415
416 dependencies->deps[dependencies->ndeps - 1] = d;
417 }
418
419 /*
420 * we're done with variations of k elements, so free the
421 * DependencyGenerator
422 */
424 }
425
427
428 return dependencies;
429}
430
431
432/*
433 * Serialize list of dependencies into a bytea value.
434 */
435bytea *
437{
438 bytea *output;
439 char *tmp;
440 Size len;
441
442 /* we need to store ndeps, with a number of attributes for each one */
444
445 /* and also include space for the actual attribute numbers and degrees */
446 for (uint32 i = 0; i < dependencies->ndeps; i++)
447 len += SizeOfItem(dependencies->deps[i]->nattributes);
448
449 output = (bytea *) palloc0(len);
451
452 tmp = VARDATA(output);
453
454 /* Store the base struct values (magic, type, ndeps) */
455 memcpy(tmp, &dependencies->magic, sizeof(uint32));
456 tmp += sizeof(uint32);
457 memcpy(tmp, &dependencies->type, sizeof(uint32));
458 tmp += sizeof(uint32);
459 memcpy(tmp, &dependencies->ndeps, sizeof(uint32));
460 tmp += sizeof(uint32);
461
462 /* store number of attributes and attribute numbers for each dependency */
463 for (uint32 i = 0; i < dependencies->ndeps; i++)
464 {
465 MVDependency *d = dependencies->deps[i];
466
467 memcpy(tmp, &d->degree, sizeof(double));
468 tmp += sizeof(double);
469
470 memcpy(tmp, &d->nattributes, sizeof(AttrNumber));
471 tmp += sizeof(AttrNumber);
472
473 memcpy(tmp, d->attributes, sizeof(AttrNumber) * d->nattributes);
474 tmp += sizeof(AttrNumber) * d->nattributes;
475
476 /* protect against overflow */
477 Assert(tmp <= ((char *) output + len));
478 }
479
480 /* make sure we've produced exactly the right amount of data */
481 Assert(tmp == ((char *) output + len));
482
483 return output;
484}
485
486/*
487 * Reads serialized dependencies into MVDependencies structure.
488 */
491{
493 MVDependencies *dependencies;
494 char *tmp;
495
496 if (data == NULL)
497 return NULL;
498
500 elog(ERROR, "invalid MVDependencies size %zu (expected at least %zu)",
502
503 /* read the MVDependencies header */
504 dependencies = palloc0_object(MVDependencies);
505
506 /* initialize pointer to the data part (skip the varlena header) */
507 tmp = VARDATA_ANY(data);
508
509 /* read the header fields and perform basic sanity checks */
510 memcpy(&dependencies->magic, tmp, sizeof(uint32));
511 tmp += sizeof(uint32);
512 memcpy(&dependencies->type, tmp, sizeof(uint32));
513 tmp += sizeof(uint32);
514 memcpy(&dependencies->ndeps, tmp, sizeof(uint32));
515 tmp += sizeof(uint32);
516
517 if (dependencies->magic != STATS_DEPS_MAGIC)
518 elog(ERROR, "invalid dependency magic %d (expected %d)",
519 dependencies->magic, STATS_DEPS_MAGIC);
520
521 if (dependencies->type != STATS_DEPS_TYPE_BASIC)
522 elog(ERROR, "invalid dependency type %d (expected %d)",
523 dependencies->type, STATS_DEPS_TYPE_BASIC);
524
525 if (dependencies->ndeps == 0)
526 elog(ERROR, "invalid zero-length item array in MVDependencies");
527
528 /* what minimum bytea size do we expect for those parameters */
529 min_expected_size = MinSizeOfItems(dependencies->ndeps);
530
532 elog(ERROR, "invalid dependencies size %zu (expected at least %zu)",
534
535 /* allocate space for the MCV items */
536 dependencies = repalloc(dependencies, offsetof(MVDependencies, deps)
537 + (dependencies->ndeps * sizeof(MVDependency *)));
538
539 for (uint32 i = 0; i < dependencies->ndeps; i++)
540 {
541 double degree;
542 AttrNumber k;
543 MVDependency *d;
544
545 /* degree of validity */
546 memcpy(&degree, tmp, sizeof(double));
547 tmp += sizeof(double);
548
549 /* number of attributes */
550 memcpy(&k, tmp, sizeof(AttrNumber));
551 tmp += sizeof(AttrNumber);
552
553 /* is the number of attributes valid? */
554 Assert((k >= 2) && (k <= STATS_MAX_DIMENSIONS));
555
556 /* now that we know the number of attributes, allocate the dependency */
557 d = (MVDependency *) palloc0(offsetof(MVDependency, attributes)
558 + (k * sizeof(AttrNumber)));
559
560 d->degree = degree;
561 d->nattributes = k;
562
563 /* copy attribute numbers */
564 memcpy(d->attributes, tmp, sizeof(AttrNumber) * d->nattributes);
565 tmp += sizeof(AttrNumber) * d->nattributes;
566
567 dependencies->deps[i] = d;
568
569 /* still within the bytea */
570 Assert(tmp <= ((char *) data + VARSIZE_ANY(data)));
571 }
572
573 /* we should have consumed the whole bytea exactly */
574 Assert(tmp == ((char *) data + VARSIZE_ANY(data)));
575
576 return dependencies;
577}
578
579/*
580 * Free allocations of a MVDependencies.
581 */
582void
584{
585 for (uint32 i = 0; i < dependencies->ndeps; i++)
586 pfree(dependencies->deps[i]);
587 pfree(dependencies);
588}
589
590/*
591 * Validate a set of MVDependencies against the extended statistics object
592 * definition.
593 *
594 * Every MVDependencies must be checked to ensure that the attnums in the
595 * attributes list correspond to attnums/expressions defined by the
596 * extended statistics object.
597 *
598 * Positive attnums are attributes which must be found in the stxkeys, while
599 * negative attnums correspond to an expression number, no attribute number
600 * can be below (0 - numexprs).
601 */
602bool
604 const int2vector *stxkeys,
605 int numexprs, int elevel)
606{
608
609 /* Scan through each dependency entry */
610 for (uint32 i = 0; i < dependencies->ndeps; i++)
611 {
612 const MVDependency *dep = dependencies->deps[i];
613
614 /*
615 * Cross-check each attribute in a dependency entry with the extended
616 * stats object definition.
617 */
618 for (int j = 0; j < dep->nattributes; j++)
619 {
621 bool ok = false;
622
623 if (attnum > 0)
624 {
625 /* attribute number in stxkeys */
626 for (int k = 0; k < stxkeys->dim1; k++)
627 {
628 if (attnum == stxkeys->values[k])
629 {
630 ok = true;
631 break;
632 }
633 }
634 }
635 else if ((attnum < 0) && (attnum >= attnum_expr_lowbound))
636 {
637 /* attribute number for an expression */
638 ok = true;
639 }
640
641 if (!ok)
642 {
643 ereport(elevel,
645 errmsg("could not validate \"%s\" object: invalid attribute number %d found",
646 "pg_dependencies", attnum)));
647 return false;
648 }
649 }
650 }
651
652 return true;
653}
654
655/*
656 * dependency_is_fully_matched
657 * checks that a functional dependency is fully matched given clauses on
658 * attributes (assuming the clauses are suitable equality clauses)
659 */
660static bool
662{
663 int j;
664
665 /*
666 * Check that the dependency actually is fully covered by clauses. We have
667 * to translate all attribute numbers, as those are referenced
668 */
669 for (j = 0; j < dependency->nattributes; j++)
670 {
671 int attnum = dependency->attributes[j];
672
673 if (!bms_is_member(attnum, attnums))
674 return false;
675 }
676
677 return true;
678}
679
680/*
681 * statext_dependencies_load
682 * Load the functional dependencies for the indicated pg_statistic_ext tuple
683 */
686{
688 bool isnull;
689 Datum deps;
690 HeapTuple htup;
691
694 BoolGetDatum(inh));
695 if (!HeapTupleIsValid(htup))
696 elog(ERROR, "cache lookup failed for statistics object %u", mvoid);
697
700 if (isnull)
701 elog(ERROR,
702 "requested statistics kind \"%c\" is not yet built for statistics object %u",
704
706
707 ReleaseSysCache(htup);
708
709 return result;
710}
711
712/*
713 * dependency_is_compatible_clause
714 * Determines if the clause is compatible with functional dependencies
715 *
716 * Only clauses that have the form of equality to a pseudoconstant, or can be
717 * interpreted that way, are currently accepted. Furthermore the variable
718 * part of the clause must be a simple Var belonging to the specified
719 * relation, whose attribute number we return in *attnum on success.
720 */
721static bool
723{
724 Var *var;
726
727 if (IsA(clause, RestrictInfo))
728 {
729 RestrictInfo *rinfo = (RestrictInfo *) clause;
730
731 /* Pseudoconstants are not interesting (they couldn't contain a Var) */
732 if (rinfo->pseudoconstant)
733 return false;
734
735 /* Clauses referencing multiple, or no, varnos are incompatible */
736 if (bms_membership(rinfo->clause_relids) != BMS_SINGLETON)
737 return false;
738
739 clause = (Node *) rinfo->clause;
740 }
741
742 if (is_opclause(clause))
743 {
744 /* If it's an opclause, check for Var = Const or Const = Var. */
745 OpExpr *expr = (OpExpr *) clause;
746
747 /* Only expressions with two arguments are candidates. */
748 if (list_length(expr->args) != 2)
749 return false;
750
751 /* Make sure non-selected argument is a pseudoconstant. */
753 clause_expr = linitial(expr->args);
754 else if (is_pseudo_constant_clause(linitial(expr->args)))
755 clause_expr = lsecond(expr->args);
756 else
757 return false;
758
759 /*
760 * If it's not an "=" operator, just ignore the clause, as it's not
761 * compatible with functional dependencies.
762 *
763 * This uses the function for estimating selectivity, not the operator
764 * directly (a bit awkward, but well ...).
765 *
766 * XXX this is pretty dubious; probably it'd be better to check btree
767 * or hash opclass membership, so as not to be fooled by custom
768 * selectivity functions, and to be more consistent with decisions
769 * elsewhere in the planner.
770 */
771 if (get_oprrest(expr->opno) != F_EQSEL)
772 return false;
773
774 /* OK to proceed with checking "var" */
775 }
776 else if (IsA(clause, ScalarArrayOpExpr))
777 {
778 /* If it's a scalar array operator, check for Var IN Const. */
779 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) clause;
780
781 /*
782 * Reject ALL() variant, we only care about ANY/IN.
783 *
784 * XXX Maybe we should check if all the values are the same, and allow
785 * ALL in that case? Doesn't seem very practical, though.
786 */
787 if (!expr->useOr)
788 return false;
789
790 /* Only expressions with two arguments are candidates. */
791 if (list_length(expr->args) != 2)
792 return false;
793
794 /*
795 * We know it's always (Var IN Const), so we assume the var is the
796 * first argument, and pseudoconstant is the second one.
797 */
799 return false;
800
801 clause_expr = linitial(expr->args);
802
803 /*
804 * If it's not an "=" operator, just ignore the clause, as it's not
805 * compatible with functional dependencies. The operator is identified
806 * simply by looking at which function it uses to estimate
807 * selectivity. That's a bit strange, but it's what other similar
808 * places do.
809 */
810 if (get_oprrest(expr->opno) != F_EQSEL)
811 return false;
812
813 /* OK to proceed with checking "var" */
814 }
815 else if (is_orclause(clause))
816 {
817 BoolExpr *bool_expr = (BoolExpr *) clause;
818 ListCell *lc;
819
820 /* start with no attribute number */
822
823 foreach(lc, bool_expr->args)
824 {
826
827 /*
828 * Had we found incompatible clause in the arguments, treat the
829 * whole clause as incompatible.
830 */
832 relid, &clause_attnum))
833 return false;
834
837
838 /* ensure all the variables are the same (same attnum) */
839 if (*attnum != clause_attnum)
840 return false;
841 }
842
843 /* the Var is already checked by the recursive call */
844 return true;
845 }
846 else if (is_notclause(clause))
847 {
848 /*
849 * "NOT x" can be interpreted as "x = false", so get the argument and
850 * proceed with seeing if it's a suitable Var.
851 */
852 clause_expr = (Node *) get_notclausearg(clause);
853 }
854 else
855 {
856 /*
857 * A boolean expression "x" can be interpreted as "x = true", so
858 * proceed with seeing if it's a suitable Var.
859 */
860 clause_expr = clause;
861 }
862
863 /*
864 * We may ignore any RelabelType node above the operand. (There won't be
865 * more than one, since eval_const_expressions has been applied already.)
866 */
868 clause_expr = (Node *) ((RelabelType *) clause_expr)->arg;
869
870 /* We only support plain Vars for now */
871 if (!IsA(clause_expr, Var))
872 return false;
873
874 /* OK, we know we have a Var */
875 var = (Var *) clause_expr;
876
877 /* Ensure Var is from the correct relation */
878 if (var->varno != relid)
879 return false;
880
881 /* We also better ensure the Var is from the current level */
882 if (var->varlevelsup != 0)
883 return false;
884
885 /* Also ignore system attributes (we don't allow stats on those) */
887 return false;
888
889 *attnum = var->varattno;
890 return true;
891}
892
893/*
894 * find_strongest_dependency
895 * find the strongest dependency on the attributes
896 *
897 * When applying functional dependencies, we start with the strongest
898 * dependencies. That is, we select the dependency that:
899 *
900 * (a) has all attributes covered by equality clauses
901 *
902 * (b) has the most attributes
903 *
904 * (c) has the highest degree of validity
905 *
906 * This guarantees that we eliminate the most redundant conditions first
907 * (see the comment in dependencies_clauselist_selectivity).
908 */
909static MVDependency *
910find_strongest_dependency(MVDependencies **dependencies, int ndependencies,
911 Bitmapset *attnums)
912{
914
915 /* number of attnums in clauses */
916 int nattnums = bms_num_members(attnums);
917
918 /*
919 * Iterate over the MVDependency items and find the strongest one from the
920 * fully-matched dependencies. We do the cheap checks first, before
921 * matching it against the attnums.
922 */
923 for (int i = 0; i < ndependencies; i++)
924 {
925 for (uint32 j = 0; j < dependencies[i]->ndeps; j++)
926 {
927 MVDependency *dependency = dependencies[i]->deps[j];
928
929 /*
930 * Skip dependencies referencing more attributes than available
931 * clauses, as those can't be fully matched.
932 */
933 if (dependency->nattributes > nattnums)
934 continue;
935
936 if (strongest)
937 {
938 /* skip dependencies on fewer attributes than the strongest. */
939 if (dependency->nattributes < strongest->nattributes)
940 continue;
941
942 /* also skip weaker dependencies when attribute count matches */
943 if (strongest->nattributes == dependency->nattributes &&
944 strongest->degree > dependency->degree)
945 continue;
946 }
947
948 /*
949 * this dependency is stronger, but we must still check that it's
950 * fully matched to these attnums. We perform this check last as
951 * it's slightly more expensive than the previous checks.
952 */
953 if (dependency_is_fully_matched(dependency, attnums))
954 strongest = dependency; /* save new best match */
955 }
956 }
957
958 return strongest;
959}
960
961/*
962 * clauselist_apply_dependencies
963 * Apply the specified functional dependencies to a list of clauses and
964 * return the estimated selectivity of the clauses that are compatible
965 * with any of the given dependencies.
966 *
967 * This will estimate all not-already-estimated clauses that are compatible
968 * with functional dependencies, and which have an attribute mentioned by any
969 * of the given dependencies (either as an implying or implied attribute).
970 *
971 * Given (lists of) clauses on attributes (a,b) and a functional dependency
972 * (a=>b), the per-column selectivities P(a) and P(b) are notionally combined
973 * using the formula
974 *
975 * P(a,b) = f * P(a) + (1-f) * P(a) * P(b)
976 *
977 * where 'f' is the degree of dependency. This reflects the fact that we
978 * expect a fraction f of all rows to be consistent with the dependency
979 * (a=>b), and so have a selectivity of P(a), while the remaining rows are
980 * treated as independent.
981 *
982 * In practice, we use a slightly modified version of this formula, which uses
983 * a selectivity of Min(P(a), P(b)) for the dependent rows, since the result
984 * should obviously not exceed either column's individual selectivity. I.e.,
985 * we actually combine selectivities using the formula
986 *
987 * P(a,b) = f * Min(P(a), P(b)) + (1-f) * P(a) * P(b)
988 *
989 * This can make quite a difference if the specific values matching the
990 * clauses are not consistent with the functional dependency.
991 */
992static Selectivity
994 int varRelid, JoinType jointype,
995 SpecialJoinInfo *sjinfo,
996 MVDependency **dependencies, int ndependencies,
999{
1000 Bitmapset *attnums;
1001 int i;
1002 int j;
1003 int nattrs;
1005 int attidx;
1006 int listidx;
1007 ListCell *l;
1009
1010 /*
1011 * Extract the attnums of all implying and implied attributes from all the
1012 * given dependencies. Each of these attributes is expected to have at
1013 * least 1 not-already-estimated compatible clause that we will estimate
1014 * here.
1015 */
1016 attnums = NULL;
1017 for (i = 0; i < ndependencies; i++)
1018 {
1019 for (j = 0; j < dependencies[i]->nattributes; j++)
1020 {
1021 AttrNumber attnum = dependencies[i]->attributes[j];
1022
1023 attnums = bms_add_member(attnums, attnum);
1024 }
1025 }
1026
1027 /*
1028 * Compute per-column selectivity estimates for each of these attributes,
1029 * and mark all the corresponding clauses as estimated.
1030 */
1031 nattrs = bms_num_members(attnums);
1033
1034 attidx = 0;
1035 i = -1;
1036 while ((i = bms_next_member(attnums, i)) >= 0)
1037 {
1040
1041 listidx = -1;
1042 foreach(l, clauses)
1043 {
1044 Node *clause = (Node *) lfirst(l);
1045
1046 listidx++;
1047 if (list_attnums[listidx] == i)
1048 {
1051 }
1052 }
1053
1055 jointype, sjinfo, false);
1056 attr_sel[attidx++] = simple_sel;
1057 }
1058
1059 /*
1060 * Now combine these selectivities using the dependency information. For
1061 * chains of dependencies such as a -> b -> c, the b -> c dependency will
1062 * come before the a -> b dependency in the array, so we traverse the
1063 * array backwards to ensure such chains are computed in the right order.
1064 *
1065 * As explained above, pairs of selectivities are combined using the
1066 * formula
1067 *
1068 * P(a,b) = f * Min(P(a), P(b)) + (1-f) * P(a) * P(b)
1069 *
1070 * to ensure that the combined selectivity is never greater than either
1071 * individual selectivity.
1072 *
1073 * Where multiple dependencies apply (e.g., a -> b -> c), we use
1074 * conditional probabilities to compute the overall result as follows:
1075 *
1076 * P(a,b,c) = P(c|a,b) * P(a,b) = P(c|a,b) * P(b|a) * P(a)
1077 *
1078 * so we replace the selectivities of all implied attributes with
1079 * conditional probabilities, that are conditional on all their implying
1080 * attributes. The selectivities of all other non-implied attributes are
1081 * left as they are.
1082 */
1083 for (i = ndependencies - 1; i >= 0; i--)
1084 {
1085 MVDependency *dependency = dependencies[i];
1088 double f;
1089
1090 /* Selectivity of all the implying attributes */
1091 s1 = 1.0;
1092 for (j = 0; j < dependency->nattributes - 1; j++)
1093 {
1094 attnum = dependency->attributes[j];
1095 attidx = bms_member_index(attnums, attnum);
1096 s1 *= attr_sel[attidx];
1097 }
1098
1099 /* Original selectivity of the implied attribute */
1100 attnum = dependency->attributes[j];
1101 attidx = bms_member_index(attnums, attnum);
1102 s2 = attr_sel[attidx];
1103
1104 /*
1105 * Replace s2 with the conditional probability s2 given s1, computed
1106 * using the formula P(b|a) = P(a,b) / P(a), which simplifies to
1107 *
1108 * P(b|a) = f * Min(P(a), P(b)) / P(a) + (1-f) * P(b)
1109 *
1110 * where P(a) = s1, the selectivity of the implying attributes, and
1111 * P(b) = s2, the selectivity of the implied attribute.
1112 */
1113 f = dependency->degree;
1114
1115 if (s1 <= s2)
1116 attr_sel[attidx] = f + (1 - f) * s2;
1117 else
1118 attr_sel[attidx] = f * s2 / s1 + (1 - f) * s2;
1119 }
1120
1121 /*
1122 * The overall selectivity of all the clauses on all these attributes is
1123 * then the product of all the original (non-implied) probabilities and
1124 * the new conditional (implied) probabilities.
1125 */
1126 s1 = 1.0;
1127 for (i = 0; i < nattrs; i++)
1128 s1 *= attr_sel[i];
1129
1131
1132 pfree(attr_sel);
1133 bms_free(attnums);
1134
1135 return s1;
1136}
1137
1138/*
1139 * dependency_is_compatible_expression
1140 * Determines if the expression is compatible with functional dependencies
1141 *
1142 * Similar to dependency_is_compatible_clause, but doesn't enforce that the
1143 * expression is a simple Var. On success, return the matching statistics
1144 * expression into *expr.
1145 */
1146static bool
1147dependency_is_compatible_expression(Node *clause, Index relid, List *statlist, Node **expr)
1148{
1149 ListCell *lc,
1150 *lc2;
1152
1153 if (IsA(clause, RestrictInfo))
1154 {
1155 RestrictInfo *rinfo = (RestrictInfo *) clause;
1156
1157 /* Pseudoconstants are not interesting (they couldn't contain a Var) */
1158 if (rinfo->pseudoconstant)
1159 return false;
1160
1161 /* Clauses referencing multiple, or no, varnos are incompatible */
1162 if (bms_membership(rinfo->clause_relids) != BMS_SINGLETON)
1163 return false;
1164
1165 clause = (Node *) rinfo->clause;
1166 }
1167
1168 if (is_opclause(clause))
1169 {
1170 /* If it's an opclause, check for Var = Const or Const = Var. */
1171 OpExpr *expr = (OpExpr *) clause;
1172
1173 /* Only expressions with two arguments are candidates. */
1174 if (list_length(expr->args) != 2)
1175 return false;
1176
1177 /* Make sure non-selected argument is a pseudoconstant. */
1179 clause_expr = linitial(expr->args);
1180 else if (is_pseudo_constant_clause(linitial(expr->args)))
1181 clause_expr = lsecond(expr->args);
1182 else
1183 return false;
1184
1185 /*
1186 * If it's not an "=" operator, just ignore the clause, as it's not
1187 * compatible with functional dependencies.
1188 *
1189 * This uses the function for estimating selectivity, not the operator
1190 * directly (a bit awkward, but well ...).
1191 *
1192 * XXX this is pretty dubious; probably it'd be better to check btree
1193 * or hash opclass membership, so as not to be fooled by custom
1194 * selectivity functions, and to be more consistent with decisions
1195 * elsewhere in the planner.
1196 */
1197 if (get_oprrest(expr->opno) != F_EQSEL)
1198 return false;
1199
1200 /* OK to proceed with checking "var" */
1201 }
1202 else if (IsA(clause, ScalarArrayOpExpr))
1203 {
1204 /* If it's a scalar array operator, check for Var IN Const. */
1205 ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) clause;
1206
1207 /*
1208 * Reject ALL() variant, we only care about ANY/IN.
1209 *
1210 * FIXME Maybe we should check if all the values are the same, and
1211 * allow ALL in that case? Doesn't seem very practical, though.
1212 */
1213 if (!expr->useOr)
1214 return false;
1215
1216 /* Only expressions with two arguments are candidates. */
1217 if (list_length(expr->args) != 2)
1218 return false;
1219
1220 /*
1221 * We know it's always (Var IN Const), so we assume the var is the
1222 * first argument, and pseudoconstant is the second one.
1223 */
1225 return false;
1226
1227 clause_expr = linitial(expr->args);
1228
1229 /*
1230 * If it's not an "=" operator, just ignore the clause, as it's not
1231 * compatible with functional dependencies. The operator is identified
1232 * simply by looking at which function it uses to estimate
1233 * selectivity. That's a bit strange, but it's what other similar
1234 * places do.
1235 */
1236 if (get_oprrest(expr->opno) != F_EQSEL)
1237 return false;
1238
1239 /* OK to proceed with checking "var" */
1240 }
1241 else if (is_orclause(clause))
1242 {
1243 BoolExpr *bool_expr = (BoolExpr *) clause;
1244
1245 /* start with no expression (we'll use the first match) */
1246 *expr = NULL;
1247
1248 foreach(lc, bool_expr->args)
1249 {
1250 Node *or_expr = NULL;
1251
1252 /*
1253 * Had we found incompatible expression in the arguments, treat
1254 * the whole expression as incompatible.
1255 */
1257 statlist, &or_expr))
1258 return false;
1259
1260 if (*expr == NULL)
1261 *expr = or_expr;
1262
1263 /* ensure all the expressions are the same */
1264 if (!equal(or_expr, *expr))
1265 return false;
1266 }
1267
1268 /* the expression is already checked by the recursive call */
1269 return true;
1270 }
1271 else if (is_notclause(clause))
1272 {
1273 /*
1274 * "NOT x" can be interpreted as "x = false", so get the argument and
1275 * proceed with seeing if it's a suitable Var.
1276 */
1277 clause_expr = (Node *) get_notclausearg(clause);
1278 }
1279 else
1280 {
1281 /*
1282 * A boolean expression "x" can be interpreted as "x = true", so
1283 * proceed with seeing if it's a suitable Var.
1284 */
1285 clause_expr = clause;
1286 }
1287
1288 /*
1289 * We may ignore any RelabelType node above the operand. (There won't be
1290 * more than one, since eval_const_expressions has been applied already.)
1291 */
1293 clause_expr = (Node *) ((RelabelType *) clause_expr)->arg;
1294
1295 /*
1296 * Search for a matching statistics expression.
1297 */
1298 foreach(lc, statlist)
1299 {
1301
1302 /* ignore stats without dependencies */
1303 if (info->kind != STATS_EXT_DEPENDENCIES)
1304 continue;
1305
1306 foreach(lc2, info->exprs)
1307 {
1308 Node *stat_expr = (Node *) lfirst(lc2);
1309
1311 {
1312 *expr = stat_expr;
1313 return true;
1314 }
1315 }
1316 }
1317
1318 return false;
1319}
1320
1321/*
1322 * dependencies_clauselist_selectivity
1323 * Return the estimated selectivity of (a subset of) the given clauses
1324 * using functional dependency statistics, or 1.0 if no useful functional
1325 * dependency statistic exists.
1326 *
1327 * 'estimatedclauses' is an input/output argument that gets a bit set
1328 * corresponding to the (zero-based) list index of each clause that is included
1329 * in the estimated selectivity.
1330 *
1331 * Given equality clauses on attributes (a,b) we find the strongest dependency
1332 * between them, i.e. either (a=>b) or (b=>a). Assuming (a=>b) is the selected
1333 * dependency, we then combine the per-clause selectivities using the formula
1334 *
1335 * P(a,b) = f * P(a) + (1-f) * P(a) * P(b)
1336 *
1337 * where 'f' is the degree of the dependency. (Actually we use a slightly
1338 * modified version of this formula -- see clauselist_apply_dependencies()).
1339 *
1340 * With clauses on more than two attributes, the dependencies are applied
1341 * recursively, starting with the widest/strongest dependencies. For example
1342 * P(a,b,c) is first split like this:
1343 *
1344 * P(a,b,c) = f * P(a,b) + (1-f) * P(a,b) * P(c)
1345 *
1346 * assuming (a,b=>c) is the strongest dependency.
1347 */
1350 List *clauses,
1351 int varRelid,
1352 JoinType jointype,
1353 SpecialJoinInfo *sjinfo,
1354 RelOptInfo *rel,
1356{
1357 Selectivity s1 = 1.0;
1358 ListCell *l;
1361 int listidx;
1364 int total_ndeps;
1365 MVDependency **dependencies;
1366 int ndependencies;
1368 RangeTblEntry *rte = planner_rt_fetch(rel->relid, root);
1369
1370 /* unique expressions */
1372 int unique_exprs_cnt;
1373
1374 /* check if there's any stats that might be useful for us. */
1375 if (!has_stats_of_kind(rel->statlist, STATS_EXT_DEPENDENCIES))
1376 return 1.0;
1377
1379
1380 /*
1381 * We allocate space as if every clause was a unique expression, although
1382 * that's probably overkill. Some will be simple column references that
1383 * we'll translate to attnums, and there might be duplicates. But it's
1384 * easier and cheaper to just do one allocation than repalloc later.
1385 */
1387 unique_exprs_cnt = 0;
1388
1389 /*
1390 * Pre-process the clauses list to extract the attnums seen in each item.
1391 * We need to determine if there's any clauses which will be useful for
1392 * dependency selectivity estimations. Along the way we'll record all of
1393 * the attnums for each clause in a list which we'll reference later so we
1394 * don't need to repeat the same work again. We'll also keep track of all
1395 * attnums seen.
1396 *
1397 * We also skip clauses that we already estimated using different types of
1398 * statistics (we treat them as incompatible).
1399 *
1400 * To handle expressions, we assign them negative attnums, as if it was a
1401 * system attribute (this is fine, as we only allow extended stats on user
1402 * attributes). And then we offset everything by the number of
1403 * expressions, so that we can store the values in a bitmapset.
1404 */
1405 listidx = 0;
1406 foreach(l, clauses)
1407 {
1408 Node *clause = (Node *) lfirst(l);
1410 Node *expr = NULL;
1411
1412 /* ignore clause by default */
1414
1416 {
1417 /*
1418 * If it's a simple column reference, just extract the attnum. If
1419 * it's an expression, assign a negative attnum as if it was a
1420 * system attribute.
1421 */
1422 if (dependency_is_compatible_clause(clause, rel->relid, &attnum))
1423 {
1425 }
1426 else if (dependency_is_compatible_expression(clause, rel->relid,
1427 rel->statlist,
1428 &expr))
1429 {
1430 /* special attnum assigned to this expression */
1432
1433 Assert(expr != NULL);
1434
1435 /* If the expression is duplicate, use the same attnum. */
1436 for (int i = 0; i < unique_exprs_cnt; i++)
1437 {
1438 if (equal(unique_exprs[i], expr))
1439 {
1440 /* negative attribute number to expression */
1441 attnum = -(i + 1);
1442 break;
1443 }
1444 }
1445
1446 /* not found in the list, so add it */
1448 {
1450
1451 /* after incrementing the value, to get -1, -2, ... */
1453 }
1454
1455 /* remember which attnum was assigned to this clause */
1457 }
1458 }
1459
1460 listidx++;
1461 }
1462
1463 Assert(listidx == list_length(clauses));
1464
1465 /*
1466 * How much we need to offset the attnums? If there are no expressions,
1467 * then no offset is needed. Otherwise we need to offset enough for the
1468 * lowest value (-unique_exprs_cnt) to become 1.
1469 */
1470 if (unique_exprs_cnt > 0)
1472 else
1473 attnum_offset = 0;
1474
1475 /*
1476 * Now that we know how many expressions there are, we can offset the
1477 * values just enough to build the bitmapset.
1478 */
1479 for (int i = 0; i < list_length(clauses); i++)
1480 {
1482
1483 /* ignore incompatible or already estimated clauses */
1485 continue;
1486
1487 /* make sure the attnum is in the expected range */
1490
1491 /* make sure the attnum is positive (valid AttrNumber) */
1493
1494 /*
1495 * Either it's a regular attribute, or it's an expression, in which
1496 * case we must not have seen it before (expressions are unique).
1497 *
1498 * XXX Check whether it's a regular attribute has to be done using the
1499 * original attnum, while the second check has to use the value with
1500 * an offset.
1501 */
1504
1505 /*
1506 * Remember the offset attnum, both for attributes and expressions.
1507 * We'll pass list_attnums to clauselist_apply_dependencies, which
1508 * uses it to identify clauses in a bitmap. We could also pass the
1509 * offset, but this is more convenient.
1510 */
1512
1514 }
1515
1516 /*
1517 * If there's not at least two distinct attnums and expressions, then
1518 * reject the whole list of clauses. We must return 1.0 so the calling
1519 * function's selectivity is unaffected.
1520 */
1522 {
1525 return 1.0;
1526 }
1527
1528 /*
1529 * Load all functional dependencies matching at least two parameters. We
1530 * can simply consider all dependencies at once, without having to search
1531 * for the best statistics object.
1532 *
1533 * To not waste cycles and memory, we deserialize dependencies only for
1534 * statistics that match at least two attributes. The array is allocated
1535 * with the assumption that all objects match - we could grow the array to
1536 * make it just the right size, but it's likely wasteful anyway thanks to
1537 * moving the freed chunks to freelists etc.
1538 */
1541 total_ndeps = 0;
1542
1543 foreach(l, rel->statlist)
1544 {
1546 int nmatched;
1547 int nexprs;
1548 int k;
1549 MVDependencies *deps;
1550
1551 /* skip statistics that are not of the correct type */
1552 if (stat->kind != STATS_EXT_DEPENDENCIES)
1553 continue;
1554
1555 /* skip statistics with mismatching stxdinherit value */
1556 if (stat->inherit != rte->inh)
1557 continue;
1558
1559 /*
1560 * Count matching attributes - we have to undo the attnum offsets. The
1561 * input attribute numbers are not offset (expressions are not
1562 * included in stat->keys, so it's not necessary). But we need to
1563 * offset it before checking against clauses_attnums.
1564 */
1565 nmatched = 0;
1566 k = -1;
1567 while ((k = bms_next_member(stat->keys, k)) >= 0)
1568 {
1570
1571 /* skip expressions */
1573 continue;
1574
1575 /* apply the same offset as above */
1577
1579 nmatched++;
1580 }
1581
1582 /* count matching expressions */
1583 nexprs = 0;
1584 for (int i = 0; i < unique_exprs_cnt; i++)
1585 {
1586 ListCell *lc;
1587
1588 foreach(lc, stat->exprs)
1589 {
1590 Node *stat_expr = (Node *) lfirst(lc);
1591
1592 /* try to match it */
1594 nexprs++;
1595 }
1596 }
1597
1598 /*
1599 * Skip objects matching fewer than two attributes/expressions from
1600 * clauses.
1601 */
1602 if (nmatched + nexprs < 2)
1603 continue;
1604
1605 deps = statext_dependencies_load(stat->statOid, rte->inh);
1606
1607 /*
1608 * The expressions may be represented by different attnums in the
1609 * stats, we need to remap them to be consistent with the clauses.
1610 * That will make the later steps (e.g. picking the strongest item and
1611 * so on) much simpler and cheaper, because it won't need to care
1612 * about the offset at all.
1613 *
1614 * When we're at it, we can ignore dependencies that are not fully
1615 * matched by clauses (i.e. referencing attributes or expressions that
1616 * are not in the clauses).
1617 *
1618 * We have to do this for all statistics, as long as there are any
1619 * expressions - we need to shift the attnums in all dependencies.
1620 *
1621 * XXX Maybe we should do this always, because it also eliminates some
1622 * of the dependencies early. It might be cheaper than having to walk
1623 * the longer list in find_strongest_dependency later, especially as
1624 * we need to do that repeatedly?
1625 *
1626 * XXX We have to do this even when there are no expressions in
1627 * clauses, otherwise find_strongest_dependency may fail for stats
1628 * with expressions (due to lookup of negative value in bitmap). So we
1629 * need to at least filter out those dependencies. Maybe we could do
1630 * it in a cheaper way (if there are no expr clauses, we can just
1631 * discard all negative attnums without any lookups).
1632 */
1633 if (unique_exprs_cnt > 0 || stat->exprs != NIL)
1634 {
1635 uint32 ndeps = 0;
1636
1637 for (uint32 i = 0; i < deps->ndeps; i++)
1638 {
1639 bool skip = false;
1640 MVDependency *dep = deps->deps[i];
1641
1642 for (int j = 0; j < dep->nattributes; j++)
1643 {
1644 int idx;
1645 Node *expr;
1648
1649 /* undo the per-statistics offset */
1650 attnum = dep->attributes[j];
1651
1652 /*
1653 * For regular attributes we can simply check if it
1654 * matches any clause. If there's no matching clause, we
1655 * can just ignore it. We need to offset the attnum
1656 * though.
1657 */
1659 {
1660 dep->attributes[j] = attnum + attnum_offset;
1661
1662 if (!bms_is_member(dep->attributes[j], clauses_attnums))
1663 {
1664 skip = true;
1665 break;
1666 }
1667
1668 continue;
1669 }
1670
1671 /*
1672 * the attnum should be a valid system attnum (-1, -2,
1673 * ...)
1674 */
1676
1677 /*
1678 * For expressions, we need to do two translations. First
1679 * we have to translate the negative attnum to index in
1680 * the list of expressions (in the statistics object).
1681 * Then we need to see if there's a matching clause. The
1682 * index of the unique expression determines the attnum
1683 * (and we offset it).
1684 */
1685 idx = -(1 + attnum);
1686
1687 /* Is the expression index is valid? */
1688 Assert((idx >= 0) && (idx < list_length(stat->exprs)));
1689
1690 expr = (Node *) list_nth(stat->exprs, idx);
1691
1692 /* try to find the expression in the unique list */
1693 for (int m = 0; m < unique_exprs_cnt; m++)
1694 {
1695 /*
1696 * found a matching unique expression, use the attnum
1697 * (derived from index of the unique expression)
1698 */
1699 if (equal(unique_exprs[m], expr))
1700 {
1701 unique_attnum = -(m + 1) + attnum_offset;
1702 break;
1703 }
1704 }
1705
1706 /*
1707 * Found no matching expression, so we can simply skip
1708 * this dependency, because there's no chance it will be
1709 * fully covered.
1710 */
1712 {
1713 skip = true;
1714 break;
1715 }
1716
1717 /* otherwise remap it to the new attnum */
1718 dep->attributes[j] = unique_attnum;
1719 }
1720
1721 /* if found a matching dependency, keep it */
1722 if (!skip)
1723 {
1724 /* maybe we've skipped something earlier, so move it */
1725 if (ndeps != i)
1726 deps->deps[ndeps] = deps->deps[i];
1727
1728 ndeps++;
1729 }
1730 }
1731
1732 deps->ndeps = ndeps;
1733 }
1734
1735 /*
1736 * It's possible we've removed all dependencies, in which case we
1737 * don't bother adding it to the list.
1738 */
1739 if (deps->ndeps > 0)
1740 {
1742 total_ndeps += deps->ndeps;
1744 }
1745 }
1746
1747 /* if no matching stats could be found then we've nothing to do */
1748 if (nfunc_dependencies == 0)
1749 {
1754 return 1.0;
1755 }
1756
1757 /*
1758 * Work out which dependencies we can apply, starting with the
1759 * widest/strongest ones, and proceeding to smaller/weaker ones.
1760 */
1761 dependencies = palloc_array(MVDependency *, total_ndeps);
1762 ndependencies = 0;
1763
1764 while (true)
1765 {
1766 MVDependency *dependency;
1768
1769 /* the widest/strongest dependency, fully matched by clauses */
1773 if (!dependency)
1774 break;
1775
1776 dependencies[ndependencies++] = dependency;
1777
1778 /* Ignore dependencies using this implied attribute in later loops */
1779 attnum = dependency->attributes[dependency->nattributes - 1];
1781 }
1782
1783 /*
1784 * If we found applicable dependencies, use them to estimate all
1785 * compatible clauses on attributes that they refer to.
1786 */
1787 if (ndependencies != 0)
1788 s1 = clauselist_apply_dependencies(root, clauses, varRelid, jointype,
1789 sjinfo, dependencies, ndependencies,
1791
1792 /* free deserialized functional dependencies (and then the array) */
1793 for (int i = 0; i < nfunc_dependencies; i++)
1795
1796 pfree(dependencies);
1801
1802 return s1;
1803}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:263
int16 AttrNumber
Definition attnum.h:21
#define AttributeNumberIsValid(attributeNumber)
Definition attnum.h:34
#define AttrNumberIsForUserDefinedAttr(attributeNumber)
Definition attnum.h:41
#define InvalidAttrNumber
Definition attnum.h:23
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1425
Bitmapset * bms_del_member(Bitmapset *a, int x)
Definition bitmapset.c:987
void bms_free(Bitmapset *a)
Definition bitmapset.c:240
int bms_num_members(const Bitmapset *a)
Definition bitmapset.c:879
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:645
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:934
BMS_Membership bms_membership(const Bitmapset *a)
Definition bitmapset.c:900
int bms_member_index(Bitmapset *a, int x)
Definition bitmapset.c:674
@ BMS_SINGLETON
Definition bitmapset.h:72
@ BMS_MULTIPLE
Definition bitmapset.h:73
#define VARHDRSZ
Definition c.h:840
#define Assert(condition)
Definition c.h:1002
uint32_t uint32
Definition c.h:683
unsigned int Index
Definition c.h:757
size_t Size
Definition c.h:748
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
bool is_pseudo_constant_clause(Node *clause)
Definition clauses.c:2349
Selectivity clauselist_selectivity_ext(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, bool use_extended_stats)
Definition clausesel.c:117
static void generate_dependencies(DependencyGenerator state)
#define SizeOfHeader
MVDependencies * statext_dependencies_deserialize(bytea *data)
MVDependencies * statext_dependencies_load(Oid mvoid, bool inh)
static bool dependency_is_compatible_expression(Node *clause, Index relid, List *statlist, Node **expr)
static AttrNumber * DependencyGenerator_next(DependencyGenerator state)
MVDependencies * statext_dependencies_build(StatsBuildData *data)
static bool dependency_is_compatible_clause(Node *clause, Index relid, AttrNumber *attnum)
bool statext_dependencies_validate(const MVDependencies *dependencies, const int2vector *stxkeys, int numexprs, int elevel)
static bool dependency_is_fully_matched(MVDependency *dependency, Bitmapset *attnums)
bytea * statext_dependencies_serialize(MVDependencies *dependencies)
void statext_dependencies_free(MVDependencies *dependencies)
static void DependencyGenerator_free(DependencyGenerator state)
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 DependencyGenerator DependencyGenerator_init(int n, int k)
#define SizeOfItem(natts)
Selectivity dependencies_clauselist_selectivity(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype, SpecialJoinInfo *sjinfo, RelOptInfo *rel, Bitmapset **estimatedclauses)
static double dependency_degree(StatsBuildData *data, int k, AttrNumber *dependency)
static void generate_dependencies_recurse(DependencyGenerator state, int index, AttrNumber start, AttrNumber *current)
#define MinSizeOfItems(ndeps)
DependencyGeneratorData * DependencyGenerator
static MVDependency * find_strongest_dependency(MVDependencies **dependencies, int ndependencies, Bitmapset *attnums)
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
bool equal(const void *a, const void *b)
Definition equalfuncs.c:223
bool has_stats_of_kind(List *stats, char requiredkind)
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)
#define palloc_array(type, count)
Definition fe_memutils.h:91
#define palloc0_array(type, count)
Definition fe_memutils.h:92
#define palloc0_object(type)
Definition fe_memutils.h:90
#define DatumGetByteaPP(X)
Definition fmgr.h:292
return str start
#define HeapTupleIsValid(tuple)
Definition htup.h:78
#define MaxHeapAttributeNumber
#define nitems(x)
Definition indent.h:31
FILE * output
int j
Definition isn.c:78
int i
Definition isn.c:77
List * lappend(List *list, void *datum)
Definition list.c:339
RegProcedure get_oprrest(Oid opno)
Definition lsyscache.c:1871
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:406
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1635
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc0(Size size)
Definition mcxt.c:1420
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:475
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
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:162
double Selectivity
Definition nodes.h:258
JoinType
Definition nodes.h:296
static char * errmsg
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
#define planner_rt_fetch(rti, root)
Definition pathnodes.h:704
int16 attnum
static const struct exclude_list_item skip[]
const void size_t len
const void * data
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
static void * list_nth(const List *list, int n)
Definition pg_list.h:331
#define linitial(l)
Definition pg_list.h:178
#define lsecond(l)
Definition pg_list.h:183
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
#define InvalidOid
unsigned int Oid
static int fb(int x)
char * s1
char * s2
tree ctl root
Definition radixtree.h:1857
#define CLAMP_PROBABILITY(p)
Definition selfuncs.h:63
#define STATS_MAX_DIMENSIONS
Definition statistics.h:19
#define STATS_DEPS_MAGIC
Definition statistics.h:43
#define STATS_DEPS_TYPE_BASIC
Definition statistics.h:44
Definition pg_list.h:54
MVDependency * deps[FLEXIBLE_ARRAY_MEMBER]
Definition statistics.h:62
AttrNumber nattributes
Definition statistics.h:53
double degree
Definition statistics.h:52
AttrNumber attributes[FLEXIBLE_ARRAY_MEMBER]
Definition statistics.h:54
Definition nodes.h:133
Oid opno
Definition primnodes.h:835
List * args
Definition primnodes.h:853
Expr * clause
Definition pathnodes.h:2901
AttrNumber varattno
Definition primnodes.h:275
int varno
Definition primnodes.h:270
Index varlevelsup
Definition primnodes.h:295
Definition type.h:97
Definition c.h:835
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache2(SysCacheIdentifier cacheId, Datum key1, Datum key2)
Definition syscache.c:231
Datum SysCacheGetAttr(SysCacheIdentifier cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition syscache.c:596
static ItemArray items
TypeCacheEntry * lookup_type_cache(Oid type_id, int flags)
Definition typcache.c:389
#define TYPECACHE_LT_OPR
Definition typcache.h:139
static Size VARSIZE_ANY(const void *PTR)
Definition varatt.h:460
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
static char * VARDATA(const void *PTR)
Definition varatt.h:305
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486
static void SET_VARSIZE(void *PTR, Size len)
Definition varatt.h:432
const char * type

◆ SizeOfHeader

#define SizeOfHeader   (3 * sizeof(uint32))

Definition at line 32 of file dependencies.c.

◆ SizeOfItem

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

Definition at line 35 of file dependencies.c.

Typedef Documentation

◆ DependencyGenerator

◆ 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 994 of file dependencies.c.

1000{
1001 Bitmapset *attnums;
1002 int i;
1003 int j;
1004 int nattrs;
1006 int attidx;
1007 int listidx;
1008 ListCell *l;
1010
1011 /*
1012 * Extract the attnums of all implying and implied attributes from all the
1013 * given dependencies. Each of these attributes is expected to have at
1014 * least 1 not-already-estimated compatible clause that we will estimate
1015 * here.
1016 */
1017 attnums = NULL;
1018 for (i = 0; i < ndependencies; i++)
1019 {
1020 for (j = 0; j < dependencies[i]->nattributes; j++)
1021 {
1022 AttrNumber attnum = dependencies[i]->attributes[j];
1023
1024 attnums = bms_add_member(attnums, attnum);
1025 }
1026 }
1027
1028 /*
1029 * Compute per-column selectivity estimates for each of these attributes,
1030 * and mark all the corresponding clauses as estimated.
1031 */
1032 nattrs = bms_num_members(attnums);
1034
1035 attidx = 0;
1036 i = -1;
1037 while ((i = bms_next_member(attnums, i)) >= 0)
1038 {
1041
1042 listidx = -1;
1043 foreach(l, clauses)
1044 {
1045 Node *clause = (Node *) lfirst(l);
1046
1047 listidx++;
1048 if (list_attnums[listidx] == i)
1049 {
1052 }
1053 }
1054
1056 jointype, sjinfo, false);
1057 attr_sel[attidx++] = simple_sel;
1058 }
1059
1060 /*
1061 * Now combine these selectivities using the dependency information. For
1062 * chains of dependencies such as a -> b -> c, the b -> c dependency will
1063 * come before the a -> b dependency in the array, so we traverse the
1064 * array backwards to ensure such chains are computed in the right order.
1065 *
1066 * As explained above, pairs of selectivities are combined using the
1067 * formula
1068 *
1069 * P(a,b) = f * Min(P(a), P(b)) + (1-f) * P(a) * P(b)
1070 *
1071 * to ensure that the combined selectivity is never greater than either
1072 * individual selectivity.
1073 *
1074 * Where multiple dependencies apply (e.g., a -> b -> c), we use
1075 * conditional probabilities to compute the overall result as follows:
1076 *
1077 * P(a,b,c) = P(c|a,b) * P(a,b) = P(c|a,b) * P(b|a) * P(a)
1078 *
1079 * so we replace the selectivities of all implied attributes with
1080 * conditional probabilities, that are conditional on all their implying
1081 * attributes. The selectivities of all other non-implied attributes are
1082 * left as they are.
1083 */
1084 for (i = ndependencies - 1; i >= 0; i--)
1085 {
1086 MVDependency *dependency = dependencies[i];
1089 double f;
1090
1091 /* Selectivity of all the implying attributes */
1092 s1 = 1.0;
1093 for (j = 0; j < dependency->nattributes - 1; j++)
1094 {
1095 attnum = dependency->attributes[j];
1096 attidx = bms_member_index(attnums, attnum);
1097 s1 *= attr_sel[attidx];
1098 }
1099
1100 /* Original selectivity of the implied attribute */
1101 attnum = dependency->attributes[j];
1102 attidx = bms_member_index(attnums, attnum);
1103 s2 = attr_sel[attidx];
1104
1105 /*
1106 * Replace s2 with the conditional probability s2 given s1, computed
1107 * using the formula P(b|a) = P(a,b) / P(a), which simplifies to
1108 *
1109 * P(b|a) = f * Min(P(a), P(b)) / P(a) + (1-f) * P(b)
1110 *
1111 * where P(a) = s1, the selectivity of the implying attributes, and
1112 * P(b) = s2, the selectivity of the implied attribute.
1113 */
1114 f = dependency->degree;
1115
1116 if (s1 <= s2)
1117 attr_sel[attidx] = f + (1 - f) * s2;
1118 else
1119 attr_sel[attidx] = f * s2 / s1 + (1 - f) * s2;
1120 }
1121
1122 /*
1123 * The overall selectivity of all the clauses on all these attributes is
1124 * then the product of all the original (non-implied) probabilities and
1125 * the new conditional (implied) probabilities.
1126 */
1127 s1 = 1.0;
1128 for (i = 0; i < nattrs; i++)
1129 s1 *= attr_sel[i];
1130
1132
1133 pfree(attr_sel);
1134 bms_free(attnums);
1135
1136 return s1;
1137}

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, fb(), i, j, lappend(), lfirst, MVDependency::nattributes, NIL, palloc_array, 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 1350 of file dependencies.c.

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

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(), fb(), find_strongest_dependency(), has_stats_of_kind(), i, idx(), InvalidAttrNumber, j, lfirst, list_length(), list_nth(), MaxHeapAttributeNumber, MVDependency::nattributes, MVDependencies::ndeps, NIL, palloc_array, 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 215 of file dependencies.c.

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

References Assert, build_sorted_items(), data, elog, ERROR, fb(), i, InvalidOid, items, lookup_type_cache(), multi_sort_add_dimension(), multi_sort_compare_dim(), multi_sort_compare_dims(), multi_sort_init(), nitems, palloc_array, 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 723 of file dependencies.c.

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

References OpExpr::args, ScalarArrayOpExpr::args, attnum, AttrNumberIsForUserDefinedAttr, bms_membership(), BMS_SINGLETON, RestrictInfo::clause, dependency_is_compatible_clause(), fb(), 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 1148 of file dependencies.c.

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

References OpExpr::args, ScalarArrayOpExpr::args, bms_membership(), BMS_SINGLETON, RestrictInfo::clause, dependency_is_compatible_expression(), equal(), StatisticExtInfo::exprs, fb(), 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 662 of file dependencies.c.

663{
664 int j;
665
666 /*
667 * Check that the dependency actually is fully covered by clauses. We have
668 * to translate all attribute numbers, as those are referenced
669 */
670 for (j = 0; j < dependency->nattributes; j++)
671 {
672 int attnum = dependency->attributes[j];
673
674 if (!bms_is_member(attnum, attnums))
675 return false;
676 }
677
678 return true;
679}

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 190 of file dependencies.c.

191{
192 pfree(state->dependencies);
193 pfree(state);
194}

References pfree().

Referenced by statext_dependencies_build().

◆ DependencyGenerator_init()

static DependencyGenerator DependencyGenerator_init ( int  n,
int  k 
)
static

Definition at line 167 of file dependencies.c.

168{
170
171 Assert((n >= k) && (k > 0));
172
173 /* allocate the DependencyGenerator state */
175 state->dependencies = palloc_array(AttrNumber, k);
176
177 state->ndependencies = 0;
178 state->current = 0;
179 state->k = k;
180 state->n = n;
181
182 /* now actually pre-generate all the variations */
184
185 return state;
186}

References Assert, generate_dependencies(), palloc0_object, and palloc_array.

Referenced by statext_dependencies_build().

◆ DependencyGenerator_next()

static AttrNumber * DependencyGenerator_next ( DependencyGenerator  state)
static

Definition at line 198 of file dependencies.c.

199{
200 if (state->current == state->ndependencies)
201 return NULL;
202
203 return &state->dependencies[state->k * state->current++];
204}

References fb().

Referenced by statext_dependencies_build().

◆ find_strongest_dependency()

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

Definition at line 911 of file dependencies.c.

913{
915
916 /* number of attnums in clauses */
917 int nattnums = bms_num_members(attnums);
918
919 /*
920 * Iterate over the MVDependency items and find the strongest one from the
921 * fully-matched dependencies. We do the cheap checks first, before
922 * matching it against the attnums.
923 */
924 for (int i = 0; i < ndependencies; i++)
925 {
926 for (uint32 j = 0; j < dependencies[i]->ndeps; j++)
927 {
928 MVDependency *dependency = dependencies[i]->deps[j];
929
930 /*
931 * Skip dependencies referencing more attributes than available
932 * clauses, as those can't be fully matched.
933 */
934 if (dependency->nattributes > nattnums)
935 continue;
936
937 if (strongest)
938 {
939 /* skip dependencies on fewer attributes than the strongest. */
940 if (dependency->nattributes < strongest->nattributes)
941 continue;
942
943 /* also skip weaker dependencies when attribute count matches */
944 if (strongest->nattributes == dependency->nattributes &&
945 strongest->degree > dependency->degree)
946 continue;
947 }
948
949 /*
950 * this dependency is stronger, but we must still check that it's
951 * fully matched to these attnums. We perform this check last as
952 * it's slightly more expensive than the previous checks.
953 */
954 if (dependency_is_fully_matched(dependency, attnums))
955 strongest = dependency; /* save new best match */
956 }
957 }
958
959 return strongest;
960}

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

Referenced by dependencies_clauselist_selectivity().

◆ generate_dependencies()

static void generate_dependencies ( DependencyGenerator  state)
static

Definition at line 151 of file dependencies.c.

152{
154
155 generate_dependencies_recurse(state, 0, 0, current);
156
157 pfree(current);
158}

References generate_dependencies_recurse(), palloc0_array, 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 85 of file dependencies.c.

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

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

Referenced by generate_dependencies(), and generate_dependencies_recurse().

◆ statext_dependencies_build()

MVDependencies * statext_dependencies_build ( StatsBuildData data)

Definition at line 342 of file dependencies.c.

343{
344 int i,
345 k;
346
347 /* result */
348 MVDependencies *dependencies = NULL;
349 MemoryContext cxt;
350
351 Assert(data->nattnums >= 2);
352
353 /* tracks memory allocated by dependency_degree calls */
355 "dependency_degree cxt",
357
358 /*
359 * We'll try build functional dependencies starting from the smallest ones
360 * covering just 2 columns, to the largest ones, covering all columns
361 * included in the statistics object. We start from the smallest ones
362 * because we want to be able to skip already implied ones.
363 */
364 for (k = 2; k <= data->nattnums; k++)
365 {
366 AttrNumber *dependency; /* array with k elements */
367
368 /* prepare a DependencyGenerator of variation */
370
371 /* generate all possible variations of k values (out of n) */
372 while ((dependency = DependencyGenerator_next(DependencyGenerator)))
373 {
374 double degree;
375 MVDependency *d;
377
378 /* release memory used by dependency degree calculation */
380
381 /* compute how valid the dependency seems */
382 degree = dependency_degree(data, k, dependency);
383
386
387 /*
388 * if the dependency seems entirely invalid, don't store it
389 */
390 if (degree == 0.0)
391 continue;
392
393 d = (MVDependency *) palloc0(offsetof(MVDependency, attributes)
394 + k * sizeof(AttrNumber));
395
396 /* copy the dependency (and keep the indexes into stxkeys) */
397 d->degree = degree;
398 d->nattributes = k;
399 for (i = 0; i < k; i++)
400 d->attributes[i] = data->attnums[dependency[i]];
401
402 /* initialize the list of dependencies */
403 if (dependencies == NULL)
404 {
405 dependencies = palloc0_object(MVDependencies);
406
407 dependencies->magic = STATS_DEPS_MAGIC;
408 dependencies->type = STATS_DEPS_TYPE_BASIC;
409 dependencies->ndeps = 0;
410 }
411
412 dependencies->ndeps++;
413 dependencies = (MVDependencies *) repalloc(dependencies,
415 + dependencies->ndeps * sizeof(MVDependency *));
416
417 dependencies->deps[dependencies->ndeps - 1] = d;
418 }
419
420 /*
421 * we're done with variations of k elements, so free the
422 * DependencyGenerator
423 */
425 }
426
428
429 return dependencies;
430}

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, MVDependency::attributes, CurrentMemoryContext, data, MVDependency::degree, dependency_degree(), DependencyGenerator_free(), DependencyGenerator_init(), DependencyGenerator_next(), MVDependencies::deps, fb(), i, MVDependencies::magic, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), MVDependency::nattributes, MVDependencies::ndeps, palloc0(), palloc0_object, 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 491 of file dependencies.c.

492{
494 MVDependencies *dependencies;
495 char *tmp;
496
497 if (data == NULL)
498 return NULL;
499
501 elog(ERROR, "invalid MVDependencies size %zu (expected at least %zu)",
503
504 /* read the MVDependencies header */
505 dependencies = palloc0_object(MVDependencies);
506
507 /* initialize pointer to the data part (skip the varlena header) */
508 tmp = VARDATA_ANY(data);
509
510 /* read the header fields and perform basic sanity checks */
511 memcpy(&dependencies->magic, tmp, sizeof(uint32));
512 tmp += sizeof(uint32);
513 memcpy(&dependencies->type, tmp, sizeof(uint32));
514 tmp += sizeof(uint32);
515 memcpy(&dependencies->ndeps, tmp, sizeof(uint32));
516 tmp += sizeof(uint32);
517
518 if (dependencies->magic != STATS_DEPS_MAGIC)
519 elog(ERROR, "invalid dependency magic %d (expected %d)",
520 dependencies->magic, STATS_DEPS_MAGIC);
521
522 if (dependencies->type != STATS_DEPS_TYPE_BASIC)
523 elog(ERROR, "invalid dependency type %d (expected %d)",
524 dependencies->type, STATS_DEPS_TYPE_BASIC);
525
526 if (dependencies->ndeps == 0)
527 elog(ERROR, "invalid zero-length item array in MVDependencies");
528
529 /* what minimum bytea size do we expect for those parameters */
530 min_expected_size = MinSizeOfItems(dependencies->ndeps);
531
533 elog(ERROR, "invalid dependencies size %zu (expected at least %zu)",
535
536 /* allocate space for the MCV items */
537 dependencies = repalloc(dependencies, offsetof(MVDependencies, deps)
538 + (dependencies->ndeps * sizeof(MVDependency *)));
539
540 for (uint32 i = 0; i < dependencies->ndeps; i++)
541 {
542 double degree;
543 AttrNumber k;
544 MVDependency *d;
545
546 /* degree of validity */
547 memcpy(&degree, tmp, sizeof(double));
548 tmp += sizeof(double);
549
550 /* number of attributes */
551 memcpy(&k, tmp, sizeof(AttrNumber));
552 tmp += sizeof(AttrNumber);
553
554 /* is the number of attributes valid? */
555 Assert((k >= 2) && (k <= STATS_MAX_DIMENSIONS));
556
557 /* now that we know the number of attributes, allocate the dependency */
558 d = (MVDependency *) palloc0(offsetof(MVDependency, attributes)
559 + (k * sizeof(AttrNumber)));
560
561 d->degree = degree;
562 d->nattributes = k;
563
564 /* copy attribute numbers */
565 memcpy(d->attributes, tmp, sizeof(AttrNumber) * d->nattributes);
566 tmp += sizeof(AttrNumber) * d->nattributes;
567
568 dependencies->deps[i] = d;
569
570 /* still within the bytea */
571 Assert(tmp <= ((char *) data + VARSIZE_ANY(data)));
572 }
573
574 /* we should have consumed the whole bytea exactly */
575 Assert(tmp == ((char *) data + VARSIZE_ANY(data)));
576
577 return dependencies;
578}

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

Referenced by extended_statistics_update(), pg_dependencies_out(), and statext_dependencies_load().

◆ statext_dependencies_free()

void statext_dependencies_free ( MVDependencies dependencies)

Definition at line 584 of file dependencies.c.

585{
586 for (uint32 i = 0; i < dependencies->ndeps; i++)
587 pfree(dependencies->deps[i]);
588 pfree(dependencies);
589}

References MVDependencies::deps, i, MVDependencies::ndeps, and pfree().

Referenced by extended_statistics_update().

◆ statext_dependencies_load()

MVDependencies * statext_dependencies_load ( Oid  mvoid,
bool  inh 
)

Definition at line 686 of file dependencies.c.

687{
689 bool isnull;
690 Datum deps;
691 HeapTuple htup;
692
695 BoolGetDatum(inh));
696 if (!HeapTupleIsValid(htup))
697 elog(ERROR, "cache lookup failed for statistics object %u", mvoid);
698
701 if (isnull)
702 elog(ERROR,
703 "requested statistics kind \"%c\" is not yet built for statistics object %u",
705
707
708 ReleaseSysCache(htup);
709
710 return result;
711}

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

Referenced by dependencies_clauselist_selectivity().

◆ statext_dependencies_serialize()

bytea * statext_dependencies_serialize ( MVDependencies dependencies)

Definition at line 437 of file dependencies.c.

438{
439 bytea *output;
440 char *tmp;
441 Size len;
442
443 /* we need to store ndeps, with a number of attributes for each one */
445
446 /* and also include space for the actual attribute numbers and degrees */
447 for (uint32 i = 0; i < dependencies->ndeps; i++)
448 len += SizeOfItem(dependencies->deps[i]->nattributes);
449
450 output = (bytea *) palloc0(len);
452
453 tmp = VARDATA(output);
454
455 /* Store the base struct values (magic, type, ndeps) */
456 memcpy(tmp, &dependencies->magic, sizeof(uint32));
457 tmp += sizeof(uint32);
458 memcpy(tmp, &dependencies->type, sizeof(uint32));
459 tmp += sizeof(uint32);
460 memcpy(tmp, &dependencies->ndeps, sizeof(uint32));
461 tmp += sizeof(uint32);
462
463 /* store number of attributes and attribute numbers for each dependency */
464 for (uint32 i = 0; i < dependencies->ndeps; i++)
465 {
466 MVDependency *d = dependencies->deps[i];
467
468 memcpy(tmp, &d->degree, sizeof(double));
469 tmp += sizeof(double);
470
471 memcpy(tmp, &d->nattributes, sizeof(AttrNumber));
472 tmp += sizeof(AttrNumber);
473
474 memcpy(tmp, d->attributes, sizeof(AttrNumber) * d->nattributes);
475 tmp += sizeof(AttrNumber) * d->nattributes;
476
477 /* protect against overflow */
478 Assert(tmp <= ((char *) output + len));
479 }
480
481 /* make sure we've produced exactly the right amount of data */
482 Assert(tmp == ((char *) output + len));
483
484 return output;
485}

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

Referenced by build_mvdependencies(), and statext_store().

◆ statext_dependencies_validate()

bool statext_dependencies_validate ( const MVDependencies dependencies,
const int2vector stxkeys,
int  numexprs,
int  elevel 
)

Definition at line 604 of file dependencies.c.

607{
609
610 /* Scan through each dependency entry */
611 for (uint32 i = 0; i < dependencies->ndeps; i++)
612 {
613 const MVDependency *dep = dependencies->deps[i];
614
615 /*
616 * Cross-check each attribute in a dependency entry with the extended
617 * stats object definition.
618 */
619 for (int j = 0; j < dep->nattributes; j++)
620 {
622 bool ok = false;
623
624 if (attnum > 0)
625 {
626 /* attribute number in stxkeys */
627 for (int k = 0; k < stxkeys->dim1; k++)
628 {
629 if (attnum == stxkeys->values[k])
630 {
631 ok = true;
632 break;
633 }
634 }
635 }
636 else if ((attnum < 0) && (attnum >= attnum_expr_lowbound))
637 {
638 /* attribute number for an expression */
639 ok = true;
640 }
641
642 if (!ok)
643 {
644 ereport(elevel,
646 errmsg("could not validate \"%s\" object: invalid attribute number %d found",
647 "pg_dependencies", attnum)));
648 return false;
649 }
650 }
651 }
652
653 return true;
654}

References attnum, MVDependency::attributes, MVDependencies::deps, ereport, errcode(), errmsg, fb(), i, j, and MVDependencies::ndeps.

Referenced by extended_statistics_update().