diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index c6e8d686d4..1961ca1344 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.30 2002/08/19 15:08:46 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.31 2002/08/22 04:51:05 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -332,6 +332,10 @@ TruncateRelation(const RangeVar *relation) { Relation rel; Oid relid; + ScanKeyData key; + Relation fkeyRel; + SysScanDesc fkeyScan; + HeapTuple tuple; /* Grab exclusive lock in preparation for truncate */ rel = heap_openrv(relation, AccessExclusiveLock); @@ -356,6 +360,36 @@ TruncateRelation(const RangeVar *relation) if (!pg_class_ownercheck(relid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, RelationGetRelationName(rel)); + /* + * Don't allow truncate on tables which are referenced + * by foreign keys + */ + fkeyRel = heap_openr(ConstraintRelationName, AccessShareLock); + + ScanKeyEntryInitialize(&key, 0, + Anum_pg_constraint_confrelid, + F_OIDEQ, + ObjectIdGetDatum(relid)); + + fkeyScan = systable_beginscan(fkeyRel, 0, false, + SnapshotNow, 1, &key); + + /* + * First foriegn 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", + NameStr(con->conname)); + } + + systable_endscan(fkeyScan); + heap_close(fkeyRel, AccessShareLock); + /* Keep the lock until transaction commit */ heap_close(rel, NoLock); diff --git a/src/test/regress/expected/truncate.out b/src/test/regress/expected/truncate.out new file mode 100644 index 0000000000..19300f63a3 --- /dev/null +++ b/src/test/regress/expected/truncate.out @@ -0,0 +1,38 @@ +-- Test basic TRUNCATE functionality. +CREATE TABLE truncate_a (col1 integer primary key); +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'truncate_a_pkey' for table 'truncate_a' +INSERT INTO truncate_a VALUES (1); +INSERT INTO truncate_a VALUES (2); +SELECT * FROM truncate_a; + col1 +------ + 1 + 2 +(2 rows) + +TRUNCATE truncate_a; +SELECT * FROM truncate_a; + col1 +------ +(0 rows) + +-- Test foreign constraint check +CREATE TABLE truncate_b(col1 integer references truncate_a); +NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s) +INSERT INTO truncate_a VALUES (1); +SELECT * FROM truncate_a; + col1 +------ + 1 +(1 row) + +TRUNCATE truncate_a; +ERROR: TRUNCATE cannot be used as other tables reference this one via foreign key constraint $1 +SELECT * FROM truncate_a; + col1 +------ + 1 +(1 row) + +DROP TABLE truncate_b; +DROP TABLE truncate_a; diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index 0ac2630706..e82d942167 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -74,4 +74,4 @@ test: select_views alter_table portals_p2 rules foreign_key cluster # The sixth group of parallel test # ---------- # "plpgsql" cannot run concurrently with "rules" -test: limit plpgsql temp domain rangefuncs copy2 conversion without_oid +test: limit plpgsql temp domain rangefuncs copy2 conversion without_oid truncate diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index d7a6deed2c..553df2dfe7 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -1,4 +1,4 @@ -# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.15 2002/08/11 02:06:32 tgl Exp $ +# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.16 2002/08/22 04:51:06 momjian Exp $ # This should probably be in an order similar to parallel_schedule. test: boolean test: char @@ -88,3 +88,4 @@ test: domain test: rangefuncs test: without_oid test: conversion +test: truncate diff --git a/src/test/regress/sql/truncate.sql b/src/test/regress/sql/truncate.sql new file mode 100644 index 0000000000..5333113a9e --- /dev/null +++ b/src/test/regress/sql/truncate.sql @@ -0,0 +1,17 @@ +-- Test basic TRUNCATE functionality. +CREATE TABLE truncate_a (col1 integer primary key); +INSERT INTO truncate_a VALUES (1); +INSERT INTO truncate_a VALUES (2); +SELECT * FROM truncate_a; +TRUNCATE truncate_a; +SELECT * FROM truncate_a; + +-- Test foreign constraint check +CREATE TABLE truncate_b(col1 integer references truncate_a); +INSERT INTO truncate_a VALUES (1); +SELECT * FROM truncate_a; +TRUNCATE truncate_a; +SELECT * FROM truncate_a; + +DROP TABLE truncate_b; +DROP TABLE truncate_a;