]> granicus.if.org Git - postgresql/commitdiff
Make the world at least somewhat safe for zero-column tables, and
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 28 Sep 2002 20:00:19 +0000 (20:00 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 28 Sep 2002 20:00:19 +0000 (20:00 +0000)
remove the special case in ALTER DROP COLUMN to prohibit dropping a
table's last column.

src/backend/access/common/tupdesc.c
src/backend/commands/tablecmds.c
src/backend/executor/execTuples.c
src/backend/executor/nodeAgg.c
src/backend/parser/parse_target.c
src/test/regress/expected/alter_table.out

index 5a1b912b3796b5ca96343ea4061a712fe725705e..f1f92af4725398677d6d8a90586ef86a43e21114 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.90 2002/09/22 19:42:50 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.91 2002/09/28 20:00:18 tgl Exp $
  *
  * NOTES
  *       some of the executor utility code such as "ExecTypeFromTL" should be
 TupleDesc
 CreateTemplateTupleDesc(int natts, bool hasoid)
 {
-       uint32          size;
        TupleDesc       desc;
 
        /*
         * sanity checks
         */
-       AssertArg(natts >= 1);
+       AssertArg(natts >= 0);
 
        /*
         * allocate enough memory for the tuple descriptor and zero it as
         * TupleDescInitEntry assumes that the descriptor is filled with NULL
         * pointers.
         */
-       size = natts * sizeof(Form_pg_attribute);
        desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
-       desc->attrs = (Form_pg_attribute *) palloc(size);
-       desc->constr = NULL;
-       MemSet(desc->attrs, 0, size);
 
        desc->natts = natts;
        desc->tdhasoid = hasoid;
 
+       if (natts > 0)
+       {
+               uint32          size = natts * sizeof(Form_pg_attribute);
+
+               desc->attrs = (Form_pg_attribute *) palloc(size);
+               MemSet(desc->attrs, 0, size);
+       }
+       else
+               desc->attrs = NULL;
+       desc->constr = NULL;
+
        return desc;
 }
 
@@ -79,7 +85,7 @@ CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs)
        /*
         * sanity checks
         */
-       AssertArg(natts >= 1);
+       AssertArg(natts >= 0);
 
        desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
        desc->attrs = attrs;
@@ -108,17 +114,20 @@ CreateTupleDescCopy(TupleDesc tupdesc)
 
        desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
        desc->natts = tupdesc->natts;
-       size = desc->natts * sizeof(Form_pg_attribute);
-       desc->attrs = (Form_pg_attribute *) palloc(size);
-       for (i = 0; i < desc->natts; i++)
+       if (desc->natts > 0)
        {
-               desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
-               memcpy(desc->attrs[i],
-                          tupdesc->attrs[i],
-                          ATTRIBUTE_TUPLE_SIZE);
-               desc->attrs[i]->attnotnull = false;
-               desc->attrs[i]->atthasdef = false;
+               size = desc->natts * sizeof(Form_pg_attribute);
+               desc->attrs = (Form_pg_attribute *) palloc(size);
+               for (i = 0; i < desc->natts; i++)
+               {
+                       desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
+                       memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);
+                       desc->attrs[i]->attnotnull = false;
+                       desc->attrs[i]->atthasdef = false;
+               }
        }
+       else
+               desc->attrs = NULL;
        desc->constr = NULL;
        desc->tdhasoid = tupdesc->tdhasoid;
 
@@ -142,15 +151,18 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc)
 
        desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
        desc->natts = tupdesc->natts;
-       size = desc->natts * sizeof(Form_pg_attribute);
-       desc->attrs = (Form_pg_attribute *) palloc(size);
-       for (i = 0; i < desc->natts; i++)
+       if (desc->natts > 0)
        {
-               desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
-               memcpy(desc->attrs[i],
-                          tupdesc->attrs[i],
-                          ATTRIBUTE_TUPLE_SIZE);
+               size = desc->natts * sizeof(Form_pg_attribute);
+               desc->attrs = (Form_pg_attribute *) palloc(size);
+               for (i = 0; i < desc->natts; i++)
+               {
+                       desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
+                       memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);
+               }
        }
+       else
+               desc->attrs = NULL;
        if (constr)
        {
                TupleConstr *cpy = (TupleConstr *) palloc(sizeof(TupleConstr));
@@ -197,7 +209,8 @@ FreeTupleDesc(TupleDesc tupdesc)
 
        for (i = 0; i < tupdesc->natts; i++)
                pfree(tupdesc->attrs[i]);
-       pfree(tupdesc->attrs);
+       if (tupdesc->attrs)
+               pfree(tupdesc->attrs);
        if (tupdesc->constr)
        {
                if (tupdesc->constr->num_defval > 0)
@@ -228,7 +241,6 @@ FreeTupleDesc(TupleDesc tupdesc)
        }
 
        pfree(tupdesc);
-
 }
 
 /*
@@ -361,6 +373,7 @@ TupleDescInitEntry(TupleDesc desc,
         */
        AssertArg(PointerIsValid(desc));
        AssertArg(attributeNumber >= 1);
+       AssertArg(attributeNumber <= desc->natts);
 
        /*
         * attributeName's are sometimes NULL, from resdom's.  I don't know
index 0934a274c7ad3d76d8707ac48af1b0fea0a84111..14d82630c8adeed544e216fa829995a318d1d1ca 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.44 2002/09/23 20:43:40 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.45 2002/09/28 20:00:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2331,9 +2331,7 @@ AlterTableDropColumn(Oid myrelid, bool recurse, bool recursing,
 {
        Relation        rel;
        AttrNumber      attnum;
-       AttrNumber      n;
        TupleDesc       tupleDesc;
-       bool            success;
        ObjectAddress object;
 
        rel = heap_open(myrelid, AccessExclusiveLock);
@@ -2359,34 +2357,13 @@ AlterTableDropColumn(Oid myrelid, bool recurse, bool recursing,
                         RelationGetRelationName(rel), colName);
 
        /* Can't drop a system attribute */
+       /* XXX perhaps someday allow dropping OID? */
        if (attnum < 0)
                elog(ERROR, "ALTER TABLE: Cannot drop system attribute \"%s\"",
                         colName);
 
-       /*
-        * Make sure there will be at least one user column left in the
-        * relation after we drop this one.  Zero-length tuples tend to
-        * confuse us.
-        */
-       tupleDesc = RelationGetDescr(rel);
-
-       success = false;
-       for (n = 1; n <= tupleDesc->natts; n++)
-       {
-               Form_pg_attribute attribute = tupleDesc->attrs[n - 1];
-
-               if (!attribute->attisdropped && n != attnum)
-               {
-                       success = true;
-                       break;
-               }
-       }
-
-       if (!success)
-               elog(ERROR, "ALTER TABLE: Cannot drop last column from table \"%s\"",
-                        RelationGetRelationName(rel));
-
        /* Don't drop inherited columns */
+       tupleDesc = RelationGetDescr(rel);
        if (tupleDesc->attrs[attnum - 1]->attinhcount > 0 && !recursing)
                elog(ERROR, "ALTER TABLE: Cannot drop inherited column \"%s\"",
                         colName);
index 1a5f835be1dd3d8a0b3a231c6a6fca6d0f1c0493..7b0df664c7468ed6b9f32f5535baddf443d82231 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.59 2002/09/04 20:31:17 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.60 2002/09/28 20:00:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -560,23 +560,14 @@ ExecInitNullTupleSlot(EState *estate, TupleDesc tupType)
 TupleDesc
 ExecTypeFromTL(List *targetList, bool hasoid)
 {
-       List       *tlitem;
        TupleDesc       typeInfo;
-       Resdom     *resdom;
-       Oid                     restype;
+       List       *tlitem;
        int                     len;
 
-       /*
-        * examine targetlist - if empty then return NULL
-        */
-       len = ExecTargetListLength(targetList);
-
-       if (len == 0)
-               return NULL;
-
        /*
         * allocate a new typeInfo
         */
+       len = ExecTargetListLength(targetList);
        typeInfo = CreateTemplateTupleDesc(len, hasoid);
 
        /*
@@ -585,6 +576,8 @@ ExecTypeFromTL(List *targetList, bool hasoid)
        foreach(tlitem, targetList)
        {
                TargetEntry *tle = lfirst(tlitem);
+               Resdom     *resdom;
+               Oid                     restype;
 
                if (tle->resdom != NULL)
                {
index 898ca62a6005495b8c0e438e5f2332fa667762ab..0ebf2f7151e5050a4e49c164df14fa7e8151f3c6 100644 (file)
@@ -46,7 +46,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.87 2002/09/18 21:35:20 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.88 2002/09/28 20:00:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -658,20 +658,20 @@ ExecAgg(Agg *node)
                        if (inputTuple == NULL)
                        {
                                TupleDesc       tupType;
-                               Datum      *tupValue;
-                               char       *null_array;
-                               AttrNumber      attnum;
+                               Datum      *dvalues;
+                               char       *dnulls;
 
                                tupType = aggstate->csstate.css_ScanTupleSlot->ttc_tupleDescriptor;
-                               tupValue = projInfo->pi_tupValue;
                                /* watch out for null input tuples, though... */
-                               if (tupType && tupValue)
+                               if (tupType && tupType->natts > 0)
                                {
-                                       null_array = (char *) palloc(sizeof(char) * tupType->natts);
-                                       for (attnum = 0; attnum < tupType->natts; attnum++)
-                                               null_array[attnum] = 'n';
-                                       inputTuple = heap_formtuple(tupType, tupValue, null_array);
-                                       pfree(null_array);
+                                       dvalues = (Datum *) palloc(sizeof(Datum) * tupType->natts);
+                                       dnulls = (char *) palloc(sizeof(char) * tupType->natts);
+                                       MemSet(dvalues, 0, sizeof(Datum) * tupType->natts);
+                                       MemSet(dnulls, 'n', sizeof(char) * tupType->natts);
+                                       inputTuple = heap_formtuple(tupType, dvalues, dnulls);
+                                       pfree(dvalues);
+                                       pfree(dnulls);
                                }
                        }
                }
index 18d11cc7f5ac55c5f0ba87eab9a63f66389b66ce..c03db4f8b4b36fbf65e84a1c2190be0a3a1bb74c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.90 2002/09/18 21:35:22 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.91 2002/09/28 20:00:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -386,6 +386,7 @@ static List *
 ExpandAllTables(ParseState *pstate)
 {
        List       *target = NIL;
+       bool            found_table = false;
        List       *ns;
 
        foreach(ns, pstate->p_namespace)
@@ -413,11 +414,12 @@ ExpandAllTables(ParseState *pstate)
                if (!rte->inFromCl)
                        continue;
 
+               found_table = true;
                target = nconc(target, expandRelAttrs(pstate, rte));
        }
 
        /* Check for SELECT *; */
-       if (target == NIL)
+       if (!found_table)
                elog(ERROR, "Wildcard with no tables specified not allowed");
 
        return target;
index de2e4a29757b7b5a4658bc548f9663094d963b49..f604c1c0dd0ddac5dc29f882e7911d1763c81a46 100644 (file)
@@ -939,11 +939,9 @@ drop table test2;
 alter table atacc1 drop c;
 alter table atacc1 drop d;
 alter table atacc1 drop b;
-ERROR:  ALTER TABLE: Cannot drop last column from table "atacc1"
 select * from atacc1;
- b  
-----
- 21
+  
+--
 (1 row)
 
 drop table atacc1;