Adds support for unlogged distributed sequences (#6292)

We can now do the following:
- Distribute sequence with logged/unlogged option
- ALTER TABLE my_sequence SET LOGGED/UNLOGGED
- ALTER SEQUENCE my_sequence SET LOGGED/UNLOGGED

Relevant PG commit
344d62fb9a
pull/6322/head
Naisila Puka 2022-09-13 10:53:39 +03:00 committed by GitHub
parent 5cfcc63308
commit 76ff4ab188
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 641 additions and 10 deletions

View File

@ -734,6 +734,17 @@ static DistributeObjectOps Sequence_AlterOwner = {
.address = AlterSequenceOwnerStmtObjectAddress, .address = AlterSequenceOwnerStmtObjectAddress,
.markDistributed = false, .markDistributed = false,
}; };
#if (PG_VERSION_NUM >= PG_VERSION_15)
static DistributeObjectOps Sequence_AlterPersistence = {
.deparse = DeparseAlterSequencePersistenceStmt,
.qualify = QualifyAlterSequencePersistenceStmt,
.preprocess = PreprocessAlterSequencePersistenceStmt,
.postprocess = NULL,
.operationType = DIST_OPS_ALTER,
.address = AlterSequencePersistenceStmtObjectAddress,
.markDistributed = false,
};
#endif
static DistributeObjectOps Sequence_Drop = { static DistributeObjectOps Sequence_Drop = {
.deparse = DeparseDropSequenceStmt, .deparse = DeparseDropSequenceStmt,
.qualify = QualifyDropSequenceStmt, .qualify = QualifyDropSequenceStmt,
@ -1463,6 +1474,41 @@ GetDistributeObjectOps(Node *node)
case OBJECT_SEQUENCE: case OBJECT_SEQUENCE:
{ {
#if (PG_VERSION_NUM >= PG_VERSION_15)
ListCell *cmdCell = NULL;
foreach(cmdCell, stmt->cmds)
{
AlterTableCmd *cmd = castNode(AlterTableCmd, lfirst(cmdCell));
switch (cmd->subtype)
{
case AT_ChangeOwner:
{
return &Sequence_AlterOwner;
}
case AT_SetLogged:
{
return &Sequence_AlterPersistence;
}
case AT_SetUnLogged:
{
return &Sequence_AlterPersistence;
}
default:
{
return &NoDistributeOps;
}
}
}
#endif
/*
* Prior to PG15, the only Alter Table statement
* with Sequence as its object was an
* Alter Owner statement
*/
return &Sequence_AlterOwner; return &Sequence_AlterOwner;
} }

View File

@ -712,6 +712,121 @@ PostprocessAlterSequenceOwnerStmt(Node *node, const char *queryString)
} }
#if (PG_VERSION_NUM >= PG_VERSION_15)
/*
* PreprocessAlterSequencePersistenceStmt is called for change of persistence
* of sequences before the persistence is changed on the local instance.
*
* If the sequence for which the persistence is changed is distributed, we execute
* the change on all the workers to keep the type in sync across the cluster.
*/
List *
PreprocessAlterSequencePersistenceStmt(Node *node, const char *queryString,
ProcessUtilityContext processUtilityContext)
{
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
Assert(AlterTableStmtObjType_compat(stmt) == OBJECT_SEQUENCE);
List *sequenceAddresses = GetObjectAddressListFromParseTree((Node *) stmt, false,
false);
/* the code-path only supports a single object */
Assert(list_length(sequenceAddresses) == 1);
if (!ShouldPropagateAnyObject(sequenceAddresses))
{
return NIL;
}
EnsureCoordinator();
QualifyTreeNode((Node *) stmt);
const char *sql = DeparseTreeNode((Node *) stmt);
List *commands = list_make3(DISABLE_DDL_PROPAGATION, (void *) sql,
ENABLE_DDL_PROPAGATION);
return NodeDDLTaskList(NON_COORDINATOR_METADATA_NODES, commands);
}
/*
* AlterSequencePersistenceStmtObjectAddress returns the ObjectAddress of the
* sequence that is the subject of the AlterPersistenceStmt.
*/
List *
AlterSequencePersistenceStmtObjectAddress(Node *node, bool missing_ok, bool isPostprocess)
{
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
Assert(AlterTableStmtObjType_compat(stmt) == OBJECT_SEQUENCE);
RangeVar *sequence = stmt->relation;
Oid seqOid = RangeVarGetRelid(sequence, NoLock, missing_ok);
ObjectAddress *sequenceAddress = palloc0(sizeof(ObjectAddress));
ObjectAddressSet(*sequenceAddress, RelationRelationId, seqOid);
return list_make1(sequenceAddress);
}
/*
* PreprocessSequenceAlterTableStmt is called for change of persistence or owner
* of sequences before the persistence/owner is changed on the local instance.
*
* Altering persistence or owner are the only ALTER commands of a sequence
* that may pass through an AlterTableStmt as well
*/
List *
PreprocessSequenceAlterTableStmt(Node *node, const char *queryString,
ProcessUtilityContext processUtilityContext)
{
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
Assert(AlterTableStmtObjType_compat(stmt) == OBJECT_SEQUENCE);
ListCell *cmdCell = NULL;
foreach(cmdCell, stmt->cmds)
{
AlterTableCmd *cmd = castNode(AlterTableCmd, lfirst(cmdCell));
switch (cmd->subtype)
{
case AT_ChangeOwner:
{
return PreprocessAlterSequenceOwnerStmt(node,
queryString,
processUtilityContext);
}
case AT_SetLogged:
{
return PreprocessAlterSequencePersistenceStmt(node,
queryString,
processUtilityContext);
}
case AT_SetUnLogged:
{
return PreprocessAlterSequencePersistenceStmt(node,
queryString,
processUtilityContext);
}
default:
{
/* normally we shouldn't ever reach this */
ereport(ERROR, (errmsg("unsupported subtype for alter sequence command"),
errdetail("sub command type: %d",
cmd->subtype)));
}
}
}
return NIL;
}
#endif
/* /*
* PreprocessGrantOnSequenceStmt is executed before the statement is applied to the local * PreprocessGrantOnSequenceStmt is executed before the statement is applied to the local
* postgres instance. * postgres instance.

View File

@ -733,20 +733,40 @@ PreprocessAlterTableStmt(Node *node, const char *alterTableCommand,
/* /*
* check whether we are dealing with a sequence or view here * check whether we are dealing with a sequence or view here
* if yes, it must be ALTER TABLE .. OWNER TO .. command
* since this is the only ALTER command of a sequence or view that
* passes through an AlterTableStmt
*/ */
char relKind = get_rel_relkind(leftRelationId); char relKind = get_rel_relkind(leftRelationId);
if (relKind == RELKIND_SEQUENCE) if (relKind == RELKIND_SEQUENCE)
{ {
AlterTableStmt *stmtCopy = copyObject(alterTableStatement); AlterTableStmt *stmtCopy = copyObject(alterTableStatement);
AlterTableStmtObjType_compat(stmtCopy) = OBJECT_SEQUENCE; AlterTableStmtObjType_compat(stmtCopy) = OBJECT_SEQUENCE;
#if (PG_VERSION_NUM >= PG_VERSION_15)
/*
* it must be ALTER TABLE .. OWNER TO ..
* or ALTER TABLE .. SET LOGGED/UNLOGGED command
* since these are the only ALTER commands of a sequence that
* pass through an AlterTableStmt
*/
return PreprocessSequenceAlterTableStmt((Node *) stmtCopy, alterTableCommand,
processUtilityContext);
#else
/*
* it must be ALTER TABLE .. OWNER TO .. command
* since this is the only ALTER command of a sequence that
* passes through an AlterTableStmt
*/
return PreprocessAlterSequenceOwnerStmt((Node *) stmtCopy, alterTableCommand, return PreprocessAlterSequenceOwnerStmt((Node *) stmtCopy, alterTableCommand,
processUtilityContext); processUtilityContext);
#endif
} }
else if (relKind == RELKIND_VIEW) else if (relKind == RELKIND_VIEW)
{ {
/*
* it must be ALTER TABLE .. OWNER TO .. command
* since this is the only ALTER command of a view that
* passes through an AlterTableStmt
*/
AlterTableStmt *stmtCopy = copyObject(alterTableStatement); AlterTableStmt *stmtCopy = copyObject(alterTableStatement);
AlterTableStmtObjType_compat(stmtCopy) = OBJECT_VIEW; AlterTableStmtObjType_compat(stmtCopy) = OBJECT_VIEW;
return PreprocessAlterViewStmt((Node *) stmtCopy, alterTableCommand, return PreprocessAlterViewStmt((Node *) stmtCopy, alterTableCommand,

View File

@ -256,7 +256,12 @@ pg_get_sequencedef_string(Oid sequenceRelationId)
char *qualifiedSequenceName = generate_qualified_relation_name(sequenceRelationId); char *qualifiedSequenceName = generate_qualified_relation_name(sequenceRelationId);
char *typeName = format_type_be(pgSequenceForm->seqtypid); char *typeName = format_type_be(pgSequenceForm->seqtypid);
char *sequenceDef = psprintf(CREATE_SEQUENCE_COMMAND, qualifiedSequenceName, char *sequenceDef = psprintf(CREATE_SEQUENCE_COMMAND,
#if (PG_VERSION_NUM >= PG_VERSION_15)
get_rel_persistence(sequenceRelationId) ==
RELPERSISTENCE_UNLOGGED ? "UNLOGGED " : "",
#endif
qualifiedSequenceName,
typeName, typeName,
pgSequenceForm->seqincrement, pgSequenceForm->seqmin, pgSequenceForm->seqincrement, pgSequenceForm->seqmin,
pgSequenceForm->seqmax, pgSequenceForm->seqstart, pgSequenceForm->seqmax, pgSequenceForm->seqstart,

View File

@ -27,6 +27,9 @@ static void AppendSequenceNameList(StringInfo buf, List *objects, ObjectType obj
static void AppendRenameSequenceStmt(StringInfo buf, RenameStmt *stmt); static void AppendRenameSequenceStmt(StringInfo buf, RenameStmt *stmt);
static void AppendAlterSequenceSchemaStmt(StringInfo buf, AlterObjectSchemaStmt *stmt); static void AppendAlterSequenceSchemaStmt(StringInfo buf, AlterObjectSchemaStmt *stmt);
static void AppendAlterSequenceOwnerStmt(StringInfo buf, AlterTableStmt *stmt); static void AppendAlterSequenceOwnerStmt(StringInfo buf, AlterTableStmt *stmt);
#if (PG_VERSION_NUM >= PG_VERSION_15)
static void AppendAlterSequencePersistenceStmt(StringInfo buf, AlterTableStmt *stmt);
#endif
static void AppendGrantOnSequenceStmt(StringInfo buf, GrantStmt *stmt); static void AppendGrantOnSequenceStmt(StringInfo buf, GrantStmt *stmt);
static void AppendGrantOnSequenceSequences(StringInfo buf, GrantStmt *stmt); static void AppendGrantOnSequenceSequences(StringInfo buf, GrantStmt *stmt);
@ -258,6 +261,96 @@ AppendAlterSequenceOwnerStmt(StringInfo buf, AlterTableStmt *stmt)
} }
#if (PG_VERSION_NUM >= PG_VERSION_15)
/*
* DeparseAlterSequencePersistenceStmt builds and returns a string representing
* the AlterTableStmt consisting of changing the persistence of a sequence
*/
char *
DeparseAlterSequencePersistenceStmt(Node *node)
{
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
StringInfoData str = { 0 };
initStringInfo(&str);
Assert(AlterTableStmtObjType_compat(stmt) == OBJECT_SEQUENCE);
AppendAlterSequencePersistenceStmt(&str, stmt);
return str.data;
}
/*
* AppendAlterSequencePersistenceStmt appends a string representing the
* AlterTableStmt to a buffer consisting of changing the persistence of a sequence
*/
static void
AppendAlterSequencePersistenceStmt(StringInfo buf, AlterTableStmt *stmt)
{
Assert(AlterTableStmtObjType_compat(stmt) == OBJECT_SEQUENCE);
RangeVar *seq = stmt->relation;
char *qualifiedSequenceName = quote_qualified_identifier(seq->schemaname,
seq->relname);
appendStringInfoString(buf, "ALTER SEQUENCE ");
if (stmt->missing_ok)
{
appendStringInfoString(buf, "IF EXISTS ");
}
appendStringInfoString(buf, qualifiedSequenceName);
ListCell *cmdCell = NULL;
foreach(cmdCell, stmt->cmds)
{
if (cmdCell != list_head(stmt->cmds))
{
/*
* As of PG15, we cannot reach this code because ALTER SEQUENCE
* is only supported for a single sequence. Still, let's be
* defensive for future PG changes
*/
ereport(ERROR, (errmsg("More than one subcommand is not supported "
"for ALTER SEQUENCE")));
}
AlterTableCmd *alterTableCmd = castNode(AlterTableCmd, lfirst(cmdCell));
switch (alterTableCmd->subtype)
{
case AT_SetLogged:
{
appendStringInfoString(buf, " SET LOGGED;");
break;
}
case AT_SetUnLogged:
{
appendStringInfoString(buf, " SET UNLOGGED;");
break;
}
default:
{
/*
* normally we shouldn't ever reach this
* because we enter this function after making sure this stmt is of the form
* ALTER SEQUENCE .. SET LOGGED/UNLOGGED
*/
ereport(ERROR, (errmsg("unsupported subtype for alter sequence command"),
errdetail("sub command type: %d",
alterTableCmd->subtype)));
}
}
}
}
#endif
/* /*
* DeparseGrantOnSequenceStmt builds and returns a string representing the GrantOnSequenceStmt * DeparseGrantOnSequenceStmt builds and returns a string representing the GrantOnSequenceStmt
*/ */

View File

@ -51,6 +51,37 @@ QualifyAlterSequenceOwnerStmt(Node *node)
} }
#if (PG_VERSION_NUM >= PG_VERSION_15)
/*
* QualifyAlterSequencePersistenceStmt transforms a
* ALTER SEQUENCE .. SET LOGGED/UNLOGGED
* statement in place and makes the sequence name fully qualified.
*/
void
QualifyAlterSequencePersistenceStmt(Node *node)
{
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
Assert(AlterTableStmtObjType_compat(stmt) == OBJECT_SEQUENCE);
RangeVar *seq = stmt->relation;
if (seq->schemaname == NULL)
{
Oid seqOid = RangeVarGetRelid(seq, NoLock, stmt->missing_ok);
if (OidIsValid(seqOid))
{
Oid schemaOid = get_rel_namespace(seqOid);
seq->schemaname = get_namespace_name(schemaOid);
}
}
}
#endif
/* /*
* QualifyAlterSequenceSchemaStmt transforms a * QualifyAlterSequenceSchemaStmt transforms a
* ALTER SEQUENCE .. SET SCHEMA .. * ALTER SEQUENCE .. SET SCHEMA ..

View File

@ -20,12 +20,6 @@
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#define CREATE_SEQUENCE_COMMAND \
"CREATE SEQUENCE IF NOT EXISTS %s AS %s INCREMENT BY " INT64_FORMAT \
" MINVALUE " INT64_FORMAT " MAXVALUE " INT64_FORMAT \
" START WITH " INT64_FORMAT " CACHE " INT64_FORMAT " %sCYCLE"
/* Function declarations for version independent Citus ruleutils wrapper functions */ /* Function declarations for version independent Citus ruleutils wrapper functions */
extern char * pg_get_extensiondef_string(Oid tableRelationId); extern char * pg_get_extensiondef_string(Oid tableRelationId);
extern Oid get_extension_schema(Oid ext_oid); extern Oid get_extension_schema(Oid ext_oid);

View File

@ -459,6 +459,13 @@ extern List * PostprocessAlterSequenceSchemaStmt(Node *node, const char *querySt
extern List * PreprocessAlterSequenceOwnerStmt(Node *node, const char *queryString, extern List * PreprocessAlterSequenceOwnerStmt(Node *node, const char *queryString,
ProcessUtilityContext processUtilityContext); ProcessUtilityContext processUtilityContext);
extern List * PostprocessAlterSequenceOwnerStmt(Node *node, const char *queryString); extern List * PostprocessAlterSequenceOwnerStmt(Node *node, const char *queryString);
#if (PG_VERSION_NUM >= PG_VERSION_15)
extern List * PreprocessAlterSequencePersistenceStmt(Node *node, const char *queryString,
ProcessUtilityContext
processUtilityContext);
extern List * PreprocessSequenceAlterTableStmt(Node *node, const char *queryString,
ProcessUtilityContext processUtilityContext);
#endif
extern List * PreprocessDropSequenceStmt(Node *node, const char *queryString, extern List * PreprocessDropSequenceStmt(Node *node, const char *queryString,
ProcessUtilityContext processUtilityContext); ProcessUtilityContext processUtilityContext);
extern List * SequenceDropStmtObjectAddress(Node *stmt, bool missing_ok, bool extern List * SequenceDropStmtObjectAddress(Node *stmt, bool missing_ok, bool
@ -474,6 +481,10 @@ extern List * AlterSequenceSchemaStmtObjectAddress(Node *node, bool missing_ok,
isPostprocess); isPostprocess);
extern List * AlterSequenceOwnerStmtObjectAddress(Node *node, bool missing_ok, bool extern List * AlterSequenceOwnerStmtObjectAddress(Node *node, bool missing_ok, bool
isPostprocess); isPostprocess);
#if (PG_VERSION_NUM >= PG_VERSION_15)
extern List * AlterSequencePersistenceStmtObjectAddress(Node *node, bool missing_ok, bool
isPostprocess);
#endif
extern List * RenameSequenceStmtObjectAddress(Node *node, bool missing_ok, bool extern List * RenameSequenceStmtObjectAddress(Node *node, bool missing_ok, bool
isPostprocess); isPostprocess);
extern void ErrorIfUnsupportedSeqStmt(CreateSeqStmt *createSeqStmt); extern void ErrorIfUnsupportedSeqStmt(CreateSeqStmt *createSeqStmt);

View File

@ -226,6 +226,9 @@ extern char * DeparseDropSequenceStmt(Node *node);
extern char * DeparseRenameSequenceStmt(Node *node); extern char * DeparseRenameSequenceStmt(Node *node);
extern char * DeparseAlterSequenceSchemaStmt(Node *node); extern char * DeparseAlterSequenceSchemaStmt(Node *node);
extern char * DeparseAlterSequenceOwnerStmt(Node *node); extern char * DeparseAlterSequenceOwnerStmt(Node *node);
#if (PG_VERSION_NUM >= PG_VERSION_15)
extern char * DeparseAlterSequencePersistenceStmt(Node *node);
#endif
extern char * DeparseGrantOnSequenceStmt(Node *node); extern char * DeparseGrantOnSequenceStmt(Node *node);
/* forward declarations for qualify_sequence_stmt.c */ /* forward declarations for qualify_sequence_stmt.c */
@ -233,6 +236,9 @@ extern void QualifyRenameSequenceStmt(Node *node);
extern void QualifyDropSequenceStmt(Node *node); extern void QualifyDropSequenceStmt(Node *node);
extern void QualifyAlterSequenceSchemaStmt(Node *node); extern void QualifyAlterSequenceSchemaStmt(Node *node);
extern void QualifyAlterSequenceOwnerStmt(Node *node); extern void QualifyAlterSequenceOwnerStmt(Node *node);
#if (PG_VERSION_NUM >= PG_VERSION_15)
extern void QualifyAlterSequencePersistenceStmt(Node *node);
#endif
extern void QualifyGrantOnSequenceStmt(Node *node); extern void QualifyGrantOnSequenceStmt(Node *node);
#endif /* CITUS_DEPARSER_H */ #endif /* CITUS_DEPARSER_H */

View File

@ -18,6 +18,10 @@
#define RelationCreateStorage_compat(a, b, c) RelationCreateStorage(a, b, c) #define RelationCreateStorage_compat(a, b, c) RelationCreateStorage(a, b, c)
#define parse_analyze_varparams_compat(a, b, c, d, e) parse_analyze_varparams(a, b, c, d, \ #define parse_analyze_varparams_compat(a, b, c, d, e) parse_analyze_varparams(a, b, c, d, \
e) e)
#define CREATE_SEQUENCE_COMMAND \
"CREATE %sSEQUENCE IF NOT EXISTS %s AS %s INCREMENT BY " INT64_FORMAT \
" MINVALUE " INT64_FORMAT " MAXVALUE " INT64_FORMAT \
" START WITH " INT64_FORMAT " CACHE " INT64_FORMAT " %sCYCLE"
#else #else
#include "nodes/value.h" #include "nodes/value.h"
@ -62,6 +66,11 @@ RelationGetSmgr(Relation rel)
} }
#define CREATE_SEQUENCE_COMMAND \
"CREATE SEQUENCE IF NOT EXISTS %s AS %s INCREMENT BY " INT64_FORMAT \
" MINVALUE " INT64_FORMAT " MAXVALUE " INT64_FORMAT \
" START WITH " INT64_FORMAT " CACHE " INT64_FORMAT " %sCYCLE"
#endif #endif
#if PG_VERSION_NUM >= PG_VERSION_14 #if PG_VERSION_NUM >= PG_VERSION_14

View File

@ -552,6 +552,176 @@ SELECT count(*)=100 FROM copy_test2;
t t
(1 row) (1 row)
--
-- In PG15, unlogged sequences are supported
-- we support this for distributed sequences as well
--
CREATE SEQUENCE seq1;
CREATE UNLOGGED SEQUENCE "pg15"."seq 2";
-- first, test that sequence persistence is distributed correctly
-- when the sequence is distributed
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('seq1', 'seq 2') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
relname | logged_info
---------------------------------------------------------------------
seq 2 | unlogged
seq1 | logged
(2 rows)
CREATE TABLE "seq test"(a int, b int default nextval ('seq1'), c int default nextval ('"pg15"."seq 2"'));
SELECT create_distributed_table('"pg15"."seq test"','a');
create_distributed_table
---------------------------------------------------------------------
(1 row)
\c - - - :worker_1_port
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('seq1', 'seq 2') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
relname | logged_info
---------------------------------------------------------------------
seq 2 | unlogged
seq1 | logged
(2 rows)
\c - - - :master_port
SET search_path TO pg15;
-- now, check that we can change sequence persistence using ALTER SEQUENCE
ALTER SEQUENCE seq1 SET UNLOGGED;
-- use IF EXISTS
ALTER SEQUENCE IF EXISTS "seq 2" SET LOGGED;
-- check non-existent sequence as well
ALTER SEQUENCE seq_non_exists SET LOGGED;
ERROR: relation "seq_non_exists" does not exist
ALTER SEQUENCE IF EXISTS seq_non_exists SET LOGGED;
NOTICE: relation "seq_non_exists" does not exist, skipping
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('seq1', 'seq 2') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
relname | logged_info
---------------------------------------------------------------------
seq 2 | logged
seq1 | unlogged
(2 rows)
\c - - - :worker_1_port
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('seq1', 'seq 2') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
relname | logged_info
---------------------------------------------------------------------
seq 2 | logged
seq1 | unlogged
(2 rows)
\c - - - :master_port
SET search_path TO pg15;
-- now, check that we can change sequence persistence using ALTER TABLE
ALTER TABLE seq1 SET LOGGED;
ALTER TABLE "seq 2" SET UNLOGGED;
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('seq1', 'seq 2') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
relname | logged_info
---------------------------------------------------------------------
seq 2 | unlogged
seq1 | logged
(2 rows)
\c - - - :worker_1_port
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('seq1', 'seq 2') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
relname | logged_info
---------------------------------------------------------------------
seq 2 | unlogged
seq1 | logged
(2 rows)
\c - - - :master_port
SET search_path TO pg15;
-- An identity/serial sequence now automatically gets and follows the
-- persistence level (logged/unlogged) of its owning table.
-- Test this behavior as well
CREATE UNLOGGED TABLE test(a bigserial, b bigserial);
SELECT create_distributed_table('test', 'a');
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- show that associated sequence is unlooged
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('test_a_seq', 'test_b_seq') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
relname | logged_info
---------------------------------------------------------------------
test_a_seq | unlogged
test_b_seq | unlogged
(2 rows)
\c - - - :worker_1_port
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('test_a_seq', 'test_b_seq') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
relname | logged_info
---------------------------------------------------------------------
test_a_seq | unlogged
test_b_seq | unlogged
(2 rows)
\c - - - :master_port
SET search_path TO pg15;
-- allow foreign key columns to have SET NULL/DEFAULT on column basis -- allow foreign key columns to have SET NULL/DEFAULT on column basis
-- currently only reference tables can support that -- currently only reference tables can support that
CREATE TABLE PKTABLE (tid int, id int, PRIMARY KEY (tid, id)); CREATE TABLE PKTABLE (tid int, id int, PRIMARY KEY (tid, id));

View File

@ -298,6 +298,137 @@ ALTER TABLE copy_test2 RENAME COLUMN data_ TO data;
COPY copy_test2 FROM :'temp_dir''copy_test.txt' WITH ( HEADER match, FORMAT text); COPY copy_test2 FROM :'temp_dir''copy_test.txt' WITH ( HEADER match, FORMAT text);
SELECT count(*)=100 FROM copy_test2; SELECT count(*)=100 FROM copy_test2;
--
-- In PG15, unlogged sequences are supported
-- we support this for distributed sequences as well
--
CREATE SEQUENCE seq1;
CREATE UNLOGGED SEQUENCE "pg15"."seq 2";
-- first, test that sequence persistence is distributed correctly
-- when the sequence is distributed
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('seq1', 'seq 2') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
CREATE TABLE "seq test"(a int, b int default nextval ('seq1'), c int default nextval ('"pg15"."seq 2"'));
SELECT create_distributed_table('"pg15"."seq test"','a');
\c - - - :worker_1_port
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('seq1', 'seq 2') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
\c - - - :master_port
SET search_path TO pg15;
-- now, check that we can change sequence persistence using ALTER SEQUENCE
ALTER SEQUENCE seq1 SET UNLOGGED;
-- use IF EXISTS
ALTER SEQUENCE IF EXISTS "seq 2" SET LOGGED;
-- check non-existent sequence as well
ALTER SEQUENCE seq_non_exists SET LOGGED;
ALTER SEQUENCE IF EXISTS seq_non_exists SET LOGGED;
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('seq1', 'seq 2') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
\c - - - :worker_1_port
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('seq1', 'seq 2') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
\c - - - :master_port
SET search_path TO pg15;
-- now, check that we can change sequence persistence using ALTER TABLE
ALTER TABLE seq1 SET LOGGED;
ALTER TABLE "seq 2" SET UNLOGGED;
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('seq1', 'seq 2') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
\c - - - :worker_1_port
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('seq1', 'seq 2') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
\c - - - :master_port
SET search_path TO pg15;
-- An identity/serial sequence now automatically gets and follows the
-- persistence level (logged/unlogged) of its owning table.
-- Test this behavior as well
CREATE UNLOGGED TABLE test(a bigserial, b bigserial);
SELECT create_distributed_table('test', 'a');
-- show that associated sequence is unlooged
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('test_a_seq', 'test_b_seq') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
\c - - - :worker_1_port
SELECT relname,
CASE relpersistence
WHEN 'u' THEN 'unlogged'
WHEN 'p' then 'logged'
ELSE 'unknown'
END AS logged_info
FROM pg_class
WHERE relname IN ('test_a_seq', 'test_b_seq') AND relnamespace='pg15'::regnamespace
ORDER BY relname;
\c - - - :master_port
SET search_path TO pg15;
-- allow foreign key columns to have SET NULL/DEFAULT on column basis -- allow foreign key columns to have SET NULL/DEFAULT on column basis
-- currently only reference tables can support that -- currently only reference tables can support that