mirror of
https://github.com/postgres/postgres.git
synced 2025-07-05 07:21:24 +03:00
Ensure that RowExprs and whole-row Vars produce the expected column names.
At one time it wasn't terribly important what column names were associated with the fields of a composite Datum, but since the introduction of operations like row_to_json(), it's important that looking up the rowtype ID embedded in the Datum returns the column names that users would expect. That did not work terribly well before this patch: you could get the column names of the underlying table, or column aliases from any level of the query, depending on minor details of the plan tree. You could even get totally empty field names, which is disastrous for cases like row_to_json(). To fix this for whole-row Vars, look to the RTE referenced by the Var, and make sure its column aliases are applied to the rowtype associated with the result Datums. This is a tad scary because we might have to return a transient RECORD type even though the Var is declared as having some named rowtype. In principle it should be all right because the record type will still be physically compatible with the named rowtype; but I had to weaken one Assert in ExecEvalConvertRowtype, and there might be third-party code containing similar assumptions. Similarly, RowExprs have to be willing to override the column names coming from a named composite result type and produce a RECORD when the column aliases visible at the site of the RowExpr differ from the underlying table's column names. In passing, revert the decision made in commit398f70ec07
to add an alias-list argument to ExecTypeFromExprList: better to provide that functionality in a separate function. This also reverts most of the code changes ind685814835
, which we don't need because we're no longer depending on the tupdesc found in the child plan node's result slot to be blessed. Back-patch to 9.4, but not earlier, since this solution changes the results in some cases that users might not have realized were buggy. We'll apply a more restricted form of this patch in older branches.
This commit is contained in:
@ -474,3 +474,163 @@ select (row('Jim', 'Beam')).text; -- error
|
||||
ERROR: could not identify column "text" in record data type
|
||||
LINE 1: select (row('Jim', 'Beam')).text;
|
||||
^
|
||||
--
|
||||
-- Test that composite values are seen to have the correct column names
|
||||
-- (bug #11210 and other reports)
|
||||
--
|
||||
select row_to_json(i) from int8_tbl i;
|
||||
row_to_json
|
||||
------------------------------------------------
|
||||
{"q1":123,"q2":456}
|
||||
{"q1":123,"q2":4567890123456789}
|
||||
{"q1":4567890123456789,"q2":123}
|
||||
{"q1":4567890123456789,"q2":4567890123456789}
|
||||
{"q1":4567890123456789,"q2":-4567890123456789}
|
||||
(5 rows)
|
||||
|
||||
select row_to_json(i) from int8_tbl i(x,y);
|
||||
row_to_json
|
||||
----------------------------------------------
|
||||
{"x":123,"y":456}
|
||||
{"x":123,"y":4567890123456789}
|
||||
{"x":4567890123456789,"y":123}
|
||||
{"x":4567890123456789,"y":4567890123456789}
|
||||
{"x":4567890123456789,"y":-4567890123456789}
|
||||
(5 rows)
|
||||
|
||||
create temp view vv1 as select * from int8_tbl;
|
||||
select row_to_json(i) from vv1 i;
|
||||
row_to_json
|
||||
------------------------------------------------
|
||||
{"q1":123,"q2":456}
|
||||
{"q1":123,"q2":4567890123456789}
|
||||
{"q1":4567890123456789,"q2":123}
|
||||
{"q1":4567890123456789,"q2":4567890123456789}
|
||||
{"q1":4567890123456789,"q2":-4567890123456789}
|
||||
(5 rows)
|
||||
|
||||
select row_to_json(i) from vv1 i(x,y);
|
||||
row_to_json
|
||||
----------------------------------------------
|
||||
{"x":123,"y":456}
|
||||
{"x":123,"y":4567890123456789}
|
||||
{"x":4567890123456789,"y":123}
|
||||
{"x":4567890123456789,"y":4567890123456789}
|
||||
{"x":4567890123456789,"y":-4567890123456789}
|
||||
(5 rows)
|
||||
|
||||
select row_to_json(ss) from
|
||||
(select q1, q2 from int8_tbl) as ss;
|
||||
row_to_json
|
||||
------------------------------------------------
|
||||
{"q1":123,"q2":456}
|
||||
{"q1":123,"q2":4567890123456789}
|
||||
{"q1":4567890123456789,"q2":123}
|
||||
{"q1":4567890123456789,"q2":4567890123456789}
|
||||
{"q1":4567890123456789,"q2":-4567890123456789}
|
||||
(5 rows)
|
||||
|
||||
select row_to_json(ss) from
|
||||
(select q1, q2 from int8_tbl offset 0) as ss;
|
||||
row_to_json
|
||||
------------------------------------------------
|
||||
{"q1":123,"q2":456}
|
||||
{"q1":123,"q2":4567890123456789}
|
||||
{"q1":4567890123456789,"q2":123}
|
||||
{"q1":4567890123456789,"q2":4567890123456789}
|
||||
{"q1":4567890123456789,"q2":-4567890123456789}
|
||||
(5 rows)
|
||||
|
||||
select row_to_json(ss) from
|
||||
(select q1 as a, q2 as b from int8_tbl) as ss;
|
||||
row_to_json
|
||||
----------------------------------------------
|
||||
{"a":123,"b":456}
|
||||
{"a":123,"b":4567890123456789}
|
||||
{"a":4567890123456789,"b":123}
|
||||
{"a":4567890123456789,"b":4567890123456789}
|
||||
{"a":4567890123456789,"b":-4567890123456789}
|
||||
(5 rows)
|
||||
|
||||
select row_to_json(ss) from
|
||||
(select q1 as a, q2 as b from int8_tbl offset 0) as ss;
|
||||
row_to_json
|
||||
----------------------------------------------
|
||||
{"a":123,"b":456}
|
||||
{"a":123,"b":4567890123456789}
|
||||
{"a":4567890123456789,"b":123}
|
||||
{"a":4567890123456789,"b":4567890123456789}
|
||||
{"a":4567890123456789,"b":-4567890123456789}
|
||||
(5 rows)
|
||||
|
||||
select row_to_json(ss) from
|
||||
(select q1 as a, q2 as b from int8_tbl) as ss(x,y);
|
||||
row_to_json
|
||||
----------------------------------------------
|
||||
{"x":123,"y":456}
|
||||
{"x":123,"y":4567890123456789}
|
||||
{"x":4567890123456789,"y":123}
|
||||
{"x":4567890123456789,"y":4567890123456789}
|
||||
{"x":4567890123456789,"y":-4567890123456789}
|
||||
(5 rows)
|
||||
|
||||
select row_to_json(ss) from
|
||||
(select q1 as a, q2 as b from int8_tbl offset 0) as ss(x,y);
|
||||
row_to_json
|
||||
----------------------------------------------
|
||||
{"x":123,"y":456}
|
||||
{"x":123,"y":4567890123456789}
|
||||
{"x":4567890123456789,"y":123}
|
||||
{"x":4567890123456789,"y":4567890123456789}
|
||||
{"x":4567890123456789,"y":-4567890123456789}
|
||||
(5 rows)
|
||||
|
||||
explain (costs off)
|
||||
select row_to_json(q) from
|
||||
(select thousand, tenthous from tenk1
|
||||
where thousand = 42 and tenthous < 2000 offset 0) q;
|
||||
QUERY PLAN
|
||||
-------------------------------------------------------------
|
||||
Subquery Scan on q
|
||||
-> Index Only Scan using tenk1_thous_tenthous on tenk1
|
||||
Index Cond: ((thousand = 42) AND (tenthous < 2000))
|
||||
(3 rows)
|
||||
|
||||
select row_to_json(q) from
|
||||
(select thousand, tenthous from tenk1
|
||||
where thousand = 42 and tenthous < 2000 offset 0) q;
|
||||
row_to_json
|
||||
---------------------------------
|
||||
{"thousand":42,"tenthous":42}
|
||||
{"thousand":42,"tenthous":1042}
|
||||
(2 rows)
|
||||
|
||||
select row_to_json(q) from
|
||||
(select thousand as x, tenthous as y from tenk1
|
||||
where thousand = 42 and tenthous < 2000 offset 0) q;
|
||||
row_to_json
|
||||
-------------------
|
||||
{"x":42,"y":42}
|
||||
{"x":42,"y":1042}
|
||||
(2 rows)
|
||||
|
||||
select row_to_json(q) from
|
||||
(select thousand as x, tenthous as y from tenk1
|
||||
where thousand = 42 and tenthous < 2000 offset 0) q(a,b);
|
||||
row_to_json
|
||||
-------------------
|
||||
{"a":42,"b":42}
|
||||
{"a":42,"b":1042}
|
||||
(2 rows)
|
||||
|
||||
create temp table tt1 as select * from int8_tbl limit 2;
|
||||
create temp table tt2 () inherits(tt1);
|
||||
insert into tt2 values(0,0);
|
||||
select row_to_json(r) from (select q2,q1 from tt1 offset 0) r;
|
||||
row_to_json
|
||||
----------------------------------
|
||||
{"q2":456,"q1":123}
|
||||
{"q2":4567890123456789,"q1":123}
|
||||
{"q2":0,"q1":0}
|
||||
(3 rows)
|
||||
|
||||
|
@ -227,3 +227,47 @@ select cast (row('Jim', 'Beam') as text);
|
||||
select (row('Jim', 'Beam'))::text;
|
||||
select text(row('Jim', 'Beam')); -- error
|
||||
select (row('Jim', 'Beam')).text; -- error
|
||||
|
||||
--
|
||||
-- Test that composite values are seen to have the correct column names
|
||||
-- (bug #11210 and other reports)
|
||||
--
|
||||
|
||||
select row_to_json(i) from int8_tbl i;
|
||||
select row_to_json(i) from int8_tbl i(x,y);
|
||||
|
||||
create temp view vv1 as select * from int8_tbl;
|
||||
select row_to_json(i) from vv1 i;
|
||||
select row_to_json(i) from vv1 i(x,y);
|
||||
|
||||
select row_to_json(ss) from
|
||||
(select q1, q2 from int8_tbl) as ss;
|
||||
select row_to_json(ss) from
|
||||
(select q1, q2 from int8_tbl offset 0) as ss;
|
||||
select row_to_json(ss) from
|
||||
(select q1 as a, q2 as b from int8_tbl) as ss;
|
||||
select row_to_json(ss) from
|
||||
(select q1 as a, q2 as b from int8_tbl offset 0) as ss;
|
||||
select row_to_json(ss) from
|
||||
(select q1 as a, q2 as b from int8_tbl) as ss(x,y);
|
||||
select row_to_json(ss) from
|
||||
(select q1 as a, q2 as b from int8_tbl offset 0) as ss(x,y);
|
||||
|
||||
explain (costs off)
|
||||
select row_to_json(q) from
|
||||
(select thousand, tenthous from tenk1
|
||||
where thousand = 42 and tenthous < 2000 offset 0) q;
|
||||
select row_to_json(q) from
|
||||
(select thousand, tenthous from tenk1
|
||||
where thousand = 42 and tenthous < 2000 offset 0) q;
|
||||
select row_to_json(q) from
|
||||
(select thousand as x, tenthous as y from tenk1
|
||||
where thousand = 42 and tenthous < 2000 offset 0) q;
|
||||
select row_to_json(q) from
|
||||
(select thousand as x, tenthous as y from tenk1
|
||||
where thousand = 42 and tenthous < 2000 offset 0) q(a,b);
|
||||
|
||||
create temp table tt1 as select * from int8_tbl limit 2;
|
||||
create temp table tt2 () inherits(tt1);
|
||||
insert into tt2 values(0,0);
|
||||
select row_to_json(r) from (select q2,q1 from tt1 offset 0) r;
|
||||
|
Reference in New Issue
Block a user