|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.146 2006/03/0515:58:33 momjian Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.147 2006/03/0521:34:34 neilc Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
@@ -1296,78 +1296,122 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
|
1296 | 1296 | returntarget_result;
|
1297 | 1297 | }
|
1298 | 1298 |
|
| 1299 | +staticGroupClause* |
| 1300 | +make_group_clause(TargetEntry*tle,List*targetlist,Oidsortop) |
| 1301 | +{ |
| 1302 | +GroupClause*result; |
| 1303 | + |
| 1304 | +result=makeNode(GroupClause); |
| 1305 | +result->tleSortGroupRef=assignSortGroupRef(tle,targetlist); |
| 1306 | +result->sortop=sortop; |
| 1307 | +returnresult; |
| 1308 | +} |
1299 | 1309 |
|
1300 | 1310 | /*
|
1301 | 1311 | * transformGroupClause -
|
1302 | 1312 | * transform a GROUP BY clause
|
1303 | 1313 | *
|
1304 | 1314 | * GROUP BY items will be added to the targetlist (as resjunk columns)
|
1305 | 1315 | * if not already present, so the targetlist must be passed by reference.
|
| 1316 | + * |
| 1317 | + * The order of the elements of the grouping clause does not affect |
| 1318 | + * the semantics of the query. However, the optimizer is not currently |
| 1319 | + * smart enough to reorder the grouping clause, so we try to do some |
| 1320 | + * primitive reordering here. |
1306 | 1321 | */
|
1307 | 1322 | List*
|
1308 | 1323 | transformGroupClause(ParseState*pstate,List*grouplist,
|
1309 | 1324 | List**targetlist,List*sortClause)
|
1310 | 1325 | {
|
1311 |
| -List*glist=NIL; |
1312 |
| -ListCell*gl; |
1313 |
| -ListCell*sortItem; |
1314 |
| - |
1315 |
| -sortItem=list_head(sortClause); |
| 1326 | +List*result=NIL; |
| 1327 | +List*tle_list=NIL; |
| 1328 | +ListCell*l; |
1316 | 1329 |
|
1317 |
| -foreach(gl,grouplist) |
| 1330 | +/* Preprocess the grouping clause, lookup TLEs */ |
| 1331 | +foreach (l,grouplist) |
1318 | 1332 | {
|
1319 | 1333 | TargetEntry*tle;
|
1320 |
| -Oidrestype; |
1321 |
| -Oidordering_op; |
1322 |
| -GroupClause*grpcl; |
| 1334 | +Oidrestype; |
1323 | 1335 |
|
1324 |
| -tle=findTargetlistEntry(pstate,lfirst(gl), |
| 1336 | +tle=findTargetlistEntry(pstate,lfirst(l), |
1325 | 1337 | targetlist,GROUP_CLAUSE);
|
1326 | 1338 |
|
1327 |
| -/* avoid making duplicate grouplist entries */ |
1328 |
| -if (targetIsInSortList(tle,glist)) |
1329 |
| -continue; |
1330 |
| - |
1331 | 1339 | /* if tlist item is an UNKNOWN literal, change it to TEXT */
|
1332 | 1340 | restype=exprType((Node*)tle->expr);
|
1333 | 1341 |
|
1334 | 1342 | if (restype==UNKNOWNOID)
|
1335 |
| -{ |
1336 | 1343 | tle->expr= (Expr*)coerce_type(pstate, (Node*)tle->expr,
|
1337 | 1344 | restype,TEXTOID,-1,
|
1338 | 1345 | COERCION_IMPLICIT,
|
1339 | 1346 | COERCE_IMPLICIT_CAST);
|
1340 |
| -restype=TEXTOID; |
1341 |
| -} |
1342 | 1347 |
|
1343 |
| -/* |
1344 |
| - * If the GROUP BY clause matches the ORDER BY clause, we want to |
1345 |
| - * adopt the ordering operators from the latter rather than using the |
1346 |
| - * default ops. This allows "GROUP BY foo ORDER BY foo DESC" to be |
1347 |
| - * done with only one sort step. Note we are assuming that any |
1348 |
| - * user-supplied ordering operator will bring equal values together, |
1349 |
| - * which is all that GROUP BY needs. |
1350 |
| - */ |
1351 |
| -if (sortItem&& |
1352 |
| -((SortClause*)lfirst(sortItem))->tleSortGroupRef== |
1353 |
| -tle->ressortgroupref) |
1354 |
| -{ |
1355 |
| -ordering_op= ((SortClause*)lfirst(sortItem))->sortop; |
1356 |
| -sortItem=lnext(sortItem); |
1357 |
| -} |
1358 |
| -else |
| 1348 | +tle_list=lappend(tle_list,tle); |
| 1349 | +} |
| 1350 | + |
| 1351 | +/* |
| 1352 | + * Now iterate through the ORDER BY clause. If we find a grouping |
| 1353 | + * element that matches the ORDER BY element, append the grouping |
| 1354 | + * element to the result set immediately. Otherwise, stop |
| 1355 | + * iterating. The effect of this is to look for a prefix of the |
| 1356 | + * ORDER BY list in the grouping clauses, and to move that prefix |
| 1357 | + * to the front of the GROUP BY. |
| 1358 | + */ |
| 1359 | +foreach (l,sortClause) |
| 1360 | +{ |
| 1361 | +SortClause*sc= (SortClause*)lfirst(l); |
| 1362 | +ListCell*prev=NULL; |
| 1363 | +ListCell*tl; |
| 1364 | +boolfound= false; |
| 1365 | + |
| 1366 | +foreach (tl,tle_list) |
1359 | 1367 | {
|
1360 |
| -ordering_op=ordering_oper_opid(restype); |
1361 |
| -sortItem=NULL;/* disregard ORDER BY once match fails */ |
| 1368 | +TargetEntry*tle= (TargetEntry*)lfirst(tl); |
| 1369 | + |
| 1370 | +if (sc->tleSortGroupRef==tle->ressortgroupref) |
| 1371 | +{ |
| 1372 | +GroupClause*gc; |
| 1373 | + |
| 1374 | +tle_list=list_delete_cell(tle_list,tl,prev); |
| 1375 | + |
| 1376 | +/* Use the sort clause's sorting operator */ |
| 1377 | +gc=make_group_clause(tle,*targetlist,sc->sortop); |
| 1378 | +result=lappend(result,gc); |
| 1379 | +found= true; |
| 1380 | +break; |
| 1381 | +} |
| 1382 | + |
| 1383 | +prev=tl; |
1362 | 1384 | }
|
1363 | 1385 |
|
1364 |
| -grpcl=makeNode(GroupClause); |
1365 |
| -grpcl->tleSortGroupRef=assignSortGroupRef(tle,*targetlist); |
1366 |
| -grpcl->sortop=ordering_op; |
1367 |
| -glist=lappend(glist,grpcl); |
| 1386 | +/* As soon as we've failed to match an ORDER BY element, stop */ |
| 1387 | +if (!found) |
| 1388 | +break; |
1368 | 1389 | }
|
1369 | 1390 |
|
1370 |
| -returnglist; |
| 1391 | +/* |
| 1392 | + * Now add any remaining elements of the GROUP BY list in the |
| 1393 | + * order we received them. |
| 1394 | + * |
| 1395 | + * XXX: are there any additional criteria to consider when |
| 1396 | + * ordering grouping clauses? |
| 1397 | + */ |
| 1398 | +foreach(l,tle_list) |
| 1399 | +{ |
| 1400 | +TargetEntry*tle= (TargetEntry*)lfirst(l); |
| 1401 | +GroupClause*gc; |
| 1402 | +Oidsort_op; |
| 1403 | + |
| 1404 | +/* avoid making duplicate grouplist entries */ |
| 1405 | +if (targetIsInSortList(tle,result)) |
| 1406 | +continue; |
| 1407 | + |
| 1408 | +sort_op=ordering_oper_opid(exprType((Node*)tle->expr)); |
| 1409 | +gc=make_group_clause(tle,*targetlist,sort_op); |
| 1410 | +result=lappend(result,gc); |
| 1411 | +} |
| 1412 | + |
| 1413 | +list_free(tle_list); |
| 1414 | +returnresult; |
1371 | 1415 | }
|
1372 | 1416 |
|
1373 | 1417 | /*
|
|