📄 predtest.c
字号:
} iterate_end(clause_info); return result; } break; case CLASS_OR: switch (pclass) { case CLASS_OR: /* * OR-clause R=> OR-clause if A refutes each of B's items */ result = true; iterate_begin(pitem, predicate, pred_info) { if (!predicate_refuted_by_recurse(clause, pitem)) { result = false; break; } } iterate_end(pred_info); return result; case CLASS_AND: /* * OR-clause R=> AND-clause if each of A's items refutes * any of B's items. */ result = true; iterate_begin(citem, clause, clause_info) { bool presult = false; iterate_begin(pitem, predicate, pred_info) { if (predicate_refuted_by_recurse(citem, pitem)) { presult = true; break; } } iterate_end(pred_info); if (!presult) { result = false; /* citem refutes nothing */ break; } } iterate_end(clause_info); return result; case CLASS_ATOM: /* * If B is a NOT-clause, A R=> B if A => B's arg */ not_arg = extract_not_arg(predicate); if (not_arg && predicate_implied_by_recurse(clause, not_arg)) return true; /* * OR-clause R=> atom if each of A's items refutes B */ result = true; iterate_begin(citem, clause, clause_info) { if (!predicate_refuted_by_recurse(citem, predicate)) { result = false; break; } } iterate_end(clause_info); return result; } break; case CLASS_ATOM:#ifdef NOT_USED /* * If A is a NOT-clause, A R=> B if B => A's arg * * Unfortunately not: this would only prove that B is not-TRUE, * not that it's not NULL either. Keep this code as a comment * because it would be useful if we ever had a need for the * weak form of refutation. */ not_arg = extract_not_arg(clause); if (not_arg && predicate_implied_by_recurse(predicate, not_arg)) return true;#endif switch (pclass) { case CLASS_AND: /* * atom R=> AND-clause if A refutes any of B's items */ result = false; iterate_begin(pitem, predicate, pred_info) { if (predicate_refuted_by_recurse(clause, pitem)) { result = true; break; } } iterate_end(pred_info); return result; case CLASS_OR: /* * atom R=> OR-clause if A refutes each of B's items */ result = true; iterate_begin(pitem, predicate, pred_info) { if (!predicate_refuted_by_recurse(clause, pitem)) { result = false; break; } } iterate_end(pred_info); return result; case CLASS_ATOM: /* * If B is a NOT-clause, A R=> B if A => B's arg */ not_arg = extract_not_arg(predicate); if (not_arg && predicate_implied_by_recurse(clause, not_arg)) return true; /* * atom R=> atom is the base case */ return predicate_refuted_by_simple_clause((Expr *) predicate, clause); } break; } /* can't get here */ elog(ERROR, "predicate_classify returned a bogus value"); return false;}/* * predicate_classify * Classify an expression node as AND-type, OR-type, or neither (an atom). * * If the expression is classified as AND- or OR-type, then *info is filled * in with the functions needed to iterate over its components. */static PredClasspredicate_classify(Node *clause, PredIterInfo info){ /* Caller should not pass us NULL, nor a RestrictInfo clause */ Assert(clause != NULL); Assert(!IsA(clause, RestrictInfo)); /* * If we see a List, assume it's an implicit-AND list; this is the correct * semantics for lists of RestrictInfo nodes. */ if (IsA(clause, List)) { info->startup_fn = list_startup_fn; info->next_fn = list_next_fn; info->cleanup_fn = list_cleanup_fn; return CLASS_AND; } /* Handle normal AND and OR boolean clauses */ if (and_clause(clause)) { info->startup_fn = boolexpr_startup_fn; info->next_fn = list_next_fn; info->cleanup_fn = list_cleanup_fn; return CLASS_AND; } if (or_clause(clause)) { info->startup_fn = boolexpr_startup_fn; info->next_fn = list_next_fn; info->cleanup_fn = list_cleanup_fn; return CLASS_OR; } /* Handle ScalarArrayOpExpr */ if (IsA(clause, ScalarArrayOpExpr)) { ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; Node *arraynode = (Node *) lsecond(saop->args); /* * We can break this down into an AND or OR structure, but only if we * know how to iterate through expressions for the array's elements. * We can do that if the array operand is a non-null constant or a * simple ArrayExpr. */ if (arraynode && IsA(arraynode, Const) && !((Const *) arraynode)->constisnull) { info->startup_fn = arrayconst_startup_fn; info->next_fn = arrayconst_next_fn; info->cleanup_fn = arrayconst_cleanup_fn; return saop->useOr ? CLASS_OR : CLASS_AND; } if (arraynode && IsA(arraynode, ArrayExpr) && !((ArrayExpr *) arraynode)->multidims) { info->startup_fn = arrayexpr_startup_fn; info->next_fn = arrayexpr_next_fn; info->cleanup_fn = arrayexpr_cleanup_fn; return saop->useOr ? CLASS_OR : CLASS_AND; } } /* None of the above, so it's an atom */ return CLASS_ATOM;}/* * PredIterInfo routines for iterating over regular Lists. The iteration * state variable is the next ListCell to visit. */static voidlist_startup_fn(Node *clause, PredIterInfo info){ info->state = (void *) list_head((List *) clause);}static Node *list_next_fn(PredIterInfo info){ ListCell *l = (ListCell *) info->state; Node *n; if (l == NULL) return NULL; n = lfirst(l); info->state = (void *) lnext(l); return n;}static voidlist_cleanup_fn(PredIterInfo info){ /* Nothing to clean up */}/* * BoolExpr needs its own startup function, but can use list_next_fn and * list_cleanup_fn. */static voidboolexpr_startup_fn(Node *clause, PredIterInfo info){ info->state = (void *) list_head(((BoolExpr *) clause)->args);}/* * PredIterInfo routines for iterating over a ScalarArrayOpExpr with a * constant array operand. */typedef struct{ OpExpr opexpr; Const constexpr; int next_elem; int num_elems; Datum *elem_values; bool *elem_nulls;} ArrayConstIterState;static voidarrayconst_startup_fn(Node *clause, PredIterInfo info){ ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; ArrayConstIterState *state; Const *arrayconst; ArrayType *arrayval; int16 elmlen; bool elmbyval; char elmalign; /* Create working state struct */ state = (ArrayConstIterState *) palloc(sizeof(ArrayConstIterState)); info->state = (void *) state; /* Deconstruct the array literal */ arrayconst = (Const *) lsecond(saop->args); arrayval = DatumGetArrayTypeP(arrayconst->constvalue); get_typlenbyvalalign(ARR_ELEMTYPE(arrayval), &elmlen, &elmbyval, &elmalign); deconstruct_array(arrayval, ARR_ELEMTYPE(arrayval), elmlen, elmbyval, elmalign, &state->elem_values, &state->elem_nulls, &state->num_elems); /* Set up a dummy OpExpr to return as the per-item node */ state->opexpr.xpr.type = T_OpExpr; state->opexpr.opno = saop->opno; state->opexpr.opfuncid = saop->opfuncid; state->opexpr.opresulttype = BOOLOID; state->opexpr.opretset = false; state->opexpr.args = list_copy(saop->args); /* Set up a dummy Const node to hold the per-element values */ state->constexpr.xpr.type = T_Const; state->constexpr.consttype = ARR_ELEMTYPE(arrayval); state->constexpr.consttypmod = -1; state->constexpr.constlen = elmlen; state->constexpr.constbyval = elmbyval; lsecond(state->opexpr.args) = &state->constexpr; /* Initialize iteration state */ state->next_elem = 0;}static Node *arrayconst_next_fn(PredIterInfo info){ ArrayConstIterState *state = (ArrayConstIterState *) info->state; if (state->next_elem >= state->num_elems) return NULL; state->constexpr.constvalue = state->elem_values[state->next_elem]; state->constexpr.constisnull = state->elem_nulls[state->next_elem]; state->next_elem++; return (Node *) &(state->opexpr);}static voidarrayconst_cleanup_fn(PredIterInfo info){ ArrayConstIterState *state = (ArrayConstIterState *) info->state; pfree(state->elem_values); pfree(state->elem_nulls); list_free(state->opexpr.args); pfree(state);}/* * PredIterInfo routines for iterating over a ScalarArrayOpExpr with a * one-dimensional ArrayExpr array operand. */typedef struct{ OpExpr opexpr; ListCell *next;} ArrayExprIterState;static voidarrayexpr_startup_fn(Node *clause, PredIterInfo info){ ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) clause; ArrayExprIterState *state; ArrayExpr *arrayexpr; /* Create working state struct */ state = (ArrayExprIterState *) palloc(sizeof(ArrayExprIterState)); info->state = (void *) state; /* Set up a dummy OpExpr to return as the per-item node */ state->opexpr.xpr.type = T_OpExpr; state->opexpr.opno = saop->opno; state->opexpr.opfuncid = saop->opfuncid; state->opexpr.opresulttype = BOOLOID; state->opexpr.opretset = false; state->opexpr.args = list_copy(saop->args); /* Initialize iteration variable to first member of ArrayExpr */ arrayexpr = (ArrayExpr *) lsecond(saop->args); state->next = list_head(arrayexpr->elements);}static Node *arrayexpr_next_fn(PredIterInfo info){ ArrayExprIterState *state = (ArrayExprIterState *) info->state; if (state->next == NULL) return NULL; lsecond(state->opexpr.args) = lfirst(state->next); state->next = lnext(state->next); return (Node *) &(state->opexpr);}static voidarrayexpr_cleanup_fn(PredIterInfo info){ ArrayExprIterState *state = (ArrayExprIterState *) info->state; list_free(state->opexpr.args); pfree(state);}/*---------- * predicate_implied_by_simple_clause * Does the predicate implication test for a "simple clause" predicate * and a "simple clause" restriction. * * We return TRUE if able to prove the implication, FALSE if not. * * We have three strategies for determining whether one simple clause * implies another: * * A simple and general way is to see if they are equal(); this works for any * kind of expression. (Actually, there is an implied assumption that the * functions in the expression are immutable, ie dependent only on their input * arguments --- but this was checked for the predicate by the caller.) * * When the predicate is of the form "foo IS NOT NULL", we can conclude that * the predicate is implied if the clause is a strict operator or function * that has "foo" as an input. In this case the clause must yield NULL when * "foo" is NULL, which we can take as equivalent to FALSE because we know * we are within an AND/OR subtree of a WHERE clause. (Again, "foo" is * already known immutable, so the clause will certainly always fail.) * * Finally, we may be able to deduce something using knowledge about btree * operator families; this is encapsulated in btree_predicate_proof(). *---------- */static boolpredicate_implied_by_simple_clause(Expr *predicate, Node *clause){ /* First try the equal() test */ if (equal((Node *) predicate, clause)) return true; /* Next try the IS NOT NULL case */ if (predicate && IsA(predicate, NullTest) && ((NullTest *) predicate)->nulltesttype == IS_NOT_NULL) { Expr *nonnullarg = ((NullTest *) predicate)->arg; /* row IS NOT NULL does not act in the simple way we have in mind */ if (!type_is_rowtype(exprType((Node *) nonnullarg))) { if (is_opclause(clause) && list_member_strip(((OpExpr *) clause)->args, nonnullarg) && op_strict(((OpExpr *) clause)->opno)) return true; if (is_funcclause(clause) && list_member_strip(((FuncExpr *) clause)->args, nonnullarg) && func_strict(((FuncExpr *) clause)->funcid)) return true; } return false; /* we can't succeed below... */ } /* Else try btree operator knowledge */ return btree_predicate_proof(predicate, clause, false);}/*---------- * predicate_refuted_by_simple_clause * Does the predicate refutation test for a "simple clause" predicate * and a "simple clause" restriction. * * We return TRUE if able to prove the refutation, FALSE if not. * * Unlike the implication case, checking for equal() clauses isn't * helpful. * * When the predicate is of the form "foo IS NULL", we can conclude that * the predicate is refuted if the clause is a strict operator or function * that has "foo" as an input (see notes for implication case), or if the * clause is "foo IS NOT NULL". A clause "foo IS NULL" refutes a predicate * "foo IS NOT NULL", but unfortunately does not refute strict predicates, * because we are looking for strong refutation. (The motivation for covering * these cases is to support using IS NULL/IS NOT NULL as partition-defining * constraints.) * * Finally, we may be able to deduce something using knowledge about btree * operator families; this is encapsulated in btree_predicate_proof(). *---------- */static boolpredicate_refuted_by_simple_clause(Expr *predicate, Node *clause){ /* A simple clause can't refute itself */ /* Worth checking because of relation_excluded_by_constraints() */ if ((Node *) predicate == clause) return false; /* Try the predicate-IS-NULL case */ if (predicate && IsA(predicate, NullTest) && ((NullTest *) predicate)->nulltesttype == IS_NULL) { Expr *isnullarg = ((NullTest *) predicate)->arg; /* row IS NULL does not act in the simple way we have in mind */ if (type_is_rowtype(exprType((Node *) isnullarg))) return false; /* Any strict op/func on foo refutes foo IS NULL */ if (is_opclause(clause) && list_member_strip(((OpExpr *) clause)->args, isnullarg) && op_strict(((OpExpr *) clause)->opno)) return true; if (is_funcclause(clause) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -