@@ -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 */
450453void
451454CheckAttributeNamesTypes (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 */
529541void
530542CheckAttributeType (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
0 commit comments