Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 918854c

Browse files
committed
Fix handling of collations in multi-row VALUES constructs.
Per spec we ought to apply select_common_collation() across the expressions in each column of the VALUES table. The original coding was just taking the first row and assuming it was representative. This patch adds a field to struct RangeTblEntry to carry the resolved collations, so initdb is forced for changes in stored rule representation.
1 parent 04db0fd commit 918854c

File tree

13 files changed

+131
-53
lines changed

13 files changed

+131
-53
lines changed

src/backend/catalog/dependency.c

+9-4
Original file line numberDiff line numberDiff line change
@@ -1671,10 +1671,15 @@ find_expr_references_walker(Node *node,
16711671
/*
16721672
* Add whole-relation refs for each plain relation mentioned in the
16731673
* subquery's rtable, as well as refs for any datatypes and collations
1674-
* used in a RECORD function's output. (Note: query_tree_walker takes
1675-
* care of recursing into RTE_FUNCTION RTEs, subqueries, etc, so no
1676-
* need to do that here. But keep it from looking at join alias
1677-
* lists.)
1674+
* used in a RECORD function's output.
1675+
*
1676+
* Note: query_tree_walker takes care of recursing into RTE_FUNCTION
1677+
* RTEs, subqueries, etc, so no need to do that here. But keep it
1678+
* from looking at join alias lists.
1679+
*
1680+
* Note: we don't need to worry about collations mentioned in
1681+
* RTE_VALUES or RTE_CTE RTEs, because those must just duplicate
1682+
* collations referenced in other parts of the Query.
16781683
*/
16791684
foreach(lc, query->rtable)
16801685
{

src/backend/nodes/copyfuncs.c

+1
Original file line numberDiff line numberDiff line change
@@ -1951,6 +1951,7 @@ _copyRangeTblEntry(RangeTblEntry *from)
19511951
COPY_NODE_FIELD(funccoltypmods);
19521952
COPY_NODE_FIELD(funccolcollations);
19531953
COPY_NODE_FIELD(values_lists);
1954+
COPY_NODE_FIELD(values_collations);
19541955
COPY_STRING_FIELD(ctename);
19551956
COPY_SCALAR_FIELD(ctelevelsup);
19561957
COPY_SCALAR_FIELD(self_reference);

src/backend/nodes/equalfuncs.c

+1
Original file line numberDiff line numberDiff line change
@@ -2310,6 +2310,7 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
23102310
COMPARE_NODE_FIELD(funccoltypmods);
23112311
COMPARE_NODE_FIELD(funccolcollations);
23122312
COMPARE_NODE_FIELD(values_lists);
2313+
COMPARE_NODE_FIELD(values_collations);
23132314
COMPARE_STRING_FIELD(ctename);
23142315
COMPARE_SCALAR_FIELD(ctelevelsup);
23152316
COMPARE_SCALAR_FIELD(self_reference);

src/backend/nodes/outfuncs.c

+1
Original file line numberDiff line numberDiff line change
@@ -2324,6 +2324,7 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
23242324
break;
23252325
case RTE_VALUES:
23262326
WRITE_NODE_FIELD(values_lists);
2327+
WRITE_NODE_FIELD(values_collations);
23272328
break;
23282329
case RTE_CTE:
23292330
WRITE_STRING_FIELD(ctename);

src/backend/nodes/readfuncs.c

+1
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,7 @@ _readRangeTblEntry(void)
12031203
break;
12041204
case RTE_VALUES:
12051205
READ_NODE_FIELD(values_lists);
1206+
READ_NODE_FIELD(values_collations);
12061207
break;
12071208
case RTE_CTE:
12081209
READ_STRING_FIELD(ctename);

src/backend/optimizer/plan/setrefs.c

+1
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ set_plan_references(PlannerGlobal *glob, Plan *plan,
216216
newrte->funccoltypmods = NIL;
217217
newrte->funccolcollations = NIL;
218218
newrte->values_lists = NIL;
219+
newrte->values_collations = NIL;
219220
newrte->ctecoltypes = NIL;
220221
newrte->ctecoltypmods = NIL;
221222
newrte->ctecolcollations = NIL;

src/backend/parser/analyze.c

+85-40
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
536536
* RTE.
537537
*/
538538
List *exprsLists = NIL;
539+
List *collations = NIL;
539540
int sublist_length = -1;
541+
int i;
540542

541543
foreach(lc, selectStmt->valuesLists)
542544
{
@@ -573,13 +575,26 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
573575
* We must assign collations now because assign_query_collations
574576
* doesn't process rangetable entries. We just assign all the
575577
* collations independently in each row, and don't worry about
576-
* whether they are consistent vertically either.
578+
* whether they are consistent vertically. The outer INSERT query
579+
* isn't going to care about the collations of the VALUES columns,
580+
* so it's not worth the effort to identify a common collation for
581+
* each one here. (But note this does have one user-visible
582+
* consequence: INSERT ... VALUES won't complain about conflicting
583+
* explicit COLLATEs in a column, whereas the same VALUES
584+
* construct in another context would complain.)
577585
*/
578586
assign_list_collations(pstate, sublist);
579587

580588
exprsLists = lappend(exprsLists, sublist);
581589
}
582590

591+
/*
592+
* Although we don't really need collation info, let's just make sure
593+
* we provide a correctly-sized list in the VALUES RTE.
594+
*/
595+
for (i = 0; i < sublist_length; i++)
596+
collations = lappend_oid(collations, InvalidOid);
597+
583598
/*
584599
* There mustn't have been any table references in the expressions,
585600
* else strange things would happen, like Cartesian products of those
@@ -610,7 +625,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
610625
/*
611626
* Generate the VALUES RTE
612627
*/
613-
rte = addRangeTableEntryForValues(pstate, exprsLists, NULL, true);
628+
rte = addRangeTableEntryForValues(pstate, exprsLists, collations,
629+
NULL, true);
614630
rtr = makeNode(RangeTblRef);
615631
/* assume new rte is at end */
616632
rtr->rtindex = list_length(pstate->p_rtable);
@@ -989,11 +1005,10 @@ static Query *
9891005
transformValuesClause(ParseState *pstate, SelectStmt *stmt)
9901006
{
9911007
Query *qry = makeNode(Query);
992-
List *exprsLists = NIL;
1008+
List *exprsLists;
1009+
List *collations;
9931010
List **colexprs = NULL;
994-
Oid *coltypes = NULL;
9951011
int sublist_length = -1;
996-
List *newExprsLists;
9971012
RangeTblEntry *rte;
9981013
RangeTblRef *rtr;
9991014
ListCell *lc;
@@ -1021,9 +1036,13 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
10211036
}
10221037

10231038
/*
1024-
* For each row of VALUES, transform the raw expressions and gather type
1025-
* information. This is also a handy place to reject DEFAULT nodes, which
1026-
* the grammar allows for simplicity.
1039+
* For each row of VALUES, transform the raw expressions. This is also a
1040+
* handy place to reject DEFAULT nodes, which the grammar allows for
1041+
* simplicity.
1042+
*
1043+
* Note that the intermediate representation we build is column-organized
1044+
* not row-organized. That simplifies the type and collation processing
1045+
* below.
10271046
*/
10281047
foreach(lc, stmt->valuesLists)
10291048
{
@@ -1041,9 +1060,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
10411060
{
10421061
/* Remember post-transformation length of first sublist */
10431062
sublist_length = list_length(sublist);
1044-
/* and allocate arrays for per-column info */
1063+
/* and allocate array for per-column lists */
10451064
colexprs = (List **) palloc0(sublist_length * sizeof(List *));
1046-
coltypes = (Oid *) palloc0(sublist_length * sizeof(Oid));
10471065
}
10481066
else if (sublist_length != list_length(sublist))
10491067
{
@@ -1054,8 +1072,6 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
10541072
exprLocation((Node *) sublist))));
10551073
}
10561074

1057-
exprsLists = lappend(exprsLists, sublist);
1058-
10591075
/* Check for DEFAULT and build per-column expression lists */
10601076
i = 0;
10611077
foreach(lc2, sublist)
@@ -1070,48 +1086,77 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
10701086
colexprs[i] = lappend(colexprs[i], col);
10711087
i++;
10721088
}
1089+
1090+
/* Release sub-list's cells to save memory */
1091+
list_free(sublist);
10731092
}
10741093

10751094
/*
10761095
* Now resolve the common types of the columns, and coerce everything to
1077-
* those types.
1096+
* those types. Then identify the common collation, if any, of each
1097+
* column.
1098+
*
1099+
* We must do collation processing now because (1) assign_query_collations
1100+
* doesn't process rangetable entries, and (2) we need to label the VALUES
1101+
* RTE with column collations for use in the outer query. We don't
1102+
* consider conflict of implicit collations to be an error here; instead
1103+
* the column will just show InvalidOid as its collation, and you'll get
1104+
* a failure later if that results in failure to resolve a collation.
1105+
*
1106+
* Note we modify the per-column expression lists in-place.
10781107
*/
1108+
collations = NIL;
10791109
for (i = 0; i < sublist_length; i++)
10801110
{
1081-
coltypes[i] = select_common_type(pstate, colexprs[i], "VALUES", NULL);
1082-
}
1111+
Oid coltype;
1112+
Oid colcoll;
10831113

1084-
newExprsLists = NIL;
1085-
foreach(lc, exprsLists)
1086-
{
1087-
List *sublist = (List *) lfirst(lc);
1088-
List *newsublist = NIL;
1114+
coltype = select_common_type(pstate, colexprs[i], "VALUES", NULL);
10891115

1090-
i = 0;
1091-
foreach(lc2, sublist)
1116+
foreach(lc, colexprs[i])
10921117
{
1093-
Node *col = (Node *) lfirst(lc2);
1118+
Node *col = (Node *) lfirst(lc);
10941119

1095-
col = coerce_to_common_type(pstate, col, coltypes[i], "VALUES");
1096-
newsublist = lappend(newsublist, col);
1097-
i++;
1120+
col = coerce_to_common_type(pstate, col, coltype, "VALUES");
1121+
lfirst(lc) = (void *) col;
10981122
}
10991123

1100-
/*
1101-
* We must assign collations now because assign_query_collations
1102-
* doesn't process rangetable entries. We just assign all the
1103-
* collations independently in each row, and don't worry about whether
1104-
* they are consistent vertically either.
1105-
*/
1106-
assign_list_collations(pstate, newsublist);
1124+
colcoll = select_common_collation(pstate, colexprs[i], true);
1125+
1126+
collations = lappend_oid(collations, colcoll);
1127+
}
11071128

1108-
newExprsLists = lappend(newExprsLists, newsublist);
1129+
/*
1130+
* Finally, rearrange the coerced expressions into row-organized lists.
1131+
*/
1132+
exprsLists = NIL;
1133+
foreach(lc, colexprs[0])
1134+
{
1135+
Node *col = (Node *) lfirst(lc);
1136+
List *sublist;
1137+
1138+
sublist = list_make1(col);
1139+
exprsLists = lappend(exprsLists, sublist);
1140+
}
1141+
list_free(colexprs[0]);
1142+
for (i = 1; i < sublist_length; i++)
1143+
{
1144+
forboth(lc, colexprs[i], lc2, exprsLists)
1145+
{
1146+
Node *col = (Node *) lfirst(lc);
1147+
List *sublist = lfirst(lc2);
1148+
1149+
/* sublist pointer in exprsLists won't need adjustment */
1150+
(void) lappend(sublist, col);
1151+
}
1152+
list_free(colexprs[i]);
11091153
}
11101154

11111155
/*
11121156
* Generate the VALUES RTE
11131157
*/
1114-
rte = addRangeTableEntryForValues(pstate, newExprsLists, NULL, true);
1158+
rte = addRangeTableEntryForValues(pstate, exprsLists, collations,
1159+
NULL, true);
11151160
rtr = makeNode(RangeTblRef);
11161161
/* assume new rte is at end */
11171162
rtr->rtindex = list_length(pstate->p_rtable);
@@ -1164,7 +1209,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
11641209
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11651210
errmsg("VALUES must not contain table references"),
11661211
parser_errposition(pstate,
1167-
locate_var_of_level((Node *) newExprsLists, 0))));
1212+
locate_var_of_level((Node *) exprsLists, 0))));
11681213

11691214
/*
11701215
* Another thing we can't currently support is NEW/OLD references in rules
@@ -1173,13 +1218,13 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
11731218
* This is a shame. FIXME
11741219
*/
11751220
if (list_length(pstate->p_rtable) != 1 &&
1176-
contain_vars_of_level((Node *) newExprsLists, 0))
1221+
contain_vars_of_level((Node *) exprsLists, 0))
11771222
ereport(ERROR,
11781223
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
11791224
errmsg("VALUES must not contain OLD or NEW references"),
11801225
errhint("Use SELECT ... UNION ALL ... instead."),
11811226
parser_errposition(pstate,
1182-
locate_var_of_level((Node *) newExprsLists, 0))));
1227+
locate_var_of_level((Node *) exprsLists, 0))));
11831228

11841229
qry->rtable = pstate->p_rtable;
11851230
qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
@@ -1191,13 +1236,13 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
11911236
(errcode(ERRCODE_GROUPING_ERROR),
11921237
errmsg("cannot use aggregate function in VALUES"),
11931238
parser_errposition(pstate,
1194-
locate_agg_of_level((Node *) newExprsLists, 0))));
1239+
locate_agg_of_level((Node *) exprsLists, 0))));
11951240
if (pstate->p_hasWindowFuncs)
11961241
ereport(ERROR,
11971242
(errcode(ERRCODE_WINDOWING_ERROR),
11981243
errmsg("cannot use window function in VALUES"),
11991244
parser_errposition(pstate,
1200-
locate_windowfunc((Node *) newExprsLists))));
1245+
locate_windowfunc((Node *) exprsLists))));
12011246

12021247
assign_query_collations(pstate, qry);
12031248

src/backend/parser/parse_relation.c

+17-7
Original file line numberDiff line numberDiff line change
@@ -1220,6 +1220,7 @@ addRangeTableEntryForFunction(ParseState *pstate,
12201220
RangeTblEntry *
12211221
addRangeTableEntryForValues(ParseState *pstate,
12221222
List *exprs,
1223+
List *collations,
12231224
Alias *alias,
12241225
bool inFromCl)
12251226
{
@@ -1233,6 +1234,7 @@ addRangeTableEntryForValues(ParseState *pstate,
12331234
rte->relid = InvalidOid;
12341235
rte->subquery = NULL;
12351236
rte->values_lists = exprs;
1237+
rte->values_collations = collations;
12361238
rte->alias = alias;
12371239

12381240
eref = alias ? copyObject(alias) : makeAlias(refname, NIL);
@@ -1657,7 +1659,9 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
16571659
ListCell *l3;
16581660
int attnum = 0;
16591661

1660-
forthree(l1, rte->funccoltypes, l2, rte->funccoltypmods, l3, rte->funccolcollations)
1662+
forthree(l1, rte->funccoltypes,
1663+
l2, rte->funccoltypmods,
1664+
l3, rte->funccolcollations)
16611665
{
16621666
Oid attrtype = lfirst_oid(l1);
16631667
int32 attrtypmod = lfirst_int(l2);
@@ -1687,12 +1691,15 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
16871691
{
16881692
/* Values RTE */
16891693
ListCell *aliasp_item = list_head(rte->eref->colnames);
1690-
ListCell *lc;
1694+
ListCell *lcv;
1695+
ListCell *lcc;
16911696

16921697
varattno = 0;
1693-
foreach(lc, (List *) linitial(rte->values_lists))
1698+
forboth(lcv, (List *) linitial(rte->values_lists),
1699+
lcc, rte->values_collations)
16941700
{
1695-
Node *col = (Node *) lfirst(lc);
1701+
Node *col = (Node *) lfirst(lcv);
1702+
Oid colcollation = lfirst_oid(lcc);
16961703

16971704
varattno++;
16981705
if (colnames)
@@ -1712,7 +1719,7 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
17121719
varnode = makeVar(rtindex, varattno,
17131720
exprType(col),
17141721
exprTypmod(col),
1715-
exprCollation(col),
1722+
colcollation,
17161723
sublevels_up);
17171724
varnode->location = location;
17181725
*colvars = lappend(*colvars, varnode);
@@ -1789,7 +1796,9 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
17891796
ListCell *lcc;
17901797

17911798
varattno = 0;
1792-
forthree(lct, rte->ctecoltypes, lcm, rte->ctecoltypmods, lcc, rte->ctecolcollations)
1799+
forthree(lct, rte->ctecoltypes,
1800+
lcm, rte->ctecoltypmods,
1801+
lcc, rte->ctecolcollations)
17931802
{
17941803
Oid coltype = lfirst_oid(lct);
17951804
int32 coltypmod = lfirst_int(lcm);
@@ -2116,6 +2125,7 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
21162125
case RTE_VALUES:
21172126
{
21182127
/* Values RTE --- get type info from first sublist */
2128+
/* collation is stored separately, though */
21192129
List *collist = (List *) linitial(rte->values_lists);
21202130
Node *col;
21212131

@@ -2125,7 +2135,7 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
21252135
col = (Node *) list_nth(collist, attnum - 1);
21262136
*vartype = exprType(col);
21272137
*vartypmod = exprTypmod(col);
2128-
*varcollid = exprCollation(col);
2138+
*varcollid = list_nth_oid(rte->values_collations, attnum - 1);
21292139
}
21302140
break;
21312141
case RTE_JOIN:

src/include/catalog/catversion.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201104051
56+
#define CATALOG_VERSION_NO 201104181
5757

5858
#endif

0 commit comments

Comments
 (0)