Except_Intersect_Rewrite() failed to ignore resjunk targetlist entries,

thus causing failure if one sub-select had resjunk entries that the other
did not (cf. bug report from Espinosa 4/27/00).
This commit is contained in:
Tom Lane 2000-04-27 20:32:41 +00:00
parent fb7318a632
commit f106779263
1 changed files with 50 additions and 33 deletions

View File

@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.72 2000/04/20 00:31:49 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.73 2000/04/27 20:32:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1542,41 +1542,52 @@ QueryRewrite(Query *parsetree)
static void static void
check_targetlists_are_compatible(List *prev_target, List *current_target) check_targetlists_are_compatible(List *prev_target, List *current_target)
{ {
List *tl, List *tl;
*next_target;
int prev_len = 0, int prev_len = 0,
next_len = 0; next_len = 0;
foreach(tl, prev_target) foreach(tl, prev_target)
if (!((TargetEntry *) lfirst(tl))->resdom->resjunk) if (!((TargetEntry *) lfirst(tl))->resdom->resjunk)
prev_len++; prev_len++;
foreach(next_target, current_target) foreach(tl, current_target)
if (!((TargetEntry *) lfirst(next_target))->resdom->resjunk) if (!((TargetEntry *) lfirst(tl))->resdom->resjunk)
next_len++; next_len++;
if (prev_len != next_len) if (prev_len != next_len)
elog(ERROR, "Each UNION | EXCEPT | INTERSECT query must have the same number of columns."); elog(ERROR, "Each UNION | EXCEPT | INTERSECT query must have the same number of columns.");
foreach(next_target, current_target) foreach(tl, current_target)
{ {
Oid itype; TargetEntry *next_tle = (TargetEntry *) lfirst(tl);
Oid otype; TargetEntry *prev_tle;
Oid itype;
Oid otype;
otype = ((TargetEntry *) lfirst(prev_target))->resdom->restype; if (next_tle->resdom->resjunk)
itype = ((TargetEntry *) lfirst(next_target))->resdom->restype; continue;
/* This loop must find an entry, since we counted them above. */
do
{
prev_tle = (TargetEntry *) lfirst(prev_target);
prev_target = lnext(prev_target);
} while (prev_tle->resdom->resjunk);
itype = next_tle->resdom->restype;
otype = prev_tle->resdom->restype;
/* one or both is a NULL column? then don't convert... */ /* one or both is a NULL column? then don't convert... */
if (otype == InvalidOid) if (otype == InvalidOid)
{ {
/* propagate a known type forward, if available */ /* propagate a known type forward, if available */
if (itype != InvalidOid) if (itype != InvalidOid)
((TargetEntry *) lfirst(prev_target))->resdom->restype = itype; prev_tle->resdom->restype = itype;
#ifdef NOT_USED #ifdef NOT_USED
else else
{ {
((TargetEntry *) lfirst(prev_target))->resdom->restype = UNKNOWNOID; prev_tle->resdom->restype = UNKNOWNOID;
((TargetEntry *) lfirst(next_target))->resdom->restype = UNKNOWNOID; next_tle->resdom->restype = UNKNOWNOID;
} }
#endif #endif
} }
@ -1588,7 +1599,7 @@ check_targetlists_are_compatible(List *prev_target, List *current_target)
{ {
Node *expr; Node *expr;
expr = ((TargetEntry *) lfirst(next_target))->expr; expr = next_tle->expr;
expr = CoerceTargetExpr(NULL, expr, itype, otype, -1); expr = CoerceTargetExpr(NULL, expr, itype, otype, -1);
if (expr == NULL) if (expr == NULL)
{ {
@ -1597,17 +1608,16 @@ check_targetlists_are_compatible(List *prev_target, List *current_target)
typeidTypeName(itype), typeidTypeName(itype),
typeidTypeName(otype)); typeidTypeName(otype));
} }
((TargetEntry *) lfirst(next_target))->expr = expr; next_tle->expr = expr;
((TargetEntry *) lfirst(next_target))->resdom->restype = otype; next_tle->resdom->restype = otype;
} }
/* both are UNKNOWN? then evaluate as text... */ /* both are UNKNOWN? then evaluate as text... */
else if (itype == UNKNOWNOID) else if (itype == UNKNOWNOID)
{ {
((TargetEntry *) lfirst(next_target))->resdom->restype = TEXTOID; next_tle->resdom->restype = TEXTOID;
((TargetEntry *) lfirst(prev_target))->resdom->restype = TEXTOID; prev_tle->resdom->restype = TEXTOID;
} }
prev_target = lnext(prev_target);
} }
} }
@ -1645,7 +1655,6 @@ Except_Intersect_Rewrite(Query *parsetree)
*sortClause, *sortClause,
*distinctClause; *distinctClause;
List *left_expr, List *left_expr,
*right_expr,
*resnames = NIL; *resnames = NIL;
char *op, char *op,
*into; *into;
@ -1664,14 +1673,15 @@ Except_Intersect_Rewrite(Query *parsetree)
* formulated by the user and he wants the columns named by these * formulated by the user and he wants the columns named by these
* strings. The transformation to DNF can cause another Select * strings. The transformation to DNF can cause another Select
* Statment to be the top one which uses other names for its columns. * Statment to be the top one which uses other names for its columns.
* Therefore we remeber the original names and attach them to the * Therefore we remember the original names and attach them to the
* targetlist of the new topmost Node at the end of this function * targetlist of the new topmost Node at the end of this function
*/ */
foreach(elist, parsetree->targetList) foreach(elist, parsetree->targetList)
{ {
TargetEntry *tent = (TargetEntry *) lfirst(elist); TargetEntry *tent = (TargetEntry *) lfirst(elist);
resnames = lappend(resnames, tent->resdom->resname); if (! tent->resdom->resjunk)
resnames = lappend(resnames, tent->resdom->resname);
} }
/* /*
@ -1778,7 +1788,6 @@ Except_Intersect_Rewrite(Query *parsetree)
if (prev_target) if (prev_target)
check_targetlists_are_compatible(prev_target, intersect_node->targetList); check_targetlists_are_compatible(prev_target, intersect_node->targetList);
prev_target = intersect_node->targetList; prev_target = intersect_node->targetList;
/* End of check for corresponding targetlists */
/* /*
* Transform all nodes remaining into subselects and add them to * Transform all nodes remaining into subselects and add them to
@ -1800,7 +1809,6 @@ Except_Intersect_Rewrite(Query *parsetree)
*/ */
check_targetlists_are_compatible(prev_target, check_targetlists_are_compatible(prev_target,
((Query *) lfirst(intersect_list))->targetList); ((Query *) lfirst(intersect_list))->targetList);
/* End of check for corresponding targetlists */
n->subselect = lfirst(intersect_list); n->subselect = lfirst(intersect_list);
op = "="; op = "=";
@ -1822,7 +1830,6 @@ Except_Intersect_Rewrite(Query *parsetree)
*/ */
check_targetlists_are_compatible(prev_target, check_targetlists_are_compatible(prev_target,
((Query *) lfirst(((Expr *) lfirst(intersect_list))->args))->targetList); ((Query *) lfirst(((Expr *) lfirst(intersect_list))->args))->targetList);
/* End of check for corresponding targetlists */
n->subselect = (Node *) lfirst(((Expr *) lfirst(intersect_list))->args); n->subselect = (Node *) lfirst(((Expr *) lfirst(intersect_list))->args);
op = "<>"; op = "<>";
@ -1840,7 +1847,8 @@ Except_Intersect_Rewrite(Query *parsetree)
{ {
TargetEntry *tent = (TargetEntry *) lfirst(elist); TargetEntry *tent = (TargetEntry *) lfirst(elist);
n->lefthand = lappend(n->lefthand, tent->expr); if (! tent->resdom->resjunk)
n->lefthand = lappend(n->lefthand, tent->expr);
} }
/* /*
@ -1849,17 +1857,21 @@ Except_Intersect_Rewrite(Query *parsetree)
* involved!) * involved!)
*/ */
left_expr = n->lefthand; left_expr = n->lefthand;
right_expr = ((Query *) (n->subselect))->targetList;
n->oper = NIL; n->oper = NIL;
foreach(elist, left_expr) foreach(elist, ((Query *) (n->subselect))->targetList)
{ {
Node *lexpr = lfirst(elist); TargetEntry *tent = (TargetEntry *) lfirst(elist);
TargetEntry *tent = (TargetEntry *) lfirst(right_expr); Node *lexpr;
Operator optup; Operator optup;
Form_pg_operator opform; Form_pg_operator opform;
Oper *newop; Oper *newop;
if (tent->resdom->resjunk)
continue;
lexpr = lfirst(left_expr);
optup = oper(op, optup = oper(op,
exprType(lexpr), exprType(lexpr),
exprType(tent->expr), exprType(tent->expr),
@ -1877,9 +1889,11 @@ Except_Intersect_Rewrite(Query *parsetree)
n->oper = lappend(n->oper, newop); n->oper = lappend(n->oper, newop);
right_expr = lnext(right_expr); left_expr = lnext(left_expr);
} }
Assert(left_expr == NIL); /* should have used 'em all */
/* /*
* If the Select Query node has aggregates in use add all the * If the Select Query node has aggregates in use add all the
* subselects to the HAVING qual else to the WHERE qual * subselects to the HAVING qual else to the WHERE qual
@ -1930,6 +1944,9 @@ Except_Intersect_Rewrite(Query *parsetree)
{ {
TargetEntry *tent = (TargetEntry *) lfirst(elist); TargetEntry *tent = (TargetEntry *) lfirst(elist);
if (tent->resdom->resjunk)
continue;
tent->resdom->resname = lfirst(resnames); tent->resdom->resname = lfirst(resnames);
resnames = lnext(resnames); resnames = lnext(resnames);
} }