88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.190 2009/07/16 06:33:43 petere Exp $
11+ * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.191 2009/08/27 20:08:02 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
3737#include "utils/rel.h"
3838
3939
40+ /* clause types for findTargetlistEntrySQL92 */
4041#define ORDER_CLAUSE 0
4142#define GROUP_CLAUSE 1
4243#define DISTINCT_ON_CLAUSE 2
43- #define PARTITION_CLAUSE 3
4444
4545static const char * const clauseText []= {
4646"ORDER BY" ,
4747"GROUP BY" ,
48- "DISTINCT ON" ,
49- "PARTITION BY"
48+ "DISTINCT ON"
5049};
5150
5251static void extractRemainingColumns (List * common_colnames ,
@@ -73,8 +72,10 @@ static Node *transformFromClauseItem(ParseState *pstate, Node *n,
7372Relids * containedRels );
7473static Node * buildMergedJoinVar (ParseState * pstate ,JoinType jointype ,
7574Var * l_colvar ,Var * r_colvar );
76- static TargetEntry * findTargetlistEntry (ParseState * pstate ,Node * node ,
77- List * * tlist ,int clause );
75+ static TargetEntry * findTargetlistEntrySQL92 (ParseState * pstate ,Node * node ,
76+ List * * tlist ,int clause );
77+ static TargetEntry * findTargetlistEntrySQL99 (ParseState * pstate ,Node * node ,
78+ List * * tlist );
7879static int get_matching_location (int sortgroupref ,
7980List * sortgrouprefs ,List * exprs );
8081static List * addTargetToSortList (ParseState * pstate ,TargetEntry * tle ,
@@ -1216,21 +1217,27 @@ transformLimitClause(ParseState *pstate, Node *clause,
12161217
12171218
12181219/*
1219- *findTargetlistEntry -
1220+ *findTargetlistEntrySQL92 -
12201221 * Returns the targetlist entry matching the given (untransformed) node.
12211222 * If no matching entry exists, one is created and appended to the target
12221223 * list as a "resjunk" node.
12231224 *
1225+ * This function supports the old SQL92 ORDER BY interpretation, where the
1226+ * expression is an output column name or number. If we fail to find a
1227+ * match of that sort, we fall through to the SQL99 rules. For historical
1228+ * reasons, Postgres also allows this interpretation for GROUP BY, though
1229+ * the standard never did. However, for GROUP BY we prefer a SQL99 match.
1230+ * This function is *not* used for WINDOW definitions.
1231+ *
12241232 * nodethe ORDER BY, GROUP BY, or DISTINCT ON expression to be matched
12251233 * tlistthe target list (passed by reference so we can append to it)
12261234 * clauseidentifies clause type being processed
12271235 */
12281236static TargetEntry *
1229- findTargetlistEntry (ParseState * pstate ,Node * node ,List * * tlist ,int clause )
1237+ findTargetlistEntrySQL92 (ParseState * pstate ,Node * node ,List * * tlist ,
1238+ int clause )
12301239{
1231- TargetEntry * target_result = NULL ;
12321240ListCell * tl ;
1233- Node * expr ;
12341241
12351242/*----------
12361243 * Handle two special cases as mandated by the SQL92 spec:
@@ -1258,8 +1265,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
12581265 * 2. IntegerConstant
12591266 * This means to use the n'th item in the existing target list.
12601267 * Note that it would make no sense to order/group/distinct by an
1261- * actual constant, so this does not create a conflict with our
1262- * extension to order/group by an expression.
1268+ * actual constant, so this does not create a conflict with SQL99.
12631269 * GROUP BY column-number is not allowed by SQL92, but since
12641270 * the standard has no other behavior defined for this syntax,
12651271 * we may as well accept this common extension.
@@ -1268,7 +1274,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
12681274 * since the user didn't write them in his SELECT list.
12691275 *
12701276 * If neither special case applies, fall through to treat the item as
1271- * an expression.
1277+ * an expression per SQL99 .
12721278 *----------
12731279 */
12741280if (IsA (node ,ColumnRef )&&
@@ -1278,15 +1284,15 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
12781284char * name = strVal (linitial (((ColumnRef * )node )-> fields ));
12791285int location = ((ColumnRef * )node )-> location ;
12801286
1281- if (clause == GROUP_CLAUSE || clause == PARTITION_CLAUSE )
1287+ if (clause == GROUP_CLAUSE )
12821288{
12831289/*
12841290 * In GROUP BY, we must prefer a match against a FROM-clause
12851291 * column to one against the targetlist. Look to see if there is
1286- * a matching column. If so, fall through tolet transformExpr()
1287- *do the rest. NOTE: if name could refer ambiguously to more
1288- *than one column name exposed by FROM, colNameToVar will
1289- *ereport(ERROR).That's just what we want here.
1292+ * a matching column. If so, fall through touse SQL99 rules.
1293+ * NOTE: if name could refer ambiguously to more than one column
1294+ * name exposed by FROM, colNameToVar will ereport(ERROR). That's
1295+ * just what we want here.
12901296 *
12911297 * Small tweak for 7.4.3: ignore matches in upper query levels.
12921298 * This effectively changes the search order for bare names to (1)
@@ -1295,15 +1301,15 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
12951301 * SQL99 do not allow GROUPing BY an outer reference, so this
12961302 * breaks no cases that are legal per spec, and it seems a more
12971303 * self-consistent behavior.
1298- *
1299- * Window PARTITION BY clauses should act exactly like GROUP BY.
13001304 */
13011305if (colNameToVar (pstate ,name , true,location )!= NULL )
13021306name = NULL ;
13031307}
13041308
13051309if (name != NULL )
13061310{
1311+ TargetEntry * target_result = NULL ;
1312+
13071313foreach (tl ,* tlist )
13081314{
13091315TargetEntry * tle = (TargetEntry * )lfirst (tl );
@@ -1367,12 +1373,36 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
13671373}
13681374
13691375/*
1370- * Otherwise, we have an expression (this is a Postgres extension not
1371- * found in SQL92). Convert the untransformed node to a transformed
1372- * expression, and search for a match in the tlist. NOTE: it doesn't
1373- * really matter whether there is more than one match.Also, we are
1374- * willing to match a resjunk target here, though the above cases must
1375- * ignore resjunk targets.
1376+ * Otherwise, we have an expression, so process it per SQL99 rules.
1377+ */
1378+ return findTargetlistEntrySQL99 (pstate ,node ,tlist );
1379+ }
1380+
1381+ /*
1382+ *findTargetlistEntrySQL99 -
1383+ * Returns the targetlist entry matching the given (untransformed) node.
1384+ * If no matching entry exists, one is created and appended to the target
1385+ * list as a "resjunk" node.
1386+ *
1387+ * This function supports the SQL99 interpretation, wherein the expression
1388+ * is just an ordinary expression referencing input column names.
1389+ *
1390+ * nodethe ORDER BY, GROUP BY, etc expression to be matched
1391+ * tlistthe target list (passed by reference so we can append to it)
1392+ */
1393+ static TargetEntry *
1394+ findTargetlistEntrySQL99 (ParseState * pstate ,Node * node ,List * * tlist )
1395+ {
1396+ TargetEntry * target_result ;
1397+ ListCell * tl ;
1398+ Node * expr ;
1399+
1400+ /*
1401+ * Convert the untransformed node to a transformed expression, and search
1402+ * for a match in the tlist. NOTE: it doesn't really matter whether there
1403+ * is more than one match. Also, we are willing to match an existing
1404+ * resjunk target here, though the SQL92 cases above must ignore resjunk
1405+ * targets.
13761406 */
13771407expr = transformExpr (pstate ,node );
13781408
@@ -1403,16 +1433,15 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
14031433 * GROUP BY items will be added to the targetlist (as resjunk columns)
14041434 * if not already present, so the targetlist must be passed by reference.
14051435 *
1406- * This is also used for window PARTITION BY clauses (whichactually act
1407- *just the same,except for the clause name used in error messages ).
1436+ * This is also used for window PARTITION BY clauses (which act almost the
1437+ * same,but are always interpreted per SQL99 rules ).
14081438 */
14091439List *
14101440transformGroupClause (ParseState * pstate ,List * grouplist ,
14111441List * * targetlist ,List * sortClause ,
1412- bool isPartition )
1442+ bool isWindowFunc )
14131443{
14141444List * result = NIL ;
1415- int clause = isPartition ?PARTITION_CLAUSE :GROUP_CLAUSE ;
14161445ListCell * gl ;
14171446
14181447foreach (gl ,grouplist )
@@ -1421,7 +1450,11 @@ transformGroupClause(ParseState *pstate, List *grouplist,
14211450TargetEntry * tle ;
14221451bool found = false;
14231452
1424- tle = findTargetlistEntry (pstate ,gexpr ,targetlist ,clause );
1453+ if (isWindowFunc )
1454+ tle = findTargetlistEntrySQL99 (pstate ,gexpr ,targetlist );
1455+ else
1456+ tle = findTargetlistEntrySQL92 (pstate ,gexpr ,targetlist ,
1457+ GROUP_CLAUSE );
14251458
14261459/* Eliminate duplicates (GROUP BY x, x) */
14271460if (targetIsInSortList (tle ,InvalidOid ,result ))
@@ -1475,12 +1508,16 @@ transformGroupClause(ParseState *pstate, List *grouplist,
14751508 *
14761509 * ORDER BY items will be added to the targetlist (as resjunk columns)
14771510 * if not already present, so the targetlist must be passed by reference.
1511+ *
1512+ * This is also used for window ORDER BY clauses (which act almost the
1513+ * same, but are always interpreted per SQL99 rules).
14781514 */
14791515List *
14801516transformSortClause (ParseState * pstate ,
14811517List * orderlist ,
14821518List * * targetlist ,
1483- bool resolveUnknown )
1519+ bool resolveUnknown ,
1520+ bool isWindowFunc )
14841521{
14851522List * sortlist = NIL ;
14861523ListCell * olitem ;
@@ -1490,8 +1527,11 @@ transformSortClause(ParseState *pstate,
14901527SortBy * sortby = (SortBy * )lfirst (olitem );
14911528TargetEntry * tle ;
14921529
1493- tle = findTargetlistEntry (pstate ,sortby -> node ,
1494- targetlist ,ORDER_CLAUSE );
1530+ if (isWindowFunc )
1531+ tle = findTargetlistEntrySQL99 (pstate ,sortby -> node ,targetlist );
1532+ else
1533+ tle = findTargetlistEntrySQL92 (pstate ,sortby -> node ,targetlist ,
1534+ ORDER_CLAUSE );
14951535
14961536sortlist = addTargetToSortList (pstate ,tle ,
14971537sortlist ,* targetlist ,sortby ,
@@ -1550,18 +1590,19 @@ transformWindowDefinitions(ParseState *pstate,
15501590
15511591/*
15521592 * Transform PARTITION and ORDER specs, if any. These are treated
1553- * exactly like top-level GROUP BY and ORDER BY clauses, including the
1554- * special handling of nondefault operator semantics.
1593+ *almost exactly like top-level GROUP BY and ORDER BY clauses,
1594+ *including the special handling of nondefault operator semantics.
15551595 */
15561596orderClause = transformSortClause (pstate ,
15571597windef -> orderClause ,
15581598targetlist ,
1559- true);
1599+ true/* fix unknowns */ ,
1600+ true/* window function */ );
15601601partitionClause = transformGroupClause (pstate ,
15611602windef -> partitionClause ,
15621603targetlist ,
15631604orderClause ,
1564- true);
1605+ true/* window function */ );
15651606
15661607/*
15671608 * And prepare the new WindowClause.
@@ -1736,8 +1777,8 @@ transformDistinctOnClause(ParseState *pstate, List *distinctlist,
17361777int sortgroupref ;
17371778TargetEntry * tle ;
17381779
1739- tle = findTargetlistEntry (pstate ,dexpr ,
1740- targetlist , DISTINCT_ON_CLAUSE );
1780+ tle = findTargetlistEntrySQL92 (pstate ,dexpr , targetlist ,
1781+ DISTINCT_ON_CLAUSE );
17411782sortgroupref = assignSortGroupRef (tle ,* targetlist );
17421783sortgrouprefs = lappend_int (sortgrouprefs ,sortgroupref );
17431784}