Commit 53dbc27c authored by Robert Haas's avatar Robert Haas

Support unlogged tables.

The contents of an unlogged table are WAL-logged; thus, they are not
available on standby servers and are truncated whenever the database
system enters recovery.  Indexes on unlogged tables are also unlogged.
Unlogged GiST indexes are not currently supported.
parent 9b8aff8c
...@@ -1644,7 +1644,8 @@ ...@@ -1644,7 +1644,8 @@
<entry><type>bool</type></entry> <entry><type>bool</type></entry>
<entry></entry> <entry></entry>
<entry> <entry>
<literal>p</> = permanent table, <literal>t</> = temporary table <literal>p</> = permanent table, <literal>u</> = unlogged table,
<literal>t</> = temporary table
</entry> </entry>
</row> </row>
......
...@@ -167,6 +167,17 @@ ambuild (Relation heapRelation, ...@@ -167,6 +167,17 @@ ambuild (Relation heapRelation,
<para> <para>
<programlisting> <programlisting>
void
ambuildempty (Relation indexRelation);
</programlisting>
Build an empty index, and write it to the initialization fork (INIT_FORKNUM)
of the given relation. This method is called only for unlogged tables; the
empty index written to the initialization fork will be copied over the main
relation fork on each server restart.
</para>
<para>
<programlisting>
bool bool
aminsert (Relation indexRelation, aminsert (Relation indexRelation,
Datum *values, Datum *values,
......
...@@ -21,7 +21,7 @@ PostgreSQL documentation ...@@ -21,7 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv> <refsynopsisdiv>
<synopsis> <synopsis>
CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE [ IF NOT EXISTS ] <replaceable class="PARAMETER">table_name</replaceable> ( [ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] <replaceable class="PARAMETER">table_name</replaceable> ( [
{ <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ <replaceable class="PARAMETER">column_constraint</replaceable> [ ... ] ] { <replaceable class="PARAMETER">column_name</replaceable> <replaceable class="PARAMETER">data_type</replaceable> [ <replaceable class="PARAMETER">column_constraint</replaceable> [ ... ] ]
| <replaceable>table_constraint</replaceable> | <replaceable>table_constraint</replaceable>
| LIKE <replaceable>parent_table</replaceable> [ <replaceable>like_option</replaceable> ... ] } | LIKE <replaceable>parent_table</replaceable> [ <replaceable>like_option</replaceable> ... ] }
...@@ -32,7 +32,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE [ IF NOT EXISTS ] <repl ...@@ -32,7 +32,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE [ IF NOT EXISTS ] <repl
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable> ] [ TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable> ]
CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE [ IF NOT EXISTS ] <replaceable class="PARAMETER">table_name</replaceable> CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXISTS ] <replaceable class="PARAMETER">table_name</replaceable>
OF <replaceable class="PARAMETER">type_name</replaceable> [ ( OF <replaceable class="PARAMETER">type_name</replaceable> [ (
{ <replaceable class="PARAMETER">column_name</replaceable> WITH OPTIONS [ <replaceable class="PARAMETER">column_constraint</replaceable> [ ... ] ] { <replaceable class="PARAMETER">column_name</replaceable> WITH OPTIONS [ <replaceable class="PARAMETER">column_constraint</replaceable> [ ... ] ]
| <replaceable>table_constraint</replaceable> } | <replaceable>table_constraint</replaceable> }
...@@ -164,6 +164,23 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE [ IF NOT EXISTS ] <repl ...@@ -164,6 +164,23 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE [ IF NOT EXISTS ] <repl
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>UNLOGGED</></term>
<listitem>
<para>
If specified, the table is created as an unlogged table. Data written
to unlogged tables is not written to the write-ahead log (see <xref
linkend="wal">), which makes them considerably faster than ordinary
tables. However, they are not crash-safe: an unlogged table is
automatically truncated after a crash or unclean shutdown. The contents
of an unlogged table are also not replicated to standby servers.
Any indexes created on an unlogged table are automatically unlogged as
well; however, unlogged <link linkend="GiST">GiST indexes</link> are
currently not supported and cannot be created on an unlogged table.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><literal>IF NOT EXISTS</></term> <term><literal>IF NOT EXISTS</></term>
<listitem> <listitem>
......
...@@ -21,7 +21,7 @@ PostgreSQL documentation ...@@ -21,7 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv> <refsynopsisdiv>
<synopsis> <synopsis>
CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable>table_name</replaceable> CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE <replaceable>table_name</replaceable>
[ (<replaceable>column_name</replaceable> [, ...] ) ] [ (<replaceable>column_name</replaceable> [, ...] ) ]
[ WITH ( <replaceable class="PARAMETER">storage_parameter</replaceable> [= <replaceable class="PARAMETER">value</replaceable>] [, ... ] ) | WITH OIDS | WITHOUT OIDS ] [ WITH ( <replaceable class="PARAMETER">storage_parameter</replaceable> [= <replaceable class="PARAMETER">value</replaceable>] [, ... ] ) | WITH OIDS | WITHOUT OIDS ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
...@@ -81,6 +81,16 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable>table_name ...@@ -81,6 +81,16 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable>table_name
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>UNLOGGED</></term>
<listitem>
<para>
If specified, the table is created as an unlogged table.
Refer to <xref linkend="sql-createtable"> for details.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><replaceable>table_name</replaceable></term> <term><replaceable>table_name</replaceable></term>
<listitem> <listitem>
......
...@@ -669,6 +669,17 @@ PostgreSQL documentation ...@@ -669,6 +669,17 @@ PostgreSQL documentation
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--no-unlogged-table-data</option></term>
<listitem>
<para>
Do not dump the contents of unlogged tables. This option has no
effect on whether or not the table definitions (schema) are dumped;
it only suppresses dumping the table data.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>--quote-all-identifiers</></term> <term><option>--quote-all-identifiers</></term>
<listitem> <listitem>
......
...@@ -201,6 +201,17 @@ PostgreSQL documentation ...@@ -201,6 +201,17 @@ PostgreSQL documentation
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--no-unlogged-table-data</option></term>
<listitem>
<para>
Do not dump the contents of unlogged tables. This option has no
effect on whether or not the table definitions (schema) are dumped;
it only suppresses dumping the table data.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>-r</option></term> <term><option>-r</option></term>
<term><option>--roles-only</option></term> <term><option>--roles-only</option></term>
......
...@@ -147,7 +147,9 @@ the relation. The free space map is stored in a file named with the filenode ...@@ -147,7 +147,9 @@ the relation. The free space map is stored in a file named with the filenode
number plus the suffix <literal>_fsm</>. Tables also have a number plus the suffix <literal>_fsm</>. Tables also have a
<firstterm>visibility map</>, stored in a fork with the suffix <literal>_vm</>, <firstterm>visibility map</>, stored in a fork with the suffix <literal>_vm</>,
to track which pages are known to have no dead tuples. The visibility map is to track which pages are known to have no dead tuples. The visibility map is
described further in <xref linkend="storage-vm">. described further in <xref linkend="storage-vm">. Unlogged tables and indexes
have a third fork, known as the initialization fork, which is stored in a fork
with the suffix <literal>_init</literal> (see <xref linkend="storage-init">).
</para> </para>
<caution> <caution>
...@@ -485,6 +487,24 @@ a bit is not set, it might or might not be true. ...@@ -485,6 +487,24 @@ a bit is not set, it might or might not be true.
</sect1> </sect1>
<sect1 id="storage-init">
<title>The Initialization Fork</title>
<indexterm>
<primary>Initialization Fork</primary>
</indexterm>
<para>
Each unlogged table, and each index on an unlogged table, has an initialization
fork. The initialization fork is an empty table or index of the appropriate
type. When an unlogged table must be reset to empty due to a crash, the
initialization fork is copied over the main fork, and any other forks are
erased (they will be recreated automatically as needed).
</para>
</sect1>
<sect1 id="storage-page-layout"> <sect1 id="storage-page-layout">
<title>Database Page Layout</title> <title>Database Page Layout</title>
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "catalog/index.h" #include "catalog/index.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/bufmgr.h" #include "storage/bufmgr.h"
#include "storage/smgr.h"
#include "storage/indexfsm.h" #include "storage/indexfsm.h"
#include "utils/memutils.h" #include "utils/memutils.h"
...@@ -411,6 +412,47 @@ ginbuild(PG_FUNCTION_ARGS) ...@@ -411,6 +412,47 @@ ginbuild(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(result); PG_RETURN_POINTER(result);
} }
/*
* ginbuildempty() -- build an empty gin index in the initialization fork
*/
Datum
ginbuildempty(PG_FUNCTION_ARGS)
{
Relation index = (Relation) PG_GETARG_POINTER(0);
Buffer RootBuffer,
MetaBuffer;
/* An empty GIN index has two pages. */
MetaBuffer =
ReadBufferExtended(index, INIT_FORKNUM, P_NEW, RBM_NORMAL, NULL);
LockBuffer(MetaBuffer, BUFFER_LOCK_EXCLUSIVE);
RootBuffer =
ReadBufferExtended(index, INIT_FORKNUM, P_NEW, RBM_NORMAL, NULL);
LockBuffer(RootBuffer, BUFFER_LOCK_EXCLUSIVE);
/* Initialize both pages, mark them dirty, unlock and release buffer. */
START_CRIT_SECTION();
GinInitMetabuffer(MetaBuffer);
MarkBufferDirty(MetaBuffer);
GinInitBuffer(RootBuffer, GIN_LEAF);
MarkBufferDirty(RootBuffer);
/* XLOG the new pages */
log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
BufferGetBlockNumber(MetaBuffer),
BufferGetPage(MetaBuffer));
log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
BufferGetBlockNumber(RootBuffer),
BufferGetPage(RootBuffer));
END_CRIT_SECTION();
/* Unlock and release the buffers. */
UnlockReleaseBuffer(MetaBuffer);
UnlockReleaseBuffer(RootBuffer);
PG_RETURN_VOID();
}
/* /*
* Inserts value during normal insertion * Inserts value during normal insertion
*/ */
......
...@@ -218,6 +218,19 @@ gistbuildCallback(Relation index, ...@@ -218,6 +218,19 @@ gistbuildCallback(Relation index,
MemoryContextReset(buildstate->tmpCtx); MemoryContextReset(buildstate->tmpCtx);
} }
/*
* gistbuildempty() -- build an empty gist index in the initialization fork
*/
Datum
gistbuildempty(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unlogged GIST indexes are not supported")));
PG_RETURN_VOID();
}
/* /*
* gistinsert -- wrapper for GiST tuple insertion. * gistinsert -- wrapper for GiST tuple insertion.
* *
......
...@@ -69,7 +69,7 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -69,7 +69,7 @@ hashbuild(PG_FUNCTION_ARGS)
estimate_rel_size(heap, NULL, &relpages, &reltuples); estimate_rel_size(heap, NULL, &relpages, &reltuples);
/* Initialize the hash index metadata page and initial buckets */ /* Initialize the hash index metadata page and initial buckets */
num_buckets = _hash_metapinit(index, reltuples); num_buckets = _hash_metapinit(index, reltuples, MAIN_FORKNUM);
/* /*
* If we just insert the tuples into the index in scan order, then * If we just insert the tuples into the index in scan order, then
...@@ -113,6 +113,19 @@ hashbuild(PG_FUNCTION_ARGS) ...@@ -113,6 +113,19 @@ hashbuild(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(result); PG_RETURN_POINTER(result);
} }
/*
* hashbuildempty() -- build an empty hash index in the initialization fork
*/
Datum
hashbuildempty(PG_FUNCTION_ARGS)
{
Relation index = (Relation) PG_GETARG_POINTER(0);
_hash_metapinit(index, 0, INIT_FORKNUM);
PG_RETURN_VOID();
}
/* /*
* Per-tuple callback from IndexBuildHeapScan * Per-tuple callback from IndexBuildHeapScan
*/ */
......
...@@ -259,7 +259,7 @@ _hash_getovflpage(Relation rel, Buffer metabuf) ...@@ -259,7 +259,7 @@ _hash_getovflpage(Relation rel, Buffer metabuf)
* convenient to pre-mark them as "in use" too. * convenient to pre-mark them as "in use" too.
*/ */
bit = metap->hashm_spares[splitnum]; bit = metap->hashm_spares[splitnum];
_hash_initbitmap(rel, metap, bitno_to_blkno(metap, bit)); _hash_initbitmap(rel, metap, bitno_to_blkno(metap, bit), MAIN_FORKNUM);
metap->hashm_spares[splitnum]++; metap->hashm_spares[splitnum]++;
} }
else else
...@@ -280,7 +280,7 @@ _hash_getovflpage(Relation rel, Buffer metabuf) ...@@ -280,7 +280,7 @@ _hash_getovflpage(Relation rel, Buffer metabuf)
* with metapage write lock held; would be better to use a lock that * with metapage write lock held; would be better to use a lock that
* doesn't block incoming searches. * doesn't block incoming searches.
*/ */
newbuf = _hash_getnewbuf(rel, blkno); newbuf = _hash_getnewbuf(rel, blkno, MAIN_FORKNUM);
metap->hashm_spares[splitnum]++; metap->hashm_spares[splitnum]++;
...@@ -503,7 +503,8 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf, ...@@ -503,7 +503,8 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf,
* All bits in the new bitmap page are set to "1", indicating "in use". * All bits in the new bitmap page are set to "1", indicating "in use".
*/ */
void void
_hash_initbitmap(Relation rel, HashMetaPage metap, BlockNumber blkno) _hash_initbitmap(Relation rel, HashMetaPage metap, BlockNumber blkno,
ForkNumber forkNum)
{ {
Buffer buf; Buffer buf;
Page pg; Page pg;
...@@ -520,7 +521,7 @@ _hash_initbitmap(Relation rel, HashMetaPage metap, BlockNumber blkno) ...@@ -520,7 +521,7 @@ _hash_initbitmap(Relation rel, HashMetaPage metap, BlockNumber blkno)
* page while holding the metapage lock, but this path is taken so seldom * page while holding the metapage lock, but this path is taken so seldom
* that it's not worth worrying about. * that it's not worth worrying about.
*/ */
buf = _hash_getnewbuf(rel, blkno); buf = _hash_getnewbuf(rel, blkno, forkNum);
pg = BufferGetPage(buf); pg = BufferGetPage(buf);
/* initialize the page's special space */ /* initialize the page's special space */
......
...@@ -183,9 +183,9 @@ _hash_getinitbuf(Relation rel, BlockNumber blkno) ...@@ -183,9 +183,9 @@ _hash_getinitbuf(Relation rel, BlockNumber blkno)
* extend the index at a time. * extend the index at a time.
*/ */
Buffer Buffer
_hash_getnewbuf(Relation rel, BlockNumber blkno) _hash_getnewbuf(Relation rel, BlockNumber blkno, ForkNumber forkNum)
{ {
BlockNumber nblocks = RelationGetNumberOfBlocks(rel); BlockNumber nblocks = RelationGetNumberOfBlocksInFork(rel, forkNum);
Buffer buf; Buffer buf;
if (blkno == P_NEW) if (blkno == P_NEW)
...@@ -197,13 +197,13 @@ _hash_getnewbuf(Relation rel, BlockNumber blkno) ...@@ -197,13 +197,13 @@ _hash_getnewbuf(Relation rel, BlockNumber blkno)
/* smgr insists we use P_NEW to extend the relation */ /* smgr insists we use P_NEW to extend the relation */
if (blkno == nblocks) if (blkno == nblocks)
{ {
buf = ReadBuffer(rel, P_NEW); buf = ReadBufferExtended(rel, forkNum, P_NEW, RBM_NORMAL, NULL);
if (BufferGetBlockNumber(buf) != blkno) if (BufferGetBlockNumber(buf) != blkno)
elog(ERROR, "unexpected hash relation size: %u, should be %u", elog(ERROR, "unexpected hash relation size: %u, should be %u",
BufferGetBlockNumber(buf), blkno); BufferGetBlockNumber(buf), blkno);
} }
else else
buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO, NULL); buf = ReadBufferExtended(rel, forkNum, blkno, RBM_ZERO, NULL);
LockBuffer(buf, HASH_WRITE); LockBuffer(buf, HASH_WRITE);
...@@ -324,7 +324,7 @@ _hash_chgbufaccess(Relation rel, ...@@ -324,7 +324,7 @@ _hash_chgbufaccess(Relation rel,
* multiple buffer locks is ignored. * multiple buffer locks is ignored.
*/ */
uint32 uint32
_hash_metapinit(Relation rel, double num_tuples) _hash_metapinit(Relation rel, double num_tuples, ForkNumber forkNum)
{ {
HashMetaPage metap; HashMetaPage metap;
HashPageOpaque pageopaque; HashPageOpaque pageopaque;
...@@ -340,7 +340,7 @@ _hash_metapinit(Relation rel, double num_tuples) ...@@ -340,7 +340,7 @@ _hash_metapinit(Relation rel, double num_tuples)
uint32 i; uint32 i;
/* safety check */ /* safety check */
if (RelationGetNumberOfBlocks(rel) != 0) if (RelationGetNumberOfBlocksInFork(rel, forkNum) != 0)
elog(ERROR, "cannot initialize non-empty hash index \"%s\"", elog(ERROR, "cannot initialize non-empty hash index \"%s\"",
RelationGetRelationName(rel)); RelationGetRelationName(rel));
...@@ -383,7 +383,7 @@ _hash_metapinit(Relation rel, double num_tuples) ...@@ -383,7 +383,7 @@ _hash_metapinit(Relation rel, double num_tuples)
* calls to occur. This ensures that the smgr level has the right idea of * calls to occur. This ensures that the smgr level has the right idea of
* the physical index length. * the physical index length.
*/ */
metabuf = _hash_getnewbuf(rel, HASH_METAPAGE); metabuf = _hash_getnewbuf(rel, HASH_METAPAGE, forkNum);
pg = BufferGetPage(metabuf); pg = BufferGetPage(metabuf);
pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg); pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg);
...@@ -451,7 +451,7 @@ _hash_metapinit(Relation rel, double num_tuples) ...@@ -451,7 +451,7 @@ _hash_metapinit(Relation rel, double num_tuples)
/* Allow interrupts, in case N is huge */ /* Allow interrupts, in case N is huge */
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
buf = _hash_getnewbuf(rel, BUCKET_TO_BLKNO(metap, i)); buf = _hash_getnewbuf(rel, BUCKET_TO_BLKNO(metap, i), forkNum);
pg = BufferGetPage(buf); pg = BufferGetPage(buf);
pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg); pageopaque = (HashPageOpaque) PageGetSpecialPointer(pg);
pageopaque->hasho_prevblkno = InvalidBlockNumber; pageopaque->hasho_prevblkno = InvalidBlockNumber;
...@@ -468,7 +468,7 @@ _hash_metapinit(Relation rel, double num_tuples) ...@@ -468,7 +468,7 @@ _hash_metapinit(Relation rel, double num_tuples)
/* /*
* Initialize first bitmap page * Initialize first bitmap page
*/ */
_hash_initbitmap(rel, metap, num_buckets + 1); _hash_initbitmap(rel, metap, num_buckets + 1, forkNum);
/* all done */ /* all done */
_hash_wrtbuf(rel, metabuf); _hash_wrtbuf(rel, metabuf);
...@@ -785,7 +785,7 @@ _hash_splitbucket(Relation rel, ...@@ -785,7 +785,7 @@ _hash_splitbucket(Relation rel,
oopaque = (HashPageOpaque) PageGetSpecialPointer(opage); oopaque = (HashPageOpaque) PageGetSpecialPointer(opage);
nblkno = start_nblkno; nblkno = start_nblkno;
nbuf = _hash_getnewbuf(rel, nblkno); nbuf = _hash_getnewbuf(rel, nblkno, MAIN_FORKNUM);
npage = BufferGetPage(nbuf); npage = BufferGetPage(nbuf);
/* initialize the new bucket's primary page */ /* initialize the new bucket's primary page */
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "storage/indexfsm.h" #include "storage/indexfsm.h"
#include "storage/ipc.h" #include "storage/ipc.h"
#include "storage/lmgr.h" #include "storage/lmgr.h"
#include "storage/smgr.h"
#include "utils/memutils.h" #include "utils/memutils.h"
...@@ -204,6 +205,36 @@ btbuildCallback(Relation index, ...@@ -204,6 +205,36 @@ btbuildCallback(Relation index,
pfree(itup); pfree(itup);
} }
/*
* btbuildempty() -- build an empty btree index in the initialization fork
*/
Datum
btbuildempty(PG_FUNCTION_ARGS)
{
Relation index = (Relation) PG_GETARG_POINTER(0);
Page metapage;
/* Construct metapage. */
metapage = (Page) palloc(BLCKSZ);
_bt_initmetapage(metapage, P_NONE, 0);
/* Write the page. If archiving/streaming, XLOG it. */
smgrwrite(index->rd_smgr, INIT_FORKNUM, BTREE_METAPAGE,
(char *) metapage, true);
if (XLogIsNeeded())
log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
BTREE_METAPAGE, metapage);
/*
* An immediate sync is require even if we xlog'd the page, because the
* write did not go through shared_buffers and therefore a concurrent
* checkpoint may have move the redo pointer past our xlog record.
*/
smgrimmedsync(index->rd_smgr, INIT_FORKNUM);
PG_RETURN_VOID();
}
/* /*
* btinsert() -- insert an index tuple into a btree. * btinsert() -- insert an index tuple into a btree.
* *
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "storage/latch.h" #include "storage/latch.h"
#include "storage/pmsignal.h" #include "storage/pmsignal.h"
#include "storage/procarray.h" #include "storage/procarray.h"
#include "storage/reinit.h"
#include "storage/smgr.h" #include "storage/smgr.h"
#include "storage/spin.h" #include "storage/spin.h"
#include "utils/builtins.h" #include "utils/builtins.h"
...@@ -5960,6 +5961,14 @@ StartupXLOG(void) ...@@ -5960,6 +5961,14 @@ StartupXLOG(void)
/* Check that the GUCs used to generate the WAL allow recovery */ /* Check that the GUCs used to generate the WAL allow recovery */
CheckRequiredParameterValues(); CheckRequiredParameterValues();
/*
* We're in recovery, so unlogged relations relations may be trashed
* and must be reset. This should be done BEFORE allowing Hot
* Standby connections, so that read-only backends don't try to
* read whatever garbage is left over from before.
*/
ResetUnloggedRelations(UNLOGGED_RELATION_CLEANUP);
/* /*
* Initialize for Hot Standby, if enabled. We won't let backends in * Initialize for Hot Standby, if enabled. We won't let backends in
* yet, not until we've reached the min recovery point specified in * yet, not until we've reached the min recovery point specified in
...@@ -6413,6 +6422,14 @@ StartupXLOG(void) ...@@ -6413,6 +6422,14 @@ StartupXLOG(void)
*/ */
PreallocXlogFiles(EndOfLog); PreallocXlogFiles(EndOfLog);
/*
* Reset initial contents of unlogged relations. This has to be done
* AFTER recovery is complete so that any unlogged relations created
* during recovery also get picked up.
*/
if (InRecovery)
ResetUnloggedRelations(UNLOGGED_RELATION_INIT);
/* /*
* Okay, we're officially UP. * Okay, we're officially UP.
*/ */
......
...@@ -55,7 +55,8 @@ ...@@ -55,7 +55,8 @@
const char *forkNames[] = { const char *forkNames[] = {
"main", /* MAIN_FORKNUM */ "main", /* MAIN_FORKNUM */
"fsm", /* FSM_FORKNUM */ "fsm", /* FSM_FORKNUM */
"vm" /* VISIBILITYMAP_FORKNUM */ "vm", /* VISIBILITYMAP_FORKNUM */
"init" /* INIT_FORKNUM */
}; };
/* /*
...@@ -82,14 +83,14 @@ forkname_to_number(char *forkName) ...@@ -82,14 +83,14 @@ forkname_to_number(char *forkName)
* We use this to figure out whether a filename could be a relation * We use this to figure out whether a filename could be a relation
* fork (as opposed to an oddly named stray file that somehow ended * fork (as opposed to an oddly named stray file that somehow ended
* up in the database directory). If the passed string begins with * up in the database directory). If the passed string begins with
* a fork name (other than the main fork name), we return its length. * a fork name (other than the main fork name), we return its length,
* If not, we return 0. * and set *fork (if not NULL) to the fork number. If not, we return 0.
* *
* Note that the present coding assumes that there are no fork names which * Note that the present coding assumes that there are no fork names which
* are prefixes of other fork names. * are prefixes of other fork names.
*/ */
int int
forkname_chars(const char *str) forkname_chars(const char *str, ForkNumber *fork)
{ {
ForkNumber forkNum; ForkNumber forkNum;
...@@ -97,7 +98,11 @@ forkname_chars(const char *str) ...@@ -97,7 +98,11 @@ forkname_chars(const char *str)
{ {
int len = strlen(forkNames[forkNum]); int len = strlen(forkNames[forkNum]);
if (strncmp(forkNames[forkNum], str, len) == 0) if (strncmp(forkNames[forkNum], str, len) == 0)
{
if (fork)
*fork = forkNum;
return len; return len;
}
} }
return 0; return 0;
} }
...@@ -537,6 +542,7 @@ GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence) ...@@ -537,6 +542,7 @@ GetNewRelFileNode(Oid reltablespace, Relation pg_class, char relpersistence)
case RELPERSISTENCE_TEMP: case RELPERSISTENCE_TEMP:
backend = MyBackendId; backend = MyBackendId;
break; break;
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT: case RELPERSISTENCE_PERMANENT:
backend = InvalidBackendId; backend = InvalidBackendId;
break; break;
......
...@@ -1210,6 +1210,25 @@ heap_create_with_catalog(const char *relname, ...@@ -1210,6 +1210,25 @@ heap_create_with_catalog(const char *relname,
if (oncommit != ONCOMMIT_NOOP) if (oncommit != ONCOMMIT_NOOP)
register_on_commit_action(relid, oncommit); register_on_commit_action(relid, oncommit);
/*
* If this is an unlogged relation, it needs an init fork so that it
* can be correctly reinitialized on restart. Since we're going to
* do an immediate sync, we ony need to xlog this if archiving or
* streaming is enabled. And the immediate sync is required, because
* otherwise there's no guarantee that this will hit the disk before
* the next checkpoint moves the redo pointer.
*/
if (relpersistence == RELPERSISTENCE_UNLOGGED)
{
Assert(relkind == RELKIND_RELATION || relkind == RELKIND_TOASTVALUE);
smgrcreate(new_rel_desc->rd_smgr, INIT_FORKNUM, false);
if (XLogIsNeeded())
log_smgrcreate(&new_rel_desc->rd_smgr->smgr_rnode.node,
INIT_FORKNUM);
smgrimmedsync(new_rel_desc->rd_smgr, INIT_FORKNUM);
}
/* /*
* ok, the relation has been cataloged, so close our relations and return * ok, the relation has been cataloged, so close our relations and return
* the OID of the newly created relation. * the OID of the newly created relation.
......
...@@ -1437,6 +1437,17 @@ index_build(Relation heapRelation, ...@@ -1437,6 +1437,17 @@ index_build(Relation heapRelation,
PointerGetDatum(indexInfo))); PointerGetDatum(indexInfo)));
Assert(PointerIsValid(stats)); Assert(PointerIsValid(stats));
/*
* If this is an unlogged index, we need to write out an init fork for it.
*/
if (heapRelation->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED)
{
RegProcedure ambuildempty = indexRelation->rd_am->ambuildempty;
RelationOpenSmgr(indexRelation);
smgrcreate(indexRelation->rd_smgr, INIT_FORKNUM, false);
OidFunctionCall1(ambuildempty, PointerGetDatum(indexRelation));
}
/* /*
* If it's for an exclusion constraint, make a second pass over the heap * If it's for an exclusion constraint, make a second pass over the heap
* to verify that the constraint is satisfied. * to verify that the constraint is satisfied.
......
...@@ -74,6 +74,7 @@ static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */ ...@@ -74,6 +74,7 @@ static PendingRelDelete *pendingDeletes = NULL; /* head of linked list */
typedef struct xl_smgr_create typedef struct xl_smgr_create
{ {
RelFileNode rnode; RelFileNode rnode;
ForkNumber forkNum;
} xl_smgr_create; } xl_smgr_create;
typedef struct xl_smgr_truncate typedef struct xl_smgr_truncate
...@@ -98,9 +99,6 @@ void ...@@ -98,9 +99,6 @@ void
RelationCreateStorage(RelFileNode rnode, char relpersistence) RelationCreateStorage(RelFileNode rnode, char relpersistence)
{ {
PendingRelDelete *pending; PendingRelDelete *pending;
XLogRecPtr lsn;
XLogRecData rdata;
xl_smgr_create xlrec;
SMgrRelation srel; SMgrRelation srel;
BackendId backend; BackendId backend;
bool needs_wal; bool needs_wal;
...@@ -111,6 +109,10 @@ RelationCreateStorage(RelFileNode rnode, char relpersistence) ...@@ -111,6 +109,10 @@ RelationCreateStorage(RelFileNode rnode, char relpersistence)
backend = MyBackendId; backend = MyBackendId;
needs_wal = false; needs_wal = false;
break; break;
case RELPERSISTENCE_UNLOGGED:
backend = InvalidBackendId;
needs_wal = false;
break;
case RELPERSISTENCE_PERMANENT: case RELPERSISTENCE_PERMANENT:
backend = InvalidBackendId; backend = InvalidBackendId;
needs_wal = true; needs_wal = true;
...@@ -124,19 +126,7 @@ RelationCreateStorage(RelFileNode rnode, char relpersistence) ...@@ -124,19 +126,7 @@ RelationCreateStorage(RelFileNode rnode, char relpersistence)
smgrcreate(srel, MAIN_FORKNUM, false); smgrcreate(srel, MAIN_FORKNUM, false);
if (needs_wal) if (needs_wal)
{ log_smgrcreate(&srel->smgr_rnode.node, MAIN_FORKNUM);
/*
* Make an XLOG entry reporting the file creation.
*/
xlrec.rnode = rnode;
rdata.data = (char *) &xlrec;
rdata.len = sizeof(xlrec);
rdata.buffer = InvalidBuffer;
rdata.next = NULL;
lsn = XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE, &rdata);
}
/* Add the relation to the list of stuff to delete at abort */ /* Add the relation to the list of stuff to delete at abort */
pending = (PendingRelDelete *) pending = (PendingRelDelete *)
...@@ -149,6 +139,29 @@ RelationCreateStorage(RelFileNode rnode, char relpersistence) ...@@ -149,6 +139,29 @@ RelationCreateStorage(RelFileNode rnode, char relpersistence)
pendingDeletes = pending; pendingDeletes = pending;
} }
/*
* Perform XLogInsert of a XLOG_SMGR_CREATE record to WAL.
*/
void
log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum)
{
xl_smgr_create xlrec;
XLogRecData rdata;
/*
* Make an XLOG entry reporting the file creation.
*/
xlrec.rnode = *rnode;
xlrec.forkNum = forkNum;
rdata.data = (char *) &xlrec;
rdata.len = sizeof(xlrec);
rdata.buffer = InvalidBuffer;
rdata.next = NULL;
XLogInsert(RM_SMGR_ID, XLOG_SMGR_CREATE, &rdata);
}
/* /*
* RelationDropStorage * RelationDropStorage
* Schedule unlinking of physical storage at transaction commit. * Schedule unlinking of physical storage at transaction commit.
...@@ -478,7 +491,7 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record) ...@@ -478,7 +491,7 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
SMgrRelation reln; SMgrRelation reln;
reln = smgropen(xlrec->rnode, InvalidBackendId); reln = smgropen(xlrec->rnode, InvalidBackendId);
smgrcreate(reln, MAIN_FORKNUM, true); smgrcreate(reln, xlrec->forkNum, true);
} }
else if (info == XLOG_SMGR_TRUNCATE) else if (info == XLOG_SMGR_TRUNCATE)
{ {
...@@ -523,7 +536,7 @@ smgr_desc(StringInfo buf, uint8 xl_info, char *rec) ...@@ -523,7 +536,7 @@ smgr_desc(StringInfo buf, uint8 xl_info, char *rec)
if (info == XLOG_SMGR_CREATE) if (info == XLOG_SMGR_CREATE)
{ {
xl_smgr_create *xlrec = (xl_smgr_create *) rec; xl_smgr_create *xlrec = (xl_smgr_create *) rec;
char *path = relpathperm(xlrec->rnode, MAIN_FORKNUM); char *path = relpathperm(xlrec->rnode, xlrec->forkNum);
appendStringInfo(buf, "file create: %s", path); appendStringInfo(buf, "file create: %s", path);
pfree(path); pfree(path);
......
...@@ -5128,12 +5128,12 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, ...@@ -5128,12 +5128,12 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
RelationGetRelationName(pkrel)))); RelationGetRelationName(pkrel))));
/* /*
* References from permanent tables to temp tables are disallowed because * References from permanent or unlogged tables to temp tables, and from
* the contents of the temp table disappear at the end of each session. * permanent tables to unlogged tables, are disallowed because the
* References from temp tables to permanent tables are also disallowed, * referenced data can vanish out from under us. References from temp
* because other backends might need to run the RI triggers on the perm * tables to any other table type are also disallowed, because other
* table, but they can't reliably see tuples in the local buffers of other * backends might need to run the RI triggers on the perm table, but they
* backends. * can't reliably see tuples in the local buffers of other backends.
*/ */
switch (rel->rd_rel->relpersistence) switch (rel->rd_rel->relpersistence)
{ {
...@@ -5143,6 +5143,13 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, ...@@ -5143,6 +5143,13 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION), (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("constraints on permanent tables may reference only permanent tables"))); errmsg("constraints on permanent tables may reference only permanent tables")));
break; break;
case RELPERSISTENCE_UNLOGGED:
if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_PERMANENT
&& pkrel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("constraints on unlogged tables may reference only permanent or unlogged tables")));
break;
case RELPERSISTENCE_TEMP: case RELPERSISTENCE_TEMP:
if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP) if (pkrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
ereport(ERROR, ereport(ERROR,
......
...@@ -538,8 +538,8 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_ ...@@ -538,8 +538,8 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
TRUNCATE TRUSTED TYPE_P TRUNCATE TRUSTED TYPE_P
UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNLOGGED
UPDATE USER USING UNTIL UPDATE USER USING
VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING
VERBOSE VERSION_P VIEW VOLATILE VERBOSE VERSION_P VIEW VOLATILE
...@@ -2365,6 +2365,7 @@ OptTemp: TEMPORARY { $$ = RELPERSISTENCE_TEMP; } ...@@ -2365,6 +2365,7 @@ OptTemp: TEMPORARY { $$ = RELPERSISTENCE_TEMP; }
| LOCAL TEMP { $$ = RELPERSISTENCE_TEMP; } | LOCAL TEMP { $$ = RELPERSISTENCE_TEMP; }
| GLOBAL TEMPORARY { $$ = RELPERSISTENCE_TEMP; } | GLOBAL TEMPORARY { $$ = RELPERSISTENCE_TEMP; }
| GLOBAL TEMP { $$ = RELPERSISTENCE_TEMP; } | GLOBAL TEMP { $$ = RELPERSISTENCE_TEMP; }
| UNLOGGED { $$ = RELPERSISTENCE_UNLOGGED; }
| /*EMPTY*/ { $$ = RELPERSISTENCE_PERMANENT; } | /*EMPTY*/ { $$ = RELPERSISTENCE_PERMANENT; }
; ;
...@@ -7927,6 +7928,11 @@ OptTempTableName: ...@@ -7927,6 +7928,11 @@ OptTempTableName:
$$ = $4; $$ = $4;
$$->relpersistence = RELPERSISTENCE_TEMP; $$->relpersistence = RELPERSISTENCE_TEMP;
} }
| UNLOGGED opt_table qualified_name
{
$$ = $3;
$$->relpersistence = RELPERSISTENCE_UNLOGGED;
}
| TABLE qualified_name | TABLE qualified_name
{ {
$$ = $2; $$ = $2;
...@@ -11395,6 +11401,7 @@ unreserved_keyword: ...@@ -11395,6 +11401,7 @@ unreserved_keyword:
| UNENCRYPTED | UNENCRYPTED
| UNKNOWN | UNKNOWN
| UNLISTEN | UNLISTEN
| UNLOGGED
| UNTIL | UNTIL
| UPDATE | UPDATE
| VACUUM | VACUUM
......
...@@ -82,7 +82,7 @@ static bool IsForInput; ...@@ -82,7 +82,7 @@ static bool IsForInput;
static volatile BufferDesc *PinCountWaitBuf = NULL; static volatile BufferDesc *PinCountWaitBuf = NULL;
static Buffer ReadBuffer_common(SMgrRelation reln, static Buffer ReadBuffer_common(SMgrRelation reln, char relpersistence,
ForkNumber forkNum, BlockNumber blockNum, ForkNumber forkNum, BlockNumber blockNum,
ReadBufferMode mode, BufferAccessStrategy strategy, ReadBufferMode mode, BufferAccessStrategy strategy,
bool *hit); bool *hit);
...@@ -97,7 +97,9 @@ static void TerminateBufferIO(volatile BufferDesc *buf, bool clear_dirty, ...@@ -97,7 +97,9 @@ static void TerminateBufferIO(volatile BufferDesc *buf, bool clear_dirty,
int set_flag_bits); int set_flag_bits);
static void shared_buffer_write_error_callback(void *arg); static void shared_buffer_write_error_callback(void *arg);
static void local_buffer_write_error_callback(void *arg); static void local_buffer_write_error_callback(void *arg);
static volatile BufferDesc *BufferAlloc(SMgrRelation smgr, ForkNumber forkNum, static volatile BufferDesc *BufferAlloc(SMgrRelation smgr,
char relpersistence,
ForkNumber forkNum,
BlockNumber blockNum, BlockNumber blockNum,
BufferAccessStrategy strategy, BufferAccessStrategy strategy,
bool *foundPtr); bool *foundPtr);
...@@ -241,8 +243,8 @@ ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ...@@ -241,8 +243,8 @@ ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
* miss. * miss.
*/ */
pgstat_count_buffer_read(reln); pgstat_count_buffer_read(reln);
buf = ReadBuffer_common(reln->rd_smgr, forkNum, blockNum, buf = ReadBuffer_common(reln->rd_smgr, reln->rd_rel->relpersistence,
mode, strategy, &hit); forkNum, blockNum, mode, strategy, &hit);
if (hit) if (hit)
pgstat_count_buffer_hit(reln); pgstat_count_buffer_hit(reln);
return buf; return buf;
...@@ -253,10 +255,10 @@ ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ...@@ -253,10 +255,10 @@ ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
* ReadBufferWithoutRelcache -- like ReadBufferExtended, but doesn't require * ReadBufferWithoutRelcache -- like ReadBufferExtended, but doesn't require
* a relcache entry for the relation. * a relcache entry for the relation.
* *
* NB: At present, this function may not be used on temporary relations, which * NB: At present, this function may only be used on permanent relations, which
* is OK, because we only use it during XLOG replay. If in the future we * is OK, because we only use it during XLOG replay. If in the future we
* want to use it on temporary relations, we could pass the backend ID as an * want to use it on temporary or unlogged relations, we could pass additional
* additional parameter. * parameters.
*/ */
Buffer Buffer
ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum, ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum,
...@@ -267,7 +269,8 @@ ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum, ...@@ -267,7 +269,8 @@ ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum,
SMgrRelation smgr = smgropen(rnode, InvalidBackendId); SMgrRelation smgr = smgropen(rnode, InvalidBackendId);
return ReadBuffer_common(smgr, forkNum, blockNum, mode, strategy, &hit); return ReadBuffer_common(smgr, RELPERSISTENCE_PERMANENT, forkNum, blockNum,
mode, strategy, &hit);
} }
...@@ -277,7 +280,7 @@ ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum, ...@@ -277,7 +280,7 @@ ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum,
* *hit is set to true if the request was satisfied from shared buffer cache. * *hit is set to true if the request was satisfied from shared buffer cache.
*/ */
static Buffer static Buffer
ReadBuffer_common(SMgrRelation smgr, ForkNumber forkNum, ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
BlockNumber blockNum, ReadBufferMode mode, BlockNumber blockNum, ReadBufferMode mode,
BufferAccessStrategy strategy, bool *hit) BufferAccessStrategy strategy, bool *hit)
{ {
...@@ -319,7 +322,8 @@ ReadBuffer_common(SMgrRelation smgr, ForkNumber forkNum, ...@@ -319,7 +322,8 @@ ReadBuffer_common(SMgrRelation smgr, ForkNumber forkNum,
* lookup the buffer. IO_IN_PROGRESS is set if the requested block is * lookup the buffer. IO_IN_PROGRESS is set if the requested block is
* not currently in memory. * not currently in memory.
*/ */
bufHdr = BufferAlloc(smgr, forkNum, blockNum, strategy, &found); bufHdr = BufferAlloc(smgr, relpersistence, forkNum, blockNum,
strategy, &found);
if (found) if (found)
pgBufferUsage.shared_blks_hit++; pgBufferUsage.shared_blks_hit++;
else else
...@@ -500,7 +504,7 @@ ReadBuffer_common(SMgrRelation smgr, ForkNumber forkNum, ...@@ -500,7 +504,7 @@ ReadBuffer_common(SMgrRelation smgr, ForkNumber forkNum,
* No locks are held either at entry or exit. * No locks are held either at entry or exit.
*/ */
static volatile BufferDesc * static volatile BufferDesc *
BufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
BlockNumber blockNum, BlockNumber blockNum,
BufferAccessStrategy strategy, BufferAccessStrategy strategy,
bool *foundPtr) bool *foundPtr)
...@@ -797,8 +801,11 @@ BufferAlloc(SMgrRelation smgr, ForkNumber forkNum, ...@@ -797,8 +801,11 @@ BufferAlloc(SMgrRelation smgr, ForkNumber forkNum,
* 1 so that the buffer can survive one clock-sweep pass.) * 1 so that the buffer can survive one clock-sweep pass.)
*/ */
buf->tag = newTag; buf->tag = newTag;
buf->flags &= ~(BM_VALID | BM_DIRTY | BM_JUST_DIRTIED | BM_CHECKPOINT_NEEDED | BM_IO_ERROR); buf->flags &= ~(BM_VALID | BM_DIRTY | BM_JUST_DIRTIED | BM_CHECKPOINT_NEEDED | BM_IO_ERROR | BM_PERMANENT);
buf->flags |= BM_TAG_VALID; if (relpersistence == RELPERSISTENCE_PERMANENT)
buf->flags |= BM_TAG_VALID | BM_PERMANENT;
else
buf->flags |= BM_TAG_VALID;
buf->usage_count = 1; buf->usage_count = 1;
UnlockBufHdr(buf); UnlockBufHdr(buf);
...@@ -1155,8 +1162,10 @@ UnpinBuffer(volatile BufferDesc *buf, bool fixOwner) ...@@ -1155,8 +1162,10 @@ UnpinBuffer(volatile BufferDesc *buf, bool fixOwner)
* BufferSync -- Write out all dirty buffers in the pool. * BufferSync -- Write out all dirty buffers in the pool.
* *
* This is called at checkpoint time to write out all dirty shared buffers. * This is called at checkpoint time to write out all dirty shared buffers.
* The checkpoint request flags should be passed in; currently the only one * The checkpoint request flags should be passed in. If CHECKPOINT_IMMEDIATE
* examined is CHECKPOINT_IMMEDIATE, which disables delays between writes. * is set, we disable delays between writes; if CHECKPOINT_IS_SHUTDOWN is
* set, we write even unlogged buffers, which are otherwise skipped. The
* remaining flags currently have no effect here.
*/ */
static void static void
BufferSync(int flags) BufferSync(int flags)
...@@ -1165,10 +1174,18 @@ BufferSync(int flags) ...@@ -1165,10 +1174,18 @@ BufferSync(int flags)
int num_to_scan; int num_to_scan;
int num_to_write; int num_to_write;
int num_written; int num_written;
int mask = BM_DIRTY;
/* Make sure we can handle the pin inside SyncOneBuffer */ /* Make sure we can handle the pin inside SyncOneBuffer */
ResourceOwnerEnlargeBuffers(CurrentResourceOwner); ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
/*
* Unless this is a shutdown checkpoint, we write only permanent, dirty
* buffers. But at shutdown time, we write all dirty buffers.
*/
if (!(flags & CHECKPOINT_IS_SHUTDOWN))
flags |= BM_PERMANENT;
/* /*
* Loop over all buffers, and mark the ones that need to be written with * Loop over all buffers, and mark the ones that need to be written with
* BM_CHECKPOINT_NEEDED. Count them as we go (num_to_write), so that we * BM_CHECKPOINT_NEEDED. Count them as we go (num_to_write), so that we
...@@ -1196,7 +1213,7 @@ BufferSync(int flags) ...@@ -1196,7 +1213,7 @@ BufferSync(int flags)
*/ */
LockBufHdr(bufHdr); LockBufHdr(bufHdr);
if (bufHdr->flags & BM_DIRTY) if ((bufHdr->flags & mask) == mask)
{ {
bufHdr->flags |= BM_CHECKPOINT_NEEDED; bufHdr->flags |= BM_CHECKPOINT_NEEDED;
num_to_write++; num_to_write++;
...@@ -1897,12 +1914,12 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln) ...@@ -1897,12 +1914,12 @@ FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln)
* Determines the current number of pages in the relation. * Determines the current number of pages in the relation.
*/ */
BlockNumber BlockNumber
RelationGetNumberOfBlocks(Relation relation) RelationGetNumberOfBlocksInFork(Relation relation, ForkNumber forkNum)
{ {
/* Open it at the smgr level if not already done */ /* Open it at the smgr level if not already done */
RelationOpenSmgr(relation); RelationOpenSmgr(relation);
return smgrnblocks(relation->rd_smgr, MAIN_FORKNUM); return smgrnblocks(relation->rd_smgr, forkNum);
} }
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
......
...@@ -12,6 +12,6 @@ subdir = src/backend/storage/file ...@@ -12,6 +12,6 @@ subdir = src/backend/storage/file
top_builddir = ../../../.. top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global include $(top_builddir)/src/Makefile.global
OBJS = fd.o buffile.o copydir.o OBJS = fd.o buffile.o copydir.o reinit.o
include $(top_srcdir)/src/backend/common.mk include $(top_srcdir)/src/backend/common.mk
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#endif #endif
static void copy_file(char *fromfile, char *tofile);
static void fsync_fname(char *fname, bool isdir); static void fsync_fname(char *fname, bool isdir);
...@@ -142,7 +141,7 @@ copydir(char *fromdir, char *todir, bool recurse) ...@@ -142,7 +141,7 @@ copydir(char *fromdir, char *todir, bool recurse)
/* /*
* copy one file * copy one file
*/ */
static void void
copy_file(char *fromfile, char *tofile) copy_file(char *fromfile, char *tofile)
{ {
char *buffer; char *buffer;
......
...@@ -2055,7 +2055,7 @@ looks_like_temp_rel_name(const char *name) ...@@ -2055,7 +2055,7 @@ looks_like_temp_rel_name(const char *name)
/* We might have _forkname or .segment or both. */ /* We might have _forkname or .segment or both. */
if (name[pos] == '_') if (name[pos] == '_')
{ {
int forkchar = forkname_chars(&name[pos+1]); int forkchar = forkname_chars(&name[pos+1], NULL);
if (forkchar <= 0) if (forkchar <= 0)
return false; return false;
pos += forkchar + 1; pos += forkchar + 1;
......
This diff is collapsed.
...@@ -615,6 +615,7 @@ pg_relation_filepath(PG_FUNCTION_ARGS) ...@@ -615,6 +615,7 @@ pg_relation_filepath(PG_FUNCTION_ARGS)
/* Determine owning backend. */ /* Determine owning backend. */
switch (relform->relpersistence) switch (relform->relpersistence)
{ {
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT: case RELPERSISTENCE_PERMANENT:
backend = InvalidBackendId; backend = InvalidBackendId;
break; break;
......
...@@ -851,6 +851,7 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) ...@@ -851,6 +851,7 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
relation->rd_newRelfilenodeSubid = InvalidSubTransactionId; relation->rd_newRelfilenodeSubid = InvalidSubTransactionId;
switch (relation->rd_rel->relpersistence) switch (relation->rd_rel->relpersistence)
{ {
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT: case RELPERSISTENCE_PERMANENT:
relation->rd_backend = InvalidBackendId; relation->rd_backend = InvalidBackendId;
break; break;
...@@ -2490,6 +2491,7 @@ RelationBuildLocalRelation(const char *relname, ...@@ -2490,6 +2491,7 @@ RelationBuildLocalRelation(const char *relname,
rel->rd_rel->relpersistence = relpersistence; rel->rd_rel->relpersistence = relpersistence;
switch (relpersistence) switch (relpersistence)
{ {
case RELPERSISTENCE_UNLOGGED:
case RELPERSISTENCE_PERMANENT: case RELPERSISTENCE_PERMANENT:
rel->rd_backend = InvalidBackendId; rel->rd_backend = InvalidBackendId;
break; break;
......
...@@ -134,6 +134,7 @@ static int disable_dollar_quoting = 0; ...@@ -134,6 +134,7 @@ static int disable_dollar_quoting = 0;
static int dump_inserts = 0; static int dump_inserts = 0;
static int column_inserts = 0; static int column_inserts = 0;
static int no_security_label = 0; static int no_security_label = 0;
static int no_unlogged_table_data = 0;
static void help(const char *progname); static void help(const char *progname);
...@@ -316,6 +317,7 @@ main(int argc, char **argv) ...@@ -316,6 +317,7 @@ main(int argc, char **argv)
{"role", required_argument, NULL, 3}, {"role", required_argument, NULL, 3},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1}, {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
{"no-security-label", no_argument, &no_security_label, 1}, {"no-security-label", no_argument, &no_security_label, 1},
{"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
...@@ -466,6 +468,8 @@ main(int argc, char **argv) ...@@ -466,6 +468,8 @@ main(int argc, char **argv)
use_setsessauth = 1; use_setsessauth = 1;
else if (strcmp(optarg, "no-security-label") == 0) else if (strcmp(optarg, "no-security-label") == 0)
no_security_label = 1; no_security_label = 1;
else if (strcmp(optarg, "no-unlogged-table-data") == 0)
no_unlogged_table_data = 1;
else else
{ {
fprintf(stderr, fprintf(stderr,
...@@ -864,6 +868,7 @@ help(const char *progname) ...@@ -864,6 +868,7 @@ help(const char *progname)
printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n")); printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n"));
printf(_(" --role=ROLENAME do SET ROLE before dump\n")); printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
printf(_(" --no-security-label do not dump security label assignments\n")); printf(_(" --no-security-label do not dump security label assignments\n"));
printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
printf(_(" --use-set-session-authorization\n" printf(_(" --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead of\n" " use SET SESSION AUTHORIZATION commands instead of\n"
" ALTER OWNER commands to set ownership\n")); " ALTER OWNER commands to set ownership\n"));
...@@ -1471,6 +1476,10 @@ getTableData(TableInfo *tblinfo, int numTables, bool oids) ...@@ -1471,6 +1476,10 @@ getTableData(TableInfo *tblinfo, int numTables, bool oids)
/* Skip SEQUENCEs (handled elsewhere) */ /* Skip SEQUENCEs (handled elsewhere) */
if (tblinfo[i].relkind == RELKIND_SEQUENCE) if (tblinfo[i].relkind == RELKIND_SEQUENCE)
continue; continue;
/* Skip unlogged tables if so requested */
if (tblinfo[i].relpersistence == RELPERSISTENCE_UNLOGGED
&& no_unlogged_table_data)
continue;
if (tblinfo[i].dobj.dump) if (tblinfo[i].dobj.dump)
{ {
...@@ -3447,6 +3456,7 @@ getTables(int *numTables) ...@@ -3447,6 +3456,7 @@ getTables(int *numTables)
int i_relhasrules; int i_relhasrules;
int i_relhasoids; int i_relhasoids;
int i_relfrozenxid; int i_relfrozenxid;
int i_relpersistence;
int i_owning_tab; int i_owning_tab;
int i_owning_col; int i_owning_col;
int i_reltablespace; int i_reltablespace;
...@@ -3477,7 +3487,40 @@ getTables(int *numTables) ...@@ -3477,7 +3487,40 @@ getTables(int *numTables)
* we cannot correctly identify inherited columns, owned sequences, etc. * we cannot correctly identify inherited columns, owned sequences, etc.
*/ */
if (g_fout->remoteVersion >= 90000) if (g_fout->remoteVersion >= 90100)
{
/*
* Left join to pick up dependency info linking sequences to their
* owning column, if any (note this dependency is AUTO as of 8.2)
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, c.relname, "
"c.relacl, c.relkind, c.relnamespace, "
"(%s c.relowner) AS rolname, "
"c.relchecks, c.relhastriggers, "
"c.relhasindex, c.relhasrules, c.relhasoids, "
"c.relfrozenxid, c.relpersistence, "
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
"d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
"array_to_string(c.reloptions, ', ') AS reloptions, "
"array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
"FROM pg_class c "
"LEFT JOIN pg_depend d ON "
"(c.relkind = '%c' AND "
"d.classid = c.tableoid AND d.objid = c.oid AND "
"d.objsubid = 0 AND "
"d.refclassid = c.tableoid AND d.deptype = 'a') "
"LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
"WHERE c.relkind in ('%c', '%c', '%c', '%c') "
"ORDER BY c.oid",
username_subquery,
RELKIND_SEQUENCE,
RELKIND_RELATION, RELKIND_SEQUENCE,
RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
}
else if (g_fout->remoteVersion >= 90000)
{ {
/* /*
* Left join to pick up dependency info linking sequences to their * Left join to pick up dependency info linking sequences to their
...@@ -3489,7 +3532,7 @@ getTables(int *numTables) ...@@ -3489,7 +3532,7 @@ getTables(int *numTables)
"(%s c.relowner) AS rolname, " "(%s c.relowner) AS rolname, "
"c.relchecks, c.relhastriggers, " "c.relchecks, c.relhastriggers, "
"c.relhasindex, c.relhasrules, c.relhasoids, " "c.relhasindex, c.relhasrules, c.relhasoids, "
"c.relfrozenxid, " "c.relfrozenxid, 'p' AS relpersistence, "
"CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, " "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
"d.refobjid AS owning_tab, " "d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, " "d.refobjsubid AS owning_col, "
...@@ -3522,7 +3565,7 @@ getTables(int *numTables) ...@@ -3522,7 +3565,7 @@ getTables(int *numTables)
"(%s c.relowner) AS rolname, " "(%s c.relowner) AS rolname, "
"c.relchecks, c.relhastriggers, " "c.relchecks, c.relhastriggers, "
"c.relhasindex, c.relhasrules, c.relhasoids, " "c.relhasindex, c.relhasrules, c.relhasoids, "
"c.relfrozenxid, " "c.relfrozenxid, 'p' AS relpersistence, "
"NULL AS reloftype, " "NULL AS reloftype, "
"d.refobjid AS owning_tab, " "d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, " "d.refobjsubid AS owning_col, "
...@@ -3555,7 +3598,7 @@ getTables(int *numTables) ...@@ -3555,7 +3598,7 @@ getTables(int *numTables)
"(%s relowner) AS rolname, " "(%s relowner) AS rolname, "
"relchecks, (reltriggers <> 0) AS relhastriggers, " "relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, relhasoids, " "relhasindex, relhasrules, relhasoids, "
"relfrozenxid, " "relfrozenxid, 'p' AS relpersistence, "
"NULL AS reloftype, " "NULL AS reloftype, "
"d.refobjid AS owning_tab, " "d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, " "d.refobjsubid AS owning_col, "
...@@ -3587,7 +3630,7 @@ getTables(int *numTables) ...@@ -3587,7 +3630,7 @@ getTables(int *numTables)
"(%s relowner) AS rolname, " "(%s relowner) AS rolname, "
"relchecks, (reltriggers <> 0) AS relhastriggers, " "relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, relhasoids, " "relhasindex, relhasrules, relhasoids, "
"0 AS relfrozenxid, " "0 AS relfrozenxid, 'p' AS relpersistence, "
"NULL AS reloftype, " "NULL AS reloftype, "
"d.refobjid AS owning_tab, " "d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, " "d.refobjsubid AS owning_col, "
...@@ -3619,7 +3662,7 @@ getTables(int *numTables) ...@@ -3619,7 +3662,7 @@ getTables(int *numTables)
"(%s relowner) AS rolname, " "(%s relowner) AS rolname, "
"relchecks, (reltriggers <> 0) AS relhastriggers, " "relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, relhasoids, " "relhasindex, relhasrules, relhasoids, "
"0 AS relfrozenxid, " "0 AS relfrozenxid, 'p' AS relpersistence, "
"NULL AS reloftype, " "NULL AS reloftype, "
"d.refobjid AS owning_tab, " "d.refobjid AS owning_tab, "
"d.refobjsubid AS owning_col, " "d.refobjsubid AS owning_col, "
...@@ -3647,7 +3690,7 @@ getTables(int *numTables) ...@@ -3647,7 +3690,7 @@ getTables(int *numTables)
"(%s relowner) AS rolname, " "(%s relowner) AS rolname, "
"relchecks, (reltriggers <> 0) AS relhastriggers, " "relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, relhasoids, " "relhasindex, relhasrules, relhasoids, "
"0 AS relfrozenxid, " "0 AS relfrozenxid, 'p' AS relpersistence, "
"NULL AS reloftype, " "NULL AS reloftype, "
"NULL::oid AS owning_tab, " "NULL::oid AS owning_tab, "
"NULL::int4 AS owning_col, " "NULL::int4 AS owning_col, "
...@@ -3670,7 +3713,7 @@ getTables(int *numTables) ...@@ -3670,7 +3713,7 @@ getTables(int *numTables)
"relchecks, (reltriggers <> 0) AS relhastriggers, " "relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, " "relhasindex, relhasrules, "
"'t'::bool AS relhasoids, " "'t'::bool AS relhasoids, "
"0 AS relfrozenxid, " "0 AS relfrozenxid, 'p' AS relpersistence, "
"NULL AS reloftype, " "NULL AS reloftype, "
"NULL::oid AS owning_tab, " "NULL::oid AS owning_tab, "
"NULL::int4 AS owning_col, " "NULL::int4 AS owning_col, "
...@@ -3703,7 +3746,7 @@ getTables(int *numTables) ...@@ -3703,7 +3746,7 @@ getTables(int *numTables)
"relchecks, (reltriggers <> 0) AS relhastriggers, " "relchecks, (reltriggers <> 0) AS relhastriggers, "
"relhasindex, relhasrules, " "relhasindex, relhasrules, "
"'t'::bool AS relhasoids, " "'t'::bool AS relhasoids, "
"0 as relfrozenxid, " "0 as relfrozenxid, 'p' AS relpersistence, "
"NULL AS reloftype, " "NULL AS reloftype, "
"NULL::oid AS owning_tab, " "NULL::oid AS owning_tab, "
"NULL::int4 AS owning_col, " "NULL::int4 AS owning_col, "
...@@ -3749,6 +3792,7 @@ getTables(int *numTables) ...@@ -3749,6 +3792,7 @@ getTables(int *numTables)
i_relhasrules = PQfnumber(res, "relhasrules"); i_relhasrules = PQfnumber(res, "relhasrules");
i_relhasoids = PQfnumber(res, "relhasoids"); i_relhasoids = PQfnumber(res, "relhasoids");
i_relfrozenxid = PQfnumber(res, "relfrozenxid"); i_relfrozenxid = PQfnumber(res, "relfrozenxid");
i_relpersistence = PQfnumber(res, "relpersistence");
i_owning_tab = PQfnumber(res, "owning_tab"); i_owning_tab = PQfnumber(res, "owning_tab");
i_owning_col = PQfnumber(res, "owning_col"); i_owning_col = PQfnumber(res, "owning_col");
i_reltablespace = PQfnumber(res, "reltablespace"); i_reltablespace = PQfnumber(res, "reltablespace");
...@@ -3783,6 +3827,7 @@ getTables(int *numTables) ...@@ -3783,6 +3827,7 @@ getTables(int *numTables)
tblinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname)); tblinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl)); tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind)); tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0); tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0); tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0); tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
...@@ -11051,8 +11096,12 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo) ...@@ -11051,8 +11096,12 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
if (binary_upgrade) if (binary_upgrade)
binary_upgrade_set_relfilenodes(q, tbinfo->dobj.catId.oid, false); binary_upgrade_set_relfilenodes(q, tbinfo->dobj.catId.oid, false);
appendPQExpBuffer(q, "CREATE TABLE %s", if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED)
fmtId(tbinfo->dobj.name)); appendPQExpBuffer(q, "CREATE UNLOGGED TABLE %s",
fmtId(tbinfo->dobj.name));
else
appendPQExpBuffer(q, "CREATE TABLE %s",
fmtId(tbinfo->dobj.name));
if (tbinfo->reloftype) if (tbinfo->reloftype)
appendPQExpBuffer(q, " OF %s", tbinfo->reloftype); appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
actual_atts = 0; actual_atts = 0;
......
...@@ -220,6 +220,7 @@ typedef struct _tableInfo ...@@ -220,6 +220,7 @@ typedef struct _tableInfo
char *rolname; /* name of owner, or empty string */ char *rolname; /* name of owner, or empty string */
char *relacl; char *relacl;
char relkind; char relkind;
char relpersistence; /* relation persistence */
char *reltablespace; /* relation tablespace */ char *reltablespace; /* relation tablespace */
char *reloptions; /* options specified by WITH (...) */ char *reloptions; /* options specified by WITH (...) */
char *toast_reloptions; /* ditto, for the TOAST table */ char *toast_reloptions; /* ditto, for the TOAST table */
......
...@@ -70,6 +70,7 @@ static int inserts = 0; ...@@ -70,6 +70,7 @@ static int inserts = 0;
static int no_tablespaces = 0; static int no_tablespaces = 0;
static int use_setsessauth = 0; static int use_setsessauth = 0;
static int no_security_label = 0; static int no_security_label = 0;
static int no_unlogged_table_data = 0;
static int server_version; static int server_version;
static FILE *OPF; static FILE *OPF;
...@@ -135,6 +136,7 @@ main(int argc, char *argv[]) ...@@ -135,6 +136,7 @@ main(int argc, char *argv[])
{"role", required_argument, NULL, 3}, {"role", required_argument, NULL, 3},
{"use-set-session-authorization", no_argument, &use_setsessauth, 1}, {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
{"no-security-label", no_argument, &no_security_label, 1}, {"no-security-label", no_argument, &no_security_label, 1},
{"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
{NULL, 0, NULL, 0} {NULL, 0, NULL, 0}
}; };
...@@ -290,6 +292,8 @@ main(int argc, char *argv[]) ...@@ -290,6 +292,8 @@ main(int argc, char *argv[])
use_setsessauth = 1; use_setsessauth = 1;
else if (strcmp(optarg, "no-security-label") == 0) else if (strcmp(optarg, "no-security-label") == 0)
no_security_label = 1; no_security_label = 1;
else if (strcmp(optarg, "no-unlogged-table-data") == 0)
no_unlogged_table_data = 1;
else else
{ {
fprintf(stderr, fprintf(stderr,
...@@ -377,6 +381,8 @@ main(int argc, char *argv[]) ...@@ -377,6 +381,8 @@ main(int argc, char *argv[])
appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization"); appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization");
if (no_security_label) if (no_security_label)
appendPQExpBuffer(pgdumpopts, " --no-security-label"); appendPQExpBuffer(pgdumpopts, " --no-security-label");
if (no_unlogged_table_data)
appendPQExpBuffer(pgdumpopts, " --no-unlogged-table-data");
/* /*
* If there was a database specified on the command line, use that, * If there was a database specified on the command line, use that,
...@@ -574,6 +580,7 @@ help(void) ...@@ -574,6 +580,7 @@ help(void)
printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n")); printf(_(" --quote-all-identifiers quote all identifiers, even if not keywords\n"));
printf(_(" --role=ROLENAME do SET ROLE before dump\n")); printf(_(" --role=ROLENAME do SET ROLE before dump\n"));
printf(_(" --no-security-label do not dump security label assignments\n")); printf(_(" --no-security-label do not dump security label assignments\n"));
printf(_(" --no-unlogged-table-data do not dump unlogged table data\n"));
printf(_(" --use-set-session-authorization\n" printf(_(" --use-set-session-authorization\n"
" use SET SESSION AUTHORIZATION commands instead of\n" " use SET SESSION AUTHORIZATION commands instead of\n"
" ALTER OWNER commands to set ownership\n")); " ALTER OWNER commands to set ownership\n"));
......
...@@ -1118,6 +1118,7 @@ describeOneTableDetails(const char *schemaname, ...@@ -1118,6 +1118,7 @@ describeOneTableDetails(const char *schemaname,
Oid tablespace; Oid tablespace;
char *reloptions; char *reloptions;
char *reloftype; char *reloftype;
char relpersistence;
} tableinfo; } tableinfo;
bool show_modifiers = false; bool show_modifiers = false;
bool retval; bool retval;
...@@ -1133,6 +1134,23 @@ describeOneTableDetails(const char *schemaname, ...@@ -1133,6 +1134,23 @@ describeOneTableDetails(const char *schemaname,
/* Get general table info */ /* Get general table info */
if (pset.sversion >= 90000) if (pset.sversion >= 90000)
{
printfPQExpBuffer(&buf,
"SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
"c.relhastriggers, c.relhasoids, "
"%s, c.reltablespace, "
"CASE WHEN c.reloftype = 0 THEN '' ELSE c.reloftype::pg_catalog.regtype::pg_catalog.text END, "
"c.relpersistence\n"
"FROM pg_catalog.pg_class c\n "
"LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)\n"
"WHERE c.oid = '%s'\n",
(verbose ?
"pg_catalog.array_to_string(c.reloptions || "
"array(select 'toast.' || x from pg_catalog.unnest(tc.reloptions) x), ', ')\n"
: "''"),
oid);
}
else if (pset.sversion >= 90000)
{ {
printfPQExpBuffer(&buf, printfPQExpBuffer(&buf,
"SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, " "SELECT c.relchecks, c.relkind, c.relhasindex, c.relhasrules, "
...@@ -1218,6 +1236,8 @@ describeOneTableDetails(const char *schemaname, ...@@ -1218,6 +1236,8 @@ describeOneTableDetails(const char *schemaname,
atooid(PQgetvalue(res, 0, 7)) : 0; atooid(PQgetvalue(res, 0, 7)) : 0;
tableinfo.reloftype = (pset.sversion >= 90000 && strcmp(PQgetvalue(res, 0, 8), "") != 0) ? tableinfo.reloftype = (pset.sversion >= 90000 && strcmp(PQgetvalue(res, 0, 8), "") != 0) ?
strdup(PQgetvalue(res, 0, 8)) : 0; strdup(PQgetvalue(res, 0, 8)) : 0;
tableinfo.relpersistence = (pset.sversion >= 90100 && strcmp(PQgetvalue(res, 0, 9), "") != 0) ?
PQgetvalue(res, 0, 9)[0] : 0;
PQclear(res); PQclear(res);
res = NULL; res = NULL;
...@@ -1269,8 +1289,12 @@ describeOneTableDetails(const char *schemaname, ...@@ -1269,8 +1289,12 @@ describeOneTableDetails(const char *schemaname,
switch (tableinfo.relkind) switch (tableinfo.relkind)
{ {
case 'r': case 'r':
printfPQExpBuffer(&title, _("Table \"%s.%s\""), if (tableinfo.relpersistence == 'u')
schemaname, relationname); printfPQExpBuffer(&title, _("Unlogged Table \"%s.%s\""),
schemaname, relationname);
else
printfPQExpBuffer(&title, _("Table \"%s.%s\""),
schemaname, relationname);
break; break;
case 'v': case 'v':
printfPQExpBuffer(&title, _("View \"%s.%s\""), printfPQExpBuffer(&title, _("View \"%s.%s\""),
...@@ -1281,8 +1305,12 @@ describeOneTableDetails(const char *schemaname, ...@@ -1281,8 +1305,12 @@ describeOneTableDetails(const char *schemaname,
schemaname, relationname); schemaname, relationname);
break; break;
case 'i': case 'i':
printfPQExpBuffer(&title, _("Index \"%s.%s\""), if (tableinfo.relpersistence == 'u')
schemaname, relationname); printfPQExpBuffer(&title, _("Unlogged Index \"%s.%s\""),
schemaname, relationname);
else
printfPQExpBuffer(&title, _("Index \"%s.%s\""),
schemaname, relationname);
break; break;
case 's': case 's':
/* not used as of 8.2, but keep it for backwards compatibility */ /* not used as of 8.2, but keep it for backwards compatibility */
......
...@@ -389,6 +389,7 @@ extern void ginUpdateStats(Relation index, const GinStatsData *stats); ...@@ -389,6 +389,7 @@ extern void ginUpdateStats(Relation index, const GinStatsData *stats);
/* gininsert.c */ /* gininsert.c */
extern Datum ginbuild(PG_FUNCTION_ARGS); extern Datum ginbuild(PG_FUNCTION_ARGS);
extern Datum ginbuildempty(PG_FUNCTION_ARGS);
extern Datum gininsert(PG_FUNCTION_ARGS); extern Datum gininsert(PG_FUNCTION_ARGS);
extern void ginEntryInsert(Relation index, GinState *ginstate, extern void ginEntryInsert(Relation index, GinState *ginstate,
OffsetNumber attnum, Datum value, OffsetNumber attnum, Datum value,
......
...@@ -281,6 +281,7 @@ typedef struct ...@@ -281,6 +281,7 @@ typedef struct
/* gist.c */ /* gist.c */
extern Datum gistbuild(PG_FUNCTION_ARGS); extern Datum gistbuild(PG_FUNCTION_ARGS);
extern Datum gistbuildempty(PG_FUNCTION_ARGS);
extern Datum gistinsert(PG_FUNCTION_ARGS); extern Datum gistinsert(PG_FUNCTION_ARGS);
extern MemoryContext createTempGistContext(void); extern MemoryContext createTempGistContext(void);
extern void initGISTstate(GISTSTATE *giststate, Relation index); extern void initGISTstate(GISTSTATE *giststate, Relation index);
......
...@@ -242,6 +242,7 @@ typedef HashMetaPageData *HashMetaPage; ...@@ -242,6 +242,7 @@ typedef HashMetaPageData *HashMetaPage;
/* public routines */ /* public routines */
extern Datum hashbuild(PG_FUNCTION_ARGS); extern Datum hashbuild(PG_FUNCTION_ARGS);
extern Datum hashbuildempty(PG_FUNCTION_ARGS);
extern Datum hashinsert(PG_FUNCTION_ARGS); extern Datum hashinsert(PG_FUNCTION_ARGS);
extern Datum hashbeginscan(PG_FUNCTION_ARGS); extern Datum hashbeginscan(PG_FUNCTION_ARGS);
extern Datum hashgettuple(PG_FUNCTION_ARGS); extern Datum hashgettuple(PG_FUNCTION_ARGS);
...@@ -291,7 +292,7 @@ extern Buffer _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf); ...@@ -291,7 +292,7 @@ extern Buffer _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf);
extern BlockNumber _hash_freeovflpage(Relation rel, Buffer ovflbuf, extern BlockNumber _hash_freeovflpage(Relation rel, Buffer ovflbuf,
BufferAccessStrategy bstrategy); BufferAccessStrategy bstrategy);
extern void _hash_initbitmap(Relation rel, HashMetaPage metap, extern void _hash_initbitmap(Relation rel, HashMetaPage metap,
BlockNumber blkno); BlockNumber blkno, ForkNumber forkNum);
extern void _hash_squeezebucket(Relation rel, extern void _hash_squeezebucket(Relation rel,
Bucket bucket, BlockNumber bucket_blkno, Bucket bucket, BlockNumber bucket_blkno,
BufferAccessStrategy bstrategy); BufferAccessStrategy bstrategy);
...@@ -303,7 +304,8 @@ extern void _hash_droplock(Relation rel, BlockNumber whichlock, int access); ...@@ -303,7 +304,8 @@ extern void _hash_droplock(Relation rel, BlockNumber whichlock, int access);
extern Buffer _hash_getbuf(Relation rel, BlockNumber blkno, extern Buffer _hash_getbuf(Relation rel, BlockNumber blkno,
int access, int flags); int access, int flags);
extern Buffer _hash_getinitbuf(Relation rel, BlockNumber blkno); extern Buffer _hash_getinitbuf(Relation rel, BlockNumber blkno);
extern Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno); extern Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno,
ForkNumber forkNum);
extern Buffer _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno, extern Buffer _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno,
int access, int flags, int access, int flags,
BufferAccessStrategy bstrategy); BufferAccessStrategy bstrategy);
...@@ -312,7 +314,8 @@ extern void _hash_dropbuf(Relation rel, Buffer buf); ...@@ -312,7 +314,8 @@ extern void _hash_dropbuf(Relation rel, Buffer buf);
extern void _hash_wrtbuf(Relation rel, Buffer buf); extern void _hash_wrtbuf(Relation rel, Buffer buf);
extern void _hash_chgbufaccess(Relation rel, Buffer buf, int from_access, extern void _hash_chgbufaccess(Relation rel, Buffer buf, int from_access,
int to_access); int to_access);
extern uint32 _hash_metapinit(Relation rel, double num_tuples); extern uint32 _hash_metapinit(Relation rel, double num_tuples,
ForkNumber forkNum);
extern void _hash_pageinit(Page page, Size size); extern void _hash_pageinit(Page page, Size size);
extern void _hash_expandtable(Relation rel, Buffer metabuf); extern void _hash_expandtable(Relation rel, Buffer metabuf);
......
...@@ -555,6 +555,7 @@ typedef BTScanOpaqueData *BTScanOpaque; ...@@ -555,6 +555,7 @@ typedef BTScanOpaqueData *BTScanOpaque;
* prototypes for functions in nbtree.c (external entry points for btree) * prototypes for functions in nbtree.c (external entry points for btree)
*/ */
extern Datum btbuild(PG_FUNCTION_ARGS); extern Datum btbuild(PG_FUNCTION_ARGS);
extern Datum btbuildempty(PG_FUNCTION_ARGS);
extern Datum btinsert(PG_FUNCTION_ARGS); extern Datum btinsert(PG_FUNCTION_ARGS);
extern Datum btbeginscan(PG_FUNCTION_ARGS); extern Datum btbeginscan(PG_FUNCTION_ARGS);
extern Datum btgettuple(PG_FUNCTION_ARGS); extern Datum btgettuple(PG_FUNCTION_ARGS);
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
extern const char *forkNames[]; extern const char *forkNames[];
extern ForkNumber forkname_to_number(char *forkName); extern ForkNumber forkname_to_number(char *forkName);
extern int forkname_chars(const char *str); extern int forkname_chars(const char *str, ForkNumber *);
extern char *relpathbackend(RelFileNode rnode, BackendId backend, extern char *relpathbackend(RelFileNode rnode, BackendId backend,
ForkNumber forknum); ForkNumber forknum);
......
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201012271 #define CATALOG_VERSION_NO 201012291
#endif #endif
...@@ -60,6 +60,7 @@ CATALOG(pg_am,2601) ...@@ -60,6 +60,7 @@ CATALOG(pg_am,2601)
regproc ammarkpos; /* "mark current scan position" function */ regproc ammarkpos; /* "mark current scan position" function */
regproc amrestrpos; /* "restore marked scan position" function */ regproc amrestrpos; /* "restore marked scan position" function */
regproc ambuild; /* "build new index" function */ regproc ambuild; /* "build new index" function */
regproc ambuildempty; /* "build empty index" function */
regproc ambulkdelete; /* bulk-delete function */ regproc ambulkdelete; /* bulk-delete function */
regproc amvacuumcleanup; /* post-VACUUM cleanup function */ regproc amvacuumcleanup; /* post-VACUUM cleanup function */
regproc amcostestimate; /* estimate cost of an indexscan */ regproc amcostestimate; /* estimate cost of an indexscan */
...@@ -101,26 +102,27 @@ typedef FormData_pg_am *Form_pg_am; ...@@ -101,26 +102,27 @@ typedef FormData_pg_am *Form_pg_am;
#define Anum_pg_am_ammarkpos 21 #define Anum_pg_am_ammarkpos 21
#define Anum_pg_am_amrestrpos 22 #define Anum_pg_am_amrestrpos 22
#define Anum_pg_am_ambuild 23 #define Anum_pg_am_ambuild 23
#define Anum_pg_am_ambulkdelete 24 #define Anum_pg_am_ambuildempty 24
#define Anum_pg_am_amvacuumcleanup 25 #define Anum_pg_am_ambulkdelete 25
#define Anum_pg_am_amcostestimate 26 #define Anum_pg_am_amvacuumcleanup 26
#define Anum_pg_am_amoptions 27 #define Anum_pg_am_amcostestimate 27
#define Anum_pg_am_amoptions 28
/* ---------------- /* ----------------
* initial contents of pg_am * initial contents of pg_am
* ---------------- * ----------------
*/ */
DATA(insert OID = 403 ( btree 5 1 t f t t t t t t f t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbulkdelete btvacuumcleanup btcostestimate btoptions )); DATA(insert OID = 403 ( btree 5 1 t f t t t t t t f t 0 btinsert btbeginscan btgettuple btgetbitmap btrescan btendscan btmarkpos btrestrpos btbuild btbuildempty btbulkdelete btvacuumcleanup btcostestimate btoptions ));
DESCR("b-tree index access method"); DESCR("b-tree index access method");
#define BTREE_AM_OID 403 #define BTREE_AM_OID 403
DATA(insert OID = 405 ( hash 1 1 f f t f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions )); DATA(insert OID = 405 ( hash 1 1 f f t f f f f f f f 23 hashinsert hashbeginscan hashgettuple hashgetbitmap hashrescan hashendscan hashmarkpos hashrestrpos hashbuild hashbuildempty hashbulkdelete hashvacuumcleanup hashcostestimate hashoptions ));
DESCR("hash index access method"); DESCR("hash index access method");
#define HASH_AM_OID 405 #define HASH_AM_OID 405
DATA(insert OID = 783 ( gist 0 8 f t f f t t t t t t 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions )); DATA(insert OID = 783 ( gist 0 8 f t f f t t t t t t 0 gistinsert gistbeginscan gistgettuple gistgetbitmap gistrescan gistendscan gistmarkpos gistrestrpos gistbuild gistbuildempty gistbulkdelete gistvacuumcleanup gistcostestimate gistoptions ));
DESCR("GiST index access method"); DESCR("GiST index access method");
#define GIST_AM_OID 783 #define GIST_AM_OID 783
DATA(insert OID = 2742 ( gin 0 5 f f f f t t f f t f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbulkdelete ginvacuumcleanup gincostestimate ginoptions )); DATA(insert OID = 2742 ( gin 0 5 f f f f t t f f t f 0 gininsert ginbeginscan - gingetbitmap ginrescan ginendscan ginmarkpos ginrestrpos ginbuild ginbuildempty ginbulkdelete ginvacuumcleanup gincostestimate ginoptions ));
DESCR("GIN index access method"); DESCR("GIN index access method");
#define GIN_AM_OID 2742 #define GIN_AM_OID 2742
......
...@@ -150,6 +150,7 @@ DESCR(""); ...@@ -150,6 +150,7 @@ DESCR("");
#define RELKIND_COMPOSITE_TYPE 'c' /* composite type */ #define RELKIND_COMPOSITE_TYPE 'c' /* composite type */
#define RELPERSISTENCE_PERMANENT 'p' #define RELPERSISTENCE_PERMANENT 'p'
#define RELPERSISTENCE_UNLOGGED 'u'
#define RELPERSISTENCE_TEMP 't' #define RELPERSISTENCE_TEMP 't'
#endif /* PG_CLASS_H */ #endif /* PG_CLASS_H */
...@@ -689,6 +689,8 @@ DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 1 0 0 f f f t f v 1 0 227 ...@@ -689,6 +689,8 @@ DATA(insert OID = 337 ( btrestrpos PGNSP PGUID 12 1 0 0 f f f t f v 1 0 227
DESCR("btree(internal)"); DESCR("btree(internal)");
DATA(insert OID = 338 ( btbuild PGNSP PGUID 12 1 0 0 f f f t f v 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ btbuild _null_ _null_ _null_ )); DATA(insert OID = 338 ( btbuild PGNSP PGUID 12 1 0 0 f f f t f v 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ btbuild _null_ _null_ _null_ ));
DESCR("btree(internal)"); DESCR("btree(internal)");
DATA(insert OID = 328 ( btbuildempty PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "2281" _null_ _null_ _null_ _null_ btbuildempty _null_ _null_ _null_ ));
DESCR("btree(internal)");
DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 f f f t f v 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ btbulkdelete _null_ _null_ _null_ )); DATA(insert OID = 332 ( btbulkdelete PGNSP PGUID 12 1 0 0 f f f t f v 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ btbulkdelete _null_ _null_ _null_ ));
DESCR("btree(internal)"); DESCR("btree(internal)");
DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ btvacuumcleanup _null_ _null_ _null_ )); DATA(insert OID = 972 ( btvacuumcleanup PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ btvacuumcleanup _null_ _null_ _null_ ));
...@@ -808,6 +810,8 @@ DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 1 0 0 f f f t f v 1 0 22 ...@@ -808,6 +810,8 @@ DATA(insert OID = 447 ( hashrestrpos PGNSP PGUID 12 1 0 0 f f f t f v 1 0 22
DESCR("hash(internal)"); DESCR("hash(internal)");
DATA(insert OID = 448 ( hashbuild PGNSP PGUID 12 1 0 0 f f f t f v 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ hashbuild _null_ _null_ _null_ )); DATA(insert OID = 448 ( hashbuild PGNSP PGUID 12 1 0 0 f f f t f v 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ hashbuild _null_ _null_ _null_ ));
DESCR("hash(internal)"); DESCR("hash(internal)");
DATA(insert OID = 327 ( hashbuildempty PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "2281" _null_ _null_ _null_ _null_ hashbuildempty _null_ _null_ _null_ ));
DESCR("hash(internal)");
DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 f f f t f v 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ hashbulkdelete _null_ _null_ _null_ )); DATA(insert OID = 442 ( hashbulkdelete PGNSP PGUID 12 1 0 0 f f f t f v 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ hashbulkdelete _null_ _null_ _null_ ));
DESCR("hash(internal)"); DESCR("hash(internal)");
DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ )); DATA(insert OID = 425 ( hashvacuumcleanup PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ hashvacuumcleanup _null_ _null_ _null_ ));
...@@ -1104,6 +1108,8 @@ DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 1 0 0 f f f t f v 1 0 22 ...@@ -1104,6 +1108,8 @@ DATA(insert OID = 781 ( gistrestrpos PGNSP PGUID 12 1 0 0 f f f t f v 1 0 22
DESCR("gist(internal)"); DESCR("gist(internal)");
DATA(insert OID = 782 ( gistbuild PGNSP PGUID 12 1 0 0 f f f t f v 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ gistbuild _null_ _null_ _null_ )); DATA(insert OID = 782 ( gistbuild PGNSP PGUID 12 1 0 0 f f f t f v 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ gistbuild _null_ _null_ _null_ ));
DESCR("gist(internal)"); DESCR("gist(internal)");
DATA(insert OID = 326 ( gistbuildempty PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "2281" _null_ _null_ _null_ _null_ gistbuildempty _null_ _null_ _null_ ));
DESCR("gist(internal)");
DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 f f f t f v 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ gistbulkdelete _null_ _null_ _null_ )); DATA(insert OID = 776 ( gistbulkdelete PGNSP PGUID 12 1 0 0 f f f t f v 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ gistbulkdelete _null_ _null_ _null_ ));
DESCR("gist(internal)"); DESCR("gist(internal)");
DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ )); DATA(insert OID = 2561 ( gistvacuumcleanup PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ gistvacuumcleanup _null_ _null_ _null_ ));
...@@ -4353,6 +4359,8 @@ DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 1 0 0 f f f t f v 1 0 22 ...@@ -4353,6 +4359,8 @@ DATA(insert OID = 2737 ( ginrestrpos PGNSP PGUID 12 1 0 0 f f f t f v 1 0 22
DESCR("gin(internal)"); DESCR("gin(internal)");
DATA(insert OID = 2738 ( ginbuild PGNSP PGUID 12 1 0 0 f f f t f v 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ ginbuild _null_ _null_ _null_ )); DATA(insert OID = 2738 ( ginbuild PGNSP PGUID 12 1 0 0 f f f t f v 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ ginbuild _null_ _null_ _null_ ));
DESCR("gin(internal)"); DESCR("gin(internal)");
DATA(insert OID = 325 ( ginbuildempty PGNSP PGUID 12 1 0 0 f f f t f v 1 0 2278 "2281" _null_ _null_ _null_ _null_ ginbuildempty _null_ _null_ _null_ ));
DESCR("gin(internal)");
DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 f f f t f v 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ ginbulkdelete _null_ _null_ _null_ )); DATA(insert OID = 2739 ( ginbulkdelete PGNSP PGUID 12 1 0 0 f f f t f v 4 0 2281 "2281 2281 2281 2281" _null_ _null_ _null_ _null_ ginbulkdelete _null_ _null_ _null_ ));
DESCR("gin(internal)"); DESCR("gin(internal)");
DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ )); DATA(insert OID = 2740 ( ginvacuumcleanup PGNSP PGUID 12 1 0 0 f f f t f v 2 0 2281 "2281 2281" _null_ _null_ _null_ _null_ ginvacuumcleanup _null_ _null_ _null_ ));
......
...@@ -35,6 +35,8 @@ extern void AtSubCommit_smgr(void); ...@@ -35,6 +35,8 @@ extern void AtSubCommit_smgr(void);
extern void AtSubAbort_smgr(void); extern void AtSubAbort_smgr(void);
extern void PostPrepare_smgr(void); extern void PostPrepare_smgr(void);
extern void log_smgrcreate(RelFileNode *rnode, ForkNumber forkNum);
extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record); extern void smgr_redo(XLogRecPtr lsn, XLogRecord *record);
extern void smgr_desc(StringInfo buf, uint8 xl_info, char *rec); extern void smgr_desc(StringInfo buf, uint8 xl_info, char *rec);
......
...@@ -390,6 +390,7 @@ PG_KEYWORD("union", UNION, RESERVED_KEYWORD) ...@@ -390,6 +390,7 @@ PG_KEYWORD("union", UNION, RESERVED_KEYWORD)
PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD) PG_KEYWORD("unique", UNIQUE, RESERVED_KEYWORD)
PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD) PG_KEYWORD("unknown", UNKNOWN, UNRESERVED_KEYWORD)
PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD) PG_KEYWORD("unlisten", UNLISTEN, UNRESERVED_KEYWORD)
PG_KEYWORD("unlogged", UNLOGGED, UNRESERVED_KEYWORD)
PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD) PG_KEYWORD("until", UNTIL, UNRESERVED_KEYWORD)
PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD) PG_KEYWORD("update", UPDATE, UNRESERVED_KEYWORD)
PG_KEYWORD("user", USER, RESERVED_KEYWORD) PG_KEYWORD("user", USER, RESERVED_KEYWORD)
......
...@@ -203,7 +203,7 @@ ...@@ -203,7 +203,7 @@
* Enable debugging print statements for WAL-related operations; see * Enable debugging print statements for WAL-related operations; see
* also the wal_debug GUC var. * also the wal_debug GUC var.
*/ */
/* #define WAL_DEBUG */ #define WAL_DEBUG
/* /*
* Enable tracing of resource consumption during sort operations; * Enable tracing of resource consumption during sort operations;
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#define BM_JUST_DIRTIED (1 << 5) /* dirtied since write started */ #define BM_JUST_DIRTIED (1 << 5) /* dirtied since write started */
#define BM_PIN_COUNT_WAITER (1 << 6) /* have waiter for sole pin */ #define BM_PIN_COUNT_WAITER (1 << 6) /* have waiter for sole pin */
#define BM_CHECKPOINT_NEEDED (1 << 7) /* must write for checkpoint */ #define BM_CHECKPOINT_NEEDED (1 << 7) /* must write for checkpoint */
#define BM_PERMANENT (1 << 8) /* permanent relation (not unlogged) */
typedef bits16 BufFlags; typedef bits16 BufFlags;
......
...@@ -177,13 +177,17 @@ extern void AtEOXact_Buffers(bool isCommit); ...@@ -177,13 +177,17 @@ extern void AtEOXact_Buffers(bool isCommit);
extern void PrintBufferLeakWarning(Buffer buffer); extern void PrintBufferLeakWarning(Buffer buffer);
extern void CheckPointBuffers(int flags); extern void CheckPointBuffers(int flags);
extern BlockNumber BufferGetBlockNumber(Buffer buffer); extern BlockNumber BufferGetBlockNumber(Buffer buffer);
extern BlockNumber RelationGetNumberOfBlocks(Relation relation); extern BlockNumber RelationGetNumberOfBlocksInFork(Relation relation,
ForkNumber forkNum);
extern void FlushRelationBuffers(Relation rel); extern void FlushRelationBuffers(Relation rel);
extern void FlushDatabaseBuffers(Oid dbid); extern void FlushDatabaseBuffers(Oid dbid);
extern void DropRelFileNodeBuffers(RelFileNodeBackend rnode, extern void DropRelFileNodeBuffers(RelFileNodeBackend rnode,
ForkNumber forkNum, BlockNumber firstDelBlock); ForkNumber forkNum, BlockNumber firstDelBlock);
extern void DropDatabaseBuffers(Oid dbid); extern void DropDatabaseBuffers(Oid dbid);
#define RelationGetNumberOfBlocks(reln) \
RelationGetNumberOfBlocksInFork(reln, MAIN_FORKNUM)
#ifdef NOT_USED #ifdef NOT_USED
extern void PrintPinnedBufs(void); extern void PrintPinnedBufs(void);
#endif #endif
......
...@@ -14,5 +14,6 @@ ...@@ -14,5 +14,6 @@
#define COPYDIR_H #define COPYDIR_H
extern void copydir(char *fromdir, char *todir, bool recurse); extern void copydir(char *fromdir, char *todir, bool recurse);
extern void copy_file(char *fromfile, char *tofile);
#endif /* COPYDIR_H */ #endif /* COPYDIR_H */
/*-------------------------------------------------------------------------
*
* reinit.h
* Reinitialization of unlogged relations
*
*
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/include/storage/fd.h
*
*-------------------------------------------------------------------------
*/
#ifndef REINIT_H
#define REINIT_H
extern void ResetUnloggedRelations(int op);
#define UNLOGGED_RELATION_CLEANUP 0x0001
#define UNLOGGED_RELATION_INIT 0x0002
#endif /* REINIT_H */
...@@ -27,7 +27,8 @@ typedef enum ForkNumber ...@@ -27,7 +27,8 @@ typedef enum ForkNumber
InvalidForkNumber = -1, InvalidForkNumber = -1,
MAIN_FORKNUM = 0, MAIN_FORKNUM = 0,
FSM_FORKNUM, FSM_FORKNUM,
VISIBILITYMAP_FORKNUM VISIBILITYMAP_FORKNUM,
INIT_FORKNUM
/* /*
* NOTE: if you add a new fork, change MAX_FORKNUM below and update the * NOTE: if you add a new fork, change MAX_FORKNUM below and update the
...@@ -35,7 +36,7 @@ typedef enum ForkNumber ...@@ -35,7 +36,7 @@ typedef enum ForkNumber
*/ */
} ForkNumber; } ForkNumber;
#define MAX_FORKNUM VISIBILITYMAP_FORKNUM #define MAX_FORKNUM INIT_FORKNUM
/* /*
* RelFileNode must provide all that we need to know to physically access * RelFileNode must provide all that we need to know to physically access
......
...@@ -114,6 +114,7 @@ typedef struct RelationAmInfo ...@@ -114,6 +114,7 @@ typedef struct RelationAmInfo
FmgrInfo ammarkpos; FmgrInfo ammarkpos;
FmgrInfo amrestrpos; FmgrInfo amrestrpos;
FmgrInfo ambuild; FmgrInfo ambuild;
FmgrInfo ambuildempty;
FmgrInfo ambulkdelete; FmgrInfo ambulkdelete;
FmgrInfo amvacuumcleanup; FmgrInfo amvacuumcleanup;
FmgrInfo amcostestimate; FmgrInfo amcostestimate;
......
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