Fix ALTER TABLE ADD COLUMN to disallow the same column types that are
authorTom Lane <[email protected]>
Mon, 16 Dec 2002 18:39:57 +0000 (18:39 +0000)
committerTom Lane <[email protected]>
Mon, 16 Dec 2002 18:39:57 +0000 (18:39 +0000)
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
src/backend/commands/tablecmds.c
src/backend/parser/parse_clause.c
src/backend/utils/cache/relcache.c
src/include/catalog/heap.h

index b476a1181eae80260a05c71589e46651df2b7c8e..19ab896ac4ebe4c124fa85a4c6806c9d7a7f4dde 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.232 2002/10/21 22:06:18 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.232.2.1 2002/12/16 18:39:56 tgl Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -306,8 +306,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
@@ -333,20 +333,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
     *
@@ -379,8 +384,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)
     *
@@ -389,28 +415,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);
-
-       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);
+       Oid     typrelid = get_typ_typrelid(atttypid);
 
-           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));
    }
 }
 
@@ -687,11 +705,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);
index 62d61b315c65a32e4af79e7f76e0c2d23b759b16..46d9b7093988eaf6f3923167a3ed6c3fc5e4fce7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.51 2002/11/02 22:02:08 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.51.2.1 2002/12/16 18:39:56 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -104,7 +104,6 @@ DefineRelation(CreateStmt *stmt, char relkind)
    char        relname[NAMEDATALEN];
    Oid         namespaceId;
    List       *schema = stmt->tableElts;
-   int         numberOfAttributes;
    Oid         relationId;
    Relation    rel;
    TupleDesc   descriptor;
@@ -147,10 +146,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)
@@ -1784,6 +1779,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,
index 245c0ba422bab57987c85830876c8158c9947898..c88ce186e4171c57a05265f76c750c03740ab3f0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.98 2002/09/18 21:35:22 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.98.2.1 2002/12/16 18:39:56 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);
+   }
+
    /*
     * Insist we have a bare function call (explain.c is the only place
     * that depends on this, I think).  If this fails, it's probably
index 29fbd5ec067d0f9bd21a84b100173f8e16df30d5..2fdbfba5e927cd6e2ae68805c3bb6257cedbe664 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.177 2002/10/14 16:51:30 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.177.2.1 2002/12/16 18:39:56 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
@@ -2041,7 +2042,7 @@ RelationBuildLocalRelation(const char *relname,
    int         natts = tupDesc->natts;
    int         i;
 
-   AssertArg(natts > 0);
+   AssertArg(natts >= 0);
 
    /*
     * switch to the cache context to create the relcache entry.
index 7ff705b1dd5b226cde396995ff15bc92613d379b..7688c76574b4c38dc84af3e5845992405d8f4c78 100644 (file)
@@ -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.57 2002/09/04 20:31:37 momjian Exp $
+ * $Id: heap.h,v 1.57.2.1 2002/12/16 18:39:57 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,4 +73,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 */