Commit b122e16a authored by Jan Wieck's avatar Jan Wieck

Bugfix - Range table entries that are unused after rewriting should

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
parent f4fadbe4
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -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 * static Node *
FindMatchingTLEntry(List *tlist, char *e_attname) FindMatchingTLEntry(List *tlist, char *e_attname)
{ {
...@@ -2116,10 +2239,23 @@ fireRIRrules(Query *parsetree) ...@@ -2116,10 +2239,23 @@ fireRIRrules(Query *parsetree)
while(rt_index < length(parsetree->rtable)) { while(rt_index < length(parsetree->rtable)) {
++rt_index; ++rt_index;
rte = nth(rt_index - 1, parsetree->rtable);
if (!rangeTableEntry_used((Node *)parsetree, rt_index, 0)) 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; continue;
}
rte = nth(rt_index - 1, parsetree->rtable);
rel = heap_openr(rte->relname); rel = heap_openr(rte->relname);
if (rel->rd_rules == NULL) { if (rel->rd_rules == NULL) {
heap_close(rel); heap_close(rel);
...@@ -2705,6 +2841,8 @@ BasicQueryRewrite(Query *parsetree) ...@@ -2705,6 +2841,8 @@ BasicQueryRewrite(Query *parsetree)
if (query->hasAggs) if (query->hasAggs)
query->hasAggs = checkQueryHasAggs((Node *)(query->targetList)) query->hasAggs = checkQueryHasAggs((Node *)(query->targetList))
| checkQueryHasAggs((Node *)(query->havingQual)); | checkQueryHasAggs((Node *)(query->havingQual));
query->hasSubLinks = checkQueryHasSubLink((Node *)(query->qual))
| checkQueryHasSubLink((Node *)(query->havingQual));
results = lappend(results, query); results = lappend(results, query);
} }
return results; return results;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment