Clean up a few failures to set collation fields in expression nodes.

I'm not sure these have any non-cosmetic implications, but I'm not sure
they don't, either.  In particular, ensure the CaseTestExpr generated
by transformAssignmentIndirection to represent the base target column
carries the correct collation, because parse_collate.c won't fix that.
Tweak lsyscache.c API so that we can get the appropriate collation
without an extra syscache lookup.
This commit is contained in:
Tom Lane 2011-03-26 14:25:48 -04:00
parent 92f4786fa9
commit b23c9fa929
9 changed files with 49 additions and 44 deletions

View File

@ -603,8 +603,7 @@ find_indexkey_var(PlannerInfo *root, RelOptInfo *rel, AttrNumber varattno)
relid = rel->relid; relid = rel->relid;
reloid = getrelid(relid, root->parse->rtable); reloid = getrelid(relid, root->parse->rtable);
get_atttypetypmod(reloid, varattno, &vartypeid, &type_mod); get_atttypetypmodcoll(reloid, varattno, &vartypeid, &type_mod, &varcollid);
varcollid = get_attcollation(reloid, varattno);
return makeVar(relid, varattno, vartypeid, type_mod, varcollid, 0); return makeVar(relid, varattno, vartypeid, type_mod, varcollid, 0);
} }

View File

@ -2652,6 +2652,8 @@ get_switched_clauses(List *clauses, Relids outerrelids)
temp->opfuncid = InvalidOid; temp->opfuncid = InvalidOid;
temp->opresulttype = clause->opresulttype; temp->opresulttype = clause->opresulttype;
temp->opretset = clause->opretset; temp->opretset = clause->opretset;
temp->opcollid = clause->opcollid;
temp->inputcollid = clause->inputcollid;
temp->args = list_copy(clause->args); temp->args = list_copy(clause->args);
temp->location = clause->location; temp->location = clause->location;
/* Commute it --- note this modifies the temp node in-place. */ /* Commute it --- note this modifies the temp node in-place. */

View File

@ -1816,7 +1816,7 @@ CommuteOpExpr(OpExpr *clause)
*/ */
clause->opno = opoid; clause->opno = opoid;
clause->opfuncid = InvalidOid; clause->opfuncid = InvalidOid;
/* opresulttype and opretset are assumed not to change */ /* opresulttype, opretset, opcollid, inputcollid need not change */
temp = linitial(clause->args); temp = linitial(clause->args);
linitial(clause->args) = lsecond(clause->args); linitial(clause->args) = lsecond(clause->args);

View File

@ -906,6 +906,8 @@ arrayconst_startup_fn(Node *clause, PredIterInfo info)
state->opexpr.opfuncid = saop->opfuncid; state->opexpr.opfuncid = saop->opfuncid;
state->opexpr.opresulttype = BOOLOID; state->opexpr.opresulttype = BOOLOID;
state->opexpr.opretset = false; state->opexpr.opretset = false;
state->opexpr.opcollid = InvalidOid;
state->opexpr.inputcollid = saop->inputcollid;
state->opexpr.args = list_copy(saop->args); state->opexpr.args = list_copy(saop->args);
/* Set up a dummy Const node to hold the per-element values */ /* Set up a dummy Const node to hold the per-element values */
@ -972,6 +974,8 @@ arrayexpr_startup_fn(Node *clause, PredIterInfo info)
state->opexpr.opfuncid = saop->opfuncid; state->opexpr.opfuncid = saop->opfuncid;
state->opexpr.opresulttype = BOOLOID; state->opexpr.opresulttype = BOOLOID;
state->opexpr.opretset = false; state->opexpr.opretset = false;
state->opexpr.opcollid = InvalidOid;
state->opexpr.inputcollid = saop->inputcollid;
state->opexpr.args = list_copy(saop->args); state->opexpr.args = list_copy(saop->args);
/* Initialize iteration variable to first member of ArrayExpr */ /* Initialize iteration variable to first member of ArrayExpr */

View File

@ -796,6 +796,7 @@ build_coercion_expression(Node *node,
* one argument. * one argument.
*/ */
acoerce->resulttypmod = (nargs >= 2) ? targetTypMod : -1; acoerce->resulttypmod = (nargs >= 2) ? targetTypMod : -1;
/* resultcollid will be set by parse_collate.c */
acoerce->isExplicit = isExplicit; acoerce->isExplicit = isExplicit;
acoerce->coerceformat = cformat; acoerce->coerceformat = cformat;
acoerce->location = location; acoerce->location = location;
@ -811,6 +812,7 @@ build_coercion_expression(Node *node,
iocoerce->arg = (Expr *) node; iocoerce->arg = (Expr *) node;
iocoerce->resulttype = targetTypeId; iocoerce->resulttype = targetTypeId;
/* resultcollid will be set by parse_collate.c */
iocoerce->coerceformat = cformat; iocoerce->coerceformat = cformat;
iocoerce->location = location; iocoerce->location = location;

View File

@ -40,6 +40,7 @@ static Node *transformAssignmentIndirection(ParseState *pstate,
bool targetIsArray, bool targetIsArray,
Oid targetTypeId, Oid targetTypeId,
int32 targetTypMod, int32 targetTypMod,
Oid targetCollation,
ListCell *indirection, ListCell *indirection,
Node *rhs, Node *rhs,
int location); int location);
@ -48,6 +49,7 @@ static Node *transformAssignmentSubscripts(ParseState *pstate,
const char *targetName, const char *targetName,
Oid targetTypeId, Oid targetTypeId,
int32 targetTypMod, int32 targetTypMod,
Oid targetCollation,
List *subscripts, List *subscripts,
bool isSlice, bool isSlice,
ListCell *next_indirection, ListCell *next_indirection,
@ -455,6 +457,7 @@ transformAssignedExpr(ParseState *pstate,
false, false,
attrtype, attrtype,
attrtypmod, attrtypmod,
attrcollation,
list_head(indirection), list_head(indirection),
(Node *) expr, (Node *) expr,
location); location);
@ -548,8 +551,9 @@ updateTargetListEntry(ParseState *pstate,
* targetIsArray is true if we're subscripting it. These are just for * targetIsArray is true if we're subscripting it. These are just for
* error reporting. * error reporting.
* *
* targetTypeId and targetTypMod indicate the datatype of the object to * targetTypeId, targetTypMod, targetCollation indicate the datatype and
* be assigned to (initially the target column, later some subobject). * collation of the object to be assigned to (initially the target column,
* later some subobject).
* *
* indirection is the sublist remaining to process. When it's NULL, we're * indirection is the sublist remaining to process. When it's NULL, we're
* done recursing and can just coerce and return the RHS. * done recursing and can just coerce and return the RHS.
@ -569,6 +573,7 @@ transformAssignmentIndirection(ParseState *pstate,
bool targetIsArray, bool targetIsArray,
Oid targetTypeId, Oid targetTypeId,
int32 targetTypMod, int32 targetTypMod,
Oid targetCollation,
ListCell *indirection, ListCell *indirection,
Node *rhs, Node *rhs,
int location) int location)
@ -585,6 +590,7 @@ transformAssignmentIndirection(ParseState *pstate,
ctest->typeId = targetTypeId; ctest->typeId = targetTypeId;
ctest->typeMod = targetTypMod; ctest->typeMod = targetTypMod;
ctest->collation = targetCollation;
basenode = (Node *) ctest; basenode = (Node *) ctest;
} }
@ -617,6 +623,7 @@ transformAssignmentIndirection(ParseState *pstate,
AttrNumber attnum; AttrNumber attnum;
Oid fieldTypeId; Oid fieldTypeId;
int32 fieldTypMod; int32 fieldTypMod;
Oid fieldCollation;
Assert(IsA(n, String)); Assert(IsA(n, String));
@ -629,6 +636,7 @@ transformAssignmentIndirection(ParseState *pstate,
targetName, targetName,
targetTypeId, targetTypeId,
targetTypMod, targetTypMod,
targetCollation,
subscripts, subscripts,
isSlice, isSlice,
i, i,
@ -662,8 +670,8 @@ transformAssignmentIndirection(ParseState *pstate,
strVal(n)), strVal(n)),
parser_errposition(pstate, location))); parser_errposition(pstate, location)));
get_atttypetypmod(typrelid, attnum, get_atttypetypmodcoll(typrelid, attnum,
&fieldTypeId, &fieldTypMod); &fieldTypeId, &fieldTypMod, &fieldCollation);
/* recurse to create appropriate RHS for field assign */ /* recurse to create appropriate RHS for field assign */
rhs = transformAssignmentIndirection(pstate, rhs = transformAssignmentIndirection(pstate,
@ -672,6 +680,7 @@ transformAssignmentIndirection(ParseState *pstate,
false, false,
fieldTypeId, fieldTypeId,
fieldTypMod, fieldTypMod,
fieldCollation,
lnext(i), lnext(i),
rhs, rhs,
location); location);
@ -696,6 +705,7 @@ transformAssignmentIndirection(ParseState *pstate,
targetName, targetName,
targetTypeId, targetTypeId,
targetTypMod, targetTypMod,
targetCollation,
subscripts, subscripts,
isSlice, isSlice,
NULL, NULL,
@ -747,6 +757,7 @@ transformAssignmentSubscripts(ParseState *pstate,
const char *targetName, const char *targetName,
Oid targetTypeId, Oid targetTypeId,
int32 targetTypMod, int32 targetTypMod,
Oid targetCollation,
List *subscripts, List *subscripts,
bool isSlice, bool isSlice,
ListCell *next_indirection, ListCell *next_indirection,
@ -758,6 +769,7 @@ transformAssignmentSubscripts(ParseState *pstate,
int32 arrayTypMod; int32 arrayTypMod;
Oid elementTypeId; Oid elementTypeId;
Oid typeNeeded; Oid typeNeeded;
Oid collationNeeded;
Assert(subscripts != NIL); Assert(subscripts != NIL);
@ -769,6 +781,16 @@ transformAssignmentSubscripts(ParseState *pstate,
/* Identify type that RHS must provide */ /* Identify type that RHS must provide */
typeNeeded = isSlice ? arrayType : elementTypeId; typeNeeded = isSlice ? arrayType : elementTypeId;
/*
* Array normally has same collation as elements, but there's an
* exception: we might be subscripting a domain over an array type.
* In that case use collation of the base type.
*/
if (arrayType == targetTypeId)
collationNeeded = targetCollation;
else
collationNeeded = get_typcollation(arrayType);
/* recurse to create appropriate RHS for array assign */ /* recurse to create appropriate RHS for array assign */
rhs = transformAssignmentIndirection(pstate, rhs = transformAssignmentIndirection(pstate,
NULL, NULL,
@ -776,6 +798,7 @@ transformAssignmentSubscripts(ParseState *pstate,
true, true,
typeNeeded, typeNeeded,
arrayTypMod, arrayTypMod,
collationNeeded,
next_indirection, next_indirection,
rhs, rhs,
location); location);

View File

@ -912,12 +912,14 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
{ {
/* Simple index column */ /* Simple index column */
char *attname; char *attname;
int32 keycoltypmod;
attname = get_relid_attribute_name(indrelid, attnum); attname = get_relid_attribute_name(indrelid, attnum);
if (!colno || colno == keyno + 1) if (!colno || colno == keyno + 1)
appendStringInfoString(&buf, quote_identifier(attname)); appendStringInfoString(&buf, quote_identifier(attname));
keycoltype = get_atttype(indrelid, attnum); get_atttypetypmodcoll(indrelid, attnum,
keycolcollation = get_attcollation(indrelid, attnum); &keycoltype, &keycoltypmod,
&keycolcollation);
} }
else else
{ {

View File

@ -904,44 +904,17 @@ get_atttypmod(Oid relid, AttrNumber attnum)
} }
/* /*
* get_attcollation * get_atttypetypmodcoll
* *
* Given the relation id and the attribute number, * A three-fer: given the relation id and the attribute number,
* return the "attcollation" field from the attribute relation. * fetch atttypid, atttypmod, and attcollation in a single cache lookup.
*/
Oid
get_attcollation(Oid relid, AttrNumber attnum)
{
HeapTuple tp;
tp = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum));
if (HeapTupleIsValid(tp))
{
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
Oid result;
result = att_tup->attcollation;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/*
* get_atttypetypmod
*
* A two-fer: given the relation id and the attribute number,
* fetch both type OID and atttypmod in a single cache lookup.
* *
* Unlike the otherwise-similar get_atttype/get_atttypmod, this routine * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
* raises an error if it can't obtain the information. * raises an error if it can't obtain the information.
*/ */
void void
get_atttypetypmod(Oid relid, AttrNumber attnum, get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
Oid *typid, int32 *typmod) Oid *typid, int32 *typmod, Oid *collid)
{ {
HeapTuple tp; HeapTuple tp;
Form_pg_attribute att_tup; Form_pg_attribute att_tup;
@ -956,6 +929,7 @@ get_atttypetypmod(Oid relid, AttrNumber attnum,
*typid = att_tup->atttypid; *typid = att_tup->atttypid;
*typmod = att_tup->atttypmod; *typmod = att_tup->atttypmod;
*collid = att_tup->attcollation;
ReleaseSysCache(tp); ReleaseSysCache(tp);
} }

View File

@ -60,9 +60,8 @@ extern char *get_relid_attribute_name(Oid relid, AttrNumber attnum);
extern AttrNumber get_attnum(Oid relid, const char *attname); extern AttrNumber get_attnum(Oid relid, const char *attname);
extern Oid get_atttype(Oid relid, AttrNumber attnum); extern Oid get_atttype(Oid relid, AttrNumber attnum);
extern int32 get_atttypmod(Oid relid, AttrNumber attnum); extern int32 get_atttypmod(Oid relid, AttrNumber attnum);
extern Oid get_attcollation(Oid relid, AttrNumber attnum); extern void get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
extern void get_atttypetypmod(Oid relid, AttrNumber attnum, Oid *typid, int32 *typmod, Oid *collid);
Oid *typid, int32 *typmod);
extern char *get_collation_name(Oid colloid); extern char *get_collation_name(Oid colloid);
extern char *get_constraint_name(Oid conoid); extern char *get_constraint_name(Oid conoid);
extern Oid get_opclass_family(Oid opclass); extern Oid get_opclass_family(Oid opclass);