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

Commit 8b7a0f1

Browse files
committed
Allow extracting fields from a ROW() expression in more cases.
Teach get_expr_result_type() to manufacture a tuple descriptor directly from a RowExpr node. If the RowExpr has type RECORD, this is the only way to get a tupdesc for its result, since even if the rowtype has been blessed, we don't have its typmod available at this point. (If the RowExpr has some named composite type, we continue to let the existing code handle it, since the RowExpr might well not have the correct column names embedded in it.) This fixes assorted corner cases illustrated by the added regression tests. Discussion: https://postgr.es/m/10872.1572202006@sss.pgh.pa.us
1 parent f885449 commit 8b7a0f1

File tree

3 files changed

+80
-0
lines changed

3 files changed

+80
-0
lines changed

src/backend/utils/fmgr/funcapi.c

+32
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,38 @@ get_expr_result_type(Node *expr,
227227
NULL,
228228
resultTypeId,
229229
resultTupleDesc);
230+
else if (expr && IsA(expr, RowExpr) &&
231+
((RowExpr *) expr)->row_typeid == RECORDOID)
232+
{
233+
/* We can resolve the record type by generating the tupdesc directly */
234+
RowExpr *rexpr = (RowExpr *) expr;
235+
TupleDesc tupdesc;
236+
AttrNumber i = 1;
237+
ListCell *lcc,
238+
*lcn;
239+
240+
tupdesc = CreateTemplateTupleDesc(list_length(rexpr->args));
241+
Assert(list_length(rexpr->args) == list_length(rexpr->colnames));
242+
forboth(lcc, rexpr->args, lcn, rexpr->colnames)
243+
{
244+
Node *col = (Node *) lfirst(lcc);
245+
char *colname = strVal(lfirst(lcn));
246+
247+
TupleDescInitEntry(tupdesc, i,
248+
colname,
249+
exprType(col),
250+
exprTypmod(col),
251+
0);
252+
TupleDescInitEntryCollation(tupdesc, i,
253+
exprCollation(col));
254+
i++;
255+
}
256+
if (resultTypeId)
257+
*resultTypeId = rexpr->row_typeid;
258+
if (resultTupleDesc)
259+
*resultTupleDesc = BlessTupleDesc(tupdesc);
260+
return TYPEFUNC_COMPOSITE;
261+
}
230262
else
231263
{
232264
/* handle as a generic expression; no chance to resolve RECORD */

src/test/regress/expected/rowtypes.out

+39
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,45 @@ where i8 in (row(123,456)::int8_tbl, '(4567890123456789,123)');
436436
4567890123456789 | 123
437437
(2 rows)
438438

439+
-- Check ability to select columns from an anonymous rowtype
440+
select (row(1, 2.0)).f1;
441+
f1
442+
----
443+
1
444+
(1 row)
445+
446+
select (row(1, 2.0)).f2;
447+
f2
448+
-----
449+
2.0
450+
(1 row)
451+
452+
select (row(1, 2.0)).nosuch; -- fail
453+
ERROR: could not identify column "nosuch" in record data type
454+
LINE 1: select (row(1, 2.0)).nosuch;
455+
^
456+
select (row(1, 2.0)).*;
457+
f1 | f2
458+
----+-----
459+
1 | 2.0
460+
(1 row)
461+
462+
select (r).f1 from (select row(1, 2.0) as r) ss;
463+
f1
464+
----
465+
1
466+
(1 row)
467+
468+
select (r).f3 from (select row(1, 2.0) as r) ss; -- fail
469+
ERROR: could not identify column "f3" in record data type
470+
LINE 1: select (r).f3 from (select row(1, 2.0) as r) ss;
471+
^
472+
select (r).* from (select row(1, 2.0) as r) ss;
473+
f1 | f2
474+
----+-----
475+
1 | 2.0
476+
(1 row)
477+
439478
-- Check some corner cases involving empty rowtypes
440479
select ROW();
441480
row

src/test/regress/sql/rowtypes.sql

+9
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,15 @@ where i8 in (row(123,456)::int8_tbl, '(4567890123456789,123)');
171171
select * from int8_tbl i8
172172
where i8 in (row(123,456)::int8_tbl, '(4567890123456789,123)');
173173

174+
-- Check ability to select columns from an anonymous rowtype
175+
select (row(1, 2.0)).f1;
176+
select (row(1, 2.0)).f2;
177+
select (row(1, 2.0)).nosuch; -- fail
178+
select (row(1, 2.0)).*;
179+
select (r).f1 from (select row(1, 2.0) as r) ss;
180+
select (r).f3 from (select row(1, 2.0) as r) ss; -- fail
181+
select (r).* from (select row(1, 2.0) as r) ss;
182+
174183
-- Check some corner cases involving empty rowtypes
175184
select ROW();
176185
select ROW() IS NULL;

0 commit comments

Comments
 (0)