Add code to handle [ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP }]

for temp tables.

Gavin Sherry
This commit is contained in:
Bruce Momjian 2002-11-09 23:56:39 +00:00
parent f2ef470196
commit ebb531836a
13 changed files with 371 additions and 25 deletions

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_table.sgml,v 1.56 2002/09/02 06:20:53 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_table.sgml,v 1.57 2002/11/09 23:56:38 momjian Exp $
PostgreSQL documentation
-->
@ -21,7 +21,7 @@ CREATE [ [ LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable class="PARAMETER">t
| <replaceable>table_constraint</replaceable> } [, ... ]
)
[ INHERITS ( <replaceable>parent_table</replaceable> [, ... ] ) ]
[ WITH OIDS | WITHOUT OIDS ]
[ WITH OIDS | WITHOUT OIDS ] [ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
where <replaceable class="PARAMETER">column_constraint</replaceable> is:
@ -107,10 +107,11 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
<para>
If specified, the table is created as a temporary table.
Temporary tables are automatically dropped at the end of a
session. Existing permanent tables with the same name are not
visible to the current session while the temporary table exists,
unless they are referenced with schema-qualified names.
Any indexes created on a temporary table are automatically
session or optionally at the end of the current transaction
(See ON COMMIT below). Existing permanent tables with the same
name are not visible to the current session while the temporary
table exists, unless they are referenced with schema-qualified
names. Any indexes created on a temporary table are automatically
temporary as well.
</para>
@ -487,9 +488,54 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>ON COMMIT</literal></term>
<listitem>
<para>
The behaviour of temporary tables at the end of a transaction
block can be controlled using <literal>ON COMMIT</literal>.
The table will exhibit the same behavior at the end of
transaction blocks for the duration of the session unless
ON COMMIT DROP is specified or the temporary table is dropped.
</para>
<para>
The three parameters to ON COMMIT are:
<variablelist>
<varlistentry>
<term><literal>PRESERVE ROWS</literal></term>
<listitem>
<para>
The rows in the temporary table will persist after the
transaction block.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>DELETE ROWS</literal></term>
<listitem>
<para>
All rows in the temporary table will be deleted at the
end of the transaction block.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>DROP</literal></term>
<listitem>
<para>
The temporary table will be dropped at the end of the transaction.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.135 2002/10/22 22:44:36 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.136 2002/11/09 23:56:38 momjian Exp $
*
* NOTES
* Transaction aborts can now occur two ways:
@ -166,6 +166,7 @@
#include "catalog/index.h"
#include "catalog/namespace.h"
#include "commands/async.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
#include "commands/user.h"
#include "executor/spi.h"
@ -1026,6 +1027,7 @@ CommitTransaction(void)
AtEOXact_hash();
AtEOXact_nbtree();
AtEOXact_rtree();
AtEOXact_temp_relations(true,s->blockState);
AtEOXact_Namespace(true);
AtEOXact_CatCache(true);
AtEOXact_Files();
@ -1136,6 +1138,7 @@ AbortTransaction(void)
AtEOXact_hash();
AtEOXact_nbtree();
AtEOXact_rtree();
AtEOXact_temp_relations(false,s->blockState);
AtEOXact_Namespace(false);
AtEOXact_CatCache(false);
AtEOXact_Files();

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.53 2002/11/01 22:52:33 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootparse.y,v 1.54 2002/11/09 23:56:38 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -34,6 +34,7 @@
#include "catalog/pg_class.h"
#include "catalog/pg_namespace.h"
#include "commands/defrem.h"
#include "commands/tablecmds.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodes.h"
@ -197,6 +198,7 @@ Boot_CreateStmt:
tupdesc,
RELKIND_RELATION,
$3,
ATEOXACTNOOP,
true);
elog(DEBUG3, "relation created with oid %u", id);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.232 2002/10/21 22:06:18 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.233 2002/11/09 23:56:39 momjian Exp $
*
*
* INTERFACE ROUTINES
@ -31,17 +31,20 @@
#include "access/heapam.h"
#include "access/genam.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/catname.h"
#include "catalog/dependency.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_inherits.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
#include "commands/tablecmds.h"
#include "commands/trigger.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
@ -670,12 +673,14 @@ AddNewRelationType(const char *typeName,
* creates a new cataloged relation. see comments above.
* --------------------------------
*/
Oid
heap_create_with_catalog(const char *relname,
Oid relnamespace,
TupleDesc tupdesc,
char relkind,
bool shared_relation,
char ateoxact, /* Only used for temp relations */
bool allow_system_table_mods)
{
Relation pg_class_desc;
@ -717,6 +722,25 @@ heap_create_with_catalog(const char *relname,
/* Assign an OID for the relation's tuple type */
new_type_oid = newoid();
/*
* Add to temprels if we are a temp relation now that we have oid
*/
if(isTempNamespace(relnamespace)) {
TempTable *t;
MemoryContext oldcxt;
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
t = (TempTable *) palloc(sizeof(TempTable));
t->relid = new_rel_oid;
t->ateoxact = ateoxact;
t->tid = GetCurrentTransactionId();
t->dead = false;
reg_temp_rel(t);
MemoryContextSwitchTo(oldcxt);
}
/*
* now create an entry in pg_class for the relation.
*
@ -1147,6 +1171,14 @@ heap_drop_with_catalog(Oid rid)
rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE)
smgrunlink(DEFAULT_SMGR, rel);
/*
* Keep temprels up to date so that we don't have ON COMMIT execution
* problems at the end of the next transaction block
*/
if(isTempNamespace(RelationGetNamespace(rel)))
rm_temp_rel(rid);
/*
* Close relcache entry, but *keep* AccessExclusiveLock on the
* relation until transaction commit. This ensures no one else will

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.38 2002/11/02 18:41:21 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.39 2002/11/09 23:56:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -34,6 +34,7 @@
#include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
#include "catalog/pg_type.h"
#include "commands/tablecmds.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
@ -1670,6 +1671,7 @@ RemoveTempRelationsCallback(void)
CommitTransactionCommand(true);
}
free_temp_rels();
}

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.91 2002/11/02 21:20:40 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.92 2002/11/09 23:56:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -25,6 +25,7 @@
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/catname.h"
#include "catalog/namespace.h"
#include "commands/cluster.h"
#include "commands/tablecmds.h"
#include "miscadmin.h"
@ -203,6 +204,7 @@ make_new_heap(Oid OIDOldHeap, const char *NewName)
tupdesc,
OldHeap->rd_rel->relkind,
OldHeap->rd_rel->relisshared,
ATEOXACTNOOP,
allowSystemTableMods);
/*

View File

@ -8,12 +8,13 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.51 2002/11/02 22:02:08 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.52 2002/11/09 23:56:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/xact.h"
#include "access/genam.h"
#include "access/tuptoaster.h"
#include "catalog/catalog.h"
@ -48,9 +49,10 @@
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/relcache.h"
#include "utils/syscache.h"
static List *temprels = NIL;
static List *MergeAttributes(List *schema, List *supers, bool istemp,
List **supOids, List **supconstr, bool *supHasOids);
@ -116,6 +118,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
int i;
AttrNumber attnum;
/*
* Truncate relname to appropriate length (probably a waste of time,
* as parser should have done this already).
@ -222,6 +225,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
descriptor,
relkind,
false,
stmt->ateoxact,
allowSystemTableMods);
StoreCatalogInheritance(relationId, inheritOids);
@ -3783,11 +3787,18 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
* when its master is, so there's no need to handle the toast rel as
* temp.
*/
/*
* Pass ATEOXACTNOOP for ateoxact since we want heap_drop_with_catalog()
* to remove TOAST tables for temp tables, not AtEOXact_temp_relations()
*/
toast_relid = heap_create_with_catalog(toast_relname,
PG_TOAST_NAMESPACE,
tupdesc,
RELKIND_TOASTVALUE,
shared_relation,
ATEOXACTNOOP,
true);
/* make the toast relation visible, else index creation will fail */
@ -3922,3 +3933,206 @@ needs_toast_table(Relation rel)
MAXALIGN(data_length);
return (tuple_length > TOAST_TUPLE_THRESHOLD);
}
/*
* To handle ON COMMIT { DROP | PRESERVE ROWS | DELETE ROWS }
*/
void
AtEOXact_temp_relations(bool iscommit, int bstate)
{
List *l,
*prev;
MemoryContext oldctx;
if (temprels == NIL)
return;
/*
* These loops are tricky because we are removing items from the List
* while we are traversing it.
*/
/* Remove 'dead' entries on commit and clear 'dead' status on abort */
l = temprels;
prev = NIL;
while (l != NIL)
{
TempTable *t = lfirst(l);
if (t->dead)
{
if (iscommit)
{
/* Remove from temprels, since the user has DROP'd */
oldctx = MemoryContextSwitchTo(CacheMemoryContext);
if (prev == NIL)
{
pfree(t);
temprels = lnext(l);
pfree(l);
l = temprels;
}
else
{
pfree(t);
lnext(prev) = lnext(l);
pfree(l);
l = lnext(prev);
}
MemoryContextSwitchTo(oldctx);
continue;
}
else
/* user dropped but now we're aborted */
t->dead = false;
}
prev = l;
l = lnext(l);
}
if ((iscommit && bstate != TBLOCK_END) ||
(!iscommit && bstate != TBLOCK_ABORT))
return;
/* Perform per-xact actions */
l = temprels;
prev = NIL;
if (iscommit)
{
while (l != NIL)
{
TempTable *t = lfirst(l);
if (t->ateoxact == ATEOXACTDROP)
{
ObjectAddress object;
object.classId = RelOid_pg_class;
object.objectId = t->relid;
object.objectSubId = 0;
performDeletion(&object, DROP_CASCADE);
oldctx = MemoryContextSwitchTo(CacheMemoryContext);
if (prev == NIL)
{
pfree(t);
temprels = lnext(l);
pfree(l);
l = temprels;
}
else
{
pfree(t);
lnext(prev) = lnext(l);
pfree(l);
l = lnext(prev);
}
MemoryContextSwitchTo(oldctx);
CommandCounterIncrement();
continue;
}
else if (t->ateoxact == ATEOXACTDELETE)
{
heap_truncate(t->relid);
CommandCounterIncrement();
}
prev = l;
l = lnext(l);
}
}
else
{
/* Abort --- remove entries added by this xact */
TransactionId curtid = GetCurrentTransactionId();
oldctx = MemoryContextSwitchTo(CacheMemoryContext);
while (l != NIL)
{
TempTable *t = lfirst(l);
if (t->tid == curtid)
{
if (prev == NIL)
{
pfree(t);
temprels = lnext(l);
pfree(l);
l = temprels;
}
else
{
pfree(t);
lnext(prev) = lnext(l);
pfree(l);
l = lnext(prev);
}
continue;
}
prev = l;
l = lnext(l);
}
MemoryContextSwitchTo(oldctx);
}
}
/*
* Register a temp rel in temprels
*/
void
reg_temp_rel(TempTable * t)
{
temprels = lcons(t, temprels);
}
/*
* return the ON COMMIT/ateoxact value for a given temp rel
*/
void
free_temp_rels(void)
{
MemoryContext oldctx;
oldctx = MemoryContextSwitchTo(CacheMemoryContext);
while (temprels != NIL)
{
List *l = temprels;
temprels = lnext(temprels);
pfree(lfirst(l));
pfree(l);
}
MemoryContextSwitchTo(oldctx);
}
/*
* Remove (actually just mark for deletion, in case we abort)
* Relid from the temprels list
*/
void
rm_temp_rel(Oid relid)
{
List *l;
foreach(l, temprels)
{
TempTable *t = lfirst(l);
if (t->relid == relid)
{
t->dead = true;
return;
}
}
/* If we get here, we're in trouble */
Assert(1==1);
}

View File

@ -27,7 +27,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.180 2002/10/14 16:51:30 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.181 2002/11/09 23:56:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -732,6 +732,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate)
tupdesc,
RELKIND_RELATION,
false,
ATEOXACTNOOP,
allowSystemTableMods);
FreeTupleDesc(tupdesc);

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.373 2002/11/02 18:41:21 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.374 2002/11/09 23:56:39 momjian Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -54,6 +54,7 @@
#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
#include "commands/tablecmds.h"
#include "nodes/makefuncs.h"
#include "nodes/params.h"
#include "nodes/parsenodes.h"
@ -224,6 +225,7 @@ static void doNegateFloat(Value *v);
%type <typnam> func_arg func_return func_type aggr_argtype
%type <boolean> opt_arg TriggerForType OptTemp OptWithOids
%type <chr> OptEOXact
%type <list> for_update_clause opt_for_update_clause update_list
%type <boolean> opt_all
@ -370,10 +372,11 @@ static void doNegateFloat(Value *v);
ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNER
PARTIAL PASSWORD PATH_P PENDANT PLACING POSITION
PRECISION PREPARE PRIMARY PRIOR PRIVILEGES PROCEDURAL PROCEDURE
PRECISION PRESERVE PREPARE PRIMARY PRIOR PRIVILEGES PROCEDURAL
PROCEDURE
READ REAL RECHECK REFERENCES REINDEX RELATIVE RENAME REPLACE
RESET RESTRICT RETURNS REVOKE RIGHT ROLLBACK ROW
RESET RESTRICT RETURNS REVOKE RIGHT ROLLBACK ROW ROWS
RULE
SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
@ -1372,15 +1375,20 @@ opt_using:
*****************************************************************************/
CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
OptInherit OptWithOids
OptInherit OptWithOids OptEOXact
{
CreateStmt *n = makeNode(CreateStmt);
if($2 == FALSE && $10 != ATEOXACTNOOP)
elog(ERROR,"ON COMMIT can only be used on TEMP tables");
$4->istemp = $2;
n->relation = $4;
n->tableElts = $6;
n->inhRelations = $8;
n->constraints = NIL;
n->hasoids = $9;
n->ateoxact = $10;
$$ = (Node *)n;
}
| CREATE OptTemp TABLE qualified_name OF qualified_name
@ -1799,7 +1807,11 @@ OptWithOids:
| /*EMPTY*/ { $$ = TRUE; }
;
OptEOXact: ON COMMIT DROP { $$ = ATEOXACTDROP; }
| ON COMMIT DELETE_P ROWS { $$ = ATEOXACTDELETE; }
| ON COMMIT PRESERVE ROWS { $$ = ATEOXACTPRESERVE; }
| /*EMPTY*/ { $$ = ATEOXACTNOOP; }
;
/*
* Note: CREATE TABLE ... AS SELECT ... is just another spelling for
* SELECT ... INTO.
@ -7074,6 +7086,7 @@ unreserved_keyword:
| PENDANT
| PRECISION
| PREPARE
| PRESERVE
| PRIOR
| PRIVILEGES
| PROCEDURAL
@ -7089,6 +7102,7 @@ unreserved_keyword:
| RETURNS
| REVOKE
| ROLLBACK
| ROWS
| RULE
| SCHEMA
| SCROLL

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.127 2002/09/18 21:35:22 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.128 2002/11/09 23:56:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -232,6 +232,7 @@ static const ScanKeyword ScanKeywords[] = {
{"position", POSITION},
{"precision", PRECISION},
{"prepare", PREPARE},
{"preserve", PRESERVE},
{"primary", PRIMARY},
{"prior", PRIOR},
{"privileges", PRIVILEGES},
@ -252,6 +253,7 @@ static const ScanKeyword ScanKeywords[] = {
{"right", RIGHT},
{"rollback", ROLLBACK},
{"row", ROW},
{"rows",ROWS},
{"rule", RULE},
{"schema", SCHEMA},
{"scroll", SCROLL},

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: heap.h,v 1.57 2002/09/04 20:31:37 momjian Exp $
* $Id: heap.h,v 1.58 2002/11/09 23:56:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -41,6 +41,7 @@ extern Oid heap_create_with_catalog(const char *relname,
TupleDesc tupdesc,
char relkind,
bool shared_relation,
char ateoxact,
bool allow_system_table_mods);
extern void heap_drop_with_catalog(Oid rid);

View File

@ -7,13 +7,14 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: tablecmds.h,v 1.8 2002/10/21 20:31:52 momjian Exp $
* $Id: tablecmds.h,v 1.9 2002/11/09 23:56:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef TABLECMDS_H
#define TABLECMDS_H
#include "access/htup.h"
#include "nodes/parsenodes.h"
extern void AlterTableAddColumn(Oid myrelid, bool recurse, ColumnDef *colDef);
@ -62,4 +63,29 @@ extern void renameatt(Oid myrelid,
extern void renamerel(Oid myrelid,
const char *newrelname);
/*
* Temp rel stuff
*/
typedef struct TempTable
{
Oid relid; /* relid of temp relation */
char ateoxact; /* what to do at end of xact */
TransactionId tid; /* trans id where in rel was created */
bool dead; /* table was dropped in the current xact */
} TempTable;
extern void AtEOXact_temp_relations(bool iscommit, int bstate);
extern void reg_temp_rel(TempTable *t);
extern void free_temp_rels(void);
extern void rm_temp_rel(Oid relid);
/*
* What to do at commit time for temporary relations
*/
#define ATEOXACTNOOP 0 /* no operation at commit */
#define ATEOXACTPRESERVE 1 /* preserve rows */
#define ATEOXACTDELETE 2 /* delete rows */
#define ATEOXACTDROP 3 /* drop temp table */
#endif /* TABLECMDS_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parsenodes.h,v 1.210 2002/11/06 00:00:44 tgl Exp $
* $Id: parsenodes.h,v 1.211 2002/11/09 23:56:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -919,6 +919,7 @@ typedef struct CreateStmt
List *inhRelations; /* relations to inherit from */
List *constraints; /* constraints (list of Constraint nodes) */
bool hasoids; /* should it have OIDs? */
char ateoxact; /* what do we do at COMMIT for TEMP ? */
} CreateStmt;
/* ----------