Skip to content

Commit b23c9fa

Browse files
committed
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.
1 parent 92f4786 commit b23c9fa

File tree

9 files changed

+49
-44
lines changed

9 files changed

+49
-44
lines changed

src/backend/optimizer/path/pathkeys.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -603,8 +603,7 @@ find_indexkey_var(PlannerInfo *root, RelOptInfo *rel, AttrNumber varattno)
603603

604604
relid = rel->relid;
605605
reloid = getrelid(relid, root->parse->rtable);
606-
get_atttypetypmod(reloid, varattno, &vartypeid, &type_mod);
607-
varcollid = get_attcollation(reloid, varattno);
606+
get_atttypetypmodcoll(reloid, varattno, &vartypeid, &type_mod, &varcollid);
608607

609608
return makeVar(relid, varattno, vartypeid, type_mod, varcollid, 0);
610609
}

src/backend/optimizer/plan/createplan.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2652,6 +2652,8 @@ get_switched_clauses(List *clauses, Relids outerrelids)
26522652
temp->opfuncid = InvalidOid;
26532653
temp->opresulttype = clause->opresulttype;
26542654
temp->opretset = clause->opretset;
2655+
temp->opcollid = clause->opcollid;
2656+
temp->inputcollid = clause->inputcollid;
26552657
temp->args = list_copy(clause->args);
26562658
temp->location = clause->location;
26572659
/* Commute it --- note this modifies the temp node in-place. */

src/backend/optimizer/util/clauses.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1816,7 +1816,7 @@ CommuteOpExpr(OpExpr *clause)
18161816
*/
18171817
clause->opno = opoid;
18181818
clause->opfuncid = InvalidOid;
1819-
/* opresulttype and opretset are assumed not to change */
1819+
/* opresulttype, opretset, opcollid, inputcollid need not change */
18201820

18211821
temp = linitial(clause->args);
18221822
linitial(clause->args) = lsecond(clause->args);

src/backend/optimizer/util/predtest.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,8 @@ arrayconst_startup_fn(Node *clause, PredIterInfo info)
906906
state->opexpr.opfuncid = saop->opfuncid;
907907
state->opexpr.opresulttype = BOOLOID;
908908
state->opexpr.opretset = false;
909+
state->opexpr.opcollid = InvalidOid;
910+
state->opexpr.inputcollid = saop->inputcollid;
909911
state->opexpr.args = list_copy(saop->args);
910912

911913
/* Set up a dummy Const node to hold the per-element values */
@@ -972,6 +974,8 @@ arrayexpr_startup_fn(Node *clause, PredIterInfo info)
972974
state->opexpr.opfuncid = saop->opfuncid;
973975
state->opexpr.opresulttype = BOOLOID;
974976
state->opexpr.opretset = false;
977+
state->opexpr.opcollid = InvalidOid;
978+
state->opexpr.inputcollid = saop->inputcollid;
975979
state->opexpr.args = list_copy(saop->args);
976980

977981
/* Initialize iteration variable to first member of ArrayExpr */

src/backend/parser/parse_coerce.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@ build_coercion_expression(Node *node,
796796
* one argument.
797797
*/
798798
acoerce->resulttypmod = (nargs >= 2) ? targetTypMod : -1;
799+
/* resultcollid will be set by parse_collate.c */
799800
acoerce->isExplicit = isExplicit;
800801
acoerce->coerceformat = cformat;
801802
acoerce->location = location;
@@ -811,6 +812,7 @@ build_coercion_expression(Node *node,
811812

812813
iocoerce->arg = (Expr *) node;
813814
iocoerce->resulttype = targetTypeId;
815+
/* resultcollid will be set by parse_collate.c */
814816
iocoerce->coerceformat = cformat;
815817
iocoerce->location = location;
816818

src/backend/parser/parse_target.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ static Node *transformAssignmentIndirection(ParseState *pstate,
4040
bool targetIsArray,
4141
Oid targetTypeId,
4242
int32 targetTypMod,
43+
Oid targetCollation,
4344
ListCell *indirection,
4445
Node *rhs,
4546
int location);
@@ -48,6 +49,7 @@ static Node *transformAssignmentSubscripts(ParseState *pstate,
4849
const char *targetName,
4950
Oid targetTypeId,
5051
int32 targetTypMod,
52+
Oid targetCollation,
5153
List *subscripts,
5254
bool isSlice,
5355
ListCell *next_indirection,
@@ -455,6 +457,7 @@ transformAssignedExpr(ParseState *pstate,
455457
false,
456458
attrtype,
457459
attrtypmod,
460+
attrcollation,
458461
list_head(indirection),
459462
(Node *) expr,
460463
location);
@@ -548,8 +551,9 @@ updateTargetListEntry(ParseState *pstate,
548551
* targetIsArray is true if we're subscripting it. These are just for
549552
* error reporting.
550553
*
551-
* targetTypeId and targetTypMod indicate the datatype of the object to
552-
* be assigned to (initially the target column, later some subobject).
554+
* targetTypeId, targetTypMod, targetCollation indicate the datatype and
555+
* collation of the object to be assigned to (initially the target column,
556+
* later some subobject).
553557
*
554558
* indirection is the sublist remaining to process. When it's NULL, we're
555559
* done recursing and can just coerce and return the RHS.
@@ -569,6 +573,7 @@ transformAssignmentIndirection(ParseState *pstate,
569573
bool targetIsArray,
570574
Oid targetTypeId,
571575
int32 targetTypMod,
576+
Oid targetCollation,
572577
ListCell *indirection,
573578
Node *rhs,
574579
int location)
@@ -585,6 +590,7 @@ transformAssignmentIndirection(ParseState *pstate,
585590

586591
ctest->typeId = targetTypeId;
587592
ctest->typeMod = targetTypMod;
593+
ctest->collation = targetCollation;
588594
basenode = (Node *) ctest;
589595
}
590596

@@ -617,6 +623,7 @@ transformAssignmentIndirection(ParseState *pstate,
617623
AttrNumber attnum;
618624
Oid fieldTypeId;
619625
int32 fieldTypMod;
626+
Oid fieldCollation;
620627

621628
Assert(IsA(n, String));
622629

@@ -629,6 +636,7 @@ transformAssignmentIndirection(ParseState *pstate,
629636
targetName,
630637
targetTypeId,
631638
targetTypMod,
639+
targetCollation,
632640
subscripts,
633641
isSlice,
634642
i,
@@ -662,8 +670,8 @@ transformAssignmentIndirection(ParseState *pstate,
662670
strVal(n)),
663671
parser_errposition(pstate, location)));
664672

665-
get_atttypetypmod(typrelid, attnum,
666-
&fieldTypeId, &fieldTypMod);
673+
get_atttypetypmodcoll(typrelid, attnum,
674+
&fieldTypeId, &fieldTypMod, &fieldCollation);
667675

668676
/* recurse to create appropriate RHS for field assign */
669677
rhs = transformAssignmentIndirection(pstate,
@@ -672,6 +680,7 @@ transformAssignmentIndirection(ParseState *pstate,
672680
false,
673681
fieldTypeId,
674682
fieldTypMod,
683+
fieldCollation,
675684
lnext(i),
676685
rhs,
677686
location);
@@ -696,6 +705,7 @@ transformAssignmentIndirection(ParseState *pstate,
696705
targetName,
697706
targetTypeId,
698707
targetTypMod,
708+
targetCollation,
699709
subscripts,
700710
isSlice,
701711
NULL,
@@ -747,6 +757,7 @@ transformAssignmentSubscripts(ParseState *pstate,
747757
const char *targetName,
748758
Oid targetTypeId,
749759
int32 targetTypMod,
760+
Oid targetCollation,
750761
List *subscripts,
751762
bool isSlice,
752763
ListCell *next_indirection,
@@ -758,6 +769,7 @@ transformAssignmentSubscripts(ParseState *pstate,
758769
int32 arrayTypMod;
759770
Oid elementTypeId;
760771
Oid typeNeeded;
772+
Oid collationNeeded;
761773

762774
Assert(subscripts != NIL);
763775

@@ -769,13 +781,24 @@ transformAssignmentSubscripts(ParseState *pstate,
769781
/* Identify type that RHS must provide */
770782
typeNeeded = isSlice ? arrayType : elementTypeId;
771783

784+
/*
785+
* Array normally has same collation as elements, but there's an
786+
* exception: we might be subscripting a domain over an array type.
787+
* In that case use collation of the base type.
788+
*/
789+
if (arrayType == targetTypeId)
790+
collationNeeded = targetCollation;
791+
else
792+
collationNeeded = get_typcollation(arrayType);
793+
772794
/* recurse to create appropriate RHS for array assign */
773795
rhs = transformAssignmentIndirection(pstate,
774796
NULL,
775797
targetName,
776798
true,
777799
typeNeeded,
778800
arrayTypMod,
801+
collationNeeded,
779802
next_indirection,
780803
rhs,
781804
location);

src/backend/utils/adt/ruleutils.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -912,12 +912,14 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
912912
{
913913
/* Simple index column */
914914
char *attname;
915+
int32 keycoltypmod;
915916

916917
attname = get_relid_attribute_name(indrelid, attnum);
917918
if (!colno || colno == keyno + 1)
918919
appendStringInfoString(&buf, quote_identifier(attname));
919-
keycoltype = get_atttype(indrelid, attnum);
920-
keycolcollation = get_attcollation(indrelid, attnum);
920+
get_atttypetypmodcoll(indrelid, attnum,
921+
&keycoltype, &keycoltypmod,
922+
&keycolcollation);
921923
}
922924
else
923925
{

src/backend/utils/cache/lsyscache.c

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -904,44 +904,17 @@ get_atttypmod(Oid relid, AttrNumber attnum)
904904
}
905905

906906
/*
907-
* get_attcollation
907+
* get_atttypetypmodcoll
908908
*
909-
* Given the relation id and the attribute number,
910-
* return the "attcollation" field from the attribute relation.
911-
*/
912-
Oid
913-
get_attcollation(Oid relid, AttrNumber attnum)
914-
{
915-
HeapTuple tp;
916-
917-
tp = SearchSysCache2(ATTNUM,
918-
ObjectIdGetDatum(relid),
919-
Int16GetDatum(attnum));
920-
if (HeapTupleIsValid(tp))
921-
{
922-
Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp);
923-
Oid result;
924-
925-
result = att_tup->attcollation;
926-
ReleaseSysCache(tp);
927-
return result;
928-
}
929-
else
930-
return InvalidOid;
931-
}
932-
933-
/*
934-
* get_atttypetypmod
935-
*
936-
* A two-fer: given the relation id and the attribute number,
937-
* fetch both type OID and atttypmod in a single cache lookup.
909+
* A three-fer: given the relation id and the attribute number,
910+
* fetch atttypid, atttypmod, and attcollation in a single cache lookup.
938911
*
939912
* Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
940913
* raises an error if it can't obtain the information.
941914
*/
942915
void
943-
get_atttypetypmod(Oid relid, AttrNumber attnum,
944-
Oid *typid, int32 *typmod)
916+
get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
917+
Oid *typid, int32 *typmod, Oid *collid)
945918
{
946919
HeapTuple tp;
947920
Form_pg_attribute att_tup;
@@ -956,6 +929,7 @@ get_atttypetypmod(Oid relid, AttrNumber attnum,
956929

957930
*typid = att_tup->atttypid;
958931
*typmod = att_tup->atttypmod;
932+
*collid = att_tup->attcollation;
959933
ReleaseSysCache(tp);
960934
}
961935

src/include/utils/lsyscache.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,8 @@ extern char *get_relid_attribute_name(Oid relid, AttrNumber attnum);
6060
extern AttrNumber get_attnum(Oid relid, const char *attname);
6161
extern Oid get_atttype(Oid relid, AttrNumber attnum);
6262
extern int32 get_atttypmod(Oid relid, AttrNumber attnum);
63-
extern Oid get_attcollation(Oid relid, AttrNumber attnum);
64-
extern void get_atttypetypmod(Oid relid, AttrNumber attnum,
65-
Oid *typid, int32 *typmod);
63+
extern void get_atttypetypmodcoll(Oid relid, AttrNumber attnum,
64+
Oid *typid, int32 *typmod, Oid *collid);
6665
extern char *get_collation_name(Oid colloid);
6766
extern char *get_constraint_name(Oid conoid);
6867
extern Oid get_opclass_family(Oid opclass);

0 commit comments

Comments
 (0)