Index: doc/src/sgml/ref/truncate.sgml =================================================================== RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/ref/truncate.sgml,v retrieving revision 1.17 diff -c -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 01:20:19 -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: /home/alvherre/cvs/pgsql/src/backend/catalog/heap.c,v retrieving revision 1.279 diff -c -r1.279 heap.c *** src/backend/catalog/heap.c 10 Jan 2005 20:02:19 -0000 1.279 --- src/backend/catalog/heap.c 20 Jan 2005 19:30:51 -0000 *************** *** 1985,2083 **** /* * 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 ! * dirty, they're just dropped without bothering to flush to disk. */ ! DropRelationBuffers(rel); ! /* Now truncate the actual data */ ! 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, - ObjectIdGetDatum(relid)); - fkeyScan = systable_beginscan(fkeyRel, NULL, false, ! SnapshotNow, 1, &key); while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan))) { 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); --- 1985,2150 ---- /* * 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/tablecmds.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, true); ! ! foreach (cell, relations) ! { ! Relation rel = lfirst(cell); ! Oid toastrelid; ! ! /* ! * Release any buffers associated with this relation. If they're ! * dirty, they're just dropped without bothering to flush to disk. ! */ ! DropRelationBuffers(rel); ! ! /* Now truncate the actual data */ ! 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. ! * ! * tempTables is only used to produce the correct error message. */ void ! heap_truncate_check_FKs(List *relations, bool tempTables) { ! List *rels = NIL; ! List *oids = NIL; ! ListCell *cell; Relation fkeyRel; SysScanDesc fkeyScan; HeapTuple tuple; /* ! * 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, it is a seqscan * because there is no available index on confrelid. */ fkeyRel = heap_openr(ConstraintRelationName, AccessShareLock); fkeyScan = systable_beginscan(fkeyRel, NULL, 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 in our list of tables */ ! if (! list_member_oid(oids, con->confrelid)) ! continue; ! ! /* The referencer should be in our list too */ ! if (! list_member_oid(oids, con->conrelid)) ! { ! if (tempTables) ! ereport(ERROR, ! (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("invalid ON COMMIT and foreign key combination"), ! errdetail("Table \"%s\" references \"%s\", but they don't have the same ON COMMIT setting", ! get_rel_name(con->conrelid), ! get_rel_name(con->confrelid)))); ! else ! 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), ! get_rel_name(con->confrelid), ! NameStr(con->conname)), ! errhint("Truncate table \"%s\" at the same time", ! get_rel_name(con->conrelid)))); ! } } systable_endscan(fkeyScan); Index: src/backend/commands/tablecmds.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/commands/tablecmds.c,v retrieving revision 1.142 diff -c -r1.142 tablecmds.c *** src/backend/commands/tablecmds.c 10 Jan 2005 20:02:20 -0000 1.142 --- src/backend/commands/tablecmds.c 20 Jan 2005 19:31:35 -0000 *************** *** 524,611 **** } /* ! * 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) ! ereport(ERROR, ! (errcode(ERRCODE_WRONG_OBJECT_TYPE), ! errmsg("\"%s\" is not a table", ! RelationGetRelationName(rel)))); ! /* Permissions checks */ ! if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) ! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, ! RelationGetRelationName(rel)); ! if (!allowSystemTableMods && IsSystemRelation(rel)) ! ereport(ERROR, ! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), ! errmsg("permission denied: \"%s\" is a system catalog", ! RelationGetRelationName(rel)))); ! ! /* ! * We can never allow truncation of shared or nailed-in-cache ! * relations, because we can't support changing their relfilenode ! * values. ! */ ! if (rel->rd_rel->relisshared || rel->rd_isnailed) ! ereport(ERROR, ! (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("cannot truncate system relation \"%s\"", ! RelationGetRelationName(rel)))); ! /* ! * Don't allow truncate on temp tables of other backends ... their ! * local buffer manager is not going to cope. ! */ ! if (isOtherTempNamespace(RelationGetNamespace(rel))) ! ereport(ERROR, ! (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); ! heap_relid = RelationGetRelid(rel); ! toast_relid = rel->rd_rel->reltoastrelid; ! heap_close(rel, NoLock); /* ! * The same for the toast table, if any. */ ! if (OidIsValid(toast_relid)) { ! rel = relation_open(toast_relid, AccessExclusiveLock); setNewRelfilenode(rel); heap_close(rel, NoLock); - } ! /* ! * Reconstruct the indexes to match, and we're done. ! */ ! reindex_relation(heap_relid, true); } /*---------- --- 524,633 ---- } /* ! * 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) ! ereport(ERROR, ! (errcode(ERRCODE_WRONG_OBJECT_TYPE), ! errmsg("\"%s\" is not a table", ! RelationGetRelationName(rel)))); ! /* Permissions checks */ ! if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) ! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, ! RelationGetRelationName(rel)); ! if (!allowSystemTableMods && IsSystemRelation(rel)) ! ereport(ERROR, ! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), ! errmsg("permission denied: \"%s\" is a system catalog", ! RelationGetRelationName(rel)))); ! /* ! * We can never allow truncation of shared or nailed-in-cache ! * relations, because we can't support changing their relfilenode ! * values. ! */ ! if (rel->rd_rel->relisshared || rel->rd_isnailed) ! ereport(ERROR, ! (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), ! errmsg("cannot truncate system relation \"%s\"", ! RelationGetRelationName(rel)))); ! /* ! * Don't allow truncate on temp tables of other backends ... their ! * local buffer manager is not going to cope. ! */ ! if (isOtherTempNamespace(RelationGetNamespace(rel))) ! 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. */ ! heap_truncate_check_FKs(rels, false); ! ! 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); + + heap_relid = RelationGetRelid(rel); + toast_relid = rel->rd_rel->reltoastrelid; + heap_close(rel, NoLock); ! /* ! * The same for the toast table, if any. ! */ ! if (OidIsValid(toast_relid)) ! { ! rel = relation_open(toast_relid, AccessExclusiveLock); ! setNewRelfilenode(rel); ! heap_close(rel, NoLock); ! } ! ! /* ! * Reconstruct the indexes to match, and we're done. ! */ ! reindex_relation(heap_relid, true); ! } } /*---------- *************** *** 5984,5989 **** --- 6006,6012 ---- PreCommit_on_commit_actions(void) { ListCell *l; + List *oids_to_truncate = NIL; foreach(l, on_commits) { *************** *** 6000,6007 **** /* 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: { --- 6023,6029 ---- /* 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: { *************** *** 6022,6027 **** --- 6044,6052 ---- } } } + if (list_length(oids_to_truncate) > 0) + heap_truncate(oids_to_truncate); + CommandCounterIncrement(); /* XXX needed? */ } /* Index: src/backend/nodes/copyfuncs.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/nodes/copyfuncs.c,v retrieving revision 1.295 diff -c -r1.295 copyfuncs.c *** src/backend/nodes/copyfuncs.c 31 Dec 2004 21:59:55 -0000 1.295 --- src/backend/nodes/copyfuncs.c 10 Jan 2005 23:29:34 -0000 *************** *** 1815,1821 **** { TruncateStmt *newnode = makeNode(TruncateStmt); ! COPY_NODE_FIELD(relation); return newnode; } --- 1815,1821 ---- { TruncateStmt *newnode = makeNode(TruncateStmt); ! COPY_NODE_FIELD(relations); return newnode; } Index: src/backend/nodes/equalfuncs.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/nodes/equalfuncs.c,v retrieving revision 1.234 diff -c -r1.234 equalfuncs.c *** src/backend/nodes/equalfuncs.c 31 Dec 2004 21:59:55 -0000 1.234 --- src/backend/nodes/equalfuncs.c 10 Jan 2005 23:29:35 -0000 *************** *** 891,897 **** static bool _equalTruncateStmt(TruncateStmt *a, TruncateStmt *b) { ! COMPARE_NODE_FIELD(relation); return true; } --- 891,897 ---- static bool _equalTruncateStmt(TruncateStmt *a, TruncateStmt *b) { ! COMPARE_NODE_FIELD(relations); return true; } Index: src/backend/parser/gram.y =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/parser/gram.y,v retrieving revision 2.481 diff -c -r2.481 gram.y *** src/backend/parser/gram.y 31 Dec 2004 22:00:27 -0000 2.481 --- src/backend/parser/gram.y 10 Jan 2005 23:29:35 -0000 *************** *** 2681,2695 **** /***************************************************************************** * * QUERY: ! * truncate table relname * *****************************************************************************/ TruncateStmt: ! TRUNCATE opt_table qualified_name { TruncateStmt *n = makeNode(TruncateStmt); ! n->relation = $3; $$ = (Node *)n; } ; --- 2681,2695 ---- /***************************************************************************** * * 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: /home/alvherre/cvs/pgsql/src/backend/tcop/utility.c,v retrieving revision 1.231 diff -c -r1.231 utility.c *** src/backend/tcop/utility.c 31 Dec 2004 22:01:16 -0000 1.231 --- src/backend/tcop/utility.c 10 Jan 2005 23:29:38 -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: /home/alvherre/cvs/pgsql/src/include/catalog/heap.h,v retrieving revision 1.72 diff -c -r1.72 heap.h *** src/include/catalog/heap.h 31 Dec 2004 22:03:24 -0000 1.72 --- src/include/catalog/heap.h 20 Jan 2005 19:31:10 -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, bool tempTables); extern List *AddRelationRawConstraints(Relation rel, List *rawColDefaults, Index: src/include/commands/tablecmds.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/commands/tablecmds.h,v retrieving revision 1.21 diff -c -r1.21 tablecmds.h *** src/include/commands/tablecmds.h 31 Dec 2004 22:03:28 -0000 1.21 --- src/include/commands/tablecmds.h 10 Jan 2005 23:29:46 -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: /home/alvherre/cvs/pgsql/src/include/nodes/parsenodes.h,v retrieving revision 1.271 diff -c -r1.271 parsenodes.h *** src/include/nodes/parsenodes.h 31 Dec 2004 22:03:34 -0000 1.271 --- src/include/nodes/parsenodes.h 10 Jan 2005 23:29:47 -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: /home/alvherre/cvs/pgsql/src/test/regress/expected/temp.out,v retrieving revision 1.9 diff -c -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 23 Jan 2005 21:42:34 -0000 *************** *** 82,84 **** --- 82,111 ---- -- 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); + 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 + ----- + 1 + (1 row) + + SELECT * FROM temptest2; + col + ----- + (0 rows) + + BEGIN; + CREATE TEMP TABLE temptest3(col int PRIMARY KEY) ON COMMIT DELETE ROWS; + NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "temptest3_pkey" for table "temptest3" + CREATE TEMP TABLE temptest4(col int REFERENCES temptest3); + COMMIT; + ERROR: invalid ON COMMIT and foreign key combination + DETAIL: Table "temptest4" references "temptest3", but they don't have the same ON COMMIT setting Index: src/test/regress/expected/truncate.out =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/test/regress/expected/truncate.out,v retrieving revision 1.9 diff -c -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 04:43:24 -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: /home/alvherre/cvs/pgsql/src/test/regress/sql/temp.sql,v retrieving revision 1.5 diff -c -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 23 Jan 2005 21:40:28 -0000 *************** *** 83,85 **** --- 83,101 ---- -- 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); + 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; + + BEGIN; + CREATE TEMP TABLE temptest3(col int PRIMARY KEY) ON COMMIT DELETE ROWS; + CREATE TEMP TABLE temptest4(col int REFERENCES temptest3); + COMMIT; Index: src/test/regress/sql/truncate.sql =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/test/regress/sql/truncate.sql,v retrieving revision 1.2 diff -c -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 04:42:24 -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;