@ -431,6 +431,7 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
CheckAttributeType ( NameStr ( tupdesc - > attrs [ i ] - > attname ) ,
CheckAttributeType ( NameStr ( tupdesc - > attrs [ i ] - > attname ) ,
tupdesc - > attrs [ i ] - > atttypid ,
tupdesc - > attrs [ i ] - > atttypid ,
tupdesc - > attrs [ i ] - > attcollation ,
tupdesc - > attrs [ i ] - > attcollation ,
NIL , /* assume we're creating a new rowtype */
allow_system_table_mods ) ;
allow_system_table_mods ) ;
}
}
}
}
@ -439,15 +440,25 @@ CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind,
* CheckAttributeType
* CheckAttributeType
*
*
* Verify that the proposed datatype of an attribute is legal .
* Verify that the proposed datatype of an attribute is legal .
* This is needed because there are types ( and pseudo - types )
* This is needed mainly because there are types ( and pseudo - types )
* in the catalogs that we do not support as elements of real tuples .
* in the catalogs that we do not support as elements of real tuples .
* We also check some other properties required of a table column .
*
* If the attribute is being proposed for addition to an existing table or
* composite type , pass a one - element list of the rowtype OID as
* containing_rowtypes . When checking a to - be - created rowtype , it ' s
* sufficient to pass NIL , because there could not be any recursive reference
* to a not - yet - existing rowtype .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
*/
void
void
CheckAttributeType ( const char * attname , Oid atttypid , Oid attcollation ,
CheckAttributeType ( const char * attname ,
Oid atttypid , Oid attcollation ,
List * containing_rowtypes ,
bool allow_system_table_mods )
bool allow_system_table_mods )
{
{
char att_typtype = get_typtype ( atttypid ) ;
char att_typtype = get_typtype ( atttypid ) ;
Oid att_typelem ;
if ( atttypid = = UNKNOWNOID )
if ( atttypid = = UNKNOWNOID )
{
{
@ -485,6 +496,20 @@ CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation,
TupleDesc tupdesc ;
TupleDesc tupdesc ;
int i ;
int i ;
/*
* Check for self - containment . Eventually we might be able to allow
* this ( just return without complaint , if so ) but it ' s not clear how
* many other places would require anti - recursion defenses before it
* would be safe to allow tables to contain their own rowtype .
*/
if ( list_member_oid ( containing_rowtypes , atttypid ) )
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_TABLE_DEFINITION ) ,
errmsg ( " composite type %s cannot be made a member of itself " ,
format_type_be ( atttypid ) ) ) ) ;
containing_rowtypes = lcons_oid ( atttypid , containing_rowtypes ) ;
relation = relation_open ( get_typ_typrelid ( atttypid ) , AccessShareLock ) ;
relation = relation_open ( get_typ_typrelid ( atttypid ) , AccessShareLock ) ;
tupdesc = RelationGetDescr ( relation ) ;
tupdesc = RelationGetDescr ( relation ) ;
@ -495,19 +520,31 @@ CheckAttributeType(const char *attname, Oid atttypid, Oid attcollation,
if ( attr - > attisdropped )
if ( attr - > attisdropped )
continue ;
continue ;
CheckAttributeType ( NameStr ( attr - > attname ) , attr - > atttypid , attr - > attcollation ,
CheckAttributeType ( NameStr ( attr - > attname ) ,
attr - > atttypid , attr - > attcollation ,
containing_rowtypes ,
allow_system_table_mods ) ;
allow_system_table_mods ) ;
}
}
relation_close ( relation , AccessShareLock ) ;
relation_close ( relation , AccessShareLock ) ;
containing_rowtypes = list_delete_first ( containing_rowtypes ) ;
}
else if ( OidIsValid ( ( att_typelem = get_element_type ( atttypid ) ) ) )
{
/*
* Must recurse into array types , too , in case they are composite .
*/
CheckAttributeType ( attname , att_typelem , attcollation ,
containing_rowtypes ,
allow_system_table_mods ) ;
}
}
/*
/*
* This might not be strictly invalid per SQL standard , but it is
* This might not be strictly invalid per SQL standard , but it is
* pretty useless , and it cannot be dumped , so we must disallow
* pretty useless , and it cannot be dumped , so we must disallow it .
* it .
*/
*/
if ( type_is_collatable ( atttypid ) & & ! OidIsValid ( attcollation ) )
if ( ! OidIsValid ( attcollation ) & & type_is_collatable ( atttypid ) )
ereport ( ERROR ,
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_TABLE_DEFINITION ) ,
( errcode ( ERRCODE_INVALID_TABLE_DEFINITION ) ,
errmsg ( " no collation was derived for column \" %s \" with collatable type %s " ,
errmsg ( " no collation was derived for column \" %s \" with collatable type %s " ,