? config.log ? GNUmakefile ? config.status ? src/Makefile.custom ? src/log ? src/Makefile.global ? src/bin/psql/psql ? src/bin/psql/po/cs.mo ? src/bin/psql/po/de.mo ? src/bin/psql/po/es.mo ? src/bin/psql/po/fa.mo ? src/bin/psql/po/fr.mo ? src/bin/psql/po/hu.mo ? src/bin/psql/po/it.mo ? src/bin/psql/po/nb.mo ? src/bin/psql/po/pt_BR.mo ? src/bin/psql/po/ru.mo ? src/bin/psql/po/sk.mo ? src/bin/psql/po/sl.mo ? src/bin/psql/po/sv.mo ? src/bin/psql/po/tr.mo ? src/bin/psql/po/zh_CN.mo ? src/bin/psql/po/zh_TW.mo ? src/include/pg_config.h ? src/include/stamp-h ? src/interfaces/libpq/libpq.so.3.2 ? src/interfaces/libpq/po/af.mo ? src/interfaces/libpq/po/cs.mo ? src/interfaces/libpq/po/de.mo ? src/interfaces/libpq/po/es.mo ? src/interfaces/libpq/po/fr.mo ? src/interfaces/libpq/po/hr.mo ? src/interfaces/libpq/po/it.mo ? src/interfaces/libpq/po/nb.mo ? src/interfaces/libpq/po/pt_BR.mo ? src/interfaces/libpq/po/ru.mo ? src/interfaces/libpq/po/sk.mo ? src/interfaces/libpq/po/sl.mo ? src/interfaces/libpq/po/sv.mo ? src/interfaces/libpq/po/tr.mo ? src/interfaces/libpq/po/zh_CN.mo ? src/interfaces/libpq/po/zh_TW.mo ? src/port/pg_config_paths.h Index: doc/src/sgml/ref/truncate.sgml =================================================================== RCS file: /cvsroot/pgsql/doc/src/sgml/ref/truncate.sgml,v retrieving revision 1.17 diff -c -c -b -r1.17 truncate.sgml *** doc/src/sgml/ref/truncate.sgml 23 Mar 2004 13:21:41 -0000 1.17 --- doc/src/sgml/ref/truncate.sgml 6 Nov 2004 05:56:52 -0000 *************** *** 11,17 **** TRUNCATE ! empty a table --- 11,17 ---- TRUNCATE ! empty a set of tables *************** *** 20,26 **** ! TRUNCATE [ TABLE ] name --- 20,26 ---- ! TRUNCATE [ TABLE ] name [, ...] *************** *** 28,37 **** Description ! TRUNCATE quickly removes all rows from a ! table. It has the same effect as an unqualified ! DELETE but since it does not actually scan the ! table it is faster. This is most useful on large tables. --- 28,37 ---- Description ! TRUNCATE quickly removes all rows from a set of ! tables. It has the same effect as an unqualified ! DELETE on each of them, but since it does not actually ! scan the tables it is faster. This is most useful on large tables. *************** *** 55,67 **** TRUNCATE cannot be used if there are foreign-key references ! to the table from other tables. Checking validity in such cases would ! require table scans, and the whole point is not to do one. TRUNCATE will not run any user-defined ON ! DELETE triggers that might exist for the table. --- 55,68 ---- TRUNCATE cannot be used if there are foreign-key references ! to the table 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. TRUNCATE will not run any user-defined ON ! DELETE triggers that might exist for the tables. *************** *** 69,78 **** Examples ! Truncate the table bigtable: ! TRUNCATE TABLE bigtable; --- 70,79 ---- Examples ! Truncate the tables bigtable and fattable: ! TRUNCATE TABLE bigtable, fattable; Index: src/backend/catalog/heap.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/catalog/heap.c,v retrieving revision 1.276 diff -c -c -b -r1.276 heap.c *** src/backend/catalog/heap.c 31 Aug 2004 17:10:36 -0000 1.276 --- src/backend/catalog/heap.c 6 Nov 2004 05:56:56 -0000 *************** *** 2002,2024 **** /* * heap_truncate * ! * This routine deletes all data within the specified relation. * * This is not transaction-safe! There is another, transaction-safe * implementation in commands/cluster.c. We now use this only for * ON COMMIT truncation of temporary tables, where it doesn't matter. */ void ! heap_truncate(Oid rid) { Relation rel; - Oid toastrelid; /* Open relation for processing, and grab exclusive access on it. */ rel = heap_open(rid, AccessExclusiveLock); /* Don't allow truncate on tables that are referenced by foreign keys */ ! heap_truncate_check_FKs(rel); /* * Release any buffers associated with this relation. If they're --- 2002,2044 ---- /* * heap_truncate * ! * This routine deletes all data within all the specified relations. * * This is not transaction-safe! There is another, transaction-safe * implementation in commands/cluster.c. We now use this only for * ON COMMIT truncation of temporary tables, where it doesn't matter. */ void ! heap_truncate(List *relids) { + List *relations = NIL; + List *toasttables = NIL; + ListCell *cell; + + /* + * Fast path when there's nothing to truncate + */ + if (list_length(relids) == 0) + return; + + foreach (cell, relids) + { + Oid rid = lfirst_oid(cell); Relation rel; /* Open relation for processing, and grab exclusive access on it. */ rel = heap_open(rid, AccessExclusiveLock); + relations = lappend(relations, rel); + } + /* Don't allow truncate on tables that are referenced by foreign keys */ ! heap_truncate_check_FKs(relations); ! ! foreach (cell, relations) ! { ! Relation rel = lfirst(cell); ! Oid toastrelid; /* * Release any buffers associated with this relation. If they're *************** *** 2030,2080 **** RelationTruncate(rel, 0); /* If this relation has indexes, truncate the indexes too */ ! RelationTruncateIndexes(rid); ! /* If it has a toast table, recursively truncate that too */ toastrelid = rel->rd_rel->reltoastrelid; if (OidIsValid(toastrelid)) ! heap_truncate(toastrelid); /* * Close the relation, but keep exclusive lock on it until commit. */ heap_close(rel, NoLock); } /* * heap_truncate_check_FKs ! * Check for foreign keys referencing a relation that's to be truncated * * We disallow such FKs (except self-referential ones) since the whole point * of TRUNCATE is to not scan the individual rows to be thrown away. * * This is split out so it can be shared by both implementations of truncate. ! * Caller should already hold a suitable lock on the relation. */ void ! heap_truncate_check_FKs(Relation rel) { ! Oid relid = RelationGetRelid(rel); ! ScanKeyData key; Relation fkeyRel; - SysScanDesc fkeyScan; - HeapTuple tuple; /* ! * Fast path: if the relation has no triggers, it surely has no FKs ! * either. */ if (rel->rd_rel->reltriggers == 0) return; /* ! * Otherwise, must scan pg_constraint. Right now, this is a seqscan * because there is no available index on confrelid. */ fkeyRel = heap_openr(ConstraintRelationName, AccessShareLock); ScanKeyInit(&key, Anum_pg_constraint_confrelid, BTEqualStrategyNumber, F_OIDEQ, --- 2050,2137 ---- RelationTruncate(rel, 0); /* If this relation has indexes, truncate the indexes too */ ! RelationTruncateIndexes(RelationGetRelid(rel)); ! /* ! * If it has a toast table, schedule it for later truncation. ! * Note that we cannot just append it to the list being processed, ! * because it's not open nor locked. ! */ toastrelid = rel->rd_rel->reltoastrelid; if (OidIsValid(toastrelid)) ! toasttables = lappend_oid(toasttables, toastrelid); /* * Close the relation, but keep exclusive lock on it until commit. */ heap_close(rel, NoLock); + } + + /* now truncate TOAST tables */ + if (list_length(toasttables) > 0) + heap_truncate(toasttables); } /* * heap_truncate_check_FKs ! * Check for foreign keys referencing a list of relations that ! * have to be truncated * * We disallow such FKs (except self-referential ones) since the whole point * of TRUNCATE is to not scan the individual rows to be thrown away. * * This is split out so it can be shared by both implementations of truncate. ! * Caller should already hold a suitable lock on the relations. */ void ! heap_truncate_check_FKs(List *relations) { ! List *rels = NIL; ! List *oids = NIL; ! ListCell *cell; Relation fkeyRel; /* ! * Get the list of involved relations and their Oids. ! */ ! foreach(cell, relations) ! { ! Relation rel = lfirst(cell); ! ! /* ! * If a relation has no triggers, then it can't neither ! * have FKs nor be referenced by a FK from another table, ! * so skip it. */ if (rel->rd_rel->reltriggers == 0) + continue; + + rels = lappend(rels, rel); + oids = lappend_oid(oids, RelationGetRelid(rel)); + } + + /* + * Fast path: if no relation has triggers, none has FKs either. + */ + if (list_length(rels) == 0) return; /* ! * Otherwise, must scan pg_constraint. Right now, these are seqscans * because there is no available index on confrelid. + * + * XXX -- is there a way to do it in one sweep? */ fkeyRel = heap_openr(ConstraintRelationName, AccessShareLock); + foreach (cell, rels) + { + Relation rel = lfirst(cell); + Oid relid = RelationGetRelid(rel); + SysScanDesc fkeyScan; + HeapTuple tuple; + ScanKeyData key; + ScanKeyInit(&key, Anum_pg_constraint_confrelid, BTEqualStrategyNumber, F_OIDEQ, *************** *** 2087,2102 **** { Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); ! if (con->contype == CONSTRAINT_FOREIGN && con->conrelid != relid) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot truncate a table referenced in a foreign key constraint"), errdetail("Table \"%s\" references \"%s\" via foreign key constraint \"%s\".", get_rel_name(con->conrelid), RelationGetRelationName(rel), ! NameStr(con->conname)))); } - systable_endscan(fkeyScan); heap_close(fkeyRel, AccessShareLock); } --- 2144,2163 ---- { Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple); ! if (con->contype == CONSTRAINT_FOREIGN && ! ! list_member_oid(oids, con->conrelid)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot truncate a table referenced in a foreign key constraint"), errdetail("Table \"%s\" references \"%s\" via foreign key constraint \"%s\".", get_rel_name(con->conrelid), RelationGetRelationName(rel), ! NameStr(con->conname)), ! errhint("Truncate table \"%s\" at the same time", ! get_rel_name(con->conrelid)))); } systable_endscan(fkeyScan); + } + heap_close(fkeyRel, AccessShareLock); } Index: src/backend/commands/tablecmds.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v retrieving revision 1.139 diff -c -c -b -r1.139 tablecmds.c *** src/backend/commands/tablecmds.c 5 Nov 2004 19:15:57 -0000 1.139 --- src/backend/commands/tablecmds.c 6 Nov 2004 05:57:08 -0000 *************** *** 524,541 **** } /* ! * TruncateRelation ! * Removes all the rows from a relation. */ void ! TruncateRelation(const RangeVar *relation) { Relation rel; - Oid heap_relid; - Oid toast_relid; /* Grab exclusive lock in preparation for truncate */ ! rel = heap_openrv(relation, AccessExclusiveLock); /* Only allow truncate on regular tables */ if (rel->rd_rel->relkind != RELKIND_RELATION) --- 524,552 ---- } /* ! * 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. */ void ! ExecuteTruncate(List *relations) { + List *rels = NIL; + ListCell *cell; + + foreach (cell, relations) + { + RangeVar *rv = lfirst(cell); Relation rel; /* Grab exclusive lock in preparation for truncate */ ! rel = heap_openrv(rv, AccessExclusiveLock); /* Only allow truncate on regular tables */ if (rel->rd_rel->relkind != RELKIND_RELATION) *************** *** 575,589 **** (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot truncate temporary tables of other sessions"))); /* ! * Don't allow truncate on tables which are referenced by foreign keys */ ! heap_truncate_check_FKs(rel); /* ! * Okay, here we go: create a new empty storage file for the relation, ! * and assign it as the relfilenode value. The old storage file is ! * scheduled for deletion at commit. */ setNewRelfilenode(rel); --- 586,610 ---- (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. */ ! heap_truncate_check_FKs(rels); ! ! foreach (cell, rels) ! { ! Relation rel = lfirst(cell); ! Oid heap_relid; ! Oid toast_relid; /* ! * Create a new empty storage file for the relation, and assign it as ! * the relfilenode value. The old storage file is scheduled for ! * deletion at commit. */ setNewRelfilenode(rel); *************** *** 606,611 **** --- 627,633 ---- * Reconstruct the indexes to match, and we're done. */ reindex_relation(heap_relid, true); + } } /*---------- *************** *** 5959,5964 **** --- 5981,5987 ---- PreCommit_on_commit_actions(void) { ListCell *l; + List *oids_to_truncate = NIL; foreach(l, on_commits) { *************** *** 5975,5982 **** /* Do nothing (there shouldn't be such entries, actually) */ break; case ONCOMMIT_DELETE_ROWS: ! heap_truncate(oc->relid); ! CommandCounterIncrement(); /* XXX needed? */ break; case ONCOMMIT_DROP: { --- 5998,6004 ---- /* Do nothing (there shouldn't be such entries, actually) */ break; case ONCOMMIT_DELETE_ROWS: ! oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid); break; case ONCOMMIT_DROP: { *************** *** 5997,6002 **** --- 6019,6027 ---- } } } + if (list_length(oids_to_truncate) > 0) + heap_truncate(oids_to_truncate); + CommandCounterIncrement(); /* XXX needed? */ } /* Index: src/backend/nodes/copyfuncs.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v retrieving revision 1.293 diff -c -c -b -r1.293 copyfuncs.c *** src/backend/nodes/copyfuncs.c 5 Nov 2004 19:15:59 -0000 1.293 --- src/backend/nodes/copyfuncs.c 6 Nov 2004 05:57:12 -0000 *************** *** 1800,1806 **** { TruncateStmt *newnode = makeNode(TruncateStmt); ! COPY_NODE_FIELD(relation); return newnode; } --- 1800,1806 ---- { TruncateStmt *newnode = makeNode(TruncateStmt); ! COPY_NODE_FIELD(relations); return newnode; } Index: src/backend/nodes/equalfuncs.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v retrieving revision 1.232 diff -c -c -b -r1.232 equalfuncs.c *** src/backend/nodes/equalfuncs.c 5 Nov 2004 19:15:59 -0000 1.232 --- src/backend/nodes/equalfuncs.c 6 Nov 2004 05:57:15 -0000 *************** *** 873,879 **** static bool _equalTruncateStmt(TruncateStmt *a, TruncateStmt *b) { ! COMPARE_NODE_FIELD(relation); return true; } --- 873,879 ---- static bool _equalTruncateStmt(TruncateStmt *a, TruncateStmt *b) { ! COMPARE_NODE_FIELD(relations); return true; } Index: src/backend/parser/gram.y =================================================================== RCS file: /cvsroot/pgsql/src/backend/parser/gram.y,v retrieving revision 2.479 diff -c -c -b -r2.479 gram.y *** src/backend/parser/gram.y 5 Nov 2004 19:16:02 -0000 2.479 --- src/backend/parser/gram.y 6 Nov 2004 05:57:29 -0000 *************** *** 2684,2698 **** /***************************************************************************** * * QUERY: ! * truncate table relname * *****************************************************************************/ TruncateStmt: ! TRUNCATE opt_table qualified_name { TruncateStmt *n = makeNode(TruncateStmt); ! n->relation = $3; $$ = (Node *)n; } ; --- 2684,2698 ---- /***************************************************************************** * * QUERY: ! * truncate table relname1, relname2, ... * *****************************************************************************/ TruncateStmt: ! TRUNCATE opt_table qualified_name_list { TruncateStmt *n = makeNode(TruncateStmt); ! n->relations = $3; $$ = (Node *)n; } ; Index: src/backend/tcop/utility.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/tcop/utility.c,v retrieving revision 1.230 diff -c -c -b -r1.230 utility.c *** src/backend/tcop/utility.c 13 Sep 2004 20:07:06 -0000 1.230 --- src/backend/tcop/utility.c 6 Nov 2004 05:57:31 -0000 *************** *** 575,581 **** { TruncateStmt *stmt = (TruncateStmt *) parsetree; ! TruncateRelation(stmt->relation); } break; --- 575,581 ---- { TruncateStmt *stmt = (TruncateStmt *) parsetree; ! ExecuteTruncate(stmt->relations); } break; Index: src/include/catalog/heap.h =================================================================== RCS file: /cvsroot/pgsql/src/include/catalog/heap.h,v retrieving revision 1.71 diff -c -c -b -r1.71 heap.h *** src/include/catalog/heap.h 31 Aug 2004 17:10:36 -0000 1.71 --- src/include/catalog/heap.h 6 Nov 2004 05:57:34 -0000 *************** *** 56,64 **** extern void heap_drop_with_catalog(Oid relid); ! extern void heap_truncate(Oid rid); ! extern void heap_truncate_check_FKs(Relation rel); extern List *AddRelationRawConstraints(Relation rel, List *rawColDefaults, --- 56,64 ---- extern void heap_drop_with_catalog(Oid relid); ! extern void heap_truncate(List *relids); ! extern void heap_truncate_check_FKs(List *relations); extern List *AddRelationRawConstraints(Relation rel, List *rawColDefaults, Index: src/include/commands/tablecmds.h =================================================================== RCS file: /cvsroot/pgsql/src/include/commands/tablecmds.h,v retrieving revision 1.20 diff -c -c -b -r1.20 tablecmds.h *** src/include/commands/tablecmds.h 16 Sep 2004 16:58:39 -0000 1.20 --- src/include/commands/tablecmds.h 6 Nov 2004 05:57:34 -0000 *************** *** 27,33 **** extern void AlterTableCreateToastTable(Oid relOid, bool silent); ! extern void TruncateRelation(const RangeVar *relation); extern void renameatt(Oid myrelid, const char *oldattname, --- 27,33 ---- extern void AlterTableCreateToastTable(Oid relOid, bool silent); ! extern void ExecuteTruncate(List *relations); extern void renameatt(Oid myrelid, const char *oldattname, Index: src/include/nodes/parsenodes.h =================================================================== RCS file: /cvsroot/pgsql/src/include/nodes/parsenodes.h,v retrieving revision 1.270 diff -c -c -b -r1.270 parsenodes.h *** src/include/nodes/parsenodes.h 5 Nov 2004 19:16:38 -0000 1.270 --- src/include/nodes/parsenodes.h 6 Nov 2004 05:57:37 -0000 *************** *** 1283,1289 **** typedef struct TruncateStmt { NodeTag type; ! RangeVar *relation; /* relation to be truncated */ } TruncateStmt; /* ---------------------- --- 1283,1289 ---- typedef struct TruncateStmt { NodeTag type; ! List *relations; /* relations (RangeVars) to be truncated */ } TruncateStmt; /* ---------------------- Index: src/test/regress/expected/temp.out =================================================================== RCS file: /cvsroot/pgsql/src/test/regress/expected/temp.out,v retrieving revision 1.9 diff -c -c -b -r1.9 temp.out *** src/test/regress/expected/temp.out 25 Sep 2003 06:58:06 -0000 1.9 --- src/test/regress/expected/temp.out 6 Nov 2004 05:57:40 -0000 *************** *** 82,84 **** --- 82,103 ---- -- ON COMMIT is only allowed for TEMP CREATE TABLE temptest(col int) ON COMMIT DELETE ROWS; ERROR: ON COMMIT can only be used on temporary tables + -- Test foreign keys + BEGIN; + CREATE TEMP TABLE temptest1(col int PRIMARY KEY) ON COMMIT DELETE ROWS; + NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "temptest1_pkey" for table "temptest1" + CREATE TEMP TABLE temptest2(col int REFERENCES temptest1) + ON COMMIT DELETE ROWS; + INSERT INTO temptest1 VALUES (1); + INSERT INTO temptest2 VALUES (1); + COMMIT; + SELECT * FROM temptest1; + col + ----- + (0 rows) + + SELECT * FROM temptest2; + col + ----- + (0 rows) + Index: src/test/regress/expected/truncate.out =================================================================== RCS file: /cvsroot/pgsql/src/test/regress/expected/truncate.out,v retrieving revision 1.9 diff -c -c -b -r1.9 truncate.out *** src/test/regress/expected/truncate.out 10 Jun 2004 17:56:01 -0000 1.9 --- src/test/regress/expected/truncate.out 6 Nov 2004 05:57:41 -0000 *************** *** 30,52 **** ------ (0 rows) ! -- Test foreign constraint check ! CREATE TABLE truncate_b(col1 integer references truncate_a); INSERT INTO truncate_a VALUES (1); ! SELECT * FROM truncate_a; ! col1 ! ------ ! 1 ! (1 row) ! ! TRUNCATE truncate_a; ERROR: cannot truncate a table referenced in a foreign key constraint ! DETAIL: Table "truncate_b" references "truncate_a" via foreign key constraint "truncate_b_col1_fkey". ! SELECT * FROM truncate_a; col1 ------ ! 1 ! (1 row) ! DROP TABLE truncate_b; ! DROP TABLE truncate_a; --- 30,113 ---- ------ (0 rows) ! -- Test foreign-key checks ! CREATE TABLE trunc_b (a int REFERENCES truncate_a); ! CREATE TABLE trunc_c (a serial PRIMARY KEY); ! NOTICE: CREATE TABLE will create implicit sequence "trunc_c_a_seq" for serial column "trunc_c.a" ! NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "trunc_c_pkey" for table "trunc_c" ! CREATE TABLE trunc_d (a int REFERENCES trunc_c); ! 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 ! 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 ! 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 ! 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 ! 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 ! 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 ! TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a,trunc_b; -- ok ! -- circular references ! ALTER TABLE truncate_a ADD FOREIGN KEY (col1) REFERENCES trunc_c; ! -- Add some data to verify that truncating actually works ... ! 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; ! 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 ! 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 ! 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 ! 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 ! TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a,trunc_b; ! -- Verify that truncating did actually work ! 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 ! NOTICE: drop cascades to constraint trunc_e_b_fkey on table trunc_e ! NOTICE: drop cascades to constraint trunc_d_a_fkey on table trunc_d Index: src/test/regress/sql/temp.sql =================================================================== RCS file: /cvsroot/pgsql/src/test/regress/sql/temp.sql,v retrieving revision 1.5 diff -c -c -b -r1.5 temp.sql *** src/test/regress/sql/temp.sql 14 May 2003 03:26:03 -0000 1.5 --- src/test/regress/sql/temp.sql 6 Nov 2004 05:57:41 -0000 *************** *** 83,85 **** --- 83,97 ---- -- ON COMMIT is only allowed for TEMP CREATE TABLE temptest(col int) ON COMMIT DELETE ROWS; + + -- Test foreign keys + BEGIN; + + CREATE TEMP TABLE temptest1(col int PRIMARY KEY) ON COMMIT DELETE ROWS; + CREATE TEMP TABLE temptest2(col int REFERENCES temptest1) + ON COMMIT DELETE ROWS; + INSERT INTO temptest1 VALUES (1); + INSERT INTO temptest2 VALUES (1); + COMMIT; + SELECT * FROM temptest1; + SELECT * FROM temptest2; Index: src/test/regress/sql/truncate.sql =================================================================== RCS file: /cvsroot/pgsql/src/test/regress/sql/truncate.sql,v retrieving revision 1.2 diff -c -c -b -r1.2 truncate.sql *** src/test/regress/sql/truncate.sql 23 Nov 2002 04:05:52 -0000 1.2 --- src/test/regress/sql/truncate.sql 6 Nov 2004 05:57:42 -0000 *************** *** 14,25 **** COMMIT; 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; --- 14,58 ---- COMMIT; SELECT * FROM truncate_a; ! -- Test foreign-key checks ! CREATE TABLE trunc_b (a int REFERENCES truncate_a); ! CREATE TABLE trunc_c (a serial PRIMARY KEY); ! CREATE TABLE trunc_d (a int REFERENCES trunc_c); ! CREATE TABLE trunc_e (a int REFERENCES truncate_a, b int REFERENCES trunc_c); ! ! TRUNCATE TABLE truncate_a; -- fail ! TRUNCATE TABLE truncate_a,trunc_b; -- fail ! TRUNCATE TABLE truncate_a,trunc_b,trunc_e; -- ok ! TRUNCATE TABLE truncate_a,trunc_e; -- fail ! TRUNCATE TABLE trunc_c; -- fail ! TRUNCATE TABLE trunc_c,trunc_d; -- fail ! 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 ! ! -- circular references ! ALTER TABLE truncate_a ADD FOREIGN KEY (col1) REFERENCES trunc_c; ! ! -- Add some data to verify that truncating actually works ... ! 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; ! TRUNCATE TABLE trunc_c,trunc_d; ! TRUNCATE TABLE trunc_c,trunc_d,trunc_e; ! TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a; ! TRUNCATE TABLE trunc_c,trunc_d,trunc_e,truncate_a,trunc_b; ! ! -- Verify that truncating did actually work ! 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;