From b23c9fa9293c54a3829093d207be37a7b42cb630 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 26 Mar 2011 14:25:48 -0400 Subject: [PATCH] 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. --- src/backend/optimizer/path/pathkeys.c | 3 +-- src/backend/optimizer/plan/createplan.c | 2 ++ src/backend/optimizer/util/clauses.c | 2 +- src/backend/optimizer/util/predtest.c | 4 ++++ src/backend/parser/parse_coerce.c | 2 ++ src/backend/parser/parse_target.c | 31 +++++++++++++++++++++++---- src/backend/utils/adt/ruleutils.c | 6 ++++-- src/backend/utils/cache/lsyscache.c | 38 ++++++--------------------------- src/include/utils/lsyscache.h | 5 ++--- 9 files changed, 49 insertions(+), 44 deletions(-) diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 34c772356b..47597a5d35 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -603,8 +603,7 @@ find_indexkey_var(PlannerInfo *root, RelOptInfo *rel, AttrNumber varattno) relid = rel->relid; reloid = getrelid(relid, root->parse->rtable); - get_atttypetypmod(reloid, varattno, &vartypeid, &type_mod); - varcollid = get_attcollation(reloid, varattno); + get_atttypetypmodcoll(reloid, varattno, &vartypeid, &type_mod, &varcollid); return makeVar(relid, varattno, vartypeid, type_mod, varcollid, 0); } diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index bdd14f524d..f130881251 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -2652,6 +2652,8 @@ get_switched_clauses(List *clauses, Relids outerrelids) temp->opfuncid = InvalidOid; temp->opresulttype = clause->opresulttype; temp->opretset = clause->opretset; + temp->opcollid = clause->opcollid; + temp->inputcollid = clause->inputcollid; temp->args = list_copy(clause->args); temp->location = clause->location; /* Commute it --- note this modifies the temp node in-place. */ diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 1a63146e6f..b1069259f9 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -1816,7 +1816,7 @@ CommuteOpExpr(OpExpr *clause) */ clause->opno = opoid; clause->opfuncid = InvalidOid; - /* opresulttype and opretset are assumed not to change */ + /* opresulttype, opretset, opcollid, inputcollid need not change */ temp = linitial(clause->args); linitial(clause->args) = lsecond(clause->args); diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index 6a1f7291ba..72fd3e4ca7 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -906,6 +906,8 @@ arrayconst_startup_fn(Node *clause, PredIterInfo info) state->opexpr.opfuncid = saop->opfuncid; state->opexpr.opresulttype = BOOLOID; state->opexpr.opretset = false; + state->opexpr.opcollid = InvalidOid; + state->opexpr.inputcollid = saop->inputcollid; state->opexpr.args = list_copy(saop->args); /* 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.opresulttype = BOOLOID; state->opexpr.opretset = false; + state->opexpr.opcollid = InvalidOid; + state->opexpr.inputcollid = saop->inputcollid; state->opexpr.args = list_copy(saop->args); /* Initialize iteration variable to first member of ArrayExpr */ diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index cc03f9f48e..dd3e748c9f 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -796,6 +796,7 @@ build_coercion_expression(Node *node, * one argument. */ acoerce->resulttypmod = (nargs >= 2) ? targetTypMod : -1; + /* resultcollid will be set by parse_collate.c */ acoerce->isExplicit = isExplicit; acoerce->coerceformat = cformat; acoerce->location = location; @@ -811,6 +812,7 @@ build_coercion_expression(Node *node, iocoerce->arg = (Expr *) node; iocoerce->resulttype = targetTypeId; + /* resultcollid will be set by parse_collate.c */ iocoerce->coerceformat = cformat; iocoerce->location = location; diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 8e92b99b5b..d53d1d9f00 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -40,6 +40,7 @@ static Node *transformAssignmentIndirection(ParseState *pstate, bool targetIsArray, Oid targetTypeId, int32 targetTypMod, + Oid targetCollation, ListCell *indirection, Node *rhs, int location); @@ -48,6 +49,7 @@ static Node *transformAssignmentSubscripts(ParseState *pstate, const char *targetName, Oid targetTypeId, int32 targetTypMod, + Oid targetCollation, List *subscripts, bool isSlice, ListCell *next_indirection, @@ -455,6 +457,7 @@ transformAssignedExpr(ParseState *pstate, false, attrtype, attrtypmod, + attrcollation, list_head(indirection), (Node *) expr, location); @@ -548,8 +551,9 @@ updateTargetListEntry(ParseState *pstate, * targetIsArray is true if we're subscripting it. These are just for * error reporting. * - * targetTypeId and targetTypMod indicate the datatype of the object to - * be assigned to (initially the target column, later some subobject). + * targetTypeId, targetTypMod, targetCollation indicate the datatype and + * 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 * done recursing and can just coerce and return the RHS. @@ -569,6 +573,7 @@ transformAssignmentIndirection(ParseState *pstate, bool targetIsArray, Oid targetTypeId, int32 targetTypMod, + Oid targetCollation, ListCell *indirection, Node *rhs, int location) @@ -585,6 +590,7 @@ transformAssignmentIndirection(ParseState *pstate, ctest->typeId = targetTypeId; ctest->typeMod = targetTypMod; + ctest->collation = targetCollation; basenode = (Node *) ctest; } @@ -617,6 +623,7 @@ transformAssignmentIndirection(ParseState *pstate, AttrNumber attnum; Oid fieldTypeId; int32 fieldTypMod; + Oid fieldCollation; Assert(IsA(n, String)); @@ -629,6 +636,7 @@ transformAssignmentIndirection(ParseState *pstate, targetName, targetTypeId, targetTypMod, + targetCollation, subscripts, isSlice, i, @@ -662,8 +670,8 @@ transformAssignmentIndirection(ParseState *pstate, strVal(n)), parser_errposition(pstate, location))); - get_atttypetypmod(typrelid, attnum, - &fieldTypeId, &fieldTypMod); + get_atttypetypmodcoll(typrelid, attnum, + &fieldTypeId, &fieldTypMod, &fieldCollation); /* recurse to create appropriate RHS for field assign */ rhs = transformAssignmentIndirection(pstate, @@ -672,6 +680,7 @@ transformAssignmentIndirection(ParseState *pstate, false, fieldTypeId, fieldTypMod, + fieldCollation, lnext(i), rhs, location); @@ -696,6 +705,7 @@ transformAssignmentIndirection(ParseState *pstate, targetName, targetTypeId, targetTypMod, + targetCollation, subscripts, isSlice, NULL, @@ -747,6 +757,7 @@ transformAssignmentSubscripts(ParseState *pstate, const char *targetName, Oid targetTypeId, int32 targetTypMod, + Oid targetCollation, List *subscripts, bool isSlice, ListCell *next_indirection, @@ -758,6 +769,7 @@ transformAssignmentSubscripts(ParseState *pstate, int32 arrayTypMod; Oid elementTypeId; Oid typeNeeded; + Oid collationNeeded; Assert(subscripts != NIL); @@ -769,6 +781,16 @@ transformAssignmentSubscripts(ParseState *pstate, /* Identify type that RHS must provide */ 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 */ rhs = transformAssignmentIndirection(pstate, NULL, @@ -776,6 +798,7 @@ transformAssignmentSubscripts(ParseState *pstate, true, typeNeeded, arrayTypMod, + collationNeeded, next_indirection, rhs, location); diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 621f1eb24a..326079a75b 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -912,12 +912,14 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, { /* Simple index column */ char *attname; + int32 keycoltypmod; attname = get_relid_attribute_name(indrelid, attnum); if (!colno || colno == keyno + 1) appendStringInfoString(&buf, quote_identifier(attname)); - keycoltype = get_atttype(indrelid, attnum); - keycolcollation = get_attcollation(indrelid, attnum); + get_atttypetypmodcoll(indrelid, attnum, + &keycoltype, &keycoltypmod, + &keycolcollation); } else { diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 6bcaf30ffe..877e50d873 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -904,44 +904,17 @@ get_atttypmod(Oid relid, AttrNumber attnum) } /* - * get_attcollation + * get_atttypetypmodcoll * - * Given the relation id and the attribute number, - * return the "attcollation" field from the attribute relation. - */ -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. + * A three-fer: given the relation id and the attribute number, + * fetch atttypid, atttypmod, and attcollation in a single cache lookup. * * Unlike the otherwise-similar get_atttype/get_atttypmod, this routine * raises an error if it can't obtain the information. */ void -get_atttypetypmod(Oid relid, AttrNumber attnum, - Oid *typid, int32 *typmod) +get_atttypetypmodcoll(Oid relid, AttrNumber attnum, + Oid *typid, int32 *typmod, Oid *collid) { HeapTuple tp; Form_pg_attribute att_tup; @@ -956,6 +929,7 @@ get_atttypetypmod(Oid relid, AttrNumber attnum, *typid = att_tup->atttypid; *typmod = att_tup->atttypmod; + *collid = att_tup->attcollation; ReleaseSysCache(tp); } diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index 22dfd58f0a..b6ceb26c8b 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -60,9 +60,8 @@ extern char *get_relid_attribute_name(Oid relid, AttrNumber attnum); extern AttrNumber get_attnum(Oid relid, const char *attname); extern Oid get_atttype(Oid relid, AttrNumber attnum); extern int32 get_atttypmod(Oid relid, AttrNumber attnum); -extern Oid get_attcollation(Oid relid, AttrNumber attnum); -extern void get_atttypetypmod(Oid relid, AttrNumber attnum, - Oid *typid, int32 *typmod); +extern void get_atttypetypmodcoll(Oid relid, AttrNumber attnum, + Oid *typid, int32 *typmod, Oid *collid); extern char *get_collation_name(Oid colloid); extern char *get_constraint_name(Oid conoid); extern Oid get_opclass_family(Oid opclass); -- 2.11.0