* transformDistinctClause - * transform a DISTINCT 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, * shou
| 3121 | * of error messages. |
| 3122 | */ |
| 3123 | List * |
| 3124 | transformDistinctClause(ParseState *pstate, |
| 3125 | List **targetlist, List *sortClause, bool is_agg) |
| 3126 | { |
| 3127 | List *result = NIL; |
| 3128 | ListCell *slitem; |
| 3129 | ListCell *tlitem; |
| 3130 | |
| 3131 | /* |
| 3132 | * The distinctClause should consist of all ORDER BY items followed by all |
| 3133 | * other non-resjunk targetlist items. There must not be any resjunk |
| 3134 | * ORDER BY items --- that would imply that we are sorting by a value that |
| 3135 | * isn't necessarily unique within a DISTINCT group, so the results |
| 3136 | * wouldn't be well-defined. This construction ensures we follow the rule |
| 3137 | * that sortClause and distinctClause match; in fact the sortClause will |
| 3138 | * always be a prefix of distinctClause. |
| 3139 | * |
| 3140 | * Note a corner case: the same TLE could be in the ORDER BY list multiple |
| 3141 | * times with different sortops. We have to include it in the |
| 3142 | * distinctClause the same way to preserve the prefix property. The net |
| 3143 | * effect will be that the TLE value will be made unique according to both |
| 3144 | * sortops. |
| 3145 | */ |
| 3146 | foreach(slitem, sortClause) |
| 3147 | { |
| 3148 | SortGroupClause *scl = (SortGroupClause *) lfirst(slitem); |
| 3149 | TargetEntry *tle = get_sortgroupclause_tle(scl, *targetlist); |
| 3150 | |
| 3151 | if (tle->resjunk) |
| 3152 | ereport(ERROR, |
| 3153 | (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), |
| 3154 | is_agg ? |
| 3155 | errmsg("in an aggregate with DISTINCT, ORDER BY expressions must appear in argument list") : |
| 3156 | errmsg("for SELECT DISTINCT, ORDER BY expressions must appear in select list"), |
| 3157 | parser_errposition(pstate, |
| 3158 | exprLocation((Node *) tle->expr)))); |
| 3159 | result = lappend(result, copyObject(scl)); |
| 3160 | } |
| 3161 | |
| 3162 | /* |
| 3163 | * Now add any remaining non-resjunk tlist items, using default sort/group |
| 3164 | * semantics for their data types. |
| 3165 | */ |
| 3166 | foreach(tlitem, *targetlist) |
| 3167 | { |
| 3168 | TargetEntry *tle = (TargetEntry *) lfirst(tlitem); |
| 3169 | |
| 3170 | if (tle->resjunk) |
| 3171 | continue; /* ignore junk */ |
| 3172 | result = addTargetToGroupList(pstate, tle, |
| 3173 | result, *targetlist, |
| 3174 | exprLocation((Node *) tle->expr)); |
| 3175 | } |
| 3176 | |
| 3177 | /* |
| 3178 | * Complain if we found nothing to make DISTINCT. Returning an empty list |
| 3179 | * would cause the parsed Query to look like it didn't have DISTINCT, with |
| 3180 | * results that would probably surprise the user. Note: this case is |
no test coverage detected