plancat.c
来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 959 行 · 第 1/2 页
C
959 行
if (constr != NULL) { int num_check = constr->num_check; int i; for (i = 0; i < num_check; i++) { Node *cexpr; cexpr = stringToNode(constr->check[i].ccbin); /* * Run each expression through const-simplification and * canonicalization. This is not just an optimization, but is * necessary, because we will be comparing it to * similarly-processed qual clauses, and may fail to detect valid * matches without this. This must match the processing done to * qual clauses in preprocess_expression()! (We can skip the * stuff involving subqueries, however, since we don't allow any * in check constraints.) */ cexpr = eval_const_expressions(root, cexpr); cexpr = (Node *) canonicalize_qual((Expr *) cexpr); /* * Also mark any coercion format fields as "don't care", so that * we can match to both explicit and implicit coercions. */ set_coercionform_dontcare(cexpr); /* Fix Vars to have the desired varno */ if (varno != 1) ChangeVarNodes(cexpr, 1, varno, 0); /* * Finally, convert to implicit-AND format (that is, a List) and * append the resulting item(s) to our output list. */ result = list_concat(result, make_ands_implicit((Expr *) cexpr)); } /* Add NOT NULL constraints in expression form, if requested */ if (include_notnull && constr->has_not_null) { int natts = relation->rd_att->natts; for (i = 1; i <= natts; i++) { Form_pg_attribute att = relation->rd_att->attrs[i - 1]; if (att->attnotnull && !att->attisdropped) { NullTest *ntest = makeNode(NullTest); ntest->arg = (Expr *) makeVar(varno, i, att->atttypid, att->atttypmod, 0); ntest->nulltesttype = IS_NOT_NULL; result = lappend(result, ntest); } } } } heap_close(relation, NoLock); return result;}/* * relation_excluded_by_constraints * * Detect whether the relation need not be scanned because it has either * self-inconsistent restrictions, or restrictions inconsistent with the * relation's CHECK constraints. * * Note: this examines only rel->relid and rel->baserestrictinfo; therefore * it can be called before filling in other fields of the RelOptInfo. */boolrelation_excluded_by_constraints(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte){ List *safe_restrictions; List *constraint_pred; List *safe_constraints; ListCell *lc; /* Skip the test if constraint exclusion is disabled */ if (!constraint_exclusion) return false; /* * Check for self-contradictory restriction clauses. We dare not make * deductions with non-immutable functions, but any immutable clauses that * are self-contradictory allow us to conclude the scan is unnecessary. * * Note: strip off RestrictInfo because predicate_refuted_by() isn't * expecting to see any in its predicate argument. */ safe_restrictions = NIL; foreach(lc, rel->baserestrictinfo) { RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc); if (!contain_mutable_functions((Node *) rinfo->clause)) safe_restrictions = lappend(safe_restrictions, rinfo->clause); } if (predicate_refuted_by(safe_restrictions, safe_restrictions)) return true; /* Only plain relations have constraints */ if (rte->rtekind != RTE_RELATION || rte->inh) return false; /* * OK to fetch the constraint expressions. Include "col IS NOT NULL" * expressions for attnotnull columns, in case we can refute those. */ constraint_pred = get_relation_constraints(root, rte->relid, rel, true); /* * We do not currently enforce that CHECK constraints contain only * immutable functions, so it's necessary to check here. We daren't draw * conclusions from plan-time evaluation of non-immutable functions. Since * they're ANDed, we can just ignore any mutable constraints in the list, * and reason about the rest. */ safe_constraints = NIL; foreach(lc, constraint_pred) { Node *pred = (Node *) lfirst(lc); if (!contain_mutable_functions(pred)) safe_constraints = lappend(safe_constraints, pred); } /* * The constraints are effectively ANDed together, so we can just try to * refute the entire collection at once. This may allow us to make proofs * that would fail if we took them individually. * * Note: we use rel->baserestrictinfo, not safe_restrictions as might seem * an obvious optimization. Some of the clauses might be OR clauses that * have volatile and nonvolatile subclauses, and it's OK to make * deductions with the nonvolatile parts. */ if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo)) return true; return false;}/* * build_physical_tlist * * Build a targetlist consisting of exactly the relation's user attributes, * in order. The executor can special-case such tlists to avoid a projection * step at runtime, so we use such tlists preferentially for scan nodes. * * Exception: if there are any dropped columns, we punt and return NIL. * Ideally we would like to handle the dropped-column case too. However this * creates problems for ExecTypeFromTL, which may be asked to build a tupdesc * for a tlist that includes vars of no-longer-existent types. In theory we * could dig out the required info from the pg_attribute entries of the * relation, but that data is not readily available to ExecTypeFromTL. * For now, we don't apply the physical-tlist optimization when there are * dropped cols. * * We also support building a "physical" tlist for subqueries, functions, * and values lists, since the same optimization can occur in SubqueryScan, * FunctionScan, and ValuesScan nodes. */List *build_physical_tlist(PlannerInfo *root, RelOptInfo *rel){ List *tlist = NIL; Index varno = rel->relid; RangeTblEntry *rte = planner_rt_fetch(varno, root); Relation relation; Query *subquery; Var *var; ListCell *l; int attrno, numattrs; List *colvars; switch (rte->rtekind) { case RTE_RELATION: /* Assume we already have adequate lock */ relation = heap_open(rte->relid, NoLock); numattrs = RelationGetNumberOfAttributes(relation); for (attrno = 1; attrno <= numattrs; attrno++) { Form_pg_attribute att_tup = relation->rd_att->attrs[attrno - 1]; if (att_tup->attisdropped) { /* found a dropped col, so punt */ tlist = NIL; break; } var = makeVar(varno, attrno, att_tup->atttypid, att_tup->atttypmod, 0); tlist = lappend(tlist, makeTargetEntry((Expr *) var, attrno, NULL, false)); } heap_close(relation, NoLock); break; case RTE_SUBQUERY: subquery = rte->subquery; foreach(l, subquery->targetList) { TargetEntry *tle = (TargetEntry *) lfirst(l); /* * A resjunk column of the subquery can be reflected as * resjunk in the physical tlist; we need not punt. */ var = makeVar(varno, tle->resno, exprType((Node *) tle->expr), exprTypmod((Node *) tle->expr), 0); tlist = lappend(tlist, makeTargetEntry((Expr *) var, tle->resno, NULL, tle->resjunk)); } break; case RTE_FUNCTION: expandRTE(rte, varno, 0, true /* include dropped */ , NULL, &colvars); foreach(l, colvars) { var = (Var *) lfirst(l); /* * A non-Var in expandRTE's output means a dropped column; * must punt. */ if (!IsA(var, Var)) { tlist = NIL; break; } tlist = lappend(tlist, makeTargetEntry((Expr *) var, var->varattno, NULL, false)); } break; case RTE_VALUES: expandRTE(rte, varno, 0, false /* dropped not applicable */ , NULL, &colvars); foreach(l, colvars) { var = (Var *) lfirst(l); tlist = lappend(tlist, makeTargetEntry((Expr *) var, var->varattno, NULL, false)); } break; default: /* caller error */ elog(ERROR, "unsupported RTE kind %d in build_physical_tlist", (int) rte->rtekind); break; } return tlist;}/* * restriction_selectivity * * Returns the selectivity of a specified restriction operator clause. * This code executes registered procedures stored in the * operator relation, by calling the function manager. * * See clause_selectivity() for the meaning of the additional parameters. */Selectivityrestriction_selectivity(PlannerInfo *root, Oid operator, List *args, int varRelid){ RegProcedure oprrest = get_oprrest(operator); float8 result; /* * if the oprrest procedure is missing for whatever reason, use a * selectivity of 0.5 */ if (!oprrest) return (Selectivity) 0.5; result = DatumGetFloat8(OidFunctionCall4(oprrest, PointerGetDatum(root), ObjectIdGetDatum(operator), PointerGetDatum(args), Int32GetDatum(varRelid))); if (result < 0.0 || result > 1.0) elog(ERROR, "invalid restriction selectivity: %f", result); return (Selectivity) result;}/* * join_selectivity * * Returns the selectivity of a specified join operator clause. * This code executes registered procedures stored in the * operator relation, by calling the function manager. */Selectivityjoin_selectivity(PlannerInfo *root, Oid operator, List *args, JoinType jointype){ RegProcedure oprjoin = get_oprjoin(operator); float8 result; /* * if the oprjoin procedure is missing for whatever reason, use a * selectivity of 0.5 */ if (!oprjoin) return (Selectivity) 0.5; result = DatumGetFloat8(OidFunctionCall4(oprjoin, PointerGetDatum(root), ObjectIdGetDatum(operator), PointerGetDatum(args), Int16GetDatum(jointype))); if (result < 0.0 || result > 1.0) elog(ERROR, "invalid join selectivity: %f", result); return (Selectivity) result;}/* * find_inheritance_children * * Returns a list containing the OIDs of all relations which * inherit *directly* from the relation with OID 'inhparent'. * * XXX might be a good idea to create an index on pg_inherits' inhparent * field, so that we can use an indexscan instead of sequential scan here. * However, in typical databases pg_inherits won't have enough entries to * justify an indexscan... */List *find_inheritance_children(Oid inhparent){ List *list = NIL; Relation relation; HeapScanDesc scan; HeapTuple inheritsTuple; Oid inhrelid; ScanKeyData key[1]; /* * Can skip the scan if pg_class shows the relation has never had a * subclass. */ if (!has_subclass(inhparent)) return NIL; ScanKeyInit(&key[0], Anum_pg_inherits_inhparent, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(inhparent)); relation = heap_open(InheritsRelationId, AccessShareLock); scan = heap_beginscan(relation, SnapshotNow, 1, key); while ((inheritsTuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid; list = lappend_oid(list, inhrelid); } heap_endscan(scan); heap_close(relation, AccessShareLock); return list;}/* * has_subclass * * In the current implementation, has_subclass returns whether a * particular class *might* have a subclass. It will not return the * correct result if a class had a subclass which was later dropped. * This is because relhassubclass in pg_class is not updated when a * subclass is dropped, primarily because of concurrency concerns. * * Currently has_subclass is only used as an efficiency hack to skip * unnecessary inheritance searches, so this is OK. */boolhas_subclass(Oid relationId){ HeapTuple tuple; bool result; tuple = SearchSysCache(RELOID, ObjectIdGetDatum(relationId), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for relation %u", relationId); result = ((Form_pg_class) GETSTRUCT(tuple))->relhassubclass; ReleaseSysCache(tuple); return result;}/* * has_unique_index * * Detect whether there is a unique index on the specified attribute * of the specified relation, thus allowing us to conclude that all * the (non-null) values of the attribute are distinct. */boolhas_unique_index(RelOptInfo *rel, AttrNumber attno){ ListCell *ilist; foreach(ilist, rel->indexlist) { IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist); /* * Note: ignore partial indexes, since they don't allow us to conclude * that all attr values are distinct. We don't take any interest in * expressional indexes either. Also, a multicolumn unique index * doesn't allow us to conclude that just the specified attr is * unique. */ if (index->unique && index->ncolumns == 1 && index->indexkeys[0] == attno && index->indpred == NIL) return true; } return false;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?