Commit 3908473c authored by Tom Lane's avatar Tom Lane

Make DROP TABLE rollback-able: postpone physical file delete until commit.

(WAL logging for this is not done yet, however.)  Clean up a number of really
crufty things that are no longer needed now that DROP behaves nicely.  Make
temp table mapper do the right things when drop or rename affecting a temp
table is rolled back.  Also, remove "relation modified while in use" error
check, in favor of locking tables at first reference and holding that lock
throughout the statement.
parent ebe0b236
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.67 2000/10/05 19:48:20 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.68 2000/11/08 22:09:53 tgl Exp $
* *
* NOTES * NOTES
* some of the executor utility code such as "ExecTypeFromTL" should be * some of the executor utility code such as "ExecTypeFromTL" should be
...@@ -228,7 +228,9 @@ FreeTupleDesc(TupleDesc tupdesc) ...@@ -228,7 +228,9 @@ FreeTupleDesc(TupleDesc tupdesc)
bool bool
equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
{ {
int i; int i,
j,
n;
if (tupdesc1->natts != tupdesc2->natts) if (tupdesc1->natts != tupdesc2->natts)
return false; return false;
...@@ -240,7 +242,9 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) ...@@ -240,7 +242,9 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
/* /*
* We do not need to check every single field here, and in fact * We do not need to check every single field here, and in fact
* some fields such as attdispersion probably shouldn't be * some fields such as attdispersion probably shouldn't be
* compared. * compared. We can also disregard attnum (it was used to
* place the row in the attrs array) and everything derived
* from the column datatype.
*/ */
if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0) if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
return false; return false;
...@@ -260,32 +264,53 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) ...@@ -260,32 +264,53 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
if (constr2 == NULL) if (constr2 == NULL)
return false; return false;
if (constr1->num_defval != constr2->num_defval) if (constr1->has_not_null != constr2->has_not_null)
return false;
n = constr1->num_defval;
if (n != (int) constr2->num_defval)
return false; return false;
for (i = 0; i < (int) constr1->num_defval; i++) for (i = 0; i < n; i++)
{ {
AttrDefault *defval1 = constr1->defval + i; AttrDefault *defval1 = constr1->defval + i;
AttrDefault *defval2 = constr2->defval + i; AttrDefault *defval2 = constr2->defval;
if (defval1->adnum != defval2->adnum) /*
* We can't assume that the items are always read from the
* system catalogs in the same order; so use the adnum field to
* identify the matching item to compare.
*/
for (j = 0; j < n; defval2++, j++)
{
if (defval1->adnum == defval2->adnum)
break;
}
if (j >= n)
return false; return false;
if (strcmp(defval1->adbin, defval2->adbin) != 0) if (strcmp(defval1->adbin, defval2->adbin) != 0)
return false; return false;
} }
if (constr1->num_check != constr2->num_check) n = constr1->num_check;
if (n != (int) constr2->num_check)
return false; return false;
for (i = 0; i < (int) constr1->num_check; i++) for (i = 0; i < n; i++)
{ {
ConstrCheck *check1 = constr1->check + i; ConstrCheck *check1 = constr1->check + i;
ConstrCheck *check2 = constr2->check + i; ConstrCheck *check2 = constr2->check;
if (strcmp(check1->ccname, check2->ccname) != 0) /*
return false; * Similarly, don't assume that the checks are always read
if (strcmp(check1->ccbin, check2->ccbin) != 0) * in the same order; match them up by name and contents.
* (The name *should* be unique, but...)
*/
for (j = 0; j < n; check2++, j++)
{
if (strcmp(check1->ccname, check2->ccname) == 0 &&
strcmp(check1->ccbin, check2->ccbin) == 0)
break;
}
if (j >= n)
return false; return false;
} }
if (constr1->has_not_null != constr2->has_not_null)
return false;
} }
else if (tupdesc2->constr != NULL) else if (tupdesc2->constr != NULL)
return false; return false;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.63 2000/10/21 15:43:09 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.64 2000/11/08 22:09:53 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -266,13 +266,12 @@ gistbuild(PG_FUNCTION_ARGS) ...@@ -266,13 +266,12 @@ gistbuild(PG_FUNCTION_ARGS)
{ {
Oid hrelid = RelationGetRelid(heap); Oid hrelid = RelationGetRelid(heap);
Oid irelid = RelationGetRelid(index); Oid irelid = RelationGetRelid(index);
bool inplace = IsReindexProcessing();
heap_close(heap, NoLock); heap_close(heap, NoLock);
index_close(index); index_close(index);
UpdateStats(hrelid, nhtups, inplace); UpdateStats(hrelid, nhtups);
UpdateStats(irelid, nitups, inplace); UpdateStats(irelid, nitups);
if (oldPred != NULL && !inplace) if (oldPred != NULL)
{ {
if (nitups == nhtups) if (nitups == nhtups)
pred = NULL; pred = NULL;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.43 2000/10/21 15:43:11 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.44 2000/11/08 22:09:54 tgl Exp $
* *
* NOTES * NOTES
* This file contains only the public interface routines. * This file contains only the public interface routines.
...@@ -217,13 +217,12 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -217,13 +217,12 @@ hashbuild(PG_FUNCTION_ARGS)
{ {
Oid hrelid = RelationGetRelid(heap); Oid hrelid = RelationGetRelid(heap);
Oid irelid = RelationGetRelid(index); Oid irelid = RelationGetRelid(index);
bool inplace = IsReindexProcessing();
heap_close(heap, NoLock); heap_close(heap, NoLock);
index_close(index); index_close(index);
UpdateStats(hrelid, nhtups, inplace); UpdateStats(hrelid, nhtups);
UpdateStats(irelid, nitups, inplace); UpdateStats(irelid, nitups);
if (oldPred != NULL && !inplace) if (oldPred != NULL)
{ {
if (nitups == nhtups) if (nitups == nhtups)
pred = NULL; pred = NULL;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.92 2000/10/29 18:33:39 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.93 2000/11/08 22:09:54 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -780,19 +780,13 @@ heap_beginscan(Relation relation, ...@@ -780,19 +780,13 @@ heap_beginscan(Relation relation,
/* ---------------- /* ----------------
* increment relation ref count while scanning relation * increment relation ref count while scanning relation
* ----------------
*/
RelationIncrementReferenceCount(relation);
/* ----------------
* Acquire AccessShareLock for the duration of the scan
* *
* Note: we could get an SI inval message here and consequently have * This is just to make really sure the relcache entry won't go away
* to rebuild the relcache entry. The refcount increment above * while the scan has a pointer to it. Caller should be holding the
* ensures that we will rebuild it and not just flush it... * rel open anyway, so this is redundant in all normal scenarios...
* ---------------- * ----------------
*/ */
LockRelation(relation, AccessShareLock); RelationIncrementReferenceCount(relation);
/* XXX someday assert SelfTimeQual if relkind == RELKIND_UNCATALOGED */ /* XXX someday assert SelfTimeQual if relkind == RELKIND_UNCATALOGED */
if (relation->rd_rel->relkind == RELKIND_UNCATALOGED) if (relation->rd_rel->relkind == RELKIND_UNCATALOGED)
...@@ -809,13 +803,11 @@ heap_beginscan(Relation relation, ...@@ -809,13 +803,11 @@ heap_beginscan(Relation relation,
scan->rs_snapshot = snapshot; scan->rs_snapshot = snapshot;
scan->rs_nkeys = (short) nkeys; scan->rs_nkeys = (short) nkeys;
/*
* we do this here instead of in initscan() because heap_rescan
* also calls initscan() and we don't want to allocate memory again
*/
if (nkeys) if (nkeys)
/*
* we do this here instead of in initscan() because heap_rescan
* also calls initscan() and we don't want to allocate memory
* again
*/
scan->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys); scan->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
else else
scan->rs_key = NULL; scan->rs_key = NULL;
...@@ -841,8 +833,6 @@ heap_rescan(HeapScanDesc scan, ...@@ -841,8 +833,6 @@ heap_rescan(HeapScanDesc scan,
IncrHeapAccessStat(local_rescan); IncrHeapAccessStat(local_rescan);
IncrHeapAccessStat(global_rescan); IncrHeapAccessStat(global_rescan);
/* Note: set relation level read lock is still set */
/* ---------------- /* ----------------
* unpin scan buffers * unpin scan buffers
* ---------------- * ----------------
...@@ -853,7 +843,7 @@ heap_rescan(HeapScanDesc scan, ...@@ -853,7 +843,7 @@ heap_rescan(HeapScanDesc scan,
* reinitialize scan descriptor * reinitialize scan descriptor
* ---------------- * ----------------
*/ */
scan->rs_atend = (bool) scanFromEnd; scan->rs_atend = scanFromEnd;
initscan(scan, scan->rs_rd, scanFromEnd, scan->rs_nkeys, key); initscan(scan, scan->rs_rd, scanFromEnd, scan->rs_nkeys, key);
} }
...@@ -882,12 +872,6 @@ heap_endscan(HeapScanDesc scan) ...@@ -882,12 +872,6 @@ heap_endscan(HeapScanDesc scan)
*/ */
unpinscan(scan); unpinscan(scan);
/* ----------------
* Release AccessShareLock acquired by heap_beginscan()
* ----------------
*/
UnlockRelation(scan->rs_rd, AccessShareLock);
/* ---------------- /* ----------------
* decrement relation reference count and free scan descriptor storage * decrement relation reference count and free scan descriptor storage
* ---------------- * ----------------
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.69 2000/11/01 20:39:58 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.70 2000/11/08 22:09:55 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -340,19 +340,16 @@ btbuild(PG_FUNCTION_ARGS) ...@@ -340,19 +340,16 @@ btbuild(PG_FUNCTION_ARGS)
{ {
Oid hrelid = RelationGetRelid(heap); Oid hrelid = RelationGetRelid(heap);
Oid irelid = RelationGetRelid(index); Oid irelid = RelationGetRelid(index);
bool inplace = IsReindexProcessing();
heap_close(heap, NoLock); heap_close(heap, NoLock);
index_close(index); index_close(index);
UpdateStats(hrelid, nhtups);
UpdateStats(hrelid, nhtups, inplace); UpdateStats(irelid, nitups);
UpdateStats(irelid, nitups, inplace);
if (oldPred != NULL) if (oldPred != NULL)
{ {
if (nitups == nhtups) if (nitups == nhtups)
pred = NULL; pred = NULL;
if (!inplace) UpdateIndexPredicate(irelid, oldPred, pred);
UpdateIndexPredicate(irelid, oldPred, pred);
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.54 2000/10/21 15:43:20 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.55 2000/11/08 22:09:55 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -237,13 +237,12 @@ rtbuild(PG_FUNCTION_ARGS) ...@@ -237,13 +237,12 @@ rtbuild(PG_FUNCTION_ARGS)
{ {
Oid hrelid = RelationGetRelid(heap); Oid hrelid = RelationGetRelid(heap);
Oid irelid = RelationGetRelid(index); Oid irelid = RelationGetRelid(index);
bool inplace = IsReindexProcessing();
heap_close(heap, NoLock); heap_close(heap, NoLock);
index_close(index); index_close(index);
UpdateStats(hrelid, nhtups, inplace); UpdateStats(hrelid, nhtups);
UpdateStats(irelid, nitups, inplace); UpdateStats(irelid, nitups);
if (oldPred != NULL && !inplace) if (oldPred != NULL)
{ {
if (nitups == nhtups) if (nitups == nhtups)
pred = NULL; pred = NULL;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.31 2000/11/03 11:39:35 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.32 2000/11/08 22:09:55 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -130,7 +130,7 @@ VariableRelationPutNextXid(TransactionId xid) ...@@ -130,7 +130,7 @@ VariableRelationPutNextXid(TransactionId xid)
TransactionIdStore(xid, &(var->nextXidData)); TransactionIdStore(xid, &(var->nextXidData));
FlushBuffer(buf, TRUE); FlushBuffer(buf, true, true);
} }
/* -------------------------------- /* --------------------------------
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.80 2000/11/05 22:50:19 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.81 2000/11/08 22:09:55 tgl Exp $
* *
* NOTES * NOTES
* Transaction aborts can now occur two ways: * Transaction aborts can now occur two ways:
...@@ -167,6 +167,7 @@ ...@@ -167,6 +167,7 @@
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/proc.h" #include "storage/proc.h"
#include "storage/sinval.h" #include "storage/sinval.h"
#include "storage/smgr.h"
#include "utils/inval.h" #include "utils/inval.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "utils/portal.h" #include "utils/portal.h"
...@@ -1105,6 +1106,9 @@ CommitTransaction(void) ...@@ -1105,6 +1106,9 @@ CommitTransaction(void)
} }
RelationPurgeLocalRelation(true); RelationPurgeLocalRelation(true);
AtEOXact_temp_relations(true);
smgrDoPendingDeletes(true);
AtEOXact_SPI(); AtEOXact_SPI();
AtEOXact_nbtree(); AtEOXact_nbtree();
AtCommit_Cache(); AtCommit_Cache();
...@@ -1181,8 +1185,11 @@ AbortTransaction(void) ...@@ -1181,8 +1185,11 @@ AbortTransaction(void)
CloseSequences(); CloseSequences();
AtEOXact_portals(); AtEOXact_portals();
RecordTransactionAbort(); RecordTransactionAbort();
RelationPurgeLocalRelation(false); RelationPurgeLocalRelation(false);
remove_temp_rel_in_myxid(); AtEOXact_temp_relations(false);
smgrDoPendingDeletes(false);
AtEOXact_SPI(); AtEOXact_SPI();
AtEOXact_nbtree(); AtEOXact_nbtree();
AtAbort_Cache(); AtAbort_Cache();
......
...@@ -171,9 +171,8 @@ XLogOpenLogRelation(void) ...@@ -171,9 +171,8 @@ XLogOpenLogRelation(void)
sprintf(RelationGetPhysicalRelationName(logRelation), "pg_log"); sprintf(RelationGetPhysicalRelationName(logRelation), "pg_log");
logRelation->rd_node.tblNode = InvalidOid; logRelation->rd_node.tblNode = InvalidOid;
logRelation->rd_node.relNode = RelOid_pg_log; logRelation->rd_node.relNode = RelOid_pg_log;
logRelation->rd_unlinked = false; /* must exists */
logRelation->rd_fd = -1; logRelation->rd_fd = -1;
logRelation->rd_fd = smgropen(DEFAULT_SMGR, logRelation); logRelation->rd_fd = smgropen(DEFAULT_SMGR, logRelation, false);
if (logRelation->rd_fd < 0) if (logRelation->rd_fd < 0)
elog(STOP, "XLogOpenLogRelation: failed to open pg_log"); elog(STOP, "XLogOpenLogRelation: failed to open pg_log");
LogRelation = logRelation; LogRelation = logRelation;
...@@ -384,9 +383,9 @@ XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode) ...@@ -384,9 +383,9 @@ XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode)
hentry->rdesc = res; hentry->rdesc = res;
res->reldata.rd_unlinked = true; /* look smgropen */
res->reldata.rd_fd = -1; res->reldata.rd_fd = -1;
res->reldata.rd_fd = smgropen(DEFAULT_SMGR, &(res->reldata)); res->reldata.rd_fd = smgropen(DEFAULT_SMGR, &(res->reldata),
true /* allow failure */);
} }
res->moreRecently = &(_xlrelarr[0]); res->moreRecently = &(_xlrelarr[0]);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.96 2000/11/04 12:43:23 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.97 2000/11/08 22:09:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1151,7 +1151,7 @@ build_indices() ...@@ -1151,7 +1151,7 @@ build_indices()
* -mer * -mer
*/ */
if (!BootstrapAlreadySeen(RelationGetRelid(heap))) if (!BootstrapAlreadySeen(RelationGetRelid(heap)))
UpdateStats(RelationGetRelid(heap), 0, true); UpdateStats(RelationGetRelid(heap), 0);
/* XXX Probably we ought to close the heap and index here? */ /* XXX Probably we ought to close the heap and index here? */
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.150 2000/10/22 23:32:38 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.151 2000/11/08 22:09:56 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -289,8 +289,7 @@ heap_create(char *relname, ...@@ -289,8 +289,7 @@ heap_create(char *relname,
*/ */
rel = (Relation) palloc(sizeof(RelationData)); rel = (Relation) palloc(sizeof(RelationData));
MemSet((char *) rel, 0, sizeof(RelationData)); MemSet((char *) rel, 0, sizeof(RelationData));
rel->rd_fd = -1; /* table is not open */ rel->rd_fd = -1; /* physical file is not open */
rel->rd_unlinked = true; /* table is not created yet */
RelationSetReferenceCount(rel, 1); RelationSetReferenceCount(rel, 1);
...@@ -345,8 +344,6 @@ heap_create(char *relname, ...@@ -345,8 +344,6 @@ heap_create(char *relname,
* have the storage manager create the relation. * have the storage manager create the relation.
* ---------------- * ----------------
*/ */
/* smgrcreate() is moved to heap_storage_create() */
if (storage_create) if (storage_create)
heap_storage_create(rel); heap_storage_create(rel);
...@@ -355,18 +352,12 @@ heap_create(char *relname, ...@@ -355,18 +352,12 @@ heap_create(char *relname,
return rel; return rel;
} }
bool void
heap_storage_create(Relation rel) heap_storage_create(Relation rel)
{ {
bool smgrcall = false; Assert(rel->rd_fd < 0);
rel->rd_fd = smgrcreate(DEFAULT_SMGR, rel);
if (rel->rd_unlinked) Assert(rel->rd_fd >= 0);
{
rel->rd_fd = (File) smgrcreate(DEFAULT_SMGR, rel);
rel->rd_unlinked = false;
smgrcall = true;
}
return smgrcall;
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
...@@ -1062,7 +1053,11 @@ RelationRemoveIndexes(Relation relation) ...@@ -1062,7 +1053,11 @@ RelationRemoveIndexes(Relation relation)
&entry); &entry);
while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
{
index_drop(((Form_pg_index) GETSTRUCT(tuple))->indexrelid); index_drop(((Form_pg_index) GETSTRUCT(tuple))->indexrelid);
/* advance cmd counter to make catalog changes visible */
CommandCounterIncrement();
}
heap_endscan(scan); heap_endscan(scan);
heap_close(indexRelation, RowExclusiveLock); heap_close(indexRelation, RowExclusiveLock);
...@@ -1165,10 +1160,10 @@ RelationTruncateIndexes(Oid heapId) ...@@ -1165,10 +1160,10 @@ RelationTruncateIndexes(Oid heapId)
LockRelation(currentIndex, AccessExclusiveLock); LockRelation(currentIndex, AccessExclusiveLock);
/* /*
* Release any buffers associated with this index. If they're * Drop any buffers associated with this index. If they're
* dirty, they're just dropped without bothering to flush to disk. * dirty, they're just dropped without bothering to flush to disk.
*/ */
ReleaseRelationBuffers(currentIndex); DropRelationBuffers(currentIndex);
/* Now truncate the actual data and set blocks to zero */ /* Now truncate the actual data and set blocks to zero */
smgrtruncate(DEFAULT_SMGR, currentIndex, 0); smgrtruncate(DEFAULT_SMGR, currentIndex, 0);
...@@ -1212,24 +1207,19 @@ heap_truncate(char *relname) ...@@ -1212,24 +1207,19 @@ heap_truncate(char *relname)
/* ---------------- /* ----------------
* TRUNCATE TABLE within a transaction block is dangerous, because * TRUNCATE TABLE within a transaction block is dangerous, because
* if the transaction is later rolled back we have no way to * if the transaction is later rolled back we have no way to
* undo truncation of the relation's physical file. For now, allow it * undo truncation of the relation's physical file. Disallow it
* but emit a warning message. * except for a rel created in the current xact (which would be deleted
* Someday we might want to consider postponing the physical truncate * on abort, anyway).
* until transaction commit, but that's a lot of work...
* The only case that actually works right is for relations created
* in the current transaction, since the post-abort state would be that
* they don't exist anyway. So, no warning in that case.
* ---------------- * ----------------
*/ */
if (IsTransactionBlock() && !rel->rd_myxactonly) if (IsTransactionBlock() && !rel->rd_myxactonly)
elog(NOTICE, "Caution: TRUNCATE TABLE cannot be rolled back, so don't abort now"); elog(ERROR, "TRUNCATE TABLE cannot run inside a BEGIN/END block");
/* /*
* Release any buffers associated with this relation. If they're * Release any buffers associated with this relation. If they're
* dirty, they're just dropped without bothering to flush to disk. * dirty, they're just dropped without bothering to flush to disk.
*/ */
DropRelationBuffers(rel);
ReleaseRelationBuffers(rel);
/* Now truncate the actual data and set blocks to zero */ /* Now truncate the actual data and set blocks to zero */
...@@ -1416,8 +1406,9 @@ heap_drop_with_catalog(const char *relname, ...@@ -1416,8 +1406,9 @@ heap_drop_with_catalog(const char *relname,
{ {
Relation rel; Relation rel;
Oid rid; Oid rid;
bool istemp = (get_temp_rel_by_username(relname) != NULL);
bool has_toasttable; bool has_toasttable;
bool istemp = (get_temp_rel_by_username(relname) != NULL);
int i;
/* ---------------- /* ----------------
* Open and lock the relation. * Open and lock the relation.
...@@ -1425,6 +1416,7 @@ heap_drop_with_catalog(const char *relname, ...@@ -1425,6 +1416,7 @@ heap_drop_with_catalog(const char *relname,
*/ */
rel = heap_openr(relname, AccessExclusiveLock); rel = heap_openr(relname, AccessExclusiveLock);
rid = RelationGetRelid(rel); rid = RelationGetRelid(rel);
has_toasttable = rel->rd_rel->reltoastrelid != InvalidOid;
/* ---------------- /* ----------------
* prevent deletion of system relations * prevent deletion of system relations
...@@ -1433,46 +1425,40 @@ heap_drop_with_catalog(const char *relname, ...@@ -1433,46 +1425,40 @@ heap_drop_with_catalog(const char *relname,
/* allow temp of pg_class? Guess so. */ /* allow temp of pg_class? Guess so. */
if (!istemp && !allow_system_table_mods && if (!istemp && !allow_system_table_mods &&
IsSystemRelationName(RelationGetRelationName(rel))) IsSystemRelationName(RelationGetRelationName(rel)))
elog(ERROR, "System relation '%s' cannot be destroyed", elog(ERROR, "System relation \"%s\" may not be dropped",
RelationGetRelationName(rel)); RelationGetRelationName(rel));
/* ---------------- /* ----------------
* DROP TABLE within a transaction block is dangerous, because * Release all buffers that belong to this relation, after writing
* if the transaction is later rolled back there will be no way to * any that are dirty
* undo the unlink of the relation's physical file. For now, allow it
* but emit a warning message.
* Someday we might want to consider postponing the physical unlink
* until transaction commit, but that's a lot of work...
* The only case that actually works right is for relations created
* in the current transaction, since the post-abort state would be that
* they don't exist anyway. So, no warning in that case.
* ---------------- * ----------------
*/ */
if (IsTransactionBlock() && !rel->rd_myxactonly) i = FlushRelationBuffers(rel, (BlockNumber) 0);
elog(NOTICE, "Caution: DROP TABLE cannot be rolled back, so don't abort now"); if (i < 0)
elog(ERROR, "heap_drop_with_catalog: FlushRelationBuffers returned %d",
i);
/* ---------------- /* ----------------
* remove inheritance information * remove rules if necessary
* ---------------- * ----------------
*/ */
RelationRemoveInheritance(rel); if (rel->rd_rules != NULL)
RelationRemoveRules(rid);
/* triggers */
RelationRemoveTriggers(rel);
/* ---------------- /* ----------------
* remove indexes if necessary * remove inheritance information
* ---------------- * ----------------
*/ */
/* should ignore relhasindex */ RelationRemoveInheritance(rel);
RelationRemoveIndexes(rel);
/* ---------------- /* ----------------
* remove rules if necessary * remove indexes if necessary
* ---------------- * ----------------
*/ */
if (rel->rd_rules != NULL) RelationRemoveIndexes(rel);
RelationRemoveRules(rid);
/* triggers */
RelationRemoveTriggers(rel);
/* ---------------- /* ----------------
* delete attribute tuples * delete attribute tuples
...@@ -1502,23 +1488,12 @@ heap_drop_with_catalog(const char *relname, ...@@ -1502,23 +1488,12 @@ heap_drop_with_catalog(const char *relname,
*/ */
DeleteRelationTuple(rel); DeleteRelationTuple(rel);
/*
* release dirty buffers of this relation; don't bother to write them
*/
ReleaseRelationBuffers(rel);
/* ---------------- /* ----------------
* unlink the relation's physical file and finish up. * unlink the relation's physical file and finish up.
* ---------------- * ----------------
*/ */
if (rel->rd_rel->relkind != RELKIND_VIEW && ! rel->rd_unlinked) if (rel->rd_rel->relkind != RELKIND_VIEW)
smgrunlink(DEFAULT_SMGR, rel); smgrunlink(DEFAULT_SMGR, rel);
rel->rd_unlinked = true;
/*
* Remember if there is a toast relation for below
*/
has_toasttable = rel->rd_rel->reltoastrelid != InvalidOid;
/* /*
* Close relcache entry, but *keep* AccessExclusiveLock on the * Close relcache entry, but *keep* AccessExclusiveLock on the
...@@ -1533,6 +1508,7 @@ heap_drop_with_catalog(const char *relname, ...@@ -1533,6 +1508,7 @@ heap_drop_with_catalog(const char *relname,
*/ */
RelationForgetRelation(rid); RelationForgetRelation(rid);
/* and from the temp-table map */
if (istemp) if (istemp)
remove_temp_rel_by_relid(rid); remove_temp_rel_by_relid(rid);
......
This diff is collapsed.
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.58 2000/07/14 22:17:42 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.59 2000/11/08 22:09:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -34,20 +34,14 @@ ...@@ -34,20 +34,14 @@
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/syscache.h" #include "utils/syscache.h"
static Relation copy_heap(Oid OIDOldHeap); static Oid copy_heap(Oid OIDOldHeap, char *NewName);
static void copy_index(Oid OIDOldIndex, Oid OIDNewHeap); static void copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName);
static void rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex); static void rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex);
/* /*
* cluster * cluster
* *
* Check that the relation is a relation in the appropriate user * STILL TO DO:
* ACL. I will use the same security that limits users on the
* renamerel() function.
*
* Check that the index specified is appropriate for the task
* ( ie it's an index over this relation ). This is trickier.
*
* Create a list of all the other indicies on this relation. Because * Create a list of all the other indicies on this relation. Because
* the cluster will wreck all the tids, I'll need to destroy bogus * the cluster will wreck all the tids, I'll need to destroy bogus
* indicies. The user will have to re-create them. Not nice, but * indicies. The user will have to re-create them. Not nice, but
...@@ -55,14 +49,6 @@ static void rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex); ...@@ -55,14 +49,6 @@ static void rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex);
* destroy re-build. This may be possible. I'll check out what the * destroy re-build. This may be possible. I'll check out what the
* index create functiond want in the way of paramaters. On the other * index create functiond want in the way of paramaters. On the other
* hand, re-creating n indicies may blow out the space. * hand, re-creating n indicies may blow out the space.
*
* Create new (temporary) relations for the base heap and the new
* index.
*
* Exclusively lock the relations.
*
* Create new clustered index and base heap relation.
*
*/ */
void void
cluster(char *oldrelname, char *oldindexname) cluster(char *oldrelname, char *oldindexname)
...@@ -70,101 +56,93 @@ cluster(char *oldrelname, char *oldindexname) ...@@ -70,101 +56,93 @@ cluster(char *oldrelname, char *oldindexname)
Oid OIDOldHeap, Oid OIDOldHeap,
OIDOldIndex, OIDOldIndex,
OIDNewHeap; OIDNewHeap;
Relation OldHeap, Relation OldHeap,
OldIndex; OldIndex;
Relation NewHeap; HeapTuple tuple;
char NewIndexName[NAMEDATALEN];
char NewHeapName[NAMEDATALEN]; char NewHeapName[NAMEDATALEN];
char NewIndexName[NAMEDATALEN];
char saveoldrelname[NAMEDATALEN]; char saveoldrelname[NAMEDATALEN];
char saveoldindexname[NAMEDATALEN]; char saveoldindexname[NAMEDATALEN];
/* /*
* Copy the arguments into local storage, because they are probably * Copy the arguments into local storage, just to be safe.
* in palloc'd storage that will go away when we commit a transaction.
*/ */
strcpy(saveoldrelname, oldrelname); StrNCpy(saveoldrelname, oldrelname, NAMEDATALEN);
strcpy(saveoldindexname, oldindexname); StrNCpy(saveoldindexname, oldindexname, NAMEDATALEN);
/* /*
* Like vacuum, cluster spans transactions, so I'm going to handle it
* in the same way: commit and restart transactions where needed.
*
* We grab exclusive access to the target rel and index for the duration * We grab exclusive access to the target rel and index for the duration
* of the initial transaction. * of the transaction.
*/ */
OldHeap = heap_openr(saveoldrelname, AccessExclusiveLock); OldHeap = heap_openr(saveoldrelname, AccessExclusiveLock);
OIDOldHeap = RelationGetRelid(OldHeap); OIDOldHeap = RelationGetRelid(OldHeap);
OldIndex = index_openr(saveoldindexname); /* Open old index relation */ OldIndex = index_openr(saveoldindexname);
LockRelation(OldIndex, AccessExclusiveLock); LockRelation(OldIndex, AccessExclusiveLock);
OIDOldIndex = RelationGetRelid(OldIndex); OIDOldIndex = RelationGetRelid(OldIndex);
/* /*
* XXX Should check that index is in fact an index on this relation? * Check that index is in fact an index on the given relation
*/ */
tuple = SearchSysCacheTuple(INDEXRELID,
heap_close(OldHeap, NoLock);/* do NOT give up the locks */ ObjectIdGetDatum(OIDOldIndex),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "CLUSTER: no pg_index entry for index %u",
OIDOldIndex);
if (((Form_pg_index) GETSTRUCT(tuple))->indrelid != OIDOldHeap)
elog(ERROR, "CLUSTER: \"%s\" is not an index for table \"%s\"",
saveoldindexname, saveoldrelname);
/* Drop relcache refcnts, but do NOT give up the locks */
heap_close(OldHeap, NoLock);
index_close(OldIndex); index_close(OldIndex);
/* /*
* I need to build the copies of the heap and the index. The Commit() * Create the new heap with a temporary name.
* between here is *very* bogus. If someone is appending stuff, they
* will get the lock after being blocked and add rows which won't be
* present in the new table. Bleagh! I'd be best to try and ensure
* that no-one's in the tables for the entire duration of this process
* with a pg_vlock. XXX Isn't the above comment now invalid?
*/ */
NewHeap = copy_heap(OIDOldHeap); snprintf(NewHeapName, NAMEDATALEN, "temp_%u", OIDOldHeap);
OIDNewHeap = RelationGetRelid(NewHeap);
strcpy(NewHeapName, RelationGetRelationName(NewHeap)); OIDNewHeap = copy_heap(OIDOldHeap, NewHeapName);
/* To make the new heap visible (which is until now empty). */ /* To make the new heap visible (which is until now empty). */
CommandCounterIncrement(); CommandCounterIncrement();
/*
* Copy the heap data into the new table in the desired order.
*/
rebuildheap(OIDNewHeap, OIDOldHeap, OIDOldIndex); rebuildheap(OIDNewHeap, OIDOldHeap, OIDOldIndex);
/* To flush the filled new heap (and the statistics about it). */ /* To make the new heap's data visible. */
CommandCounterIncrement(); CommandCounterIncrement();
/* Create new index over the tuples of the new heap. */ /* Create new index over the tuples of the new heap. */
copy_index(OIDOldIndex, OIDNewHeap); snprintf(NewIndexName, NAMEDATALEN, "temp_%u", OIDOldIndex);
snprintf(NewIndexName, NAMEDATALEN, "temp_%x", OIDOldIndex);
/* copy_index(OIDOldIndex, OIDNewHeap, NewIndexName);
* make this really happen. Flush all the buffers. (Believe me, it is
* necessary ... ended up in a mess without it.) CommandCounterIncrement();
*/
CommitTransactionCommand();
StartTransactionCommand();
/* Destroy old heap (along with its index) and rename new. */ /* Destroy old heap (along with its index) and rename new. */
heap_drop_with_catalog(saveoldrelname, allowSystemTableMods); heap_drop_with_catalog(saveoldrelname, allowSystemTableMods);
CommitTransactionCommand(); CommandCounterIncrement();
StartTransactionCommand();
renamerel(NewHeapName, saveoldrelname); renamerel(NewHeapName, saveoldrelname);
/* This one might be unnecessary, but let's be safe. */
CommandCounterIncrement();
renamerel(NewIndexName, saveoldindexname); renamerel(NewIndexName, saveoldindexname);
} }
static Relation static Oid
copy_heap(Oid OIDOldHeap) copy_heap(Oid OIDOldHeap, char *NewName)
{ {
char NewName[NAMEDATALEN];
TupleDesc OldHeapDesc, TupleDesc OldHeapDesc,
tupdesc; tupdesc;
Oid OIDNewHeap; Oid OIDNewHeap;
Relation NewHeap, Relation OldHeap;
OldHeap;
/*
* Create a new heap relation with a temporary name, which has the
* same tuple description as the old one.
*/
snprintf(NewName, NAMEDATALEN, "temp_%x", OIDOldHeap);
OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock); OldHeap = heap_open(OIDOldHeap, AccessExclusiveLock);
OldHeapDesc = RelationGetDescr(OldHeap); OldHeapDesc = RelationGetDescr(OldHeap);
...@@ -173,7 +151,6 @@ copy_heap(Oid OIDOldHeap) ...@@ -173,7 +151,6 @@ copy_heap(Oid OIDOldHeap)
* Need to make a copy of the tuple descriptor, * Need to make a copy of the tuple descriptor,
* heap_create_with_catalog modifies it. * heap_create_with_catalog modifies it.
*/ */
tupdesc = CreateTupleDescCopy(OldHeapDesc); tupdesc = CreateTupleDescCopy(OldHeapDesc);
OIDNewHeap = heap_create_with_catalog(NewName, tupdesc, OIDNewHeap = heap_create_with_catalog(NewName, tupdesc,
...@@ -181,19 +158,15 @@ copy_heap(Oid OIDOldHeap) ...@@ -181,19 +158,15 @@ copy_heap(Oid OIDOldHeap)
allowSystemTableMods); allowSystemTableMods);
if (!OidIsValid(OIDNewHeap)) if (!OidIsValid(OIDNewHeap))
elog(ERROR, "clusterheap: cannot create temporary heap relation\n"); elog(ERROR, "copy_heap: cannot create temporary heap relation");
/* XXX why are we bothering to do this: */ heap_close(OldHeap, NoLock);
NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
heap_close(NewHeap, AccessExclusiveLock);
heap_close(OldHeap, AccessExclusiveLock);
return NewHeap; return OIDNewHeap;
} }
static void static void
copy_index(Oid OIDOldIndex, Oid OIDNewHeap) copy_index(Oid OIDOldIndex, Oid OIDNewHeap, char *NewIndexName)
{ {
Relation OldIndex, Relation OldIndex,
NewHeap; NewHeap;
...@@ -202,18 +175,17 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap) ...@@ -202,18 +175,17 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
Form_pg_index Old_pg_index_Form; Form_pg_index Old_pg_index_Form;
Form_pg_class Old_pg_index_relation_Form; Form_pg_class Old_pg_index_relation_Form;
IndexInfo *indexInfo; IndexInfo *indexInfo;
char *NewIndexName;
NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock); NewHeap = heap_open(OIDNewHeap, AccessExclusiveLock);
OldIndex = index_open(OIDOldIndex); OldIndex = index_open(OIDOldIndex);
/* /*
* OK. Create a new (temporary) index for the one that's already here. * Create a new (temporary) index like the one that's already here.
* To do this I get the info from pg_index, and add a new index with * To do this I get the info from pg_index, and add a new index with
* a temporary name. * a temporary name.
*/ */
Old_pg_index_Tuple = SearchSysCacheTupleCopy(INDEXRELID, Old_pg_index_Tuple = SearchSysCacheTupleCopy(INDEXRELID,
ObjectIdGetDatum(RelationGetRelid(OldIndex)), ObjectIdGetDatum(OIDOldIndex),
0, 0, 0); 0, 0, 0);
Assert(Old_pg_index_Tuple); Assert(Old_pg_index_Tuple);
Old_pg_index_Form = (Form_pg_index) GETSTRUCT(Old_pg_index_Tuple); Old_pg_index_Form = (Form_pg_index) GETSTRUCT(Old_pg_index_Tuple);
...@@ -221,15 +193,11 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap) ...@@ -221,15 +193,11 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
indexInfo = BuildIndexInfo(Old_pg_index_Tuple); indexInfo = BuildIndexInfo(Old_pg_index_Tuple);
Old_pg_index_relation_Tuple = SearchSysCacheTupleCopy(RELOID, Old_pg_index_relation_Tuple = SearchSysCacheTupleCopy(RELOID,
ObjectIdGetDatum(RelationGetRelid(OldIndex)), ObjectIdGetDatum(OIDOldIndex),
0, 0, 0); 0, 0, 0);
Assert(Old_pg_index_relation_Tuple); Assert(Old_pg_index_relation_Tuple);
Old_pg_index_relation_Form = (Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple); Old_pg_index_relation_Form = (Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple);
/* Set the name. */
NewIndexName = palloc(NAMEDATALEN); /* XXX */
snprintf(NewIndexName, NAMEDATALEN, "temp_%x", OIDOldIndex);
index_create(RelationGetRelationName(NewHeap), index_create(RelationGetRelationName(NewHeap),
NewIndexName, NewIndexName,
indexInfo, indexInfo,
...@@ -239,10 +207,10 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap) ...@@ -239,10 +207,10 @@ copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
Old_pg_index_Form->indisprimary, Old_pg_index_Form->indisprimary,
allowSystemTableMods); allowSystemTableMods);
setRelhasindexInplace(OIDNewHeap, true, false); setRelhasindex(OIDNewHeap, true);
index_close(OldIndex); index_close(OldIndex);
heap_close(NewHeap, AccessExclusiveLock); heap_close(NewHeap, NoLock);
} }
...@@ -294,6 +262,6 @@ rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex) ...@@ -294,6 +262,6 @@ rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
index_endscan(ScanDesc); index_endscan(ScanDesc);
index_close(LocalOldIndex); index_close(LocalOldIndex);
heap_close(LocalOldHeap, AccessExclusiveLock); heap_close(LocalOldHeap, NoLock);
heap_close(LocalNewHeap, AccessExclusiveLock); heap_close(LocalNewHeap, NoLock);
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.108 2000/10/26 21:34:44 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.109 2000/11/08 22:09:57 tgl Exp $
* *
* NOTES * NOTES
* The PerformAddAttribute() code, like most of the relation * The PerformAddAttribute() code, like most of the relation
...@@ -1661,9 +1661,13 @@ AlterTableCreateToastTable(const char *relationName, bool silent) ...@@ -1661,9 +1661,13 @@ AlterTableCreateToastTable(const char *relationName, bool silent)
/* /*
* Update toast rel's pg_class entry to show that it has an index. * Update toast rel's pg_class entry to show that it has an index.
* NOTE this also does CommandCounterIncrement() to make index visible.
*/ */
setRelhasindexInplace(toast_relid, true, false); setRelhasindex(toast_relid, true);
/*
* Make index visible
*/
CommandCounterIncrement();
/* /*
* Get the OID of the newly created index * Get the OID of the newly created index
......
...@@ -356,10 +356,8 @@ CommentAttribute(char *relname, char *attrname, char *comment) ...@@ -356,10 +356,8 @@ CommentAttribute(char *relname, char *attrname, char *comment)
attrtuple = SearchSysCacheTuple(ATTNAME, ObjectIdGetDatum(relation->rd_id), attrtuple = SearchSysCacheTuple(ATTNAME, ObjectIdGetDatum(relation->rd_id),
PointerGetDatum(attrname), 0, 0); PointerGetDatum(attrname), 0, 0);
if (!HeapTupleIsValid(attrtuple)) if (!HeapTupleIsValid(attrtuple))
{
elog(ERROR, "'%s' is not an attribute of class '%s'", elog(ERROR, "'%s' is not an attribute of class '%s'",
attrname, relname); attrname, relname);
}
oid = attrtuple->t_data->t_oid; oid = attrtuple->t_data->t_oid;
/*** Call CreateComments() to create/drop the comments ***/ /*** Call CreateComments() to create/drop the comments ***/
...@@ -368,8 +366,7 @@ CommentAttribute(char *relname, char *attrname, char *comment) ...@@ -368,8 +366,7 @@ CommentAttribute(char *relname, char *attrname, char *comment)
/*** Now, close the heap relation and return ***/ /*** Now, close the heap relation and return ***/
heap_close(relation, AccessShareLock); heap_close(relation, NoLock);
} }
/*------------------------------------------------------------------ /*------------------------------------------------------------------
...@@ -840,6 +837,5 @@ CommentTrigger(char *trigger, char *relname, char *comment) ...@@ -840,6 +837,5 @@ CommentTrigger(char *trigger, char *relname, char *comment)
heap_endscan(scan); heap_endscan(scan);
heap_close(pg_trigger, AccessShareLock); heap_close(pg_trigger, AccessShareLock);
heap_close(relation, AccessShareLock); heap_close(relation, NoLock);
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.64 2000/09/12 21:06:47 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.65 2000/11/08 22:09:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -149,6 +149,20 @@ DefineRelation(CreateStmt *stmt, char relkind) ...@@ -149,6 +149,20 @@ DefineRelation(CreateStmt *stmt, char relkind)
StoreCatalogInheritance(relationId, inheritList); StoreCatalogInheritance(relationId, inheritList);
/*
* We must bump the command counter to make the newly-created relation
* tuple visible for opening.
*/
CommandCounterIncrement();
/*
* Open the new relation and acquire exclusive lock on it. This isn't
* really necessary for locking out other backends (since they can't
* see the new rel anyway until we commit), but it keeps the lock manager
* from complaining about deadlock risks.
*/
rel = heap_openr(relname, AccessExclusiveLock);
/* /*
* Now add any newly specified column default values and CHECK * Now add any newly specified column default values and CHECK
* constraints to the new relation. These are passed to us in the * constraints to the new relation. These are passed to us in the
...@@ -181,25 +195,11 @@ DefineRelation(CreateStmt *stmt, char relkind) ...@@ -181,25 +195,11 @@ DefineRelation(CreateStmt *stmt, char relkind)
rawDefaults = lappend(rawDefaults, rawEnt); rawDefaults = lappend(rawDefaults, rawEnt);
} }
/* If no raw defaults and no constraints, nothing to do. */
if (rawDefaults == NIL && stmt->constraints == NIL)
return;
/*
* We must bump the command counter to make the newly-created relation
* tuple visible for opening.
*/
CommandCounterIncrement();
/*
* Open the new relation.
*/
rel = heap_openr(relname, AccessExclusiveLock);
/* /*
* Parse and add the defaults/constraints. * Parse and add the defaults/constraints, if any.
*/ */
AddRelationRawConstraints(rel, rawDefaults, stmt->constraints); if (rawDefaults || stmt->constraints)
AddRelationRawConstraints(rel, rawDefaults, stmt->constraints);
/* /*
* Clean up. We keep lock on new relation (although it shouldn't be * Clean up. We keep lock on new relation (although it shouldn't be
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.39 2000/10/22 23:32:39 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.40 2000/11/08 22:09:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -214,7 +214,7 @@ DefineIndex(char *heapRelationName, ...@@ -214,7 +214,7 @@ DefineIndex(char *heapRelationName,
* backends to flush their relcache entries and in particular their * backends to flush their relcache entries and in particular their
* cached lists of the indexes for this relation. * cached lists of the indexes for this relation.
*/ */
setRelhasindexInplace(relationId, true, false); setRelhasindex(relationId, true);
} }
...@@ -635,6 +635,15 @@ ReindexIndex(const char *name, bool force /* currently unused */ ) ...@@ -635,6 +635,15 @@ ReindexIndex(const char *name, bool force /* currently unused */ )
{ {
HeapTuple tuple; HeapTuple tuple;
/* ----------------
* REINDEX within a transaction block is dangerous, because
* if the transaction is later rolled back we have no way to
* undo truncation of the index's physical file. Disallow it.
* ----------------
*/
if (IsTransactionBlock())
elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
tuple = SearchSysCacheTuple(RELNAME, tuple = SearchSysCacheTuple(RELNAME,
PointerGetDatum(name), PointerGetDatum(name),
0, 0, 0); 0, 0, 0);
...@@ -666,6 +675,15 @@ ReindexTable(const char *name, bool force) ...@@ -666,6 +675,15 @@ ReindexTable(const char *name, bool force)
{ {
HeapTuple tuple; HeapTuple tuple;
/* ----------------
* REINDEX within a transaction block is dangerous, because
* if the transaction is later rolled back we have no way to
* undo truncation of the index's physical file. Disallow it.
* ----------------
*/
if (IsTransactionBlock())
elog(ERROR, "REINDEX cannot run inside a BEGIN/END block");
tuple = SearchSysCacheTuple(RELNAME, tuple = SearchSysCacheTuple(RELNAME,
PointerGetDatum(name), PointerGetDatum(name),
0, 0, 0); 0, 0, 0);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.51 2000/10/22 23:32:39 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.52 2000/11/08 22:09:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -183,16 +183,9 @@ renamerel(const char *oldrelname, const char *newrelname) ...@@ -183,16 +183,9 @@ renamerel(const char *oldrelname, const char *newrelname)
Oid reloid; Oid reloid;
char relkind; char relkind;
Relation irelations[Num_pg_class_indices]; Relation irelations[Num_pg_class_indices];
#ifdef OLD_FILE_NAMING
int i;
char oldpath[MAXPGPATH],
newpath[MAXPGPATH],
toldpath[MAXPGPATH + 10],
tnewpath[MAXPGPATH + 10];
#endif
if (!allowSystemTableMods && IsSystemRelationName(oldrelname)) if (!allowSystemTableMods && IsSystemRelationName(oldrelname))
elog(ERROR, "renamerel: system relation \"%s\" not renamed", elog(ERROR, "renamerel: system relation \"%s\" may not be renamed",
oldrelname); oldrelname);
if (!allowSystemTableMods && IsSystemRelationName(newrelname)) if (!allowSystemTableMods && IsSystemRelationName(newrelname))
...@@ -201,7 +194,7 @@ renamerel(const char *oldrelname, const char *newrelname) ...@@ -201,7 +194,7 @@ renamerel(const char *oldrelname, const char *newrelname)
/* /*
* Check for renaming a temp table, which only requires altering * Check for renaming a temp table, which only requires altering
* the temp-table mapping, not the physical table. * the temp-table mapping, not the underlying table.
*/ */
if (rename_temp_relation(oldrelname, newrelname)) if (rename_temp_relation(oldrelname, newrelname))
return; /* all done... */ return; /* all done... */
...@@ -213,7 +206,7 @@ renamerel(const char *oldrelname, const char *newrelname) ...@@ -213,7 +206,7 @@ renamerel(const char *oldrelname, const char *newrelname)
targetrelation = RelationNameGetRelation(oldrelname); targetrelation = RelationNameGetRelation(oldrelname);
if (!RelationIsValid(targetrelation)) if (!RelationIsValid(targetrelation))
elog(ERROR, "Relation '%s' does not exist", oldrelname); elog(ERROR, "Relation \"%s\" does not exist", oldrelname);
/* /*
* Grab an exclusive lock on the target table, which we will NOT * Grab an exclusive lock on the target table, which we will NOT
...@@ -221,46 +214,9 @@ renamerel(const char *oldrelname, const char *newrelname) ...@@ -221,46 +214,9 @@ renamerel(const char *oldrelname, const char *newrelname)
*/ */
LockRelation(targetrelation, AccessExclusiveLock); LockRelation(targetrelation, AccessExclusiveLock);
/* ----------------
* RENAME TABLE within a transaction block is dangerous, because
* if the transaction is later rolled back we have no way to
* undo the rename of the relation's physical file. For now, allow it
* but emit a warning message.
* Someday we might want to consider postponing the physical rename
* until transaction commit, but that's a lot of work...
* The only case that actually works right is for relations created
* in the current transaction, since the post-abort state would be that
* they don't exist anyway. So, no warning in that case.
* ----------------
*/
if (IsTransactionBlock() && !targetrelation->rd_myxactonly)
elog(NOTICE, "Caution: RENAME TABLE cannot be rolled back, so don't abort now");
reloid = RelationGetRelid(targetrelation); reloid = RelationGetRelid(targetrelation);
relkind = targetrelation->rd_rel->relkind; relkind = targetrelation->rd_rel->relkind;
/*
* Flush all blocks of the relation out of the buffer pool. We need
* this because the blocks are marked with the relation's name as well
* as OID. If some backend tries to write a dirty buffer with
* mdblindwrt after we've renamed the physical file, we'll be in big
* trouble.
*
* Since we hold the exclusive lock on the relation, we don't have to
* worry about more blocks being read in while we finish the rename.
*/
if (FlushRelationBuffers(targetrelation, (BlockNumber) 0) < 0)
elog(ERROR, "renamerel: unable to flush relation from buffer pool");
/*
* Make sure smgr and lower levels close the relation's files. (Next
* access to rel will reopen them.)
*
* Note: we rely on shared cache invalidation message to make other
* backends close and re-open the files.
*/
smgrclose(DEFAULT_SMGR, targetrelation);
/* /*
* Close rel, but keep exclusive lock! * Close rel, but keep exclusive lock!
*/ */
...@@ -271,8 +227,9 @@ renamerel(const char *oldrelname, const char *newrelname) ...@@ -271,8 +227,9 @@ renamerel(const char *oldrelname, const char *newrelname)
* the right instant). It'll get rebuilt on next access to relation. * the right instant). It'll get rebuilt on next access to relation.
* *
* XXX What if relation is myxactonly? * XXX What if relation is myxactonly?
*
* XXX this is probably not necessary anymore?
*/ */
targetrelation = NULL; /* make sure I don't touch it again */
RelationIdInvalidateRelationCacheByRelationId(reloid); RelationIdInvalidateRelationCacheByRelationId(reloid);
/* /*
...@@ -291,7 +248,8 @@ renamerel(const char *oldrelname, const char *newrelname) ...@@ -291,7 +248,8 @@ renamerel(const char *oldrelname, const char *newrelname)
elog(ERROR, "renamerel: relation \"%s\" exists", newrelname); elog(ERROR, "renamerel: relation \"%s\" exists", newrelname);
/* /*
* Update pg_class tuple with new relname. * Update pg_class tuple with new relname. (Scribbling on oldreltup
* is OK because it's a copy...)
*/ */
StrNCpy(NameStr(((Form_pg_class) GETSTRUCT(oldreltup))->relname), StrNCpy(NameStr(((Form_pg_class) GETSTRUCT(oldreltup))->relname),
newrelname, NAMEDATALEN); newrelname, NAMEDATALEN);
...@@ -310,36 +268,4 @@ renamerel(const char *oldrelname, const char *newrelname) ...@@ -310,36 +268,4 @@ renamerel(const char *oldrelname, const char *newrelname)
*/ */
if (relkind != RELKIND_INDEX) if (relkind != RELKIND_INDEX)
TypeRename(oldrelname, newrelname); TypeRename(oldrelname, newrelname);
#ifdef OLD_FILE_NAMING
/*
* Perform physical rename of files. If this fails, we haven't yet
* done anything irreversible. NOTE that this MUST be the last step;
* an error occurring afterwards would leave the relation hosed!
*
* XXX smgr.c ought to provide an interface for this; doing it directly
* is bletcherous.
*/
strcpy(oldpath, relpath(oldrelname));
strcpy(newpath, relpath(newrelname));
if (rename(oldpath, newpath) < 0)
elog(ERROR, "renamerel: unable to rename %s to %s: %m",
oldpath, newpath);
/* rename additional segments of relation, too */
for (i = 1;; i++)
{
sprintf(toldpath, "%s.%d", oldpath, i);
sprintf(tnewpath, "%s.%d", newpath, i);
if (rename(toldpath, tnewpath) < 0)
{
/* expected case is that there's not another segment file */
if (errno == ENOENT)
break;
/* otherwise we're up the creek... */
elog(ERROR, "renamerel: unable to rename %s to %s: %m",
toldpath, tnewpath);
}
}
#endif
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.78 2000/10/16 17:08:05 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.79 2000/11/08 22:09:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -388,6 +388,7 @@ RelationRemoveTriggers(Relation rel) ...@@ -388,6 +388,7 @@ RelationRemoveTriggers(Relation rel)
HeapScanDesc tgscan; HeapScanDesc tgscan;
ScanKeyData key; ScanKeyData key;
HeapTuple tup; HeapTuple tup;
bool found = false;
tgrel = heap_openr(TriggerRelationName, RowExclusiveLock); tgrel = heap_openr(TriggerRelationName, RowExclusiveLock);
ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid, ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
...@@ -403,17 +404,44 @@ RelationRemoveTriggers(Relation rel) ...@@ -403,17 +404,44 @@ RelationRemoveTriggers(Relation rel)
DeleteComments(tup->t_data->t_oid); DeleteComments(tup->t_data->t_oid);
heap_delete(tgrel, &tup->t_self, NULL); heap_delete(tgrel, &tup->t_self, NULL);
found = true;
} }
heap_endscan(tgscan); heap_endscan(tgscan);
/* ---------- /* ----------
* Need to bump it here so the following doesn't see * If we deleted any triggers, must update pg_class entry and
* the already deleted triggers again for a self-referencing * advance command counter to make the updated entry visible.
* table. * This is fairly annoying, since we'e just going to drop the
* durn thing later, but it's necessary to have a consistent
* state in case we do CommandCounterIncrement() below ---
* if RelationBuildTriggers() runs, it will complain otherwise.
* Perhaps RelationBuildTriggers() shouldn't be so picky...
* ---------- * ----------
*/ */
CommandCounterIncrement(); if (found)
{
Relation pgrel;
Relation ridescs[Num_pg_class_indices];
pgrel = heap_openr(RelationRelationName, RowExclusiveLock);
tup = SearchSysCacheTupleCopy(RELOID,
RelationGetRelid(rel),
0, 0, 0);
if (!HeapTupleIsValid(tup))
elog(ERROR, "RelationRemoveTriggers: relation %u not found in pg_class",
RelationGetRelid(rel));
((Form_pg_class) GETSTRUCT(tup))->reltriggers = 0;
heap_update(pgrel, &tup->t_self, tup, NULL);
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tup);
CatalogCloseIndices(Num_pg_class_indices, ridescs);
heap_freetuple(tup);
heap_close(pgrel, RowExclusiveLock);
CommandCounterIncrement();
}
/* ---------- /* ----------
* Also drop all constraint triggers referencing this relation * Also drop all constraint triggers referencing this relation
...@@ -431,22 +459,21 @@ RelationRemoveTriggers(Relation rel) ...@@ -431,22 +459,21 @@ RelationRemoveTriggers(Relation rel)
pg_trigger = (Form_pg_trigger) GETSTRUCT(tup); pg_trigger = (Form_pg_trigger) GETSTRUCT(tup);
refrel = heap_open(pg_trigger->tgrelid, NoLock); stmt.trigname = pstrdup(NameStr(pg_trigger->tgname));
/* May as well grab AccessExclusiveLock, since DropTrigger will. */
refrel = heap_open(pg_trigger->tgrelid, AccessExclusiveLock);
stmt.relname = pstrdup(RelationGetRelationName(refrel)); stmt.relname = pstrdup(RelationGetRelationName(refrel));
heap_close(refrel, NoLock); heap_close(refrel, NoLock);
stmt.trigname = DatumGetCString(DirectFunctionCall1(nameout,
NameGetDatum(&pg_trigger->tgname)));
elog(NOTICE, "DROP TABLE implicitly drops referential integrity trigger from table \"%s\"", stmt.relname); elog(NOTICE, "DROP TABLE implicitly drops referential integrity trigger from table \"%s\"", stmt.relname);
DropTrigger(&stmt); DropTrigger(&stmt);
/* ---------- /* ----------
* Need to do a command counter increment here to show up * Need to do a command counter increment here to show up
* new pg_class.reltriggers in the next loop invocation already * new pg_class.reltriggers in the next loop iteration
* (there are multiple referential integrity action * (in case there are multiple referential integrity action
* triggers for the same FK table defined on the PK table). * triggers for the same FK table defined on the PK table).
* ---------- * ----------
*/ */
...@@ -747,9 +774,6 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2) ...@@ -747,9 +774,6 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2)
* We need not examine the "index" data, just the trigger array * We need not examine the "index" data, just the trigger array
* itself; if we have the same triggers with the same types, the * itself; if we have the same triggers with the same types, the
* derived index data should match. * derived index data should match.
*
* XXX It seems possible that the same triggers could appear in different
* orders in the two trigger arrays; do we need to handle that?
*/ */
if (trigdesc1 != NULL) if (trigdesc1 != NULL)
{ {
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: execAmi.c,v 1.54 2000/10/26 21:35:15 tgl Exp $ * $Id: execAmi.c,v 1.55 2000/11/08 22:09:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -61,11 +61,8 @@ static Pointer ExecBeginScan(Relation relation, int nkeys, ScanKey skeys, ...@@ -61,11 +61,8 @@ static Pointer ExecBeginScan(Relation relation, int nkeys, ScanKey skeys,
* nkeys -- number of keys * nkeys -- number of keys
* skeys -- keys to restrict scanning * skeys -- keys to restrict scanning
* isindex -- if this is true, the relation is the relid of * isindex -- if this is true, the relation is the relid of
* an index relation, else it is an index into the * an index relation, else it is a heap relation.
* range table.
* Returns the relation as(relDesc scanDesc) * Returns the relation as(relDesc scanDesc)
* If this structure is changed, need to modify the access macros
* defined in execInt.h.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
void void
...@@ -90,16 +87,19 @@ ExecOpenScanR(Oid relOid, ...@@ -90,16 +87,19 @@ ExecOpenScanR(Oid relOid,
*/ */
/* ---------------- /* ----------------
* open the relation with the correct call depending * Open the relation with the correct call depending
* on whether this is a heap relation or an index relation. * on whether this is a heap relation or an index relation.
* *
* Do not lock the rel here; beginscan will acquire AccessShareLock. * For a table, acquire AccessShareLock for the duration of the query
* execution. For indexes, acquire no lock here; the index machinery
* does its own locks and unlocks. (We rely on having some kind of
* lock on the parent table to ensure the index won't go away!)
* ---------------- * ----------------
*/ */
if (isindex) if (isindex)
relation = index_open(relOid); relation = index_open(relOid);
else else
relation = heap_open(relOid, NoLock); relation = heap_open(relOid, AccessShareLock);
scanDesc = ExecBeginScan(relation, scanDesc = ExecBeginScan(relation,
nkeys, nkeys,
...@@ -136,8 +136,6 @@ ExecBeginScan(Relation relation, ...@@ -136,8 +136,6 @@ ExecBeginScan(Relation relation,
{ {
Pointer scanDesc; Pointer scanDesc;
scanDesc = NULL;
/* ---------------- /* ----------------
* open the appropriate type of scan. * open the appropriate type of scan.
* *
...@@ -183,12 +181,11 @@ ExecCloseR(Plan *node) ...@@ -183,12 +181,11 @@ ExecCloseR(Plan *node)
HeapScanDesc scanDesc; HeapScanDesc scanDesc;
/* ---------------- /* ----------------
* shut down the heap scan and close the heap relation * get state for node and shut down the heap scan, if any
* ---------------- * ----------------
*/ */
switch (nodeTag(node)) switch (nodeTag(node))
{ {
case T_SeqScan: case T_SeqScan:
state = ((SeqScan *) node)->scanstate; state = ((SeqScan *) node)->scanstate;
break; break;
...@@ -212,18 +209,9 @@ ExecCloseR(Plan *node) ...@@ -212,18 +209,9 @@ ExecCloseR(Plan *node)
if (scanDesc != NULL) if (scanDesc != NULL)
heap_endscan(scanDesc); heap_endscan(scanDesc);
/*
* endscan released AccessShareLock acquired by beginscan. If we are
* holding any stronger locks on the rel, they should be held till end
* of xact. Therefore, we need only close the rel and not release
* locks.
*/
if (relation != NULL)
heap_close(relation, NoLock);
/* ---------------- /* ----------------
* if this is an index scan then we have to take care * if this is an index scan then we have to take care
* of the index relations as well.. * of the index relations as well.
* ---------------- * ----------------
*/ */
if (IsA(node, IndexScan)) if (IsA(node, IndexScan))
...@@ -242,7 +230,7 @@ ExecCloseR(Plan *node) ...@@ -242,7 +230,7 @@ ExecCloseR(Plan *node)
for (i = 0; i < numIndices; i++) for (i = 0; i < numIndices; i++)
{ {
/* ---------------- /* ----------------
* shut down each of the scans and * shut down each of the index scans and
* close each of the index relations * close each of the index relations
* ---------------- * ----------------
*/ */
...@@ -253,6 +241,16 @@ ExecCloseR(Plan *node) ...@@ -253,6 +241,16 @@ ExecCloseR(Plan *node)
index_close(indexRelationDescs[i]); index_close(indexRelationDescs[i]);
} }
} }
/*
* Finally, close the heap relation.
*
* Currently, we do not release the AccessShareLock acquired by
* ExecOpenScanR. This lock should be held till end of transaction.
* (There is a faction that considers this too much locking, however.)
*/
if (relation != NULL)
heap_close(relation, NoLock);
} }
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: analyze.c,v 1.164 2000/11/05 01:42:07 tgl Exp $ * $Id: analyze.c,v 1.165 2000/11/08 22:09:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -115,7 +115,7 @@ static void ...@@ -115,7 +115,7 @@ static void
release_pstate_resources(ParseState *pstate) release_pstate_resources(ParseState *pstate)
{ {
if (pstate->p_target_relation != NULL) if (pstate->p_target_relation != NULL)
heap_close(pstate->p_target_relation, AccessShareLock); heap_close(pstate->p_target_relation, NoLock);
pstate->p_target_relation = NULL; pstate->p_target_relation = NULL;
pstate->p_target_rangetblentry = NULL; pstate->p_target_rangetblentry = NULL;
} }
...@@ -292,6 +292,7 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt) ...@@ -292,6 +292,7 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
qry->commandType = CMD_DELETE; qry->commandType = CMD_DELETE;
/* set up a range table */ /* set up a range table */
lockTargetTable(pstate, stmt->relname);
makeRangeTable(pstate, NIL); makeRangeTable(pstate, NIL);
setTargetTable(pstate, stmt->relname, stmt->inh, true); setTargetTable(pstate, stmt->relname, stmt->inh, true);
...@@ -331,6 +332,13 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) ...@@ -331,6 +332,13 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
qry->commandType = CMD_INSERT; qry->commandType = CMD_INSERT;
pstate->p_is_insert = true; pstate->p_is_insert = true;
/*
* Must get write lock on target table before scanning SELECT,
* else we will grab the wrong kind of initial lock if the target
* table is also mentioned in the SELECT part.
*/
lockTargetTable(pstate, stmt->relname);
/* /*
* Is it INSERT ... SELECT or INSERT ... VALUES? * Is it INSERT ... SELECT or INSERT ... VALUES?
*/ */
...@@ -1521,6 +1529,16 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt) ...@@ -1521,6 +1529,16 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
qry->commandType = CMD_UTILITY; qry->commandType = CMD_UTILITY;
qry->utilityStmt = (Node *) stmt; qry->utilityStmt = (Node *) stmt;
/*
* To avoid deadlock, make sure the first thing we do is grab
* AccessExclusiveLock on the target relation. This will be
* needed by DefineQueryRewrite(), and we don't want to grab a lesser
* lock beforehand. We don't need to hold a refcount on the relcache
* entry, however.
*/
heap_close(heap_openr(stmt->object->relname, AccessExclusiveLock),
NoLock);
/* /*
* NOTE: 'OLD' must always have a varno equal to 1 and 'NEW' * NOTE: 'OLD' must always have a varno equal to 1 and 'NEW'
* equal to 2. Set up their RTEs in the main pstate for use * equal to 2. Set up their RTEs in the main pstate for use
...@@ -1727,6 +1745,9 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -1727,6 +1745,9 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
qry->isBinary = FALSE; qry->isBinary = FALSE;
} }
/* make FOR UPDATE clause available to addRangeTableEntry */
pstate->p_forUpdate = stmt->forUpdate;
/* set up a range table */ /* set up a range table */
makeRangeTable(pstate, stmt->fromClause); makeRangeTable(pstate, stmt->fromClause);
...@@ -1765,7 +1786,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -1765,7 +1786,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
qry->rtable = pstate->p_rtable; qry->rtable = pstate->p_rtable;
qry->jointree = makeFromExpr(pstate->p_joinlist, qual); qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
if (stmt->forUpdate != NULL) if (stmt->forUpdate != NIL)
transformForUpdate(qry, stmt->forUpdate); transformForUpdate(qry, stmt->forUpdate);
return qry; return qry;
...@@ -1951,7 +1972,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -1951,7 +1972,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
qry->rtable = pstate->p_rtable; qry->rtable = pstate->p_rtable;
qry->jointree = makeFromExpr(pstate->p_joinlist, NULL); qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
if (forUpdate != NULL) if (forUpdate != NIL)
transformForUpdate(qry, forUpdate); transformForUpdate(qry, forUpdate);
return qry; return qry;
...@@ -2159,6 +2180,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) ...@@ -2159,6 +2180,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
* used in FROM, we'd fail to notice that it should be marked * used in FROM, we'd fail to notice that it should be marked
* checkForRead as well as checkForWrite. See setTargetTable(). * checkForRead as well as checkForWrite. See setTargetTable().
*/ */
lockTargetTable(pstate, stmt->relname);
makeRangeTable(pstate, stmt->fromClause); makeRangeTable(pstate, stmt->fromClause);
setTargetTable(pstate, stmt->relname, stmt->inh, true); setTargetTable(pstate, stmt->relname, stmt->inh, true);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.207 2000/11/08 21:28:06 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.208 2000/11/08 22:09:58 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -334,7 +334,7 @@ static void doNegateFloat(Value *v); ...@@ -334,7 +334,7 @@ static void doNegateFloat(Value *v);
* when some sort of pg_privileges relation is introduced. * when some sort of pg_privileges relation is introduced.
* - Todd A. Brandys 1998-01-01? * - Todd A. Brandys 1998-01-01?
*/ */
%token ABORT_TRANS, ACCESS, AFTER, AGGREGATE, ANALYZE, ANALYSE /* British */ %token ABORT_TRANS, ACCESS, AFTER, AGGREGATE, ANALYZE, ANALYSE,
BACKWARD, BEFORE, BINARY, BIT, BACKWARD, BEFORE, BINARY, BIT,
CACHE, CHECKPOINT, CLUSTER, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE, CACHE, CHECKPOINT, CLUSTER, COMMENT, COPY, CREATEDB, CREATEUSER, CYCLE,
DATABASE, DELIMITERS, DO, DATABASE, DELIMITERS, DO,
...@@ -2466,11 +2466,7 @@ ExtendStmt: EXTEND INDEX index_name where_clause ...@@ -2466,11 +2466,7 @@ ExtendStmt: EXTEND INDEX index_name where_clause
/* NOT USED /* NOT USED
RecipeStmt: EXECUTE RECIPE recipe_name RecipeStmt: EXECUTE RECIPE recipe_name
{ {
RecipeStmt *n; RecipeStmt *n = makeNode(RecipeStmt);
if (!IsTransactionBlock())
elog(ERROR,"EXECUTE RECIPE may only be used in begin/end transaction blocks");
n = makeNode(RecipeStmt);
n->recipeName = $3; n->recipeName = $3;
$$ = (Node *)n; $$ = (Node *)n;
} }
...@@ -2633,8 +2629,6 @@ oper_argtypes: Typename ...@@ -2633,8 +2629,6 @@ oper_argtypes: Typename
ReindexStmt: REINDEX reindex_type name opt_force ReindexStmt: REINDEX reindex_type name opt_force
{ {
ReindexStmt *n = makeNode(ReindexStmt); ReindexStmt *n = makeNode(ReindexStmt);
if (IsTransactionBlock())
elog(ERROR,"REINDEX command could only be used outside begin/end transaction blocks");
n->reindexType = $2; n->reindexType = $2;
n->name = $3; n->name = $3;
n->force = $4; n->force = $4;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.70 2000/10/07 00:58:17 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.71 2000/11/08 22:09:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -87,6 +87,34 @@ makeRangeTable(ParseState *pstate, List *frmList) ...@@ -87,6 +87,34 @@ makeRangeTable(ParseState *pstate, List *frmList)
} }
} }
/*
* lockTargetTable
* Find the target relation of INSERT/UPDATE/DELETE and acquire write
* lock on it. This must be done before building the range table,
* in case the target is also mentioned as a source relation --- we
* want to be sure to grab the write lock before any read lock.
*
* The ParseState's link to the target relcache entry is also set here.
*/
void
lockTargetTable(ParseState *pstate, char *relname)
{
/* Close old target; this could only happen for multi-action rules */
if (pstate->p_target_relation != NULL)
heap_close(pstate->p_target_relation, NoLock);
pstate->p_target_relation = NULL;
pstate->p_target_rangetblentry = NULL; /* setTargetTable will set this */
/*
* Open target rel and grab suitable lock (which we will hold till
* end of transaction).
*
* analyze.c will eventually do the corresponding heap_close(),
* but *not* release the lock.
*/
pstate->p_target_relation = heap_openr(relname, RowExclusiveLock);
}
/* /*
* setTargetTable * setTargetTable
* Add the target relation of INSERT/UPDATE/DELETE to the range table, * Add the target relation of INSERT/UPDATE/DELETE to the range table,
...@@ -133,13 +161,10 @@ setTargetTable(ParseState *pstate, char *relname, bool inh, bool inJoinSet) ...@@ -133,13 +161,10 @@ setTargetTable(ParseState *pstate, char *relname, bool inh, bool inJoinSet)
if (inJoinSet) if (inJoinSet)
addRTEtoJoinList(pstate, rte); addRTEtoJoinList(pstate, rte);
/* This could only happen for multi-action rules */ /* lockTargetTable should have been called earlier */
if (pstate->p_target_relation != NULL) Assert(pstate->p_target_relation != NULL);
heap_close(pstate->p_target_relation, AccessShareLock);
pstate->p_target_rangetblentry = rte; pstate->p_target_rangetblentry = rte;
pstate->p_target_relation = heap_open(rte->relid, AccessShareLock);
/* will close relation later, see analyze.c */
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.49 2000/09/29 18:21:36 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.50 2000/11/08 22:09:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -34,6 +34,7 @@ static Node *scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, ...@@ -34,6 +34,7 @@ static Node *scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
char *colname); char *colname);
static Node *scanJoinForColumn(JoinExpr *join, char *colname, static Node *scanJoinForColumn(JoinExpr *join, char *colname,
int sublevels_up); int sublevels_up);
static bool isForUpdate(ParseState *pstate, char *relname);
static List *expandNamesVars(ParseState *pstate, List *names, List *vars); static List *expandNamesVars(ParseState *pstate, List *names, List *vars);
static void warnAutoRange(ParseState *pstate, char *refname); static void warnAutoRange(ParseState *pstate, char *refname);
...@@ -477,6 +478,7 @@ addRangeTableEntry(ParseState *pstate, ...@@ -477,6 +478,7 @@ addRangeTableEntry(ParseState *pstate,
bool inFromCl) bool inFromCl)
{ {
char *refname = alias ? alias->relname : relname; char *refname = alias ? alias->relname : relname;
LOCKMODE lockmode;
Relation rel; Relation rel;
RangeTblEntry *rte; RangeTblEntry *rte;
Attr *eref; Attr *eref;
...@@ -502,17 +504,22 @@ addRangeTableEntry(ParseState *pstate, ...@@ -502,17 +504,22 @@ addRangeTableEntry(ParseState *pstate,
/* /*
* Get the rel's OID. This access also ensures that we have an * Get the rel's OID. This access also ensures that we have an
* up-to-date relcache entry for the rel. We don't need to keep it * up-to-date relcache entry for the rel. Since this is typically
* open, however. Since this is open anyway, let's check that the * the first access to a rel in a statement, be careful to get the
* number of column aliases is reasonable. - Thomas 2000-02-04 * right access level depending on whether we're doing SELECT FOR UPDATE.
*/ */
rel = heap_openr(relname, AccessShareLock); lockmode = isForUpdate(pstate, relname) ? RowShareLock : AccessShareLock;
rel = heap_openr(relname, lockmode);
rte->relid = RelationGetRelid(rel); rte->relid = RelationGetRelid(rel);
maxattrs = RelationGetNumberOfAttributes(rel);
eref = alias ? (Attr *) copyObject(alias) : makeAttr(refname, NULL); eref = alias ? (Attr *) copyObject(alias) : makeAttr(refname, NULL);
numaliases = length(eref->attrs); numaliases = length(eref->attrs);
/*
* Since the rel is open anyway, let's check that the
* number of column aliases is reasonable. - Thomas 2000-02-04
*/
maxattrs = RelationGetNumberOfAttributes(rel);
if (maxattrs < numaliases) if (maxattrs < numaliases)
elog(ERROR, "Table \"%s\" has %d columns available but %d columns specified", elog(ERROR, "Table \"%s\" has %d columns available but %d columns specified",
refname, maxattrs, numaliases); refname, maxattrs, numaliases);
...@@ -527,7 +534,12 @@ addRangeTableEntry(ParseState *pstate, ...@@ -527,7 +534,12 @@ addRangeTableEntry(ParseState *pstate,
} }
rte->eref = eref; rte->eref = eref;
heap_close(rel, AccessShareLock); /*
* Drop the rel refcount, but keep the access lock till end of transaction
* so that the table can't be deleted or have its schema modified
* underneath us.
*/
heap_close(rel, NoLock);
/*---------- /*----------
* Flags: * Flags:
...@@ -643,6 +655,41 @@ addRangeTableEntryForSubquery(ParseState *pstate, ...@@ -643,6 +655,41 @@ addRangeTableEntryForSubquery(ParseState *pstate,
return rte; return rte;
} }
/*
* Has the specified relname been selected FOR UPDATE?
*/
static bool
isForUpdate(ParseState *pstate, char *relname)
{
/* Outer loop to check parent query levels as well as this one */
while (pstate != NULL)
{
if (pstate->p_forUpdate != NIL)
{
if (lfirst(pstate->p_forUpdate) == NULL)
{
/* all tables used in query */
return true;
}
else
{
/* just the named tables */
List *l;
foreach(l, pstate->p_forUpdate)
{
char *rname = lfirst(l);
if (strcmp(relname, rname) == 0)
return true;
}
}
}
pstate = pstate->parentParseState;
}
return false;
}
/* /*
* Add the given RTE as a top-level entry in the pstate's join list, * Add the given RTE as a top-level entry in the pstate's join list,
* unless there already is an entry for it. * unless there already is an entry for it.
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.82 2000/10/05 19:11:34 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.83 2000/11/08 22:09:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -363,14 +363,6 @@ static Query * ...@@ -363,14 +363,6 @@ static Query *
fireRIRrules(Query *parsetree) fireRIRrules(Query *parsetree)
{ {
int rt_index; int rt_index;
RangeTblEntry *rte;
Relation rel;
List *locks;
RuleLock *rules;
RewriteRule *rule;
bool relIsUsed;
int i;
List *l;
/* /*
* don't try to convert this into a foreach loop, because rtable list * don't try to convert this into a foreach loop, because rtable list
...@@ -379,6 +371,16 @@ fireRIRrules(Query *parsetree) ...@@ -379,6 +371,16 @@ fireRIRrules(Query *parsetree)
rt_index = 0; rt_index = 0;
while (rt_index < length(parsetree->rtable)) while (rt_index < length(parsetree->rtable))
{ {
RangeTblEntry *rte;
Relation rel;
List *locks;
RuleLock *rules;
RewriteRule *rule;
LOCKMODE lockmode;
bool relIsUsed;
int i;
List *l;
++rt_index; ++rt_index;
rte = rt_fetch(rt_index, parsetree->rtable); rte = rt_fetch(rt_index, parsetree->rtable);
...@@ -406,11 +408,32 @@ fireRIRrules(Query *parsetree) ...@@ -406,11 +408,32 @@ fireRIRrules(Query *parsetree)
if (!relIsUsed && rt_index != parsetree->resultRelation) if (!relIsUsed && rt_index != parsetree->resultRelation)
continue; continue;
rel = heap_openr(rte->relname, AccessShareLock); /*
* This may well be the first access to the relation during
* the current statement (it will be, if this Query was extracted
* from a rule or somehow got here other than via the parser).
* Therefore, grab the appropriate lock type for the relation,
* and do not release it until end of transaction. This protects
* the rewriter and planner against schema changes mid-query.
*
* If the relation is the query's result relation, then RewriteQuery()
* already got the right lock on it, so we need no additional lock.
* Otherwise, check to see if the relation is accessed FOR UPDATE
* or not.
*/
if (rt_index == parsetree->resultRelation)
lockmode = NoLock;
else if (intMember(rt_index, parsetree->rowMarks))
lockmode = RowShareLock;
else
lockmode = AccessShareLock;
rel = heap_openr(rte->relname, lockmode);
rules = rel->rd_rules; rules = rel->rd_rules;
if (rules == NULL) if (rules == NULL)
{ {
heap_close(rel, AccessShareLock); heap_close(rel, NoLock);
continue; continue;
} }
...@@ -450,7 +473,7 @@ fireRIRrules(Query *parsetree) ...@@ -450,7 +473,7 @@ fireRIRrules(Query *parsetree)
relIsUsed); relIsUsed);
} }
heap_close(rel, AccessShareLock); heap_close(rel, NoLock);
} }
/* /*
...@@ -761,8 +784,19 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products) ...@@ -761,8 +784,19 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
* the statement is an update, insert or delete - fire rules on it. * the statement is an update, insert or delete - fire rules on it.
*/ */
result_relation = parsetree->resultRelation; result_relation = parsetree->resultRelation;
Assert(result_relation != 0);
rt_entry = rt_fetch(result_relation, parsetree->rtable); rt_entry = rt_fetch(result_relation, parsetree->rtable);
rt_entry_relation = heap_openr(rt_entry->relname, AccessShareLock);
/*
* This may well be the first access to the result relation during
* the current statement (it will be, if this Query was extracted
* from a rule or somehow got here other than via the parser).
* Therefore, grab the appropriate lock type for a result relation,
* and do not release it until end of transaction. This protects the
* rewriter and planner against schema changes mid-query.
*/
rt_entry_relation = heap_openr(rt_entry->relname, RowExclusiveLock);
rt_entry_locks = rt_entry_relation->rd_rules; rt_entry_locks = rt_entry_relation->rd_rules;
if (rt_entry_locks != NULL) if (rt_entry_locks != NULL)
...@@ -778,7 +812,7 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products) ...@@ -778,7 +812,7 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
qual_products); qual_products);
} }
heap_close(rt_entry_relation, AccessShareLock); heap_close(rt_entry_relation, NoLock); /* keep lock! */
return product_queries; return product_queries;
} }
......
This diff is collapsed.
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.33 2000/10/28 16:20:56 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.34 2000/11/08 22:09:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -183,7 +183,7 @@ WriteLocalBuffer(Buffer buffer, bool release) ...@@ -183,7 +183,7 @@ WriteLocalBuffer(Buffer buffer, bool release)
* flushes a local buffer * flushes a local buffer
*/ */
int int
FlushLocalBuffer(Buffer buffer, bool release) FlushLocalBuffer(Buffer buffer, bool sync, bool release)
{ {
int bufid; int bufid;
Relation bufrel; Relation bufrel;
...@@ -199,13 +199,18 @@ FlushLocalBuffer(Buffer buffer, bool release) ...@@ -199,13 +199,18 @@ FlushLocalBuffer(Buffer buffer, bool release)
bufHdr = &LocalBufferDescriptors[bufid]; bufHdr = &LocalBufferDescriptors[bufid];
bufHdr->flags &= ~BM_DIRTY; bufHdr->flags &= ~BM_DIRTY;
bufrel = RelationNodeCacheGetRelation(bufHdr->tag.rnode); bufrel = RelationNodeCacheGetRelation(bufHdr->tag.rnode);
Assert(bufrel != NULL); Assert(bufrel != NULL);
smgrflush(DEFAULT_SMGR, bufrel, bufHdr->tag.blockNum,
(char *) MAKE_PTR(bufHdr->data)); if (sync)
smgrflush(DEFAULT_SMGR, bufrel, bufHdr->tag.blockNum,
(char *) MAKE_PTR(bufHdr->data));
else
smgrwrite(DEFAULT_SMGR, bufrel, bufHdr->tag.blockNum,
(char *) MAKE_PTR(bufHdr->data));
LocalBufferFlushCount++; LocalBufferFlushCount++;
/* drop relcache refcount incremented by RelationIdCacheGetRelation */ /* drop relcache refcount incremented by RelationNodeCacheGetRelation */
RelationDecrementReferenceCount(bufrel); RelationDecrementReferenceCount(bufrel);
if (release) if (release)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/xlog_bufmgr.c,v 1.1 2000/10/28 16:20:56 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/xlog_bufmgr.c,v 1.2 2000/11/08 22:09:59 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -838,7 +838,7 @@ BufferSync() ...@@ -838,7 +838,7 @@ BufferSync()
SpinRelease(BufMgrLock); SpinRelease(BufMgrLock);
/* drop refcnt obtained by RelationIdCacheGetRelation */ /* drop refcnt obtained by RelationNodeCacheGetRelation */
if (reln != (Relation) NULL) if (reln != (Relation) NULL)
{ {
RelationDecrementReferenceCount(reln); RelationDecrementReferenceCount(reln);
...@@ -1128,7 +1128,7 @@ BufferReplace(BufferDesc *bufHdr) ...@@ -1128,7 +1128,7 @@ BufferReplace(BufferDesc *bufHdr)
false); /* no fsync */ false); /* no fsync */
} }
/* drop relcache refcnt incremented by RelationIdCacheGetRelation */ /* drop relcache refcnt incremented by RelationNodeCacheGetRelation */
if (reln != (Relation) NULL) if (reln != (Relation) NULL)
RelationDecrementReferenceCount(reln); RelationDecrementReferenceCount(reln);
...@@ -1159,21 +1159,23 @@ RelationGetNumberOfBlocks(Relation relation) ...@@ -1159,21 +1159,23 @@ RelationGetNumberOfBlocks(Relation relation)
} }
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
* ReleaseRelationBuffers * DropRelationBuffers
* *
* This function removes all the buffered pages for a relation * This function removes all the buffered pages for a relation
* from the buffer pool. Dirty pages are simply dropped, without * from the buffer pool. Dirty pages are simply dropped, without
* bothering to write them out first. This is used when the * bothering to write them out first. This is NOT rollback-able,
* relation is about to be deleted. We assume that the caller * and so should be used only with extreme caution!
* holds an exclusive lock on the relation, which should assure *
* that no new buffers will be acquired for the rel meanwhile. * We assume that the caller holds an exclusive lock on the relation,
* which should assure that no new buffers will be acquired for the rel
* meanwhile.
* *
* XXX currently it sequentially searches the buffer pool, should be * XXX currently it sequentially searches the buffer pool, should be
* changed to more clever ways of searching. * changed to more clever ways of searching.
* -------------------------------------------------------------------- * --------------------------------------------------------------------
*/ */
void void
ReleaseRelationBuffers(Relation rel) DropRelationBuffers(Relation rel)
{ {
int i; int i;
BufferDesc *bufHdr; BufferDesc *bufHdr;
...@@ -1248,6 +1250,91 @@ recheck: ...@@ -1248,6 +1250,91 @@ recheck:
SpinRelease(BufMgrLock); SpinRelease(BufMgrLock);
} }
/* ---------------------------------------------------------------------
* DropRelFileNodeBuffers
*
* This is the same as DropRelationBuffers, except that the target
* relation is specified by RelFileNode.
*
* This is NOT rollback-able. One legitimate use is to clear the
* buffer cache of buffers for a relation that is being deleted
* during transaction abort.
* --------------------------------------------------------------------
*/
void
DropRelFileNodeBuffers(RelFileNode rnode)
{
int i;
BufferDesc *bufHdr;
/* We have to search both local and shared buffers... */
for (i = 0; i < NLocBuffer; i++)
{
bufHdr = &LocalBufferDescriptors[i];
if (RelFileNodeEquals(bufHdr->tag.rnode, rnode))
{
bufHdr->flags &= ~(BM_DIRTY | BM_JUST_DIRTIED);
bufHdr->cntxDirty = false;
LocalRefCount[i] = 0;
bufHdr->tag.rnode.relNode = InvalidOid;
}
}
SpinAcquire(BufMgrLock);
for (i = 1; i <= NBuffers; i++)
{
bufHdr = &BufferDescriptors[i - 1];
recheck:
if (RelFileNodeEquals(bufHdr->tag.rnode, rnode))
{
/*
* If there is I/O in progress, better wait till it's done;
* don't want to delete the relation out from under someone
* who's just trying to flush the buffer!
*/
if (bufHdr->flags & BM_IO_IN_PROGRESS)
{
WaitIO(bufHdr, BufMgrLock);
/*
* By now, the buffer very possibly belongs to some other
* rel, so check again before proceeding.
*/
goto recheck;
}
/* Now we can do what we came for */
bufHdr->flags &= ~(BM_DIRTY | BM_JUST_DIRTIED);
bufHdr->cntxDirty = false;
/*
* Release any refcount we may have.
*
* This is very probably dead code, and if it isn't then it's
* probably wrong. I added the Assert to find out --- tgl
* 11/99.
*/
if (!(bufHdr->flags & BM_FREE))
{
/* Assert checks that buffer will actually get freed! */
Assert(PrivateRefCount[i - 1] == 1 &&
bufHdr->refcount == 1);
/* ReleaseBuffer expects we do not hold the lock at entry */
SpinRelease(BufMgrLock);
ReleaseBuffer(i);
SpinAcquire(BufMgrLock);
}
/*
* And mark the buffer as no longer occupied by this rel.
*/
BufTableDelete(bufHdr);
}
}
SpinRelease(BufMgrLock);
}
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
* DropBuffers * DropBuffers
* *
...@@ -1256,7 +1343,7 @@ recheck: ...@@ -1256,7 +1343,7 @@ recheck:
* bothering to write them out first. This is used when we destroy a * bothering to write them out first. This is used when we destroy a
* database, to avoid trying to flush data to disk when the directory * database, to avoid trying to flush data to disk when the directory
* tree no longer exists. Implementation is pretty similar to * tree no longer exists. Implementation is pretty similar to
* ReleaseRelationBuffers() which is for destroying just one relation. * DropRelationBuffers() which is for destroying just one relation.
* -------------------------------------------------------------------- * --------------------------------------------------------------------
*/ */
void void
...@@ -1399,33 +1486,32 @@ BufferPoolBlowaway() ...@@ -1399,33 +1486,32 @@ BufferPoolBlowaway()
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
* FlushRelationBuffers * FlushRelationBuffers
* *
* This function flushes all dirty pages of a relation out to disk. * This function writes all dirty pages of a relation out to disk.
* Furthermore, pages that have blocknumber >= firstDelBlock are * Furthermore, pages that have blocknumber >= firstDelBlock are
* actually removed from the buffer pool. An error code is returned * actually removed from the buffer pool. An error code is returned
* if we fail to dump a dirty buffer or if we find one of * if we fail to dump a dirty buffer or if we find one of
* the target pages is pinned into the cache. * the target pages is pinned into the cache.
* *
* This is used by VACUUM before truncating the relation to the given * This is called by DROP TABLE to clear buffers for the relation
* number of blocks. (TRUNCATE TABLE also uses it in the same way.) * from the buffer pool. Note that we must write dirty buffers,
* It might seem unnecessary to flush dirty pages before firstDelBlock, * rather than just dropping the changes, because our transaction
* since VACUUM should already have committed its changes. However, * might abort later on; we want to roll back safely in that case.
* it is possible for there still to be dirty pages: if some page
* had unwritten on-row tuple status updates from a prior transaction,
* and VACUUM had no additional changes to make to that page, then
* VACUUM won't have written it. This is harmless in most cases but
* will break pg_upgrade, which relies on VACUUM to ensure that *all*
* tuples have correct on-row status. So, we check and flush all
* dirty pages of the rel regardless of block number.
* *
* This is also used by RENAME TABLE (with firstDelBlock = 0) * This is also called by VACUUM before truncating the relation to the
* to clear out the buffer cache before renaming the physical files of * given number of blocks. It might seem unnecessary for VACUUM to
* a relation. Without that, some other backend might try to do a * write dirty pages before firstDelBlock, since VACUUM should already
* blind write of a buffer page (relying on the BlindId of the buffer) * have committed its changes. However, it is possible for there still
* and fail because it's not got the right filename anymore. * to be dirty pages: if some page had unwritten on-row tuple status
* updates from a prior transaction, and VACUUM had no additional
* changes to make to that page, then VACUUM won't have written it.
* This is harmless in most cases but will break pg_upgrade, which
* relies on VACUUM to ensure that *all* tuples have correct on-row
* status. So, we check and flush all dirty pages of the rel
* regardless of block number.
* *
* In all cases, the caller should be holding AccessExclusiveLock on * In all cases, the caller should be holding AccessExclusiveLock on
* the target relation to ensure that no other backend is busy reading * the target relation to ensure that no other backend is busy reading
* more blocks of the relation. * more blocks of the relation (or might do so before we commit).
* *
* Formerly, we considered it an error condition if we found dirty * Formerly, we considered it an error condition if we found dirty
* buffers here. However, since BufferSync no longer forces out all * buffers here. However, since BufferSync no longer forces out all
......
This diff is collapsed.
...@@ -8,17 +8,17 @@ ...@@ -8,17 +8,17 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.77 2000/10/28 16:20:57 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.78 2000/11/08 22:10:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h"
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/file.h> #include <sys/file.h>
#include "postgres.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/smgr.h" #include "storage/smgr.h"
...@@ -123,63 +123,39 @@ mdinit() ...@@ -123,63 +123,39 @@ mdinit()
int int
mdcreate(Relation reln) mdcreate(Relation reln)
{ {
char *path;
int fd, int fd,
vfd; vfd;
char *path;
Assert(reln->rd_unlinked && reln->rd_fd < 0); Assert(reln->rd_fd < 0);
path = relpath(reln->rd_node); path = relpath(reln->rd_node);
fd = FileNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600);
/* fd = FileNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600);
* For cataloged relations, pg_class is guaranteed to have a unique
* record with the same relname by the unique index. So we are able to
* reuse existent files for new cataloged relations. Currently we reuse
* them in the following cases. 1. they are empty. 2. they are used
* for Index relations and their size == BLCKSZ * 2.
*
* During bootstrap processing, we skip that check, because pg_time,
* pg_variable, and pg_log get created before their .bki file entries
* are processed.
*/
if (fd < 0) if (fd < 0)
{ {
int save_errno = errno; int save_errno = errno;
if (!IsBootstrapProcessingMode() && /*
reln->rd_rel->relkind == RELKIND_UNCATALOGED) * During bootstrap, there are cases where a system relation will be
return -1; * accessed (by internal backend processes) before the bootstrap
* script nominally creates it. Therefore, allow the file to exist
fd = FileNameOpenFile(path, O_RDWR | PG_BINARY, 0600); * already, but in bootstrap mode only. (See also mdopen)
*/
if (IsBootstrapProcessingMode())
fd = FileNameOpenFile(path, O_RDWR | PG_BINARY, 0600);
if (fd < 0) if (fd < 0)
{ {
pfree(path);
/* be sure to return the error reported by create, not open */ /* be sure to return the error reported by create, not open */
errno = save_errno; errno = save_errno;
return -1; return -1;
} }
if (!IsBootstrapProcessingMode())
{
bool reuse = false;
long len = FileSeek(fd, 0L, SEEK_END);
if (len == 0)
reuse = true;
else if (reln->rd_rel->relkind == RELKIND_INDEX &&
len == BLCKSZ * 2)
reuse = true;
if (!reuse)
{
FileClose(fd);
/* be sure to return the error reported by create */
errno = save_errno;
return -1;
}
}
errno = 0; errno = 0;
} }
reln->rd_unlinked = false;
pfree(path);
vfd = _fdvec_alloc(); vfd = _fdvec_alloc();
if (vfd < 0) if (vfd < 0)
...@@ -187,12 +163,10 @@ mdcreate(Relation reln) ...@@ -187,12 +163,10 @@ mdcreate(Relation reln)
Md_fdvec[vfd].mdfd_vfd = fd; Md_fdvec[vfd].mdfd_vfd = fd;
Md_fdvec[vfd].mdfd_flags = (uint16) 0; Md_fdvec[vfd].mdfd_flags = (uint16) 0;
Md_fdvec[vfd].mdfd_lstbcnt = 0;
#ifndef LET_OS_MANAGE_FILESIZE #ifndef LET_OS_MANAGE_FILESIZE
Md_fdvec[vfd].mdfd_chain = (MdfdVec *) NULL; Md_fdvec[vfd].mdfd_chain = (MdfdVec *) NULL;
#endif #endif
Md_fdvec[vfd].mdfd_lstbcnt = 0;
pfree(path);
return vfd; return vfd;
} }
...@@ -201,65 +175,50 @@ mdcreate(Relation reln) ...@@ -201,65 +175,50 @@ mdcreate(Relation reln)
* mdunlink() -- Unlink a relation. * mdunlink() -- Unlink a relation.
*/ */
int int
mdunlink(Relation reln) mdunlink(RelFileNode rnode)
{ {
int nblocks; int status = SM_SUCCESS;
int fd; int save_errno = 0;
MdfdVec *v; char *path;
/*
* If the relation is already unlinked,we have nothing to do any more.
*/
if (reln->rd_unlinked && reln->rd_fd < 0)
return SM_SUCCESS;
/*
* Force all segments of the relation to be opened, so that we won't
* miss deleting any of them.
*/
nblocks = mdnblocks(reln);
/* path = relpath(rnode);
* Clean out the mdfd vector, letting fd.c unlink the physical files.
*
* NOTE: We truncate the file(s) before deleting 'em, because if other
* backends are holding the files open, the unlink will fail on some
* platforms (think Microsoft). Better a zero-size file gets left
* around than a big file. Those other backends will be forced to
* close the relation by cache invalidation, but that probably hasn't
* happened yet.
*/
fd = RelationGetFile(reln);
if (fd < 0) /* should not happen */
elog(ERROR, "mdunlink: mdnblocks didn't open relation");
Md_fdvec[fd].mdfd_flags = (uint16) 0; /* Delete the first segment, or only segment if not doing segmenting */
if (unlink(path) < 0)
{
status = SM_FAIL;
save_errno = errno;
}
#ifndef LET_OS_MANAGE_FILESIZE #ifndef LET_OS_MANAGE_FILESIZE
for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;) /* Get the additional segments, if any */
if (status == SM_SUCCESS)
{ {
MdfdVec *ov = v; char *segpath = (char *) palloc(strlen(path) + 12);
int segno;
FileTruncate(v->mdfd_vfd, 0); for (segno = 1; ; segno++)
FileUnlink(v->mdfd_vfd); {
v = v->mdfd_chain; sprintf(segpath, "%s.%d", path, segno);
if (ov != &Md_fdvec[fd]) if (unlink(segpath) < 0)
pfree(ov); {
/* ENOENT is expected after the last segment... */
if (errno != ENOENT)
{
status = SM_FAIL;
save_errno = errno;
}
break;
}
}
pfree(segpath);
} }
Md_fdvec[fd].mdfd_chain = (MdfdVec *) NULL;
#else
v = &Md_fdvec[fd];
FileTruncate(v->mdfd_vfd, 0);
FileUnlink(v->mdfd_vfd);
#endif #endif
_fdvec_free(fd); pfree(path);
/* be sure to mark relation closed && unlinked */
reln->rd_fd = -1;
reln->rd_unlinked = true;
return SM_SUCCESS; errno = save_errno;
return status;
} }
/* /*
...@@ -327,24 +286,29 @@ mdopen(Relation reln) ...@@ -327,24 +286,29 @@ mdopen(Relation reln)
int vfd; int vfd;
Assert(reln->rd_fd < 0); Assert(reln->rd_fd < 0);
path = relpath(reln->rd_node); path = relpath(reln->rd_node);
fd = FileNameOpenFile(path, O_RDWR | PG_BINARY, 0600); fd = FileNameOpenFile(path, O_RDWR | PG_BINARY, 0600);
if (fd < 0) if (fd < 0)
{ {
/* in bootstrap mode, accept mdopen as substitute for mdcreate */ /*
* During bootstrap, there are cases where a system relation will be
* accessed (by internal backend processes) before the bootstrap
* script nominally creates it. Therefore, accept mdopen() as a
* substitute for mdcreate() in bootstrap mode only. (See mdcreate)
*/
if (IsBootstrapProcessingMode()) if (IsBootstrapProcessingMode())
fd = FileNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600); fd = FileNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, 0600);
if (fd < 0) if (fd < 0)
{ {
elog(NOTICE, "mdopen: couldn't open %s: %m", path); pfree(path);
/* mark relation closed and unlinked */
reln->rd_fd = -1;
reln->rd_unlinked = true;
return -1; return -1;
} }
} }
reln->rd_unlinked = false;
pfree(path);
vfd = _fdvec_alloc(); vfd = _fdvec_alloc();
if (vfd < 0) if (vfd < 0)
...@@ -362,8 +326,6 @@ mdopen(Relation reln) ...@@ -362,8 +326,6 @@ mdopen(Relation reln)
#endif #endif
#endif #endif
pfree(path);
return vfd; return vfd;
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/Attic/mm.c,v 1.19 2000/04/10 23:41:51 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/smgr/Attic/mm.c,v 1.20 2000/11/08 22:10:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -204,9 +204,11 @@ mmcreate(Relation reln) ...@@ -204,9 +204,11 @@ mmcreate(Relation reln)
/* /*
* mmunlink() -- Unlink a relation. * mmunlink() -- Unlink a relation.
*
* XXX currently broken: needs to accept RelFileNode, not Relation
*/ */
int int
mmunlink(Relation reln) mmunlink(RelFileNode rnode)
{ {
int i; int i;
Oid reldbid; Oid reldbid;
......
...@@ -11,13 +11,16 @@ ...@@ -11,13 +11,16 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.42 2000/10/28 16:20:57 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.43 2000/11/08 22:10:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "storage/bufmgr.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "utils/memutils.h"
static void smgrshutdown(void); static void smgrshutdown(void);
...@@ -26,7 +29,7 @@ typedef struct f_smgr ...@@ -26,7 +29,7 @@ typedef struct f_smgr
int (*smgr_init) (void); /* may be NULL */ int (*smgr_init) (void); /* may be NULL */
int (*smgr_shutdown) (void); /* may be NULL */ int (*smgr_shutdown) (void); /* may be NULL */
int (*smgr_create) (Relation reln); int (*smgr_create) (Relation reln);
int (*smgr_unlink) (Relation reln); int (*smgr_unlink) (RelFileNode rnode);
int (*smgr_extend) (Relation reln, char *buffer); int (*smgr_extend) (Relation reln, char *buffer);
int (*smgr_open) (Relation reln); int (*smgr_open) (Relation reln);
int (*smgr_close) (Relation reln); int (*smgr_close) (Relation reln);
...@@ -60,10 +63,11 @@ static f_smgr smgrsw[] = { ...@@ -60,10 +63,11 @@ static f_smgr smgrsw[] = {
{mdinit, NULL, mdcreate, mdunlink, mdextend, mdopen, mdclose, {mdinit, NULL, mdcreate, mdunlink, mdextend, mdopen, mdclose,
mdread, mdwrite, mdflush, mdblindwrt, mdmarkdirty, mdblindmarkdirty, mdread, mdwrite, mdflush, mdblindwrt, mdmarkdirty, mdblindmarkdirty,
#ifdef XLOG #ifdef XLOG
mdnblocks, mdtruncate, mdcommit, mdabort, mdsync}, mdnblocks, mdtruncate, mdcommit, mdabort, mdsync
#else #else
mdnblocks, mdtruncate, mdcommit, mdabort}, mdnblocks, mdtruncate, mdcommit, mdabort
#endif #endif
},
#ifdef STABLE_MEMORY_STORAGE #ifdef STABLE_MEMORY_STORAGE
/* main memory */ /* main memory */
...@@ -93,6 +97,31 @@ static bool smgrwo[] = { ...@@ -93,6 +97,31 @@ static bool smgrwo[] = {
static int NSmgr = lengthof(smgrsw); static int NSmgr = lengthof(smgrsw);
/*
* We keep a list of all relations (represented as RelFileNode values)
* that have been created or deleted in the current transaction. When
* a relation is created, we create the physical file immediately, but
* remember it so that we can delete the file again if the current
* transaction is aborted. Conversely, a deletion request is NOT
* executed immediately, but is just entered in the list. When and if
* the transaction commits, we can delete the physical file.
*
* NOTE: the list is kept in TopMemoryContext to be sure it won't disappear
* unbetimes. It'd probably be OK to keep it in TopTransactionContext,
* but I'm being paranoid.
*/
typedef struct PendingRelDelete
{
RelFileNode relnode; /* relation that may need to be deleted */
int16 which; /* which storage manager? */
bool atCommit; /* T=delete at commit; F=delete at abort */
struct PendingRelDelete *next; /* linked-list link */
} PendingRelDelete;
static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
/* /*
* smgrinit(), smgrshutdown() -- Initialize or shut down all storage * smgrinit(), smgrshutdown() -- Initialize or shut down all storage
* managers. * managers.
...@@ -147,27 +176,58 @@ int ...@@ -147,27 +176,58 @@ int
smgrcreate(int16 which, Relation reln) smgrcreate(int16 which, Relation reln)
{ {
int fd; int fd;
PendingRelDelete *pending;
if ((fd = (*(smgrsw[which].smgr_create)) (reln)) < 0) if ((fd = (*(smgrsw[which].smgr_create)) (reln)) < 0)
elog(ERROR, "cannot create %s: %m", RelationGetRelationName(reln)); elog(ERROR, "cannot create %s: %m", RelationGetRelationName(reln));
/* Add the relation to the list of stuff to delete at abort */
pending = (PendingRelDelete *)
MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
pending->relnode = reln->rd_node;
pending->which = which;
pending->atCommit = false; /* delete if abort */
pending->next = pendingDeletes;
pendingDeletes = pending;
return fd; return fd;
} }
/* /*
* smgrunlink() -- Unlink a relation. * smgrunlink() -- Unlink a relation.
* *
* The relation is removed from the store. * The relation is removed from the store. Actually, we just remember
* that we want to do this at transaction commit.
*/ */
int int
smgrunlink(int16 which, Relation reln) smgrunlink(int16 which, Relation reln)
{ {
int status; PendingRelDelete *pending;
if ((status = (*(smgrsw[which].smgr_unlink)) (reln)) == SM_FAIL) /* Make sure the file is closed */
elog(ERROR, "cannot unlink %s: %m", RelationGetRelationName(reln)); if (reln->rd_fd >= 0)
smgrclose(which, reln);
/* Add the relation to the list of stuff to delete at commit */
pending = (PendingRelDelete *)
MemoryContextAlloc(TopMemoryContext, sizeof(PendingRelDelete));
pending->relnode = reln->rd_node;
pending->which = which;
pending->atCommit = true; /* delete if commit */
pending->next = pendingDeletes;
pendingDeletes = pending;
/*
* NOTE: if the relation was created in this transaction, it will now
* be present in the pending-delete list twice, once with atCommit true
* and once with atCommit false. Hence, it will be physically deleted
* at end of xact in either case (and the other entry will be ignored
* by smgrDoPendingDeletes, so no error will occur). We could instead
* remove the existing list entry and delete the physical file
* immediately, but for now I'll keep the logic simple.
*/
return status; return SM_SUCCESS;
} }
/* /*
...@@ -193,17 +253,18 @@ smgrextend(int16 which, Relation reln, char *buffer) ...@@ -193,17 +253,18 @@ smgrextend(int16 which, Relation reln, char *buffer)
/* /*
* smgropen() -- Open a relation using a particular storage manager. * smgropen() -- Open a relation using a particular storage manager.
* *
* Returns the fd for the open relation on success, aborts the * Returns the fd for the open relation on success.
* transaction on failure. *
* On failure, returns -1 if failOK, else aborts the transaction.
*/ */
int int
smgropen(int16 which, Relation reln) smgropen(int16 which, Relation reln, bool failOK)
{ {
int fd; int fd;
if ((fd = (*(smgrsw[which].smgr_open)) (reln)) < 0 && if ((fd = (*(smgrsw[which].smgr_open)) (reln)) < 0)
!reln->rd_unlinked) if (! failOK)
elog(ERROR, "cannot open %s: %m", RelationGetRelationName(reln)); elog(ERROR, "cannot open %s: %m", RelationGetRelationName(reln));
return fd; return fd;
} }
...@@ -211,12 +272,6 @@ smgropen(int16 which, Relation reln) ...@@ -211,12 +272,6 @@ smgropen(int16 which, Relation reln)
/* /*
* smgrclose() -- Close a relation. * smgrclose() -- Close a relation.
* *
* NOTE: underlying manager should allow case where relation is
* already closed. Indeed relation may have been unlinked!
* This is currently called only from RelationFlushRelation() when
* the relation cache entry is about to be dropped; could be doing
* simple relation cache clear, or finishing up DROP TABLE.
*
* Returns SM_SUCCESS on success, aborts on failure. * Returns SM_SUCCESS on success, aborts on failure.
*/ */
int int
...@@ -411,6 +466,41 @@ smgrtruncate(int16 which, Relation reln, int nblocks) ...@@ -411,6 +466,41 @@ smgrtruncate(int16 which, Relation reln, int nblocks)
return newblks; return newblks;
} }
/*
* smgrDoPendingDeletes() -- take care of relation deletes at end of xact.
*/
int
smgrDoPendingDeletes(bool isCommit)
{
while (pendingDeletes != NULL)
{
PendingRelDelete *pending = pendingDeletes;
pendingDeletes = pending->next;
if (pending->atCommit == isCommit)
{
/*
* Get rid of any leftover buffers for the rel (shouldn't be
* any in the commit case, but there can be in the abort case).
*/
DropRelFileNodeBuffers(pending->relnode);
/*
* And delete the physical files.
*
* Note: we treat deletion failure as a NOTICE, not an error,
* because we've already decided to commit or abort the current
* xact.
*/
if ((*(smgrsw[pending->which].smgr_unlink)) (pending->relnode) == SM_FAIL)
elog(NOTICE, "cannot unlink %u/%u: %m",
pending->relnode.tblNode, pending->relnode.relNode);
}
pfree(pending);
}
return SM_SUCCESS;
}
/* /*
* smgrcommit(), smgrabort() -- Commit or abort changes made during the * smgrcommit(), smgrabort() -- Commit or abort changes made during the
* current transaction. * current transaction.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.37 2000/06/08 19:51:03 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.38 2000/11/08 22:10:01 tgl Exp $
* *
* Note - this code is real crufty... * Note - this code is real crufty...
* *
...@@ -80,10 +80,10 @@ typedef InvalidationMessageData *InvalidationMessage; ...@@ -80,10 +80,10 @@ typedef InvalidationMessageData *InvalidationMessage;
/* /*
* ---------------- * ----------------
* Invalidation info was devided into three parts. * Invalidation info is divided into three parts.
* 1) shared invalidation to be registerd for all backends * 1) shared invalidation to be registered for all backends
* 2) local invalidation for the transaction itself * 2) local invalidation for the transaction itself
* 3) rollback information for the transaction itself * 3) rollback information for the transaction itself (in case we abort)
* ---------------- * ----------------
*/ */
...@@ -160,7 +160,9 @@ LocalInvalidRegister(LocalInvalid invalid, ...@@ -160,7 +160,9 @@ LocalInvalidRegister(LocalInvalid invalid,
* -------------------------------- * --------------------------------
*/ */
static void static void
LocalInvalidInvalidate(LocalInvalid invalid, void (*function) (), bool freemember) LocalInvalidInvalidate(LocalInvalid invalid,
void (*function) (),
bool freemember)
{ {
InvalidationEntryData *entryDataP; InvalidationEntryData *entryDataP;
...@@ -216,15 +218,10 @@ elog(DEBUG, "CacheIdRegisterLocalInvalid(%d, %d, [%d, %d])", \ ...@@ -216,15 +218,10 @@ elog(DEBUG, "CacheIdRegisterLocalInvalid(%d, %d, [%d, %d])", \
elog(DEBUG, "CacheIdRegisterLocalRollback(%d, %d, [%d, %d])", \ elog(DEBUG, "CacheIdRegisterLocalRollback(%d, %d, [%d, %d])", \
cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \ cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \
ItemPointerGetOffsetNumber(pointer)) ItemPointerGetOffsetNumber(pointer))
#define CacheIdImmediateRegisterSharedInvalid_DEBUG1 \
elog(DEBUG, "CacheIdImmediateRegisterSharedInvalid(%d, %d, [%d, %d])", \
cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \
ItemPointerGetOffsetNumber(pointer))
#else #else
#define CacheIdRegisterSpecifiedLocalInvalid_DEBUG1 #define CacheIdRegisterSpecifiedLocalInvalid_DEBUG1
#define CacheIdRegisterLocalInvalid_DEBUG1 #define CacheIdRegisterLocalInvalid_DEBUG1
#define CacheIdRegisterLocalRollback_DEBUG1 #define CacheIdRegisterLocalRollback_DEBUG1
#define CacheIdImmediateRegisterSharedInvalid_DEBUG1
#endif /* INVALIDDEBUG */ #endif /* INVALIDDEBUG */
/* -------------------------------- /* --------------------------------
...@@ -233,7 +230,9 @@ elog(DEBUG, "CacheIdImmediateRegisterSharedInvalid(%d, %d, [%d, %d])", \ ...@@ -233,7 +230,9 @@ elog(DEBUG, "CacheIdImmediateRegisterSharedInvalid(%d, %d, [%d, %d])", \
*/ */
static LocalInvalid static LocalInvalid
CacheIdRegisterSpecifiedLocalInvalid(LocalInvalid invalid, CacheIdRegisterSpecifiedLocalInvalid(LocalInvalid invalid,
Index cacheId, Index hashIndex, ItemPointer pointer) Index cacheId,
Index hashIndex,
ItemPointer pointer)
{ {
InvalidationMessage message; InvalidationMessage message;
...@@ -317,43 +316,6 @@ CacheIdRegisterLocalRollback(Index cacheId, Index hashIndex, ...@@ -317,43 +316,6 @@ CacheIdRegisterLocalRollback(Index cacheId, Index hashIndex,
RollbackStack, cacheId, hashIndex, pointer); RollbackStack, cacheId, hashIndex, pointer);
} }
/* --------------------------------
* CacheIdImmediateRegisterSharedInvalid
* --------------------------------
*/
static void
CacheIdImmediateRegisterSharedInvalid(Index cacheId, Index hashIndex,
ItemPointer pointer)
{
InvalidationMessage message;
/* ----------------
* debugging stuff
* ----------------
*/
CacheIdImmediateRegisterSharedInvalid_DEBUG1;
/* ----------------
* create a message describing the system catalog tuple
* we wish to invalidate.
* ----------------
*/
message = (InvalidationMessage)
InvalidationEntryAllocate(sizeof(InvalidationMessageData));
message->kind = 'c';
message->any.catalog.cacheId = cacheId;
message->any.catalog.hashIndex = hashIndex;
ItemPointerCopy(pointer, &message->any.catalog.pointerData);
/* ----------------
* Register a shared catalog cache invalidation.
* ----------------
*/
InvalidationMessageRegisterSharedInvalid(message);
free((Pointer) &((InvalidationUserData *) message)->dataP[-1]);
}
/* -------------------------------- /* --------------------------------
* RelationIdRegisterSpecifiedLocalInvalid * RelationIdRegisterSpecifiedLocalInvalid
* -------------------------------- * --------------------------------
...@@ -448,44 +410,6 @@ RelationIdRegisterLocalRollback(Oid relationId, Oid objectId) ...@@ -448,44 +410,6 @@ RelationIdRegisterLocalRollback(Oid relationId, Oid objectId)
RollbackStack, relationId, objectId); RollbackStack, relationId, objectId);
} }
/* --------------------------------
* RelationIdImmediateRegisterSharedInvalid
* --------------------------------
*/
static void
RelationIdImmediateRegisterSharedInvalid(Oid relationId, Oid objectId)
{
InvalidationMessage message;
/* ----------------
* debugging stuff
* ----------------
*/
#ifdef INVALIDDEBUG
elog(DEBUG, "RelationImmediateRegisterSharedInvalid(%u, %u)", relationId,
objectId);
#endif /* defined(INVALIDDEBUG) */
/* ----------------
* create a message describing the relation descriptor
* we wish to invalidate.
* ----------------
*/
message = (InvalidationMessage)
InvalidationEntryAllocate(sizeof(InvalidationMessageData));
message->kind = 'r';
message->any.relation.relationId = relationId;
message->any.relation.objectId = objectId;
/* ----------------
* Register a shared catalog cache invalidation.
* ----------------
*/
InvalidationMessageRegisterSharedInvalid(message);
free((Pointer) &((InvalidationUserData *) message)->dataP[-1]);
}
/* -------------------------------- /* --------------------------------
* CacheIdInvalidate * CacheIdInvalidate
* *
...@@ -890,55 +814,3 @@ RelationMark4RollbackHeapTuple(Relation relation, HeapTuple tuple) ...@@ -890,55 +814,3 @@ RelationMark4RollbackHeapTuple(Relation relation, HeapTuple tuple)
RelationIdRegisterLocalRollback, RelationIdRegisterLocalRollback,
"RelationMark4RollbackHeapTuple"); "RelationMark4RollbackHeapTuple");
} }
/*
* ImmediateInvalidateSharedHeapTuple
* Different from RelationInvalidateHeapTuple()
* this function queues shared invalidation info immediately.
*/
void
ImmediateInvalidateSharedHeapTuple(Relation relation, HeapTuple tuple)
{
InvokeHeapTupleInvalidation(relation, tuple,
CacheIdImmediateRegisterSharedInvalid,
RelationIdImmediateRegisterSharedInvalid,
"ImmediateInvalidateSharedHeapTuple");
}
#ifdef NOT_USED
/*
* ImmediateSharedRelationCacheInvalidate
* Register shared relation cache invalidation immediately
*
* This is needed for smgrunlink()/smgrtruncate().
* Those functions unlink/truncate the base file immediately
* and couldn't be rollbacked in case of abort/crash.
* So relation cache invalidation must be registerd immediately.
* Note:
* Assumes Relation is valid.
*/
void
ImmediateSharedRelationCacheInvalidate(Relation relation)
{
/* ----------------
* sanity checks
* ----------------
*/
Assert(RelationIsValid(relation));
if (IsBootstrapProcessingMode())
return;
/* ----------------
* debugging stuff
* ----------------
*/
#ifdef INVALIDDEBUG
elog(DEBUG, "ImmediateSharedRelationCacheInvalidate(%s)", \
RelationGetPhysicalRelationName(relation));
#endif /* defined(INVALIDDEBUG) */
RelationIdImmediateRegisterSharedInvalid(
RelOid_pg_class, RelationGetRelid(relation));
}
#endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.114 2000/10/28 16:20:57 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.115 2000/11/08 22:10:01 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -954,7 +954,6 @@ static Relation ...@@ -954,7 +954,6 @@ static Relation
RelationBuildDesc(RelationBuildDescInfo buildinfo, RelationBuildDesc(RelationBuildDescInfo buildinfo,
Relation oldrelation) Relation oldrelation)
{ {
File fd;
Relation relation; Relation relation;
Oid relid; Oid relid;
Oid relam; Oid relam;
...@@ -1069,18 +1068,10 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo, ...@@ -1069,18 +1068,10 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
* by the storage manager code to rd_fd. * by the storage manager code to rd_fd.
* ---------------- * ----------------
*/ */
if (relation->rd_rel->relkind != RELKIND_VIEW) { if (relation->rd_rel->relkind != RELKIND_VIEW)
fd = smgropen(DEFAULT_SMGR, relation); relation->rd_fd = smgropen(DEFAULT_SMGR, relation, false);
else
Assert(fd >= -1);
if (fd == -1)
elog(NOTICE, "RelationBuildDesc: smgropen(%s): %m",
NameStr(relation->rd_rel->relname));
relation->rd_fd = fd;
} else {
relation->rd_fd = -1; relation->rd_fd = -1;
}
/* ---------------- /* ----------------
* insert newly created relation into proper relcaches, * insert newly created relation into proper relcaches,
...@@ -1337,14 +1328,11 @@ RelationIdCacheGetRelation(Oid relationId) ...@@ -1337,14 +1328,11 @@ RelationIdCacheGetRelation(Oid relationId)
if (RelationIsValid(rd)) if (RelationIsValid(rd))
{ {
/* re-open files if necessary */
if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW) if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
{ rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
Assert(rd->rd_fd != -1 || rd->rd_unlinked);
}
RelationIncrementReferenceCount(rd); RelationIncrementReferenceCount(rd);
} }
return rd; return rd;
...@@ -1371,14 +1359,11 @@ RelationNameCacheGetRelation(const char *relationName) ...@@ -1371,14 +1359,11 @@ RelationNameCacheGetRelation(const char *relationName)
if (RelationIsValid(rd)) if (RelationIsValid(rd))
{ {
/* re-open files if necessary */
if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW) if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
{ rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
Assert(rd->rd_fd != -1 || rd->rd_unlinked);
}
RelationIncrementReferenceCount(rd); RelationIncrementReferenceCount(rd);
} }
return rd; return rd;
...@@ -1393,14 +1378,11 @@ RelationNodeCacheGetRelation(RelFileNode rnode) ...@@ -1393,14 +1378,11 @@ RelationNodeCacheGetRelation(RelFileNode rnode)
if (RelationIsValid(rd)) if (RelationIsValid(rd))
{ {
/* re-open files if necessary */
if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW) if (rd->rd_fd == -1 && rd->rd_rel->relkind != RELKIND_VIEW)
{ rd->rd_fd = smgropen(DEFAULT_SMGR, rd, false);
rd->rd_fd = smgropen(DEFAULT_SMGR, rd);
Assert(rd->rd_fd != -1 || rd->rd_unlinked);
}
RelationIncrementReferenceCount(rd); RelationIncrementReferenceCount(rd);
} }
return rd; return rd;
...@@ -1536,15 +1518,13 @@ RelationClearRelation(Relation relation, bool rebuildIt) ...@@ -1536,15 +1518,13 @@ RelationClearRelation(Relation relation, bool rebuildIt)
/* /*
* Make sure smgr and lower levels close the relation's files, if they * Make sure smgr and lower levels close the relation's files, if they
* weren't closed already. We do this unconditionally; if the * weren't closed already. If the relation is not getting deleted,
* relation is not deleted, the next smgr access should reopen the * the next smgr access should reopen the files automatically. This
* files automatically. This ensures that the low-level file access * ensures that the low-level file access state is updated after, say,
* state is updated after, say, a vacuum truncation. * a vacuum truncation.
*
* NOTE: this call is a no-op if the relation's smgr file is already
* closed or unlinked.
*/ */
smgrclose(DEFAULT_SMGR, relation); if (relation->rd_fd >= 0)
smgrclose(DEFAULT_SMGR, relation);
/* /*
* Never, never ever blow away a nailed-in system relation, because * Never, never ever blow away a nailed-in system relation, because
...@@ -1617,7 +1597,6 @@ RelationClearRelation(Relation relation, bool rebuildIt) ...@@ -1617,7 +1597,6 @@ RelationClearRelation(Relation relation, bool rebuildIt)
MemoryContext old_rulescxt = relation->rd_rulescxt; MemoryContext old_rulescxt = relation->rd_rulescxt;
TriggerDesc *old_trigdesc = relation->trigdesc; TriggerDesc *old_trigdesc = relation->trigdesc;
int old_nblocks = relation->rd_nblocks; int old_nblocks = relation->rd_nblocks;
bool relDescChanged = false;
RelationBuildDescInfo buildinfo; RelationBuildDescInfo buildinfo;
buildinfo.infotype = INFO_RELID; buildinfo.infotype = INFO_RELID;
...@@ -1644,7 +1623,6 @@ RelationClearRelation(Relation relation, bool rebuildIt) ...@@ -1644,7 +1623,6 @@ RelationClearRelation(Relation relation, bool rebuildIt)
else else
{ {
FreeTupleDesc(old_att); FreeTupleDesc(old_att);
relDescChanged = true;
} }
if (equalRuleLocks(old_rules, relation->rd_rules)) if (equalRuleLocks(old_rules, relation->rd_rules))
{ {
...@@ -1657,7 +1635,6 @@ RelationClearRelation(Relation relation, bool rebuildIt) ...@@ -1657,7 +1635,6 @@ RelationClearRelation(Relation relation, bool rebuildIt)
{ {
if (old_rulescxt) if (old_rulescxt)
MemoryContextDelete(old_rulescxt); MemoryContextDelete(old_rulescxt);
relDescChanged = true;
} }
if (equalTriggerDescs(old_trigdesc, relation->trigdesc)) if (equalTriggerDescs(old_trigdesc, relation->trigdesc))
{ {
...@@ -1667,7 +1644,6 @@ RelationClearRelation(Relation relation, bool rebuildIt) ...@@ -1667,7 +1644,6 @@ RelationClearRelation(Relation relation, bool rebuildIt)
else else
{ {
FreeTriggerDesc(old_trigdesc); FreeTriggerDesc(old_trigdesc);
relDescChanged = true;
} }
relation->rd_nblocks = old_nblocks; relation->rd_nblocks = old_nblocks;
...@@ -1675,14 +1651,7 @@ RelationClearRelation(Relation relation, bool rebuildIt) ...@@ -1675,14 +1651,7 @@ RelationClearRelation(Relation relation, bool rebuildIt)
* this is kind of expensive, but I think we must do it in case * this is kind of expensive, but I think we must do it in case
* relation has been truncated... * relation has been truncated...
*/ */
if (relation->rd_unlinked) relation->rd_nblocks = RelationGetNumberOfBlocks(relation);
relation->rd_nblocks = 0;
else
relation->rd_nblocks = RelationGetNumberOfBlocks(relation);
if (relDescChanged && !RelationHasReferenceCountZero(relation))
elog(ERROR, "RelationClearRelation: relation %u modified while in use",
buildinfo.i.info_id);
} }
} }
...@@ -1934,9 +1903,6 @@ RelationRegisterRelation(Relation relation) ...@@ -1934,9 +1903,6 @@ RelationRegisterRelation(Relation relation)
void void
RelationPurgeLocalRelation(bool xactCommitted) RelationPurgeLocalRelation(bool xactCommitted)
{ {
if (newlyCreatedRelns == NULL)
return;
while (newlyCreatedRelns) while (newlyCreatedRelns)
{ {
List *l = newlyCreatedRelns; List *l = newlyCreatedRelns;
...@@ -1949,19 +1915,7 @@ RelationPurgeLocalRelation(bool xactCommitted) ...@@ -1949,19 +1915,7 @@ RelationPurgeLocalRelation(bool xactCommitted)
newlyCreatedRelns = lnext(newlyCreatedRelns); newlyCreatedRelns = lnext(newlyCreatedRelns);
pfree(l); pfree(l);
if (!xactCommitted) /* XXX is this step still needed? If so, why? */
{
/*
* remove the file if we abort. This is so that files for
* tables created inside a transaction block get removed.
*/
if (! reln->rd_unlinked)
{
smgrunlink(DEFAULT_SMGR, reln);
reln->rd_unlinked = true;
}
}
if (!IsBootstrapProcessingMode()) if (!IsBootstrapProcessingMode())
RelationClearRelation(reln, false); RelationClearRelation(reln, false);
} }
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: heap.h,v 1.31 2000/07/04 06:11:54 tgl Exp $ * $Id: heap.h,v 1.32 2000/11/08 22:10:01 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -29,7 +29,7 @@ extern Relation heap_create(char *relname, TupleDesc tupDesc, ...@@ -29,7 +29,7 @@ extern Relation heap_create(char *relname, TupleDesc tupDesc,
bool istemp, bool storage_create, bool istemp, bool storage_create,
bool allow_system_table_mods); bool allow_system_table_mods);
extern bool heap_storage_create(Relation rel); extern void heap_storage_create(Relation rel);
extern Oid heap_create_with_catalog(char *relname, TupleDesc tupdesc, extern Oid heap_create_with_catalog(char *relname, TupleDesc tupdesc,
char relkind, bool istemp, char relkind, bool istemp,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: index.h,v 1.29 2000/07/14 22:17:56 tgl Exp $ * $Id: index.h,v 1.30 2000/11/08 22:10:01 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -46,9 +46,9 @@ extern void FormIndexDatum(IndexInfo *indexInfo, ...@@ -46,9 +46,9 @@ extern void FormIndexDatum(IndexInfo *indexInfo,
Datum *datum, Datum *datum,
char *nullv); char *nullv);
extern void UpdateStats(Oid relid, long reltuples, bool inplace); extern void UpdateStats(Oid relid, long reltuples);
extern bool IndexesAreActive(Oid relid, bool comfirmCommitted); extern bool IndexesAreActive(Oid relid, bool comfirmCommitted);
extern void setRelhasindexInplace(Oid relid, bool hasindex, bool immediate); extern void setRelhasindex(Oid relid, bool hasindex);
extern bool SetReindexProcessing(bool processing); extern bool SetReindexProcessing(bool processing);
extern bool IsReindexProcessing(void); extern bool IsReindexProcessing(void);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_clause.h,v 1.19 2000/09/12 21:07:12 tgl Exp $ * $Id: parse_clause.h,v 1.20 2000/11/08 22:10:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "parser/parse_node.h" #include "parser/parse_node.h"
extern void makeRangeTable(ParseState *pstate, List *frmList); extern void makeRangeTable(ParseState *pstate, List *frmList);
extern void lockTargetTable(ParseState *pstate, char *relname);
extern void setTargetTable(ParseState *pstate, char *relname, extern void setTargetTable(ParseState *pstate, char *relname,
bool inh, bool inJoinSet); bool inh, bool inJoinSet);
extern Node *transformWhereClause(ParseState *pstate, Node *where); extern Node *transformWhereClause(ParseState *pstate, Node *where);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_node.h,v 1.22 2000/09/29 18:21:40 tgl Exp $ * $Id: parse_node.h,v 1.23 2000/11/08 22:10:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -26,6 +26,7 @@ typedef struct ParseState ...@@ -26,6 +26,7 @@ typedef struct ParseState
List *p_joinlist; /* join items so far (will become List *p_joinlist; /* join items so far (will become
* FromExpr node's fromlist) */ * FromExpr node's fromlist) */
int p_last_resno; /* last targetlist resno assigned */ int p_last_resno; /* last targetlist resno assigned */
List *p_forUpdate; /* FOR UPDATE clause, if any (see gram.y) */
bool p_hasAggs; bool p_hasAggs;
bool p_hasSubLinks; bool p_hasSubLinks;
bool p_is_insert; bool p_is_insert;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: buf_internals.h,v 1.42 2000/10/28 16:21:00 vadim Exp $ * $Id: buf_internals.h,v 1.43 2000/11/08 22:10:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -200,7 +200,7 @@ extern int NLocBuffer; ...@@ -200,7 +200,7 @@ extern int NLocBuffer;
extern BufferDesc *LocalBufferAlloc(Relation reln, BlockNumber blockNum, extern BufferDesc *LocalBufferAlloc(Relation reln, BlockNumber blockNum,
bool *foundPtr); bool *foundPtr);
extern int WriteLocalBuffer(Buffer buffer, bool release); extern int WriteLocalBuffer(Buffer buffer, bool release);
extern int FlushLocalBuffer(Buffer buffer, bool release); extern int FlushLocalBuffer(Buffer buffer, bool sync, bool release);
extern void InitLocalBuffer(void); extern void InitLocalBuffer(void);
extern void LocalBufferSync(void); extern void LocalBufferSync(void);
extern void ResetLocalBufferPool(void); extern void ResetLocalBufferPool(void);
......
...@@ -7,15 +7,16 @@ ...@@ -7,15 +7,16 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: bufmgr.h,v 1.42 2000/10/28 16:21:00 vadim Exp $ * $Id: bufmgr.h,v 1.43 2000/11/08 22:10:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef BUFMGR_H #ifndef BUFMGR_H
#define BUFMGR_H #define BUFMGR_H
#include "storage/buf_internals.h"
#include "access/xlogdefs.h" #include "access/xlogdefs.h"
#include "storage/buf_internals.h"
#include "storage/relfilenode.h"
typedef void *Block; typedef void *Block;
...@@ -151,7 +152,7 @@ extern int WriteBuffer(Buffer buffer); ...@@ -151,7 +152,7 @@ extern int WriteBuffer(Buffer buffer);
extern int WriteNoReleaseBuffer(Buffer buffer); extern int WriteNoReleaseBuffer(Buffer buffer);
extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation,
BlockNumber blockNum); BlockNumber blockNum);
extern int FlushBuffer(Buffer buffer, bool release); extern int FlushBuffer(Buffer buffer, bool sync, bool release);
extern void InitBufferPool(IPCKey key); extern void InitBufferPool(IPCKey key);
extern void PrintBufferUsage(FILE *statfp); extern void PrintBufferUsage(FILE *statfp);
...@@ -162,7 +163,8 @@ extern void FlushBufferPool(void); ...@@ -162,7 +163,8 @@ extern void FlushBufferPool(void);
extern BlockNumber BufferGetBlockNumber(Buffer buffer); extern BlockNumber BufferGetBlockNumber(Buffer buffer);
extern BlockNumber RelationGetNumberOfBlocks(Relation relation); extern BlockNumber RelationGetNumberOfBlocks(Relation relation);
extern int FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock); extern int FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock);
extern void ReleaseRelationBuffers(Relation rel); extern void DropRelationBuffers(Relation rel);
extern void DropRelFileNodeBuffers(RelFileNode rnode);
extern void DropBuffers(Oid dbid); extern void DropBuffers(Oid dbid);
extern void PrintPinnedBufs(void); extern void PrintPinnedBufs(void);
extern int BufferShmemSize(void); extern int BufferShmemSize(void);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: smgr.h,v 1.23 2000/10/28 16:21:00 vadim Exp $ * $Id: smgr.h,v 1.24 2000/11/08 22:10:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -28,7 +28,7 @@ extern int smgrinit(void); ...@@ -28,7 +28,7 @@ extern int smgrinit(void);
extern int smgrcreate(int16 which, Relation reln); extern int smgrcreate(int16 which, Relation reln);
extern int smgrunlink(int16 which, Relation reln); extern int smgrunlink(int16 which, Relation reln);
extern int smgrextend(int16 which, Relation reln, char *buffer); extern int smgrextend(int16 which, Relation reln, char *buffer);
extern int smgropen(int16 which, Relation reln); extern int smgropen(int16 which, Relation reln, bool failOK);
extern int smgrclose(int16 which, Relation reln); extern int smgrclose(int16 which, Relation reln);
extern int smgrread(int16 which, Relation reln, BlockNumber blocknum, extern int smgrread(int16 which, Relation reln, BlockNumber blocknum,
char *buffer); char *buffer);
...@@ -43,6 +43,7 @@ extern int smgrblindmarkdirty(int16 which, RelFileNode rnode, ...@@ -43,6 +43,7 @@ extern int smgrblindmarkdirty(int16 which, RelFileNode rnode,
extern int smgrmarkdirty(int16 which, Relation reln, BlockNumber blkno); extern int smgrmarkdirty(int16 which, Relation reln, BlockNumber blkno);
extern int smgrnblocks(int16 which, Relation reln); extern int smgrnblocks(int16 which, Relation reln);
extern int smgrtruncate(int16 which, Relation reln, int nblocks); extern int smgrtruncate(int16 which, Relation reln, int nblocks);
extern int smgrDoPendingDeletes(bool isCommit);
extern int smgrcommit(void); extern int smgrcommit(void);
extern int smgrabort(void); extern int smgrabort(void);
...@@ -56,7 +57,7 @@ extern int smgrsync(void); ...@@ -56,7 +57,7 @@ extern int smgrsync(void);
/* in md.c */ /* in md.c */
extern int mdinit(void); extern int mdinit(void);
extern int mdcreate(Relation reln); extern int mdcreate(Relation reln);
extern int mdunlink(Relation reln); extern int mdunlink(RelFileNode rnode);
extern int mdextend(Relation reln, char *buffer); extern int mdextend(Relation reln, char *buffer);
extern int mdopen(Relation reln); extern int mdopen(Relation reln);
extern int mdclose(Relation reln); extern int mdclose(Relation reln);
...@@ -64,9 +65,9 @@ extern int mdread(Relation reln, BlockNumber blocknum, char *buffer); ...@@ -64,9 +65,9 @@ extern int mdread(Relation reln, BlockNumber blocknum, char *buffer);
extern int mdwrite(Relation reln, BlockNumber blocknum, char *buffer); extern int mdwrite(Relation reln, BlockNumber blocknum, char *buffer);
extern int mdflush(Relation reln, BlockNumber blocknum, char *buffer); extern int mdflush(Relation reln, BlockNumber blocknum, char *buffer);
extern int mdmarkdirty(Relation reln, BlockNumber blkno); extern int mdmarkdirty(Relation reln, BlockNumber blkno);
extern int mdblindwrt(RelFileNode rnode, BlockNumber blkno, extern int mdblindwrt(RelFileNode rnode, BlockNumber blkno,
char *buffer, bool dofsync); char *buffer, bool dofsync);
extern int mdblindmarkdirty(RelFileNode rnode, BlockNumber blkno); extern int mdblindmarkdirty(RelFileNode rnode, BlockNumber blkno);
extern int mdnblocks(Relation reln); extern int mdnblocks(Relation reln);
extern int mdtruncate(Relation reln, int nblocks); extern int mdtruncate(Relation reln, int nblocks);
extern int mdcommit(void); extern int mdcommit(void);
...@@ -81,7 +82,7 @@ extern SPINLOCK MMCacheLock; ...@@ -81,7 +82,7 @@ extern SPINLOCK MMCacheLock;
extern int mminit(void); extern int mminit(void);
extern int mmcreate(Relation reln); extern int mmcreate(Relation reln);
extern int mmunlink(Relation reln); extern int mmunlink(RelFileNode rnode);
extern int mmextend(Relation reln, char *buffer); extern int mmextend(Relation reln, char *buffer);
extern int mmopen(Relation reln); extern int mmopen(Relation reln);
extern int mmclose(Relation reln); extern int mmclose(Relation reln);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: inval.h,v 1.17 2000/06/08 19:51:06 momjian Exp $ * $Id: inval.h,v 1.18 2000/11/08 22:10:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -26,6 +26,4 @@ extern void RelationInvalidateHeapTuple(Relation relation, HeapTuple tuple); ...@@ -26,6 +26,4 @@ extern void RelationInvalidateHeapTuple(Relation relation, HeapTuple tuple);
extern void RelationMark4RollbackHeapTuple(Relation relation, HeapTuple tuple); extern void RelationMark4RollbackHeapTuple(Relation relation, HeapTuple tuple);
extern void ImmediateInvalidateSharedHeapTuple(Relation relation, HeapTuple tuple);
#endif /* INVAL_H */ #endif /* INVAL_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: rel.h,v 1.41 2000/09/07 09:58:38 vadim Exp $ * $Id: rel.h,v 1.42 2000/11/08 22:10:02 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -92,7 +92,6 @@ typedef struct RelationData ...@@ -92,7 +92,6 @@ typedef struct RelationData
uint16 rd_refcnt; /* reference count */ uint16 rd_refcnt; /* reference count */
bool rd_myxactonly; /* rel uses the local buffer mgr */ bool rd_myxactonly; /* rel uses the local buffer mgr */
bool rd_isnailed; /* rel is nailed in cache */ bool rd_isnailed; /* rel is nailed in cache */
bool rd_unlinked; /* rel already unlinked or not created yet */
bool rd_indexfound; /* true if rd_indexlist is valid */ bool rd_indexfound; /* true if rd_indexlist is valid */
bool rd_uniqueindex; /* true if rel is a UNIQUE index */ bool rd_uniqueindex; /* true if rel is a UNIQUE index */
Form_pg_am rd_am; /* AM tuple */ Form_pg_am rd_am; /* AM tuple */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: temprel.h,v 1.11 2000/10/11 21:28:19 momjian Exp $ * $Id: temprel.h,v 1.12 2000/11/08 22:10:03 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -23,7 +23,7 @@ extern bool rename_temp_relation(const char *oldname, ...@@ -23,7 +23,7 @@ extern bool rename_temp_relation(const char *oldname,
const char *newname); const char *newname);
extern void remove_all_temp_relations(void); extern void remove_all_temp_relations(void);
extern void remove_temp_rel_in_myxid(void); extern void AtEOXact_temp_relations(bool isCommit);
extern char *get_temp_rel_by_username(const char *user_relname); extern char *get_temp_rel_by_username(const char *user_relname);
extern char *get_temp_rel_by_physicalname(const char *relname); extern char *get_temp_rel_by_physicalname(const char *relname);
......
...@@ -62,10 +62,10 @@ alter table rename; ...@@ -62,10 +62,10 @@ alter table rename;
ERROR: parser: parse error at or near ";" ERROR: parser: parse error at or near ";"
-- no such relation -- no such relation
alter table nonesuch rename to newnonesuch; alter table nonesuch rename to newnonesuch;
ERROR: Relation 'nonesuch' does not exist ERROR: Relation "nonesuch" does not exist
-- no such relation -- no such relation
alter table nonesuch rename to stud_emp; alter table nonesuch rename to stud_emp;
ERROR: Relation 'nonesuch' does not exist ERROR: Relation "nonesuch" does not exist
-- system relation -- system relation
alter table stud_emp rename to pg_stud_emp; alter table stud_emp rename to pg_stud_emp;
ERROR: renamerel: Illegal class name: "pg_stud_emp" -- pg_ is reserved for system catalogs ERROR: renamerel: Illegal class name: "pg_stud_emp" -- pg_ is reserved for system catalogs
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment