Make the world at least somewhat safe for zero-column tables, and

remove the special case in ALTER DROP COLUMN to prohibit dropping a
table's last column.
This commit is contained in:
Tom Lane 2002-09-28 20:00:19 +00:00
parent 23616b47d5
commit 6d0d15c451
6 changed files with 64 additions and 81 deletions

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* some of the executor utility code such as "ExecTypeFromTL" should be * some of the executor utility code such as "ExecTypeFromTL" should be
@ -39,28 +39,34 @@
TupleDesc TupleDesc
CreateTemplateTupleDesc(int natts, bool hasoid) CreateTemplateTupleDesc(int natts, bool hasoid)
{ {
uint32 size;
TupleDesc desc; TupleDesc desc;
/* /*
* sanity checks * sanity checks
*/ */
AssertArg(natts >= 1); AssertArg(natts >= 0);
/* /*
* allocate enough memory for the tuple descriptor and zero it as * allocate enough memory for the tuple descriptor and zero it as
* TupleDescInitEntry assumes that the descriptor is filled with NULL * TupleDescInitEntry assumes that the descriptor is filled with NULL
* pointers. * pointers.
*/ */
size = natts * sizeof(Form_pg_attribute);
desc = (TupleDesc) palloc(sizeof(struct tupleDesc)); 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->natts = natts;
desc->tdhasoid = hasoid; 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; return desc;
} }
@ -79,7 +85,7 @@ CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs)
/* /*
* sanity checks * sanity checks
*/ */
AssertArg(natts >= 1); AssertArg(natts >= 0);
desc = (TupleDesc) palloc(sizeof(struct tupleDesc)); desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
desc->attrs = attrs; desc->attrs = attrs;
@ -108,17 +114,20 @@ CreateTupleDescCopy(TupleDesc tupdesc)
desc = (TupleDesc) palloc(sizeof(struct tupleDesc)); desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
desc->natts = tupdesc->natts; desc->natts = tupdesc->natts;
size = desc->natts * sizeof(Form_pg_attribute); if (desc->natts > 0)
desc->attrs = (Form_pg_attribute *) palloc(size);
for (i = 0; i < desc->natts; i++)
{ {
desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); size = desc->natts * sizeof(Form_pg_attribute);
memcpy(desc->attrs[i], desc->attrs = (Form_pg_attribute *) palloc(size);
tupdesc->attrs[i], for (i = 0; i < desc->natts; i++)
ATTRIBUTE_TUPLE_SIZE); {
desc->attrs[i]->attnotnull = false; desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
desc->attrs[i]->atthasdef = false; 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->constr = NULL;
desc->tdhasoid = tupdesc->tdhasoid; desc->tdhasoid = tupdesc->tdhasoid;
@ -142,15 +151,18 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc)
desc = (TupleDesc) palloc(sizeof(struct tupleDesc)); desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
desc->natts = tupdesc->natts; desc->natts = tupdesc->natts;
size = desc->natts * sizeof(Form_pg_attribute); if (desc->natts > 0)
desc->attrs = (Form_pg_attribute *) palloc(size);
for (i = 0; i < desc->natts; i++)
{ {
desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); size = desc->natts * sizeof(Form_pg_attribute);
memcpy(desc->attrs[i], desc->attrs = (Form_pg_attribute *) palloc(size);
tupdesc->attrs[i], for (i = 0; i < desc->natts; i++)
ATTRIBUTE_TUPLE_SIZE); {
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) if (constr)
{ {
TupleConstr *cpy = (TupleConstr *) palloc(sizeof(TupleConstr)); TupleConstr *cpy = (TupleConstr *) palloc(sizeof(TupleConstr));
@ -197,7 +209,8 @@ FreeTupleDesc(TupleDesc tupdesc)
for (i = 0; i < tupdesc->natts; i++) for (i = 0; i < tupdesc->natts; i++)
pfree(tupdesc->attrs[i]); pfree(tupdesc->attrs[i]);
pfree(tupdesc->attrs); if (tupdesc->attrs)
pfree(tupdesc->attrs);
if (tupdesc->constr) if (tupdesc->constr)
{ {
if (tupdesc->constr->num_defval > 0) if (tupdesc->constr->num_defval > 0)
@ -228,7 +241,6 @@ FreeTupleDesc(TupleDesc tupdesc)
} }
pfree(tupdesc); pfree(tupdesc);
} }
/* /*
@ -361,6 +373,7 @@ TupleDescInitEntry(TupleDesc desc,
*/ */
AssertArg(PointerIsValid(desc)); AssertArg(PointerIsValid(desc));
AssertArg(attributeNumber >= 1); AssertArg(attributeNumber >= 1);
AssertArg(attributeNumber <= desc->natts);
/* /*
* attributeName's are sometimes NULL, from resdom's. I don't know * attributeName's are sometimes NULL, from resdom's. I don't know

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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; Relation rel;
AttrNumber attnum; AttrNumber attnum;
AttrNumber n;
TupleDesc tupleDesc; TupleDesc tupleDesc;
bool success;
ObjectAddress object; ObjectAddress object;
rel = heap_open(myrelid, AccessExclusiveLock); rel = heap_open(myrelid, AccessExclusiveLock);
@ -2359,34 +2357,13 @@ AlterTableDropColumn(Oid myrelid, bool recurse, bool recursing,
RelationGetRelationName(rel), colName); RelationGetRelationName(rel), colName);
/* Can't drop a system attribute */ /* Can't drop a system attribute */
/* XXX perhaps someday allow dropping OID? */
if (attnum < 0) if (attnum < 0)
elog(ERROR, "ALTER TABLE: Cannot drop system attribute \"%s\"", elog(ERROR, "ALTER TABLE: Cannot drop system attribute \"%s\"",
colName); 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 */ /* Don't drop inherited columns */
tupleDesc = RelationGetDescr(rel);
if (tupleDesc->attrs[attnum - 1]->attinhcount > 0 && !recursing) if (tupleDesc->attrs[attnum - 1]->attinhcount > 0 && !recursing)
elog(ERROR, "ALTER TABLE: Cannot drop inherited column \"%s\"", elog(ERROR, "ALTER TABLE: Cannot drop inherited column \"%s\"",
colName); colName);

View File

@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * 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 TupleDesc
ExecTypeFromTL(List *targetList, bool hasoid) ExecTypeFromTL(List *targetList, bool hasoid)
{ {
List *tlitem;
TupleDesc typeInfo; TupleDesc typeInfo;
Resdom *resdom; List *tlitem;
Oid restype;
int len; int len;
/*
* examine targetlist - if empty then return NULL
*/
len = ExecTargetListLength(targetList);
if (len == 0)
return NULL;
/* /*
* allocate a new typeInfo * allocate a new typeInfo
*/ */
len = ExecTargetListLength(targetList);
typeInfo = CreateTemplateTupleDesc(len, hasoid); typeInfo = CreateTemplateTupleDesc(len, hasoid);
/* /*
@ -585,6 +576,8 @@ ExecTypeFromTL(List *targetList, bool hasoid)
foreach(tlitem, targetList) foreach(tlitem, targetList)
{ {
TargetEntry *tle = lfirst(tlitem); TargetEntry *tle = lfirst(tlitem);
Resdom *resdom;
Oid restype;
if (tle->resdom != NULL) if (tle->resdom != NULL)
{ {

View File

@ -46,7 +46,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) if (inputTuple == NULL)
{ {
TupleDesc tupType; TupleDesc tupType;
Datum *tupValue; Datum *dvalues;
char *null_array; char *dnulls;
AttrNumber attnum;
tupType = aggstate->csstate.css_ScanTupleSlot->ttc_tupleDescriptor; tupType = aggstate->csstate.css_ScanTupleSlot->ttc_tupleDescriptor;
tupValue = projInfo->pi_tupValue;
/* watch out for null input tuples, though... */ /* watch out for null input tuples, though... */
if (tupType && tupValue) if (tupType && tupType->natts > 0)
{ {
null_array = (char *) palloc(sizeof(char) * tupType->natts); dvalues = (Datum *) palloc(sizeof(Datum) * tupType->natts);
for (attnum = 0; attnum < tupType->natts; attnum++) dnulls = (char *) palloc(sizeof(char) * tupType->natts);
null_array[attnum] = 'n'; MemSet(dvalues, 0, sizeof(Datum) * tupType->natts);
inputTuple = heap_formtuple(tupType, tupValue, null_array); MemSet(dnulls, 'n', sizeof(char) * tupType->natts);
pfree(null_array); inputTuple = heap_formtuple(tupType, dvalues, dnulls);
pfree(dvalues);
pfree(dnulls);
} }
} }
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ExpandAllTables(ParseState *pstate)
{ {
List *target = NIL; List *target = NIL;
bool found_table = false;
List *ns; List *ns;
foreach(ns, pstate->p_namespace) foreach(ns, pstate->p_namespace)
@ -413,11 +414,12 @@ ExpandAllTables(ParseState *pstate)
if (!rte->inFromCl) if (!rte->inFromCl)
continue; continue;
found_table = true;
target = nconc(target, expandRelAttrs(pstate, rte)); target = nconc(target, expandRelAttrs(pstate, rte));
} }
/* Check for SELECT *; */ /* Check for SELECT *; */
if (target == NIL) if (!found_table)
elog(ERROR, "Wildcard with no tables specified not allowed"); elog(ERROR, "Wildcard with no tables specified not allowed");
return target; return target;

View File

@ -939,11 +939,9 @@ drop table test2;
alter table atacc1 drop c; alter table atacc1 drop c;
alter table atacc1 drop d; alter table atacc1 drop d;
alter table atacc1 drop b; alter table atacc1 drop b;
ERROR: ALTER TABLE: Cannot drop last column from table "atacc1"
select * from atacc1; select * from atacc1;
b
---- --
21
(1 row) (1 row)
drop table atacc1; drop table atacc1;