From 0f1112923cf5ae8d4a3a81d5ffe78e0c866cb1ac Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 22 Aug 2002 14:23:36 +0000 Subject: [PATCH] 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. --- src/backend/commands/tablecmds.c | 40 +++++++++++++++++--------- src/test/regress/expected/truncate.out | 2 +- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 1961ca1344..ee2df73f21 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.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; Oid relid; + Oid toastrelid; ScanKeyData key; Relation fkeyRel; SysScanDesc fkeyScan; @@ -341,17 +342,20 @@ TruncateRelation(const RangeVar *relation) rel = heap_openrv(relation, AccessExclusiveLock); relid = RelationGetRelid(rel); - if (rel->rd_rel->relkind == RELKIND_SEQUENCE) - elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence", - RelationGetRelationName(rel)); - - if (rel->rd_rel->relkind == RELKIND_VIEW) - elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view", - RelationGetRelationName(rel)); - - if (rel->rd_rel->relkind == RELKIND_COMPOSITE_TYPE) - elog(ERROR, "TRUNCATE cannot be used on type relations. '%s' is a type", + /* 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) + elog(ERROR, "TRUNCATE cannot be used on sequences. '%s' is a sequence", + RelationGetRelationName(rel)); + if (rel->rd_rel->relkind == RELKIND_VIEW) + elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view", + RelationGetRelationName(rel)); + /* else a generic error message will do */ + elog(ERROR, "TRUNCATE can only be used on tables. '%s' is not a table", RelationGetRelationName(rel)); + } if (!allowSystemTableMods && IsSystemRelation(rel)) 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); /* - * First foriegn key found with us as the reference + * First foreign key found with us as the reference * should throw an error. */ while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan))) { Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); - if (con->contype == 'f') - elog(ERROR, "TRUNCATE cannot be used as other tables reference this one via foreign key constraint %s", + if (con->contype == 'f' && con->conrelid != relid) + 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)); } systable_endscan(fkeyScan); heap_close(fkeyRel, AccessShareLock); + toastrelid = rel->rd_rel->reltoastrelid; + /* Keep the lock until transaction commit */ heap_close(rel, NoLock); + /* Truncate the table proper */ heap_truncate(relid); + + /* If it has a toast table, truncate that too */ + if (OidIsValid(toastrelid)) + heap_truncate(toastrelid); } /*---------- diff --git a/src/test/regress/expected/truncate.out b/src/test/regress/expected/truncate.out index 19300f63a3..8751b1fdb7 100644 --- a/src/test/regress/expected/truncate.out +++ b/src/test/regress/expected/truncate.out @@ -27,7 +27,7 @@ SELECT * FROM truncate_a; (1 row) 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; col1 ------