diff options
author | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
commit | d31084e9d1118b25fd16580d9d8c2924b5740dff (patch) | |
tree | 3179e66307d54df9c7b966543550e601eb55e668 /src/backend/optimizer/util/clauses.c | |
download | postgresql-PG95-1_01.tar.gz postgresql-PG95-1_01.zip |
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 736 |
1 files changed, 736 insertions, 0 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c new file mode 100644 index 00000000000..daba4d8fdb0 --- /dev/null +++ b/src/backend/optimizer/util/clauses.c @@ -0,0 +1,736 @@ +/*------------------------------------------------------------------------- + * + * clauses.c-- + * routines to manipulate qualification clauses + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.1.1.1 1996/07/09 06:21:38 scrappy Exp $ + * + * HISTORY + * AUTHOR DATE MAJOR EVENT + * Andrew Yu Nov 3, 1994 clause.c and clauses.c combined + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "nodes/pg_list.h" +#include "nodes/primnodes.h" +#include "nodes/relation.h" +#include "nodes/parsenodes.h" +#include "nodes/makefuncs.h" +#include "nodes/nodeFuncs.h" + +#include "catalog/pg_aggregate.h" + +#include "utils/elog.h" +#include "utils/syscache.h" +#include "utils/lsyscache.h" + +#include "optimizer/clauses.h" +#include "optimizer/internal.h" +#include "optimizer/var.h" + + +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 { + /* 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; + expr->args = makeList(leftop, rightop, -1); + 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). + * + */ +Var * +get_rightop(Expr *clause) +{ + if (clause->args!=NULL && lnext(clause->args)!=NULL) + return (lfirst(lnext(clause->args))); + else + return NULL; +} + +/***************************************************************************** + * AGG clause functions + *****************************************************************************/ + +bool +agg_clause(Node *clause) +{ + return + (clause!=NULL && nodeTag(clause)==T_Aggreg); +} + +/***************************************************************************** + * 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; +} + +/***************************************************************************** + * * + * * + * * + *****************************************************************************/ + + +/* + * 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. + * + * XXX take the nreverse's out later + * + */ +void +clause_relids_vars(Node *clause, List **relids, List **vars) +{ + List *clvars = pull_var_clause(clause); + List *var_list = NIL; + List *varno_list = NIL; + List *i = NIL; + + foreach (i, clvars) { + Var *var = (Var *)lfirst(i); + + if (!intMember(var->varno, varno_list)) { + varno_list = lappendi(varno_list, var->varno); + var_list = lappend(var_list, var); + } + } + + *relids = varno_list; + *vars = var_list; + return; +} + +/* + * NumRelids-- + * (formerly clause-relids) + * + * Returns the number of different relations referenced in 'clause'. + */ +int +NumRelids(Node *clause) +{ + List *vars = pull_var_clause(clause); + List *i = NIL; + List *var_list = NIL; + + 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. + * + */ +bool +contains_not(Node *clause) +{ + if (single_node(clause)) + return (false); + + if (not_clause(clause)) + return (true); + + if (or_clause(clause)) { + List *a; + foreach(a, ((Expr*)clause)->args) { + if (contains_not(lfirst(a))) + return (true); + } + } + + return(false); +} + +/* + * join-clause-p-- + * + * Returns t iff 'clause' is a valid join clause. + * + */ +bool +join_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); + + /* + * 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. + * + */ +bool +qual_clause_p(Node *clause) +{ + if (!is_opclause(clause)) + return false; + + if (IsA (get_leftop((Expr*)clause),Var) && + IsA (get_rightop((Expr*)clause),Const)) + { + return(true); + } + else if (IsA (get_rightop((Expr*)clause),Var) && + IsA (get_leftop((Expr*)clause),Const)) + { + return(true); + } + return(false); +} + +/* + * fix-opid-- + * Calculate the opfid from the opno... + * + * Returns nothing. + * + */ +void +fix_opid(Node *clause) +{ + if (clause==NULL || single_node(clause)) { + ; + } + else if (or_clause (clause)) { + fix_opids(((Expr*)clause)->args); + } + else if (is_funcclause (clause)) { + fix_opids(((Expr*)clause)->args); + } + else if (IsA(clause,ArrayRef)) { + ArrayRef *aref = (ArrayRef *)clause; + + fix_opids(aref->refupperindexpr); + fix_opids(aref->reflowerindexpr); + fix_opid(aref->refexpr); + fix_opid(aref->refassgnexpr); + } + else if (not_clause(clause)) { + fix_opid((Node*)get_notclausearg((Expr*)clause)); + } + else if (is_opclause (clause)) { + replace_opid((Oper*)((Expr*)clause)->oper); + fix_opid((Node*)get_leftop((Expr*)clause)); + fix_opid((Node*)get_rightop((Expr*)clause)); + } + +} + +/* + * fix-opids-- + * Calculate the opfid from the opno for all the clauses... + * + * Returns its argument. + * + */ +List * +fix_opids(List *clauses) +{ + List *clause; + + foreach(clause, clauses) + fix_opid(lfirst(clause)); + + 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 \0) is + * returned for the value if it is unknown or null. + * END OF OLD OBSOLETE COMMENT. + * NEW COMMENT: + * when defining rules one of the attibutes of the operator can + * be a Param node (which is supposed to be treated as a constant). + * However as there is no value specified for a parameter until run time + * this routine used to return "" as value, which made 'compute_selec' + * to bomb (because it was expecting a lisp integer and got back a lisp + * string). Now the code returns a plain old good "lispInteger(0)". + * + */ +void +get_relattval(Node *clause, + int *relid, + AttrNumber *attno, + Datum *constval, + int *flag) +{ + Var *left = get_leftop((Expr*)clause); + Var *right = get_rightop((Expr*)clause); + + if(is_opclause(clause) && IsA(left,Var) && + IsA(right,Const)) { + + if(right!=NULL) { + + *relid = left->varno; + *attno = left->varattno; + *constval = ((Const *)right)->constvalue; + *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_); + + } else { + + *relid = left->varno; + *attno = left->varattno; + *constval = 0; + *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_NOT_CONSTANT_); + + } + }else if (is_opclause(clause) && + is_funcclause((Node*)left) && + IsA(right,Const)) { + List *args = ((Expr*)left)->args; + + + *relid = ((Var*)lfirst(args))->varno; + *attno = InvalidAttrNumber; + *constval = ((Const*)right)->constvalue; + *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_); + + /* + * XXX both of these func clause handling if's seem wrong to me. + * they assume that the first argument is the Var. It could + * not handle (for example) f(1, emp.name). I think I may have + * been assuming no constants in functional index scans when I + * implemented this originally (still currently true). + * -mer 10 Aug 1992 + */ + } else if (is_opclause(clause) && + is_funcclause((Node*)right) && + IsA(left,Const)) { + List *args = ((Expr*)right)->args; + + *relid = ((Var*)lfirst(args))->varno; + *attno = InvalidAttrNumber; + *constval = ((Const*)left)->constvalue; + *flag = ( _SELEC_IS_CONSTANT_); + + } else if (is_opclause (clause) && IsA (right,Var) && + IsA (left,Const)) { + if (left!=NULL) { + + *relid = right->varno; + *attno = right->varattno; + *constval = ((Const*)left)->constvalue; + *flag = (_SELEC_IS_CONSTANT_); + } else { + + *relid = right->varno; + *attno = right->varattno; + *constval = 0; + *flag = (_SELEC_NOT_CONSTANT_); + } + } else { + /* One or more of the operands are expressions + * (e.g., oper clauses) + */ + *relid = _SELEC_VALUE_UNKNOWN_; + *attno = _SELEC_VALUE_UNKNOWN_; + *constval = 0; + *flag = (_SELEC_NOT_CONSTANT_); + } +} + +/* + * get_relsatts-- + * + * Returns a list + * ( relid1 attno1 relid2 attno2 ) + * for a joinclause. + * + * If the clause is not of the form (op var var) or if any of the vars + * refer to nested attributes, then -1's are returned. + * + */ +void +get_rels_atts(Node *clause, + int *relid1, + AttrNumber *attno1, + int *relid2, + AttrNumber *attno2) +{ + Var *left = get_leftop((Expr*)clause); + Var *right = get_rightop((Expr*)clause); + bool var_left = (IsA(left,Var)); + bool var_right = (IsA(right,Var)); + bool varexpr_left = (bool)((IsA(left,Func) || IsA (left,Oper)) && + contain_var_clause((Node*)left)); + bool varexpr_right = (bool)(( IsA(right,Func) || IsA (right,Oper)) && + contain_var_clause((Node*)right)); + + if (is_opclause(clause)) { + if(var_left && var_right) { + + *relid1 = left->varno; + *attno1 = left->varoattno; + *relid2 = right->varno; + *attno2 = right->varoattno; + return; + } else if (var_left && varexpr_right ) { + + *relid1 = left->varno; + *attno1 = left->varoattno; + *relid2 = _SELEC_VALUE_UNKNOWN_; + *attno2 = _SELEC_VALUE_UNKNOWN_; + return; + } else if (varexpr_left && var_right) { + + *relid1 = _SELEC_VALUE_UNKNOWN_; + *attno1 = _SELEC_VALUE_UNKNOWN_; + *relid2 = right->varno; + *attno2 = right->varoattno; + return; + } + } + + *relid1 = _SELEC_VALUE_UNKNOWN_; + *attno1 = _SELEC_VALUE_UNKNOWN_; + *relid2 = _SELEC_VALUE_UNKNOWN_; + *attno2 = _SELEC_VALUE_UNKNOWN_; + return; +} + +void +CommuteClause(Node *clause) +{ + Node *temp; + Oper *commu; + OperatorTupleForm commuTup; + HeapTuple heapTup; + + if (!is_opclause(clause)) + return; + + heapTup = (HeapTuple) + get_operator_tuple(get_commutator(((Oper*)((Expr*)clause)->oper)->opno)); + + if (heapTup == (HeapTuple)NULL) + return; + + commuTup = (OperatorTupleForm)GETSTRUCT(heapTup); + + commu = makeOper(heapTup->t_oid, + InvalidOid, + commuTup->oprresult, + ((Oper*)((Expr*)clause)->oper)->opsize, + NULL); + + /* + * reform the clause -> (operator func/var constant) + */ + ((Expr*)clause)->oper = (Node*)commu; + temp = lfirst(((Expr*)clause)->args); + lfirst(((Expr*)clause)->args) = lsecond(((Expr*)clause)->args); + lsecond(((Expr*)clause)->args) = temp; +} + + |