aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/nodeSubplan.c19
-rw-r--r--src/backend/optimizer/plan/subselect.c315
-rw-r--r--src/backend/optimizer/util/clauses.c53
-rw-r--r--src/backend/parser/parse_expr.c66
-rw-r--r--src/backend/rewrite/rewriteHandler.c79
-rw-r--r--src/backend/rewrite/rewriteManip.c65
-rw-r--r--src/backend/utils/adt/ruleutils.c17
-rw-r--r--src/include/nodes/primnodes.h32
8 files changed, 325 insertions, 321 deletions
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index e4e83d654ac..4bd0eb2ff31 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -94,8 +94,25 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
Const *con = lsecond(expr->args);
bool isnull;
+ /*
+ * The righthand side of the expression should be either a Const
+ * or a function call taking a Const as arg (the function would
+ * be a run-time type coercion inserted by the parser to get to
+ * the input type needed by the operator). Find the Const node
+ * and insert the actual righthand side value into it.
+ */
+ if (! IsA(con, Const))
+ {
+ Assert(IsA(con, Expr));
+ con = lfirst(((Expr *) con)->args);
+ Assert(IsA(con, Const));
+ }
con->constvalue = heap_getattr(tup, i, tdesc, &(con->constisnull));
- result = ExecEvalExpr((Node *) expr, econtext, &isnull, (bool *) NULL);
+ /*
+ * Now we can eval the expression.
+ */
+ result = ExecEvalExpr((Node *) expr, econtext, &isnull,
+ (bool *) NULL);
if (isnull)
{
if (subLinkType == EXPR_SUBLINK)
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index c275b7adc45..7e5d2be749e 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -6,18 +6,24 @@
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.23 1999/08/22 20:14:49 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.24 1999/08/25 23:21:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planner.h"
#include "optimizer/subselect.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_node.h"
+#include "parser/parse_oper.h"
+#include "utils/lsyscache.h"
+
int PlannerQueryLevel; /* level of current query */
List *PlannerInitPlan; /* init subplans for current query */
@@ -46,7 +52,7 @@ int PlannerPlanId; /* to assign unique ID to subquery plans */
* is set from the absolute level value given by varlevel.
*/
static int
-_new_param(Var *var, int varlevel)
+new_param(Var *var, int varlevel)
{
Var *paramVar = (Var *) copyObject(var);
@@ -62,7 +68,7 @@ _new_param(Var *var, int varlevel)
* which is expected to have varlevelsup > 0 (ie, it is not local).
*/
static Param *
-_replace_var(Var *var)
+replace_var(Var *var)
{
List *ppv;
Param *retval;
@@ -98,7 +104,7 @@ _replace_var(Var *var)
if (! ppv)
{
/* Nope, so make a new one */
- i = _new_param(var, varlevel);
+ i = new_param(var, varlevel);
}
retval = makeNode(Param);
@@ -109,8 +115,11 @@ _replace_var(Var *var)
return retval;
}
+/*
+ * Convert a bare SubLink (as created by the parser) into a SubPlan.
+ */
static Node *
-_make_subplan(SubLink *slink)
+make_subplan(SubLink *slink)
{
SubPlan *node = makeNode(SubPlan);
Plan *plan;
@@ -126,7 +135,7 @@ _make_subplan(SubLink *slink)
/*
* Assign subPlan, extParam and locParam to plan nodes. At the moment,
- * SS_finalize_plan doesn't handle initPlan-s and so we assigne them
+ * SS_finalize_plan doesn't handle initPlan-s and so we assign them
* to the topmost plan node and take care about its extParam too.
*/
(void) SS_finalize_plan(plan);
@@ -169,31 +178,58 @@ _make_subplan(SubLink *slink)
*/
if (node->parParam == NULL && slink->subLinkType == EXPR_SUBLINK)
{
+ List *newoper = NIL;
int i = 0;
- /* transform right side of all sublink Oper-s into Param */
+ /*
+ * Convert oper list of Opers into a list of Exprs, using
+ * lefthand arguments and Params representing inside results.
+ */
foreach(lst, slink->oper)
{
- List *rside = lnext(((Expr *) lfirst(lst))->args);
+ Oper *oper = (Oper *) lfirst(lst);
+ Node *lefthand = nth(i, slink->lefthand);
TargetEntry *te = nth(i, plan->targetlist);
+ /* need a var node just to pass to new_param()... */
Var *var = makeVar(0, 0, te->resdom->restype,
te->resdom->restypmod, 0);
Param *prm = makeNode(Param);
+ Operator tup;
+ Form_pg_operator opform;
+ Node *left,
+ *right;
prm->paramkind = PARAM_EXEC;
- prm->paramid = (AttrNumber) _new_param(var, PlannerQueryLevel);
+ prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
prm->paramtype = var->vartype;
- lfirst(rside) = prm;
+
+ Assert(IsA(oper, Oper));
+ tup = get_operator_tuple(oper->opno);
+ Assert(HeapTupleIsValid(tup));
+ opform = (Form_pg_operator) GETSTRUCT(tup);
+ /* Note: we use make_operand in case runtime type conversion
+ * function calls must be inserted for this operator!
+ */
+ left = make_operand("", lefthand,
+ exprType(lefthand), opform->oprleft);
+ right = make_operand("", (Node *) prm,
+ prm->paramtype, opform->oprright);
+ newoper = lappend(newoper,
+ make_opclause(oper,
+ (Var *) left,
+ (Var *) right));
node->setParam = lappendi(node->setParam, prm->paramid);
pfree(var);
i++;
}
+ slink->oper = newoper;
+ slink->lefthand = NIL;
PlannerInitPlan = lappend(PlannerInitPlan, node);
if (i > 1)
- result = (Node *) ((slink->useor) ? make_orclause(slink->oper) :
- make_andclause(slink->oper));
+ result = (Node *) ((slink->useor) ? make_orclause(newoper) :
+ make_andclause(newoper));
else
- result = (Node *) lfirst(slink->oper);
+ result = (Node *) lfirst(newoper);
}
else if (node->parParam == NULL && slink->subLinkType == EXISTS_SUBLINK)
{
@@ -201,7 +237,7 @@ _make_subplan(SubLink *slink)
Param *prm = makeNode(Param);
prm->paramkind = PARAM_EXEC;
- prm->paramid = (AttrNumber) _new_param(var, PlannerQueryLevel);
+ prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
prm->paramtype = var->vartype;
node->setParam = lappendi(node->setParam, prm->paramid);
pfree(var);
@@ -213,16 +249,15 @@ _make_subplan(SubLink *slink)
/* make expression of SUBPLAN type */
Expr *expr = makeNode(Expr);
List *args = NIL;
+ List *newoper = NIL;
int i = 0;
- expr->typeOid = BOOLOID;
+ expr->typeOid = BOOLOID; /* bogus, but we don't really care */
expr->opType = SUBPLAN_EXPR;
expr->oper = (Node *) node;
/*
- * Make expr->args from parParam. Left sides of sublink Oper-s are
- * handled by optimizer directly... Also, transform right side of
- * sublink Oper-s into Const.
+ * Make expr->args from parParam.
*/
foreach(lst, node->parParam)
{
@@ -236,23 +271,55 @@ _make_subplan(SubLink *slink)
var->varlevelsup = 0;
args = lappend(args, var);
}
+ expr->args = args;
+ /*
+ * Convert oper list of Opers into a list of Exprs, using
+ * lefthand arguments and Consts representing inside results.
+ */
foreach(lst, slink->oper)
{
- List *rside = lnext(((Expr *) lfirst(lst))->args);
+ Oper *oper = (Oper *) lfirst(lst);
+ Node *lefthand = nth(i, slink->lefthand);
TargetEntry *te = nth(i, plan->targetlist);
- Const *con = makeConst(te->resdom->restype,
- 0, 0, true, 0, 0, 0);
-
- lfirst(rside) = con;
+ Const *con;
+ Operator tup;
+ Form_pg_operator opform;
+ Node *left,
+ *right;
+
+ /*
+ * XXX really ought to fill in constlen and constbyval correctly,
+ * but right now ExecEvalExpr won't look at them...
+ */
+ con = makeConst(te->resdom->restype, 0, 0, true, 0, 0, 0);
+
+ Assert(IsA(oper, Oper));
+ tup = get_operator_tuple(oper->opno);
+ Assert(HeapTupleIsValid(tup));
+ opform = (Form_pg_operator) GETSTRUCT(tup);
+ /* Note: we use make_operand in case runtime type conversion
+ * function calls must be inserted for this operator!
+ */
+ left = make_operand("", lefthand,
+ exprType(lefthand), opform->oprleft);
+ right = make_operand("", (Node *) con,
+ con->consttype, opform->oprright);
+ newoper = lappend(newoper,
+ make_opclause(oper,
+ (Var *) left,
+ (Var *) right));
i++;
}
- expr->args = args;
+ slink->oper = newoper;
+ slink->lefthand = NIL;
result = (Node *) expr;
}
return result;
}
+/* this oughta be merged with LispUnioni */
+
static List *
set_unioni(List *l1, List *l2)
{
@@ -264,6 +331,11 @@ set_unioni(List *l1, List *l2)
return nconc(l1, set_differencei(l2, l1));
}
+/*
+ * finalize_primnode: build lists of subplans and params appearing
+ * in the given expression tree.
+ */
+
typedef struct finalize_primnode_results {
List *subplans; /* List of subplans found in expr */
List *paramids; /* List of PARAM_EXEC paramids found */
@@ -315,165 +387,83 @@ finalize_primnode_walker(Node *node,
! intMember(paramid, results->paramids))
results->paramids = lconsi(paramid, results->paramids);
}
- /* XXX We do NOT allow expression_tree_walker to examine the args
- * passed to the subplan. Is that correct??? It's what the
- * old code did, but it seems mighty bogus... tgl 7/14/99
- */
- return false; /* don't recurse into subplan args */
+ /* fall through to recurse into subplan args */
}
return expression_tree_walker(node, finalize_primnode_walker,
(void *) results);
}
-/* Replace correlation vars (uplevel vars) with Params. */
-
-/* XXX should replace this with use of a generalized tree rebuilder,
- * designed along the same lines as expression_tree_walker.
- * Not done yet.
+/*
+ * Replace correlation vars (uplevel vars) with Params.
*/
+
+static Node *replace_correlation_vars_mutator(Node *node, void *context);
+
Node *
SS_replace_correlation_vars(Node *expr)
{
- if (expr == NULL)
- return NULL;
- if (IsA(expr, Var))
- {
- if (((Var *) expr)->varlevelsup > 0)
- expr = (Node *) _replace_var((Var *) expr);
- }
- else if (single_node(expr))
- return expr;
- else if (IsA(expr, List))
- {
- List *le;
-
- foreach(le, (List *) expr)
- lfirst(le) = SS_replace_correlation_vars((Node *) lfirst(le));
- }
- else if (IsA(expr, Expr))
- {
- /* XXX do we need to do anything special with subplans? */
- ((Expr *) expr)->args = (List *)
- SS_replace_correlation_vars((Node *) ((Expr *) expr)->args);
- }
- else if (IsA(expr, Aggref))
- ((Aggref *) expr)->target = SS_replace_correlation_vars(((Aggref *) expr)->target);
- else if (IsA(expr, Iter))
- ((Iter *) expr)->iterexpr = SS_replace_correlation_vars(((Iter *) expr)->iterexpr);
- else if (IsA(expr, ArrayRef))
- {
- ((ArrayRef *) expr)->refupperindexpr = (List *)
- SS_replace_correlation_vars((Node *) ((ArrayRef *) expr)->refupperindexpr);
- ((ArrayRef *) expr)->reflowerindexpr = (List *)
- SS_replace_correlation_vars((Node *) ((ArrayRef *) expr)->reflowerindexpr);
- ((ArrayRef *) expr)->refexpr = SS_replace_correlation_vars(((ArrayRef *) expr)->refexpr);
- ((ArrayRef *) expr)->refassgnexpr = SS_replace_correlation_vars(((ArrayRef *) expr)->refassgnexpr);
- }
- else if (IsA(expr, CaseExpr))
- {
- CaseExpr *caseexpr = (CaseExpr *) expr;
- List *le;
+ /* No setup needed for tree walk, so away we go */
+ return replace_correlation_vars_mutator(expr, NULL);
+}
- foreach(le, caseexpr->args)
- {
- CaseWhen *when = (CaseWhen *) lfirst(le);
- Assert(IsA(when, CaseWhen));
- when->expr = SS_replace_correlation_vars(when->expr);
- when->result = SS_replace_correlation_vars(when->result);
- }
- /* caseexpr->arg should be null, but we'll check it anyway */
- caseexpr->arg = SS_replace_correlation_vars(caseexpr->arg);
- caseexpr->defresult = SS_replace_correlation_vars(caseexpr->defresult);
- }
- else if (IsA(expr, TargetEntry))
- ((TargetEntry *) expr)->expr = SS_replace_correlation_vars(((TargetEntry *) expr)->expr);
- else if (IsA(expr, SubLink))
+static Node *
+replace_correlation_vars_mutator(Node *node, void *context)
+{
+ if (node == NULL)
+ return NULL;
+ if (IsA(node, Var))
{
- List *le;
-
- foreach(le, ((SubLink *) expr)->oper) /* left sides only */
- {
- List *oparg = ((Expr *) lfirst(le))->args;
-
- lfirst(oparg) = (List *)
- SS_replace_correlation_vars((Node *) lfirst(oparg));
- }
- ((SubLink *) expr)->lefthand = (List *)
- SS_replace_correlation_vars((Node *) ((SubLink *) expr)->lefthand);
+ if (((Var *) node)->varlevelsup > 0)
+ return (Node *) replace_var((Var *) node);
}
- else
- elog(ERROR, "SS_replace_correlation_vars: can't handle node %d",
- nodeTag(expr));
-
- return expr;
+ return expression_tree_mutator(node,
+ replace_correlation_vars_mutator,
+ context);
}
-/* Replace sublinks by subplans in the given expression */
-
-/* XXX should replace this with use of a generalized tree rebuilder,
- * designed along the same lines as expression_tree_walker.
- * Not done yet.
+/*
+ * Expand SubLinks to SubPlans in the given expression.
*/
+
+static Node *process_sublinks_mutator(Node *node, void *context);
+
Node *
SS_process_sublinks(Node *expr)
{
- if (expr == NULL)
+ /* No setup needed for tree walk, so away we go */
+ return process_sublinks_mutator(expr, NULL);
+}
+
+static Node *
+process_sublinks_mutator(Node *node, void *context)
+{
+ if (node == NULL)
return NULL;
- if (IsA(expr, SubLink))
- {
- expr = _make_subplan((SubLink *) expr);
- }
- else if (single_node(expr))
- return expr;
- else if (IsA(expr, List))
+ if (IsA(node, SubLink))
{
- List *le;
+ SubLink *sublink = (SubLink *) node;
- foreach(le, (List *) expr)
- lfirst(le) = SS_process_sublinks((Node *) lfirst(le));
- }
- else if (IsA(expr, Expr))
- {
- /* We should never see a subplan node here, since this is the
- * routine that makes 'em in the first place. No need to check.
+ /* First, scan the lefthand-side expressions.
+ * This is a tad klugy since we modify the input SubLink node,
+ * but that should be OK (make_subplan does it too!)
*/
- ((Expr *) expr)->args = (List *)
- SS_process_sublinks((Node *) ((Expr *) expr)->args);
- }
- else if (IsA(expr, Aggref))
- ((Aggref *) expr)->target = SS_process_sublinks(((Aggref *) expr)->target);
- else if (IsA(expr, Iter))
- ((Iter *) expr)->iterexpr = SS_process_sublinks(((Iter *) expr)->iterexpr);
- else if (IsA(expr, ArrayRef))
- {
- ((ArrayRef *) expr)->refupperindexpr = (List *)
- SS_process_sublinks((Node *) ((ArrayRef *) expr)->refupperindexpr);
- ((ArrayRef *) expr)->reflowerindexpr = (List *)
- SS_process_sublinks((Node *) ((ArrayRef *) expr)->reflowerindexpr);
- ((ArrayRef *) expr)->refexpr = SS_process_sublinks(((ArrayRef *) expr)->refexpr);
- ((ArrayRef *) expr)->refassgnexpr = SS_process_sublinks(((ArrayRef *) expr)->refassgnexpr);
- }
- else if (IsA(expr, CaseExpr))
- {
- CaseExpr *caseexpr = (CaseExpr *) expr;
- List *le;
-
- foreach(le, caseexpr->args)
- {
- CaseWhen *when = (CaseWhen *) lfirst(le);
- Assert(IsA(when, CaseWhen));
- when->expr = SS_process_sublinks(when->expr);
- when->result = SS_process_sublinks(when->result);
- }
- /* caseexpr->arg should be null, but we'll check it anyway */
- caseexpr->arg = SS_process_sublinks(caseexpr->arg);
- caseexpr->defresult = SS_process_sublinks(caseexpr->defresult);
+ sublink->lefthand = (List *)
+ process_sublinks_mutator((Node *) sublink->lefthand, context);
+ /* Now build the SubPlan node and make the expr to return */
+ return make_subplan(sublink);
}
- else
- elog(ERROR, "SS_process_sublinks: can't handle node %d",
- nodeTag(expr));
+ /*
+ * Note that we will never see a SubPlan expression in the input
+ * (since this is the very routine that creates 'em to begin with).
+ * So the code in expression_tree_mutator() that might do
+ * inappropriate things with SubPlans or SubLinks will not be
+ * exercised.
+ */
+ Assert(! is_subplan(node));
- return expr;
+ return expression_tree_mutator(node,
+ process_sublinks_mutator,
+ context);
}
List *
@@ -585,7 +575,9 @@ SS_finalize_plan(Plan *plan)
return results.paramids;
}
-/* Construct a list of all subplans found within the given node tree */
+/*
+ * Construct a list of all subplans found within the given node tree.
+ */
static bool SS_pull_subplan_walker(Node *node, List **listptr);
@@ -606,8 +598,7 @@ SS_pull_subplan_walker(Node *node, List **listptr)
if (is_subplan(node))
{
*listptr = lappend(*listptr, ((Expr *) node)->oper);
- /* XXX original code did not examine args to subplan, is this right? */
- return false;
+ /* fall through to check args to subplan */
}
return expression_tree_walker(node, SS_pull_subplan_walker,
(void *) listptr);
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index fbb5a98e83d..2d960b5cf03 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.48 1999/08/22 20:14:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.49 1999/08/25 23:21:41 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -817,8 +817,8 @@ CommuteClause(Expr *clause)
* the args and slink->oper lists (which belong to the outer plan), but it
* will *not* visit the inner plan, since that's typically what expression
* tree walkers want. A walker that wants to visit the subplan can force
- * appropriate behavior by recognizing subplan nodes and doing the right
- * thing.
+ * appropriate behavior by recognizing subplan expression nodes and doing
+ * the right thing.
*
* Bare SubLink nodes (without a SUBPLAN_EXPR) are handled by recursing into
* the "lefthand" argument list only. (A bare SubLink should be seen only if
@@ -854,26 +854,18 @@ expression_tree_walker(Node *node, bool (*walker) (), void *context)
case T_Expr:
{
Expr *expr = (Expr *) node;
+
if (expr->opType == SUBPLAN_EXPR)
{
- /* examine args list (params to be passed to subplan) */
- if (expression_tree_walker((Node *) expr->args,
- walker, context))
- return true;
- /* examine oper list as well */
- if (expression_tree_walker(
- (Node *) ((SubPlan *) expr->oper)->sublink->oper,
- walker, context))
- return true;
- /* but not the subplan itself */
- }
- else
- {
- /* for other Expr node types, just examine args list */
- if (expression_tree_walker((Node *) expr->args,
- walker, context))
+ /* recurse to the SubLink node (skipping SubPlan!) */
+ if (walker((Node *) ((SubPlan *) expr->oper)->sublink,
+ context))
return true;
}
+ /* for all Expr node types, examine args list */
+ if (expression_tree_walker((Node *) expr->args,
+ walker, context))
+ return true;
}
break;
case T_Aggref:
@@ -918,11 +910,20 @@ expression_tree_walker(Node *node, bool (*walker) (), void *context)
}
break;
case T_SubLink:
- /* A "bare" SubLink (note we will not come here if we found
- * a SUBPLAN_EXPR node above it). Examine the lefthand side,
- * but not the oper list nor the subquery.
- */
- return walker(((SubLink *) node)->lefthand, context);
+ {
+ SubLink *sublink = (SubLink *) node;
+
+ /* If the SubLink has already been processed by subselect.c,
+ * it will have lefthand=NIL, and we only need to look at
+ * the oper list. Otherwise we only need to look at lefthand
+ * (the Oper nodes in the oper list are deemed uninteresting).
+ */
+ if (sublink->lefthand)
+ return walker((Node *) sublink->lefthand, context);
+ else
+ return walker((Node *) sublink->oper, context);
+ }
+ break;
case T_List:
foreach(temp, (List *) node)
{
@@ -988,8 +989,8 @@ expression_tree_walker(Node *node, bool (*walker) (), void *context)
* the args and slink->oper lists (which belong to the outer plan), but it
* will simply copy the link to the inner plan, since that's typically what
* expression tree mutators want. A mutator that wants to modify the subplan
- * can force appropriate behavior by recognizing subplan nodes and doing the
- * right thing.
+ * can force appropriate behavior by recognizing subplan expression nodes
+ * and doing the right thing.
*
* Bare SubLink nodes (without a SUBPLAN_EXPR) are handled by recursing into
* the "lefthand" argument list only. (A bare SubLink should be seen only if
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 0ecee29f52d..a2280a74511 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -7,12 +7,14 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.56 1999/08/05 02:33:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.57 1999/08/25 23:21:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+
+#include "catalog/pg_operator.h"
#include "nodes/makefuncs.h"
#include "nodes/params.h"
#include "nodes/relation.h"
@@ -22,6 +24,7 @@
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
+#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
#include "utils/builtins.h"
@@ -209,7 +212,15 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
elog(ERROR, "parser: bad query in subselect");
sublink->subselect = (Node *) qtree;
- if (sublink->subLinkType != EXISTS_SUBLINK)
+ if (sublink->subLinkType == EXISTS_SUBLINK)
+ {
+ /* EXISTS needs no lefthand or combining operator.
+ * These fields should be NIL already, but make sure.
+ */
+ sublink->lefthand = NIL;
+ sublink->oper = NIL;
+ }
+ else
{
char *op = lfirst(sublink->oper);
List *left_list = sublink->lefthand;
@@ -236,27 +247,39 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
{
TargetEntry *tent = (TargetEntry *) lfirst(right_list);
Node *lexpr;
- Expr *op_expr;
+ Operator optup;
+ Form_pg_operator opform;
+ Oper *newop;
- if (! tent->resdom->resjunk)
- {
- if (left_list == NIL)
- elog(ERROR, "parser: Subselect has too many fields.");
- lexpr = lfirst(left_list);
- left_list = lnext(left_list);
- op_expr = make_op(op, lexpr, tent->expr);
- if (op_expr->typeOid != BOOLOID &&
- sublink->subLinkType != EXPR_SUBLINK)
- elog(ERROR, "parser: '%s' must return 'bool' to be used with quantified predicate subquery", op);
- sublink->oper = lappend(sublink->oper, op_expr);
- }
right_list = lnext(right_list);
+ if (tent->resdom->resjunk)
+ continue;
+
+ if (left_list == NIL)
+ elog(ERROR, "parser: Subselect has too many fields.");
+ lexpr = lfirst(left_list);
+ left_list = lnext(left_list);
+
+ optup = oper(op,
+ exprType(lexpr),
+ exprType(tent->expr),
+ FALSE);
+ opform = (Form_pg_operator) GETSTRUCT(optup);
+
+ if (opform->oprresult != BOOLOID &&
+ sublink->subLinkType != EXPR_SUBLINK)
+ elog(ERROR, "parser: '%s' must return 'bool' to be used with quantified predicate subquery", op);
+
+ newop = makeOper(oprid(optup),/* opno */
+ InvalidOid, /* opid */
+ opform->oprresult,
+ 0,
+ NULL);
+ sublink->oper = lappend(sublink->oper, newop);
}
if (left_list != NIL)
elog(ERROR, "parser: Subselect has too few fields.");
}
- else
- sublink->oper = NIL;
result = (Node *) expr;
break;
}
@@ -565,10 +588,13 @@ exprType(Node *expr)
if (sublink->subLinkType == EXPR_SUBLINK)
{
- /* return the result type of the combining operator */
- Expr *op_expr = (Expr *) lfirst(sublink->oper);
+ /* return the result type of the combining operator;
+ * should only be one...
+ */
+ Oper *op = (Oper *) lfirst(sublink->oper);
- type = op_expr->typeOid;
+ Assert(IsA(op, Oper));
+ type = op->opresulttype;
}
else
{
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 88bef2237aa..0fa7fd72d43 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -6,19 +6,23 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.54 1999/07/17 20:17:37 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.55 1999/08/25 23:21:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
+#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
+#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/prep.h"
#include "parser/analyze.h"
+#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
+#include "parser/parse_oper.h"
#include "parser/parse_target.h"
#include "parser/parse_type.h"
#include "parser/parsetree.h"
@@ -643,9 +647,6 @@ modifyAggrefUplevel(Node *node)
(Node *) (sub->lefthand));
modifyAggrefUplevel(
- (Node *) (sub->oper));
-
- modifyAggrefUplevel(
(Node *) (sub->subselect));
}
break;
@@ -817,12 +818,6 @@ modifyAggrefChangeVarnodes(Node **nodePtr, int rt_index, int new_index, int subl
sublevels_up);
modifyAggrefChangeVarnodes(
- (Node **) (&(sub->oper)),
- rt_index,
- new_index,
- sublevels_up);
-
- modifyAggrefChangeVarnodes(
(Node **) (&(sub->subselect)),
rt_index,
new_index,
@@ -989,6 +984,7 @@ modifyAggrefDropQual(Node **nodePtr, Node *orignode, Expr *expr)
SubLink *sub = (SubLink *) node;
SubLink *osub = (SubLink *) orignode;
+ /* what about the lefthand? */
modifyAggrefDropQual(
(Node **) (&(sub->subselect)),
(Node *) (osub->subselect),
@@ -1046,19 +1042,21 @@ modifyAggrefMakeSublink(Expr *origexp, Query *parsetree)
if (nodeTag(nth(1, exp->args)) == T_Aggref)
elog(ERROR, "rewrite: comparision of 2 aggregate columns not supported");
else
- elog(ERROR, "rewrite: aggregate column of view must be at rigth side in qual");
+ elog(ERROR, "rewrite: aggregate column of view must be at right side in qual");
}
aggref = (Aggref *) nth(1, exp->args);
target = (Var *) (aggref->target);
+ /* XXX bogus --- agg's target might not be a Var! */
rte = (RangeTblEntry *) nth(target->varno - 1, parsetree->rtable);
+
tle = makeNode(TargetEntry);
resdom = makeNode(Resdom);
- aggref->usenulls = TRUE;
+ aggref->usenulls = TRUE; /* XXX safe for all aggs?? */
resdom->resno = 1;
- resdom->restype = ((Oper *) (exp->oper))->opresulttype;
+ resdom->restype = aggref->aggtype;
resdom->restypmod = -1;
resdom->resname = pstrdup("<noname>");
resdom->reskey = 0;
@@ -1074,9 +1072,8 @@ modifyAggrefMakeSublink(Expr *origexp, Query *parsetree)
sublink = makeNode(SubLink);
sublink->subLinkType = EXPR_SUBLINK;
sublink->useor = FALSE;
- sublink->lefthand = lappend(NIL, copyObject(lfirst(exp->args)));
- sublink->oper = lappend(NIL, copyObject(exp));
- sublink->subselect = NULL;
+ sublink->lefthand = lcons(lfirst(exp->args), NIL);
+ sublink->oper = lcons(exp->oper, NIL);
subquery = makeNode(Query);
sublink->subselect = (Node *) subquery;
@@ -1105,8 +1102,6 @@ modifyAggrefMakeSublink(Expr *origexp, Query *parsetree)
modifyAggrefChangeVarnodes((Node **) &(sublink->lefthand), target->varno,
1, target->varlevelsup);
- modifyAggrefChangeVarnodes((Node **) &(sublink->oper), target->varno,
- 1, target->varlevelsup);
modifyAggrefChangeVarnodes((Node **) &(sublink->subselect), target->varno,
1, target->varlevelsup);
@@ -1249,6 +1244,7 @@ modifyAggrefQual(Node **nodePtr, Query *parsetree)
{
SubLink *sub = (SubLink *) node;
+ /* lefthand ??? */
modifyAggrefQual(
(Node **) (&(sub->subselect)),
(Query *) (sub->subselect));
@@ -1318,9 +1314,6 @@ checkQueryHasSubLink_walker(Node *node, void *context)
return false;
if (IsA(node, SubLink))
return true; /* abort the tree traversal and return true */
- /* Note: we assume the tree has not yet been rewritten by subselect.c,
- * therefore we will find bare SubLink nodes and not SUBPLAN nodes.
- */
return expression_tree_walker(node, checkQueryHasSubLink_walker, context);
}
@@ -1654,8 +1647,6 @@ apply_RIR_view(Node **nodePtr, int rt_index, RangeTblEntry *rte, List *tlist, in
case T_SubLink:
{
SubLink *sub = (SubLink *) node;
- List *tmp_lefthand,
- *tmp_oper;
apply_RIR_view(
(Node **) (&(sub->lefthand)),
@@ -1672,14 +1663,6 @@ apply_RIR_view(Node **nodePtr, int rt_index, RangeTblEntry *rte, List *tlist, in
tlist,
modified,
sublevels_up + 1);
-
- tmp_lefthand = sub->lefthand;
- foreach(tmp_oper, sub->oper)
- {
- lfirst(((Expr *) lfirst(tmp_oper))->args) =
- lfirst(tmp_lefthand);
- tmp_lefthand = lnext(tmp_lefthand);
- }
}
break;
@@ -3014,31 +2997,47 @@ Except_Intersect_Rewrite(Query *parsetree)
* of the targetlist must be (IN) or must not be (NOT IN) the
* subselect
*/
+ n->lefthand = NIL;
foreach(elist, intersect_node->targetList)
{
- Node *expr = lfirst(elist);
- TargetEntry *tent = (TargetEntry *) expr;
+ TargetEntry *tent = (TargetEntry *) lfirst(elist);
n->lefthand = lappend(n->lefthand, tent->expr);
}
/*
- * The first arguments of oper also have to be created for the
- * sublink (they are the same as the lefthand side!)
+ * Also prepare the list of Opers that must be used for the
+ * comparisons (they depend on the specific datatypes involved!)
*/
left_expr = n->lefthand;
right_expr = ((Query *) (n->subselect))->targetList;
+ n->oper = NIL;
foreach(elist, left_expr)
{
Node *lexpr = lfirst(elist);
- Node *rexpr = lfirst(right_expr);
- TargetEntry *tent = (TargetEntry *) rexpr;
- Expr *op_expr;
+ TargetEntry *tent = (TargetEntry *) lfirst(right_expr);
+ Operator optup;
+ Form_pg_operator opform;
+ Oper *newop;
+
+ optup = oper(op,
+ exprType(lexpr),
+ exprType(tent->expr),
+ FALSE);
+ opform = (Form_pg_operator) GETSTRUCT(optup);
+
+ if (opform->oprresult != BOOLOID)
+ elog(ERROR, "parser: '%s' must return 'bool' to be used with quantified predicate subquery", op);
+
+ newop = makeOper(oprid(optup),/* opno */
+ InvalidOid, /* opid */
+ opform->oprresult,
+ 0,
+ NULL);
- op_expr = make_op(op, lexpr, tent->expr);
+ n->oper = lappend(n->oper, newop);
- n->oper = lappend(n->oper, op_expr);
right_expr = lnext(right_expr);
}
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index f88e936412a..16b31eae84d 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.39 1999/08/21 03:49:13 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.40 1999/08/25 23:21:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -137,13 +137,7 @@ OffsetVarNodes(Node *node, int offset, int sublevels_up)
case T_SubLink:
{
SubLink *sub = (SubLink *) node;
- List *tmp_oper,
- *tmp_lefthand;
- /*
- * We also have to adapt the variables used in
- * sub->lefthand and sub->oper
- */
OffsetVarNodes(
(Node *) (sub->lefthand),
offset,
@@ -153,20 +147,6 @@ OffsetVarNodes(Node *node, int offset, int sublevels_up)
(Node *) (sub->subselect),
offset,
sublevels_up + 1);
-
- /*
- * Make sure the first argument of sub->oper points to the
- * same var as sub->lefthand does otherwise we will run
- * into troubles using aggregates (aggno will not be set
- * correctly)
- */
- tmp_lefthand = sub->lefthand;
- foreach(tmp_oper, sub->oper)
- {
- lfirst(((Expr *) lfirst(tmp_oper))->args) =
- lfirst(tmp_lefthand);
- tmp_lefthand = lnext(tmp_lefthand);
- }
}
break;
@@ -357,8 +337,6 @@ ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
case T_SubLink:
{
SubLink *sub = (SubLink *) node;
- List *tmp_oper,
- *tmp_lefthand;
ChangeVarNodes(
(Node *) (sub->lefthand),
@@ -371,20 +349,6 @@ ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
rt_index,
new_index,
sublevels_up + 1);
-
- /*
- * Make sure the first argument of sub->oper points to the
- * same var as sub->lefthand does otherwise we will run
- * into troubles using aggregates (aggno will not be set
- * correctly)
- */
- tmp_lefthand = sub->lefthand;
- foreach(tmp_oper, sub->oper)
- {
- lfirst(((Expr *) lfirst(tmp_oper))->args) =
- lfirst(tmp_lefthand);
- tmp_lefthand = lnext(tmp_lefthand);
- }
}
break;
@@ -732,6 +696,7 @@ ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr,
SubLink *sublink = (SubLink *) node;
Query *query = (Query *) sublink->subselect;
+ /* XXX what about lefthand? What about rest of subquery? */
ResolveNew(info, targetlist, (Node **) &(query->qual), sublevels_up + 1);
}
break;
@@ -888,6 +853,7 @@ nodeHandleRIRAttributeRule(Node **nodePtr,
SubLink *sublink = (SubLink *) node;
Query *query = (Query *) sublink->subselect;
+ /* XXX what about lefthand? What about rest of subquery? */
nodeHandleRIRAttributeRule((Node **) &(query->qual), rtable, targetlist,
rt_index, attr_num, modified, badsql,
sublevels_up + 1);
@@ -1062,9 +1028,6 @@ nodeHandleViewRule(Node **nodePtr,
{
SubLink *sublink = (SubLink *) node;
Query *query = (Query *) sublink->subselect;
- List *tmp_lefthand,
- *tmp_oper;
-
nodeHandleViewRule((Node **) &(query->qual), rtable, targetlist,
rt_index, modified, sublevels_up + 1);
@@ -1078,30 +1041,10 @@ nodeHandleViewRule(Node **nodePtr,
/*
* We also have to adapt the variables used in
- * sublink->lefthand and sublink->oper
+ * sublink->lefthand
*/
nodeHandleViewRule((Node **) &(sublink->lefthand), rtable,
targetlist, rt_index, modified, sublevels_up);
-
- /*
- * Make sure the first argument of sublink->oper points to
- * the same var as sublink->lefthand does otherwise we
- * will run into troubles using aggregates (aggno will not
- * be set correctly
- */
- pfree(lfirst(((Expr *) lfirst(sublink->oper))->args));
- lfirst(((Expr *) lfirst(sublink->oper))->args) =
- lfirst(sublink->lefthand);
-
-
- /* INTERSECT want's this - Jan */
-
- /*
- * tmp_lefthand = sublink->lefthand; foreach(tmp_oper,
- * sublink->oper) { lfirst(((Expr *)
- * lfirst(tmp_oper))->args) = lfirst(tmp_lefthand);
- * tmp_lefthand = lnext(tmp_lefthand); }
- */
}
break;
default:
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 008402e26f3..ea7950ec502 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -3,7 +3,7 @@
* out of it's tuple
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.22 1999/08/21 03:48:53 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.23 1999/08/25 23:21:35 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -1586,7 +1586,7 @@ get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
{
SubLink *sublink = (SubLink *) node;
Query *query = (Query *) (sublink->subselect);
- Expr *expr;
+ Oper *oper;
List *l;
char *sep;
char buf[BUFSIZE];
@@ -1620,20 +1620,20 @@ get_sublink_expr(QryHier *qh, int rt_index, Node *node, bool varprefix)
break;
case ANY_SUBLINK:
- expr = (Expr *) lfirst(sublink->oper);
- strcat(buf, get_opname(((Oper *) (expr->oper))->opno));
+ oper = (Oper *) lfirst(sublink->oper);
+ strcat(buf, get_opname(oper->opno));
strcat(buf, " ANY ");
break;
case ALL_SUBLINK:
- expr = (Expr *) lfirst(sublink->oper);
- strcat(buf, get_opname(((Oper *) (expr->oper))->opno));
+ oper = (Oper *) lfirst(sublink->oper);
+ strcat(buf, get_opname(oper->opno));
strcat(buf, " ALL ");
break;
case EXPR_SUBLINK:
- expr = (Expr *) lfirst(sublink->oper);
- strcat(buf, get_opname(((Oper *) (expr->oper))->opno));
+ oper = (Oper *) lfirst(sublink->oper);
+ strcat(buf, get_opname(oper->opno));
strcat(buf, " ");
break;
@@ -1766,6 +1766,7 @@ check_if_rte_used(int rt_index, Node *node, int sup)
if (check_if_rte_used(rt_index, (Node *) (query->qual), sup + 1))
return TRUE;
+ /* why aren't we looking at query->targetlist, havingQual? */
if (check_if_rte_used(rt_index, (Node *) (sublink->lefthand), sup))
return TRUE;
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 10e51e40268..e2ef42218fc 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: primnodes.h,v 1.35 1999/08/22 20:15:00 tgl Exp $
+ * $Id: primnodes.h,v 1.36 1999/08/25 23:21:36 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -319,10 +319,36 @@ typedef struct Aggref
/* ----------------
* SubLink
* subLinkType - EXISTS, ALL, ANY, EXPR
- * useor - TRUE for <>
- * lefthand - list of Var/Const nodes on the left
+ * useor - TRUE for <> (combine op results with "or" not "and")
+ * lefthand - list of outer-query expressions on the left
* oper - list of Oper nodes
* subselect - subselect as Query* or parsetree
+ *
+ * NOTE: lefthand and oper have varying meanings depending on where you look
+ * in the parse/plan pipeline:
+ * 1. gram.y delivers a list of the (untransformed) lefthand expressions in
+ * lefthand, and sets oper to a one-element list containing the string
+ * name of the operator.
+ * 2. The parser's expression transformation transforms lefthand normally,
+ * and replaces oper with a list of Oper nodes, one per lefthand
+ * expression. These nodes represent the parser's resolution of exactly
+ * which operator to apply to each pair of lefthand and targetlist
+ * expressions. However, we have not constructed actual Expr trees for
+ * these operators yet. This is the representation seen in saved rules
+ * and in the rewriter.
+ * 3. Finally, the planner converts the oper list to a list of normal Expr
+ * nodes representing the application of the operator(s) to the lefthand
+ * expressions and values from the inner targetlist. The inner
+ * targetlist items are represented by placeholder Param or Const nodes.
+ * The lefthand field is set to NIL, since its expressions are now in
+ * the Expr list. This representation is passed to the executor.
+ *
+ * Planner routines that might see either representation 2 or 3 can tell
+ * the difference by checking whether lefthand is NIL or not. Also,
+ * representation 2 appears in a "bare" SubLink, while representation 3 is
+ * found in SubLinks that are children of SubPlan nodes.
+ *
+ * In an EXISTS SubLink, both lefthand and oper are unused and are always NIL.
* ----------------
*/
typedef enum SubLinkType