1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-14 18:42:34 +03:00

Allow GROUP BY, ORDER BY, DISTINCT targets to be unknown literals,

silently resolving them to type TEXT.  This is comparable to what we
do when faced with UNKNOWN in CASE, UNION, and other contexts.  It gets
rid of this and related annoyances:
	select distinct f1, '' from int4_tbl;
	ERROR:  Unable to identify an ordering operator '<' for type unknown
This was discussed many moons ago, but no one got round to fixing it.
This commit is contained in:
Tom Lane
2003-06-16 02:03:38 +00:00
parent cb02610e50
commit a499725469
6 changed files with 105 additions and 39 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.115 2003/06/15 16:42:07 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.116 2003/06/16 02:03:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -59,8 +59,9 @@ static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype,
Var *l_colvar, Var *r_colvar);
static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
List *tlist, int clause);
static List *addTargetToSortList(TargetEntry *tle, List *sortlist,
List *targetlist, List *opname);
static List *addTargetToSortList(ParseState *pstate, TargetEntry *tle,
List *sortlist, List *targetlist,
List *opname, bool resolveUnknown);
/*
@ -1133,6 +1134,7 @@ transformGroupClause(ParseState *pstate, List *grouplist,
foreach(gl, grouplist)
{
TargetEntry *tle;
Oid restype;
Oid ordering_op;
GroupClause *grpcl;
@ -1143,6 +1145,19 @@ transformGroupClause(ParseState *pstate, List *grouplist,
if (targetIsInSortList(tle, glist))
continue;
/* if tlist item is an UNKNOWN literal, change it to TEXT */
restype = tle->resdom->restype;
if (restype == UNKNOWNOID)
{
tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
restype, TEXTOID,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST);
restype = tle->resdom->restype = TEXTOID;
tle->resdom->restypmod = -1;
}
/*
* If the GROUP BY clause matches the ORDER BY clause, we want to
* adopt the ordering operators from the latter rather than using
@ -1160,7 +1175,7 @@ transformGroupClause(ParseState *pstate, List *grouplist,
}
else
{
ordering_op = ordering_oper_opid(tle->resdom->restype);
ordering_op = ordering_oper_opid(restype);
sortClause = NIL; /* disregard ORDER BY once match fails */
}
@ -1180,7 +1195,8 @@ transformGroupClause(ParseState *pstate, List *grouplist,
List *
transformSortClause(ParseState *pstate,
List *orderlist,
List *targetlist)
List *targetlist,
bool resolveUnknown)
{
List *sortlist = NIL;
List *olitem;
@ -1193,8 +1209,9 @@ transformSortClause(ParseState *pstate,
tle = findTargetlistEntry(pstate, sortby->node,
targetlist, ORDER_CLAUSE);
sortlist = addTargetToSortList(tle, sortlist, targetlist,
sortby->useOp);
sortlist = addTargetToSortList(pstate, tle,
sortlist, targetlist,
sortby->useOp, resolveUnknown);
}
return sortlist;
@ -1232,7 +1249,10 @@ transformDistinctClause(ParseState *pstate, List *distinctlist,
* the user's ORDER BY spec alone, and just add additional sort
* keys to it to ensure that all targetlist items get sorted.)
*/
*sortClause = addAllTargetsToSortList(*sortClause, targetlist);
*sortClause = addAllTargetsToSortList(pstate,
*sortClause,
targetlist,
true);
/*
* Now, DISTINCT list consists of all non-resjunk sortlist items.
@ -1291,8 +1311,9 @@ transformDistinctClause(ParseState *pstate, List *distinctlist,
}
else
{
*sortClause = addTargetToSortList(tle, *sortClause,
targetlist, NIL);
*sortClause = addTargetToSortList(pstate, tle,
*sortClause, targetlist,
NIL, true);
/*
* Probably, the tle should always have been added at the
@ -1323,10 +1344,13 @@ transformDistinctClause(ParseState *pstate, List *distinctlist,
* ORDER BY list, adding the not-yet-sorted ones to the end of the list.
* This is typically used to help implement SELECT DISTINCT.
*
* See addTargetToSortList for info about pstate and resolveUnknown inputs.
*
* Returns the updated ORDER BY list.
*/
List *
addAllTargetsToSortList(List *sortlist, List *targetlist)
addAllTargetsToSortList(ParseState *pstate, List *sortlist,
List *targetlist, bool resolveUnknown)
{
List *i;
@ -1335,7 +1359,9 @@ addAllTargetsToSortList(List *sortlist, List *targetlist)
TargetEntry *tle = (TargetEntry *) lfirst(i);
if (!tle->resdom->resjunk)
sortlist = addTargetToSortList(tle, sortlist, targetlist, NIL);
sortlist = addTargetToSortList(pstate, tle,
sortlist, targetlist,
NIL, resolveUnknown);
}
return sortlist;
}
@ -1346,26 +1372,44 @@ addAllTargetsToSortList(List *sortlist, List *targetlist)
* add it to the end of the list, using the sortop with given name
* or the default sort operator if opname == NIL.
*
* If resolveUnknown is TRUE, convert TLEs of type UNKNOWN to TEXT. If not,
* do nothing (which implies the search for a sort operator will fail).
* pstate should be provided if resolveUnknown is TRUE, but can be NULL
* otherwise.
*
* Returns the updated ORDER BY list.
*/
static List *
addTargetToSortList(TargetEntry *tle, List *sortlist, List *targetlist,
List *opname)
addTargetToSortList(ParseState *pstate, TargetEntry *tle,
List *sortlist, List *targetlist,
List *opname, bool resolveUnknown)
{
/* avoid making duplicate sortlist entries */
if (!targetIsInSortList(tle, sortlist))
{
SortClause *sortcl = makeNode(SortClause);
Oid restype = tle->resdom->restype;
/* if tlist item is an UNKNOWN literal, change it to TEXT */
if (restype == UNKNOWNOID && resolveUnknown)
{
tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
restype, TEXTOID,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST);
restype = tle->resdom->restype = TEXTOID;
tle->resdom->restypmod = -1;
}
sortcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
if (opname)
sortcl->sortop = compatible_oper_opid(opname,
tle->resdom->restype,
tle->resdom->restype,
restype,
restype,
false);
else
sortcl->sortop = ordering_oper_opid(tle->resdom->restype);
sortcl->sortop = ordering_oper_opid(restype);
sortlist = lappend(sortlist, sortcl);
}