Code review for recent TRUNCATE changes. Tighten relation-kind check,

tighten foreign-key check (a self-reference should not prevent TRUNCATE),
improve error message, cause a relation's TOAST table to be truncated
along with the relation.
This commit is contained in:
Tom Lane 2002-08-22 14:23:36 +00:00
parent b4f24fed7a
commit 0f1112923c
2 changed files with 27 additions and 15 deletions

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.31 2002/08/22 04:51:05 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.32 2002/08/22 14:23:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -332,6 +332,7 @@ TruncateRelation(const RangeVar *relation)
{ {
Relation rel; Relation rel;
Oid relid; Oid relid;
Oid toastrelid;
ScanKeyData key; ScanKeyData key;
Relation fkeyRel; Relation fkeyRel;
SysScanDesc fkeyScan; SysScanDesc fkeyScan;
@ -341,17 +342,20 @@ TruncateRelation(const RangeVar *relation)
rel = heap_openrv(relation, AccessExclusiveLock); rel = heap_openrv(relation, AccessExclusiveLock);
relid = RelationGetRelid(rel); relid = RelationGetRelid(rel);
/* Only allow truncate on regular tables */
if (rel->rd_rel->relkind != RELKIND_RELATION)
{
/* special errors for backwards compatibility */
if (rel->rd_rel->relkind == RELKIND_SEQUENCE) if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence", elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence",
RelationGetRelationName(rel)); RelationGetRelationName(rel));
if (rel->rd_rel->relkind == RELKIND_VIEW) if (rel->rd_rel->relkind == RELKIND_VIEW)
elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view", elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view",
RelationGetRelationName(rel)); RelationGetRelationName(rel));
/* else a generic error message will do */
if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) elog(ERROR, "TRUNCATE can only be used on tables. '%s' is not a table",
elog(ERROR, "TRUNCATE cannot be used on type relations. '%s' is a type",
RelationGetRelationName(rel)); RelationGetRelationName(rel));
}
if (!allowSystemTableMods && IsSystemRelation(rel)) if (!allowSystemTableMods && IsSystemRelation(rel))
elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table", elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table",
@ -375,25 +379,33 @@ TruncateRelation(const RangeVar *relation)
SnapshotNow, 1, &key); SnapshotNow, 1, &key);
/* /*
* First foriegn key found with us as the reference * First foreign key found with us as the reference
* should throw an error. * should throw an error.
*/ */
while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan))) while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan)))
{ {
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
if (con->contype == 'f') if (con->contype == 'f' && con->conrelid != relid)
elog(ERROR, "TRUNCATE cannot be used as other tables reference this one via foreign key constraint %s", elog(ERROR, "TRUNCATE cannot be used as table %s references this one via foreign key constraint %s",
get_rel_name(con->conrelid),
NameStr(con->conname)); NameStr(con->conname));
} }
systable_endscan(fkeyScan); systable_endscan(fkeyScan);
heap_close(fkeyRel, AccessShareLock); heap_close(fkeyRel, AccessShareLock);
toastrelid = rel->rd_rel->reltoastrelid;
/* Keep the lock until transaction commit */ /* Keep the lock until transaction commit */
heap_close(rel, NoLock); heap_close(rel, NoLock);
/* Truncate the table proper */
heap_truncate(relid); heap_truncate(relid);
/* If it has a toast table, truncate that too */
if (OidIsValid(toastrelid))
heap_truncate(toastrelid);
} }
/*---------- /*----------

View File

@ -27,7 +27,7 @@ SELECT * FROM truncate_a;
(1 row) (1 row)
TRUNCATE truncate_a; TRUNCATE truncate_a;
ERROR: TRUNCATE cannot be used as other tables reference this one via foreign key constraint $1 ERROR: TRUNCATE cannot be used as table truncate_b references this one via foreign key constraint $1
SELECT * FROM truncate_a; SELECT * FROM truncate_a;
col1 col1
------ ------