From 260faf0b633716d02e30103bd5e94eb40f06bf27 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 16 Dec 2002 18:39:22 +0000 Subject: [PATCH] Fix ALTER TABLE ADD COLUMN to disallow the same column types that are disallowed by CREATE TABLE (eg, pseudo-types); also disallow these types from being introduced by the range-function syntax. While at it, allow CREATE TABLE to create zero-column tables, per recent pghackers discussion. I am back-patching this into 7.3 since failure to disallow pseudo-types is arguably a security hole. --- src/backend/catalog/heap.c | 83 ++++++++++++++++++------------ src/backend/commands/tablecmds.c | 10 ++-- src/backend/parser/parse_clause.c | 15 +++++- src/backend/utils/cache/relcache.c | 7 +-- src/include/catalog/heap.h | 6 ++- 5 files changed, 76 insertions(+), 45 deletions(-) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 424684d74d..3d671e92f3 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.237 2002/12/12 20:35:08 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.238 2002/12/16 18:39:22 tgl Exp $ * * * INTERFACE ROUTINES @@ -307,8 +307,8 @@ heap_storage_create(Relation rel) * * this is done in 6 steps: * - * 1) CheckAttributeNames() is used to make certain the tuple - * descriptor contains a valid set of attribute names + * 1) CheckAttributeNamesTypes() is used to make certain the tuple + * descriptor contains a valid set of attribute names and types * * 2) pg_class is opened and get_relname_relid() * performs a scan to ensure that no relation with the @@ -334,20 +334,25 @@ heap_storage_create(Relation rel) */ /* -------------------------------- - * CheckAttributeNames + * CheckAttributeNamesTypes * * this is used to make certain the tuple descriptor contains a - * valid set of attribute names. a problem simply generates - * elog(ERROR) which aborts the current transaction. + * valid set of attribute names and datatypes. a problem simply + * generates elog(ERROR) which aborts the current transaction. * -------------------------------- */ -static void -CheckAttributeNames(TupleDesc tupdesc, char relkind) +void +CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind) { int i; int j; int natts = tupdesc->natts; + /* Sanity check on column count */ + if (natts < 0 || natts > MaxHeapAttributeNumber) + elog(ERROR, "Number of columns is out of range (0 to %d)", + MaxHeapAttributeNumber); + /* * first check for collision with system attribute names * @@ -380,8 +385,29 @@ CheckAttributeNames(TupleDesc tupdesc, char relkind) } /* - * We also do some checking of the attribute types here. - * + * next check the attribute types + */ + for (i = 0; i < natts; i++) + { + CheckAttributeType(NameStr(tupdesc->attrs[i]->attname), + tupdesc->attrs[i]->atttypid); + } +} + +/* -------------------------------- + * CheckAttributeType + * + * Verify that the proposed datatype of an attribute is legal. + * This is needed because there are types (and pseudo-types) + * in the catalogs that we do not support as elements of real tuples. + * -------------------------------- + */ +void +CheckAttributeType(const char *attname, Oid atttypid) +{ + char att_typtype = get_typtype(atttypid); + + /* * Warn user, but don't fail, if column to be created has UNKNOWN type * (usually as a result of a 'retrieve into' - jolly) * @@ -390,28 +416,20 @@ CheckAttributeNames(TupleDesc tupdesc, char relkind) * all references to complex types, but for now there's still some * Berkeley-derived code that thinks it can do this...) */ - for (i = 0; i < natts; i++) + if (atttypid == UNKNOWNOID) + elog(WARNING, "Attribute \"%s\" has an unknown type" + "\n\tProceeding with relation creation anyway", + attname); + else if (att_typtype == 'p') + elog(ERROR, "Attribute \"%s\" has pseudo-type %s", + attname, format_type_be(atttypid)); + else if (att_typtype == 'c') { - Oid att_type = tupdesc->attrs[i]->atttypid; - char att_typtype = get_typtype(att_type); + Oid typrelid = get_typ_typrelid(atttypid); - if (att_type == UNKNOWNOID) - elog(WARNING, "Attribute \"%s\" has an unknown type" - "\n\tProceeding with relation creation anyway", - NameStr(tupdesc->attrs[i]->attname)); - if (att_typtype == 'p') - elog(ERROR, "Attribute \"%s\" has pseudo-type %s", - NameStr(tupdesc->attrs[i]->attname), - format_type_be(att_type)); - if (att_typtype == 'c') - { - Oid typrelid = get_typ_typrelid(att_type); - - if (get_rel_relkind(typrelid) == RELKIND_COMPOSITE_TYPE) - elog(ERROR, "Attribute \"%s\" has composite type %s", - NameStr(tupdesc->attrs[i]->attname), - format_type_be(att_type)); - } + if (get_rel_relkind(typrelid) == RELKIND_COMPOSITE_TYPE) + elog(ERROR, "Attribute \"%s\" has composite type %s", + attname, format_type_be(atttypid)); } } @@ -689,11 +707,8 @@ heap_create_with_catalog(const char *relname, * sanity checks */ Assert(IsNormalProcessingMode() || IsBootstrapProcessingMode()); - if (tupdesc->natts <= 0 || tupdesc->natts > MaxHeapAttributeNumber) - elog(ERROR, "Number of columns is out of range (1 to %d)", - MaxHeapAttributeNumber); - CheckAttributeNames(tupdesc, relkind); + CheckAttributeNamesTypes(tupdesc, relkind); if (get_relname_relid(relname, relnamespace)) elog(ERROR, "Relation '%s' already exists", relname); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 09c60bdf3f..2a1a2b4cf4 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.61 2002/12/15 16:17:42 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.62 2002/12/16 18:39:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -125,7 +125,6 @@ DefineRelation(CreateStmt *stmt, char relkind) char relname[NAMEDATALEN]; Oid namespaceId; List *schema = stmt->tableElts; - int numberOfAttributes; Oid relationId; Relation rel; TupleDesc descriptor; @@ -174,10 +173,6 @@ DefineRelation(CreateStmt *stmt, char relkind) stmt->relation->istemp, &inheritOids, &old_constraints, &parentHasOids); - numberOfAttributes = length(schema); - if (numberOfAttributes <= 0) - elog(ERROR, "DefineRelation: please inherit from a relation or define an attribute"); - /* * Create a relation descriptor from the relation schema and create * the relation. Note that in this stage only inherited (pre-cooked) @@ -1800,6 +1795,9 @@ AlterTableAddColumn(Oid myrelid, typeTuple = typenameType(colDef->typename); tform = (Form_pg_type) GETSTRUCT(typeTuple); + /* make sure datatype is legal for a column */ + CheckAttributeType(colDef->colname, HeapTupleGetOid(typeTuple)); + attributeTuple = heap_addheader(Natts_pg_attribute, false, ATTRIBUTE_TUPLE_SIZE, diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 71375f62c9..5d72921675 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.102 2002/12/12 20:35:13 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.103 2002/12/16 18:39:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,6 +16,7 @@ #include "postgres.h" #include "access/heapam.h" +#include "catalog/heap.h" #include "nodes/makefuncs.h" #include "optimizer/clauses.h" #include "optimizer/tlist.h" @@ -502,6 +503,18 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r) elog(ERROR, "cannot use aggregate function in FROM function expression"); } + /* + * If a coldeflist is supplied, ensure it defines a legal set of names + * (no duplicates) and datatypes (no pseudo-types, for instance). + */ + if (r->coldeflist) + { + TupleDesc tupdesc; + + tupdesc = BuildDescForRelation(r->coldeflist); + CheckAttributeNamesTypes(tupdesc, RELKIND_COMPOSITE_TYPE); + } + /* * OK, build an RTE for the function. */ diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 87992769e9..15f61ce59a 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.182 2002/12/15 21:01:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.183 2002/12/16 18:39:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -570,7 +570,8 @@ RelationBuildTupleDesc(RelationBuildDescInfo buildinfo, * cases for attnum=1 that used to exist in fastgetattr() and * index_getattr(). */ - relation->rd_att->attrs[0]->attcacheoff = 0; + if (relation->rd_rel->relnatts > 0) + relation->rd_att->attrs[0]->attcacheoff = 0; /* * Set up constraint/default info @@ -2049,7 +2050,7 @@ RelationBuildLocalRelation(const char *relname, int i; bool has_not_null; - AssertArg(natts > 0); + AssertArg(natts >= 0); /* * switch to the cache context to create the relcache entry. diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 677347c24f..1a69f0147f 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: heap.h,v 1.59 2002/11/11 22:19:23 tgl Exp $ + * $Id: heap.h,v 1.60 2002/12/16 18:39:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -74,4 +74,8 @@ extern Form_pg_attribute SystemAttributeDefinition(AttrNumber attno, extern Form_pg_attribute SystemAttributeByName(const char *attname, bool relhasoids); +extern void CheckAttributeNamesTypes(TupleDesc tupdesc, char relkind); + +extern void CheckAttributeType(const char *attname, Oid atttypid); + #endif /* HEAP_H */