clauses.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,256 行 · 第 1/5 页
C
2,256 行
/*------------------------------------------------------------------------- * * clauses.c * routines to manipulate qualification clauses * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.154.2.2 2004/01/28 00:05:25 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT * Andrew Yu Nov 3, 1994 clause.c and clauses.c combined * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/pg_language.h"#include "catalog/pg_proc.h"#include "catalog/pg_type.h"#include "executor/executor.h"#include "miscadmin.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/cost.h"#include "optimizer/planmain.h"#include "optimizer/var.h"#include "parser/analyze.h"#include "parser/parse_clause.h"#include "parser/parse_expr.h"#include "tcop/tcopprot.h"#include "utils/acl.h"#include "utils/builtins.h"#include "utils/datum.h"#include "utils/lsyscache.h"#include "utils/memutils.h"#include "utils/syscache.h"/* note that pg_type.h hardwires size of bool as 1 ... duplicate it */#define MAKEBOOLCONST(val,isnull) \ ((Node *) makeConst(BOOLOID, 1, (Datum) (val), (isnull), true))typedef struct{ int nargs; List *args; int *usecounts;} substitute_actual_parameters_context;static bool contain_agg_clause_walker(Node *node, void *context);static bool contain_distinct_agg_clause_walker(Node *node, void *context);static bool count_agg_clause_walker(Node *node, int *count);static bool expression_returns_set_walker(Node *node, void *context);static bool contain_subplans_walker(Node *node, void *context);static bool contain_mutable_functions_walker(Node *node, void *context);static bool contain_volatile_functions_walker(Node *node, void *context);static bool contain_nonstrict_functions_walker(Node *node, void *context);static Node *eval_const_expressions_mutator(Node *node, List *active_fns);static Expr *simplify_function(Oid funcid, Oid result_type, List *args, bool allow_inline, List *active_fns);static Expr *evaluate_function(Oid funcid, Oid result_type, List *args, HeapTuple func_tuple);static Expr *inline_function(Oid funcid, Oid result_type, List *args, HeapTuple func_tuple, List *active_fns);static Node *substitute_actual_parameters(Node *expr, int nargs, List *args, int *usecounts);static Node *substitute_actual_parameters_mutator(Node *node, substitute_actual_parameters_context *context);static void sql_inline_error_callback(void *arg);static Expr *evaluate_expr(Expr *expr, Oid result_type);/***************************************************************************** * OPERATOR clause functions *****************************************************************************//* * make_opclause * Creates an operator clause given its operator info, left operand, * and right operand (pass NULL to create single-operand clause). */Expr *make_opclause(Oid opno, Oid opresulttype, bool opretset, Expr *leftop, Expr *rightop){ OpExpr *expr = makeNode(OpExpr); expr->opno = opno; expr->opfuncid = InvalidOid; expr->opresulttype = opresulttype; expr->opretset = opretset; if (rightop) expr->args = makeList2(leftop, rightop); else expr->args = makeList1(leftop); return (Expr *) expr;}/* * get_leftop * * Returns the left operand of a clause of the form (op expr expr) * or (op expr) */Node *get_leftop(Expr *clause){ OpExpr *expr = (OpExpr *) clause; if (expr->args != NIL) return lfirst(expr->args); else return NULL;}/* * get_rightop * * Returns the right operand in a clause of the form (op expr expr). * NB: result will be NULL if applied to a unary op clause. */Node *get_rightop(Expr *clause){ OpExpr *expr = (OpExpr *) clause; if (expr->args != NIL && lnext(expr->args) != NIL) return lfirst(lnext(expr->args)); else return NULL;}/***************************************************************************** * NOT clause functions *****************************************************************************//* * not_clause * * Returns t iff this is a 'not' clause: (NOT expr). */boolnot_clause(Node *clause){ return (clause != NULL && IsA(clause, BoolExpr) && ((BoolExpr *) clause)->boolop == NOT_EXPR);}/* * make_notclause * * Create a 'not' clause given the expression to be negated. */Expr *make_notclause(Expr *notclause){ BoolExpr *expr = makeNode(BoolExpr); expr->boolop = NOT_EXPR; expr->args = makeList1(notclause); return (Expr *) expr;}/* * get_notclausearg * * Retrieve the clause within a 'not' clause */Expr *get_notclausearg(Expr *notclause){ return lfirst(((BoolExpr *) notclause)->args);}/***************************************************************************** * OR clause functions *****************************************************************************//* * or_clause * * Returns t iff the clause is an 'or' clause: (OR { expr }). */boolor_clause(Node *clause){ return (clause != NULL && IsA(clause, BoolExpr) && ((BoolExpr *) clause)->boolop == OR_EXPR);}/* * make_orclause * * Creates an 'or' clause given a list of its subclauses. */Expr *make_orclause(List *orclauses){ BoolExpr *expr = makeNode(BoolExpr); expr->boolop = OR_EXPR; expr->args = orclauses; return (Expr *) expr;}/***************************************************************************** * AND clause functions *****************************************************************************//* * and_clause * * Returns t iff its argument is an 'and' clause: (AND { expr }). */booland_clause(Node *clause){ return (clause != NULL && IsA(clause, BoolExpr) && ((BoolExpr *) clause)->boolop == AND_EXPR);}/* * make_andclause * * Creates an 'and' clause given a list of its subclauses. */Expr *make_andclause(List *andclauses){ BoolExpr *expr = makeNode(BoolExpr); expr->boolop = AND_EXPR; expr->args = andclauses; return (Expr *) expr;}/* * make_and_qual * * Variant of make_andclause for ANDing two qual conditions together. * Qual conditions have the property that a NULL nodetree is interpreted * as 'true'. */Node *make_and_qual(Node *qual1, Node *qual2){ if (qual1 == NULL) return qual2; if (qual2 == NULL) return qual1; return (Node *) make_andclause(makeList2(qual1, qual2));}/* * Sometimes (such as in the result of canonicalize_qual or the input of * ExecQual), we use lists of expression nodes with implicit AND semantics. * * These functions convert between an AND-semantics expression list and the * ordinary representation of a boolean expression. * * Note that an empty list is considered equivalent to TRUE. */Expr *make_ands_explicit(List *andclauses){ if (andclauses == NIL) return (Expr *) MAKEBOOLCONST(true, false); else if (lnext(andclauses) == NIL) return (Expr *) lfirst(andclauses); else return make_andclause(andclauses);}List *make_ands_implicit(Expr *clause){ /* * NB: because the parser sets the qual field to NULL in a query that * has no WHERE clause, we must consider a NULL input clause as TRUE, * even though one might more reasonably think it FALSE. Grumble. If * this causes trouble, consider changing the parser's behavior. */ if (clause == NULL) return NIL; /* NULL -> NIL list == TRUE */ else if (and_clause((Node *) clause)) return ((BoolExpr *) clause)->args; else if (IsA(clause, Const) && !((Const *) clause)->constisnull && DatumGetBool(((Const *) clause)->constvalue)) return NIL; /* constant TRUE input -> NIL list */ else return makeList1(clause);}/***************************************************************************** * Aggregate-function clause manipulation *****************************************************************************//* * contain_agg_clause * Recursively search for Aggref nodes within a clause. * * Returns true if any aggregate found. * * This does not descend into subqueries, and so should be used only after * reduction of sublinks to subplans, or in contexts where it's known there * are no subqueries. There mustn't be outer-aggregate references either. * * (If you want something like this but able to deal with subqueries, * see rewriteManip.c's checkExprHasAggs().) */boolcontain_agg_clause(Node *clause){ return contain_agg_clause_walker(clause, NULL);}static boolcontain_agg_clause_walker(Node *node, void *context){ if (node == NULL) return false; if (IsA(node, Aggref)) { Assert(((Aggref *) node)->agglevelsup == 0); return true; /* abort the tree traversal and return * true */ } Assert(!IsA(node, SubLink)); return expression_tree_walker(node, contain_agg_clause_walker, context);}/* * contain_distinct_agg_clause * Recursively search for DISTINCT Aggref nodes within a clause. * * Returns true if any DISTINCT aggregate found. * * This does not descend into subqueries, and so should be used only after * reduction of sublinks to subplans, or in contexts where it's known there * are no subqueries. There mustn't be outer-aggregate references either. */boolcontain_distinct_agg_clause(Node *clause){ return contain_distinct_agg_clause_walker(clause, NULL);}static boolcontain_distinct_agg_clause_walker(Node *node, void *context){ if (node == NULL) return false; if (IsA(node, Aggref)) { Assert(((Aggref *) node)->agglevelsup == 0); if (((Aggref *) node)->aggdistinct) return true; /* abort the tree traversal and return * true */ } Assert(!IsA(node, SubLink)); return expression_tree_walker(node, contain_distinct_agg_clause_walker, context);}/* * count_agg_clause * Recursively count the Aggref nodes in an expression tree. * * Note: this also checks for nested aggregates, which are an error. * * This does not descend into subqueries, and so should be used only after * reduction of sublinks to subplans, or in contexts where it's known there * are no subqueries. There mustn't be outer-aggregate references either. */intcount_agg_clause(Node *clause){ int result = 0; count_agg_clause_walker(clause, &result); return result;}static boolcount_agg_clause_walker(Node *node, int *count){ if (node == NULL) return false; if (IsA(node, Aggref)) { Assert(((Aggref *) node)->agglevelsup == 0); (*count)++; /* * Complain if the aggregate's argument contains any aggregates; * nested agg functions are semantically nonsensical. */ if (contain_agg_clause((Node *) ((Aggref *) node)->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_clause_walker, (void *) count);}/***************************************************************************** * 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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?