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,
|
.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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 ..
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue