1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-14 18:42:34 +03:00

Selectively include window frames in expression walks/mutates.

query_tree_walker and query_tree_mutator were skipping the
windowClause of the query, without regard for the fact that the
startOffset and endOffset in a WindowClause node are expression trees
that need to be processed. This was an oversight in commit ec4be2ee6
from 2010 which added the expression fields; the main symptom is that
function parameters in window frame clauses don't work in inlined
functions.

Fix (as conservatively as possible since this needs to not break
existing out-of-tree callers) and add tests.

Backpatch all the way, since this has been broken since 9.0.

Per report from Alastair McKinley; fix by me with kibitzing and review
from Tom Lane.

Discussion: https://postgr.es/m/DB6PR0202MB2904E7FDDA9D81504D1E8C68E3800@DB6PR0202MB2904.eurprd02.prod.outlook.com
This commit is contained in:
Andrew Gierth
2019-10-03 10:54:52 +01:00
parent b1c1aa5318
commit b7a1c5539a
5 changed files with 169 additions and 7 deletions

View File

@ -2278,6 +2278,13 @@ query_tree_walker(Query *query,
{
Assert(query != NULL && IsA(query, Query));
/*
* We don't walk any utilityStmt here. However, we can't easily assert
* that it is absent, since there are at least two code paths by which
* action statements from CREATE RULE end up here, and NOTIFY is allowed
* in a rule action.
*/
if (walker((Node *) query->targetList, context))
return true;
if (walker((Node *) query->withCheckOptions, context))
@ -2296,6 +2303,54 @@ query_tree_walker(Query *query,
return true;
if (walker(query->limitCount, context))
return true;
/*
* Most callers aren't interested in SortGroupClause nodes since those
* don't contain actual expressions. However they do contain OIDs which
* may be needed by dependency walkers etc.
*/
if ((flags & QTW_EXAMINE_SORTGROUP))
{
if (walker((Node *) query->groupClause, context))
return true;
if (walker((Node *) query->windowClause, context))
return true;
if (walker((Node *) query->sortClause, context))
return true;
if (walker((Node *) query->distinctClause, context))
return true;
}
else
{
/*
* But we need to walk the expressions under WindowClause nodes even
* if we're not interested in SortGroupClause nodes.
*/
ListCell *lc;
foreach(lc, query->windowClause)
{
WindowClause *wc = lfirst_node(WindowClause, lc);
if (walker(wc->startOffset, context))
return true;
if (walker(wc->endOffset, context))
return true;
}
}
/*
* groupingSets and rowMarks are not walked:
*
* groupingSets contain only ressortgrouprefs (integers) which are
* meaningless without the corresponding groupClause or tlist.
* Accordingly, any walker that needs to care about them needs to handle
* them itself in its Query processing.
*
* rowMarks is not walked because it contains only rangetable indexes (and
* flags etc.) and therefore should be handled at Query level similarly.
*/
if (!(flags & QTW_IGNORE_CTE_SUBQUERIES))
{
if (walker((Node *) query->cteList, context))
@ -3153,6 +3208,56 @@ query_tree_mutator(Query *query,
MUTATE(query->havingQual, query->havingQual, Node *);
MUTATE(query->limitOffset, query->limitOffset, Node *);
MUTATE(query->limitCount, query->limitCount, Node *);
/*
* Most callers aren't interested in SortGroupClause nodes since those
* don't contain actual expressions. However they do contain OIDs, which
* may be of interest to some mutators.
*/
if ((flags & QTW_EXAMINE_SORTGROUP))
{
MUTATE(query->groupClause, query->groupClause, List *);
MUTATE(query->windowClause, query->windowClause, List *);
MUTATE(query->sortClause, query->sortClause, List *);
MUTATE(query->distinctClause, query->distinctClause, List *);
}
else
{
/*
* But we need to mutate the expressions under WindowClause nodes even
* if we're not interested in SortGroupClause nodes.
*/
List *resultlist;
ListCell *temp;
resultlist = NIL;
foreach(temp, query->windowClause)
{
WindowClause *wc = lfirst_node(WindowClause, temp);
WindowClause *newnode;
FLATCOPY(newnode, wc, WindowClause);
MUTATE(newnode->startOffset, wc->startOffset, Node *);
MUTATE(newnode->endOffset, wc->endOffset, Node *);
resultlist = lappend(resultlist, (Node *) newnode);
}
query->windowClause = resultlist;
}
/*
* groupingSets and rowMarks are not mutated:
*
* groupingSets contain only ressortgroup refs (integers) which are
* meaningless without the groupClause or tlist. Accordingly, any mutator
* that needs to care about them needs to handle them itself in its Query
* processing.
*
* rowMarks contains only rangetable indexes (and flags etc.) and
* therefore should be handled at Query level similarly.
*/
if (!(flags & QTW_IGNORE_CTE_SUBQUERIES))
MUTATE(query->cteList, query->cteList, List *);
else /* else copy CTE list as-is */