From 984a6ced3ece409e97b74ce163297b8193eeeb6c Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Fri, 3 Mar 2006 03:30:54 +0000 Subject: [PATCH] Add CASCADE option to TRUNCATE. Joachim Wieland --- doc/src/sgml/ref/truncate.sgml | 42 ++++++++++-- src/backend/catalog/heap.c | 62 +++++++++++++++++- src/backend/commands/tablecmds.c | 90 +++++++++++++++++++++----- src/backend/nodes/copyfuncs.c | 3 +- src/backend/nodes/equalfuncs.c | 3 +- src/backend/parser/gram.y | 5 +- src/backend/tcop/utility.c | 8 +-- src/include/catalog/heap.h | 4 +- src/include/commands/tablecmds.h | 4 +- src/include/nodes/parsenodes.h | 3 +- src/test/regress/expected/truncate.out | 54 +++++++++++++--- src/test/regress/sql/truncate.sql | 21 ++++++ 12 files changed, 252 insertions(+), 47 deletions(-) diff --git a/doc/src/sgml/ref/truncate.sgml b/doc/src/sgml/ref/truncate.sgml index fe68c5b334a..67d1a9843ee 100644 --- a/doc/src/sgml/ref/truncate.sgml +++ b/doc/src/sgml/ref/truncate.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/ref/truncate.sgml,v 1.19 2005/02/22 19:06:18 tgl Exp $ +$PostgreSQL: pgsql/doc/src/sgml/ref/truncate.sgml,v 1.20 2006/03/03 03:30:52 tgl Exp $ PostgreSQL documentation --> @@ -20,7 +20,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] +TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] </synopsis> </refsynopsisdiv> @@ -47,6 +47,27 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] </para> </listitem> </varlistentry> + + <varlistentry> + <term><literal>CASCADE</literal></term> + <listitem> + <para> + Automatically truncate all tables that have foreign-key references + to any of the named tables, or to any tables added to the group + due to <literal>CASCADE</literal>. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>RESTRICT</literal></term> + <listitem> + <para> + Refuse to truncate if any of the tables have foreign-key references + from tables that are not to be truncated. This is the default. + </para> + </listitem> + </varlistentry> </variablelist> </refsect1> @@ -61,7 +82,10 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] <command>TRUNCATE</> cannot be used on a table that has foreign-key references from other tables, unless all such tables are also truncated in the same command. Checking validity in such cases would require table - scans, and the whole point is not to do one. + scans, and the whole point is not to do one. The <literal>CASCADE</> + option can be used to automatically include all dependent tables — + but be very careful when using this option, else you might lose data you + did not intend to! </para> <para> @@ -78,10 +102,20 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] <programlisting> TRUNCATE TABLE bigtable, fattable; +</programlisting> + </para> + + <para> + Truncate the table <literal>othertable</literal>, and cascade to any tables + that are referencing <literal>othertable</literal> via foreign-key + constraints: + +<programlisting> +TRUNCATE othertable CASCADE; </programlisting> </para> </refsect1> - + <refsect1> <title>Compatibility</title> diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index b79b9f07086..ae86c44c38b 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.293 2005/11/22 18:17:08 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.294 2006/03/03 03:30:52 tgl Exp $ * * * INTERFACE ROUTINES @@ -2043,7 +2043,7 @@ heap_truncate_check_FKs(List *relations, bool tempTables) if (con->contype != CONSTRAINT_FOREIGN) continue; - /* Not for one of our list of tables */ + /* Not referencing one of our list of tables */ if (!list_member_oid(oids, con->confrelid)) continue; @@ -2066,7 +2066,8 @@ heap_truncate_check_FKs(List *relations, bool tempTables) get_rel_name(con->conrelid), get_rel_name(con->confrelid), NameStr(con->conname)), - errhint("Truncate table \"%s\" at the same time.", + errhint("Truncate table \"%s\" at the same time, " + "or use TRUNCATE ... CASCADE.", get_rel_name(con->conrelid)))); } } @@ -2074,3 +2075,58 @@ heap_truncate_check_FKs(List *relations, bool tempTables) systable_endscan(fkeyScan); heap_close(fkeyRel, AccessShareLock); } + +/* + * heap_truncate_find_FKs + * Find relations having foreign keys referencing any relations that + * are to be truncated + * + * This is almost the same code as heap_truncate_check_FKs, but we don't + * raise an error if we find such relations; instead we return a list of + * their OIDs. Also note that the input is a list of OIDs not a list + * of Relations. The result list does *not* include any rels that are + * already in the input list. + * + * Note: caller should already have exclusive lock on all rels mentioned + * in relationIds. Since adding or dropping an FK requires exclusive lock + * on both rels, this ensures that the answer will be stable. + */ +List * +heap_truncate_find_FKs(List *relationIds) +{ + List *result = NIL; + Relation fkeyRel; + SysScanDesc fkeyScan; + HeapTuple tuple; + + /* + * Must scan pg_constraint. Right now, it is a seqscan because + * there is no available index on confrelid. + */ + fkeyRel = heap_open(ConstraintRelationId, AccessShareLock); + + fkeyScan = systable_beginscan(fkeyRel, InvalidOid, false, + SnapshotNow, 0, NULL); + + while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan))) + { + Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); + + /* Not a foreign key */ + if (con->contype != CONSTRAINT_FOREIGN) + continue; + + /* Not referencing one of our list of tables */ + if (!list_member_oid(relationIds, con->confrelid)) + continue; + + /* Add referencer unless already in input or result list */ + if (!list_member_oid(relationIds, con->conrelid)) + result = list_append_unique_oid(result, con->conrelid); + } + + systable_endscan(fkeyScan); + heap_close(fkeyRel, AccessShareLock); + + return result; +} diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 48ebd597c99..4a3c146faa0 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.177 2006/01/30 16:18:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.178 2006/03/03 03:30:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -527,26 +527,79 @@ RemoveRelation(const RangeVar *relation, DropBehavior behavior) * ExecuteTruncate * Executes a TRUNCATE command. * - * This is a multi-relation truncate. It first opens and grabs exclusive - * locks on all relations involved, checking permissions and otherwise - * verifying that the relation is OK for truncation. When they are all - * open, it checks foreign key references on them, namely that FK references - * are all internal to the group that's being truncated. Finally all - * relations are truncated and reindexed. + * This is a multi-relation truncate. We first open and grab exclusive + * lock on all relations involved, checking permissions and otherwise + * verifying that the relation is OK for truncation. In CASCADE mode, + * relations having FK references to the targeted relations are automatically + * added to the group; in RESTRICT mode, we check that all FK references are + * internal to the group that's being truncated. Finally all the relations + * are truncated and reindexed. */ void -ExecuteTruncate(List *relations) +ExecuteTruncate(TruncateStmt *stmt) { List *rels = NIL; + List *directRelids = NIL; ListCell *cell; + Oid relid; + Relation rel; - foreach(cell, relations) + /* + * Open and exclusive-lock all the explicitly-specified relations + */ + foreach(cell, stmt->relations) { RangeVar *rv = lfirst(cell); - Relation rel; - /* Grab exclusive lock in preparation for truncate */ rel = heap_openrv(rv, AccessExclusiveLock); + rels = lappend(rels, rel); + directRelids = lappend_oid(directRelids, RelationGetRelid(rel)); + } + + /* + * In CASCADE mode, suck in all referencing relations as well. This + * requires multiple iterations to find indirectly-dependent relations. + * At each phase, we need to exclusive-lock new rels before looking + * for their dependencies, else we might miss something. + */ + if (stmt->behavior == DROP_CASCADE) + { + List *relids = list_copy(directRelids); + + for (;;) + { + List *newrelids; + + newrelids = heap_truncate_find_FKs(relids); + if (newrelids == NIL) + break; /* nothing else to add */ + + foreach(cell, newrelids) + { + relid = lfirst_oid(cell); + rel = heap_open(relid, AccessExclusiveLock); + rels = lappend(rels, rel); + relids = lappend_oid(relids, relid); + } + } + } + + /* now check all involved relations */ + foreach(cell, rels) + { + rel = (Relation) lfirst(cell); + relid = RelationGetRelid(rel); + + /* + * If this table was added to the command by CASCADE, report it. + * We don't do this earlier because if we error out on one of the + * tables, it'd be confusing to list subsequently-added tables. + */ + if (stmt->behavior == DROP_CASCADE && + !list_member_oid(directRelids, relid)) + ereport(NOTICE, + (errmsg("truncate cascades to table \"%s\"", + RelationGetRelationName(rel)))); /* Only allow truncate on regular tables */ if (rel->rd_rel->relkind != RELKIND_RELATION) @@ -585,25 +638,30 @@ ExecuteTruncate(List *relations) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot truncate temporary tables of other sessions"))); - - /* Save it into the list of rels to truncate */ - rels = lappend(rels, rel); } /* - * Check foreign key references. + * Check foreign key references. In CASCADE mode, this should be + * unnecessary since we just pulled in all the references; but as + * a cross-check, do it anyway if in an Assert-enabled build. */ +#ifdef USE_ASSERT_CHECKING heap_truncate_check_FKs(rels, false); +#else + if (stmt->behavior == DROP_RESTRICT) + heap_truncate_check_FKs(rels, false); +#endif /* * OK, truncate each table. */ foreach(cell, rels) { - Relation rel = lfirst(cell); Oid heap_relid; Oid toast_relid; + rel = (Relation) lfirst(cell); + /* * Create a new empty storage file for the relation, and assign it as * the relfilenode value. The old storage file is scheduled for diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 91f06df039a..1e79857d807 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.327 2006/02/19 00:04:26 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.328 2006/03/03 03:30:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1961,6 +1961,7 @@ _copyTruncateStmt(TruncateStmt *from) TruncateStmt *newnode = makeNode(TruncateStmt); COPY_NODE_FIELD(relations); + COPY_SCALAR_FIELD(behavior); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 9a2a5fd0d59..6c255548042 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -18,7 +18,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.263 2006/02/19 00:04:26 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.264 2006/03/03 03:30:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -930,6 +930,7 @@ static bool _equalTruncateStmt(TruncateStmt *a, TruncateStmt *b) { COMPARE_NODE_FIELD(relations); + COMPARE_SCALAR_FIELD(behavior); return true; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index a60d4157b2e..92f0ba67d73 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.531 2006/02/28 22:37:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.532 2006/03/03 03:30:53 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -2938,10 +2938,11 @@ attrs: '.' attr_name *****************************************************************************/ TruncateStmt: - TRUNCATE opt_table qualified_name_list + TRUNCATE opt_table qualified_name_list opt_drop_behavior { TruncateStmt *n = makeNode(TruncateStmt); n->relations = $3; + n->behavior = $4; $$ = (Node *)n; } ; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index b55b1578b38..9a9d138032b 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.252 2006/02/12 19:11:01 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.253 2006/03/03 03:30:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -628,11 +628,7 @@ ProcessUtility(Node *parsetree, break; case T_TruncateStmt: - { - TruncateStmt *stmt = (TruncateStmt *) parsetree; - - ExecuteTruncate(stmt->relations); - } + ExecuteTruncate((TruncateStmt *) parsetree); break; case T_CommentStmt: diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 9cb4c5351a8..09516ed0215 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.76 2005/10/15 02:49:42 momjian Exp $ + * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.77 2006/03/03 03:30:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -62,6 +62,8 @@ extern void heap_truncate(List *relids); extern void heap_truncate_check_FKs(List *relations, bool tempTables); +extern List *heap_truncate_find_FKs(List *relationIds); + extern List *AddRelationRawConstraints(Relation rel, List *rawColDefaults, List *rawConstraints); diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index b6e30f6f699..1e367210d70 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/tablecmds.h,v 1.25 2005/11/21 12:49:32 alvherre Exp $ + * $PostgreSQL: pgsql/src/include/commands/tablecmds.h,v 1.26 2006/03/03 03:30:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -36,7 +36,7 @@ extern void AlterRelationNamespaceInternal(Relation classRel, Oid relOid, Oid oldNspOid, Oid newNspOid, bool hasDependEntry); -extern void ExecuteTruncate(List *relations); +extern void ExecuteTruncate(TruncateStmt *stmt); extern void renameatt(Oid myrelid, const char *oldattname, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index a251e0759d3..f1f7d4456dd 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.301 2006/02/19 00:04:27 neilc Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.302 2006/03/03 03:30:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1314,6 +1314,7 @@ typedef struct TruncateStmt { NodeTag type; List *relations; /* relations (RangeVars) to be truncated */ + DropBehavior behavior; /* RESTRICT or CASCADE behavior */ } TruncateStmt; /* ---------------------- diff --git a/src/test/regress/expected/truncate.out b/src/test/regress/expected/truncate.out index c03deef1e8e..263c5c8e083 100644 --- a/src/test/regress/expected/truncate.out +++ b/src/test/regress/expected/truncate.out @@ -40,30 +40,37 @@ CREATE TABLE trunc_e (a int REFERENCES truncate_a, b int REFERENCES trunc_c); TRUNCATE TABLE truncate_a; -- fail ERROR: cannot truncate a table referenced in a foreign key constraint DETAIL: Table "trunc_b" references "truncate_a" via foreign key constraint "trunc_b_a_fkey". -HINT: Truncate table "trunc_b" at the same time. +HINT: Truncate table "trunc_b" at the same time, or use TRUNCATE ... CASCADE. TRUNCATE TABLE truncate_a,trunc_b; -- fail ERROR: cannot truncate a table referenced in a foreign key constraint DETAIL: Table "trunc_e" references "truncate_a" via foreign key constraint "trunc_e_a_fkey". -HINT: Truncate table "trunc_e" at the same time. +HINT: Truncate table "trunc_e" at the same time, or use TRUNCATE ... CASCADE. TRUNCATE TABLE truncate_a,trunc_b,trunc_e; -- ok TRUNCATE TABLE truncate_a,trunc_e; -- fail ERROR: cannot truncate a table referenced in a foreign key constraint DETAIL: Table "trunc_b" references "truncate_a" via foreign key constraint "trunc_b_a_fkey". -HINT: Truncate table "trunc_b" at the same time. +HINT: Truncate table "trunc_b" at the same time, or use TRUNCATE ... CASCADE. TRUNCATE TABLE trunc_c; -- fail ERROR: cannot truncate a table referenced in a foreign key constraint DETAIL: Table "trunc_d" references "trunc_c" via foreign key constraint "trunc_d_a_fkey". -HINT: Truncate table "trunc_d" at the same time. +HINT: Truncate table "trunc_d" at the same time, or use TRUNCATE ... CASCADE. TRUNCATE TABLE trunc_c,trunc_d; -- fail ERROR: cannot truncate a table referenced in a foreign key constraint DETAIL: Table "trunc_e" references "trunc_c" via foreign key constraint "trunc_e_b_fkey". -HINT: Truncate table "trunc_e" at the same time. +HINT: Truncate table "trunc_e" at the same time, or use TRUNCATE ... CASCADE. TRUNCATE TABLE trunc_c,trunc_d,trunc_e; -- ok TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a; -- fail ERROR: cannot truncate a table referenced in a foreign key constraint DETAIL: Table "trunc_b" references "truncate_a" via foreign key constraint "trunc_b_a_fkey". -HINT: Truncate table "trunc_b" at the same time. +HINT: Truncate table "trunc_b" at the same time, or use TRUNCATE ... CASCADE. TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a,trunc_b; -- ok +TRUNCATE TABLE truncate_a RESTRICT; -- fail +ERROR: cannot truncate a table referenced in a foreign key constraint +DETAIL: Table "trunc_b" references "truncate_a" via foreign key constraint "trunc_b_a_fkey". +HINT: Truncate table "trunc_b" at the same time, or use TRUNCATE ... CASCADE. +TRUNCATE TABLE truncate_a CASCADE; -- ok +NOTICE: truncate cascades to table "trunc_b" +NOTICE: truncate cascades to table "trunc_e" -- circular references ALTER TABLE truncate_a ADD FOREIGN KEY (col1) REFERENCES trunc_c; -- Add some data to verify that truncating actually works ... @@ -75,19 +82,19 @@ INSERT INTO trunc_e VALUES (1,1); TRUNCATE TABLE trunc_c; ERROR: cannot truncate a table referenced in a foreign key constraint DETAIL: Table "trunc_d" references "trunc_c" via foreign key constraint "trunc_d_a_fkey". -HINT: Truncate table "trunc_d" at the same time. +HINT: Truncate table "trunc_d" at the same time, or use TRUNCATE ... CASCADE. TRUNCATE TABLE trunc_c,trunc_d; ERROR: cannot truncate a table referenced in a foreign key constraint DETAIL: Table "trunc_e" references "trunc_c" via foreign key constraint "trunc_e_b_fkey". -HINT: Truncate table "trunc_e" at the same time. +HINT: Truncate table "trunc_e" at the same time, or use TRUNCATE ... CASCADE. TRUNCATE TABLE trunc_c,trunc_d,trunc_e; ERROR: cannot truncate a table referenced in a foreign key constraint DETAIL: Table "truncate_a" references "trunc_c" via foreign key constraint "truncate_a_col1_fkey". -HINT: Truncate table "truncate_a" at the same time. +HINT: Truncate table "truncate_a" at the same time, or use TRUNCATE ... CASCADE. TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a; ERROR: cannot truncate a table referenced in a foreign key constraint DETAIL: Table "trunc_b" references "truncate_a" via foreign key constraint "trunc_b_a_fkey". -HINT: Truncate table "trunc_b" at the same time. +HINT: Truncate table "trunc_b" at the same time, or use TRUNCATE ... CASCADE. TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a,trunc_b; -- Verify that truncating did actually work SELECT * FROM truncate_a @@ -106,6 +113,33 @@ SELECT * FROM trunc_e; ---+--- (0 rows) +-- Add data again to test TRUNCATE ... CASCADE +INSERT INTO trunc_c VALUES (1); +INSERT INTO truncate_a VALUES (1); +INSERT INTO trunc_b VALUES (1); +INSERT INTO trunc_d VALUES (1); +INSERT INTO trunc_e VALUES (1,1); +TRUNCATE TABLE trunc_c CASCADE; -- ok +NOTICE: truncate cascades to table "trunc_d" +NOTICE: truncate cascades to table "trunc_e" +NOTICE: truncate cascades to table "truncate_a" +NOTICE: truncate cascades to table "trunc_b" +SELECT * FROM truncate_a + UNION ALL + SELECT * FROM trunc_c + UNION ALL + SELECT * FROM trunc_b + UNION ALL + SELECT * FROM trunc_d; + col1 +------ +(0 rows) + +SELECT * FROM trunc_e; + a | b +---+--- +(0 rows) + DROP TABLE truncate_a,trunc_c,trunc_b,trunc_d,trunc_e CASCADE; NOTICE: drop cascades to constraint trunc_e_a_fkey on table trunc_e NOTICE: drop cascades to constraint trunc_b_a_fkey on table trunc_b diff --git a/src/test/regress/sql/truncate.sql b/src/test/regress/sql/truncate.sql index 09a08e5652a..a4d27d01e1f 100644 --- a/src/test/regress/sql/truncate.sql +++ b/src/test/regress/sql/truncate.sql @@ -30,6 +30,9 @@ TRUNCATE TABLE trunc_c,trunc_d,trunc_e; -- ok TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a; -- fail TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a,trunc_b; -- ok +TRUNCATE TABLE truncate_a RESTRICT; -- fail +TRUNCATE TABLE truncate_a CASCADE; -- ok + -- circular references ALTER TABLE truncate_a ADD FOREIGN KEY (col1) REFERENCES trunc_c; @@ -55,4 +58,22 @@ SELECT * FROM truncate_a SELECT * FROM trunc_d; SELECT * FROM trunc_e; +-- Add data again to test TRUNCATE ... CASCADE +INSERT INTO trunc_c VALUES (1); +INSERT INTO truncate_a VALUES (1); +INSERT INTO trunc_b VALUES (1); +INSERT INTO trunc_d VALUES (1); +INSERT INTO trunc_e VALUES (1,1); + +TRUNCATE TABLE trunc_c CASCADE; -- ok + +SELECT * FROM truncate_a + UNION ALL + SELECT * FROM trunc_c + UNION ALL + SELECT * FROM trunc_b + UNION ALL + SELECT * FROM trunc_d; +SELECT * FROM trunc_e; + DROP TABLE truncate_a,trunc_c,trunc_b,trunc_d,trunc_e CASCADE; -- GitLab