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:
parent
fb7318a632
commit
f106779263
@ -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,8 +1542,7 @@ 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;
|
||||||
|
|
||||||
@ -1551,32 +1550,44 @@ check_targetlists_are_compatible(List *prev_target, List *current_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)
|
||||||
{
|
{
|
||||||
|
TargetEntry *next_tle = (TargetEntry *) lfirst(tl);
|
||||||
|
TargetEntry *prev_tle;
|
||||||
Oid itype;
|
Oid itype;
|
||||||
Oid otype;
|
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,13 +1673,14 @@ 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);
|
||||||
|
|
||||||
|
if (! tent->resdom->resjunk)
|
||||||
resnames = lappend(resnames, tent->resdom->resname);
|
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,6 +1847,7 @@ Except_Intersect_Rewrite(Query *parsetree)
|
|||||||
{
|
{
|
||||||
TargetEntry *tent = (TargetEntry *) lfirst(elist);
|
TargetEntry *tent = (TargetEntry *) lfirst(elist);
|
||||||
|
|
||||||
|
if (! tent->resdom->resjunk)
|
||||||
n->lefthand = lappend(n->lefthand, tent->expr);
|
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);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user