|
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 | /* |
|