Except_Intersect_Rewrite() failed to ignore resjunk targetlist entries,
authorTom Lane <[email protected]>
Thu, 27 Apr 2000 20:32:41 +0000 (20:32 +0000)
committerTom Lane <[email protected]>
Thu, 27 Apr 2000 20:32:41 +0000 (20:32 +0000)
thus causing failure if one sub-select had resjunk entries that the other
did not (cf. bug report from Espinosa 4/27/00).

src/backend/rewrite/rewriteHandler.c

index 327d8c0aefee4a50c223796ecfe868db55282c5d..8d740ddd9984ab14cd38e2700b6fd68c18feff8f 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * 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
 check_targetlists_are_compatible(List *prev_target, List *current_target)
 {
-       List       *tl,
-                          *next_target;
+       List       *tl;
        int                     prev_len = 0,
                                next_len = 0;
 
        foreach(tl, prev_target)
                if (!((TargetEntry *) lfirst(tl))->resdom->resjunk)
-               prev_len++;
+                       prev_len++;
 
-       foreach(next_target, current_target)
-               if (!((TargetEntry *) lfirst(next_target))->resdom->resjunk)
-               next_len++;
+       foreach(tl, current_target)
+               if (!((TargetEntry *) lfirst(tl))->resdom->resjunk)
+                       next_len++;
 
        if (prev_len != next_len)
                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;
-               Oid                     otype;
+               TargetEntry        *next_tle = (TargetEntry *) lfirst(tl);
+               TargetEntry        *prev_tle;
+               Oid                             itype;
+               Oid                             otype;
+
+               if (next_tle->resdom->resjunk)
+                       continue;
 
-               otype = ((TargetEntry *) lfirst(prev_target))->resdom->restype;
-               itype = ((TargetEntry *) lfirst(next_target))->resdom->restype;
+               /* 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... */
                if (otype == InvalidOid)
                {
                        /* propagate a known type forward, if available */
                        if (itype != InvalidOid)
-                               ((TargetEntry *) lfirst(prev_target))->resdom->restype = itype;
+                               prev_tle->resdom->restype = itype;
 #ifdef NOT_USED
                        else
                        {
-                               ((TargetEntry *) lfirst(prev_target))->resdom->restype = UNKNOWNOID;
-                               ((TargetEntry *) lfirst(next_target))->resdom->restype = UNKNOWNOID;
+                               prev_tle->resdom->restype = UNKNOWNOID;
+                               next_tle->resdom->restype = UNKNOWNOID;
                        }
 #endif
                }
@@ -1588,7 +1599,7 @@ check_targetlists_are_compatible(List *prev_target, List *current_target)
                {
                        Node       *expr;
 
-                       expr = ((TargetEntry *) lfirst(next_target))->expr;
+                       expr = next_tle->expr;
                        expr = CoerceTargetExpr(NULL, expr, itype, otype, -1);
                        if (expr == NULL)
                        {
@@ -1597,17 +1608,16 @@ check_targetlists_are_compatible(List *prev_target, List *current_target)
                                         typeidTypeName(itype),
                                         typeidTypeName(otype));
                        }
-                       ((TargetEntry *) lfirst(next_target))->expr = expr;
-                       ((TargetEntry *) lfirst(next_target))->resdom->restype = otype;
+                       next_tle->expr = expr;
+                       next_tle->resdom->restype = otype;
                }
 
                /* both are UNKNOWN? then evaluate as text... */
                else if (itype == UNKNOWNOID)
                {
-                       ((TargetEntry *) lfirst(next_target))->resdom->restype = TEXTOID;
-                       ((TargetEntry *) lfirst(prev_target))->resdom->restype = TEXTOID;
+                       next_tle->resdom->restype = TEXTOID;
+                       prev_tle->resdom->restype = TEXTOID;
                }
-               prev_target = lnext(prev_target);
        }
 }
 
@@ -1645,7 +1655,6 @@ Except_Intersect_Rewrite(Query *parsetree)
                           *sortClause,
                           *distinctClause;
        List       *left_expr,
-                          *right_expr,
                           *resnames = NIL;
        char       *op,
                           *into;
@@ -1664,14 +1673,15 @@ Except_Intersect_Rewrite(Query *parsetree)
         * formulated by the user and he wants the columns named by these
         * strings. The transformation to DNF can cause another Select
         * 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
         */
        foreach(elist, parsetree->targetList)
        {
                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)
                        check_targetlists_are_compatible(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
@@ -1800,7 +1809,6 @@ Except_Intersect_Rewrite(Query *parsetree)
                                 */
                                check_targetlists_are_compatible(prev_target,
                                                 ((Query *) lfirst(intersect_list))->targetList);
-                               /* End of check for corresponding targetlists */
 
                                n->subselect = lfirst(intersect_list);
                                op = "=";
@@ -1822,7 +1830,6 @@ Except_Intersect_Rewrite(Query *parsetree)
                                 */
                                check_targetlists_are_compatible(prev_target,
                                                                                                 ((Query *) lfirst(((Expr *) lfirst(intersect_list))->args))->targetList);
-                               /* End of check for corresponding targetlists */
 
                                n->subselect = (Node *) lfirst(((Expr *) lfirst(intersect_list))->args);
                                op = "<>";
@@ -1840,7 +1847,8 @@ Except_Intersect_Rewrite(Query *parsetree)
                        {
                                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!)
                         */
                        left_expr = n->lefthand;
-                       right_expr = ((Query *) (n->subselect))->targetList;
                        n->oper = NIL;
 
-                       foreach(elist, left_expr)
+                       foreach(elist, ((Query *) (n->subselect))->targetList)
                        {
-                               Node       *lexpr = lfirst(elist);
-                               TargetEntry *tent = (TargetEntry *) lfirst(right_expr);
+                               TargetEntry *tent = (TargetEntry *) lfirst(elist);
+                               Node       *lexpr;
                                Operator        optup;
                                Form_pg_operator opform;
                                Oper       *newop;
 
+                               if (tent->resdom->resjunk)
+                                       continue;
+
+                               lexpr = lfirst(left_expr);
+
                                optup = oper(op,
                                                         exprType(lexpr),
                                                         exprType(tent->expr),
@@ -1877,9 +1889,11 @@ Except_Intersect_Rewrite(Query *parsetree)
 
                                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
                         * subselects to the HAVING qual else to the WHERE qual
@@ -1930,6 +1944,9 @@ Except_Intersect_Rewrite(Query *parsetree)
        {
                TargetEntry *tent = (TargetEntry *) lfirst(elist);
 
+               if (tent->resdom->resjunk)
+                       continue;
+
                tent->resdom->resname = lfirst(resnames);
                resnames = lnext(resnames);
        }