mirror of https://github.com/citusdata/citus.git
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
parent
5cfcc63308
commit
76ff4ab188
|
@ -734,6 +734,17 @@ static DistributeObjectOps Sequence_AlterOwner = {
|
|||
.address = AlterSequenceOwnerStmtObjectAddress,
|
||||
.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 = {
|
||||
.deparse = DeparseDropSequenceStmt,
|
||||
.qualify = QualifyDropSequenceStmt,
|
||||
|
@ -1463,6 +1474,41 @@ GetDistributeObjectOps(Node *node)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
* postgres instance.
|
||||
|
|
|
@ -733,20 +733,40 @@ PreprocessAlterTableStmt(Node *node, const char *alterTableCommand,
|
|||
|
||||
/*
|
||||
* 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);
|
||||
if (relKind == RELKIND_SEQUENCE)
|
||||
{
|
||||
AlterTableStmt *stmtCopy = copyObject(alterTableStatement);
|
||||
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,
|
||||
processUtilityContext);
|
||||
#endif
|
||||
}
|
||||
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);
|
||||
AlterTableStmtObjType_compat(stmtCopy) = OBJECT_VIEW;
|
||||
return PreprocessAlterViewStmt((Node *) stmtCopy, alterTableCommand,
|
||||
|
|
|
@ -256,7 +256,12 @@ pg_get_sequencedef_string(Oid sequenceRelationId)
|
|||
char *qualifiedSequenceName = generate_qualified_relation_name(sequenceRelationId);
|
||||
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,
|
||||
pgSequenceForm->seqincrement, pgSequenceForm->seqmin,
|
||||
pgSequenceForm->seqmax, pgSequenceForm->seqstart,
|
||||
|
|
|
@ -27,6 +27,9 @@ static void AppendSequenceNameList(StringInfo buf, List *objects, ObjectType obj
|
|||
static void AppendRenameSequenceStmt(StringInfo buf, RenameStmt *stmt);
|
||||
static void AppendAlterSequenceSchemaStmt(StringInfo buf, AlterObjectSchemaStmt *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 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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
* ALTER SEQUENCE .. SET SCHEMA ..
|
||||
|
|
|
@ -20,12 +20,6 @@
|
|||
#include "nodes/parsenodes.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 */
|
||||
extern char * pg_get_extensiondef_string(Oid tableRelationId);
|
||||
extern Oid get_extension_schema(Oid ext_oid);
|
||||
|
|
|
@ -459,6 +459,13 @@ extern List * PostprocessAlterSequenceSchemaStmt(Node *node, const char *querySt
|
|||
extern List * PreprocessAlterSequenceOwnerStmt(Node *node, const char *queryString,
|
||||
ProcessUtilityContext processUtilityContext);
|
||||
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,
|
||||
ProcessUtilityContext processUtilityContext);
|
||||
extern List * SequenceDropStmtObjectAddress(Node *stmt, bool missing_ok, bool
|
||||
|
@ -474,6 +481,10 @@ extern List * AlterSequenceSchemaStmtObjectAddress(Node *node, bool missing_ok,
|
|||
isPostprocess);
|
||||
extern List * AlterSequenceOwnerStmtObjectAddress(Node *node, bool missing_ok, bool
|
||||
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
|
||||
isPostprocess);
|
||||
extern void ErrorIfUnsupportedSeqStmt(CreateSeqStmt *createSeqStmt);
|
||||
|
|
|
@ -226,6 +226,9 @@ extern char * DeparseDropSequenceStmt(Node *node);
|
|||
extern char * DeparseRenameSequenceStmt(Node *node);
|
||||
extern char * DeparseAlterSequenceSchemaStmt(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);
|
||||
|
||||
/* forward declarations for qualify_sequence_stmt.c */
|
||||
|
@ -233,6 +236,9 @@ extern void QualifyRenameSequenceStmt(Node *node);
|
|||
extern void QualifyDropSequenceStmt(Node *node);
|
||||
extern void QualifyAlterSequenceSchemaStmt(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);
|
||||
|
||||
#endif /* CITUS_DEPARSER_H */
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
#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, \
|
||||
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
|
||||
|
||||
#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
|
||||
|
||||
#if PG_VERSION_NUM >= PG_VERSION_14
|
||||
|
|
|
@ -552,6 +552,176 @@ SELECT count(*)=100 FROM copy_test2;
|
|||
t
|
||||
(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
|
||||
-- currently only reference tables can support that
|
||||
CREATE TABLE PKTABLE (tid int, id int, PRIMARY KEY (tid, id));
|
||||
|
|
|
@ -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);
|
||||
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
|
||||
-- currently only reference tables can support that
|
||||
|
|
Loading…
Reference in New Issue