* transformDistinctOnClause - * transform a DISTINCT ON clause * * Since we may need to add items to the query's targetlist, that list * is passed by reference. * * As with GROUP BY, we absorb the sorting semantics of ORDER BY as much as * possible into the distinctClause. This avoids a possible need to re-sort, * and allows the user to choose the equality semantics used by DISTINCT, *
| 3205 | * operator. |
| 3206 | */ |
| 3207 | List * |
| 3208 | transformDistinctOnClause(ParseState *pstate, List *distinctlist, |
| 3209 | List **targetlist, List *sortClause) |
| 3210 | { |
| 3211 | List *result = NIL; |
| 3212 | List *sortgrouprefs = NIL; |
| 3213 | bool skipped_sortitem; |
| 3214 | ListCell *lc; |
| 3215 | ListCell *lc2; |
| 3216 | |
| 3217 | /* |
| 3218 | * Add all the DISTINCT ON expressions to the tlist (if not already |
| 3219 | * present, they are added as resjunk items). Assign sortgroupref numbers |
| 3220 | * to them, and make a list of these numbers. (NB: we rely below on the |
| 3221 | * sortgrouprefs list being one-for-one with the original distinctlist. |
| 3222 | * Also notice that we could have duplicate DISTINCT ON expressions and |
| 3223 | * hence duplicate entries in sortgrouprefs.) |
| 3224 | */ |
| 3225 | foreach(lc, distinctlist) |
| 3226 | { |
| 3227 | Node *dexpr = (Node *) lfirst(lc); |
| 3228 | int sortgroupref; |
| 3229 | TargetEntry *tle; |
| 3230 | |
| 3231 | tle = findTargetlistEntrySQL92(pstate, dexpr, targetlist, |
| 3232 | EXPR_KIND_DISTINCT_ON); |
| 3233 | sortgroupref = assignSortGroupRef(tle, *targetlist); |
| 3234 | sortgrouprefs = lappend_int(sortgrouprefs, sortgroupref); |
| 3235 | } |
| 3236 | |
| 3237 | /* |
| 3238 | * If the user writes both DISTINCT ON and ORDER BY, adopt the sorting |
| 3239 | * semantics from ORDER BY items that match DISTINCT ON items, and also |
| 3240 | * adopt their column sort order. We insist that the distinctClause and |
| 3241 | * sortClause match, so throw error if we find the need to add any more |
| 3242 | * distinctClause items after we've skipped an ORDER BY item that wasn't |
| 3243 | * in DISTINCT ON. |
| 3244 | */ |
| 3245 | skipped_sortitem = false; |
| 3246 | foreach(lc, sortClause) |
| 3247 | { |
| 3248 | SortGroupClause *scl = (SortGroupClause *) lfirst(lc); |
| 3249 | |
| 3250 | if (list_member_int(sortgrouprefs, scl->tleSortGroupRef)) |
| 3251 | { |
| 3252 | if (skipped_sortitem) |
| 3253 | ereport(ERROR, |
| 3254 | (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), |
| 3255 | errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions"), |
| 3256 | parser_errposition(pstate, |
| 3257 | get_matching_location(scl->tleSortGroupRef, |
| 3258 | sortgrouprefs, |
| 3259 | distinctlist)))); |
| 3260 | else |
| 3261 | result = lappend(result, copyObject(scl)); |
| 3262 | } |
| 3263 | else |
| 3264 | skipped_sortitem = true; |
no test coverage detected