MarkBufferDirty(stack->buffer);
 
-           if (!btree->index->rd_istemp)
+           if (RelationNeedsWAL(btree->index))
            {
                XLogRecPtr  recptr;
 
                MarkBufferDirty(lbuffer);
                MarkBufferDirty(stack->buffer);
 
-               if (!btree->index->rd_istemp)
+               if (RelationNeedsWAL(btree->index))
                {
                    XLogRecPtr  recptr;
 
                MarkBufferDirty(rbuffer);
                MarkBufferDirty(stack->buffer);
 
-               if (!btree->index->rd_istemp)
+               if (RelationNeedsWAL(btree->index))
                {
                    XLogRecPtr  recptr;
 
 
 
    MarkBufferDirty(buffer);
 
-   if (!index->rd_istemp)
+   if (RelationNeedsWAL(index))
    {
        XLogRecData rdata[2];
        ginxlogInsertListPage data;
     */
    MarkBufferDirty(metabuffer);
 
-   if (!index->rd_istemp)
+   if (RelationNeedsWAL(index))
    {
        XLogRecPtr  recptr;
 
            MarkBufferDirty(buffers[i]);
        }
 
-       if (!index->rd_istemp)
+       if (RelationNeedsWAL(index))
        {
            XLogRecPtr  recptr;
 
 
 
    MarkBufferDirty(buffer);
 
-   if (!index->rd_istemp)
+   if (RelationNeedsWAL(index))
    {
        XLogRecPtr  recptr;
        XLogRecData rdata[2];
    GinInitBuffer(RootBuffer, GIN_LEAF);
    MarkBufferDirty(RootBuffer);
 
-   if (!index->rd_istemp)
+   if (RelationNeedsWAL(index))
    {
        XLogRecPtr  recptr;
        XLogRecData rdata;
 
 
    MarkBufferDirty(metabuffer);
 
-   if (!index->rd_istemp)
+   if (RelationNeedsWAL(index))
    {
        XLogRecPtr          recptr;
        ginxlogUpdateMeta   data;
 
 
    Assert(GinPageIsLeaf(page));
 
-   if (index->rd_istemp)
+   if (!RelationNeedsWAL(index))
        return;
 
    data.node = index->rd_node;
        MarkBufferDirty(lBuffer);
    MarkBufferDirty(dBuffer);
 
-   if (!gvs->index->rd_istemp)
+   if (RelationNeedsWAL(gvs->index))
    {
        XLogRecPtr  recptr;
        XLogRecData rdata[4];
 
 
    MarkBufferDirty(buffer);
 
-   if (!index->rd_istemp)
+   if (RelationNeedsWAL(index))
    {
        XLogRecPtr  recptr;
        XLogRecData rdata;
            dist->page = BufferGetPage(dist->buffer);
        }
 
-       if (!state->r->rd_istemp)
+       if (RelationNeedsWAL(state->r))
        {
            XLogRecPtr  recptr;
            XLogRecData *rdata;
 
        MarkBufferDirty(state->stack->buffer);
 
-       if (!state->r->rd_istemp)
+       if (RelationNeedsWAL(state->r))
        {
            OffsetNumber noffs = 0,
                        offs[1];
        opaque = GistPageGetOpaque(state->stack->page);
 
        state->stack->lsn = PageGetLSN(state->stack->page);
-       Assert(state->r->rd_istemp || !XLogRecPtrIsInvalid(state->stack->lsn));
+       Assert(!RelationNeedsWAL(state->r) || !XLogRecPtrIsInvalid(state->stack->lsn));
 
        if (state->stack->blkno != GIST_ROOT_BLKNO &&
            XLByteLT(state->stack->parent->lsn, opaque->nsn))
    }
 
    /* say to xlog that insert is completed */
-   if (state->needInsertComplete && !state->r->rd_istemp)
+   if (state->needInsertComplete && RelationNeedsWAL(state->r))
        gistxlogInsertCompletion(state->r->rd_node, &(state->key), 1);
 }
 
 
    MarkBufferDirty(buffer);
 
-   if (!r->rd_istemp)
+   if (RelationNeedsWAL(r))
    {
        XLogRecPtr  recptr;
        XLogRecData *rdata;
 
                    PageIndexTupleDelete(page, todelete[i]);
                GistMarkTuplesDeleted(page);
 
-               if (!rel->rd_istemp)
+               if (RelationNeedsWAL(rel))
                {
                    XLogRecData *rdata;
                    XLogRecPtr  recptr;
 
     *
     * During a rescan, don't make a new strategy object if we don't have to.
     */
-   if (!scan->rs_rd->rd_istemp &&
+   if (!RelationUsesLocalBuffers(scan->rs_rd) &&
        scan->rs_nblocks > NBuffers / 4)
    {
        allow_strat = scan->rs_allow_strat;
        elog(ERROR, "could not open relation with OID %u", relationId);
 
    /* Make note that we've accessed a temporary relation */
-   if (r->rd_istemp)
+   if (RelationUsesLocalBuffers(r))
        MyXactAccessedTempRel = true;
 
    pgstat_initstats(r);
        elog(ERROR, "could not open relation with OID %u", relationId);
 
    /* Make note that we've accessed a temporary relation */
-   if (r->rd_istemp)
+   if (RelationUsesLocalBuffers(r))
        MyXactAccessedTempRel = true;
 
    pgstat_initstats(r);
    MarkBufferDirty(buffer);
 
    /* XLOG stuff */
-   if (!(options & HEAP_INSERT_SKIP_WAL) && !relation->rd_istemp)
+   if (!(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation))
    {
        xl_heap_insert xlrec;
        xl_heap_header xlhdr;
    MarkBufferDirty(buffer);
 
    /* XLOG stuff */
-   if (!relation->rd_istemp)
+   if (RelationNeedsWAL(relation))
    {
        xl_heap_delete xlrec;
        XLogRecPtr  recptr;
    MarkBufferDirty(buffer);
 
    /* XLOG stuff */
-   if (!relation->rd_istemp)
+   if (RelationNeedsWAL(relation))
    {
        XLogRecPtr  recptr = log_heap_update(relation, buffer, oldtup.t_self,
                                             newbuf, heaptup,
     * (Also, in a PITR log-shipping or 2PC environment, we have to have XLOG
     * entries for everything anyway.)
     */
-   if (!relation->rd_istemp)
+   if (RelationNeedsWAL(relation))
    {
        xl_heap_lock xlrec;
        XLogRecPtr  recptr;
    MarkBufferDirty(buffer);
 
    /* XLOG stuff */
-   if (!relation->rd_istemp)
+   if (RelationNeedsWAL(relation))
    {
        xl_heap_inplace xlrec;
        XLogRecPtr  recptr;
    XLogRecPtr  recptr;
    XLogRecData rdata[4];
 
-   /* Caller should not call me on a temp relation */
-   Assert(!reln->rd_istemp);
+   /* Caller should not call me on a non-WAL-logged relation */
+   Assert(RelationNeedsWAL(reln));
 
    xlrec.node = reln->rd_node;
    xlrec.block = BufferGetBlockNumber(buffer);
    XLogRecPtr  recptr;
    XLogRecData rdata[2];
 
-   /* Caller should not call me on a temp relation */
-   Assert(!reln->rd_istemp);
+   /* Caller should not call me on a non-WAL-logged relation */
+   Assert(RelationNeedsWAL(reln));
    /* nor when there are no tuples to freeze */
    Assert(offcnt > 0);
 
    XLogRecData rdata[4];
    Page        page = BufferGetPage(newbuf);
 
-   /* Caller should not call me on a temp relation */
-   Assert(!reln->rd_istemp);
+   /* Caller should not call me on a non-WAL-logged relation */
+   Assert(RelationNeedsWAL(reln));
 
    if (HeapTupleIsHeapOnly(newtup))
        info = XLOG_HEAP_HOT_UPDATE;
  * heap_sync       - sync a heap, for use when no WAL has been written
  *
  * This forces the heap contents (including TOAST heap if any) down to disk.
- * If we skipped using WAL, and it's not a temp relation, we must force the
+ * If we skipped using WAL, and WAL is otherwise needed, we must force the
  * relation down to disk before it's safe to commit the transaction.  This
  * requires writing out any dirty buffers and then doing a forced fsync.
  *
 void
 heap_sync(Relation rel)
 {
-   /* temp tables never need fsync */
-   if (rel->rd_istemp)
+   /* non-WAL-logged tables never need fsync */
+   if (!RelationNeedsWAL(rel))
        return;
 
    /* main heap */
 
        /*
         * Emit a WAL HEAP_CLEAN record showing what we did
         */
-       if (!relation->rd_istemp)
+       if (RelationNeedsWAL(relation))
        {
            XLogRecPtr  recptr;
 
 
    }
 
    /*
-    * If the rel isn't temp, must fsync before commit.  We use heap_sync to
-    * ensure that the toast table gets fsync'd too.
+    * If the rel is WAL-logged, must fsync before commit.  We use heap_sync
+    * to ensure that the toast table gets fsync'd too.
     *
     * It's obvious that we must do this when not WAL-logging. It's less
     * obvious that we have to do it even if we did WAL-log the pages. The
     * occurring during the rewriteheap operation won't have fsync'd data we
     * wrote before the checkpoint.
     */
-   if (!state->rs_new_rel->rd_istemp)
+   if (RelationNeedsWAL(state->rs_new_rel))
        heap_sync(state->rs_new_rel);
 
    /* Deleting the context frees everything */
 
        }
 
        /* XLOG stuff */
-       if (!rel->rd_istemp)
+       if (RelationNeedsWAL(rel))
        {
            xl_btree_insert xlrec;
            BlockNumber xldownlink;
    }
 
    /* XLOG stuff */
-   if (!rel->rd_istemp)
+   if (RelationNeedsWAL(rel))
    {
        xl_btree_split xlrec;
        uint8       xlinfo;
    MarkBufferDirty(metabuf);
 
    /* XLOG stuff */
-   if (!rel->rd_istemp)
+   if (RelationNeedsWAL(rel))
    {
        xl_btree_newroot xlrec;
        XLogRecPtr  recptr;
 
        MarkBufferDirty(metabuf);
 
        /* XLOG stuff */
-       if (!rel->rd_istemp)
+       if (RelationNeedsWAL(rel))
        {
            xl_btree_newroot xlrec;
            XLogRecPtr  recptr;
 static void
 _bt_log_reuse_page(Relation rel, BlockNumber blkno, TransactionId latestRemovedXid)
 {
-   if (rel->rd_istemp)
+   if (!RelationNeedsWAL(rel))
        return;
 
    /* No ereport(ERROR) until changes are logged */
    MarkBufferDirty(buf);
 
    /* XLOG stuff */
-   if (!rel->rd_istemp)
+   if (RelationNeedsWAL(rel))
    {
        XLogRecPtr  recptr;
        XLogRecData rdata[2];
    MarkBufferDirty(buf);
 
    /* XLOG stuff */
-   if (!rel->rd_istemp)
+   if (RelationNeedsWAL(rel))
    {
        XLogRecPtr  recptr;
        XLogRecData rdata[3];
        MarkBufferDirty(lbuf);
 
    /* XLOG stuff */
-   if (!rel->rd_istemp)
+   if (RelationNeedsWAL(rel))
    {
        xl_btree_delete_page xlrec;
        xl_btree_metadata xlmeta;
 
 
    /*
     * We need to log index creation in WAL iff WAL archiving/streaming is
-    * enabled AND it's not a temp index.
+    * enabled UNLESS the index isn't WAL-logged anyway.
     */
-   wstate.btws_use_wal = XLogIsNeeded() && !wstate.index->rd_istemp;
+   wstate.btws_use_wal = XLogIsNeeded() && RelationNeedsWAL(wstate.index);
 
    /* reserve the metapage */
    wstate.btws_pages_alloced = BTREE_METAPAGE + 1;
    _bt_uppershutdown(wstate, state);
 
    /*
-    * If the index isn't temp, we must fsync it down to disk before it's safe
-    * to commit the transaction.  (For a temp index we don't care since the
-    * index will be uninteresting after a crash anyway.)
+    * If the index is WAL-logged, we must fsync it down to disk before it's
+    * safe to commit the transaction.  (For a non-WAL-logged index we don't
+    * care since the index will be uninteresting after a crash anyway.)
     *
     * It's obvious that we must do this when not WAL-logging the build. It's
     * less obvious that we have to do it even if we did WAL-log the index
     * fsync those pages here, they might still not be on disk when the crash
     * occurs.
     */
-   if (!wstate->index->rd_istemp)
+   if (RelationNeedsWAL(wstate->index))
    {
        RelationOpenSmgr(wstate->index);
        smgrimmedsync(wstate->index->rd_smgr, MAIN_FORKNUM);
 
                                                   $3,
                                                   tupdesc,
                                                   RELKIND_RELATION,
+                                                  RELPERSISTENCE_PERMANENT,
                                                   shared_relation,
                                                   mapped_relation,
                                                   true);
                                                      tupdesc,
                                                      NIL,
                                                      RELKIND_RELATION,
+                                                     RELPERSISTENCE_PERMANENT,
                                                      shared_relation,
                                                      mapped_relation,
                                                      true,
 
  * created by bootstrap have preassigned OIDs, so there's no need.
  */
 Oid
-GetNewRelFileNode(Oid reltablespace, Relation pg_class, BackendId backend)
+GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
 {
    RelFileNodeBackend rnode;
    char       *rpath;
    int         fd;
    bool        collides;
+   BackendId   backend;
+
+   switch (relpersistence)
+   {
+       case RELPERSISTENCE_TEMP:
+           backend = MyBackendId;
+           break;
+       case RELPERSISTENCE_PERMANENT:
+           backend = InvalidBackendId;
+           break;
+       default:
+           elog(ERROR, "invalid relpersistence: %c", relpersistence);
+           return InvalidOid;  /* placate compiler */
+   }
 
    /* This logic should match RelationInitPhysicalAddr */
    rnode.node.spcNode = reltablespace ? reltablespace : MyDatabaseTableSpace;
 
            Oid relid,
            TupleDesc tupDesc,
            char relkind,
+           char relpersistence,
            bool shared_relation,
            bool mapped_relation,
            bool allow_system_table_mods)
                                     relid,
                                     reltablespace,
                                     shared_relation,
-                                    mapped_relation);
+                                    mapped_relation,
+                                    relpersistence);
 
    /*
     * Have the storage manager create the relation's disk file, if needed.
    if (create_storage)
    {
        RelationOpenSmgr(rel);
-       RelationCreateStorage(rel->rd_node, rel->rd_istemp);
+       RelationCreateStorage(rel->rd_node, relpersistence);
    }
 
    return rel;
    values[Anum_pg_class_reltoastidxid - 1] = ObjectIdGetDatum(rd_rel->reltoastidxid);
    values[Anum_pg_class_relhasindex - 1] = BoolGetDatum(rd_rel->relhasindex);
    values[Anum_pg_class_relisshared - 1] = BoolGetDatum(rd_rel->relisshared);
-   values[Anum_pg_class_relistemp - 1] = BoolGetDatum(rd_rel->relistemp);
+   values[Anum_pg_class_relpersistence - 1] = CharGetDatum(rd_rel->relpersistence);
    values[Anum_pg_class_relkind - 1] = CharGetDatum(rd_rel->relkind);
    values[Anum_pg_class_relnatts - 1] = Int16GetDatum(rd_rel->relnatts);
    values[Anum_pg_class_relchecks - 1] = Int16GetDatum(rd_rel->relchecks);
                         TupleDesc tupdesc,
                         List *cooked_constraints,
                         char relkind,
+                        char relpersistence,
                         bool shared_relation,
                         bool mapped_relation,
                         bool oidislocal,
        }
        else
            relid = GetNewRelFileNode(reltablespace, pg_class_desc,
-                                     isTempOrToastNamespace(relnamespace) ?
-                                         MyBackendId : InvalidBackendId);
+                                     relpersistence);
    }
 
    /*
                               relid,
                               tupdesc,
                               relkind,
+                              relpersistence,
                               shared_relation,
                               mapped_relation,
                               allow_system_table_mods);
 
    bool        is_exclusion;
    Oid         namespaceId;
    int         i;
+   char        relpersistence;
 
    is_exclusion = (indexInfo->ii_ExclusionOps != NULL);
 
    /*
     * The index will be in the same namespace as its parent table, and is
     * shared across databases if and only if the parent is.  Likewise, it
-    * will use the relfilenode map if and only if the parent does.
+    * will use the relfilenode map if and only if the parent does; and it
+    * inherits the parent's relpersistence.
     */
    namespaceId = RelationGetNamespace(heapRelation);
    shared_relation = heapRelation->rd_rel->relisshared;
    mapped_relation = RelationIsMapped(heapRelation);
+   relpersistence = heapRelation->rd_rel->relpersistence;
 
    /*
     * check parameters
        else
        {
            indexRelationId =
-               GetNewRelFileNode(tableSpaceId, pg_class,
-                                 heapRelation->rd_istemp ?
-                                   MyBackendId : InvalidBackendId);
+               GetNewRelFileNode(tableSpaceId, pg_class, relpersistence);
        }
    }
 
                                indexRelationId,
                                indexTupDesc,
                                RELKIND_INDEX,
+                               relpersistence,
                                shared_relation,
                                mapped_relation,
                                allow_system_table_mods);
 
    }
 
    /*
-    * If istemp is set, this is a reference to a temp relation.  The parser
-    * never generates such a RangeVar in simple DML, but it can happen in
-    * contexts such as "CREATE TEMP TABLE foo (f1 int PRIMARY KEY)".  Such a
-    * command will generate an added CREATE INDEX operation, which must be
+    * Some non-default relpersistence value may have been specified.  The
+    * parser never generates such a RangeVar in simple DML, but it can happen
+    * in contexts such as "CREATE TEMP TABLE foo (f1 int PRIMARY KEY)".  Such
+    * a command will generate an added CREATE INDEX operation, which must be
     * careful to find the temp table, even when pg_temp is not first in the
     * search path.
     */
-   if (relation->istemp)
+   if (relation->relpersistence == RELPERSISTENCE_TEMP)
    {
        if (relation->schemaname)
            ereport(ERROR,
                            newRelation->relname)));
    }
 
-   if (newRelation->istemp)
+   if (newRelation->relpersistence == RELPERSISTENCE_TEMP)
    {
        /* TEMP tables are created in our backend-local temp namespace */
        if (newRelation->schemaname)
 
  * transaction aborts later on, the storage will be destroyed.
  */
 void
-RelationCreateStorage(RelFileNode rnode, bool istemp)
+RelationCreateStorage(RelFileNode rnode, char relpersistence)
 {
    PendingRelDelete *pending;
    XLogRecPtr  lsn;
    XLogRecData rdata;
    xl_smgr_create xlrec;
    SMgrRelation srel;
-   BackendId   backend = istemp ? MyBackendId : InvalidBackendId;
+   BackendId   backend;
+   bool        needs_wal;
+
+   switch (relpersistence)
+   {
+       case RELPERSISTENCE_TEMP:
+           backend = MyBackendId;
+           needs_wal = false;
+           break;
+       case RELPERSISTENCE_PERMANENT:
+           backend = InvalidBackendId;
+           needs_wal = true;
+           break;
+       default:
+           elog(ERROR, "invalid relpersistence: %c", relpersistence);
+           return;         /* placate compiler */
+   }
 
    srel = smgropen(rnode, backend);
    smgrcreate(srel, MAIN_FORKNUM, false);
 
-   if (!istemp)
+   if (needs_wal)
    {
        /*
         * Make an XLOG entry reporting the file creation.
     * failure to truncate, that might spell trouble at WAL replay, into a
     * certain PANIC.
     */
-   if (!rel->rd_istemp)
+   if (RelationNeedsWAL(rel))
    {
        /*
         * Make an XLOG entry reporting the file truncation.
 
     * Toast tables for regular relations go in pg_toast; those for temp
     * relations go into the per-backend temp-toast-table namespace.
     */
-   if (rel->rd_backend == MyBackendId)
+   if (RelationUsesTempNamespace(rel))
        namespaceid = GetTempToastNamespace();
    else
        namespaceid = PG_TOAST_NAMESPACE;
                                           tupdesc,
                                           NIL,
                                           RELKIND_TOASTVALUE,
+                                          rel->rd_rel->relpersistence,
                                           shared_relation,
                                           mapped_relation,
                                           true,
 
                                          tupdesc,
                                          NIL,
                                          OldHeap->rd_rel->relkind,
+                                         OldHeap->rd_rel->relpersistence,
                                          false,
                                          RelationIsMapped(OldHeap),
                                          true,
 
    /*
     * We need to log the copied data in WAL iff WAL archiving/streaming is
-    * enabled AND it's not a temp rel.
+    * enabled AND it's not a WAL-logged rel.
     */
-   use_wal = XLogIsNeeded() && !NewHeap->rd_istemp;
+   use_wal = XLogIsNeeded() && RelationNeedsWAL(NewHeap);
 
    /* use_wal off requires smgr_targblock be initially invalid */
    Assert(RelationGetTargetBlock(NewHeap) == InvalidBlockNumber);
 
    }
    else
    {
-       tablespaceId = GetDefaultTablespace(rel->rd_istemp);
+       tablespaceId = GetDefaultTablespace(rel->rd_rel->relpersistence);
        /* note InvalidOid is OK in this case */
    }
 
            continue;
 
        /* Skip temp tables of other backends; we can't reindex them at all */
-       if (classtuple->relistemp &&
+       if (classtuple->relpersistence == RELPERSISTENCE_TEMP &&
            !isTempNamespace(classtuple->relnamespace))
            continue;
 
 
    MarkBufferDirty(buf);
 
    /* XLOG stuff */
-   if (!rel->rd_istemp)
+   if (RelationNeedsWAL(rel))
    {
        xl_seq_rec  xlrec;
        XLogRecPtr  recptr;
    MarkBufferDirty(buf);
 
    /* XLOG stuff */
-   if (!seqrel->rd_istemp)
+   if (RelationNeedsWAL(seqrel))
    {
        xl_seq_rec  xlrec;
        XLogRecPtr  recptr;
    MarkBufferDirty(buf);
 
    /* XLOG stuff */
-   if (logit && !seqrel->rd_istemp)
+   if (logit && RelationNeedsWAL(seqrel))
    {
        xl_seq_rec  xlrec;
        XLogRecPtr  recptr;
    MarkBufferDirty(buf);
 
    /* XLOG stuff */
-   if (!seqrel->rd_istemp)
+   if (RelationNeedsWAL(seqrel))
    {
        xl_seq_rec  xlrec;
        XLogRecPtr  recptr;
 
 
 
 static void truncate_check_rel(Relation rel);
-static List *MergeAttributes(List *schema, List *supers, bool istemp,
+static List *MergeAttributes(List *schema, List *supers, char relpersistence,
                List **supOids, List **supconstr, int *supOidCount);
 static bool MergeCheckConstraint(List *constraints, char *name, Node *expr);
 static bool change_varattnos_walker(Node *node, const AttrNumber *newattno);
 static void ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode);
 static void ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode);
 static void copy_relation_data(SMgrRelation rel, SMgrRelation dst,
-                  ForkNumber forkNum, bool istemp);
+                  ForkNumber forkNum, char relpersistence);
 static const char *storage_name(char c);
 
 
    /*
     * Check consistency of arguments
     */
-   if (stmt->oncommit != ONCOMMIT_NOOP && !stmt->relation->istemp)
+   if (stmt->oncommit != ONCOMMIT_NOOP 
+       && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                 errmsg("ON COMMIT can only be used on temporary tables")));
     * code.  This is needed because calling code might not expect untrusted
     * tables to appear in pg_temp at the front of its search path.
     */
-   if (stmt->relation->istemp && InSecurityRestrictedOperation())
+   if (stmt->relation->relpersistence == RELPERSISTENCE_TEMP
+       && InSecurityRestrictedOperation())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("cannot create temporary table within security-restricted operation")));
    }
    else
    {
-       tablespaceId = GetDefaultTablespace(stmt->relation->istemp);
+       tablespaceId = GetDefaultTablespace(stmt->relation->relpersistence);
        /* note InvalidOid is OK in this case */
    }
 
     * inherited attributes.
     */
    schema = MergeAttributes(schema, stmt->inhRelations,
-                            stmt->relation->istemp,
+                            stmt->relation->relpersistence,
                             &inheritOids, &old_constraints, &parentOidCount);
 
    /*
                                          list_concat(cookedDefaults,
                                                      old_constraints),
                                          relkind,
+                                         stmt->relation->relpersistence,
                                          false,
                                          false,
                                          localHasOids,
  *----------
  */
 static List *
-MergeAttributes(List *schema, List *supers, bool istemp,
+MergeAttributes(List *schema, List *supers, char relpersistence,
                List **supOids, List **supconstr, int *supOidCount)
 {
    ListCell   *entry;
                     errmsg("inherited relation \"%s\" is not a table",
                            parent->relname)));
        /* Permanent rels cannot inherit from temporary ones */
-       if (!istemp && relation->rd_istemp)
+       if (relpersistence != RELPERSISTENCE_TEMP
+           && RelationUsesTempNamespace(relation))
            ereport(ERROR,
                    (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                     errmsg("cannot inherit from temporary relation \"%s\"",
                        RelationGetRelationName(pkrel))));
 
    /*
-    * Disallow reference from permanent table to temp table or vice versa.
-    * (The ban on perm->temp is for fairly obvious reasons.  The ban on
-    * temp->perm is because other backends might need to run the RI triggers
-    * on the perm table, but they can't reliably see tuples the owning
-    * backend has created in the temp table, because non-shared buffers are
-    * used for temp tables.)
+    * References from permanent tables to temp tables are disallowed because
+    * the contents of the temp table disappear at the end of each session.
+    * References from temp tables to permanent tables are also disallowed,
+    * because other backends might need to run the RI triggers on the perm
+    * table, but they can't reliably see tuples in the local buffers of other
+    * backends.
     */
-   if (pkrel->rd_istemp)
+   switch (rel->rd_rel->relpersistence)
    {
-       if (!rel->rd_istemp)
-           ereport(ERROR,
-                   (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-                    errmsg("cannot reference temporary table from permanent table constraint")));
-   }
-   else
-   {
-       if (rel->rd_istemp)
-           ereport(ERROR,
-                   (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
-                    errmsg("cannot reference permanent table from temporary table constraint")));
+       case RELPERSISTENCE_PERMANENT:
+           if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT)
+               ereport(ERROR,
+                       (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+                        errmsg("constraints on permanent tables may reference only permanent tables")));
+           break;
+       case RELPERSISTENCE_TEMP:
+           if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
+               ereport(ERROR,
+                       (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+                        errmsg("constraints on temporary tables may reference only temporary tables")));
+           break;
    }
 
    /*
     * Relfilenodes are not unique across tablespaces, so we need to allocate
     * a new one in the new tablespace.
     */
-   newrelfilenode = GetNewRelFileNode(newTableSpace, NULL, rel->rd_backend);
+   newrelfilenode = GetNewRelFileNode(newTableSpace, NULL,
+                                      rel->rd_rel->relpersistence);
 
    /* Open old and new relation */
    newrnode = rel->rd_node;
     * NOTE: any conflict in relfilenode value will be caught in
     * RelationCreateStorage().
     */
-   RelationCreateStorage(newrnode, rel->rd_istemp);
+   RelationCreateStorage(newrnode, rel->rd_rel->relpersistence);
 
    /* copy main fork */
-   copy_relation_data(rel->rd_smgr, dstrel, MAIN_FORKNUM, rel->rd_istemp);
+   copy_relation_data(rel->rd_smgr, dstrel, MAIN_FORKNUM,
+                      rel->rd_rel->relpersistence);
 
    /* copy those extra forks that exist */
    for (forkNum = MAIN_FORKNUM + 1; forkNum <= MAX_FORKNUM; forkNum++)
        if (smgrexists(rel->rd_smgr, forkNum))
        {
            smgrcreate(dstrel, forkNum, false);
-           copy_relation_data(rel->rd_smgr, dstrel, forkNum, rel->rd_istemp);
+           copy_relation_data(rel->rd_smgr, dstrel, forkNum,
+                              rel->rd_rel->relpersistence);
        }
    }
 
  */
 static void
 copy_relation_data(SMgrRelation src, SMgrRelation dst,
-                  ForkNumber forkNum, bool istemp)
+                  ForkNumber forkNum, char relpersistence)
 {
    char       *buf;
    Page        page;
 
    /*
     * We need to log the copied data in WAL iff WAL archiving/streaming is
-    * enabled AND it's not a temp rel.
+    * enabled AND it's a permanent relation.
     */
-   use_wal = XLogIsNeeded() && !istemp;
+   use_wal = XLogIsNeeded() && relpersistence == RELPERSISTENCE_PERMANENT;
 
    nblocks = smgrnblocks(src, forkNum);
 
     * wouldn't replay our earlier WAL entries. If we do not fsync those pages
     * here, they might still not be on disk when the crash occurs.
     */
-   if (!istemp)
+   if (relpersistence == RELPERSISTENCE_PERMANENT)
        smgrimmedsync(dst, forkNum);
 }
 
    ATSimplePermissions(parent_rel, false, false);
 
    /* Permanent rels cannot inherit from temporary ones */
-   if (parent_rel->rd_istemp && !child_rel->rd_istemp)
+   if (RelationUsesTempNamespace(parent_rel)
+       && !RelationUsesTempNamespace(child_rel))
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("cannot inherit from temporary relation \"%s\"",
 
 /*
  * GetDefaultTablespace -- get the OID of the current default tablespace
  *
- * Regular objects and temporary objects have different default tablespaces,
- * hence the forTemp parameter must be specified.
+ * Temporary objects have different default tablespaces, hence the
+ * relpersistence parameter must be specified.
  *
  * May return InvalidOid to indicate "use the database's default tablespace".
  *
  * default_tablespace GUC variable.
  */
 Oid
-GetDefaultTablespace(bool forTemp)
+GetDefaultTablespace(char relpersistence)
 {
    Oid         result;
 
    /* The temp-table case is handled elsewhere */
-   if (forTemp)
+   if (relpersistence == RELPERSISTENCE_TEMP)
    {
        PrepareTempTablespaces();
        return GetNextTempTableSpace();
 
 vacuum_log_cleanup_info(Relation rel, LVRelStats *vacrelstats)
 {
    /*
-    * No need to log changes for temp tables, they do not contain data
-    * visible on the standby server.
+    * Skip this for relations for which no WAL is to be written, or if we're
+    * not trying to support archive recovery.
     */
-   if (rel->rd_istemp || !XLogIsNeeded())
+   if (!RelationNeedsWAL(rel) || !XLogIsNeeded())
        return;
 
    /*
        if (nfrozen > 0)
        {
            MarkBufferDirty(buf);
-           /* no XLOG for temp tables, though */
-           if (!onerel->rd_istemp)
+           if (RelationNeedsWAL(onerel))
            {
                XLogRecPtr  recptr;
 
    MarkBufferDirty(buffer);
 
    /* XLOG stuff */
-   if (!onerel->rd_istemp)
+   if (RelationNeedsWAL(onerel))
    {
        XLogRecPtr  recptr;
 
 
            if (rte->rtekind == RTE_RELATION)
            {
                Relation    rel = heap_open(rte->relid, AccessShareLock);
-               bool        istemp = rel->rd_istemp;
+               char        relpersistence = rel->rd_rel->relpersistence;
 
                heap_close(rel, AccessShareLock);
-               if (istemp)
+               if (relpersistence == RELPERSISTENCE_TEMP)
                    return true;
            }
        }
        /*
         * Due to the namespace visibility rules for temporary objects, we
         * should only end up replacing a temporary view with another
-        * temporary view, and vice versa.
+        * temporary view, and similarly for permanent views.
         */
-       Assert(relation->istemp == rel->rd_istemp);
+       Assert(relation->relpersistence == rel->rd_rel->relpersistence);
 
        /*
         * Create a tuple descriptor to compare against the existing view, and
     * schema name.
     */
    view = stmt->view;
-   if (!view->istemp && isViewOnTempTable(viewParse))
+   if (view->relpersistence == RELPERSISTENCE_PERMANENT
+       && isViewOnTempTable(viewParse))
    {
        view = copyObject(view);    /* don't corrupt original command */
-       view->istemp = true;
+       view->relpersistence = RELPERSISTENCE_TEMP;
        ereport(NOTICE,
                (errmsg("view \"%s\" will be a temporary view",
                        view->relname)));
 
    /*
     * Check consistency of arguments
     */
-   if (into->onCommit != ONCOMMIT_NOOP && !into->rel->istemp)
+   if (into->onCommit != ONCOMMIT_NOOP
+       && into->rel->relpersistence != RELPERSISTENCE_TEMP)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                 errmsg("ON COMMIT can only be used on temporary tables")));
     * code.  This is needed because calling code might not expect untrusted
     * tables to appear in pg_temp at the front of its search path.
     */
-   if (into->rel->istemp && InSecurityRestrictedOperation())
+   if (into->rel->relpersistence == RELPERSISTENCE_TEMP
+       && InSecurityRestrictedOperation())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("cannot create temporary table within security-restricted operation")));
    }
    else
    {
-       tablespaceId = GetDefaultTablespace(into->rel->istemp);
+       tablespaceId = GetDefaultTablespace(into->rel->relpersistence);
        /* note InvalidOid is OK in this case */
    }
 
                                              tupdesc,
                                              NIL,
                                              RELKIND_RELATION,
+                                             into->rel->relpersistence,
                                              false,
                                              false,
                                              true,
 
    COPY_STRING_FIELD(schemaname);
    COPY_STRING_FIELD(relname);
    COPY_SCALAR_FIELD(inhOpt);
-   COPY_SCALAR_FIELD(istemp);
+   COPY_SCALAR_FIELD(relpersistence);
    COPY_NODE_FIELD(alias);
    COPY_LOCATION_FIELD(location);
 
 
    COMPARE_STRING_FIELD(schemaname);
    COMPARE_STRING_FIELD(relname);
    COMPARE_SCALAR_FIELD(inhOpt);
-   COMPARE_SCALAR_FIELD(istemp);
+   COMPARE_SCALAR_FIELD(relpersistence);
    COMPARE_NODE_FIELD(alias);
    COMPARE_LOCATION_FIELD(location);
 
 
  */
 #include "postgres.h"
 
+#include "catalog/pg_class.h"
 #include "catalog/pg_type.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
    r->schemaname = schemaname;
    r->relname = relname;
    r->inhOpt = INH_DEFAULT;
-   r->istemp = false;
+   r->relpersistence = RELPERSISTENCE_PERMANENT;
    r->alias = NULL;
    r->location = location;
 
 
    WRITE_STRING_FIELD(schemaname);
    WRITE_STRING_FIELD(relname);
    WRITE_ENUM_FIELD(inhOpt, InhOption);
-   WRITE_BOOL_FIELD(istemp);
+   WRITE_CHAR_FIELD(relpersistence);
    WRITE_NODE_FIELD(alias);
    WRITE_LOCATION_FIELD(location);
 }
 
    READ_STRING_FIELD(schemaname);
    READ_STRING_FIELD(relname);
    READ_ENUM_FIELD(inhOpt, InhOption);
-   READ_BOOL_FIELD(istemp);
+   READ_CHAR_FIELD(relpersistence);
    READ_NODE_FIELD(alias);
    READ_LOCATION_FIELD(location);
 
 
 %type <fun_param_mode> arg_class
 %type <typnam> func_return func_type
 
-%type <boolean>  OptTemp opt_trusted opt_restart_seqs
+%type <boolean>  opt_trusted opt_restart_seqs
+%type <ival>    OptTemp
 %type <oncommit> OnCommitOption
 
 %type <node>   for_locking_item
            OptInherit OptWith OnCommitOption OptTableSpace
                {
                    CreateStmt *n = makeNode(CreateStmt);
-                   $4->istemp = $2;
+                   $4->relpersistence = $2;
                    n->relation = $4;
                    n->tableElts = $6;
                    n->inhRelations = $8;
            OptTableSpace
                {
                    CreateStmt *n = makeNode(CreateStmt);
-                   $7->istemp = $2;
+                   $7->relpersistence = $2;
                    n->relation = $7;
                    n->tableElts = $9;
                    n->inhRelations = $11;
            OptTypedTableElementList OptWith OnCommitOption OptTableSpace
                {
                    CreateStmt *n = makeNode(CreateStmt);
-                   $4->istemp = $2;
+                   $4->relpersistence = $2;
                    n->relation = $4;
                    n->tableElts = $7;
                    n->ofTypename = makeTypeNameFromNameList($6);
            OptTypedTableElementList OptWith OnCommitOption OptTableSpace
                {
                    CreateStmt *n = makeNode(CreateStmt);
-                   $7->istemp = $2;
+                   $7->relpersistence = $2;
                    n->relation = $7;
                    n->tableElts = $10;
                    n->ofTypename = makeTypeNameFromNameList($9);
  * NOTE: we accept both GLOBAL and LOCAL options; since we have no modules
  * the LOCAL keyword is really meaningless.
  */
-OptTemp:   TEMPORARY                       { $$ = TRUE; }
-           | TEMP                          { $$ = TRUE; }
-           | LOCAL TEMPORARY               { $$ = TRUE; }
-           | LOCAL TEMP                    { $$ = TRUE; }
-           | GLOBAL TEMPORARY              { $$ = TRUE; }
-           | GLOBAL TEMP                   { $$ = TRUE; }
-           | /*EMPTY*/                     { $$ = FALSE; }
+OptTemp:   TEMPORARY                   { $$ = RELPERSISTENCE_TEMP; }
+           | TEMP                      { $$ = RELPERSISTENCE_TEMP; }
+           | LOCAL TEMPORARY           { $$ = RELPERSISTENCE_TEMP; }
+           | LOCAL TEMP                { $$ = RELPERSISTENCE_TEMP; }
+           | GLOBAL TEMPORARY          { $$ = RELPERSISTENCE_TEMP; }
+           | GLOBAL TEMP               { $$ = RELPERSISTENCE_TEMP; }
+           | /*EMPTY*/                 { $$ = RELPERSISTENCE_PERMANENT; }
        ;
 
 OptTableElementList:
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 errmsg("CREATE TABLE AS cannot specify INTO"),
                                 parser_errposition(exprLocation((Node *) n->intoClause))));
-                   $4->rel->istemp = $2;
+                   $4->rel->relpersistence = $2;
                    n->intoClause = $4;
                    /* Implement WITH NO DATA by forcing top-level LIMIT 0 */
                    if (!$7)
            CREATE OptTemp SEQUENCE qualified_name OptSeqOptList
                {
                    CreateSeqStmt *n = makeNode(CreateSeqStmt);
-                   $4->istemp = $2;
+                   $4->relpersistence = $2;
                    n->sequence = $4;
                    n->options = $5;
                    n->ownerId = InvalidOid;
                {
                    ViewStmt *n = makeNode(ViewStmt);
                    n->view = $4;
-                   n->view->istemp = $2;
+                   n->view->relpersistence = $2;
                    n->aliases = $5;
                    n->query = $7;
                    n->replace = false;
                {
                    ViewStmt *n = makeNode(ViewStmt);
                    n->view = $6;
-                   n->view->istemp = $4;
+                   n->view->relpersistence = $4;
                    n->aliases = $7;
                    n->query = $9;
                    n->replace = true;
                    ExecuteStmt *n = makeNode(ExecuteStmt);
                    n->name = $7;
                    n->params = $8;
-                   $4->rel->istemp = $2;
+                   $4->rel->relpersistence = $2;
                    n->into = $4;
                    if ($4->colNames)
                        ereport(ERROR,
            TEMPORARY opt_table qualified_name
                {
                    $$ = $3;
-                   $$->istemp = true;
+                   $$->relpersistence = RELPERSISTENCE_TEMP;
                }
            | TEMP opt_table qualified_name
                {
                    $$ = $3;
-                   $$->istemp = true;
+                   $$->relpersistence = RELPERSISTENCE_TEMP;
                }
            | LOCAL TEMPORARY opt_table qualified_name
                {
                    $$ = $4;
-                   $$->istemp = true;
+                   $$->relpersistence = RELPERSISTENCE_TEMP;
                }
            | LOCAL TEMP opt_table qualified_name
                {
                    $$ = $4;
-                   $$->istemp = true;
+                   $$->relpersistence = RELPERSISTENCE_TEMP;
                }
            | GLOBAL TEMPORARY opt_table qualified_name
                {
                    $$ = $4;
-                   $$->istemp = true;
+                   $$->relpersistence = RELPERSISTENCE_TEMP;
                }
            | GLOBAL TEMP opt_table qualified_name
                {
                    $$ = $4;
-                   $$->istemp = true;
+                   $$->relpersistence = RELPERSISTENCE_TEMP;
                }
            | TABLE qualified_name
                {
                    $$ = $2;
-                   $$->istemp = false;
+                   $$->relpersistence = RELPERSISTENCE_PERMANENT;
                }
            | qualified_name
                {
                    $$ = $1;
-                   $$->istemp = false;
+                   $$->relpersistence = RELPERSISTENCE_PERMANENT;
                }
        ;
 
 qualified_name:
            ColId
                {
-                   $$ = makeNode(RangeVar);
-                   $$->catalogname = NULL;
-                   $$->schemaname = NULL;
-                   $$->relname = $1;
-                   $$->location = @1;
+                   $$ = makeRangeVar(NULL, $1, @1);
                }
            | ColId indirection
                {
                    check_qualified_name($2, yyscanner);
-                   $$ = makeNode(RangeVar);
+                   $$ = makeRangeVar(NULL, NULL, @1);
                    switch (list_length($2))
                    {
                        case 1:
                                     parser_errposition(@1)));
                            break;
                    }
-                   $$->location = @1;
                }
        ;
 
            break;
    }
 
+   r->relpersistence = RELPERSISTENCE_PERMANENT;
    r->location = position;
 
    return r;
 
     * If the target relation name isn't schema-qualified, make it so.  This
     * prevents some corner cases in which added-on rewritten commands might
     * think they should apply to other relations that have the same name and
-    * are earlier in the search path.  "istemp" is equivalent to a
-    * specification of pg_temp, so no need for anything extra in that case.
+    * are earlier in the search path.  But a local temp table is effectively
+    * specified to be in pg_temp, so no need for anything extra in that case.
     */
-   if (stmt->relation->schemaname == NULL && !stmt->relation->istemp)
+   if (stmt->relation->schemaname == NULL
+       && stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
    {
        Oid         namespaceid = RangeVarGetCreationNamespace(stmt->relation);
 
 
         * Check if it is a temp table (presumably, of some other backend's).
         * We cannot safely process other backends' temp tables.
         */
-       if (classForm->relistemp)
+       if (classForm->relpersistence == RELPERSISTENCE_TEMP)
        {
            int         backendID;
 
        /*
         * We cannot safely process other backends' temp tables, so skip 'em.
         */
-       if (classForm->relistemp)
+       if (classForm->relpersistence == RELPERSISTENCE_TEMP)
            continue;
 
        relid = HeapTupleGetOid(tuple);
 
    /* Open it at the smgr level if not already done */
    RelationOpenSmgr(reln);
 
-   if (reln->rd_istemp)
+   if (RelationUsesLocalBuffers(reln))
    {
        /* see comments in ReadBufferExtended */
        if (RELATION_IS_OTHER_TEMP(reln))
    /* Open rel at the smgr level if not already done */
    RelationOpenSmgr(rel);
 
-   if (rel->rd_istemp)
+   if (RelationUsesLocalBuffers(rel))
    {
        for (i = 0; i < NLocBuffer; i++)
        {
 
        PG_RETURN_NULL();
    }
 
-   /* If temporary, determine owning backend. */
-   if (!relform->relistemp)
-       backend = InvalidBackendId;
-   else if (isTempOrToastNamespace(relform->relnamespace))
-       backend = MyBackendId;
-   else
+   /* Determine owning backend. */
+   switch (relform->relpersistence)
    {
-       /* Do it the hard way. */
-       backend = GetTempNamespaceBackendId(relform->relnamespace);
-       Assert(backend != InvalidBackendId);
+       case RELPERSISTENCE_PERMANENT:
+           backend = InvalidBackendId;
+           break;
+       case RELPERSISTENCE_TEMP:
+           if (isTempOrToastNamespace(relform->relnamespace))
+               backend = MyBackendId;
+           else
+           {
+               /* Do it the hard way. */
+               backend = GetTempNamespaceBackendId(relform->relnamespace);
+               Assert(backend != InvalidBackendId);
+           }
+           break;
+       default:
+           elog(ERROR, "invalid relpersistence: %c", relform->relpersistence);
+           backend = InvalidBackendId;     /* placate compiler */
+           break;
    }
 
    ReleaseSysCache(tuple);
 
    relation->rd_isnailed = false;
    relation->rd_createSubid = InvalidSubTransactionId;
    relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
-   relation->rd_istemp = relation->rd_rel->relistemp;
-   if (!relation->rd_istemp)
-       relation->rd_backend = InvalidBackendId;
-   else if (isTempOrToastNamespace(relation->rd_rel->relnamespace))
-       relation->rd_backend = MyBackendId;
-   else
+   switch (relation->rd_rel->relpersistence)
    {
-       /*
-        * If it's a temporary table, but not one of ours, we have to use
-        * the slow, grotty method to figure out the owning backend.
-        */
-       relation->rd_backend =
-           GetTempNamespaceBackendId(relation->rd_rel->relnamespace);
-       Assert(relation->rd_backend != InvalidBackendId);
+       case RELPERSISTENCE_PERMANENT:
+           relation->rd_backend = InvalidBackendId;
+           break;
+       case RELPERSISTENCE_TEMP:
+           if (isTempOrToastNamespace(relation->rd_rel->relnamespace))
+               relation->rd_backend = MyBackendId;
+           else
+           {
+               /*
+                * If it's a local temp table, but not one of ours, we have to
+                * use the slow, grotty method to figure out the owning
+                * backend.
+                */
+               relation->rd_backend =
+                   GetTempNamespaceBackendId(relation->rd_rel->relnamespace);
+               Assert(relation->rd_backend != InvalidBackendId);
+           }
+           break;
+       default:
+           elog(ERROR, "invalid relpersistence: %c",
+                relation->rd_rel->relpersistence);
+           break;
    }
 
    /*
    relation->rd_isnailed = true;
    relation->rd_createSubid = InvalidSubTransactionId;
    relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
-   relation->rd_istemp = false;
    relation->rd_backend = InvalidBackendId;
 
    /*
    if (isshared)
        relation->rd_rel->reltablespace = GLOBALTABLESPACE_OID;
 
-   /*
-    * Likewise, we must know if a relation is temp ... but formrdesc is not
-    * used for any temp relations.
-    */
-   relation->rd_rel->relistemp = false;
+   /* formrdesc is used only for permanent relations */
+   relation->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
 
    relation->rd_rel->relpages = 1;
    relation->rd_rel->reltuples = 1;
                           Oid relid,
                           Oid reltablespace,
                           bool shared_relation,
-                          bool mapped_relation)
+                          bool mapped_relation,
+                          char relpersistence)
 {
    Relation    rel;
    MemoryContext oldcxt;
    /* must flag that we have rels created in this transaction */
    need_eoxact_work = true;
 
-   /* it is temporary if and only if it is in my temp-table namespace */
-   rel->rd_istemp = isTempOrToastNamespace(relnamespace);
-   rel->rd_backend = rel->rd_istemp ? MyBackendId : InvalidBackendId;
-
    /*
     * create a new tuple descriptor from the one passed in.  We do this
     * partly to copy it into the cache context, and partly because the new
    /* needed when bootstrapping: */
    rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
 
+   /* set up persistence; rd_backend is a function of persistence type */
+   rel->rd_rel->relpersistence = relpersistence;
+   switch (relpersistence)
+   {
+       case RELPERSISTENCE_PERMANENT:
+           rel->rd_backend = InvalidBackendId;
+           break;
+       case RELPERSISTENCE_TEMP:
+           rel->rd_backend = MyBackendId;
+           break;
+       default:
+           elog(ERROR, "invalid relpersistence: %c", relpersistence);
+           break;
+   }
+
    /*
     * Insert relation physical and logical identifiers (OIDs) into the right
     * places.  Note that the physical ID (relfilenode) is initially the same
     * map.
     */
    rel->rd_rel->relisshared = shared_relation;
-   rel->rd_rel->relistemp = rel->rd_istemp;
 
    RelationGetRelid(rel) = relid;
 
 
    /* Allocate a new relfilenode */
    newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace, NULL,
-                                      relation->rd_backend);
+                                      relation->rd_rel->relpersistence);
 
    /*
     * Get a writable copy of the pg_class tuple for the given relation.
    newrnode.node = relation->rd_node;
    newrnode.node.relNode = newrelfilenode;
    newrnode.backend = relation->rd_backend;
-   RelationCreateStorage(newrnode.node, relation->rd_istemp);
+   RelationCreateStorage(newrnode.node, relation->rd_rel->relpersistence);
    smgrclosenode(newrnode);
 
    /*
 
 extern Oid GetNewOidWithIndex(Relation relation, Oid indexId,
                   AttrNumber oidcolumn);
 extern Oid GetNewRelFileNode(Oid reltablespace, Relation pg_class,
-                 BackendId backend);
+                 char relpersistence);
 
 #endif   /* CATALOG_H */
 
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201012031
+#define CATALOG_VERSION_NO 201012131
 
 #endif
 
            Oid relid,
            TupleDesc tupDesc,
            char relkind,
+           char relpersistence,
            bool shared_relation,
            bool mapped_relation,
            bool allow_system_table_mods);
                         TupleDesc tupdesc,
                         List *cooked_constraints,
                         char relkind,
+                        char relpersistence,
                         bool shared_relation,
                         bool mapped_relation,
                         bool oidislocal,
 
    Oid         reltoastidxid;  /* if toast table, OID of chunk_id index */
    bool        relhasindex;    /* T if has (or has had) any indexes */
    bool        relisshared;    /* T if shared across databases */
-   bool        relistemp;      /* T if temporary relation */
+   char        relpersistence; /* see RELPERSISTENCE_xxx constants */
    char        relkind;        /* see RELKIND_xxx constants below */
    int2        relnatts;       /* number of user attributes */
 
 #define Anum_pg_class_reltoastidxid        12
 #define Anum_pg_class_relhasindex      13
 #define Anum_pg_class_relisshared      14
-#define Anum_pg_class_relistemp            15
+#define Anum_pg_class_relpersistence   15
 #define Anum_pg_class_relkind          16
 #define Anum_pg_class_relnatts         17
 #define Anum_pg_class_relchecks            18
  */
 
 /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */
-DATA(insert OID = 1247 (  pg_type      PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f f r 28 0 t f f f f f 3 _null_ _null_ ));
+DATA(insert OID = 1247 (  pg_type      PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 28 0 t f f f f f 3 _null_ _null_ ));
 DESCR("");
-DATA(insert OID = 1249 (  pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f f r 19 0 f f f f f f 3 _null_ _null_ ));
+DATA(insert OID = 1249 (  pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 19 0 f f f f f f 3 _null_ _null_ ));
 DESCR("");
-DATA(insert OID = 1255 (  pg_proc      PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f f r 25 0 t f f f f f 3 _null_ _null_ ));
+DATA(insert OID = 1255 (  pg_proc      PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 25 0 t f f f f f 3 _null_ _null_ ));
 DESCR("");
-DATA(insert OID = 1259 (  pg_class     PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f f r 27 0 t f f f f f 3 _null_ _null_ ));
+DATA(insert OID = 1259 (  pg_class     PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f p r 27 0 t f f f f f 3 _null_ _null_ ));
 DESCR("");
 
 #define          RELKIND_INDEX           'i'       /* secondary index */
 #define          RELKIND_VIEW            'v'       /* view */
 #define          RELKIND_COMPOSITE_TYPE  'c'       /* composite type */
 
+#define          RELPERSISTENCE_PERMANENT  'p'
+#define          RELPERSISTENCE_TEMP       't'
+
 #endif   /* PG_CLASS_H */
 
 #include "storage/relfilenode.h"
 #include "utils/relcache.h"
 
-extern void RelationCreateStorage(RelFileNode rnode, bool istemp);
+extern void RelationCreateStorage(RelFileNode rnode, char relpersistence);
 extern void RelationDropStorage(Relation rel);
 extern void RelationPreserveStorage(RelFileNode rnode);
 extern void RelationTruncate(Relation rel, BlockNumber nblocks);
 
 
 extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo);
 
-extern Oid GetDefaultTablespace(bool forTemp);
+extern Oid GetDefaultTablespace(char relpersistence);
 
 extern void PrepareTempTablespaces(void);
 
 
    char       *relname;        /* the relation/sequence name */
    InhOption   inhOpt;         /* expand rel by inheritance? recursively act
                                 * on children? */
-   bool        istemp;         /* is this a temp relation/sequence? */
+   char        relpersistence; /* see RELPERSISTENCE_* in pg_class.h */
    Alias      *alias;          /* table alias & optional column aliases */
    int         location;       /* token location, or -1 if unknown */
 } RangeVar;
 
    struct SMgrRelationData *rd_smgr;   /* cached file handle, or NULL */
    int         rd_refcnt;      /* reference count */
    BackendId   rd_backend;     /* owning backend id, if temporary relation */
-   bool        rd_istemp;      /* rel is a temporary relation */
    bool        rd_isnailed;    /* rel is nailed in cache */
    bool        rd_isvalid;     /* relcache entry is valid */
    char        rd_indexvalid;  /* state of rd_indexlist: 0 = not valid, 1 =
        (relation)->rd_smgr->smgr_targblock = (targblock); \
    } while (0)
 
+/*
+ * RelationNeedsWAL
+ *     True if relation needs WAL.
+ */
+#define RelationNeedsWAL(relation) \
+   ((relation)->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT)
+
+/*
+ * RelationUsesLocalBuffers
+ *     True if relation's pages are stored in local buffers.
+ */
+#define RelationUsesLocalBuffers(relation) \
+   ((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
+
+/*
+ * RelationUsesTempNamespace
+ *     True if relation's catalog entries live in a private namespace.
+ */
+#define RelationUsesTempNamespace(relation) \
+   ((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
+
 /*
  * RELATION_IS_LOCAL
  *     If a rel is either temp or newly created in the current transaction,
  * Beware of multiple eval of argument
  */
 #define RELATION_IS_OTHER_TEMP(relation) \
-   ((relation)->rd_istemp && (relation)->rd_backend != MyBackendId)
+   ((relation)->rd_rel->relpersistence == RELPERSISTENCE_TEMP \
+   && (relation)->rd_backend != MyBackendId)
 
 /* routines in utils/cache/relcache.c */
 extern void RelationIncrementReferenceCount(Relation rel);
 
                           Oid relid,
                           Oid reltablespace,
                           bool shared_relation,
-                          bool mapped_relation);
+                          bool mapped_relation,
+                          char relpersistence);
 
 /*
  * Routine to manage assignment of new relfilenode to a relation