mirror of
https://github.com/postgres/postgres.git
synced 2025-06-26 12:21:12 +03:00
Revise implementation of SubLinks so that there is a consistent,
documented intepretation of the lefthand and oper fields. Fix a number of obscure problems while at it --- for example, the old code failed if the parser decided to insert a type-coercion function just below the operator of a SubLink. CAUTION: this will break stored rules that contain subplans. You may need to initdb.
This commit is contained in:
@ -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"
|
||||
@ -642,9 +646,6 @@ modifyAggrefUplevel(Node *node)
|
||||
modifyAggrefUplevel(
|
||||
(Node *) (sub->lefthand));
|
||||
|
||||
modifyAggrefUplevel(
|
||||
(Node *) (sub->oper));
|
||||
|
||||
modifyAggrefUplevel(
|
||||
(Node *) (sub->subselect));
|
||||
}
|
||||
@ -816,12 +817,6 @@ modifyAggrefChangeVarnodes(Node **nodePtr, int rt_index, int new_index, int subl
|
||||
new_index,
|
||||
sublevels_up);
|
||||
|
||||
modifyAggrefChangeVarnodes(
|
||||
(Node **) (&(sub->oper)),
|
||||
rt_index,
|
||||
new_index,
|
||||
sublevels_up);
|
||||
|
||||
modifyAggrefChangeVarnodes(
|
||||
(Node **) (&(sub->subselect)),
|
||||
rt_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;
|
||||
|
||||
op_expr = make_op(op, lexpr, tent->expr);
|
||||
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);
|
||||
|
||||
n->oper = lappend(n->oper, newop);
|
||||
|
||||
n->oper = lappend(n->oper, op_expr);
|
||||
right_expr = lnext(right_expr);
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
Reference in New Issue
Block a user