clauses.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:23k
- /*-------------------------------------------------------------------------
- *
- * clauses.c
- * routines to manipulate qualification clauses
- *
- * Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.37.2.1 1999/08/02 06:27:07 scrappy Exp $
- *
- * HISTORY
- * AUTHOR DATE MAJOR EVENT
- * Andrew Yu Nov 3, 1994 clause.c and clauses.c combined
- *
- *-------------------------------------------------------------------------
- */
- #include "postgres.h"
- #include "catalog/pg_operator.h"
- #include "nodes/makefuncs.h"
- #include "nodes/nodeFuncs.h"
- #include "nodes/plannodes.h"
- #include "optimizer/clauses.h"
- #include "optimizer/internal.h"
- #include "optimizer/var.h"
- #include "utils/lsyscache.h"
- static bool fix_opid_walker(Node *node, void *context);
- Expr *
- make_clause(int type, Node *oper, List *args)
- {
- if (type == AND_EXPR || type == OR_EXPR || type == NOT_EXPR ||
- type == OP_EXPR || type == FUNC_EXPR)
- {
- Expr *expr = makeNode(Expr);
- /*
- * assume type checking already done and we don't need the type of
- * the expr any more.
- */
- expr->typeOid = InvalidOid;
- expr->opType = type;
- expr->oper = oper; /* ignored for AND, OR, NOT */
- expr->args = args;
- return expr;
- }
- else
- {
- elog(ERROR, "make_clause: unsupported type %d", type);
- /* will this ever happen? translated from lispy C code - ay 10/94 */
- return (Expr *) args;
- }
- }
- /*****************************************************************************
- * OPERATOR clause functions
- *****************************************************************************/
- /*
- * is_opclause
- *
- * Returns t iff the clause is an operator clause:
- * (op expr expr) or (op expr).
- *
- * [historical note: is_clause has the exact functionality and is used
- * throughout the code. They're renamed to is_opclause for clarity.
- * - ay 10/94.]
- */
- bool
- is_opclause(Node *clause)
- {
- return (clause != NULL &&
- nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == OP_EXPR);
- }
- /*
- * make_opclause
- * Creates a clause given its operator left operand and right
- * operand (if it is non-null).
- *
- */
- Expr *
- make_opclause(Oper *op, Var *leftop, Var *rightop)
- {
- Expr *expr = makeNode(Expr);
- expr->typeOid = InvalidOid; /* assume type checking done */
- expr->opType = OP_EXPR;
- expr->oper = (Node *) op;
- if (rightop)
- expr->args = lcons(leftop, lcons(rightop, NIL));
- else
- expr->args = lcons(leftop, NIL);
- return expr;
- }
- /*
- * get_leftop
- *
- * Returns the left operand of a clause of the form (op expr expr)
- * or (op expr)
- * NB: it is assumed (for now) that all expr must be Var nodes
- */
- Var *
- get_leftop(Expr *clause)
- {
- if (clause->args != NULL)
- return lfirst(clause->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.
- */
- Var *
- get_rightop(Expr *clause)
- {
- if (clause->args != NULL && lnext(clause->args) != NULL)
- return lfirst(lnext(clause->args));
- else
- return NULL;
- }
- /*****************************************************************************
- * FUNC clause functions
- *****************************************************************************/
- /*
- * is_funcclause
- *
- * Returns t iff the clause is a function clause: (func { expr }).
- *
- */
- bool
- is_funcclause(Node *clause)
- {
- return (clause != NULL &&
- nodeTag(clause) == T_Expr &&
- ((Expr *) clause)->opType == FUNC_EXPR);
- }
- /*
- * make_funcclause
- *
- * Creates a function clause given the FUNC node and the functional
- * arguments.
- *
- */
- Expr *
- make_funcclause(Func *func, List *funcargs)
- {
- Expr *expr = makeNode(Expr);
- expr->typeOid = InvalidOid; /* assume type checking done */
- expr->opType = FUNC_EXPR;
- expr->oper = (Node *) func;
- expr->args = funcargs;
- return expr;
- }
- /*****************************************************************************
- * OR clause functions
- *****************************************************************************/
- /*
- * or_clause
- *
- * Returns t iff the clause is an 'or' clause: (OR { expr }).
- *
- */
- bool
- or_clause(Node *clause)
- {
- return clause != NULL &&
- nodeTag(clause) == T_Expr &&
- ((Expr *) clause)->opType == OR_EXPR;
- }
- /*
- * make_orclause
- *
- * Creates an 'or' clause given a list of its subclauses.
- *
- */
- Expr *
- make_orclause(List *orclauses)
- {
- Expr *expr = makeNode(Expr);
- expr->typeOid = InvalidOid; /* assume type checking done */
- expr->opType = OR_EXPR;
- expr->oper = NULL;
- expr->args = orclauses;
- return expr;
- }
- /*****************************************************************************
- * NOT clause functions
- *****************************************************************************/
- /*
- * not_clause
- *
- * Returns t iff this is a 'not' clause: (NOT expr).
- *
- */
- bool
- not_clause(Node *clause)
- {
- return (clause != NULL &&
- nodeTag(clause) == T_Expr &&
- ((Expr *) clause)->opType == NOT_EXPR);
- }
- /*
- * make_notclause
- *
- * Create a 'not' clause given the expression to be negated.
- *
- */
- Expr *
- make_notclause(Expr *notclause)
- {
- Expr *expr = makeNode(Expr);
- expr->typeOid = InvalidOid; /* assume type checking done */
- expr->opType = NOT_EXPR;
- expr->oper = NULL;
- expr->args = lcons(notclause, NIL);
- return expr;
- }
- /*
- * get_notclausearg
- *
- * Retrieve the clause within a 'not' clause
- *
- */
- Expr *
- get_notclausearg(Expr *notclause)
- {
- return lfirst(notclause->args);
- }
- /*****************************************************************************
- * AND clause functions
- *****************************************************************************/
- /*
- * and_clause
- *
- * Returns t iff its argument is an 'and' clause: (AND { expr }).
- *
- */
- bool
- and_clause(Node *clause)
- {
- return (clause != NULL &&
- nodeTag(clause) == T_Expr &&
- ((Expr *) clause)->opType == AND_EXPR);
- }
- /*
- * make_andclause
- *
- * Create an 'and' clause given its arguments in a list.
- *
- */
- Expr *
- make_andclause(List *andclauses)
- {
- Expr *expr = makeNode(Expr);
- expr->typeOid = InvalidOid; /* assume type checking done */
- expr->opType = AND_EXPR;
- expr->oper = NULL;
- expr->args = andclauses;
- return expr;
- }
- /*****************************************************************************
- * CASE clause functions
- *****************************************************************************/
- /*
- * case_clause
- *
- * Returns t iff its argument is a 'case' clause: (CASE { expr }).
- *
- */
- bool
- case_clause(Node *clause)
- {
- return (clause != NULL &&
- nodeTag(clause) == T_CaseExpr);
- }
- /*****************************************************************************
- * *
- * *
- * *
- *****************************************************************************/
- /*
- * pull_constant_clauses
- * Scans through a list of qualifications and find those that
- * contain no variables.
- *
- * Returns a list of the constant clauses in constantQual and the remaining
- * quals as the return value.
- *
- */
- List *
- pull_constant_clauses(List *quals, List **constantQual)
- {
- List *q;
- List *constqual = NIL;
- List *restqual = NIL;
- foreach(q, quals)
- {
- if (!contain_var_clause(lfirst(q)))
- constqual = lcons(lfirst(q), constqual);
- else
- restqual = lcons(lfirst(q), restqual);
- }
- freeList(quals);
- *constantQual = constqual;
- return restqual;
- }
- /*
- * clause_relids_vars
- * Retrieves relids and vars appearing within a clause.
- * Returns ((relid1 relid2 ... relidn) (var1 var2 ... varm)) where
- * vars appear in the clause this is done by recursively searching
- * through the left and right operands of a clause.
- *
- * Returns the list of relids and vars.
- *
- */
- void
- clause_get_relids_vars(Node *clause, Relids *relids, List **vars)
- {
- List *clvars = pull_var_clause(clause);
- List *var_list = NIL;
- List *varno_list = NIL;
- List *i;
- foreach(i, clvars)
- {
- Var *var = (Var *) lfirst(i);
- List *vi;
- Assert(var->varlevelsup == 0);
- if (!intMember(var->varno, varno_list))
- varno_list = lappendi(varno_list, var->varno);
- foreach(vi, var_list)
- {
- Var *in_list = (Var *) lfirst(vi);
- if (in_list->varno == var->varno &&
- in_list->varattno == var->varattno)
- break;
- }
- if (vi == NIL)
- var_list = lappend(var_list, var);
- }
- *relids = varno_list;
- *vars = var_list;
- }
- /*
- * NumRelids
- * (formerly clause_relids)
- *
- * Returns the number of different relations referenced in 'clause'.
- */
- int
- NumRelids(Node *clause)
- {
- List *vars = pull_var_clause(clause);
- List *var_list = NIL;
- List *i;
- foreach(i, vars)
- {
- Var *var = (Var *) lfirst(i);
- if (!intMember(var->varno, var_list))
- var_list = lconsi(var->varno, var_list);
- }
- return length(var_list);
- }
- /*
- * contains_not
- *
- * Returns t iff the clause is a 'not' clause or if any of the
- * subclauses within an 'or' clause contain 'not's.
- *
- * NOTE that only the top-level AND/OR structure is searched for NOTs;
- * we are not interested in buried substructure.
- */
- bool
- contains_not(Node *clause)
- {
- if (single_node(clause))
- return false;
- if (not_clause(clause))
- return true;
- if (or_clause(clause) || and_clause(clause))
- {
- List *a;
- foreach(a, ((Expr *) clause)->args)
- {
- if (contains_not(lfirst(a)))
- return true;
- }
- }
- return false;
- }
- /*
- * is_joinable
- *
- * Returns t iff 'clause' is a valid join clause.
- *
- */
- bool
- is_joinable(Node *clause)
- {
- Node *leftop,
- *rightop;
- if (!is_opclause(clause))
- return false;
- leftop = (Node *) get_leftop((Expr *) clause);
- rightop = (Node *) get_rightop((Expr *) clause);
- if (!rightop)
- return false; /* unary opclauses need not apply */
- /*
- * One side of the clause (i.e. left or right operands) must either be
- * a var node ...
- */
- if (IsA(leftop, Var) ||IsA(rightop, Var))
- return true;
- /*
- * ... or a func node.
- */
- if (is_funcclause(leftop) || is_funcclause(rightop))
- return true;
- return false;
- }
- /*
- * qual_clause_p
- *
- * Returns t iff 'clause' is a valid qualification clause.
- *
- * For now we accept only "var op const" or "const op var".
- */
- bool
- qual_clause_p(Node *clause)
- {
- Node *leftop,
- *rightop;
- if (!is_opclause(clause))
- return false;
- leftop = (Node *) get_leftop((Expr *) clause);
- rightop = (Node *) get_rightop((Expr *) clause);
- if (!rightop)
- return false; /* unary opclauses need not apply */
- /* How about Param-s ? - vadim 02/03/98 */
- if (IsA(leftop, Var) &&IsA(rightop, Const))
- return true;
- if (IsA(rightop, Var) &&IsA(leftop, Const))
- return true;
- return false;
- }
- /*
- * fix_opid
- * Calculate opid field from opno for each Oper node in given tree.
- *
- * Returns nothing.
- */
- void
- fix_opid(Node *clause)
- {
- /* This tree walk requires no special setup, so away we go... */
- fix_opid_walker(clause, NULL);
- }
- static bool
- fix_opid_walker (Node *node, void *context)
- {
- if (node == NULL)
- return false;
- if (is_opclause(node))
- replace_opid((Oper *) ((Expr *) node)->oper);
- return expression_tree_walker(node, fix_opid_walker, context);
- }
- /*
- * fix_opids
- * Calculate the opid from the opno for all the clauses...
- *
- * Returns its argument.
- *
- * XXX This could and should be merged with fix_opid.
- *
- */
- List *
- fix_opids(List *clauses)
- {
- fix_opid((Node *) clauses);
- return clauses;
- }
- /*
- * get_relattval
- * For a non-join clause, returns a list consisting of the
- * relid,
- * attno,
- * value of the CONST node (if any), and a
- * flag indicating whether the value appears on the left or right
- * of the operator and whether the value varied.
- *
- * OLD OBSOLETE COMMENT FOLLOWS:
- * If 'clause' is not of the format (op var node) or (op node var),
- * or if the var refers to a nested attribute, then -1's are returned for
- * everything but the value a blank string "" (pointer to