Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit2afe282

Browse files
committed
Fix reporting of column typmods for multi-row VALUES constructs.
expandRTE() and get_rte_attribute_type() reported the exprType() andexprTypmod() values of the expressions in the first row of the VALUES asbeing the column type/typmod returned by the VALUES RTE. That's fine forthe data type, since we coerce all expressions in a column to have the samecommon type. But we don't coerce them to have a common typmod, so it waspossible for rows after the first one to return values that violate theclaimed column typmod. This leads to the incorrect result seen in bug#14448 from Hassan Mahmood, as well as some other corner-case misbehaviors.The desired behavior is the same as we use in other type-unificationcases: report the common typmod if there is one, but otherwise return -1indicating no particular constraint.We fixed this in HEAD by deriving the typmods during transformValuesClauseand storing them in the RTE, but that's not a feasible solution in the backbranches. Instead, just use a brute-force approach of determining thecorrect common typmod during expandRTE() and get_rte_attribute_type().Simple testing says that that doesn't really cost much, at least not incommon cases where expandRTE() is only used once per query. It turns outthat get_rte_attribute_type() is typically never used at all on VALUESRTEs, so the inefficiency there is of no great concern.Report:https://postgr.es/m/20161205143037.4377.60754@wrigleys.postgresql.orgDiscussion:https://postgr.es/m/27429.1480968538@sss.pgh.pa.us
1 parent8e403f2 commit2afe282

File tree

3 files changed

+147
-4
lines changed

3 files changed

+147
-4
lines changed

‎src/backend/parser/parse_relation.c

Lines changed: 97 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ static void expandTupleDesc(TupleDesc tupdesc, Alias *eref,
5050
intrtindex,intsublevels_up,
5151
intlocation,boolinclude_dropped,
5252
List**colnames,List**colvars);
53+
staticint32*getValuesTypmods(RangeTblEntry*rte);
5354
staticintspecialAttNum(constchar*attname);
5455
staticboolisQueryUsingTempRelation_walker(Node*node,void*context);
5556

@@ -1814,9 +1815,22 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
18141815
{
18151816
/* Values RTE */
18161817
ListCell*aliasp_item=list_head(rte->eref->colnames);
1818+
int32*coltypmods;
18171819
ListCell*lcv;
18181820
ListCell*lcc;
18191821

1822+
/*
1823+
* It's okay to extract column types from the expressions in
1824+
* the first row, since all rows will have been coerced to the
1825+
* same types. Their typmods might not be the same though, so
1826+
* we potentially need to examine all rows to compute those.
1827+
* Column collations are pre-computed in values_collations.
1828+
*/
1829+
if (colvars)
1830+
coltypmods=getValuesTypmods(rte);
1831+
else
1832+
coltypmods=NULL;
1833+
18201834
varattno=0;
18211835
forboth(lcv, (List*)linitial(rte->values_lists),
18221836
lcc,rte->values_collations)
@@ -1841,13 +1855,15 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
18411855

18421856
varnode=makeVar(rtindex,varattno,
18431857
exprType(col),
1844-
exprTypmod(col),
1858+
coltypmods[varattno-1],
18451859
colcollation,
18461860
sublevels_up);
18471861
varnode->location=location;
18481862
*colvars=lappend(*colvars,varnode);
18491863
}
18501864
}
1865+
if (coltypmods)
1866+
pfree(coltypmods);
18511867
}
18521868
break;
18531869
caseRTE_JOIN:
@@ -1953,6 +1969,8 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
19531969
varnode=makeVar(rtindex,varattno,
19541970
coltype,coltypmod,colcoll,
19551971
sublevels_up);
1972+
varnode->location=location;
1973+
19561974
*colvars=lappend(*colvars,varnode);
19571975
}
19581976
}
@@ -2043,6 +2061,74 @@ expandTupleDesc(TupleDesc tupdesc, Alias *eref,
20432061
}
20442062
}
20452063

2064+
/*
2065+
* getValuesTypmods -- expandRTE subroutine
2066+
*
2067+
* Identify per-column typmods for the given VALUES RTE. Returns a
2068+
* palloc'd array.
2069+
*/
2070+
staticint32*
2071+
getValuesTypmods(RangeTblEntry*rte)
2072+
{
2073+
int32*coltypmods;
2074+
List*firstrow;
2075+
intncolumns,
2076+
nvalid,
2077+
i;
2078+
ListCell*lc;
2079+
2080+
Assert(rte->values_lists!=NIL);
2081+
firstrow= (List*)linitial(rte->values_lists);
2082+
ncolumns=list_length(firstrow);
2083+
coltypmods= (int32*)palloc(ncolumns*sizeof(int32));
2084+
nvalid=0;
2085+
2086+
/* Collect the typmods from the first VALUES row */
2087+
i=0;
2088+
foreach(lc,firstrow)
2089+
{
2090+
Node*col= (Node*)lfirst(lc);
2091+
2092+
coltypmods[i]=exprTypmod(col);
2093+
if (coltypmods[i] >=0)
2094+
nvalid++;
2095+
i++;
2096+
}
2097+
2098+
/*
2099+
* Scan remaining rows; as soon as we have a non-matching typmod for a
2100+
* column, reset that typmod to -1. We can bail out early if all typmods
2101+
* become -1.
2102+
*/
2103+
if (nvalid>0)
2104+
{
2105+
for_each_cell(lc,lnext(list_head(rte->values_lists)))
2106+
{
2107+
List*thisrow= (List*)lfirst(lc);
2108+
ListCell*lc2;
2109+
2110+
Assert(list_length(thisrow)==ncolumns);
2111+
i=0;
2112+
foreach(lc2,thisrow)
2113+
{
2114+
Node*col= (Node*)lfirst(lc2);
2115+
2116+
if (coltypmods[i] >=0&&coltypmods[i]!=exprTypmod(col))
2117+
{
2118+
coltypmods[i]=-1;
2119+
nvalid--;
2120+
}
2121+
i++;
2122+
}
2123+
2124+
if (nvalid <=0)
2125+
break;
2126+
}
2127+
}
2128+
2129+
returncoltypmods;
2130+
}
2131+
20462132
/*
20472133
* expandRelAttrs -
20482134
* Workhorse for "*" expansion: produce a list of targetentries
@@ -2256,18 +2342,25 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
22562342
break;
22572343
caseRTE_VALUES:
22582344
{
2259-
/* Values RTE --- get type info from first sublist */
2260-
/* collation is stored separately, though */
2345+
/*
2346+
* Values RTE --- we can get type info from first sublist, but
2347+
* typmod may require scanning all sublists, and collation is
2348+
* stored separately. Using getValuesTypmods() is overkill,
2349+
* but this path is taken so seldom for VALUES that it's not
2350+
* worth writing extra code.
2351+
*/
22612352
List*collist= (List*)linitial(rte->values_lists);
22622353
Node*col;
2354+
int32*coltypmods=getValuesTypmods(rte);
22632355

22642356
if (attnum<1||attnum>list_length(collist))
22652357
elog(ERROR,"values list %s does not have attribute %d",
22662358
rte->eref->aliasname,attnum);
22672359
col= (Node*)list_nth(collist,attnum-1);
22682360
*vartype=exprType(col);
2269-
*vartypmod=exprTypmod(col);
2361+
*vartypmod=coltypmods[attnum-1];
22702362
*varcollid=list_nth_oid(rte->values_collations,attnum-1);
2363+
pfree(coltypmods);
22712364
}
22722365
break;
22732366
caseRTE_JOIN:

‎src/test/regress/expected/create_view.out

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,43 @@ SELECT relname, relkind, reloptions FROM pg_class
288288
mysecview4 | v | {security_barrier=false}
289289
(4 rows)
290290

291+
-- This test checks that proper typmods are assigned in a multi-row VALUES
292+
CREATE VIEW tt1 AS
293+
SELECT * FROM (
294+
VALUES
295+
('abc'::varchar(3), '0123456789', 42, 'abcd'::varchar(4)),
296+
('0123456789', 'abc'::varchar(3), 42.12, 'abc'::varchar(4))
297+
) vv(a,b,c,d);
298+
\d+ tt1
299+
View "testviewschm2.tt1"
300+
Column | Type | Modifiers | Storage | Description
301+
--------+----------------------+-----------+----------+-------------
302+
a | character varying | | extended |
303+
b | character varying | | extended |
304+
c | numeric | | main |
305+
d | character varying(4) | | extended |
306+
View definition:
307+
SELECT vv.a,
308+
vv.b,
309+
vv.c,
310+
vv.d
311+
FROM ( VALUES ('abc'::character varying(3),'0123456789'::character varying,42,'abcd'::character varying(4)), ('0123456789'::character varying,'abc'::character varying(3),42.12,'abc'::character varying(4))) vv(a, b, c, d);
312+
313+
SELECT * FROM tt1;
314+
a | b | c | d
315+
------------+------------+-------+------
316+
abc | 0123456789 | 42 | abcd
317+
0123456789 | abc | 42.12 | abc
318+
(2 rows)
319+
320+
SELECT a::varchar(3) FROM tt1;
321+
a
322+
-----
323+
abc
324+
012
325+
(2 rows)
326+
327+
DROP VIEW tt1;
291328
-- Test view decompilation in the face of relation renaming conflicts
292329
CREATE TABLE tt1 (f1 int, f2 int, f3 text);
293330
CREATE TABLE tx1 (x1 int, x2 int, x3 text);

‎src/test/regress/sql/create_view.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,19 @@ SELECT relname, relkind, reloptions FROM pg_class
224224
'mysecview3'::regclass,'mysecview4'::regclass)
225225
ORDER BY relname;
226226

227+
-- This test checks that proper typmods are assigned in a multi-row VALUES
228+
229+
CREATEVIEWtt1AS
230+
SELECT*FROM (
231+
VALUES
232+
('abc'::varchar(3),'0123456789',42,'abcd'::varchar(4)),
233+
('0123456789','abc'::varchar(3),42.12,'abc'::varchar(4))
234+
) vv(a,b,c,d);
235+
\d+ tt1
236+
SELECT*FROM tt1;
237+
SELECT a::varchar(3)FROM tt1;
238+
DROPVIEW tt1;
239+
227240
-- Test view decompilation in the face of relation renaming conflicts
228241

229242
CREATETABLEtt1 (f1int, f2int, f3text);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp