Bugfix - Range table entries that are unused after rewriting should
authorJan Wieck
Tue, 25 May 1999 13:16:10 +0000 (13:16 +0000)
committerJan Wieck
Tue, 25 May 1999 13:16:10 +0000 (13:16 +0000)
not be marked inFromCl any longer. Otherwise the planner gets confused
and joins over them where in fact it does not have to.

Adjust hasSubLinks now with a recursive lookup - could be wrong in
multi action rules because parse state isn't reset correctly and all
actions in the rule are marked hasSubLinks if one of them has.

Jan

src/backend/rewrite/rewriteHandler.c

index 26626d0bb8a52dfc2f6aa7b572aecc263f632998..7769d72299280bed86610acc2ca75bb05068fe7c 100644 (file)
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.43 1999/05/17 18:22:19 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.44 1999/05/25 13:16:10 wieck Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1393,6 +1393,129 @@ checkQueryHasAggs(Node *node)
 }
 
 
+/*
+ * checkQueryHasSubLink -
+ * Queries marked hasAggs might not have them any longer after
+ * rewriting. Check it.
+ */
+static bool
+checkQueryHasSubLink(Node *node)
+{
+   if (node == NULL)
+       return FALSE;
+
+   switch(nodeTag(node)) {
+       case T_TargetEntry:
+           {
+               TargetEntry *tle = (TargetEntry *)node;
+
+               return checkQueryHasSubLink((Node *)(tle->expr));
+           }
+           break;
+
+       case T_Aggref:
+           return TRUE;
+
+       case T_Expr:
+           {
+               Expr    *exp = (Expr *)node;
+
+               return checkQueryHasSubLink((Node *)(exp->args));
+           }
+           break;
+
+       case T_Iter:
+           {
+               Iter    *iter = (Iter *)node;
+
+               return checkQueryHasSubLink((Node *)(iter->iterexpr));
+           }
+           break;
+
+       case T_ArrayRef:
+           {
+               ArrayRef    *ref = (ArrayRef *)node;
+
+               if (checkQueryHasSubLink((Node *)(ref->refupperindexpr)))
+                   return TRUE;
+               
+               if (checkQueryHasSubLink((Node *)(ref->reflowerindexpr)))
+                   return TRUE;
+               
+               if (checkQueryHasSubLink((Node *)(ref->refexpr)))
+                   return TRUE;
+               
+               if (checkQueryHasSubLink((Node *)(ref->refassgnexpr)))
+                   return TRUE;
+               
+               return FALSE;
+           }
+           break;
+
+       case T_Var:
+           return FALSE;
+
+       case T_Param:
+           return FALSE;
+
+       case T_Const:
+           return FALSE;
+
+       case T_List:
+           {
+               List    *l;
+
+               foreach (l, (List *)node) {
+                   if (checkQueryHasSubLink((Node *)lfirst(l)))
+                       return TRUE;
+               }
+               return FALSE;
+           }
+           break;
+
+       case T_CaseExpr:
+           {
+               CaseExpr    *exp = (CaseExpr *)node;
+
+               if (checkQueryHasSubLink((Node *)(exp->args)))
+                   return TRUE;
+
+               if (checkQueryHasSubLink((Node *)(exp->defresult)))
+                   return TRUE;
+
+               return FALSE;
+           }
+           break;
+
+       case T_CaseWhen:
+           {
+               CaseWhen    *when = (CaseWhen *)node;
+
+               if (checkQueryHasSubLink((Node *)(when->expr)))
+                   return TRUE;
+
+               if (checkQueryHasSubLink((Node *)(when->result)))
+                   return TRUE;
+
+               return FALSE;
+           }
+           break;
+
+       case T_SubLink:
+           return TRUE;
+
+       default:
+           elog(NOTICE, "unknown node tag %d in checkQueryHasSubLink()", nodeTag(node));
+           elog(NOTICE, "Node is: %s", nodeToString(node));
+           break;
+
+
+   }
+
+   return FALSE;
+}
+
+
 static Node *
 FindMatchingTLEntry(List *tlist, char *e_attname)
 {
@@ -2116,10 +2239,23 @@ fireRIRrules(Query *parsetree)
    while(rt_index < length(parsetree->rtable)) {
        ++rt_index;
 
+       rte = nth(rt_index - 1, parsetree->rtable);
+
        if (!rangeTableEntry_used((Node *)parsetree, rt_index, 0))
+       {
+           /*
+            * Unused range table entries must not be marked as coming
+            * from a clause. Otherwise the planner will generate
+            * joins over relations that in fact shouldn't be scanned
+            * at all and the result will contain duplicates
+            *
+            * Jan
+            *
+            */
+           rte->inFromCl = FALSE;
            continue;
+       }
        
-       rte = nth(rt_index - 1, parsetree->rtable);
        rel = heap_openr(rte->relname);
        if (rel->rd_rules == NULL) {
            heap_close(rel);
@@ -2705,6 +2841,8 @@ BasicQueryRewrite(Query *parsetree)
        if (query->hasAggs)
            query->hasAggs = checkQueryHasAggs((Node *)(query->targetList))
                           | checkQueryHasAggs((Node *)(query->havingQual));
+       query->hasSubLinks = checkQueryHasSubLink((Node *)(query->qual))
+                          | checkQueryHasSubLink((Node *)(query->havingQual));
        results = lappend(results, query);
    }
    return results;