aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/clauses.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r--src/backend/optimizer/util/clauses.c736
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;
+}
+
+