diff --git a/src/backend/access/common/tupdesc.c b/src/backend/access/common/tupdesc.c index 5a1b912b37..f1f92af472 100644 --- a/src/backend/access/common/tupdesc.c +++ b/src/backend/access/common/tupdesc.c @@ -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 @@ -39,28 +39,34 @@ 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 diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 0934a274c7..14d82630c8 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.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); diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 1a5f835be1..7b0df664c7 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -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) { diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 898ca62a60..0ebf2f7151 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -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); } } } diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 18d11cc7f5..c03db4f8b4 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -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; diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index de2e4a2975..f604c1c0dd 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -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;