mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-21 08:29:39 +08:00
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:
parent
23616b47d5
commit
6d0d15c451
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user