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

Commit 5f5c014

Browse files
committed
Allow RECORD and RECORD[] to be specified in function coldeflists.
We can't allow these pseudo-types to be used as table column types, because storing an anonymous record value in a table would result in data that couldn't be understood by other sessions. However, it seems like there's no harm in allowing the case in a column definition list that's specifying what a function-returning-record returns. The data involved is all local to the current session, so we should be just as able to resolve its actual tuple type as we are for the function-returning-record's top-level tuple output. Elvis Pranskevichus, with cosmetic changes by me Discussion: https://postgr.es/m/11038447.kQ5A9Uj5xi@hammer.magicstack.net
1 parent 689d15e commit 5f5c014

File tree

7 files changed

+70
-19
lines changed

7 files changed

+70
-19
lines changed

src/backend/catalog/heap.c

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -445,11 +445,14 @@ heap_create(const char *relname,
445445
* this is used to make certain the tuple descriptor contains a
446446
* valid set of attribute names and datatypes. a problem simply
447447
* generates ereport(ERROR) which aborts the current transaction.
448+
*
449+
* relkind is the relkind of the relation to be created.
450+
* flags controls which datatypes are allowed, cf CheckAttributeType.
448451
* --------------------------------
449452
*/
450453
void
451454
CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
452-
bool allow_system_table_mods)
455+
int flags)
453456
{
454457
int i;
455458
int j;
@@ -507,7 +510,7 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
507510
TupleDescAttr(tupdesc, i)->atttypid,
508511
TupleDescAttr(tupdesc, i)->attcollation,
509512
NIL, /* assume we're creating a new rowtype */
510-
allow_system_table_mods);
513+
flags);
511514
}
512515
}
513516

@@ -524,26 +527,41 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
524527
* containing_rowtypes. When checking a to-be-created rowtype, it's
525528
* sufficient to pass NIL, because there could not be any recursive reference
526529
* to a not-yet-existing rowtype.
530+
*
531+
* flags is a bitmask controlling which datatypes we allow. For the most
532+
* part, pseudo-types are disallowed as attribute types, but there are some
533+
* exceptions: ANYARRAYOID, RECORDOID, and RECORDARRAYOID can be allowed
534+
* in some cases. (This works because values of those type classes are
535+
* self-identifying to some extent. However, RECORDOID and RECORDARRAYOID
536+
* are reliably identifiable only within a session, since the identity info
537+
* may use a typmod that is only locally assigned. The caller is expected
538+
* to know whether these cases are safe.)
527539
* --------------------------------
528540
*/
529541
void
530542
CheckAttributeType(const char *attname,
531543
Oid atttypid, Oid attcollation,
532544
List *containing_rowtypes,
533-
bool allow_system_table_mods)
545+
int flags)
534546
{
535547
char att_typtype = get_typtype(atttypid);
536548
Oid att_typelem;
537549

538550
if (att_typtype == TYPTYPE_PSEUDO)
539551
{
540552
/*
541-
* Refuse any attempt to create a pseudo-type column, except for a
542-
* special hack for pg_statistic: allow ANYARRAY when modifying system
543-
* catalogs (this allows creating pg_statistic and cloning it during
544-
* VACUUM FULL)
553+
* We disallow pseudo-type columns, with the exception of ANYARRAY,
554+
* RECORD, and RECORD[] when the caller says that those are OK.
555+
*
556+
* We don't need to worry about recursive containment for RECORD and
557+
* RECORD[] because (a) no named composite type should be allowed to
558+
* contain those, and (b) two "anonymous" record types couldn't be
559+
* considered to be the same type, so infinite recursion isn't
560+
* possible.
545561
*/
546-
if (atttypid != ANYARRAYOID || !allow_system_table_mods)
562+
if (!((atttypid == ANYARRAYOID && (flags & CHKATYPE_ANYARRAY)) ||
563+
(atttypid == RECORDOID && (flags & CHKATYPE_ANYRECORD)) ||
564+
(atttypid == RECORDARRAYOID && (flags & CHKATYPE_ANYRECORD))))
547565
ereport(ERROR,
548566
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
549567
errmsg("column \"%s\" has pseudo-type %s",
@@ -556,7 +574,7 @@ CheckAttributeType(const char *attname,
556574
*/
557575
CheckAttributeType(attname, getBaseType(atttypid), attcollation,
558576
containing_rowtypes,
559-
allow_system_table_mods);
577+
flags);
560578
}
561579
else if (att_typtype == TYPTYPE_COMPOSITE)
562580
{
@@ -594,7 +612,7 @@ CheckAttributeType(const char *attname,
594612
CheckAttributeType(NameStr(attr->attname),
595613
attr->atttypid, attr->attcollation,
596614
containing_rowtypes,
597-
allow_system_table_mods);
615+
flags);
598616
}
599617

600618
relation_close(relation, AccessShareLock);
@@ -608,7 +626,7 @@ CheckAttributeType(const char *attname,
608626
*/
609627
CheckAttributeType(attname, att_typelem, attcollation,
610628
containing_rowtypes,
611-
allow_system_table_mods);
629+
flags);
612630
}
613631

614632
/*
@@ -1074,7 +1092,13 @@ heap_create_with_catalog(const char *relname,
10741092
*/
10751093
Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode());
10761094

1077-
CheckAttributeNamesTypes(tupdesc, relkind, allow_system_table_mods);
1095+
/*
1096+
* Validate proposed tupdesc for the desired relkind. If
1097+
* allow_system_table_mods is on, allow ANYARRAY to be used; this is a
1098+
* hack to allow creating pg_statistic and cloning it during VACUUM FULL.
1099+
*/
1100+
CheckAttributeNamesTypes(tupdesc, relkind,
1101+
allow_system_table_mods ? CHKATYPE_ANYARRAY : 0);
10781102

10791103
/*
10801104
* This would fail later on anyway, if the relation already exists. But

src/backend/catalog/index.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ ConstructTupleDescriptor(Relation heapRelation,
410410
*/
411411
CheckAttributeType(NameStr(to->attname),
412412
to->atttypid, to->attcollation,
413-
NIL, false);
413+
NIL, 0);
414414
}
415415

416416
/*

src/backend/commands/tablecmds.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5505,7 +5505,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
55055505
/* make sure datatype is legal for a column */
55065506
CheckAttributeType(colDef->colname, typeOid, collOid,
55075507
list_make1_oid(rel->rd_rel->reltype),
5508-
false);
5508+
0);
55095509

55105510
/* construct new attribute's pg_attribute entry */
55115511
attribute.attrelid = myrelid;
@@ -9445,7 +9445,7 @@ ATPrepAlterColumnType(List **wqueue,
94459445
/* make sure datatype is legal for a column */
94469446
CheckAttributeType(colName, targettype, targetcollid,
94479447
list_make1_oid(rel->rd_rel->reltype),
9448-
false);
9448+
0);
94499449

94509450
if (tab->relkind == RELKIND_RELATION ||
94519451
tab->relkind == RELKIND_PARTITIONED_TABLE)

src/backend/parser/parse_relation.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,9 +1590,15 @@ addRangeTableEntryForFunction(ParseState *pstate,
15901590

15911591
/*
15921592
* Ensure that the coldeflist defines a legal set of names (no
1593-
* duplicates) and datatypes (no pseudo-types, for instance).
1593+
* duplicates, but we needn't worry about system column names) and
1594+
* datatypes. Although we mostly can't allow pseudo-types, it
1595+
* seems safe to allow RECORD and RECORD[], since values within
1596+
* those type classes are self-identifying at runtime, and the
1597+
* coldeflist doesn't represent anything that will be visible to
1598+
* other sessions.
15941599
*/
1595-
CheckAttributeNamesTypes(tupdesc, RELKIND_COMPOSITE_TYPE, false);
1600+
CheckAttributeNamesTypes(tupdesc, RELKIND_COMPOSITE_TYPE,
1601+
CHKATYPE_ANYRECORD);
15961602
}
15971603
else
15981604
ereport(ERROR,

src/include/catalog/heap.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
#include "parser/parse_node.h"
2020

2121

22+
/* flag bits for CheckAttributeType/CheckAttributeNamesTypes */
23+
#define CHKATYPE_ANYARRAY 0x01 /* allow ANYARRAY */
24+
#define CHKATYPE_ANYRECORD 0x02 /* allow RECORD and RECORD[] */
25+
2226
typedef struct RawColumnDefault
2327
{
2428
AttrNumber attnum; /* attribute to attach default to */
@@ -130,12 +134,12 @@ extern const FormData_pg_attribute *SystemAttributeDefinition(AttrNumber attno);
130134
extern const FormData_pg_attribute *SystemAttributeByName(const char *attname);
131135

132136
extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
133-
bool allow_system_table_mods);
137+
int flags);
134138

135139
extern void CheckAttributeType(const char *attname,
136140
Oid atttypid, Oid attcollation,
137141
List *containing_rowtypes,
138-
bool allow_system_table_mods);
142+
int flags);
139143

140144
/* pg_partitioned_table catalog manipulation functions */
141145
extern void StorePartitionKey(Relation rel,

src/test/regress/expected/rowtypes.out

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,17 @@ select row(1, '(1,2)')::testtype6 *<> row(1, '(1,3)')::testtype6;
667667
t
668668
(1 row)
669669

670+
-- anonymous rowtypes in coldeflists
671+
select q.a, q.b = row(2), q.c = array[row(3)], q.d = row(row(4)) from
672+
unnest(array[row(1, row(2), array[row(3)], row(row(4))),
673+
row(2, row(3), array[row(4)], row(row(5)))])
674+
as q(a int, b record, c record[], d record);
675+
a | ?column? | ?column? | ?column?
676+
---+----------+----------+----------
677+
1 | t | t | t
678+
2 | f | f | f
679+
(2 rows)
680+
670681
drop type testtype1, testtype2, testtype3, testtype4, testtype5, testtype6;
671682
--
672683
-- Test case derived from bug #5716: check multiple uses of a rowtype result

src/test/regress/sql/rowtypes.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,12 @@ select row(1, '(1,2)')::testtype6 *< row(1, '(1,3)')::testtype6;
259259
select row(1, '(1,2)')::testtype6 *>= row(1, '(1,3)')::testtype6;
260260
select row(1, '(1,2)')::testtype6 *<> row(1, '(1,3)')::testtype6;
261261

262+
-- anonymous rowtypes in coldeflists
263+
select q.a, q.b = row(2), q.c = array[row(3)], q.d = row(row(4)) from
264+
unnest(array[row(1, row(2), array[row(3)], row(row(4))),
265+
row(2, row(3), array[row(4)], row(row(5)))])
266+
as q(a int, b record, c record[], d record);
267+
262268
drop type testtype1, testtype2, testtype3, testtype4, testtype5, testtype6;
263269

264270

0 commit comments

Comments
 (0)