diff options
-rw-r--r-- | doc/src/sgml/ref/alter_sequence.sgml | 12 | ||||
-rw-r--r-- | doc/src/sgml/ref/alter_table.sgml | 6 | ||||
-rw-r--r-- | doc/src/sgml/ref/create_sequence.sgml | 23 | ||||
-rw-r--r-- | doc/src/sgml/ref/create_table.sgml | 5 | ||||
-rw-r--r-- | doc/src/sgml/ref/pg_dump.sgml | 7 | ||||
-rw-r--r-- | src/backend/commands/sequence.c | 58 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 32 | ||||
-rw-r--r-- | src/backend/parser/parse_utilcmd.c | 1 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_dump.c | 15 | ||||
-rw-r--r-- | src/bin/psql/describe.c | 8 | ||||
-rw-r--r-- | src/bin/psql/tab-complete.c | 5 | ||||
-rw-r--r-- | src/include/commands/sequence.h | 1 | ||||
-rw-r--r-- | src/test/recovery/t/014_unlogged_reinit.pl | 61 | ||||
-rw-r--r-- | src/test/regress/expected/alter_table.out | 4 | ||||
-rw-r--r-- | src/test/regress/expected/sequence.out | 20 | ||||
-rw-r--r-- | src/test/regress/sql/sequence.sql | 10 |
16 files changed, 237 insertions, 31 deletions
diff --git a/doc/src/sgml/ref/alter_sequence.sgml b/doc/src/sgml/ref/alter_sequence.sgml index 3cd9ece49f2..148085d4f20 100644 --- a/doc/src/sgml/ref/alter_sequence.sgml +++ b/doc/src/sgml/ref/alter_sequence.sgml @@ -31,6 +31,7 @@ ALTER SEQUENCE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> [ RESTART [ [ WITH ] <replaceable class="parameter">restart</replaceable> ] ] [ CACHE <replaceable class="parameter">cache</replaceable> ] [ [ NO ] CYCLE ] [ OWNED BY { <replaceable class="parameter">table_name</replaceable>.<replaceable class="parameter">column_name</replaceable> | NONE } ] +ALTER SEQUENCE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> SET { LOGGED | UNLOGGED } ALTER SEQUENCE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> OWNER TO { <replaceable class="parameter">new_owner</replaceable> | CURRENT_ROLE | CURRENT_USER | SESSION_USER } ALTER SEQUENCE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> RENAME TO <replaceable class="parameter">new_name</replaceable> ALTER SEQUENCE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> SET SCHEMA <replaceable class="parameter">new_schema</replaceable> @@ -237,6 +238,17 @@ ALTER SEQUENCE [ IF EXISTS ] <replaceable class="parameter">name</replaceable> S </listitem> </varlistentry> + <varlistentry> + <term><literal>SET { LOGGED | UNLOGGED }</literal></term> + <listitem> + <para> + This form changes the sequence from unlogged to logged or vice-versa + (see <xref linkend="sql-createsequence"/>). It cannot be applied to a + temporary sequence. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><literal>OWNED BY</literal> <replaceable class="parameter">table_name</replaceable>.<replaceable class="parameter">column_name</replaceable></term> <term><literal>OWNED BY NONE</literal></term> diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml index e610cbbc0ec..c2a458eb5db 100644 --- a/doc/src/sgml/ref/alter_table.sgml +++ b/doc/src/sgml/ref/alter_table.sgml @@ -753,6 +753,12 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM (see <xref linkend="sql-createtable-unlogged"/>). It cannot be applied to a temporary table. </para> + + <para> + This also changes the persistence of any sequences linked to the table + (for identity or serial columns). However, it is also possible to + change the persistence of such sequences separately. + </para> </listitem> </varlistentry> diff --git a/doc/src/sgml/ref/create_sequence.sgml b/doc/src/sgml/ref/create_sequence.sgml index 20bdbc002fa..a84aa5bf56a 100644 --- a/doc/src/sgml/ref/create_sequence.sgml +++ b/doc/src/sgml/ref/create_sequence.sgml @@ -21,7 +21,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -CREATE [ TEMPORARY | TEMP ] SEQUENCE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> +CREATE [ { TEMPORARY | TEMP } | UNLOGGED ] SEQUENCE [ IF NOT EXISTS ] <replaceable class="parameter">name</replaceable> [ AS <replaceable class="parameter">data_type</replaceable> ] [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ] [ MINVALUE <replaceable class="parameter">minvalue</replaceable> | NO MINVALUE ] [ MAXVALUE <replaceable class="parameter">maxvalue</replaceable> | NO MAXVALUE ] @@ -93,6 +93,27 @@ SELECT * FROM <replaceable>name</replaceable>; </varlistentry> <varlistentry> + <term><literal>UNLOGGED</literal></term> + <listitem> + <para> + If specified, the sequence is created as an unlogged sequence. Changes + to unlogged sequences are not written to the write-ahead log. They are + not crash-safe: an unlogged sequence is automatically reset to its + initial state after a crash or unclean shutdown. Unlogged sequences are + also not replicated to standby servers. + </para> + + <para> + Unlike unlogged tables, unlogged sequences do not offer a significant + performance advantage. This option is mainly intended for sequences + associated with unlogged tables via identity columns or serial columns. + In those cases, it usually wouldn't make sense to have the sequence + WAL-logged and replicated but not its associated table. + </para> + </listitem> + </varlistentry> + + <varlistentry> <term><literal>IF NOT EXISTS</literal></term> <listitem> <para> diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index 7e4ef312c0e..6c9918b0a1e 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -215,6 +215,11 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM Any indexes created on an unlogged table are automatically unlogged as well. </para> + + <para> + If this is specified, any sequences created together with the unlogged + table (for identity or serial columns) are also created as unlogged. + </para> </listitem> </varlistentry> diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index 2f0042fd968..723b2a1a66a 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -981,9 +981,10 @@ PostgreSQL documentation <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. Data in unlogged tables + Do not dump the contents of unlogged tables and sequences. This + option has no effect on whether or not the table and sequence + definitions (schema) are dumped; it only suppresses dumping the table + and sequence data. Data in unlogged tables and sequences is always excluded when dumping from a standby server. </para> </listitem> diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 717bb0b2aa9..47f62c28d42 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -30,6 +30,7 @@ #include "catalog/objectaccess.h" #include "catalog/pg_sequence.h" #include "catalog/pg_type.h" +#include "catalog/storage_xlog.h" #include "commands/defrem.h" #include "commands/sequence.h" #include "commands/tablecmds.h" @@ -95,6 +96,7 @@ static HTAB *seqhashtab = NULL; /* hash table for SeqTable items */ static SeqTableData *last_used_seq = NULL; static void fill_seq_with_data(Relation rel, HeapTuple tuple); +static void fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum); static Relation lock_and_open_sequence(SeqTable seq); static void create_seq_hashtable(void); static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel); @@ -133,12 +135,6 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq) bool pgs_nulls[Natts_pg_sequence]; int i; - /* Unlogged sequences are not implemented -- not clear if useful. */ - if (seq->sequence->relpersistence == RELPERSISTENCE_UNLOGGED) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("unlogged sequences are not supported"))); - /* * If if_not_exists was given and a relation with the same name already * exists, bail out. (Note: we needn't check this when not if_not_exists, @@ -492,10 +488,34 @@ SetSequence(Oid seq_relid, bool transactional, int64 last_value, int64 log_cnt, /* * Initialize a sequence's relation with the specified tuple as content + * + * This handles unlogged sequences by writing to both the main and the init + * fork as necessary. */ static void fill_seq_with_data(Relation rel, HeapTuple tuple) { + fill_seq_fork_with_data(rel, tuple, MAIN_FORKNUM); + + if (rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED) + { + SMgrRelation srel; + + srel = smgropen(rel->rd_node, InvalidBackendId); + smgrcreate(srel, INIT_FORKNUM, false); + log_smgrcreate(&rel->rd_node, INIT_FORKNUM); + fill_seq_fork_with_data(rel, tuple, INIT_FORKNUM); + FlushRelationBuffers(rel); + smgrclose(srel); + } +} + +/* + * Initialize a sequence's relation fork with the specified tuple as content + */ +static void +fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum) +{ Buffer buf; Page page; sequence_magic *sm; @@ -503,7 +523,7 @@ fill_seq_with_data(Relation rel, HeapTuple tuple) /* Initialize first page of relation with special magic number */ - buf = ReadBuffer(rel, P_NEW); + buf = ReadBufferExtended(rel, forkNum, P_NEW, RBM_NORMAL, NULL); Assert(BufferGetBlockNumber(buf) == 0); page = BufferGetPage(buf); @@ -549,7 +569,7 @@ fill_seq_with_data(Relation rel, HeapTuple tuple) elog(ERROR, "failed to add sequence tuple to page"); /* XLOG stuff */ - if (RelationNeedsWAL(rel)) + if (RelationNeedsWAL(rel) || forkNum == INIT_FORKNUM) { xl_seq_rec xlrec; XLogRecPtr recptr; @@ -683,6 +703,28 @@ AlterSequence(ParseState *pstate, AlterSeqStmt *stmt) } void +SequenceChangePersistence(Oid relid, char newrelpersistence) +{ + SeqTable elm; + Relation seqrel; + Buffer buf; + HeapTupleData seqdatatuple; + + init_sequence(relid, &elm, &seqrel); + + /* check the comment above nextval_internal()'s equivalent call. */ + if (RelationNeedsWAL(seqrel)) + GetTopTransactionId(); + + (void) read_seq_tuple(seqrel, &buf, &seqdatatuple); + RelationSetNewRelfilenode(seqrel, newrelpersistence); + fill_seq_with_data(seqrel, &seqdatatuple); + UnlockReleaseBuffer(buf); + + relation_close(seqrel, NoLock); +} + +void DeleteSequenceTuple(Oid relid) { Relation rel; diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index a241b444975..4dd545cdd20 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -319,6 +319,7 @@ struct DropRelationCallbackState #define ATT_COMPOSITE_TYPE 0x0010 #define ATT_FOREIGN_TABLE 0x0020 #define ATT_PARTITIONED_INDEX 0x0040 +#define ATT_SEQUENCE 0x0080 /* * ForeignTruncateInfo @@ -4660,7 +4661,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_MISC; break; case AT_SetLogged: /* SET LOGGED */ - ATSimplePermissions(cmd->subtype, rel, ATT_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_SEQUENCE); if (tab->chgPersistence) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -4675,7 +4676,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, pass = AT_PASS_MISC; break; case AT_SetUnLogged: /* SET UNLOGGED */ - ATSimplePermissions(cmd->subtype, rel, ATT_TABLE); + ATSimplePermissions(cmd->subtype, rel, ATT_TABLE | ATT_SEQUENCE); if (tab->chgPersistence) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), @@ -5425,7 +5426,7 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, * and assigns a new relfilenode, we automatically create or drop an * init fork for the relation as appropriate. */ - if (tab->rewrite > 0) + if (tab->rewrite > 0 && tab->relkind != RELKIND_SEQUENCE) { /* Build a temporary relation and copy data */ Relation OldHeap; @@ -5546,6 +5547,11 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, InvokeObjectPostAlterHook(RelationRelationId, tab->relid, 0); } + else if (tab->rewrite > 0 && tab->relkind == RELKIND_SEQUENCE) + { + if (tab->chgPersistence) + SequenceChangePersistence(tab->relid, tab->newrelpersistence); + } else { /* @@ -5564,6 +5570,23 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode, if (tab->newTableSpace) ATExecSetTableSpace(tab->relid, tab->newTableSpace, lockmode); } + + /* + * Also change persistence of owned sequences, so that it matches the + * table persistence. + */ + if (tab->chgPersistence) + { + List *seqlist = getOwnedSequences(tab->relid); + ListCell *lc; + + foreach(lc, seqlist) + { + Oid seq_relid = lfirst_oid(lc); + + SequenceChangePersistence(seq_relid, tab->newrelpersistence); + } + } } /* @@ -6224,6 +6247,9 @@ ATSimplePermissions(AlterTableType cmdtype, Relation rel, int allowed_targets) case RELKIND_FOREIGN_TABLE: actual_target = ATT_FOREIGN_TABLE; break; + case RELKIND_SEQUENCE: + actual_target = ATT_SEQUENCE; + break; default: actual_target = 0; break; diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index cd946c76921..2826559d09b 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -445,6 +445,7 @@ generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column, seqstmt = makeNode(CreateSeqStmt); seqstmt->for_identity = for_identity; seqstmt->sequence = makeRangeVar(snamespace, sname, -1); + seqstmt->sequence->relpersistence = cxt->relation->relpersistence; seqstmt->options = seqoptions; /* diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 535b1601655..3c2201a725f 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -16570,6 +16570,7 @@ dumpSequence(Archive *fout, const TableInfo *tbinfo) PQExpBuffer query = createPQExpBuffer(); PQExpBuffer delqry = createPQExpBuffer(); char *qseqname; + TableInfo *owning_tab = NULL; qseqname = pg_strdup(fmtId(tbinfo->dobj.name)); @@ -16678,7 +16679,7 @@ dumpSequence(Archive *fout, const TableInfo *tbinfo) if (tbinfo->is_identity_sequence) { - TableInfo *owning_tab = findTableByOid(tbinfo->owning_tab); + owning_tab = findTableByOid(tbinfo->owning_tab); appendPQExpBuffer(query, "ALTER TABLE %s ", @@ -16696,7 +16697,9 @@ dumpSequence(Archive *fout, const TableInfo *tbinfo) else { appendPQExpBuffer(query, - "CREATE SEQUENCE %s\n", + "CREATE %sSEQUENCE %s\n", + tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ? + "UNLOGGED " : "", fmtQualifiedDumpable(tbinfo)); if (strcmp(seqtype, "bigint") != 0) @@ -16722,7 +16725,15 @@ dumpSequence(Archive *fout, const TableInfo *tbinfo) cache, (cycled ? "\n CYCLE" : "")); if (tbinfo->is_identity_sequence) + { appendPQExpBufferStr(query, "\n);\n"); + if (tbinfo->relpersistence != owning_tab->relpersistence) + appendPQExpBuffer(query, + "ALTER SEQUENCE %s SET %s;\n", + fmtQualifiedDumpable(tbinfo), + tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ? + "UNLOGGED" : "LOGGED"); + } else appendPQExpBufferStr(query, ";\n"); diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index 4dddf087893..73bbbe2eb40 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -1681,8 +1681,12 @@ describeOneTableDetails(const char *schemaname, printTableInit(&cont, &myopt, title.data, 7, numrows); printTableInitialized = true; - printfPQExpBuffer(&title, _("Sequence \"%s.%s\""), - schemaname, relationname); + if (tableinfo.relpersistence == 'u') + printfPQExpBuffer(&title, _("Unlogged sequence \"%s.%s\""), + schemaname, relationname); + else + printfPQExpBuffer(&title, _("Sequence \"%s.%s\""), + schemaname, relationname); printTableAddHeader(&cont, gettext_noop("Type"), true, 'l'); printTableAddHeader(&cont, gettext_noop("Start"), true, 'r'); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 32d0b4855f5..025d3f71a11 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -2116,7 +2116,7 @@ psql_completion(const char *text, int start, int end) /* ALTER SEQUENCE <name> */ else if (Matches("ALTER", "SEQUENCE", MatchAny)) COMPLETE_WITH("AS", "INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", - "NO", "CACHE", "CYCLE", "SET SCHEMA", "OWNED BY", + "NO", "CACHE", "CYCLE", "SET", "OWNED BY", "OWNER TO", "RENAME TO"); /* ALTER SEQUENCE <name> AS */ else if (TailMatches("ALTER", "SEQUENCE", MatchAny, "AS")) @@ -2124,6 +2124,9 @@ psql_completion(const char *text, int start, int end) /* ALTER SEQUENCE <name> NO */ else if (Matches("ALTER", "SEQUENCE", MatchAny, "NO")) COMPLETE_WITH("MINVALUE", "MAXVALUE", "CYCLE"); + /* ALTER SEQUENCE <name> SET */ + else if (Matches("ALTER", "SEQUENCE", MatchAny, "SET")) + COMPLETE_WITH("SCHEMA", "LOGGED", "UNLOGGED"); /* ALTER SERVER <name> */ else if (Matches("ALTER", "SERVER", MatchAny)) COMPLETE_WITH("VERSION", "OPTIONS", "OWNER TO", "RENAME TO"); diff --git a/src/include/commands/sequence.h b/src/include/commands/sequence.h index 5bab90db8e0..f2381982d5d 100644 --- a/src/include/commands/sequence.h +++ b/src/include/commands/sequence.h @@ -58,6 +58,7 @@ extern List *sequence_options(Oid relid); extern ObjectAddress DefineSequence(ParseState *pstate, CreateSeqStmt *stmt); extern ObjectAddress AlterSequence(ParseState *pstate, AlterSeqStmt *stmt); +extern void SequenceChangePersistence(Oid relid, char newrelpersistence); extern void DeleteSequenceTuple(Oid relid); extern void ResetSequence(Oid seq_relid); extern void SetSequence(Oid seq_relid, bool transactional, int64 last_value, int64 log_cnt, bool is_called); diff --git a/src/test/recovery/t/014_unlogged_reinit.pl b/src/test/recovery/t/014_unlogged_reinit.pl index f3199fbd2e1..0dca3f69fe3 100644 --- a/src/test/recovery/t/014_unlogged_reinit.pl +++ b/src/test/recovery/t/014_unlogged_reinit.pl @@ -18,16 +18,27 @@ $node->init; $node->start; my $pgdata = $node->data_dir; -# Create an unlogged table to test that forks other than init are not -# copied. +# Create an unlogged table and an unlogged sequence to test that forks +# other than init are not copied. $node->safe_psql('postgres', 'CREATE UNLOGGED TABLE base_unlogged (id int)'); +$node->safe_psql('postgres', 'CREATE UNLOGGED SEQUENCE seq_unlogged'); my $baseUnloggedPath = $node->safe_psql('postgres', q{select pg_relation_filepath('base_unlogged')}); +my $seqUnloggedPath = $node->safe_psql('postgres', + q{select pg_relation_filepath('seq_unlogged')}); # Test that main and init forks exist. -ok(-f "$pgdata/${baseUnloggedPath}_init", 'init fork in base exists'); -ok(-f "$pgdata/$baseUnloggedPath", 'main fork in base exists'); +ok(-f "$pgdata/${baseUnloggedPath}_init", 'table init fork exists'); +ok(-f "$pgdata/$baseUnloggedPath", 'table main fork exists'); +ok(-f "$pgdata/${seqUnloggedPath}_init", 'sequence init fork exists'); +ok(-f "$pgdata/$seqUnloggedPath", 'sequence main fork exists'); + +# Test the sequence +is($node->safe_psql('postgres', "SELECT nextval('seq_unlogged')"), + 1, 'sequence nextval'); +is($node->safe_psql('postgres', "SELECT nextval('seq_unlogged')"), + 2, 'sequence nextval again'); # Create an unlogged table in a tablespace. @@ -44,6 +55,19 @@ my $ts1UnloggedPath = $node->safe_psql('postgres', ok(-f "$pgdata/${ts1UnloggedPath}_init", 'init fork in tablespace exists'); ok(-f "$pgdata/$ts1UnloggedPath", 'main fork in tablespace exists'); +# Create more unlogged sequences for testing. +$node->safe_psql('postgres', 'CREATE UNLOGGED SEQUENCE seq_unlogged2'); +# This rewrites the sequence relation in AlterSequence(). +$node->safe_psql('postgres', 'ALTER SEQUENCE seq_unlogged2 INCREMENT 2'); +$node->safe_psql('postgres', "SELECT nextval('seq_unlogged2')"); + +$node->safe_psql('postgres', + 'CREATE UNLOGGED TABLE tab_seq_unlogged3 (a int GENERATED ALWAYS AS IDENTITY)' +); +# This rewrites the sequence relation in ResetSequence(). +$node->safe_psql('postgres', 'TRUNCATE tab_seq_unlogged3 RESTART IDENTITY'); +$node->safe_psql('postgres', 'INSERT INTO tab_seq_unlogged3 DEFAULT VALUES'); + # Crash the postmaster. $node->stop('immediate'); @@ -54,6 +78,8 @@ append_to_file("$pgdata/${baseUnloggedPath}_fsm", 'TEST_FSM'); # Remove main fork to test that it is recopied from init. unlink("$pgdata/${baseUnloggedPath}") or BAIL_OUT("could not remove \"${baseUnloggedPath}\": $!"); +unlink("$pgdata/${seqUnloggedPath}") + or BAIL_OUT("could not remove \"${seqUnloggedPath}\": $!"); # the same for the tablespace append_to_file("$pgdata/${ts1UnloggedPath}_vm", 'TEST_VM'); @@ -64,13 +90,25 @@ unlink("$pgdata/${ts1UnloggedPath}") $node->start; # check unlogged table in base -ok(-f "$pgdata/${baseUnloggedPath}_init", 'init fork in base still exists'); -ok(-f "$pgdata/$baseUnloggedPath", 'main fork in base recreated at startup'); +ok( -f "$pgdata/${baseUnloggedPath}_init", + 'table init fork in base still exists'); +ok(-f "$pgdata/$baseUnloggedPath", + 'table main fork in base recreated at startup'); ok(!-f "$pgdata/${baseUnloggedPath}_vm", 'vm fork in base removed at startup'); ok( !-f "$pgdata/${baseUnloggedPath}_fsm", 'fsm fork in base removed at startup'); +# check unlogged sequence +ok(-f "$pgdata/${seqUnloggedPath}_init", 'sequence init fork still exists'); +ok(-f "$pgdata/$seqUnloggedPath", 'sequence main fork recreated at startup'); + +# Test the sequence after restart +is($node->safe_psql('postgres', "SELECT nextval('seq_unlogged')"), + 1, 'sequence nextval after restart'); +is($node->safe_psql('postgres', "SELECT nextval('seq_unlogged')"), + 2, 'sequence nextval after restart again'); + # check unlogged table in tablespace ok( -f "$pgdata/${ts1UnloggedPath}_init", 'init fork still exists in tablespace'); @@ -81,4 +119,15 @@ ok( !-f "$pgdata/${ts1UnloggedPath}_vm", ok( !-f "$pgdata/${ts1UnloggedPath}_fsm", 'fsm fork in tablespace removed at startup'); +# Test other sequences +is($node->safe_psql('postgres', "SELECT nextval('seq_unlogged2')"), + 1, 'altered sequence nextval after restart'); +is($node->safe_psql('postgres', "SELECT nextval('seq_unlogged2')"), + 3, 'altered sequence nextval after restart again'); + +$node->safe_psql('postgres', + "INSERT INTO tab_seq_unlogged3 VALUES (DEFAULT), (DEFAULT)"); +is($node->safe_psql('postgres', "SELECT * FROM tab_seq_unlogged3"), + "1\n2", 'reset sequence nextval after restart'); + done_testing(); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 07473dd6600..5ede56d9b55 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3461,7 +3461,7 @@ ORDER BY relname; unlogged1 | r | u unlogged1 toast index | i | u unlogged1 toast table | t | u - unlogged1_f1_seq | S | p + unlogged1_f1_seq | S | u unlogged1_pkey | i | u (5 rows) @@ -3528,7 +3528,7 @@ ORDER BY relname; logged1 | r | u logged1 toast index | i | u logged1 toast table | t | u - logged1_f1_seq | S | p + logged1_f1_seq | S | u logged1_pkey | i | u (5 rows) diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out index 71c2b0f1dff..7cb2f7cc02b 100644 --- a/src/test/regress/expected/sequence.out +++ b/src/test/regress/expected/sequence.out @@ -2,8 +2,6 @@ -- CREATE SEQUENCE -- -- various error cases -CREATE UNLOGGED SEQUENCE sequence_testx; -ERROR: unlogged sequences are not supported CREATE SEQUENCE sequence_testx INCREMENT BY 0; ERROR: INCREMENT must not be zero CREATE SEQUENCE sequence_testx INCREMENT BY -1 MINVALUE 20; @@ -600,6 +598,24 @@ DROP SEQUENCE seq2; -- should fail SELECT lastval(); ERROR: lastval is not yet defined in this session +-- unlogged sequences +-- (more tests in src/test/recovery/) +CREATE UNLOGGED SEQUENCE sequence_test_unlogged; +ALTER SEQUENCE sequence_test_unlogged SET LOGGED; +\d sequence_test_unlogged + Sequence "public.sequence_test_unlogged" + Type | Start | Minimum | Maximum | Increment | Cycles? | Cache +--------+-------+---------+---------------------+-----------+---------+------- + bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1 + +ALTER SEQUENCE sequence_test_unlogged SET UNLOGGED; +\d sequence_test_unlogged + Unlogged sequence "public.sequence_test_unlogged" + Type | Start | Minimum | Maximum | Increment | Cycles? | Cache +--------+-------+---------+---------------------+-----------+---------+------- + bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1 + +DROP SEQUENCE sequence_test_unlogged; -- Test sequences in read-only transactions CREATE TEMPORARY SEQUENCE sequence_test_temp1; START TRANSACTION READ ONLY; diff --git a/src/test/regress/sql/sequence.sql b/src/test/regress/sql/sequence.sql index 7928ee23ee8..674f5f1f668 100644 --- a/src/test/regress/sql/sequence.sql +++ b/src/test/regress/sql/sequence.sql @@ -3,7 +3,6 @@ -- -- various error cases -CREATE UNLOGGED SEQUENCE sequence_testx; CREATE SEQUENCE sequence_testx INCREMENT BY 0; CREATE SEQUENCE sequence_testx INCREMENT BY -1 MINVALUE 20; CREATE SEQUENCE sequence_testx INCREMENT BY 1 MAXVALUE -20; @@ -272,6 +271,15 @@ DROP SEQUENCE seq2; -- should fail SELECT lastval(); +-- unlogged sequences +-- (more tests in src/test/recovery/) +CREATE UNLOGGED SEQUENCE sequence_test_unlogged; +ALTER SEQUENCE sequence_test_unlogged SET LOGGED; +\d sequence_test_unlogged +ALTER SEQUENCE sequence_test_unlogged SET UNLOGGED; +\d sequence_test_unlogged +DROP SEQUENCE sequence_test_unlogged; + -- Test sequences in read-only transactions CREATE TEMPORARY SEQUENCE sequence_test_temp1; START TRANSACTION READ ONLY; |