From 77ba610805e7ef9ba9c9a593ea8b1ca8f98f8bcb Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 7 Jun 2016 17:21:17 -0400 Subject: [PATCH] Revert "Use Foreign Key relationships to infer multi-column join selectivity". This commit reverts 137805f89 as well as the associated commits 015e88942, 5306df283, and 68d704edb. We found multiple bugs in this feature, and there was concern about possible planner slowdown (though to be fair, exhibiting a very large slowdown proved difficult). The way forward requires a considerable rewrite, which may or may not be possible to accomplish in time for beta2. In my judgment reviewing the rewrite will be easier to accomplish starting from a clean slate, so let's temporarily revert what's there now. This also leaves us in a safe state if it turns out to be necessary to postpone the rewrite to the next development cycle. Discussion: <20160429102531.GA13701@huehner.biz> --- src/backend/nodes/outfuncs.c | 13 - src/backend/optimizer/path/costsize.c | 375 +---------------------- src/backend/optimizer/util/plancat.c | 85 +---- src/backend/utils/cache/relcache.c | 75 ----- src/backend/utils/misc/guc.c | 9 - src/include/nodes/nodes.h | 1 - src/include/nodes/relation.h | 22 -- src/include/optimizer/cost.h | 1 - src/include/optimizer/paths.h | 2 - src/include/utils/rel.h | 3 - src/include/utils/relcache.h | 1 - src/test/regress/expected/rangefuncs.out | 29 +- 12 files changed, 25 insertions(+), 591 deletions(-) diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index c2f0e0f8ee..389808c9e9 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -2137,16 +2137,6 @@ _outIndexOptInfo(StringInfo str, const IndexOptInfo *node) /* we don't bother with fields copied from the index AM's API struct */ } -static void -_outForeignKeyOptInfo(StringInfo str, const ForeignKeyOptInfo *node) -{ - WRITE_NODE_TYPE("FOREIGNKEYOPTINFO"); - - WRITE_OID_FIELD(conrelid); - WRITE_OID_FIELD(confrelid); - WRITE_INT_FIELD(nkeys); -} - static void _outEquivalenceClass(StringInfo str, const EquivalenceClass *node) { @@ -3617,9 +3607,6 @@ outNode(StringInfo str, const void *obj) case T_IndexOptInfo: _outIndexOptInfo(str, obj); break; - case T_ForeignKeyOptInfo: - _outForeignKeyOptInfo(str, obj); - break; case T_EquivalenceClass: _outEquivalenceClass(str, obj); break; diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index 4c9d8d9cbd..b39c928eba 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -126,7 +126,6 @@ bool enable_nestloop = true; bool enable_material = true; bool enable_mergejoin = true; bool enable_hashjoin = true; -bool enable_fkey_estimates = true; typedef struct { @@ -3888,361 +3887,6 @@ get_parameterized_joinrel_size(PlannerInfo *root, RelOptInfo *rel, return nrows; } -/* - * quals_match_foreign_key - * Determines if the foreign key is matched by joinquals. - * - * Checks that there are conditions on all columns of the foreign key, matching - * the operator used by the foreign key etc. If such complete match is found, - * the function returns bitmap identifying the matching quals (0-based). - * - * Otherwise (no match at all or incomplete match), NULL is returned. - * - * XXX It seems possible in the future to do something useful when a - * partial match occurs between join and FK, but that is less common - * and that part isn't worked out yet. - */ -static Bitmapset * -quals_match_foreign_key(PlannerInfo *root, ForeignKeyOptInfo *fkinfo, - RelOptInfo *fkrel, RelOptInfo *foreignrel, - List *joinquals) -{ - int i; - int nkeys = fkinfo->nkeys; - Bitmapset *qualmatches = NULL; - Bitmapset *fkmatches = NULL; - - /* - * Loop over each column of the foreign key and build a bitmapset - * of each joinqual which matches. Note that we don't stop when we find - * the first match, as the expression could be duplicated in the - * joinquals, and we want to generate a bitmapset which has bits set for - * every matching join qual. - */ - for (i = 0; i < nkeys; i++) - { - ListCell *lc; - int quallstidx = -1; - - foreach(lc, joinquals) - { - RestrictInfo *rinfo; - OpExpr *clause; - Var *leftvar; - Var *rightvar; - - quallstidx++; - - /* - * Technically we don't need to, but here we skip this qual if - * we've matched it to part of the foreign key already. This - * should prove to be a useful optimization when the quals appear - * in the same order as the foreign key's keys. We need only bother - * doing this when the foreign key is made up of more than 1 set - * of columns, and we're not testing the first column. - */ - if (i > 0 && bms_is_member(quallstidx, qualmatches)) - continue; - - rinfo = (RestrictInfo *) lfirst(lc); - clause = (OpExpr *) rinfo->clause; - - /* only OpExprs are useful for consideration */ - if (!IsA(clause, OpExpr)) - continue; - - /* - * If the operator does not match then there's little point in - * checking the operands. - */ - if (clause->opno != fkinfo->conpfeqop[i]) - continue; - - leftvar = (Var *) get_leftop((Expr *) clause); - rightvar = (Var *) get_rightop((Expr *) clause); - - /* Foreign keys only support Vars, so ignore anything more complex */ - if (!IsA(leftvar, Var) || !IsA(rightvar, Var)) - continue; - - /* - * For RestrictInfos built from an eclass we must consider each - * member of the eclass as rinfo's operands may not belong to the - * foreign key. For efficient tracking of which Vars we've found, - * since we're only tracking 2 Vars, we use a bitmask. We can - * safely finish searching when both of the least significant bits - * are set. - */ - if (rinfo->parent_ec) - { - EquivalenceClass *ec = rinfo->parent_ec; - ListCell *lc2; - int foundvarmask = 0; - - foreach(lc2, ec->ec_members) - { - EquivalenceMember *em = (EquivalenceMember *) lfirst(lc2); - Var *var = (Var *) em->em_expr; - - if (!IsA(var, Var)) - continue; - - if (foreignrel->relid == var->varno && - fkinfo->confkeys[i] == var->varattno) - foundvarmask |= 1; - - else if (fkrel->relid == var->varno && - fkinfo->conkeys[i] == var->varattno) - foundvarmask |= 2; - - /* - * Check if we've found both matches. If found we add - * this qual to the matched list and mark this key as - * matched too. - */ - if (foundvarmask == 3) - { - qualmatches = bms_add_member(qualmatches, quallstidx); - fkmatches = bms_add_member(fkmatches, i); - break; - } - } - } - else - { - /* - * In this non eclass RestrictInfo case we'll check if the left - * and right Vars match to this part of the foreign key. - * Remember that this could be written with the Vars in either - * order, so we test both permutations of the expression. - */ - if ((foreignrel->relid == leftvar->varno) && - (fkrel->relid == rightvar->varno) && - (fkinfo->confkeys[i] == leftvar->varattno) && - (fkinfo->conkeys[i] == rightvar->varattno)) - { - qualmatches = bms_add_member(qualmatches, quallstidx); - fkmatches = bms_add_member(fkmatches, i); - } - else if ((foreignrel->relid == rightvar->varno) && - (fkrel->relid == leftvar->varno) && - (fkinfo->confkeys[i] == rightvar->varattno) && - (fkinfo->conkeys[i] == leftvar->varattno)) - { - qualmatches = bms_add_member(qualmatches, quallstidx); - fkmatches = bms_add_member(fkmatches, i); - } - } - } - } - - /* can't find more matches than columns in the foreign key */ - Assert(bms_num_members(fkmatches) <= nkeys); - - /* Only return the matches if the foreign key is matched fully. */ - if (bms_num_members(fkmatches) == nkeys) - { - bms_free(fkmatches); - return qualmatches; - } - - bms_free(fkmatches); - bms_free(qualmatches); - - return NULL; -} - -/* - * find_best_foreign_key_quals - * Finds the foreign key best matching the joinquals. - * - * Analyzes joinquals to determine if any quals match foreign keys defined the - * two relations (fkrel referencing foreignrel). When multiple foreign keys - * match, we choose the one with the most keys as the best one because of the - * way estimation occurs in clauselist_join_selectivity(). We could choose - * the FK matching the most quals, however we assume the quals may be duplicated. - * - * We also track which joinquals match the current foreign key, so that we can - * easily skip then when computing the selectivity. - * - * When no matching foreign key is found we return 0, otherwise we return the - * number of keys in the foreign key. - * - * Foreign keys matched only partially are currently ignored. - */ -static int -find_best_foreign_key_quals(PlannerInfo *root, RelOptInfo *fkrel, - RelOptInfo *foreignrel, List *joinquals, - Bitmapset **joinqualsbitmap) -{ - Bitmapset *qualbestmatch; - ListCell *lc; - int bestmatchnkeys; - - /* - * fast path out when there's no foreign keys on fkrel, or when use of - * foreign keys for estimation is disabled by GUC - */ - if ((fkrel->fkeylist == NIL) || (!enable_fkey_estimates)) - { - *joinqualsbitmap = NULL; - return 0; - } - - qualbestmatch = NULL; - bestmatchnkeys = 0; - - /* now check the matches for each foreign key defined on the fkrel */ - foreach(lc, fkrel->fkeylist) - { - ForeignKeyOptInfo *fkinfo = (ForeignKeyOptInfo *) lfirst(lc); - Bitmapset *qualsmatched; - - /* - * We make no attempt in checking that this foreign key actually - * references 'foreignrel', the reasoning here is that we may be able - * to match the foreign key to an eclass member Var of a RestrictInfo - * that's in qualslist, this Var may belong to some other relation. - * - * XXX Is this assumption safe in all cases? Maybe not, but does - * it lead to a worse estimate than the previous approach? Doubt it. - */ - qualsmatched = quals_match_foreign_key(root, fkinfo, fkrel, foreignrel, - joinquals); - - /* Did we get a match? And is that match better than a previous one? */ - if (qualsmatched != NULL && fkinfo->nkeys > bestmatchnkeys) - { - /* save the new best match */ - bms_free(qualbestmatch); - qualbestmatch = qualsmatched; - bestmatchnkeys = fkinfo->nkeys; - } - } - - *joinqualsbitmap = qualbestmatch; - return bestmatchnkeys; -} - -/* - * clauselist_join_selectivity - * Estimate selectivity of join clauses either by using foreign key info - * or by using the regular clauselist_selectivity(). - * - * Since selectivity estimates for each joinqual are multiplied together, this - * can cause significant underestimates on the number of join tuples in cases - * where there's more than 1 clause in the join condition. To help ease the - * pain here we make use of foreign keys, and we assume that 1 row will match - * when *all* of the foreign key columns are present in the join condition, any - * additional clauses are estimated using clauselist_selectivity(). - * - * Note this ignores whether the FK is invalid or currently deferred; we don't - * rely on this assumption for correctness of the query, so it is a reasonable - * and safe assumption for planning purposes. - */ -static Selectivity -clauselist_join_selectivity(PlannerInfo *root, List *joinquals, - JoinType jointype, SpecialJoinInfo *sjinfo) -{ - int outerid; - int innerid; - Selectivity sel = 1.0; - Bitmapset *foundfkquals = NULL; - - innerid = -1; - while ((innerid = bms_next_member(sjinfo->min_righthand, innerid)) >= 0) - { - RelOptInfo *innerrel = find_base_rel(root, innerid); - - outerid = -1; - while ((outerid = bms_next_member(sjinfo->min_lefthand, outerid)) >= 0) - { - RelOptInfo *outerrel = find_base_rel(root, outerid); - Bitmapset *outer2inner; - Bitmapset *inner2outer; - int innermatches; - int outermatches; - - /* - * check which quals are matched by a foreign key referencing the - * innerrel. - */ - outermatches = find_best_foreign_key_quals(root, outerrel, - innerrel, joinquals, &outer2inner); - - /* do the same, but with relations swapped */ - innermatches = find_best_foreign_key_quals(root, innerrel, - outerrel, joinquals, &inner2outer); - - /* - * did we find any matches at all? If so we need to see which one is - * the best/longest match - */ - if (outermatches != 0 || innermatches != 0) - { - double referenced_tuples; - bool overlap; - - /* either could be zero, but not both. */ - if (outermatches < innermatches) - { - overlap = bms_overlap(foundfkquals, inner2outer); - - foundfkquals = bms_add_members(foundfkquals, inner2outer); - referenced_tuples = Max(outerrel->tuples, 1.0); - } - else - { - overlap = bms_overlap(foundfkquals, outer2inner); - - foundfkquals = bms_add_members(foundfkquals, outer2inner); - referenced_tuples = Max(innerrel->tuples, 1.0); - } - - /* - * XXX should we ignore these overlapping matches? - * Or perhaps take the Max() or Min()? - */ - if (overlap) - { - if (jointype == JOIN_SEMI || jointype == JOIN_ANTI) - sel = Min(sel,Min(1.0 / (outerrel->tuples / Max(innerrel->tuples, 1.0)), 1.0)); - else - sel = Min(sel, 1.0 / referenced_tuples); - } - else - { - if (jointype == JOIN_SEMI || jointype == JOIN_ANTI) - sel *= Min(1.0 / (outerrel->tuples / Max(innerrel->tuples, 1.0)), 1.0); - else - sel *= 1.0 / referenced_tuples; - } - } - } - } - - /* - * If any non matched quals exist then we build a list of the non-matches - * and use clauselist_selectivity() to estimate the selectivity of these. - */ - if (bms_num_members(foundfkquals) < list_length(joinquals)) - { - ListCell *lc; - int lstidx = 0; - List *nonfkeyclauses = NIL; - - foreach (lc, joinquals) - { - if (!bms_is_member(lstidx, foundfkquals)) - nonfkeyclauses = lappend(nonfkeyclauses, lfirst(lc)); - lstidx++; - } - sel *= clauselist_selectivity(root, nonfkeyclauses, 0, jointype, sjinfo); - } - - return sel; -} - /* * calc_joinrel_size_estimate * Workhorse for set_joinrel_size_estimates and @@ -4289,11 +3933,11 @@ calc_joinrel_size_estimate(PlannerInfo *root, } /* Get the separate selectivities */ - jselec = clauselist_join_selectivity(root, - joinquals, - jointype, - sjinfo); - + jselec = clauselist_selectivity(root, + joinquals, + 0, + jointype, + sjinfo); pselec = clauselist_selectivity(root, pushedquals, 0, @@ -4306,10 +3950,11 @@ calc_joinrel_size_estimate(PlannerInfo *root, } else { - jselec = clauselist_join_selectivity(root, - restrictlist, - jointype, - sjinfo); + jselec = clauselist_selectivity(root, + restrictlist, + 0, + jointype, + sjinfo); pselec = 0.0; /* not used, keep compiler quiet */ } diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index b0b606ebc8..3a585ade74 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -28,7 +28,6 @@ #include "catalog/dependency.h" #include "catalog/heap.h" #include "catalog/pg_am.h" -#include "catalog/pg_constraint.h" #include "foreign/fdwapi.h" #include "miscadmin.h" #include "nodes/makefuncs.h" @@ -42,7 +41,6 @@ #include "rewrite/rewriteManip.h" #include "storage/bufmgr.h" #include "utils/lsyscache.h" -#include "utils/syscache.h" #include "utils/rel.h" #include "utils/snapmgr.h" @@ -96,9 +94,6 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, Relation relation; bool hasindex; List *indexinfos = NIL; - List *fkinfos = NIL; - List *fkoidlist; - ListCell *l; /* * We need not lock the relation since it was already locked, either by @@ -149,6 +144,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, if (hasindex) { List *indexoidlist; + ListCell *l; LOCKMODE lmode; indexoidlist = RelationGetIndexList(relation); @@ -395,85 +391,6 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent, rel->indexlist = indexinfos; - /* - * Load foreign key data. Note this is the definitional data from the - * catalog only and does not lock the referenced tables here. The - * precise definition of the FK is important and may affect the usage - * elsewhere in the planner, e.g. if the constraint is deferred or - * if the constraint is not valid then relying upon this in the executor - * may not be accurate, though might be considered a useful estimate for - * planning purposes. - */ - fkoidlist = RelationGetFKeyList(relation); - - foreach(l, fkoidlist) - { - Oid fkoid = lfirst_oid(l); - HeapTuple htup; - Form_pg_constraint constraint; - ForeignKeyOptInfo *info; - Datum adatum; - bool isnull; - ArrayType *arr; - int numkeys; - int i; - - htup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(fkoid)); - if (!HeapTupleIsValid(htup)) /* should not happen */ - elog(ERROR, "cache lookup failed for constraint %u", fkoid); - constraint = (Form_pg_constraint) GETSTRUCT(htup); - - Assert(constraint->contype == CONSTRAINT_FOREIGN); - - info = makeNode(ForeignKeyOptInfo); - - info->conrelid = constraint->conrelid; - info->confrelid = constraint->confrelid; - - /* conkey */ - adatum = SysCacheGetAttr(CONSTROID, htup, - Anum_pg_constraint_conkey, &isnull); - Assert(!isnull); - - arr = DatumGetArrayTypeP(adatum); - numkeys = ARR_DIMS(arr)[0]; - info->conkeys = (int*)palloc(numkeys * sizeof(int)); - for (i = 0; i < numkeys; i++) - info->conkeys[i] = ((int16 *) ARR_DATA_PTR(arr))[i]; - - /* confkey */ - adatum = SysCacheGetAttr(CONSTROID, htup, - Anum_pg_constraint_confkey, &isnull); - Assert(!isnull); - - arr = DatumGetArrayTypeP(adatum); - Assert(numkeys == ARR_DIMS(arr)[0]); - info->confkeys = (int*)palloc(numkeys * sizeof(int)); - for (i = 0; i < numkeys; i++) - info->confkeys[i] = ((int16 *) ARR_DATA_PTR(arr))[i]; - - /* conpfeqop */ - adatum = SysCacheGetAttr(CONSTROID, htup, - Anum_pg_constraint_conpfeqop, &isnull); - Assert(!isnull); - - arr = DatumGetArrayTypeP(adatum); - Assert(numkeys == ARR_DIMS(arr)[0]); - info->conpfeqop = (Oid*)palloc(numkeys * sizeof(Oid)); - for (i = 0; i < numkeys; i++) - info->conpfeqop[i] = ((Oid *) ARR_DATA_PTR(arr))[i]; - - info->nkeys = numkeys; - - ReleaseSysCache(htup); - - fkinfos = lappend(fkinfos, info); - } - - list_free(fkoidlist); - - rel->fkeylist = fkinfos; - /* Grab foreign-table info using the relcache, while we have it */ if (relation->rd_rel->relkind == RELKIND_FOREIGN_TABLE) { diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 79cc3df590..1b7b99548c 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -2031,7 +2031,6 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc) FreeTupleDesc(relation->rd_att); } list_free(relation->rd_indexlist); - list_free(relation->rd_fkeylist); bms_free(relation->rd_indexattr); bms_free(relation->rd_keyattr); bms_free(relation->rd_idattr); @@ -3957,79 +3956,6 @@ RelationGetIndexList(Relation relation) return result; } -/* - * RelationGetFKeyList -- get a list of foreign key oids - * - * Use an index scan on pg_constraint to load in FK definitions, - * intended for use within the planner, not for enforcing FKs. - * - * Data is ordered by Oid, though this is not critical at this point - * since we do not lock the referenced relations. - */ -List * -RelationGetFKeyList(Relation relation) -{ - Relation conrel; - SysScanDesc conscan; - ScanKeyData skey; - HeapTuple htup; - List *result; - List *oldlist; - MemoryContext oldcxt; - - /* Quick exit if we already computed the list. */ - if (relation->rd_fkeylist) - return list_copy(relation->rd_fkeylist); - - /* Fast path if no FKs... if it doesn't have a trigger, it can't have a FK */ - if (!relation->rd_rel->relhastriggers) - return NIL; - /* - * We build the list we intend to return (in the caller's context) while - * doing the scan. After successfully completing the scan, we copy that - * list into the relcache entry. This avoids cache-context memory leakage - * if we get some sort of error partway through. - */ - result = NIL; - - /* Prepare to scan pg_constraint for entries having conrelid = this rel. */ - ScanKeyInit(&skey, - Anum_pg_constraint_conrelid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(RelationGetRelid(relation))); - - conrel = heap_open(ConstraintRelationId, AccessShareLock); - conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true, - NULL, 1, &skey); - - while (HeapTupleIsValid(htup = systable_getnext(conscan))) - { - Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup); - - /* return only foreign keys */ - if (constraint->contype != CONSTRAINT_FOREIGN) - continue; - - /* Add FK's OID to result list in the proper order */ - result = insert_ordered_oid(result, HeapTupleGetOid(htup)); - } - - systable_endscan(conscan); - - heap_close(conrel, AccessShareLock); - - /* Now save a copy of the completed list in the relcache entry. */ - oldcxt = MemoryContextSwitchTo(CacheMemoryContext); - oldlist = relation->rd_fkeylist; - relation->rd_fkeylist = list_copy(result); - MemoryContextSwitchTo(oldcxt); - - /* Don't leak the old list, if there is one */ - list_free(oldlist); - - return result; -} - /* * insert_ordered_oid * Insert a new Oid into a sorted list of Oids, preserving ordering @@ -4994,7 +4920,6 @@ load_relcache_init_file(bool shared) rel->rd_indexattr = NULL; rel->rd_keyattr = NULL; rel->rd_idattr = NULL; - rel->rd_fkeylist = NIL; rel->rd_createSubid = InvalidSubTransactionId; rel->rd_newRelfilenodeSubid = InvalidSubTransactionId; rel->rd_amcache = NULL; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index e246a9c2f0..edfa39adf4 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -877,15 +877,6 @@ static struct config_bool ConfigureNamesBool[] = true, NULL, NULL, NULL }, - { - {"enable_fkey_estimates", PGC_USERSET, QUERY_TUNING_METHOD, - gettext_noop("Enables use of foreign keys for estimating joins."), - NULL - }, - &enable_fkey_estimates, - true, - NULL, NULL, NULL - }, { {"geqo", PGC_USERSET, QUERY_TUNING_GEQO, diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index ea65f2e453..5953db45a8 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -223,7 +223,6 @@ typedef enum NodeTag T_PlannerGlobal, T_RelOptInfo, T_IndexOptInfo, - T_ForeignKeyOptInfo, T_ParamPathInfo, T_Path, T_IndexPath, diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 45739c3ee7..b1f6cf45f0 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -516,7 +516,6 @@ typedef struct RelOptInfo List *lateral_vars; /* LATERAL Vars and PHVs referenced by rel */ Relids lateral_referencers; /* rels that reference me laterally */ List *indexlist; /* list of IndexOptInfo */ - List *fkeylist; /* list of ForeignKeyOptInfo */ BlockNumber pages; /* size estimates derived from pg_class */ double tuples; double allvisfrac; @@ -623,27 +622,6 @@ typedef struct IndexOptInfo void (*amcostestimate) (); /* AM's cost estimator */ } IndexOptInfo; -/* - * ForeignKeyOptInfo - * Per-foreign-key information for planning/optimization - * - * Only includes columns from pg_constraint related to foreign keys. - * - * conkeys[], confkeys[] and conpfeqop[] each have nkeys entries. - */ -typedef struct ForeignKeyOptInfo -{ - NodeTag type; - - Oid conrelid; /* relation constrained by the foreign key */ - Oid confrelid; /* relation referenced by the foreign key */ - - int nkeys; /* number of columns in the foreign key */ - int *conkeys; /* attnums of columns in the constrained table */ - int *confkeys; /* attnums of columns in the referenced table */ - Oid *conpfeqop; /* OIDs of equality operators used by the FK */ - -} ForeignKeyOptInfo; /* * EquivalenceClasses diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index 58ac1638ec..d4adca6836 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -66,7 +66,6 @@ extern bool enable_nestloop; extern bool enable_material; extern bool enable_mergejoin; extern bool enable_hashjoin; -extern bool enable_fkey_estimates; extern int constraint_exclusion; extern double clamp_row_est(double nrows); diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index e0ac4515c9..f3b25e2419 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -76,8 +76,6 @@ extern Expr *adjust_rowcompare_for_index(RowCompareExpr *clause, int indexcol, List **indexcolnos, bool *var_on_left_p); -extern bool has_matching_fkey(RelOptInfo *rel, RelOptInfo *frel, List *clauses, - bool reverse); /* * tidpath.h diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index a0ba417764..5d354c0f67 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -95,9 +95,6 @@ typedef struct RelationData Oid rd_oidindex; /* OID of unique index on OID, if any */ Oid rd_replidindex; /* OID of replica identity index, if any */ - /* data managed by RelationGetFKList: */ - List *rd_fkeylist; /* OIDs of foreign keys */ - /* data managed by RelationGetIndexAttrBitmap: */ Bitmapset *rd_indexattr; /* identifies columns used in indexes */ Bitmapset *rd_keyattr; /* cols that can be ref'd by foreign keys */ diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h index 7f07c26914..1b4830462d 100644 --- a/src/include/utils/relcache.h +++ b/src/include/utils/relcache.h @@ -38,7 +38,6 @@ extern void RelationClose(Relation relation); * Routines to compute/retrieve additional cached information */ extern List *RelationGetIndexList(Relation relation); -extern List *RelationGetFKeyList(Relation relation); extern Oid RelationGetOidIndex(Relation relation); extern Oid RelationGetReplicaIndex(Relation relation); extern List *RelationGetIndexExpressions(Relation relation); diff --git a/src/test/regress/expected/rangefuncs.out b/src/test/regress/expected/rangefuncs.out index abe0dc983e..00ef421054 100644 --- a/src/test/regress/expected/rangefuncs.out +++ b/src/test/regress/expected/rangefuncs.out @@ -1,19 +1,18 @@ SELECT name, setting FROM pg_settings WHERE name LIKE 'enable%'; - name | setting ------------------------+--------- - enable_bitmapscan | on - enable_fkey_estimates | on - enable_hashagg | on - enable_hashjoin | on - enable_indexonlyscan | on - enable_indexscan | on - enable_material | on - enable_mergejoin | on - enable_nestloop | on - enable_seqscan | on - enable_sort | on - enable_tidscan | on -(12 rows) + name | setting +----------------------+--------- + enable_bitmapscan | on + enable_hashagg | on + enable_hashjoin | on + enable_indexonlyscan | on + enable_indexscan | on + enable_material | on + enable_mergejoin | on + enable_nestloop | on + enable_seqscan | on + enable_sort | on + enable_tidscan | on +(11 rows) CREATE TABLE foo2(fooid int, f2 int); INSERT INTO foo2 VALUES(1, 11); -- 2.30.2