📄 clauses.c
字号:
else aggtranstypmod = -1; avgwidth = get_typavgwidth(aggtranstype, aggtranstypmod); avgwidth = MAXALIGN(avgwidth); counts->transitionSpace += avgwidth + 2 * sizeof(void *); } /* * Complain if the aggregate's argument contains any aggregates; * nested agg functions are semantically nonsensical. */ if (contain_agg_clause((Node *) aggref->target)) ereport(ERROR, (errcode(ERRCODE_GROUPING_ERROR), errmsg("aggregate function calls may not be nested"))); /* * Having checked that, we need not recurse into the argument. */ return false; } Assert(!IsA(node, SubLink)); return expression_tree_walker(node, count_agg_clauses_walker, (void *) counts);}/***************************************************************************** * Support for expressions returning sets *****************************************************************************//* * expression_returns_set * Test whether an expression returns a set result. * * Because we use expression_tree_walker(), this can also be applied to * whole targetlists; it'll produce TRUE if any one of the tlist items * returns a set. */boolexpression_returns_set(Node *clause){ return expression_returns_set_walker(clause, NULL);}static boolexpression_returns_set_walker(Node *node, void *context){ if (node == NULL) return false; if (IsA(node, FuncExpr)) { FuncExpr *expr = (FuncExpr *) node; if (expr->funcretset) return true; /* else fall through to check args */ } if (IsA(node, OpExpr)) { OpExpr *expr = (OpExpr *) node; if (expr->opretset) return true; /* else fall through to check args */ } /* Avoid recursion for some cases that can't return a set */ if (IsA(node, Aggref)) return false; if (IsA(node, DistinctExpr)) return false; if (IsA(node, ScalarArrayOpExpr)) return false; if (IsA(node, BoolExpr)) return false; if (IsA(node, SubLink)) return false; if (IsA(node, SubPlan)) return false; if (IsA(node, ArrayExpr)) return false; if (IsA(node, RowExpr)) return false; if (IsA(node, CoalesceExpr)) return false; if (IsA(node, MinMaxExpr)) return false; if (IsA(node, NullIfExpr)) return false; return expression_tree_walker(node, expression_returns_set_walker, context);}/***************************************************************************** * Subplan clause manipulation *****************************************************************************//* * contain_subplans * Recursively search for subplan nodes within a clause. * * If we see a SubLink node, we will return TRUE. This is only possible if * the expression tree hasn't yet been transformed by subselect.c. We do not * know whether the node will produce a true subplan or just an initplan, * but we make the conservative assumption that it will be a subplan. * * Returns true if any subplan found. */boolcontain_subplans(Node *clause){ return contain_subplans_walker(clause, NULL);}static boolcontain_subplans_walker(Node *node, void *context){ if (node == NULL) return false; if (IsA(node, SubPlan) || IsA(node, SubLink)) return true; /* abort the tree traversal and return true */ return expression_tree_walker(node, contain_subplans_walker, context);}/***************************************************************************** * Check clauses for mutable functions *****************************************************************************//* * contain_mutable_functions * Recursively search for mutable functions within a clause. * * Returns true if any mutable function (or operator implemented by a * mutable function) is found. This test is needed so that we don't * mistakenly think that something like "WHERE random() < 0.5" can be treated * as a constant qualification. * * XXX we do not examine sub-selects to see if they contain uses of * mutable functions. It's not real clear if that is correct or not... */boolcontain_mutable_functions(Node *clause){ return contain_mutable_functions_walker(clause, NULL);}static boolcontain_mutable_functions_walker(Node *node, void *context){ if (node == NULL) return false; if (IsA(node, FuncExpr)) { FuncExpr *expr = (FuncExpr *) node; if (func_volatile(expr->funcid) != PROVOLATILE_IMMUTABLE) return true; /* else fall through to check args */ } if (IsA(node, OpExpr)) { OpExpr *expr = (OpExpr *) node; if (op_volatile(expr->opno) != PROVOLATILE_IMMUTABLE) return true; /* else fall through to check args */ } if (IsA(node, DistinctExpr)) { DistinctExpr *expr = (DistinctExpr *) node; if (op_volatile(expr->opno) != PROVOLATILE_IMMUTABLE) return true; /* else fall through to check args */ } if (IsA(node, ScalarArrayOpExpr)) { ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node; if (op_volatile(expr->opno) != PROVOLATILE_IMMUTABLE) return true; /* else fall through to check args */ } if (IsA(node, NullIfExpr)) { NullIfExpr *expr = (NullIfExpr *) node; if (op_volatile(expr->opno) != PROVOLATILE_IMMUTABLE) return true; /* else fall through to check args */ } if (IsA(node, SubLink)) { SubLink *sublink = (SubLink *) node; ListCell *opid; foreach(opid, sublink->operOids) { if (op_volatile(lfirst_oid(opid)) != PROVOLATILE_IMMUTABLE) return true; } /* else fall through to check args */ } return expression_tree_walker(node, contain_mutable_functions_walker, context);}/***************************************************************************** * Check clauses for volatile functions *****************************************************************************//* * contain_volatile_functions * Recursively search for volatile functions within a clause. * * Returns true if any volatile function (or operator implemented by a * volatile function) is found. This test prevents invalid conversions * of volatile expressions into indexscan quals. * * XXX we do not examine sub-selects to see if they contain uses of * volatile functions. It's not real clear if that is correct or not... */boolcontain_volatile_functions(Node *clause){ return contain_volatile_functions_walker(clause, NULL);}static boolcontain_volatile_functions_walker(Node *node, void *context){ if (node == NULL) return false; if (IsA(node, FuncExpr)) { FuncExpr *expr = (FuncExpr *) node; if (func_volatile(expr->funcid) == PROVOLATILE_VOLATILE) return true; /* else fall through to check args */ } if (IsA(node, OpExpr)) { OpExpr *expr = (OpExpr *) node; if (op_volatile(expr->opno) == PROVOLATILE_VOLATILE) return true; /* else fall through to check args */ } if (IsA(node, DistinctExpr)) { DistinctExpr *expr = (DistinctExpr *) node; if (op_volatile(expr->opno) == PROVOLATILE_VOLATILE) return true; /* else fall through to check args */ } if (IsA(node, ScalarArrayOpExpr)) { ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node; if (op_volatile(expr->opno) == PROVOLATILE_VOLATILE) return true; /* else fall through to check args */ } if (IsA(node, NullIfExpr)) { NullIfExpr *expr = (NullIfExpr *) node; if (op_volatile(expr->opno) == PROVOLATILE_VOLATILE) return true; /* else fall through to check args */ } if (IsA(node, SubLink)) { SubLink *sublink = (SubLink *) node; ListCell *opid; foreach(opid, sublink->operOids) { if (op_volatile(lfirst_oid(opid)) == PROVOLATILE_VOLATILE) return true; } /* else fall through to check args */ } return expression_tree_walker(node, contain_volatile_functions_walker, context);}/***************************************************************************** * Check clauses for nonstrict functions *****************************************************************************//* * contain_nonstrict_functions * Recursively search for nonstrict functions within a clause. * * Returns true if any nonstrict construct is found --- ie, anything that * could produce non-NULL output with a NULL input. * * The idea here is that the caller has verified that the expression contains * one or more Var or Param nodes (as appropriate for the caller's need), and * now wishes to prove that the expression result will be NULL if any of these * inputs is NULL. If we return false, then the proof succeeded. */boolcontain_nonstrict_functions(Node *clause){ return contain_nonstrict_functions_walker(clause, NULL);}static boolcontain_nonstrict_functions_walker(Node *node, void *context){ if (node == NULL) return false; if (IsA(node, Aggref)) { /* an aggregate could return non-null with null input */ return true; } if (IsA(node, ArrayRef)) { /* array assignment is nonstrict */ if (((ArrayRef *) node)->refassgnexpr != NULL) return true; /* else fall through to check args */ } if (IsA(node, FuncExpr)) { FuncExpr *expr = (FuncExpr *) node; if (!func_strict(expr->funcid)) return true; /* else fall through to check args */ } if (IsA(node, OpExpr)) { OpExpr *expr = (OpExpr *) node; if (!op_strict(expr->opno)) return true; /* else fall through to check args */ } if (IsA(node, DistinctExpr)) { /* IS DISTINCT FROM is inherently non-strict */ return true; } if (IsA(node, ScalarArrayOpExpr)) { /* inherently non-strict, consider null scalar and empty array */ return true; } if (IsA(node, BoolExpr)) { BoolExpr *expr = (BoolExpr *) node; switch (expr->boolop) { case AND_EXPR: case OR_EXPR: /* AND, OR are inherently non-strict */ return true; default: break; } } if (IsA(node, SubLink)) { /* In some cases a sublink might be strict, but in general not */ return true; } if (IsA(node, SubPlan)) return true; if (IsA(node, FieldStore)) return true; if (IsA(node, CaseExpr)) return true; if (IsA(node, CaseWhen)) return true; /* NB: ArrayExpr might someday be nonstrict */ if (IsA(node, RowExpr)) return true; if (IsA(node, CoalesceExpr)) return true; if (IsA(node, MinMaxExpr)) return true; if (IsA(node, NullIfExpr)) return true; if (IsA(node, NullTest)) return true; if (IsA(node, BooleanTest)) return true; return expression_tree_walker(node, contain_nonstrict_functions_walker, context);}/***************************************************************************** * Check for "pseudo-constant" clauses *****************************************************************************//* * is_pseudo_constant_clause * Detect whether a clause is "constant", ie, it contains no variables * of the current query level and no uses of volatile functions. * Such a clause is not necessarily a true constant: it can still contain * Params and outer-level Vars, not to mention functions whose results * may vary from one statement to the next. However, the clause's value * will be constant over any one scan of the current query, so it can be * used as an indexscan key or (if a top-level qual) can be pushed up to * become a gating qual. */boolis_pseudo_constant_clause(Node *clause){ /* * We could implement this check in one recursive scan. But since the * check for volatile functions is both moderately expensive and unlikely * to fail, it seems better to look for Vars first and only check for * volatile functions if we find no Vars. */ if (!contain_var_clause(clause) && !contain_volatile_functions(clause)) return true; return false;}/* * is_pseudo_constant_clause_relids * Same as above, except caller already has available the var membership * of the clause; this lets us avoid the contain_var_clause() scan. */boolis_pseudo_constant_clause_relids(Node *clause, Relids relids){ if (bms_is_empty(relids) && !contain_volatile_functions(clause)) return true; return false;}/* * pull_constant_clauses * Scan through a list of qualifications and separate "constant" quals * from those that are not.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -