unl2log_20110422.patch
application/octet-stream
Filename: unl2log_20110422.patch
Type: application/octet-stream
Part: 0
Message:
Re: switch UNLOGGED to LOGGED
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/access/transam/twophase.c | 0 | 0 |
| src/backend/access/transam/xact.c | 0 | 0 |
| src/backend/catalog/storage.c | 0 | 0 |
| src/backend/commands/tablecmds.c | 0 | 0 |
| src/backend/parser/gram.y | 0 | 0 |
| src/include/access/xact.h | 0 | 0 |
| src/include/catalog/storage.h | 0 | 0 |
| src/include/nodes/parsenodes.h | 0 | 0 |
| src/include/parser/kwlist.h | 0 | 0 |
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
new file mode 100644
index 2812681..d285cf2
*** a/src/backend/access/transam/twophase.c
--- b/src/backend/access/transam/twophase.c
*************** static void RecordTransactionCommitPrepa
*** 151,156 ****
--- 151,158 ----
RelFileNode *rels,
int ninvalmsgs,
SharedInvalidationMessage *invalmsgs,
+ int ninitforks,
+ RelFileNode *initforks,
bool initfileinval);
static void RecordTransactionAbortPrepared(TransactionId xid,
int nchildren,
*************** typedef struct TwoPhaseFileHeader
*** 769,774 ****
--- 771,777 ----
int32 ncommitrels; /* number of delete-on-commit rels */
int32 nabortrels; /* number of delete-on-abort rels */
int32 ninvalmsgs; /* number of cache invalidation messages */
+ int32 ncommitinitforks;/* number of delete-on-commit init fork rels */
bool initfileinval; /* does relcache init file need invalidation? */
char gid[GIDSIZE]; /* GID for transaction */
} TwoPhaseFileHeader;
*************** StartPrepare(GlobalTransaction gxact)
*** 845,850 ****
--- 848,854 ----
TransactionId *children;
RelFileNode *commitrels;
RelFileNode *abortrels;
+ RelFileNode *commitinitforks;
SharedInvalidationMessage *invalmsgs;
/* Initialize linked list */
*************** StartPrepare(GlobalTransaction gxact)
*** 872,877 ****
--- 876,882 ----
hdr.nabortrels = smgrGetPendingDeletes(false, &abortrels);
hdr.ninvalmsgs = xactGetCommittedInvalidationMessages(&invalmsgs,
&hdr.initfileinval);
+ hdr.ncommitinitforks = smgrGetPendingInitForkDeletes(true, &commitinitforks);
StrNCpy(hdr.gid, gxact->gid, GIDSIZE);
save_state_data(&hdr, sizeof(TwoPhaseFileHeader));
*************** StartPrepare(GlobalTransaction gxact)
*** 902,907 ****
--- 907,918 ----
hdr.ninvalmsgs * sizeof(SharedInvalidationMessage));
pfree(invalmsgs);
}
+ if (hdr.ncommitinitforks > 0)
+ {
+ save_state_data(commitinitforks,
+ hdr.ncommitinitforks * sizeof(RelFileNode));
+ pfree(commitinitforks);
+ }
}
/*
*************** FinishPreparedTransaction(const char *gi
*** 1250,1255 ****
--- 1261,1267 ----
RelFileNode *commitrels;
RelFileNode *abortrels;
RelFileNode *delrels;
+ RelFileNode *commitinitforks;
int ndelrels;
SharedInvalidationMessage *invalmsgs;
int i;
*************** FinishPreparedTransaction(const char *gi
*** 1285,1290 ****
--- 1297,1304 ----
bufptr += MAXALIGN(hdr->nabortrels * sizeof(RelFileNode));
invalmsgs = (SharedInvalidationMessage *) bufptr;
bufptr += MAXALIGN(hdr->ninvalmsgs * sizeof(SharedInvalidationMessage));
+ commitinitforks = (RelFileNode *) bufptr;
+ bufptr += MAXALIGN(hdr->ncommitinitforks * sizeof(RelFileNode));
/* compute latestXid among all children */
latestXid = TransactionIdLatest(xid, hdr->nsubxacts, children);
*************** FinishPreparedTransaction(const char *gi
*** 1302,1307 ****
--- 1316,1323 ----
hdr->nsubxacts, children,
hdr->ncommitrels, commitrels,
hdr->ninvalmsgs, invalmsgs,
+ hdr->ncommitinitforks,
+ commitinitforks,
hdr->initfileinval);
else
RecordTransactionAbortPrepared(xid,
*************** FinishPreparedTransaction(const char *gi
*** 1349,1354 ****
--- 1365,1381 ----
smgrclose(srel);
}
+ if (isCommit)
+ {
+ /* Make sure init fork files supposed to be dropped are dropped */
+ for (i = 0; i < hdr->ncommitinitforks; i++)
+ {
+ SMgrRelation srel = smgropen(commitinitforks[i], InvalidBackendId);
+ if (smgrexists(srel, INIT_FORKNUM))
+ smgrdounlink(srel, INIT_FORKNUM, true);
+ smgrclose(srel);
+ }
+ }
/*
* Handle cache invalidation messages.
*
*************** RecoverPreparedTransactions(void)
*** 1890,1895 ****
--- 1917,1923 ----
bufptr += MAXALIGN(hdr->ncommitrels * sizeof(RelFileNode));
bufptr += MAXALIGN(hdr->nabortrels * sizeof(RelFileNode));
bufptr += MAXALIGN(hdr->ninvalmsgs * sizeof(SharedInvalidationMessage));
+ bufptr += MAXALIGN(hdr->ncommitinitforks * sizeof(RelFileNode));
/*
* It's possible that SubTransSetParent has been set before, if
*************** RecordTransactionCommitPrepared(Transact
*** 1961,1969 ****
RelFileNode *rels,
int ninvalmsgs,
SharedInvalidationMessage *invalmsgs,
bool initfileinval)
{
! XLogRecData rdata[4];
int lastrdata = 0;
xl_xact_commit_prepared xlrec;
XLogRecPtr recptr;
--- 1989,1999 ----
RelFileNode *rels,
int ninvalmsgs,
SharedInvalidationMessage *invalmsgs,
+ int ninitforks,
+ RelFileNode *initforks,
bool initfileinval)
{
! XLogRecData rdata[5];
int lastrdata = 0;
xl_xact_commit_prepared xlrec;
XLogRecPtr recptr;
*************** RecordTransactionCommitPrepared(Transact
*** 1981,1986 ****
--- 2011,2017 ----
xlrec.crec.nrels = nrels;
xlrec.crec.nsubxacts = nchildren;
xlrec.crec.nmsgs = ninvalmsgs;
+ xlrec.crec.ninitforks = ninitforks;
rdata[0].data = (char *) (&xlrec);
rdata[0].len = MinSizeOfXactCommitPrepared;
*************** RecordTransactionCommitPrepared(Transact
*** 2012,2017 ****
--- 2043,2057 ----
rdata[3].buffer = InvalidBuffer;
lastrdata = 3;
}
+ /* dump init fork deletions */
+ if (ninitforks > 0)
+ {
+ rdata[lastrdata].next = &(rdata[4]);
+ rdata[4].data = (char *) initforks;
+ rdata[4].len = ninitforks * sizeof(RelFileNode);
+ rdata[4].buffer = InvalidBuffer;
+ lastrdata = 4;
+ }
rdata[lastrdata].next = NULL;
recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT_PREPARED, rdata);
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
new file mode 100644
index 8a4c4ec..a0bb222
*** a/src/backend/access/transam/xact.c
--- b/src/backend/access/transam/xact.c
*************** RecordTransactionCommit(void)
*** 907,912 ****
--- 907,914 ----
TransactionId latestXid = InvalidTransactionId;
int nrels;
RelFileNode *rels;
+ int ninitforks;
+ RelFileNode *initforks;
int nchildren;
TransactionId *children;
int nmsgs = 0;
*************** RecordTransactionCommit(void)
*** 917,922 ****
--- 919,926 ----
/* Get data needed for commit record */
nrels = smgrGetPendingDeletes(true, &rels);
nchildren = xactGetCommittedChildren(&children);
+ /* TODO 2PC needs this too? */
+ ninitforks = smgrGetPendingInitForkDeletes(true, &initforks);
if (XLogStandbyInfoActive())
nmsgs = xactGetCommittedInvalidationMessages(&invalMessages,
&RelcacheInitFileInval);
*************** RecordTransactionCommit(void)
*** 955,961 ****
/*
* Begin commit critical section and insert the commit XLOG record.
*/
! XLogRecData rdata[4];
int lastrdata = 0;
xl_xact_commit xlrec;
--- 959,965 ----
/*
* Begin commit critical section and insert the commit XLOG record.
*/
! XLogRecData rdata[5];
int lastrdata = 0;
xl_xact_commit xlrec;
*************** RecordTransactionCommit(void)
*** 999,1004 ****
--- 1003,1009 ----
xlrec.nrels = nrels;
xlrec.nsubxacts = nchildren;
xlrec.nmsgs = nmsgs;
+ xlrec.ninitforks = ninitforks;
rdata[0].data = (char *) (&xlrec);
rdata[0].len = MinSizeOfXactCommit;
rdata[0].buffer = InvalidBuffer;
*************** RecordTransactionCommit(void)
*** 1029,1034 ****
--- 1034,1048 ----
rdata[3].buffer = InvalidBuffer;
lastrdata = 3;
}
+ /* dump init fork deletions */
+ if (ninitforks > 0)
+ {
+ rdata[lastrdata].next = &(rdata[4]);
+ rdata[4].data = (char *) initforks;
+ rdata[4].len = ninitforks * sizeof(RelFileNode);
+ rdata[4].buffer = InvalidBuffer;
+ lastrdata = 4;
+ }
rdata[lastrdata].next = NULL;
(void) XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, rdata);
*************** cleanup:
*** 1143,1148 ****
--- 1157,1164 ----
/* Clean up local data */
if (rels)
pfree(rels);
+ if (initforks)
+ pfree(initforks);
return latestXid;
}
*************** xact_redo_commit(xl_xact_commit *xlrec,
*** 4438,4443 ****
--- 4454,4460 ----
{
TransactionId *sub_xids;
SharedInvalidationMessage *inval_msgs;
+ RelFileNode *initforks;
TransactionId max_xid;
int i;
*************** xact_redo_commit(xl_xact_commit *xlrec,
*** 4445,4450 ****
--- 4462,4469 ----
sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
/* invalidation messages array follows subxids */
inval_msgs = (SharedInvalidationMessage *) &(sub_xids[xlrec->nsubxacts]);
+ /* init fork deletes array follows invalidation messages */
+ initforks = (RelFileNode *) &(inval_msgs[xlrec->nmsgs]);
max_xid = TransactionIdLatest(xid, xlrec->nsubxacts, sub_xids);
*************** xact_redo_commit(xl_xact_commit *xlrec,
*** 4534,4539 ****
--- 4553,4570 ----
smgrclose(srel);
}
+ /* Make sure init fork files supposed to be dropped are dropped */
+ for (i = 0; i < xlrec->ninitforks; i++)
+ {
+ SMgrRelation srel = smgropen(initforks[i], InvalidBackendId);
+ if (smgrexists(srel, INIT_FORKNUM))
+ {
+ XLogDropRelation(initforks[i], INIT_FORKNUM);
+ smgrdounlink(srel, INIT_FORKNUM, true);
+ }
+ smgrclose(srel);
+ }
+
/*
* We issue an XLogFlush() for the same reason we emit ForceSyncCommit()
* in normal operation. For example, in DROP DATABASE, we delete all the
*************** xact_desc_commit(StringInfo buf, xl_xact
*** 4749,4754 ****
--- 4780,4801 ----
appendStringInfo(buf, " unknown id %d", msg->id);
}
}
+ if (xlrec->ninitforks > 0)
+ {
+ RelFileNode *rl;
+
+ rl = (RelFileNode *) &xacts[xlrec->nmsgs];
+
+ appendStringInfo(buf, "; init fork rels:");
+ for (i = 0; i < xlrec->ninitforks; i++)
+ {
+ char *path = relpathperm(rl[i], INIT_FORKNUM);
+
+ appendStringInfo(buf, " %s", path);
+ pfree(path);
+ }
+ }
+
}
static void
diff --git a/src/backend/catalog/storage.c b/src/backend/catalog/storage.c
new file mode 100644
index 57987be..3363d7e
*** a/src/backend/catalog/storage.c
--- b/src/backend/catalog/storage.c
*************** typedef struct PendingRelDelete
*** 55,60 ****
--- 55,61 ----
BackendId backend; /* InvalidBackendId if not a temp rel */
bool atCommit; /* T=delete at commit; F=delete at abort */
int nestLevel; /* xact nesting level of request */
+ bool onlyInitFork; /* delete only INIT_FORKNUM */
struct PendingRelDelete *next; /* linked-list link */
} PendingRelDelete;
*************** RelationCreateStorage(RelFileNode rnode,
*** 135,140 ****
--- 136,142 ----
pending->backend = backend;
pending->atCommit = false; /* delete if abort */
pending->nestLevel = GetCurrentTransactionNestLevel();
+ pending->onlyInitFork = false;
pending->next = pendingDeletes;
pendingDeletes = pending;
}
*************** log_smgrcreate(RelFileNode *rnode, ForkN
*** 163,173 ****
}
/*
! * RelationDropStorage
* Schedule unlinking of physical storage at transaction commit.
*/
! void
! RelationDropStorage(Relation rel)
{
PendingRelDelete *pending;
--- 165,176 ----
}
/*
! * RelationDropStorageForks
* Schedule unlinking of physical storage at transaction commit.
+ * onlyInitFork: true if only the init fork as to be deleted
*/
! static void
! RelationDropStorageForks(Relation rel, bool onlyInitFork)
{
PendingRelDelete *pending;
*************** RelationDropStorage(Relation rel)
*** 178,183 ****
--- 181,187 ----
pending->backend = rel->rd_backend;
pending->atCommit = true; /* delete if commit */
pending->nestLevel = GetCurrentTransactionNestLevel();
+ pending->onlyInitFork = onlyInitFork;
pending->next = pendingDeletes;
pendingDeletes = pending;
*************** RelationDropStorage(Relation rel)
*** 195,200 ****
--- 199,225 ----
}
/*
+ * RelationDropStorage
+ * Schedule unlinking of physical storage at transaction commit.
+ */
+ void
+ RelationDropStorage(Relation rel)
+ {
+ RelationDropStorageForks(rel, false);
+ }
+
+ /*
+ * RelationDropInitForkStorage
+ * Schedule unlinking of physical storage of the init fork at transaction
+ * commit.
+ */
+ void
+ RelationDropInitForkStorage(Relation rel)
+ {
+ RelationDropStorageForks(rel, true);
+ }
+
+ /*
* RelationPreserveStorage
* Mark a relation as not to be deleted after all.
*
*************** smgrDoPendingDeletes(bool isCommit)
*** 358,367 ****
int i;
srel = smgropen(pending->relnode, pending->backend);
! for (i = 0; i <= MAX_FORKNUM; i++)
{
! if (smgrexists(srel, i))
! smgrdounlink(srel, i, false);
}
smgrclose(srel);
}
--- 383,400 ----
int i;
srel = smgropen(pending->relnode, pending->backend);
! if (pending->onlyInitFork)
{
! if (smgrexists(srel, INIT_FORKNUM))
! smgrdounlink(srel, INIT_FORKNUM, false);
! }
! else
! {
! for (i = 0; i <= MAX_FORKNUM; i++)
! {
! if (smgrexists(srel, i))
! smgrdounlink(srel, i, false);
! }
}
smgrclose(srel);
}
*************** smgrDoPendingDeletes(bool isCommit)
*** 373,378 ****
--- 406,449 ----
}
/*
+ * smgrGetPendingInitForkDeletes() -- Get a list of init forksto be deleted.
+ */
+ int
+ smgrGetPendingInitForkDeletes(bool forCommit, RelFileNode **ptr)
+ {
+ int nestLevel = GetCurrentTransactionNestLevel();
+ int nrels;
+ RelFileNode *rptr;
+ PendingRelDelete *pending;
+
+ nrels = 0;
+ for (pending = pendingDeletes; pending != NULL; pending = pending->next)
+ {
+ if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
+ && pending->backend == InvalidBackendId && pending->onlyInitFork)
+ nrels++;
+ }
+ if (nrels == 0)
+ {
+ *ptr = NULL;
+ return 0;
+ }
+ rptr = (RelFileNode *) palloc(nrels * sizeof(RelFileNode));
+ *ptr = rptr;
+ for (pending = pendingDeletes; pending != NULL; pending = pending->next)
+ {
+ if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
+ && pending->backend == InvalidBackendId && pending->onlyInitFork)
+ {
+ *rptr = pending->relnode;
+ rptr++;
+ }
+ }
+ return nrels;
+ }
+
+
+ /*
* smgrGetPendingDeletes() -- Get a list of non-temp relations to be deleted.
*
* The return value is the number of relations scheduled for termination.
*************** smgrGetPendingDeletes(bool forCommit, Re
*** 401,407 ****
for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{
if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
! && pending->backend == InvalidBackendId)
nrels++;
}
if (nrels == 0)
--- 472,478 ----
for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{
if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
! && pending->backend == InvalidBackendId && !pending->onlyInitFork)
nrels++;
}
if (nrels == 0)
*************** smgrGetPendingDeletes(bool forCommit, Re
*** 414,420 ****
for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{
if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
! && pending->backend == InvalidBackendId)
{
*rptr = pending->relnode;
rptr++;
--- 485,491 ----
for (pending = pendingDeletes; pending != NULL; pending = pending->next)
{
if (pending->nestLevel >= nestLevel && pending->atCommit == forCommit
! && pending->backend == InvalidBackendId && !pending->onlyInitFork)
{
*rptr = pending->relnode;
rptr++;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
new file mode 100644
index 790bc2a..bbdcc64
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** static void ATPrepAddInherit(Relation ch
*** 358,363 ****
--- 358,365 ----
static void ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
static void ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
static void ATExecGenericOptions(Relation rel, List *options);
+ static void ATPrepSetLogged(Relation rel);
+ static void ATExecSetLogged(Relation rel);
static void copy_relation_data(SMgrRelation rel, SMgrRelation dst,
ForkNumber forkNum, char relpersistence);
*************** AlterTableGetLockLevel(List *cmds)
*** 2614,2619 ****
--- 2616,2622 ----
case AT_DropNotNull: /* may change some SQL plans */
case AT_SetNotNull:
case AT_GenericOptions:
+ case AT_SetLogged: /* must drop shared buffers */
cmd_lockmode = AccessExclusiveLock;
break;
*************** ATPrepCmd(List **wqueue, Relation rel, A
*** 2958,2963 ****
--- 2961,2973 ----
/* No command-specific prep needed */
pass = AT_PASS_MISC;
break;
+ case AT_SetLogged: /* ALTER TABLE SET LOGGED */
+ ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
+ ATSimplePermissions(rel, ATT_TABLE);
+ /* Performs also own permission checks */
+ ATPrepSetLogged(rel);
+ pass = AT_PASS_MISC;
+ break;
default: /* oops */
elog(ERROR, "unrecognized alter table type: %d",
(int) cmd->subtype);
*************** ATExecCmd(List **wqueue, AlteredTableInf
*** 3221,3226 ****
--- 3231,3239 ----
case AT_GenericOptions:
ATExecGenericOptions(rel, (List *) cmd->def);
break;
+ case AT_SetLogged:
+ ATExecSetLogged(rel);
+ break;
default: /* oops */
elog(ERROR, "unrecognized alter table type: %d",
(int) cmd->subtype);
*************** ATPrepSetTableSpace(AlteredTableInfo *ta
*** 7603,7608 ****
--- 7616,7800 ----
}
/*
+ * 0) check we're in the wal_level=minimal case - this check will have to be
+ * removed later...
+ * 1) check the table is, in fact, unlogged
+ * 2) unlogged referencing permanent is OK, but permanent referencing unlogged
+ * is a no-no, so what matters when upgrading is "outbound" foreign keys
+ */
+ static void
+ ATPrepSetLogged(Relation rel)
+ {
+ Relation pg_constraint;
+ HeapTuple tuple;
+ SysScanDesc scan;
+ ScanKeyData skey[1];
+
+ if (wal_level != WAL_LEVEL_MINIMAL)
+ {
+ /* TODO change ERRCODE_INSUFFICIENT_PRIVILEGE to something else */
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("cannot change table to LOGGED in wal_level != minimal case")));
+
+ }
+
+ if (rel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ errmsg("table %s is not unlogged",
+ RelationGetRelationName(rel))));
+ }
+
+ /*
+ * Fetch the constraint tuple from pg_constraint.
+ */
+ pg_constraint = heap_open(ConstraintRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ Anum_pg_constraint_conrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(RelationGetRelid(rel)));
+
+ scan = systable_beginscan(pg_constraint, ConstraintRelidIndexId, true,
+ SnapshotNow, 1, skey);
+
+ while (HeapTupleIsValid(tuple = systable_getnext(scan)))
+ {
+ Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
+ if (con->contype == CONSTRAINT_FOREIGN)
+ {
+ Relation relfk = relation_open(con->confrelid, AccessShareLock);
+ if (relfk->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
+ {
+ /* TODO better error description */
+ /* TODO: exit at first error, or list all dependencies? */
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ errmsg("table %s references unlogged table %s",
+ RelationGetRelationName(rel),
+ RelationGetRelationName(relfk))));
+ }
+ relation_close(relfk, AccessShareLock);
+ }
+ }
+
+ systable_endscan(scan);
+
+ heap_close(pg_constraint, AccessShareLock);
+
+ }
+
+ /*
+ * 1) Write out all shared buffers for the target table/index, and drop them
+ * 2) fsync() any segments of the target relation - of any fork except
+ * that init fork
+ * 3) Arrange for the appropriate file deletions at commit or abort, by
+ * updating pendingDeletes
+ */
+ static void
+ ATUpdateToLogged(Relation rel, Relation pg_classRel)
+ {
+ HeapTuple reltup;
+ Form_pg_class relStruct;
+ bool fsm;
+ bool vm;
+
+ /* main heap */
+ FlushRelationBuffers(rel);
+
+ /* FlushRelationBuffers will have opened rd_smgr */
+ DropRelFileNodeBuffers(rel->rd_smgr->smgr_rnode, MAIN_FORKNUM, 0);
+ smgrimmedsync(rel->rd_smgr, MAIN_FORKNUM);
+
+ fsm = smgrexists(rel->rd_smgr, FSM_FORKNUM);
+ if (fsm)
+ smgrimmedsync(rel->rd_smgr, FSM_FORKNUM);
+
+ vm = smgrexists(rel->rd_smgr, VISIBILITYMAP_FORKNUM);
+ if (vm)
+ smgrimmedsync(rel->rd_smgr, VISIBILITYMAP_FORKNUM);
+
+ /* init fork delete */
+ RelationDropInitForkStorage(rel);
+
+ reltup = SearchSysCacheCopy1(RELOID,
+ ObjectIdGetDatum(RelationGetRelid(rel)));
+ if (!HeapTupleIsValid(reltup))
+ elog(ERROR, "cache lookup failed for relation %u",
+ RelationGetRelid(rel));
+ relStruct = (Form_pg_class) GETSTRUCT(reltup);
+
+ Assert(relStruct->relpersistence == RELPERSISTENCE_UNLOGGED);
+
+ relStruct->relpersistence = RELPERSISTENCE_PERMANENT;
+
+ simple_heap_update(pg_classRel, &reltup->t_self, reltup);
+
+ /* keep catalog indexes current */
+ CatalogUpdateIndexes(pg_classRel, reltup);
+
+ heap_freetuple(reltup);
+
+ }
+
+ /*
+ * update main heap, tost and index(es) of the target Relation to logged
+ */
+ static void
+ ATExecSetLogged(Relation rel)
+ {
+ Relation indexRelation;
+ ScanKeyData skey;
+ SysScanDesc scan;
+ HeapTuple indexTuple;
+ Relation relrel;
+
+ /* open pg_class to update relpersistence */
+ relrel = heap_open(RelationRelationId, RowExclusiveLock);
+
+ /* main heap */
+ ATUpdateToLogged(rel, relrel);
+
+ /* toast heap, if any */
+ if (OidIsValid(rel->rd_rel->reltoastrelid))
+ {
+ Relation toastrel;
+
+ toastrel = heap_open(rel->rd_rel->reltoastrelid, AccessShareLock);
+ ATUpdateToLogged(toastrel, relrel);
+ heap_close(toastrel, AccessShareLock);
+ }
+
+ /* indexes init fork delete */
+ /* Prepare to scan pg_index for entries having indrelid = this rel. */
+ indexRelation = heap_open(IndexRelationId, AccessShareLock);
+ ScanKeyInit(&skey,
+ Anum_pg_index_indrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(RelationGetRelid(rel)));
+
+ scan = systable_beginscan(indexRelation, IndexIndrelidIndexId, true,
+ SnapshotNow, 1, &skey);
+
+ while (HeapTupleIsValid(indexTuple = systable_getnext(scan)))
+ {
+ Form_pg_index index = (Form_pg_index) GETSTRUCT(indexTuple);
+ Relation indxrel = index_open(index->indexrelid, AccessShareLock);
+
+ ATUpdateToLogged(indxrel, relrel);
+
+ index_close(indxrel, AccessShareLock);
+ }
+
+ systable_endscan(scan);
+ heap_close(indexRelation, AccessShareLock);
+
+ heap_close(relrel, RowExclusiveLock);
+ }
+
+ /*
* ALTER TABLE/INDEX SET (...) or RESET (...)
*/
static void
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
new file mode 100644
index a22ab66..e1a50a4
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
*************** static void SplitColQualList(List *qualL
*** 520,526 ****
LABEL LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
! LOCATION LOCK_P
MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
--- 520,526 ----
LABEL LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
! LOCATION LOCK_P LOGGED
MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
*************** alter_table_cmd:
*** 1795,1800 ****
--- 1795,1807 ----
n->missing_ok = FALSE;
$$ = (Node *)n;
}
+ /* ALTER TABLE <name> SET LOGGED */
+ | SET LOGGED
+ {
+ AlterTableCmd *n = makeNode(AlterTableCmd);
+ n->subtype = AT_SetLogged;
+ $$ = (Node *)n;
+ }
/* ALTER TABLE <name> SET WITH OIDS */
| SET WITH OIDS
{
*************** unreserved_keyword:
*** 11935,11940 ****
--- 11942,11948 ----
| LOCAL
| LOCATION
| LOCK_P
+ | LOGGED
| MAPPING
| MATCH
| MAXVALUE
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
new file mode 100644
index cb440d4..ef56d17
*** a/src/include/access/xact.h
--- b/src/include/access/xact.h
*************** typedef struct xl_xact_commit
*** 123,134 ****
--- 123,136 ----
int nrels; /* number of RelFileNodes */
int nsubxacts; /* number of subtransaction XIDs */
int nmsgs; /* number of shared inval msgs */
+ int ninitforks; /* number of init fork RelFileNodes */
Oid dbId; /* MyDatabaseId */
Oid tsId; /* MyDatabaseTableSpace */
/* Array of RelFileNode(s) to drop at commit */
RelFileNode xnodes[1]; /* VARIABLE LENGTH ARRAY */
/* ARRAY OF COMMITTED SUBTRANSACTION XIDs FOLLOWS */
/* ARRAY OF SHARED INVALIDATION MESSAGES FOLLOWS */
+ /* ARRAY OF INIT FORK RelFileNodes FOLLOWS */
} xl_xact_commit;
#define MinSizeOfXactCommit offsetof(xl_xact_commit, xnodes)
diff --git a/src/include/catalog/storage.h b/src/include/catalog/storage.h
new file mode 100644
index 8dee8cf..04e1118
*** a/src/include/catalog/storage.h
--- b/src/include/catalog/storage.h
***************
*** 22,27 ****
--- 22,28 ----
extern void RelationCreateStorage(RelFileNode rnode, char relpersistence);
extern void RelationDropStorage(Relation rel);
+ extern void RelationDropInitForkStorage(Relation rel);
extern void RelationPreserveStorage(RelFileNode rnode);
extern void RelationTruncate(Relation rel, BlockNumber nblocks);
*************** extern void RelationTruncate(Relation re
*** 31,36 ****
--- 32,38 ----
*/
extern void smgrDoPendingDeletes(bool isCommit);
extern int smgrGetPendingDeletes(bool forCommit, RelFileNode **ptr);
+ extern int smgrGetPendingInitForkDeletes(bool forCommit, RelFileNode **ptr);
extern void AtSubCommit_smgr(void);
extern void AtSubAbort_smgr(void);
extern void PostPrepare_smgr(void);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
new file mode 100644
index 566cd3a..56f1384
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
*************** typedef enum AlterTableType
*** 1219,1224 ****
--- 1219,1225 ----
AT_AddInherit, /* INHERIT parent */
AT_DropInherit, /* NO INHERIT parent */
AT_GenericOptions, /* OPTIONS (...) */
+ AT_SetLogged, /* SET LOGGED */
} AlterTableType;
typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
new file mode 100644
index 12c2faf..45e17ea
*** a/src/include/parser/kwlist.h
--- b/src/include/parser/kwlist.h
*************** PG_KEYWORD("localtime", LOCALTIME, RESER
*** 227,232 ****
--- 227,233 ----
PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD)
PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD)
PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD)
+ PG_KEYWORD("logged", LOGGED, UNRESERVED_KEYWORD)
PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD)
PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD)
PG_KEYWORD("maxvalue", MAXVALUE, UNRESERVED_KEYWORD)