Adds propagation of ALTER SEQUENCE and other improvements (#5061)

* Alter seq type when we first use the seq in a dist table

* Don't allow type changes when seq is used in dist table

* ALTER SEQUENCE propagation

* Tests for ALTER SEQUENCE propagation

* Relocate AlterSequenceType and ensure dependencies for sequence

* Support for citus local tables, and other fixes

* Final formatting
pull/5075/head^2
Naisila Puka 2021-06-24 21:23:25 +03:00 committed by GitHub
parent e9bfb8eddd
commit fe5907ad2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 1345 additions and 297 deletions

View File

@ -75,7 +75,7 @@ static void DropDefaultColumnDefinition(Oid relationId, char *columnName);
static void TransferSequenceOwnership(Oid ownedSequenceId, Oid targetRelationId, static void TransferSequenceOwnership(Oid ownedSequenceId, Oid targetRelationId,
char *columnName); char *columnName);
static void InsertMetadataForCitusLocalTable(Oid citusLocalTableId, uint64 shardId); static void InsertMetadataForCitusLocalTable(Oid citusLocalTableId, uint64 shardId);
static void FinalizeCitusLocalTableCreation(Oid relationId); static void FinalizeCitusLocalTableCreation(Oid relationId, List *dependentSequenceList);
PG_FUNCTION_INFO_V1(citus_add_local_table_to_metadata); PG_FUNCTION_INFO_V1(citus_add_local_table_to_metadata);
@ -315,7 +315,18 @@ CreateCitusLocalTable(Oid relationId, bool cascadeViaForeignKeys)
InsertMetadataForCitusLocalTable(shellRelationId, shardId); InsertMetadataForCitusLocalTable(shellRelationId, shardId);
FinalizeCitusLocalTableCreation(shellRelationId); /*
* Ensure that the sequences used in column defaults of the table
* have proper types
*/
List *attnumList = NIL;
List *dependentSequenceList = NIL;
GetDependentSequencesWithRelation(shellRelationId, &attnumList,
&dependentSequenceList, 0);
EnsureDistributedSequencesHaveOneType(shellRelationId, dependentSequenceList,
attnumList);
FinalizeCitusLocalTableCreation(shellRelationId, dependentSequenceList);
} }
@ -1025,9 +1036,11 @@ InsertMetadataForCitusLocalTable(Oid citusLocalTableId, uint64 shardId)
* FinalizeCitusLocalTableCreation completes creation of the citus local table * FinalizeCitusLocalTableCreation completes creation of the citus local table
* with relationId by performing operations that should be done after creating * with relationId by performing operations that should be done after creating
* the shard and inserting the metadata. * the shard and inserting the metadata.
* If the cluster has metadata workers, we ensure proper propagation of the
* sequences dependent with the table.
*/ */
static void static void
FinalizeCitusLocalTableCreation(Oid relationId) FinalizeCitusLocalTableCreation(Oid relationId, List *dependentSequenceList)
{ {
/* /*
* If it is a foreign table, then skip creating citus truncate trigger * If it is a foreign table, then skip creating citus truncate trigger
@ -1040,6 +1053,14 @@ FinalizeCitusLocalTableCreation(Oid relationId)
if (ShouldSyncTableMetadata(relationId)) if (ShouldSyncTableMetadata(relationId))
{ {
if (ClusterHasKnownMetadataWorkers())
{
/*
* Ensure sequence dependencies and mark them as distributed
* before creating table metadata on workers
*/
MarkSequenceListDistributedAndPropagateDependencies(dependentSequenceList);
}
CreateTableMetadataOnWorkers(relationId); CreateTableMetadataOnWorkers(relationId);
} }

View File

@ -33,6 +33,7 @@
#include "catalog/pg_trigger.h" #include "catalog/pg_trigger.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "commands/extension.h" #include "commands/extension.h"
#include "commands/sequence.h"
#include "commands/tablecmds.h" #include "commands/tablecmds.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "distributed/commands/multi_copy.h" #include "distributed/commands/multi_copy.h"
@ -64,6 +65,7 @@
#include "executor/executor.h" #include "executor/executor.h"
#include "executor/spi.h" #include "executor/spi.h"
#include "nodes/execnodes.h" #include "nodes/execnodes.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h" #include "nodes/nodeFuncs.h"
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
@ -465,6 +467,16 @@ CreateDistributedTable(Oid relationId, Var *distributionColumn, char distributio
InsertIntoPgDistPartition(relationId, distributionMethod, distributionColumn, InsertIntoPgDistPartition(relationId, distributionMethod, distributionColumn,
colocationId, replicationModel); colocationId, replicationModel);
/*
* Ensure that the sequences used in column defaults of the table
* have proper types
*/
List *attnumList = NIL;
List *dependentSequenceList = NIL;
GetDependentSequencesWithRelation(relationId, &attnumList, &dependentSequenceList, 0);
EnsureDistributedSequencesHaveOneType(relationId, dependentSequenceList,
attnumList);
/* foreign tables do not support TRUNCATE trigger */ /* foreign tables do not support TRUNCATE trigger */
if (RegularTable(relationId)) if (RegularTable(relationId))
{ {
@ -498,6 +510,15 @@ CreateDistributedTable(Oid relationId, Var *distributionColumn, char distributio
if (ShouldSyncTableMetadata(relationId)) if (ShouldSyncTableMetadata(relationId))
{ {
if (ClusterHasKnownMetadataWorkers())
{
/*
* Ensure sequence dependencies and mark them as distributed
* before creating table metadata on workers
*/
MarkSequenceListDistributedAndPropagateDependencies(dependentSequenceList);
}
CreateTableMetadataOnWorkers(relationId); CreateTableMetadataOnWorkers(relationId);
} }
@ -544,6 +565,149 @@ CreateDistributedTable(Oid relationId, Var *distributionColumn, char distributio
} }
/*
* EnsureSequenceTypeSupported ensures that the type of the column that uses
* a sequence on its DEFAULT is consistent with previous uses (if any) of the
* sequence in distributed tables.
* If any other distributed table uses the input sequence, it checks whether
* the types of the columns using the sequence match. If they don't, it errors out.
* Otherwise, the condition is ensured.
*/
void
EnsureSequenceTypeSupported(Oid seqOid, Oid seqTypId)
{
List *citusTableIdList = CitusTableTypeIdList(ANY_CITUS_TABLE_TYPE);
Oid citusTableId = InvalidOid;
foreach_oid(citusTableId, citusTableIdList)
{
List *attnumList = NIL;
List *dependentSequenceList = NIL;
GetDependentSequencesWithRelation(citusTableId, &attnumList,
&dependentSequenceList, 0);
ListCell *attnumCell = NULL;
ListCell *dependentSequenceCell = NULL;
forboth(attnumCell, attnumList, dependentSequenceCell,
dependentSequenceList)
{
AttrNumber currentAttnum = lfirst_int(attnumCell);
Oid currentSeqOid = lfirst_oid(dependentSequenceCell);
/*
* If another distributed table is using the same sequence
* in one of its column defaults, make sure the types of the
* columns match
*/
if (currentSeqOid == seqOid)
{
Oid currentSeqTypId = GetAttributeTypeOid(citusTableId,
currentAttnum);
if (seqTypId != currentSeqTypId)
{
char *sequenceName = generate_qualified_relation_name(
seqOid);
char *citusTableName =
generate_qualified_relation_name(citusTableId);
ereport(ERROR, (errmsg(
"The sequence %s is already used for a different"
" type in column %d of the table %s",
sequenceName, currentAttnum,
citusTableName)));
}
}
}
}
}
/*
* AlterSequenceType alters the given sequence's type to the given type.
*/
void
AlterSequenceType(Oid seqOid, Oid typeOid)
{
Form_pg_sequence sequenceData = pg_get_sequencedef(seqOid);
Oid currentSequenceTypeOid = sequenceData->seqtypid;
if (currentSequenceTypeOid != typeOid)
{
AlterSeqStmt *alterSequenceStatement = makeNode(AlterSeqStmt);
char *seqNamespace = get_namespace_name(get_rel_namespace(seqOid));
char *seqName = get_rel_name(seqOid);
alterSequenceStatement->sequence = makeRangeVar(seqNamespace, seqName, -1);
Node *asTypeNode = (Node *) makeTypeNameFromOid(typeOid, -1);
SetDefElemArg(alterSequenceStatement, "as", asTypeNode);
ParseState *pstate = make_parsestate(NULL);
AlterSequence(pstate, alterSequenceStatement);
}
}
/*
* MarkSequenceListDistributedAndPropagateDependencies ensures dependencies
* for the given sequence list exist on all nodes and marks the sequences
* as distributed.
*/
void
MarkSequenceListDistributedAndPropagateDependencies(List *sequenceList)
{
Oid sequenceOid = InvalidOid;
foreach_oid(sequenceOid, sequenceList)
{
MarkSequenceDistributedAndPropagateDependencies(sequenceOid);
}
}
/*
* MarkSequenceDistributedAndPropagateDependencies ensures dependencies
* for the given sequence exist on all nodes and marks the sequence
* as distributed.
*/
void
MarkSequenceDistributedAndPropagateDependencies(Oid sequenceOid)
{
/* get sequence address */
ObjectAddress sequenceAddress = { 0 };
ObjectAddressSet(sequenceAddress, RelationRelationId, sequenceOid);
EnsureDependenciesExistOnAllNodes(&sequenceAddress);
MarkObjectDistributed(&sequenceAddress);
}
/*
* EnsureDistributedSequencesHaveOneType first ensures that the type of the column
* in which the sequence is used as default is supported for each sequence in input
* dependentSequenceList, and then alters the sequence type if not the same with the column type.
*/
void
EnsureDistributedSequencesHaveOneType(Oid relationId, List *dependentSequenceList,
List *attnumList)
{
ListCell *attnumCell = NULL;
ListCell *dependentSequenceCell = NULL;
forboth(attnumCell, attnumList, dependentSequenceCell, dependentSequenceList)
{
AttrNumber attnum = lfirst_int(attnumCell);
Oid sequenceOid = lfirst_oid(dependentSequenceCell);
/*
* We should make sure that the type of the column that uses
* that sequence is supported
*/
Oid seqTypId = GetAttributeTypeOid(relationId, attnum);
EnsureSequenceTypeSupported(sequenceOid, seqTypId);
/*
* Alter the sequence's data type in the coordinator if needed.
* A sequence's type is bigint by default and it doesn't change even if
* it's used in an int column. We should change the type if needed,
* and not allow future ALTER SEQUENCE ... TYPE ... commands for
* sequences used as defaults in distributed tables
*/
AlterSequenceType(sequenceOid, seqTypId);
}
}
/* /*
* GetFKeyCreationCommandsRelationInvolvedWithTableType returns a list of DDL * GetFKeyCreationCommandsRelationInvolvedWithTableType returns a list of DDL
* commands to recreate the foreign keys that relation with relationId is involved * commands to recreate the foreign keys that relation with relationId is involved

View File

@ -371,15 +371,22 @@ static DistributeObjectOps Sequence_Alter = {
.qualify = NULL, .qualify = NULL,
.preprocess = PreprocessAlterSequenceStmt, .preprocess = PreprocessAlterSequenceStmt,
.postprocess = NULL, .postprocess = NULL,
.address = AlterSequenceObjectAddress, .address = AlterSequenceStmtObjectAddress,
}; };
static DistributeObjectOps Sequence_AlterObjectSchema = { static DistributeObjectOps Sequence_AlterObjectSchema = {
.deparse = NULL, .deparse = DeparseAlterSequenceSchemaStmt,
.qualify = NULL, .qualify = QualifyAlterSequenceSchemaStmt,
.preprocess = PreprocessAlterSequenceSchemaStmt, .preprocess = PreprocessAlterSequenceSchemaStmt,
.postprocess = NULL, .postprocess = PostprocessAlterSequenceSchemaStmt,
.address = AlterSequenceSchemaStmtObjectAddress, .address = AlterSequenceSchemaStmtObjectAddress,
}; };
static DistributeObjectOps Sequence_AlterOwner = {
.deparse = DeparseAlterSequenceOwnerStmt,
.qualify = QualifyAlterSequenceOwnerStmt,
.preprocess = PreprocessAlterSequenceOwnerStmt,
.postprocess = PostprocessAlterSequenceOwnerStmt,
.address = AlterSequenceOwnerStmtObjectAddress,
};
static DistributeObjectOps Sequence_Drop = { static DistributeObjectOps Sequence_Drop = {
.deparse = DeparseDropSequenceStmt, .deparse = DeparseDropSequenceStmt,
.qualify = NULL, .qualify = NULL,
@ -787,6 +794,11 @@ GetDistributeObjectOps(Node *node)
return &Index_AlterTable; return &Index_AlterTable;
} }
case OBJECT_SEQUENCE:
{
return &Sequence_AlterOwner;
}
default: default:
{ {
return &NoDistributeOps; return &NoDistributeOps;

View File

@ -16,6 +16,7 @@
#include "distributed/commands/utility_hook.h" #include "distributed/commands/utility_hook.h"
#include "distributed/metadata_cache.h" #include "distributed/metadata_cache.h"
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
#include "utils/lsyscache.h"
/* /*
@ -62,6 +63,15 @@ PreprocessRenameStmt(Node *node, const char *renameCommand,
return NIL; return NIL;
} }
/* check whether we are dealing with a sequence here */
if (get_rel_relkind(objectRelationId) == RELKIND_SEQUENCE)
{
RenameStmt *stmtCopy = copyObject(renameStmt);
stmtCopy->renameType = OBJECT_SEQUENCE;
return PreprocessRenameSequenceStmt((Node *) stmtCopy, renameCommand,
processUtilityContext);
}
/* we have no planning to do unless the table is distributed */ /* we have no planning to do unless the table is distributed */
switch (renameStmt->renameType) switch (renameStmt->renameType)
{ {

View File

@ -24,10 +24,12 @@
#include "distributed/metadata_cache.h" #include "distributed/metadata_cache.h"
#include "distributed/metadata_sync.h" #include "distributed/metadata_sync.h"
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
/* Local functions forward declarations for helper functions */ /* Local functions forward declarations for helper functions */
static bool OptionsSpecifyOwnedBy(List *optionList, Oid *ownedByTableId); static bool OptionsSpecifyOwnedBy(List *optionList, Oid *ownedByTableId);
static bool ShouldPropagateAlterSequence(const ObjectAddress *address); static Oid SequenceUsedInDistributedTable(const ObjectAddress *sequenceAddress);
/* /*
@ -284,9 +286,9 @@ PreprocessDropSequenceStmt(Node *node, const char *queryString,
} }
/* /*
* managing types can only be done on the coordinator if ddl propagation is on. when * managing sequences can only be done on the coordinator if ddl propagation is on. when
* it is off we will never get here. MX workers don't have a notion of distributed * it is off we will never get here. MX workers don't have a notion of distributed
* types, so we block the call. * sequences, so we block the call.
*/ */
EnsureCoordinator(); EnsureCoordinator();
@ -303,14 +305,13 @@ PreprocessDropSequenceStmt(Node *node, const char *queryString,
*/ */
DropStmt *stmtCopy = copyObject(stmt); DropStmt *stmtCopy = copyObject(stmt);
stmtCopy->objects = distributedSequencesList; stmtCopy->objects = distributedSequencesList;
stmtCopy->missing_ok = true;
const char *dropStmtSql = DeparseTreeNode((Node *) stmtCopy); const char *dropStmtSql = DeparseTreeNode((Node *) stmtCopy);
List *commands = list_make3(DISABLE_DDL_PROPAGATION, List *commands = list_make3(DISABLE_DDL_PROPAGATION,
(void *) dropStmtSql, (void *) dropStmtSql,
ENABLE_DDL_PROPAGATION); ENABLE_DDL_PROPAGATION);
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands); return NodeDDLTaskList(NON_COORDINATOR_METADATA_NODES, commands);
} }
@ -332,7 +333,7 @@ PreprocessRenameSequenceStmt(Node *node, const char *queryString, ProcessUtility
ObjectAddress address = GetObjectAddressFromParseTree((Node *) stmt, ObjectAddress address = GetObjectAddressFromParseTree((Node *) stmt,
stmt->missing_ok); stmt->missing_ok);
if (!ShouldPropagateAlterSequence(&address)) if (!ShouldPropagateObject(&address))
{ {
return NIL; return NIL;
} }
@ -340,16 +341,12 @@ PreprocessRenameSequenceStmt(Node *node, const char *queryString, ProcessUtility
EnsureCoordinator(); EnsureCoordinator();
QualifyTreeNode((Node *) stmt); QualifyTreeNode((Node *) stmt);
/* this takes care of cases where not all workers have synced metadata */ const char *sql = DeparseTreeNode((Node *) stmt);
RenameStmt *stmtCopy = copyObject(stmt);
stmtCopy->missing_ok = true;
const char *sql = DeparseTreeNode((Node *) stmtCopy);
List *commands = list_make3(DISABLE_DDL_PROPAGATION, (void *) sql, List *commands = list_make3(DISABLE_DDL_PROPAGATION, (void *) sql,
ENABLE_DDL_PROPAGATION); ENABLE_DDL_PROPAGATION);
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands); return NodeDDLTaskList(NON_COORDINATOR_METADATA_NODES, commands);
} }
@ -372,40 +369,6 @@ RenameSequenceStmtObjectAddress(Node *node, bool missing_ok)
} }
/*
* ShouldPropagateAlterSequence returns, based on the address of a sequence, if alter
* statements targeting the function should be propagated.
*/
static bool
ShouldPropagateAlterSequence(const ObjectAddress *address)
{
if (creating_extension)
{
/*
* extensions should be created separately on the workers, sequences cascading
* from an extension should therefore not be propagated.
*/
return false;
}
if (!EnableDependencyCreation)
{
/*
* we are configured to disable object propagation, should not propagate anything
*/
return false;
}
if (!IsObjectDistributed(address))
{
/* do not propagate alter sequence for non-distributed sequences */
return false;
}
return true;
}
/* /*
* PreprocessAlterSequenceStmt gets called during the planning phase of an ALTER SEQUENCE statement * PreprocessAlterSequenceStmt gets called during the planning phase of an ALTER SEQUENCE statement
* of one of the following forms: * of one of the following forms:
@ -435,21 +398,77 @@ PreprocessAlterSequenceStmt(Node *node, const char *queryString,
if (IsObjectDistributed(&address)) if (IsObjectDistributed(&address))
{ {
ereport(ERROR, (errmsg( ereport(ERROR, (errmsg(
"This operation is currently not allowed for a distributed sequence."))); "Altering a distributed sequence is currently not supported.")));
} }
else
/*
* error out if the sequence is used in a distributed table
* and this is an ALTER SEQUENCE .. AS .. statement
*/
Oid citusTableId = SequenceUsedInDistributedTable(&address);
if (citusTableId != InvalidOid)
{ {
return NIL; List *options = stmt->options;
DefElem *defel = NULL;
foreach_ptr(defel, options)
{
if (strcmp(defel->defname, "as") == 0)
{
if (IsCitusTableType(citusTableId, CITUS_LOCAL_TABLE))
{
ereport(ERROR, (errmsg(
"Altering a sequence used in a local table that"
" is added to metadata is currently not supported.")));
}
ereport(ERROR, (errmsg(
"Altering a sequence used in a distributed"
" table is currently not supported.")));
}
}
} }
return NIL;
} }
/* /*
* AlterSequenceOwnerObjectAddress returns the ObjectAddress of the sequence that is the * SequenceUsedInDistributedTable returns true if the argument sequence
* subject of the AlterOwnerStmt. * is used as the default value of a column in a distributed table.
* Returns false otherwise
*/
static Oid
SequenceUsedInDistributedTable(const ObjectAddress *sequenceAddress)
{
List *citusTableIdList = CitusTableTypeIdList(ANY_CITUS_TABLE_TYPE);
Oid citusTableId = InvalidOid;
foreach_oid(citusTableId, citusTableIdList)
{
List *attnumList = NIL;
List *dependentSequenceList = NIL;
GetDependentSequencesWithRelation(citusTableId, &attnumList,
&dependentSequenceList, 0);
Oid currentSeqOid = InvalidOid;
foreach_oid(currentSeqOid, dependentSequenceList)
{
/*
* This sequence is used in a distributed table
*/
if (currentSeqOid == sequenceAddress->objectId)
{
return citusTableId;
}
}
}
return InvalidOid;
}
/*
* AlterSequenceStmtObjectAddress returns the ObjectAddress of the sequence that is the
* subject of the AlterSeqStmt.
*/ */
ObjectAddress ObjectAddress
AlterSequenceObjectAddress(Node *node, bool missing_ok) AlterSequenceStmtObjectAddress(Node *node, bool missing_ok)
{ {
AlterSeqStmt *stmt = castNode(AlterSeqStmt, node); AlterSeqStmt *stmt = castNode(AlterSeqStmt, node);
@ -466,7 +485,7 @@ AlterSequenceObjectAddress(Node *node, bool missing_ok)
* PreprocessAlterSequenceSchemaStmt is executed before the statement is applied to the local * PreprocessAlterSequenceSchemaStmt is executed before the statement is applied to the local
* postgres instance. * postgres instance.
* *
* For distributed sequences, this operation will not be allowed for now. * In this stage we can prepare the commands that need to be run on all workers.
*/ */
List * List *
PreprocessAlterSequenceSchemaStmt(Node *node, const char *queryString, PreprocessAlterSequenceSchemaStmt(Node *node, const char *queryString,
@ -477,17 +496,20 @@ PreprocessAlterSequenceSchemaStmt(Node *node, const char *queryString,
ObjectAddress address = GetObjectAddressFromParseTree((Node *) stmt, ObjectAddress address = GetObjectAddressFromParseTree((Node *) stmt,
stmt->missing_ok); stmt->missing_ok);
if (!ShouldPropagateObject(&address))
/* error out if the sequence is distributed */
if (IsObjectDistributed(&address))
{
ereport(ERROR, (errmsg(
"This operation is currently not allowed for a distributed sequence.")));
}
else
{ {
return NIL; 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);
} }
@ -501,6 +523,108 @@ AlterSequenceSchemaStmtObjectAddress(Node *node, bool missing_ok)
AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node); AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node);
Assert(stmt->objectType == OBJECT_SEQUENCE); Assert(stmt->objectType == OBJECT_SEQUENCE);
RangeVar *sequence = stmt->relation;
Oid seqOid = RangeVarGetRelid(sequence, NoLock, true);
if (seqOid == InvalidOid)
{
/*
* couldn't find the sequence, might have already been moved to the new schema, we
* construct a new sequence name that uses the new schema to search in.
*/
const char *newSchemaName = stmt->newschema;
Oid newSchemaOid = get_namespace_oid(newSchemaName, true);
seqOid = get_relname_relid(sequence->relname, newSchemaOid);
if (!missing_ok && seqOid == InvalidOid)
{
/*
* if the sequence is still invalid we couldn't find the sequence, error with the same
* message postgres would error with if missing_ok is false (not ok to miss)
*/
const char *quotedSequenceName =
quote_qualified_identifier(sequence->schemaname, sequence->relname);
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation \"%s\" does not exist",
quotedSequenceName)));
}
}
ObjectAddress sequenceAddress = { 0 };
ObjectAddressSet(sequenceAddress, RelationRelationId, seqOid);
return sequenceAddress;
}
/*
* PostprocessAlterSequenceSchemaStmt is executed after the change has been applied locally,
* we can now use the new dependencies of the sequence to ensure all its dependencies
* exist on the workers before we apply the commands remotely.
*/
List *
PostprocessAlterSequenceSchemaStmt(Node *node, const char *queryString)
{
AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node);
Assert(stmt->objectType == OBJECT_SEQUENCE);
ObjectAddress address = GetObjectAddressFromParseTree((Node *) stmt,
stmt->missing_ok);
if (!ShouldPropagateObject(&address))
{
return NIL;
}
/* dependencies have changed (schema) let's ensure they exist */
EnsureDependenciesExistOnAllNodes(&address);
return NIL;
}
/*
* PreprocessAlterSequenceOwnerStmt is called for change of ownership of sequences before the
* ownership is changed on the local instance.
*
* If the sequence for which the owner is changed is distributed we execute the change on
* all the workers to keep the type in sync across the cluster.
*/
List *
PreprocessAlterSequenceOwnerStmt(Node *node, const char *queryString,
ProcessUtilityContext processUtilityContext)
{
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
Assert(stmt->relkind == OBJECT_SEQUENCE);
ObjectAddress sequenceAddress = GetObjectAddressFromParseTree((Node *) stmt, false);
if (!ShouldPropagateObject(&sequenceAddress))
{
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);
}
/*
* AlterSequenceOwnerStmtObjectAddress returns the ObjectAddress of the sequence that is the
* subject of the AlterOwnerStmt.
*/
ObjectAddress
AlterSequenceOwnerStmtObjectAddress(Node *node, bool missing_ok)
{
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
Assert(stmt->relkind == OBJECT_SEQUENCE);
RangeVar *sequence = stmt->relation; RangeVar *sequence = stmt->relation;
Oid seqOid = RangeVarGetRelid(sequence, NoLock, missing_ok); Oid seqOid = RangeVarGetRelid(sequence, NoLock, missing_ok);
ObjectAddress sequenceAddress = { 0 }; ObjectAddress sequenceAddress = { 0 };
@ -508,3 +632,27 @@ AlterSequenceSchemaStmtObjectAddress(Node *node, bool missing_ok)
return sequenceAddress; return sequenceAddress;
} }
/*
* PostprocessAlterSequenceOwnerStmt is executed after the change has been applied locally,
* we can now use the new dependencies of the sequence to ensure all its dependencies
* exist on the workers before we apply the commands remotely.
*/
List *
PostprocessAlterSequenceOwnerStmt(Node *node, const char *queryString)
{
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
Assert(stmt->relkind == OBJECT_SEQUENCE);
ObjectAddress sequenceAddress = GetObjectAddressFromParseTree((Node *) stmt, false);
if (!ShouldPropagateObject(&sequenceAddress))
{
return NIL;
}
/* dependencies have changed (owner) let's ensure they exist */
EnsureDependenciesExistOnAllNodes(&sequenceAddress);
return NIL;
}

View File

@ -14,6 +14,7 @@
#include "access/htup_details.h" #include "access/htup_details.h"
#include "access/xact.h" #include "access/xact.h"
#include "catalog/index.h" #include "catalog/index.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_class.h" #include "catalog/pg_class.h"
#include "catalog/pg_constraint.h" #include "catalog/pg_constraint.h"
#include "catalog/pg_depend.h" #include "catalog/pg_depend.h"
@ -42,6 +43,7 @@
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
#include "storage/lmgr.h" #include "storage/lmgr.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
@ -92,6 +94,8 @@ static void SetInterShardDDLTaskPlacementList(Task *task,
static void SetInterShardDDLTaskRelationShardList(Task *task, static void SetInterShardDDLTaskRelationShardList(Task *task,
ShardInterval *leftShardInterval, ShardInterval *leftShardInterval,
ShardInterval *rightShardInterval); ShardInterval *rightShardInterval);
static Oid GetSequenceOid(Oid relationId, AttrNumber attnum);
static Oid get_attrdef_oid(Oid relationId, AttrNumber attnum);
/* /*
@ -463,6 +467,13 @@ PostprocessAlterTableSchemaStmt(Node *node, const char *queryString)
*/ */
ObjectAddress tableAddress = GetObjectAddressFromParseTree((Node *) stmt, true); ObjectAddress tableAddress = GetObjectAddressFromParseTree((Node *) stmt, true);
/* check whether we are dealing with a sequence here */
if (get_rel_relkind(tableAddress.objectId) == RELKIND_SEQUENCE)
{
stmt->objectType = OBJECT_SEQUENCE;
return PostprocessAlterSequenceSchemaStmt((Node *) stmt, queryString);
}
if (!ShouldPropagate() || !IsCitusTable(tableAddress.objectId)) if (!ShouldPropagate() || !IsCitusTable(tableAddress.objectId))
{ {
return NIL; return NIL;
@ -503,6 +514,20 @@ PreprocessAlterTableStmt(Node *node, const char *alterTableCommand,
return NIL; return NIL;
} }
/*
* check whether we are dealing with a sequence here
* if yes, it must be ALTER TABLE .. OWNER TO .. command
* since this is the only ALTER command of a sequence that
* passes through an AlterTableStmt
*/
if (get_rel_relkind(leftRelationId) == RELKIND_SEQUENCE)
{
AlterTableStmt *stmtCopy = copyObject(alterTableStatement);
stmtCopy->relkind = OBJECT_SEQUENCE;
return PreprocessAlterSequenceOwnerStmt((Node *) stmtCopy, alterTableCommand,
processUtilityContext);
}
/* /*
* AlterTableStmt applies also to INDEX relations, and we have support for * AlterTableStmt applies also to INDEX relations, and we have support for
* SET/SET storage parameters in Citus, so we might have to check for * SET/SET storage parameters in Citus, so we might have to check for
@ -1385,6 +1410,15 @@ PreprocessAlterTableSchemaStmt(Node *node, const char *queryString,
stmt->missing_ok); stmt->missing_ok);
Oid relationId = address.objectId; Oid relationId = address.objectId;
/* check whether we are dealing with a sequence here */
if (get_rel_relkind(relationId) == RELKIND_SEQUENCE)
{
AlterObjectSchemaStmt *stmtCopy = copyObject(stmt);
stmtCopy->objectType = OBJECT_SEQUENCE;
return PreprocessAlterSequenceSchemaStmt((Node *) stmtCopy, queryString,
processUtilityContext);
}
/* first check whether a distributed relation is affected */ /* first check whether a distributed relation is affected */
if (!OidIsValid(relationId) || !IsCitusTable(relationId)) if (!OidIsValid(relationId) || !IsCitusTable(relationId))
{ {
@ -1547,6 +1581,19 @@ PostprocessAlterTableStmt(AlterTableStmt *alterTableStatement)
if (relationId != InvalidOid) if (relationId != InvalidOid)
{ {
/*
* check whether we are dealing with a sequence here
* if yes, it must be ALTER TABLE .. OWNER TO .. command
* since this is the only ALTER command of a sequence that
* passes through an AlterTableStmt
*/
if (get_rel_relkind(relationId) == RELKIND_SEQUENCE)
{
alterTableStatement->relkind = OBJECT_SEQUENCE;
PostprocessAlterSequenceOwnerStmt((Node *) alterTableStatement, NULL);
return;
}
/* changing a relation could introduce new dependencies */ /* changing a relation could introduce new dependencies */
ObjectAddress tableAddress = { 0 }; ObjectAddress tableAddress = { 0 };
ObjectAddressSet(tableAddress, RelationRelationId, relationId); ObjectAddressSet(tableAddress, RelationRelationId, relationId);
@ -1629,8 +1676,22 @@ PostprocessAlterTableStmt(AlterTableStmt *alterTableStatement)
{ {
AttrNumber attnum = get_attnum(relationId, AttrNumber attnum = get_attnum(relationId,
columnDefinition->colname); columnDefinition->colname);
Oid seqTypId = GetAttributeTypeOid(relationId, attnum); Oid seqOid = GetSequenceOid(relationId, attnum);
EnsureSequenceTypeSupported(relationId, attnum, seqTypId); if (seqOid != InvalidOid)
{
EnsureDistributedSequencesHaveOneType(relationId,
list_make1_oid(
seqOid),
list_make1_int(
attnum));
if (ShouldSyncTableMetadata(relationId) &&
ClusterHasKnownMetadataWorkers())
{
MarkSequenceDistributedAndPropagateDependencies(
seqOid);
}
}
} }
} }
} }
@ -1650,8 +1711,19 @@ PostprocessAlterTableStmt(AlterTableStmt *alterTableStatement)
if (contain_nextval_expression_walker(expr, NULL)) if (contain_nextval_expression_walker(expr, NULL))
{ {
AttrNumber attnum = get_attnum(relationId, command->name); AttrNumber attnum = get_attnum(relationId, command->name);
Oid seqTypId = GetAttributeTypeOid(relationId, attnum); Oid seqOid = GetSequenceOid(relationId, attnum);
EnsureSequenceTypeSupported(relationId, attnum, seqTypId); if (seqOid != InvalidOid)
{
EnsureDistributedSequencesHaveOneType(relationId,
list_make1_oid(seqOid),
list_make1_int(attnum));
if (ShouldSyncTableMetadata(relationId) &&
ClusterHasKnownMetadataWorkers())
{
MarkSequenceDistributedAndPropagateDependencies(seqOid);
}
}
} }
} }
} }
@ -1680,6 +1752,100 @@ PostprocessAlterTableStmt(AlterTableStmt *alterTableStatement)
} }
/*
* GetSequenceOid returns the oid of the sequence used as default value
* of the attribute with given attnum of the given table relationId
* If there is no sequence used it returns InvalidOid.
*/
static Oid
GetSequenceOid(Oid relationId, AttrNumber attnum)
{
/* get attrdefoid from the given relationId and attnum */
Oid attrdefOid = get_attrdef_oid(relationId, attnum);
/* retrieve the sequence id of the sequence found in nextval('seq') */
List *sequencesFromAttrDef = GetSequencesFromAttrDef(attrdefOid);
if (list_length(sequencesFromAttrDef) == 0)
{
/*
* We need this check because sometimes there are cases where the
* dependency between the table and the sequence is not formed
* One example is when the default is defined by
* DEFAULT nextval('seq_name'::text) (not by DEFAULT nextval('seq_name'))
* In these cases, sequencesFromAttrDef with be empty.
*/
return InvalidOid;
}
if (list_length(sequencesFromAttrDef) > 1)
{
/* to simplify and eliminate cases like "DEFAULT nextval('..') - nextval('..')" */
if (IsCitusTableType(relationId, CITUS_LOCAL_TABLE))
{
ereport(ERROR, (errmsg(
"More than one sequence in a column default"
" is not supported for adding local tables to metadata")));
}
ereport(ERROR, (errmsg(
"More than one sequence in a column default"
" is not supported for distribution")));
}
return lfirst_oid(list_head(sequencesFromAttrDef));
}
/*
* get_attrdef_oid gets the oid of the attrdef that has dependency with
* the given relationId (refobjid) and attnum (refobjsubid).
* If there is no such attrdef it returns InvalidOid.
* NOTE: we are iterating pg_depend here since this function is used together
* with other functions that iterate pg_depend. Normally, a look at pg_attrdef
* would make more sense.
*/
static Oid
get_attrdef_oid(Oid relationId, AttrNumber attnum)
{
Oid resultAttrdefOid = InvalidOid;
ScanKeyData key[3];
Relation depRel = table_open(DependRelationId, AccessShareLock);
ScanKeyInit(&key[0],
Anum_pg_depend_refclassid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationRelationId));
ScanKeyInit(&key[1],
Anum_pg_depend_refobjid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(relationId));
ScanKeyInit(&key[2],
Anum_pg_depend_refobjsubid,
BTEqualStrategyNumber, F_INT4EQ,
Int32GetDatum(attnum));
SysScanDesc scan = systable_beginscan(depRel, DependReferenceIndexId, true,
NULL, attnum ? 3 : 2, key);
HeapTuple tup;
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
if (deprec->classid == AttrDefaultRelationId)
{
resultAttrdefOid = deprec->objid;
}
}
systable_endscan(scan);
table_close(depRel, AccessShareLock);
return resultAttrdefOid;
}
void void
ErrorUnsupportedAlterTableAddColumn(Oid relationId, AlterTableCmd *command, ErrorUnsupportedAlterTableAddColumn(Oid relationId, AlterTableCmd *command,
Constraint *constraint) Constraint *constraint)

View File

@ -27,7 +27,6 @@
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "catalog/pg_am.h" #include "catalog/pg_am.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_attribute.h" #include "catalog/pg_attribute.h"
#include "catalog/pg_authid.h" #include "catalog/pg_authid.h"
#include "catalog/pg_class.h" #include "catalog/pg_class.h"
@ -47,6 +46,7 @@
#include "distributed/metadata_utility.h" #include "distributed/metadata_utility.h"
#include "distributed/relay_utility.h" #include "distributed/relay_utility.h"
#include "distributed/version_compat.h" #include "distributed/version_compat.h"
#include "distributed/worker_protocol.h"
#include "foreign/foreign.h" #include "foreign/foreign.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
#include "nodes/nodes.h" #include "nodes/nodes.h"
@ -77,7 +77,6 @@ static void AppendStorageParametersToString(StringInfo stringBuffer,
List *optionList); List *optionList);
static void simple_quote_literal(StringInfo buf, const char *val); static void simple_quote_literal(StringInfo buf, const char *val);
static char * flatten_reloptions(Oid relid); static char * flatten_reloptions(Oid relid);
static Oid get_attrdef_oid(Oid relationId, AttrNumber attnum);
/* /*
@ -370,16 +369,6 @@ pg_get_tableschemadef_string(Oid tableRelationId, bool includeSequenceDefaults,
appendStringInfo(&buffer, " DEFAULT %s", defaultString); appendStringInfo(&buffer, " DEFAULT %s", defaultString);
} }
} }
/*
* We should make sure that the type of the column that uses
* that sequence is supported
*/
if (contain_nextval_expression_walker(defaultNode, NULL))
{
EnsureSequenceTypeSupported(tableRelationId, defaultValue->adnum,
attributeForm->atttypid);
}
} }
/* if this column has a not null constraint, append the constraint */ /* if this column has a not null constraint, append the constraint */
@ -498,138 +487,6 @@ pg_get_tableschemadef_string(Oid tableRelationId, bool includeSequenceDefaults,
} }
/*
* EnsureSequenceTypeSupported ensures that the type of the column that uses
* a sequence on its DEFAULT is consistent with previous uses of the sequence (if any)
* It gets the AttrDefault OID from the given relationId and attnum, extracts the sequence
* id from it, and if any other distributed table uses that same sequence, it checks whether
* the types of the columns using the sequence match. If they don't, it errors out.
* Otherwise, the condition is ensured.
*/
void
EnsureSequenceTypeSupported(Oid relationId, AttrNumber attnum, Oid seqTypId)
{
/* get attrdefoid from the given relationId and attnum */
Oid attrdefOid = get_attrdef_oid(relationId, attnum);
/* retrieve the sequence id of the sequence found in nextval('seq') */
List *sequencesFromAttrDef = GetSequencesFromAttrDef(attrdefOid);
if (list_length(sequencesFromAttrDef) == 0)
{
/*
* We need this check because sometimes there are cases where the
* dependency between the table and the sequence is not formed
* One example is when the default is defined by
* DEFAULT nextval('seq_name'::text) (not by DEFAULT nextval('seq_name'))
* In these cases, sequencesFromAttrDef with be empty.
*/
return;
}
if (list_length(sequencesFromAttrDef) > 1)
{
/* to simplify and eliminate cases like "DEFAULT nextval('..') - nextval('..')" */
ereport(ERROR, (errmsg(
"More than one sequence in a column default"
" is not supported for distribution")));
}
Oid seqOid = lfirst_oid(list_head(sequencesFromAttrDef));
List *citusTableIdList = CitusTableTypeIdList(ANY_CITUS_TABLE_TYPE);
Oid citusTableId = InvalidOid;
foreach_oid(citusTableId, citusTableIdList)
{
List *attnumList = NIL;
List *dependentSequenceList = NIL;
GetDependentSequencesWithRelation(citusTableId, &attnumList,
&dependentSequenceList, 0);
ListCell *attnumCell = NULL;
ListCell *dependentSequenceCell = NULL;
forboth(attnumCell, attnumList, dependentSequenceCell,
dependentSequenceList)
{
AttrNumber currentAttnum = lfirst_int(attnumCell);
Oid currentSeqOid = lfirst_oid(dependentSequenceCell);
/*
* If another distributed table is using the same sequence
* in one of its column defaults, make sure the types of the
* columns match
*/
if (currentSeqOid == seqOid)
{
Oid currentSeqTypId = GetAttributeTypeOid(citusTableId,
currentAttnum);
if (seqTypId != currentSeqTypId)
{
char *sequenceName = generate_qualified_relation_name(
seqOid);
char *citusTableName =
generate_qualified_relation_name(citusTableId);
ereport(ERROR, (errmsg(
"The sequence %s is already used for a different"
" type in column %d of the table %s",
sequenceName, currentAttnum,
citusTableName)));
}
}
}
}
}
/*
* get_attrdef_oid gets the oid of the attrdef that has dependency with
* the given relationId (refobjid) and attnum (refobjsubid).
* If there is no such attrdef it returns InvalidOid.
* NOTE: we are iterating pg_depend here since this function is used together
* with other functions that iterate pg_depend. Normally, a look at pg_attrdef
* would make more sense.
*/
static Oid
get_attrdef_oid(Oid relationId, AttrNumber attnum)
{
Oid resultAttrdefOid = InvalidOid;
ScanKeyData key[3];
Relation depRel = table_open(DependRelationId, AccessShareLock);
ScanKeyInit(&key[0],
Anum_pg_depend_refclassid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationRelationId));
ScanKeyInit(&key[1],
Anum_pg_depend_refobjid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(relationId));
ScanKeyInit(&key[2],
Anum_pg_depend_refobjsubid,
BTEqualStrategyNumber, F_INT4EQ,
Int32GetDatum(attnum));
SysScanDesc scan = systable_beginscan(depRel, DependReferenceIndexId, true,
NULL, attnum ? 3 : 2, key);
HeapTuple tup;
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
if (deprec->classid == AttrDefaultRelationId)
{
resultAttrdefOid = deprec->objid;
}
}
systable_endscan(scan);
table_close(depRel, AccessShareLock);
return resultAttrdefOid;
}
/* /*
* EnsureRelationKindSupported errors out if the given relation is not supported * EnsureRelationKindSupported errors out if the given relation is not supported
* as a distributed relation. * as a distributed relation.

View File

@ -15,6 +15,7 @@
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "distributed/deparser.h" #include "distributed/deparser.h"
#include "utils/acl.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
@ -23,6 +24,8 @@
static void AppendDropSequenceStmt(StringInfo buf, DropStmt *stmt); static void AppendDropSequenceStmt(StringInfo buf, DropStmt *stmt);
static void AppendSequenceNameList(StringInfo buf, List *objects, ObjectType objtype); static void AppendSequenceNameList(StringInfo buf, List *objects, ObjectType objtype);
static void AppendRenameSequenceStmt(StringInfo buf, RenameStmt *stmt); static void AppendRenameSequenceStmt(StringInfo buf, RenameStmt *stmt);
static void AppendAlterSequenceSchemaStmt(StringInfo buf, AlterObjectSchemaStmt *stmt);
static void AppendAlterSequenceOwnerStmt(StringInfo buf, AlterTableStmt *stmt);
/* /*
* DeparseDropSequenceStmt builds and returns a string representing the DropStmt * DeparseDropSequenceStmt builds and returns a string representing the DropStmt
@ -138,21 +141,121 @@ AppendRenameSequenceStmt(StringInfo buf, RenameStmt *stmt)
/* /*
* QualifyRenameSequenceStmt transforms a * DeparseAlterSequenceSchemaStmt builds and returns a string representing the AlterObjectSchemaStmt
* ALTER SEQUENCE .. RENAME TO ..
* statement in place and makes the sequence name fully qualified.
*/ */
void char *
QualifyRenameSequenceStmt(Node *node) DeparseAlterSequenceSchemaStmt(Node *node)
{ {
RenameStmt *stmt = castNode(RenameStmt, node); AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node);
Assert(stmt->renameType == OBJECT_SEQUENCE); StringInfoData str = { 0 };
initStringInfo(&str);
Assert(stmt->objectType == OBJECT_SEQUENCE);
AppendAlterSequenceSchemaStmt(&str, stmt);
return str.data;
}
/*
* AppendAlterSequenceSchemaStmt appends a string representing the AlterObjectSchemaStmt to a buffer
*/
static void
AppendAlterSequenceSchemaStmt(StringInfo buf, AlterObjectSchemaStmt *stmt)
{
RangeVar *seq = stmt->relation; RangeVar *seq = stmt->relation;
if (seq->schemaname == NULL) char *qualifiedSequenceName = quote_qualified_identifier(seq->schemaname,
seq->relname);
appendStringInfoString(buf, "ALTER SEQUENCE ");
if (stmt->missing_ok)
{ {
Oid schemaOid = RangeVarGetCreationNamespace(seq); appendStringInfoString(buf, "IF EXISTS ");
seq->schemaname = get_namespace_name(schemaOid); }
appendStringInfoString(buf, qualifiedSequenceName);
appendStringInfo(buf, " SET SCHEMA %s;", quote_identifier(stmt->newschema));
}
/*
* DeparseAlterSequenceOwnerStmt builds and returns a string representing the AlterTableStmt
* consisting of changing the owner of a sequence
*/
char *
DeparseAlterSequenceOwnerStmt(Node *node)
{
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
StringInfoData str = { 0 };
initStringInfo(&str);
Assert(stmt->relkind == OBJECT_SEQUENCE);
AppendAlterSequenceOwnerStmt(&str, stmt);
return str.data;
}
/*
* AppendAlterSequenceOwnerStmt appends a string representing the AlterTableStmt to a buffer
* consisting of changing the owner of a sequence
*/
static void
AppendAlterSequenceOwnerStmt(StringInfo buf, AlterTableStmt *stmt)
{
Assert(stmt->relkind == 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))
{
/*
* normally we shouldn't ever reach this
* because we enter this function after making sure we have only
* one subcommand of the type AT_ChangeOwner
*/
ereport(ERROR, (errmsg("More than one subcommand is not supported "
"for ALTER SEQUENCE")));
}
AlterTableCmd *alterTableCmd = castNode(AlterTableCmd, lfirst(cmdCell));
switch (alterTableCmd->subtype)
{
case AT_ChangeOwner:
{
appendStringInfo(buf, " OWNER TO %s;", get_rolespec_name(
alterTableCmd->newowner));
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 .. OWNER TO ..
*/
ereport(ERROR, (errmsg("unsupported subtype for alter sequence command"),
errdetail("sub command type: %d",
alterTableCmd->subtype)));
}
}
} }
} }

View File

@ -0,0 +1,85 @@
/*-------------------------------------------------------------------------
*
* qualify_sequence_stmt.c
* Functions specialized in fully qualifying all sequence statements. These
* functions are dispatched from qualify.c
*
* Fully qualifying sequence statements consists of adding the schema name
* to the subject of the sequence.
*
* Goal would be that the deparser functions for these statements can
* serialize the statement without any external lookups.
*
* Copyright (c), Citus Data, Inc.
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "distributed/deparser.h"
#include "parser/parse_func.h"
#include "utils/lsyscache.h"
/*
* QualifyAlterSequenceOwnerStmt transforms a
* ALTER SEQUENCE .. OWNER TO ..
* statement in place and makes the sequence name fully qualified.
*/
void
QualifyAlterSequenceOwnerStmt(Node *node)
{
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
Assert(stmt->relkind == OBJECT_SEQUENCE);
RangeVar *seq = stmt->relation;
if (seq->schemaname == NULL)
{
Oid schemaOid = RangeVarGetCreationNamespace(seq);
seq->schemaname = get_namespace_name(schemaOid);
}
}
/*
* QualifyAlterSequenceSchemaStmt transforms a
* ALTER SEQUENCE .. SET SCHEMA ..
* statement in place and makes the sequence name fully qualified.
*/
void
QualifyAlterSequenceSchemaStmt(Node *node)
{
AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node);
Assert(stmt->objectType == OBJECT_SEQUENCE);
RangeVar *seq = stmt->relation;
if (seq->schemaname == NULL)
{
Oid schemaOid = RangeVarGetCreationNamespace(seq);
seq->schemaname = get_namespace_name(schemaOid);
}
}
/*
* QualifyRenameSequenceStmt transforms a
* ALTER SEQUENCE .. RENAME TO ..
* statement in place and makes the sequence name fully qualified.
*/
void
QualifyRenameSequenceStmt(Node *node)
{
RenameStmt *stmt = castNode(RenameStmt, node);
Assert(stmt->renameType == OBJECT_SEQUENCE);
RangeVar *seq = stmt->relation;
if (seq->schemaname == NULL)
{
Oid schemaOid = RangeVarGetCreationNamespace(seq);
seq->schemaname = get_namespace_name(schemaOid);
}
}

View File

@ -31,7 +31,6 @@
#include "catalog/pg_namespace.h" #include "catalog/pg_namespace.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/async.h" #include "commands/async.h"
#include "commands/sequence.h"
#include "distributed/citus_ruleutils.h" #include "distributed/citus_ruleutils.h"
#include "distributed/commands.h" #include "distributed/commands.h"
#include "distributed/deparser.h" #include "distributed/deparser.h"
@ -48,13 +47,11 @@
#include "distributed/pg_dist_node.h" #include "distributed/pg_dist_node.h"
#include "distributed/remote_commands.h" #include "distributed/remote_commands.h"
#include "distributed/worker_manager.h" #include "distributed/worker_manager.h"
#include "distributed/worker_protocol.h"
#include "distributed/worker_transaction.h" #include "distributed/worker_transaction.h"
#include "distributed/version_compat.h" #include "distributed/version_compat.h"
#include "executor/spi.h" #include "executor/spi.h"
#include "foreign/foreign.h" #include "foreign/foreign.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#include "pgstat.h" #include "pgstat.h"
#include "postmaster/bgworker.h" #include "postmaster/bgworker.h"
@ -390,6 +387,15 @@ MetadataCreateCommands(void)
ObjectAddressSet(tableAddress, RelationRelationId, relationId); ObjectAddressSet(tableAddress, RelationRelationId, relationId);
EnsureDependenciesExistOnAllNodes(&tableAddress); EnsureDependenciesExistOnAllNodes(&tableAddress);
/*
* Ensure sequence dependencies and mark them as distributed
*/
List *attnumList = NIL;
List *dependentSequenceList = NIL;
GetDependentSequencesWithRelation(relationId, &attnumList,
&dependentSequenceList, 0);
MarkSequenceListDistributedAndPropagateDependencies(dependentSequenceList);
List *workerSequenceDDLCommands = SequenceDDLCommandsForTable(relationId); List *workerSequenceDDLCommands = SequenceDDLCommandsForTable(relationId);
metadataSnapshotCommandList = list_concat(metadataSnapshotCommandList, metadataSnapshotCommandList = list_concat(metadataSnapshotCommandList,
workerSequenceDDLCommands); workerSequenceDDLCommands);
@ -1056,51 +1062,18 @@ SequenceDDLCommandsForTable(Oid relationId)
char *ownerName = TableOwner(relationId); char *ownerName = TableOwner(relationId);
ListCell *attnumCell = NULL; Oid sequenceOid = InvalidOid;
ListCell *dependentSequenceCell = NULL; foreach_oid(sequenceOid, dependentSequenceList)
forboth(attnumCell, attnumList, dependentSequenceCell, dependentSequenceList)
{ {
AttrNumber attnum = lfirst_int(attnumCell);
Oid sequenceOid = lfirst_oid(dependentSequenceCell);
char *sequenceDef = pg_get_sequencedef_string(sequenceOid); char *sequenceDef = pg_get_sequencedef_string(sequenceOid);
char *escapedSequenceDef = quote_literal_cstr(sequenceDef); char *escapedSequenceDef = quote_literal_cstr(sequenceDef);
StringInfo wrappedSequenceDef = makeStringInfo(); StringInfo wrappedSequenceDef = makeStringInfo();
StringInfo sequenceGrantStmt = makeStringInfo(); StringInfo sequenceGrantStmt = makeStringInfo();
char *sequenceName = generate_qualified_relation_name(sequenceOid); char *sequenceName = generate_qualified_relation_name(sequenceOid);
Form_pg_sequence sequenceData = pg_get_sequencedef(sequenceOid); Form_pg_sequence sequenceData = pg_get_sequencedef(sequenceOid);
Oid sequenceTypeOid = GetAttributeTypeOid(relationId, attnum); Oid sequenceTypeOid = sequenceData->seqtypid;
char *typeName = format_type_be(sequenceTypeOid); char *typeName = format_type_be(sequenceTypeOid);
/* get sequence address */
ObjectAddress sequenceAddress = { 0 };
ObjectAddressSet(sequenceAddress, RelationRelationId, sequenceOid);
EnsureDependenciesExistOnAllNodes(&sequenceAddress);
/*
* Alter the sequence's data type in the coordinator if needed.
* A sequence's type is bigint by default and it doesn't change even if
* it's used in an int column. However, when distributing the sequence,
* we don't allow incompatible min/max ranges between the coordinator and
* workers, so we determine the sequence type here based on its current usage
* and propagate that same type to the workers as well.
* TODO: move this command to the part where the sequence is
* used in a distributed table: both in create_distributed_table
* and ALTER TABLE commands that include a sequence default
*/
Oid currentSequenceTypeOid = sequenceData->seqtypid;
if (currentSequenceTypeOid != sequenceTypeOid)
{
AlterSeqStmt *alterSequenceStatement = makeNode(AlterSeqStmt);
char *seqNamespace = get_namespace_name(get_rel_namespace(sequenceOid));
char *seqName = get_rel_name(sequenceOid);
alterSequenceStatement->sequence = makeRangeVar(seqNamespace, seqName, -1);
Node *asTypeNode = (Node *) makeTypeNameFromOid(sequenceTypeOid, -1);
SetDefElemArg(alterSequenceStatement, "as", asTypeNode);
ParseState *pstate = make_parsestate(NULL);
AlterSequence(pstate, alterSequenceStatement);
}
/* create schema if needed */ /* create schema if needed */
appendStringInfo(wrappedSequenceDef, appendStringInfo(wrappedSequenceDef,
WORKER_APPLY_SEQUENCE_COMMAND, WORKER_APPLY_SEQUENCE_COMMAND,
@ -1113,8 +1086,6 @@ SequenceDDLCommandsForTable(Oid relationId)
sequenceDDLList = lappend(sequenceDDLList, wrappedSequenceDef->data); sequenceDDLList = lappend(sequenceDDLList, wrappedSequenceDef->data);
sequenceDDLList = lappend(sequenceDDLList, sequenceGrantStmt->data); sequenceDDLList = lappend(sequenceDDLList, sequenceGrantStmt->data);
MarkObjectDistributed(&sequenceAddress);
} }
return sequenceDDLList; return sequenceDDLList;
@ -1232,6 +1203,12 @@ GetDependentSequencesWithRelation(Oid relationId, List **attnumList,
/* to simplify and eliminate cases like "DEFAULT nextval('..') - nextval('..')" */ /* to simplify and eliminate cases like "DEFAULT nextval('..') - nextval('..')" */
if (list_length(sequencesFromAttrDef) > 1) if (list_length(sequencesFromAttrDef) > 1)
{ {
if (IsCitusTableType(relationId, CITUS_LOCAL_TABLE))
{
ereport(ERROR, (errmsg(
"More than one sequence in a column default"
" is not supported for adding local tables to metadata")));
}
ereport(ERROR, (errmsg("More than one sequence in a column default" ereport(ERROR, (errmsg("More than one sequence in a column default"
" is not supported for distribution"))); " is not supported for distribution")));
} }

View File

@ -42,7 +42,6 @@ extern char * pg_get_indexclusterdef_string(Oid indexRelationId);
extern bool contain_nextval_expression_walker(Node *node, void *context); extern bool contain_nextval_expression_walker(Node *node, void *context);
extern char * pg_get_replica_identity_command(Oid tableRelationId); extern char * pg_get_replica_identity_command(Oid tableRelationId);
extern const char * RoleSpecString(RoleSpec *spec, bool withQuoteIdentifier); extern const char * RoleSpecString(RoleSpec *spec, bool withQuoteIdentifier);
extern void EnsureSequenceTypeSupported(Oid relationId, AttrNumber attnum, Oid seqTypId);
/* Function declarations for version dependent PostgreSQL ruleutils functions */ /* Function declarations for version dependent PostgreSQL ruleutils functions */
extern void pg_get_query_def(Query *query, StringInfo buffer); extern void pg_get_query_def(Query *query, StringInfo buffer);

View File

@ -345,18 +345,23 @@ extern List * PreprocessAlterSchemaRenameStmt(Node *node, const char *queryStrin
extern ObjectAddress AlterSchemaRenameStmtObjectAddress(Node *node, bool missing_ok); extern ObjectAddress AlterSchemaRenameStmtObjectAddress(Node *node, bool missing_ok);
/* sequence.c - forward declarations */ /* sequence.c - forward declarations */
extern List * PreprocessAlterSequenceStmt(Node *stmt, const char *queryString, extern List * PreprocessAlterSequenceStmt(Node *node, const char *queryString,
ProcessUtilityContext processUtilityContext); ProcessUtilityContext processUtilityContext);
extern List * PreprocessAlterSequenceSchemaStmt(Node *node, const char *queryString, extern List * PreprocessAlterSequenceSchemaStmt(Node *node, const char *queryString,
ProcessUtilityContext ProcessUtilityContext
processUtilityContext); processUtilityContext);
extern List * PreprocessDropSequenceStmt(Node *stmt, const char *queryString, extern List * PostprocessAlterSequenceSchemaStmt(Node *node, const char *queryString);
extern List * PreprocessAlterSequenceOwnerStmt(Node *node, const char *queryString,
ProcessUtilityContext processUtilityContext);
extern List * PostprocessAlterSequenceOwnerStmt(Node *node, const char *queryString);
extern List * PreprocessDropSequenceStmt(Node *node, const char *queryString,
ProcessUtilityContext processUtilityContext); ProcessUtilityContext processUtilityContext);
extern List * PreprocessRenameSequenceStmt(Node *stmt, const char *queryString, extern List * PreprocessRenameSequenceStmt(Node *node, const char *queryString,
ProcessUtilityContext processUtilityContext); ProcessUtilityContext processUtilityContext);
extern ObjectAddress AlterSequenceObjectAddress(Node *stmt, bool missing_ok); extern ObjectAddress AlterSequenceStmtObjectAddress(Node *node, bool missing_ok);
extern ObjectAddress AlterSequenceSchemaStmtObjectAddress(Node *stmt, bool missing_ok); extern ObjectAddress AlterSequenceSchemaStmtObjectAddress(Node *node, bool missing_ok);
extern ObjectAddress RenameSequenceStmtObjectAddress(Node *stmt, bool missing_ok); extern ObjectAddress AlterSequenceOwnerStmtObjectAddress(Node *node, bool missing_ok);
extern ObjectAddress RenameSequenceStmtObjectAddress(Node *node, bool missing_ok);
extern void ErrorIfUnsupportedSeqStmt(CreateSeqStmt *createSeqStmt); extern void ErrorIfUnsupportedSeqStmt(CreateSeqStmt *createSeqStmt);
extern void ErrorIfDistributedAlterSeqOwnedBy(AlterSeqStmt *alterSeqStmt); extern void ErrorIfDistributedAlterSeqOwnedBy(AlterSeqStmt *alterSeqStmt);

View File

@ -132,8 +132,14 @@ extern char * DeparseAlterExtensionStmt(Node *stmt);
extern char * DeparseAlterDatabaseOwnerStmt(Node *node); extern char * DeparseAlterDatabaseOwnerStmt(Node *node);
/* forward declarations for deparse_sequence_stmts.c */ /* forward declarations for deparse_sequence_stmts.c */
extern char * DeparseDropSequenceStmt(Node *stmt); extern char * DeparseDropSequenceStmt(Node *node);
extern char * DeparseRenameSequenceStmt(Node *stmt); extern char * DeparseRenameSequenceStmt(Node *node);
extern void QualifyRenameSequenceStmt(Node *stmt); extern char * DeparseAlterSequenceSchemaStmt(Node *node);
extern char * DeparseAlterSequenceOwnerStmt(Node *node);
/* forward declarations for qualify_sequence_stmt.c */
extern void QualifyRenameSequenceStmt(Node *node);
extern void QualifyAlterSequenceSchemaStmt(Node *node);
extern void QualifyAlterSequenceOwnerStmt(Node *node);
#endif /* CITUS_DEPARSER_H */ #endif /* CITUS_DEPARSER_H */

View File

@ -290,4 +290,11 @@ extern bool GetNodeDiskSpaceStatsForConnection(MultiConnection *connection,
uint64 *availableBytes, uint64 *availableBytes,
uint64 *totalBytes); uint64 *totalBytes);
extern void ExecuteQueryViaSPI(char *query, int SPIOK); extern void ExecuteQueryViaSPI(char *query, int SPIOK);
extern void EnsureSequenceTypeSupported(Oid seqOid, Oid seqTypId);
extern void AlterSequenceType(Oid seqOid, Oid typeOid);
extern void MarkSequenceListDistributedAndPropagateDependencies(List *sequenceList);
extern void MarkSequenceDistributedAndPropagateDependencies(Oid sequenceOid);
extern void EnsureDistributedSequencesHaveOneType(Oid relationId,
List *dependentSequenceList,
List *attnumList);
#endif /* METADATA_UTILITY_H */ #endif /* METADATA_UTILITY_H */

View File

@ -8,24 +8,69 @@ SET citus.shard_count TO 4;
SET citus.shard_replication_factor TO 1; SET citus.shard_replication_factor TO 1;
CREATE SCHEMA sequence_default; CREATE SCHEMA sequence_default;
SET search_path = sequence_default, public; SET search_path = sequence_default, public;
-- test both distributed and citus local tables
SELECT 1 FROM citus_add_node('localhost', :master_port, groupId => 0);
?column?
---------------------------------------------------------------------
1
(1 row)
-- Cannot add a column involving DEFAULT nextval('..') because the table is not empty -- Cannot add a column involving DEFAULT nextval('..') because the table is not empty
CREATE SEQUENCE seq_0; CREATE SEQUENCE seq_0;
CREATE SEQUENCE seq_0_local_table;
-- check sequence type & other things
\d seq_0
Sequence "sequence_default.seq_0"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------------------------------------------------------------------
bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1
\d seq_0_local_table
Sequence "sequence_default.seq_0_local_table"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------------------------------------------------------------------
bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1
-- we can change the type of the sequence before using it in distributed tables
ALTER SEQUENCE seq_0 AS smallint;
\d seq_0
Sequence "sequence_default.seq_0"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------------------------------------------------------------------
smallint | 1 | 1 | 32767 | 1 | no | 1
CREATE TABLE seq_test_0 (x int, y int); CREATE TABLE seq_test_0 (x int, y int);
CREATE TABLE seq_test_0_local_table (x int, y int);
SELECT create_distributed_table('seq_test_0','x'); SELECT create_distributed_table('seq_test_0','x');
create_distributed_table create_distributed_table
--------------------------------------------------------------------- ---------------------------------------------------------------------
(1 row) (1 row)
SELECT citus_add_local_table_to_metadata('seq_test_0_local_table');
citus_add_local_table_to_metadata
---------------------------------------------------------------------
(1 row)
INSERT INTO seq_test_0 SELECT 1, s FROM generate_series(1, 50) s; INSERT INTO seq_test_0 SELECT 1, s FROM generate_series(1, 50) s;
INSERT INTO seq_test_0_local_table SELECT 1, s FROM generate_series(1, 50) s;
ALTER TABLE seq_test_0 ADD COLUMN z int DEFAULT nextval('seq_0'); ALTER TABLE seq_test_0 ADD COLUMN z int DEFAULT nextval('seq_0');
ERROR: cannot add a column involving DEFAULT nextval('..') because the table is not empty ERROR: cannot add a column involving DEFAULT nextval('..') because the table is not empty
HINT: You can first call ALTER TABLE .. ADD COLUMN .. smallint/int/bigint HINT: You can first call ALTER TABLE .. ADD COLUMN .. smallint/int/bigint
Then set the default by ALTER TABLE .. ALTER COLUMN .. SET DEFAULT nextval('..') Then set the default by ALTER TABLE .. ALTER COLUMN .. SET DEFAULT nextval('..')
ALTER TABLE seq_test_0_local_table ADD COLUMN z int DEFAULT nextval('seq_0_local_table');
ERROR: cannot add a column involving DEFAULT nextval('..') because the table is not empty
HINT: You can first call ALTER TABLE .. ADD COLUMN .. smallint/int/bigint
Then set the default by ALTER TABLE .. ALTER COLUMN .. SET DEFAULT nextval('..')
ALTER TABLE seq_test_0 ADD COLUMN z serial; ALTER TABLE seq_test_0 ADD COLUMN z serial;
ERROR: Cannot add a column involving serial pseudotypes because the table is not empty ERROR: Cannot add a column involving serial pseudotypes because the table is not empty
HINT: You can first call ALTER TABLE .. ADD COLUMN .. smallint/int/bigint HINT: You can first call ALTER TABLE .. ADD COLUMN .. smallint/int/bigint
Then set the default by ALTER TABLE .. ALTER COLUMN .. SET DEFAULT nextval('..') Then set the default by ALTER TABLE .. ALTER COLUMN .. SET DEFAULT nextval('..')
ALTER TABLE seq_test_0_local_table ADD COLUMN z serial;
ERROR: Cannot add a column involving serial pseudotypes because the table is not empty
HINT: You can first call ALTER TABLE .. ADD COLUMN .. smallint/int/bigint
Then set the default by ALTER TABLE .. ALTER COLUMN .. SET DEFAULT nextval('..')
-- follow hint -- follow hint
ALTER TABLE seq_test_0 ADD COLUMN z int; ALTER TABLE seq_test_0 ADD COLUMN z int;
ALTER TABLE seq_test_0 ALTER COLUMN z SET DEFAULT nextval('seq_0'); ALTER TABLE seq_test_0 ALTER COLUMN z SET DEFAULT nextval('seq_0');
@ -47,6 +92,63 @@ SELECT * FROM seq_test_0 ORDER BY 1, 2 LIMIT 5;
y | integer | | | y | integer | | |
z | integer | | | nextval('seq_0'::regclass) z | integer | | | nextval('seq_0'::regclass)
ALTER TABLE seq_test_0_local_table ADD COLUMN z int;
ALTER TABLE seq_test_0_local_table ALTER COLUMN z SET DEFAULT nextval('seq_0_local_table');
SELECT * FROM seq_test_0_local_table ORDER BY 1, 2 LIMIT 5;
x | y | z
---------------------------------------------------------------------
1 | 1 |
1 | 2 |
1 | 3 |
1 | 4 |
1 | 5 |
(5 rows)
\d seq_test_0_local_table
Table "sequence_default.seq_test_0_local_table"
Column | Type | Collation | Nullable | Default
---------------------------------------------------------------------
x | integer | | |
y | integer | | |
z | integer | | | nextval('seq_0_local_table'::regclass)
-- check sequence type -> since it was used in a distributed table
-- type has changed to the type of the column it was used
-- in this case column z is of type int
\d seq_0
Sequence "sequence_default.seq_0"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------------------------------------------------------------------
integer | 1 | 1 | 2147483647 | 1 | no | 1
\d seq_0_local_table
Sequence "sequence_default.seq_0_local_table"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------------------------------------------------------------------
integer | 1 | 1 | 2147483647 | 1 | no | 1
-- cannot change the type of a sequence used in a distributed table
-- even if metadata is not synced to workers
ALTER SEQUENCE seq_0 AS bigint;
ERROR: Altering a sequence used in a distributed table is currently not supported.
ALTER SEQUENCE seq_0_local_table AS bigint;
ERROR: Altering a sequence used in a local table that is added to metadata is currently not supported.
-- we can change other things like increment
-- if metadata is not synced to workers
ALTER SEQUENCE seq_0 INCREMENT BY 2;
ALTER SEQUENCE seq_0_local_table INCREMENT BY 2;
\d seq_0
Sequence "sequence_default.seq_0"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------------------------------------------------------------------
integer | 1 | 1 | 2147483647 | 2 | no | 1
\d seq_0_local_table
Sequence "sequence_default.seq_0_local_table"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------------------------------------------------------------------
integer | 1 | 1 | 2147483647 | 2 | no | 1
-- check that we can add serial pseudo-type columns -- check that we can add serial pseudo-type columns
-- when metadata is not yet synced to workers -- when metadata is not yet synced to workers
TRUNCATE seq_test_0; TRUNCATE seq_test_0;
@ -56,11 +158,22 @@ ALTER TABLE seq_test_0 ADD COLUMN w10 serial;
ALTER TABLE seq_test_0 ADD COLUMN w11 serial4; ALTER TABLE seq_test_0 ADD COLUMN w11 serial4;
ALTER TABLE seq_test_0 ADD COLUMN w20 bigserial; ALTER TABLE seq_test_0 ADD COLUMN w20 bigserial;
ALTER TABLE seq_test_0 ADD COLUMN w21 serial8; ALTER TABLE seq_test_0 ADD COLUMN w21 serial8;
TRUNCATE seq_test_0_local_table;
ALTER TABLE seq_test_0_local_table ADD COLUMN w00 smallserial;
ALTER TABLE seq_test_0_local_table ADD COLUMN w01 serial2;
ALTER TABLE seq_test_0_local_table ADD COLUMN w10 serial;
ALTER TABLE seq_test_0_local_table ADD COLUMN w11 serial4;
ALTER TABLE seq_test_0_local_table ADD COLUMN w20 bigserial;
ALTER TABLE seq_test_0_local_table ADD COLUMN w21 serial8;
-- check alter column type precaution -- check alter column type precaution
ALTER TABLE seq_test_0 ALTER COLUMN z TYPE bigint; ALTER TABLE seq_test_0 ALTER COLUMN z TYPE bigint;
ERROR: cannot execute ALTER COLUMN TYPE .. command because the column involves a default coming from a sequence ERROR: cannot execute ALTER COLUMN TYPE .. command because the column involves a default coming from a sequence
ALTER TABLE seq_test_0 ALTER COLUMN z TYPE smallint; ALTER TABLE seq_test_0 ALTER COLUMN z TYPE smallint;
ERROR: cannot execute ALTER COLUMN TYPE .. command because the column involves a default coming from a sequence ERROR: cannot execute ALTER COLUMN TYPE .. command because the column involves a default coming from a sequence
ALTER TABLE seq_test_0_local_table ALTER COLUMN z TYPE bigint;
ERROR: cannot execute ALTER COLUMN TYPE .. command because the column involves a default coming from a sequence
ALTER TABLE seq_test_0_local_table ALTER COLUMN z TYPE smallint;
ERROR: cannot execute ALTER COLUMN TYPE .. command because the column involves a default coming from a sequence
-- MX tests -- MX tests
-- check that there's not problem with group ID cache -- check that there's not problem with group ID cache
CREATE TABLE seq_test_4 (x int, y int); CREATE TABLE seq_test_4 (x int, y int);
@ -91,6 +204,19 @@ INSERT INTO sequence_default.seq_test_4 VALUES (1,2) RETURNING *;
1 | 2 | | 268435457 1 | 2 | | 268435457
(1 row) (1 row)
-- check that we have can properly insert to tables from before metadata sync
INSERT INTO sequence_default.seq_test_0 VALUES (1,2) RETURNING *;
x | y | z | w00 | w01 | w10 | w11 | w20 | w21
---------------------------------------------------------------------
1 | 2 | 268435457 | 4097 | 4097 | 268435457 | 268435457 | 281474976710657 | 281474976710657
(1 row)
INSERT INTO sequence_default.seq_test_0_local_table VALUES (1,2) RETURNING *;
x | y | z | w00 | w01 | w10 | w11 | w20 | w21
---------------------------------------------------------------------
1 | 2 | 268435457 | 4097 | 4097 | 268435457 | 268435457 | 281474976710657 | 281474976710657
(1 row)
\c - - - :master_port \c - - - :master_port
SET citus.shard_replication_factor TO 1; SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public; SET search_path = sequence_default, public;
@ -100,7 +226,7 @@ SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
(1 row) (1 row)
-- check sequence type consistency in all nodes -- check sequence type consistency in all nodes for distributed tables
CREATE SEQUENCE seq_1; CREATE SEQUENCE seq_1;
-- type is bigint by default -- type is bigint by default
\d seq_1 \d seq_1
@ -141,10 +267,53 @@ SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
(1 row) (1 row)
-- check sequence type consistency in all nodes for citus local tables
CREATE SEQUENCE seq_1_local_table;
-- type is bigint by default
\d seq_1_local_table
Sequence "sequence_default.seq_1_local_table"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------------------------------------------------------------------
bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1
CREATE TABLE seq_test_1_local_table (x int, y int);
SELECT citus_add_local_table_to_metadata('seq_test_1_local_table');
citus_add_local_table_to_metadata
---------------------------------------------------------------------
(1 row)
ALTER TABLE seq_test_1_local_table ADD COLUMN z int DEFAULT nextval('seq_1_local_table');
-- type is changed to int
\d seq_1_local_table
Sequence "sequence_default.seq_1_local_table"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------------------------------------------------------------------
integer | 1 | 1 | 2147483647 | 1 | no | 1
-- check insertion is within int bounds in the worker
\c - - - :worker_1_port
INSERT INTO sequence_default.seq_test_1_local_table values (1, 2) RETURNING *;
x | y | z
---------------------------------------------------------------------
1 | 2 | 268435457
(1 row)
\c - - - :master_port
SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
start_metadata_sync_to_node
---------------------------------------------------------------------
(1 row)
-- check that we cannot add serial pseudo-type columns -- check that we cannot add serial pseudo-type columns
-- when metadata is synced to workers -- when metadata is synced to workers
ALTER TABLE seq_test_1 ADD COLUMN w bigserial; ALTER TABLE seq_test_1 ADD COLUMN w bigserial;
ERROR: cannot execute ADD COLUMN commands involving serial pseudotypes when metadata is synchronized to workers ERROR: cannot execute ADD COLUMN commands involving serial pseudotypes when metadata is synchronized to workers
ALTER TABLE seq_test_1_local_table ADD COLUMN w bigserial;
ERROR: cannot execute ADD COLUMN commands involving serial pseudotypes when metadata is synchronized to workers
-- check for sequence type clashes -- check for sequence type clashes
CREATE SEQUENCE seq_2; CREATE SEQUENCE seq_2;
CREATE TABLE seq_test_2 (x int, y bigint DEFAULT nextval('seq_2')); CREATE TABLE seq_test_2 (x int, y bigint DEFAULT nextval('seq_2'));
@ -168,6 +337,8 @@ CREATE TABLE seq_test_2_0(x int, y smallint DEFAULT nextval('seq_2'));
-- shouldn't work -- shouldn't work
SELECT create_distributed_table('seq_test_2_0','x'); SELECT create_distributed_table('seq_test_2_0','x');
ERROR: The sequence sequence_default.seq_2 is already used for a different type in column 2 of the table sequence_default.seq_test_2 ERROR: The sequence sequence_default.seq_2 is already used for a different type in column 2 of the table sequence_default.seq_test_2
SELECT citus_add_local_table_to_metadata('seq_test_2_0');
ERROR: The sequence sequence_default.seq_2 is already used for a different type in column 2 of the table sequence_default.seq_test_2
DROP TABLE seq_test_2; DROP TABLE seq_test_2;
DROP TABLE seq_test_2_0; DROP TABLE seq_test_2_0;
-- should work -- should work
@ -183,6 +354,8 @@ CREATE TABLE seq_test_2 (x int, y int DEFAULT nextval('seq_2'), z bigint DEFAULT
-- shouldn't work -- shouldn't work
SELECT create_distributed_table('seq_test_2','x'); SELECT create_distributed_table('seq_test_2','x');
ERROR: The sequence sequence_default.seq_2 is already used for a different type in column 3 of the table sequence_default.seq_test_2 ERROR: The sequence sequence_default.seq_2 is already used for a different type in column 3 of the table sequence_default.seq_test_2
SELECT citus_add_local_table_to_metadata('seq_test_2');
ERROR: The sequence sequence_default.seq_2 is already used for a different type in column 3 of the table sequence_default.seq_test_2
-- check rename is propagated properly -- check rename is propagated properly
ALTER SEQUENCE seq_2 RENAME TO sequence_2; ALTER SEQUENCE seq_2 RENAME TO sequence_2;
-- check in the worker -- check in the worker
@ -202,6 +375,25 @@ SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
(1 row) (1 row)
-- check rename is propagated properly when we use ALTER TABLE
ALTER TABLE sequence_2 RENAME TO seq_2;
-- check in the worker
\c - - - :worker_1_port
\d sequence_default.seq_2
Sequence "sequence_default.seq_2"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------------------------------------------------------------------
bigint | 281474976710657 | 281474976710657 | 562949953421313 | 1 | no | 1
\c - - - :master_port
SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
start_metadata_sync_to_node
---------------------------------------------------------------------
(1 row)
-- check rename with another schema -- check rename with another schema
-- we notice that schema is also propagated as one of the sequence's dependencies -- we notice that schema is also propagated as one of the sequence's dependencies
CREATE SCHEMA sequence_default_0; CREATE SCHEMA sequence_default_0;
@ -354,7 +546,7 @@ CREATE SCHEMA sequence_default_8;
-- can change schema in a sequence not yet distributed -- can change schema in a sequence not yet distributed
ALTER SEQUENCE seq_8 SET SCHEMA sequence_default_8; ALTER SEQUENCE seq_8 SET SCHEMA sequence_default_8;
ALTER SEQUENCE sequence_default_8.seq_8 SET SCHEMA sequence_default; ALTER SEQUENCE sequence_default_8.seq_8 SET SCHEMA sequence_default;
CREATE TABLE seq_test_8 (x int, y int DEFAULT nextval('seq_8')); CREATE TABLE seq_test_8 (x int, y int DEFAULT nextval('seq_8'), z bigserial);
SELECT create_distributed_table('seq_test_8', 'x'); SELECT create_distributed_table('seq_test_8', 'x');
create_distributed_table create_distributed_table
--------------------------------------------------------------------- ---------------------------------------------------------------------
@ -363,29 +555,179 @@ SELECT create_distributed_table('seq_test_8', 'x');
-- cannot change sequence specifications -- cannot change sequence specifications
ALTER SEQUENCE seq_8 AS bigint; ALTER SEQUENCE seq_8 AS bigint;
ERROR: This operation is currently not allowed for a distributed sequence. ERROR: Altering a distributed sequence is currently not supported.
ALTER SEQUENCE seq_8 INCREMENT BY 2; ALTER SEQUENCE seq_8 INCREMENT BY 2;
ERROR: This operation is currently not allowed for a distributed sequence. ERROR: Altering a distributed sequence is currently not supported.
ALTER SEQUENCE seq_8 MINVALUE 5 MAXVALUE 5000; ALTER SEQUENCE seq_8 MINVALUE 5 MAXVALUE 5000;
ERROR: This operation is currently not allowed for a distributed sequence. ERROR: Altering a distributed sequence is currently not supported.
ALTER SEQUENCE seq_8 START WITH 6; ALTER SEQUENCE seq_8 START WITH 6;
ERROR: This operation is currently not allowed for a distributed sequence. ERROR: Altering a distributed sequence is currently not supported.
ALTER SEQUENCE seq_8 RESTART WITH 6; ALTER SEQUENCE seq_8 RESTART WITH 6;
ERROR: This operation is currently not allowed for a distributed sequence. ERROR: Altering a distributed sequence is currently not supported.
ALTER SEQUENCE seq_8 NO CYCLE; ALTER SEQUENCE seq_8 NO CYCLE;
ERROR: This operation is currently not allowed for a distributed sequence. ERROR: Altering a distributed sequence is currently not supported.
ALTER SEQUENCE seq_8 OWNED BY seq_test_7; ALTER SEQUENCE seq_8 OWNED BY seq_test_7;
ERROR: This operation is currently not allowed for a distributed sequence. ERROR: Altering a distributed sequence is currently not supported.
-- cannot change schema in a distributed sequence ALTER SEQUENCE seq_test_8_z_seq AS smallint;
ERROR: Altering a distributed sequence is currently not supported.
ALTER SEQUENCE seq_test_8_z_seq INCREMENT BY 2;
ERROR: Altering a distributed sequence is currently not supported.
ALTER SEQUENCE seq_test_8_z_seq MINVALUE 5 MAXVALUE 5000;
ERROR: Altering a distributed sequence is currently not supported.
ALTER SEQUENCE seq_test_8_z_seq START WITH 6;
ERROR: Altering a distributed sequence is currently not supported.
ALTER SEQUENCE seq_test_8_z_seq RESTART WITH 6;
ERROR: Altering a distributed sequence is currently not supported.
ALTER SEQUENCE seq_test_8_z_seq NO CYCLE;
ERROR: Altering a distributed sequence is currently not supported.
ALTER SEQUENCE seq_test_8_z_seq OWNED BY seq_test_7;
ERROR: cannot alter OWNED BY option of a sequence already owned by a distributed table
-- can change schema in a distributed sequence
-- sequence_default_8 will be created in workers as part of dependencies
ALTER SEQUENCE seq_8 SET SCHEMA sequence_default_8; ALTER SEQUENCE seq_8 SET SCHEMA sequence_default_8;
ERROR: This operation is currently not allowed for a distributed sequence. \c - - - :worker_1_port
\d sequence_default_8.seq_8
Sequence "sequence_default_8.seq_8"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------------------------------------------------------------------
bigint | 268435457 | 268435457 | 536870913 | 1 | no | 1
\c - - - :master_port
SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
start_metadata_sync_to_node
---------------------------------------------------------------------
(1 row)
-- check we can change the schema when we use ALTER TABLE
ALTER TABLE sequence_default_8.seq_8 SET SCHEMA sequence_default;
\c - - - :worker_1_port
\d sequence_default.seq_8
Sequence "sequence_default.seq_8"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------------------------------------------------------------------
bigint | 268435457 | 268435457 | 536870913 | 1 | no | 1
\c - - - :master_port
SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
start_metadata_sync_to_node
---------------------------------------------------------------------
(1 row)
DROP SCHEMA sequence_default_8; DROP SCHEMA sequence_default_8;
SELECT run_command_on_workers('DROP SCHEMA IF EXISTS sequence_default_8 CASCADE');
run_command_on_workers
---------------------------------------------------------------------
(localhost,57637,t,"DROP SCHEMA")
(localhost,57638,t,"DROP SCHEMA")
(2 rows)
-- cannot use more than one sequence in a column default -- cannot use more than one sequence in a column default
CREATE SEQUENCE seq_9; CREATE SEQUENCE seq_9;
CREATE SEQUENCE seq_10; CREATE SEQUENCE seq_10;
CREATE TABLE seq_test_9 (x int, y int DEFAULT nextval('seq_9') - nextval('seq_10')); CREATE TABLE seq_test_9 (x int, y int DEFAULT nextval('seq_9') - nextval('seq_10'));
SELECT create_distributed_table('seq_test_9', 'x'); SELECT create_distributed_table('seq_test_9', 'x');
ERROR: More than one sequence in a column default is not supported for distribution ERROR: More than one sequence in a column default is not supported for distribution
SELECT citus_add_local_table_to_metadata('seq_test_9');
ERROR: More than one sequence in a column default is not supported for adding local tables to metadata
ALTER TABLE seq_test_9 ALTER COLUMN y SET DEFAULT nextval('seq_9');
SELECT create_distributed_table('seq_test_9', 'x');
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- we can change the owner role of a sequence
CREATE ROLE seq_role_0;
NOTICE: not propagating CREATE ROLE/USER commands to worker nodes
HINT: Connect to worker nodes directly to manually create all necessary users and roles.
CREATE ROLE seq_role_1;
NOTICE: not propagating CREATE ROLE/USER commands to worker nodes
HINT: Connect to worker nodes directly to manually create all necessary users and roles.
ALTER SEQUENCE seq_10 OWNER TO seq_role_0;
SELECT sequencename, sequenceowner FROM pg_sequences WHERE sequencename = 'seq_10' ORDER BY 1, 2;
sequencename | sequenceowner
---------------------------------------------------------------------
seq_10 | seq_role_0
(1 row)
SELECT run_command_on_workers('CREATE ROLE seq_role_0');
run_command_on_workers
---------------------------------------------------------------------
(localhost,57637,t,"CREATE ROLE")
(localhost,57638,t,"CREATE ROLE")
(2 rows)
SELECT run_command_on_workers('CREATE ROLE seq_role_1');
run_command_on_workers
---------------------------------------------------------------------
(localhost,57637,t,"CREATE ROLE")
(localhost,57638,t,"CREATE ROLE")
(2 rows)
ALTER TABLE seq_test_9 ALTER COLUMN y SET DEFAULT nextval('seq_10');
ALTER SEQUENCE seq_10 OWNER TO seq_role_1;
SELECT sequencename, sequenceowner FROM pg_sequences WHERE sequencename = 'seq_10' ORDER BY 1, 2;
sequencename | sequenceowner
---------------------------------------------------------------------
seq_10 | seq_role_1
(1 row)
\c - - - :worker_1_port
SELECT sequencename, sequenceowner FROM pg_sequences WHERE sequencename = 'seq_10' ORDER BY 1, 2;
sequencename | sequenceowner
---------------------------------------------------------------------
seq_10 | seq_role_1
(1 row)
\c - - - :master_port
SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
start_metadata_sync_to_node
---------------------------------------------------------------------
(1 row)
-- check we can change the owner role of a sequence when we use ALTER TABLE
ALTER TABLE seq_10 OWNER TO seq_role_0;
SELECT sequencename, sequenceowner FROM pg_sequences WHERE sequencename = 'seq_10' ORDER BY 1, 2;
sequencename | sequenceowner
---------------------------------------------------------------------
seq_10 | seq_role_0
(1 row)
\c - - - :worker_1_port
SELECT sequencename, sequenceowner FROM pg_sequences WHERE sequencename = 'seq_10' ORDER BY 1, 2;
sequencename | sequenceowner
---------------------------------------------------------------------
seq_10 | seq_role_0
(1 row)
\c - - - :master_port
SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
start_metadata_sync_to_node
---------------------------------------------------------------------
(1 row)
DROP SEQUENCE seq_10 CASCADE;
NOTICE: drop cascades to default value for column y of table seq_test_9
DROP ROLE seq_role_0, seq_role_1;
SELECT run_command_on_workers('DROP ROLE IF EXISTS seq_role_0, seq_role_1');
run_command_on_workers
---------------------------------------------------------------------
(localhost,57637,t,"DROP ROLE")
(localhost,57638,t,"DROP ROLE")
(2 rows)
-- Check some cases when default is defined by -- Check some cases when default is defined by
-- DEFAULT nextval('seq_name'::text) (not by DEFAULT nextval('seq_name')) -- DEFAULT nextval('seq_name'::text) (not by DEFAULT nextval('seq_name'))
SELECT stop_metadata_sync_to_node('localhost', :worker_1_port); SELECT stop_metadata_sync_to_node('localhost', :worker_1_port);
@ -426,14 +768,20 @@ ERROR: relation "seq_11" does not exist
-- clean up -- clean up
DROP TABLE sequence_default.seq_test_7_par; DROP TABLE sequence_default.seq_test_7_par;
DROP SCHEMA sequence_default CASCADE; DROP SCHEMA sequence_default CASCADE;
NOTICE: drop cascades to 23 other objects NOTICE: drop cascades to 29 other objects
DETAIL: drop cascades to sequence sequence_default.seq_0 DETAIL: drop cascades to sequence sequence_default.seq_0
drop cascades to sequence sequence_default.seq_0_local_table
drop cascades to table sequence_default.seq_test_0 drop cascades to table sequence_default.seq_test_0
drop cascades to table sequence_default.seq_test_0_local_table_890004
drop cascades to table sequence_default.seq_test_0_local_table
drop cascades to table sequence_default.seq_test_4 drop cascades to table sequence_default.seq_test_4
drop cascades to sequence sequence_default.seq_4 drop cascades to sequence sequence_default.seq_4
drop cascades to sequence sequence_default.seq_1 drop cascades to sequence sequence_default.seq_1
drop cascades to table sequence_default.seq_test_1 drop cascades to table sequence_default.seq_test_1
drop cascades to sequence sequence_default.sequence_2 drop cascades to sequence sequence_default.seq_1_local_table
drop cascades to table sequence_default.seq_test_1_local_table_102016
drop cascades to table sequence_default.seq_test_1_local_table
drop cascades to sequence sequence_default.seq_2
drop cascades to table sequence_default.seq_test_2 drop cascades to table sequence_default.seq_test_2
drop cascades to table sequence_default.seq_test_3 drop cascades to table sequence_default.seq_test_3
drop cascades to table sequence_default.seq_test_5 drop cascades to table sequence_default.seq_test_5
@ -445,10 +793,10 @@ drop cascades to sequence sequence_default.seq_7_par
drop cascades to sequence sequence_default.seq_8 drop cascades to sequence sequence_default.seq_8
drop cascades to table sequence_default.seq_test_8 drop cascades to table sequence_default.seq_test_8
drop cascades to sequence sequence_default.seq_9 drop cascades to sequence sequence_default.seq_9
drop cascades to sequence sequence_default.seq_10
drop cascades to table sequence_default.seq_test_9 drop cascades to table sequence_default.seq_test_9
drop cascades to sequence sequence_default.seq_11 drop cascades to sequence sequence_default.seq_11
drop cascades to table sequence_default.seq_test_10 drop cascades to table sequence_default.seq_test_10
drop cascades to table sequence_default.seq_test_10_102060
drop cascades to table sequence_default.seq_test_11 drop cascades to table sequence_default.seq_test_11
SELECT run_command_on_workers('DROP SCHEMA IF EXISTS sequence_default CASCADE'); SELECT run_command_on_workers('DROP SCHEMA IF EXISTS sequence_default CASCADE');
run_command_on_workers run_command_on_workers
@ -463,4 +811,10 @@ SELECT stop_metadata_sync_to_node('localhost', :worker_1_port);
(1 row) (1 row)
SELECT master_remove_node('localhost', :master_port);
master_remove_node
---------------------------------------------------------------------
(1 row)
SET search_path TO public; SET search_path TO public;

View File

@ -116,9 +116,7 @@ HINT: Use a sequence in a distributed table by specifying a serial column type
CREATE SEQUENCE standalone_sequence; CREATE SEQUENCE standalone_sequence;
ALTER SEQUENCE standalone_sequence OWNED BY testserialtable.group_id; ALTER SEQUENCE standalone_sequence OWNED BY testserialtable.group_id;
-- an edge case, but it's OK to change an owner to the same distributed table -- an edge case, but it's OK to change an owner to the same distributed table
-- EDIT: this doesn't work for now for a distributed sequence
ALTER SEQUENCE testserialtable_id_seq OWNED BY testserialtable.id; ALTER SEQUENCE testserialtable_id_seq OWNED BY testserialtable.id;
ERROR: This operation is currently not allowed for a distributed sequence.
-- drop distributed table -- drop distributed table
\c - - - :master_port \c - - - :master_port
DROP TABLE testserialtable; DROP TABLE testserialtable;

View File

@ -11,18 +11,51 @@ CREATE SCHEMA sequence_default;
SET search_path = sequence_default, public; SET search_path = sequence_default, public;
-- test both distributed and citus local tables
SELECT 1 FROM citus_add_node('localhost', :master_port, groupId => 0);
-- Cannot add a column involving DEFAULT nextval('..') because the table is not empty -- Cannot add a column involving DEFAULT nextval('..') because the table is not empty
CREATE SEQUENCE seq_0; CREATE SEQUENCE seq_0;
CREATE SEQUENCE seq_0_local_table;
-- check sequence type & other things
\d seq_0
\d seq_0_local_table
-- we can change the type of the sequence before using it in distributed tables
ALTER SEQUENCE seq_0 AS smallint;
\d seq_0
CREATE TABLE seq_test_0 (x int, y int); CREATE TABLE seq_test_0 (x int, y int);
CREATE TABLE seq_test_0_local_table (x int, y int);
SELECT create_distributed_table('seq_test_0','x'); SELECT create_distributed_table('seq_test_0','x');
SELECT citus_add_local_table_to_metadata('seq_test_0_local_table');
INSERT INTO seq_test_0 SELECT 1, s FROM generate_series(1, 50) s; INSERT INTO seq_test_0 SELECT 1, s FROM generate_series(1, 50) s;
INSERT INTO seq_test_0_local_table SELECT 1, s FROM generate_series(1, 50) s;
ALTER TABLE seq_test_0 ADD COLUMN z int DEFAULT nextval('seq_0'); ALTER TABLE seq_test_0 ADD COLUMN z int DEFAULT nextval('seq_0');
ALTER TABLE seq_test_0_local_table ADD COLUMN z int DEFAULT nextval('seq_0_local_table');
ALTER TABLE seq_test_0 ADD COLUMN z serial; ALTER TABLE seq_test_0 ADD COLUMN z serial;
ALTER TABLE seq_test_0_local_table ADD COLUMN z serial;
-- follow hint -- follow hint
ALTER TABLE seq_test_0 ADD COLUMN z int; ALTER TABLE seq_test_0 ADD COLUMN z int;
ALTER TABLE seq_test_0 ALTER COLUMN z SET DEFAULT nextval('seq_0'); ALTER TABLE seq_test_0 ALTER COLUMN z SET DEFAULT nextval('seq_0');
SELECT * FROM seq_test_0 ORDER BY 1, 2 LIMIT 5; SELECT * FROM seq_test_0 ORDER BY 1, 2 LIMIT 5;
\d seq_test_0 \d seq_test_0
ALTER TABLE seq_test_0_local_table ADD COLUMN z int;
ALTER TABLE seq_test_0_local_table ALTER COLUMN z SET DEFAULT nextval('seq_0_local_table');
SELECT * FROM seq_test_0_local_table ORDER BY 1, 2 LIMIT 5;
\d seq_test_0_local_table
-- check sequence type -> since it was used in a distributed table
-- type has changed to the type of the column it was used
-- in this case column z is of type int
\d seq_0
\d seq_0_local_table
-- cannot change the type of a sequence used in a distributed table
-- even if metadata is not synced to workers
ALTER SEQUENCE seq_0 AS bigint;
ALTER SEQUENCE seq_0_local_table AS bigint;
-- we can change other things like increment
-- if metadata is not synced to workers
ALTER SEQUENCE seq_0 INCREMENT BY 2;
ALTER SEQUENCE seq_0_local_table INCREMENT BY 2;
\d seq_0
\d seq_0_local_table
-- check that we can add serial pseudo-type columns -- check that we can add serial pseudo-type columns
@ -35,10 +68,21 @@ ALTER TABLE seq_test_0 ADD COLUMN w11 serial4;
ALTER TABLE seq_test_0 ADD COLUMN w20 bigserial; ALTER TABLE seq_test_0 ADD COLUMN w20 bigserial;
ALTER TABLE seq_test_0 ADD COLUMN w21 serial8; ALTER TABLE seq_test_0 ADD COLUMN w21 serial8;
TRUNCATE seq_test_0_local_table;
ALTER TABLE seq_test_0_local_table ADD COLUMN w00 smallserial;
ALTER TABLE seq_test_0_local_table ADD COLUMN w01 serial2;
ALTER TABLE seq_test_0_local_table ADD COLUMN w10 serial;
ALTER TABLE seq_test_0_local_table ADD COLUMN w11 serial4;
ALTER TABLE seq_test_0_local_table ADD COLUMN w20 bigserial;
ALTER TABLE seq_test_0_local_table ADD COLUMN w21 serial8;
-- check alter column type precaution -- check alter column type precaution
ALTER TABLE seq_test_0 ALTER COLUMN z TYPE bigint; ALTER TABLE seq_test_0 ALTER COLUMN z TYPE bigint;
ALTER TABLE seq_test_0 ALTER COLUMN z TYPE smallint; ALTER TABLE seq_test_0 ALTER COLUMN z TYPE smallint;
ALTER TABLE seq_test_0_local_table ALTER COLUMN z TYPE bigint;
ALTER TABLE seq_test_0_local_table ALTER COLUMN z TYPE smallint;
-- MX tests -- MX tests
@ -55,13 +99,18 @@ ALTER TABLE seq_test_4 ADD COLUMN b int DEFAULT nextval('seq_4');
-- on worker it should generate high sequence number -- on worker it should generate high sequence number
\c - - - :worker_1_port \c - - - :worker_1_port
INSERT INTO sequence_default.seq_test_4 VALUES (1,2) RETURNING *; INSERT INTO sequence_default.seq_test_4 VALUES (1,2) RETURNING *;
-- check that we have can properly insert to tables from before metadata sync
INSERT INTO sequence_default.seq_test_0 VALUES (1,2) RETURNING *;
INSERT INTO sequence_default.seq_test_0_local_table VALUES (1,2) RETURNING *;
\c - - - :master_port \c - - - :master_port
SET citus.shard_replication_factor TO 1; SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public; SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port); SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
-- check sequence type consistency in all nodes -- check sequence type consistency in all nodes for distributed tables
CREATE SEQUENCE seq_1; CREATE SEQUENCE seq_1;
-- type is bigint by default -- type is bigint by default
\d seq_1 \d seq_1
@ -79,9 +128,28 @@ SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port); SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
-- check sequence type consistency in all nodes for citus local tables
CREATE SEQUENCE seq_1_local_table;
-- type is bigint by default
\d seq_1_local_table
CREATE TABLE seq_test_1_local_table (x int, y int);
SELECT citus_add_local_table_to_metadata('seq_test_1_local_table');
ALTER TABLE seq_test_1_local_table ADD COLUMN z int DEFAULT nextval('seq_1_local_table');
-- type is changed to int
\d seq_1_local_table
-- check insertion is within int bounds in the worker
\c - - - :worker_1_port
INSERT INTO sequence_default.seq_test_1_local_table values (1, 2) RETURNING *;
\c - - - :master_port
SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
-- check that we cannot add serial pseudo-type columns -- check that we cannot add serial pseudo-type columns
-- when metadata is synced to workers -- when metadata is synced to workers
ALTER TABLE seq_test_1 ADD COLUMN w bigserial; ALTER TABLE seq_test_1 ADD COLUMN w bigserial;
ALTER TABLE seq_test_1_local_table ADD COLUMN w bigserial;
-- check for sequence type clashes -- check for sequence type clashes
@ -96,6 +164,7 @@ SELECT create_distributed_table('seq_test_2','x');
CREATE TABLE seq_test_2_0(x int, y smallint DEFAULT nextval('seq_2')); CREATE TABLE seq_test_2_0(x int, y smallint DEFAULT nextval('seq_2'));
-- shouldn't work -- shouldn't work
SELECT create_distributed_table('seq_test_2_0','x'); SELECT create_distributed_table('seq_test_2_0','x');
SELECT citus_add_local_table_to_metadata('seq_test_2_0');
DROP TABLE seq_test_2; DROP TABLE seq_test_2;
DROP TABLE seq_test_2_0; DROP TABLE seq_test_2_0;
-- should work -- should work
@ -105,6 +174,7 @@ DROP TABLE seq_test_2;
CREATE TABLE seq_test_2 (x int, y int DEFAULT nextval('seq_2'), z bigint DEFAULT nextval('seq_2')); CREATE TABLE seq_test_2 (x int, y int DEFAULT nextval('seq_2'), z bigint DEFAULT nextval('seq_2'));
-- shouldn't work -- shouldn't work
SELECT create_distributed_table('seq_test_2','x'); SELECT create_distributed_table('seq_test_2','x');
SELECT citus_add_local_table_to_metadata('seq_test_2');
-- check rename is propagated properly -- check rename is propagated properly
@ -116,6 +186,15 @@ ALTER SEQUENCE seq_2 RENAME TO sequence_2;
SET citus.shard_replication_factor TO 1; SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public; SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port); SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
-- check rename is propagated properly when we use ALTER TABLE
ALTER TABLE sequence_2 RENAME TO seq_2;
-- check in the worker
\c - - - :worker_1_port
\d sequence_default.seq_2
\c - - - :master_port
SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
-- check rename with another schema -- check rename with another schema
-- we notice that schema is also propagated as one of the sequence's dependencies -- we notice that schema is also propagated as one of the sequence's dependencies
CREATE SCHEMA sequence_default_0; CREATE SCHEMA sequence_default_0;
@ -195,7 +274,7 @@ CREATE SCHEMA sequence_default_8;
-- can change schema in a sequence not yet distributed -- can change schema in a sequence not yet distributed
ALTER SEQUENCE seq_8 SET SCHEMA sequence_default_8; ALTER SEQUENCE seq_8 SET SCHEMA sequence_default_8;
ALTER SEQUENCE sequence_default_8.seq_8 SET SCHEMA sequence_default; ALTER SEQUENCE sequence_default_8.seq_8 SET SCHEMA sequence_default;
CREATE TABLE seq_test_8 (x int, y int DEFAULT nextval('seq_8')); CREATE TABLE seq_test_8 (x int, y int DEFAULT nextval('seq_8'), z bigserial);
SELECT create_distributed_table('seq_test_8', 'x'); SELECT create_distributed_table('seq_test_8', 'x');
-- cannot change sequence specifications -- cannot change sequence specifications
ALTER SEQUENCE seq_8 AS bigint; ALTER SEQUENCE seq_8 AS bigint;
@ -205,9 +284,32 @@ ALTER SEQUENCE seq_8 START WITH 6;
ALTER SEQUENCE seq_8 RESTART WITH 6; ALTER SEQUENCE seq_8 RESTART WITH 6;
ALTER SEQUENCE seq_8 NO CYCLE; ALTER SEQUENCE seq_8 NO CYCLE;
ALTER SEQUENCE seq_8 OWNED BY seq_test_7; ALTER SEQUENCE seq_8 OWNED BY seq_test_7;
-- cannot change schema in a distributed sequence ALTER SEQUENCE seq_test_8_z_seq AS smallint;
ALTER SEQUENCE seq_test_8_z_seq INCREMENT BY 2;
ALTER SEQUENCE seq_test_8_z_seq MINVALUE 5 MAXVALUE 5000;
ALTER SEQUENCE seq_test_8_z_seq START WITH 6;
ALTER SEQUENCE seq_test_8_z_seq RESTART WITH 6;
ALTER SEQUENCE seq_test_8_z_seq NO CYCLE;
ALTER SEQUENCE seq_test_8_z_seq OWNED BY seq_test_7;
-- can change schema in a distributed sequence
-- sequence_default_8 will be created in workers as part of dependencies
ALTER SEQUENCE seq_8 SET SCHEMA sequence_default_8; ALTER SEQUENCE seq_8 SET SCHEMA sequence_default_8;
\c - - - :worker_1_port
\d sequence_default_8.seq_8
\c - - - :master_port
SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
-- check we can change the schema when we use ALTER TABLE
ALTER TABLE sequence_default_8.seq_8 SET SCHEMA sequence_default;
\c - - - :worker_1_port
\d sequence_default.seq_8
\c - - - :master_port
SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
DROP SCHEMA sequence_default_8; DROP SCHEMA sequence_default_8;
SELECT run_command_on_workers('DROP SCHEMA IF EXISTS sequence_default_8 CASCADE');
-- cannot use more than one sequence in a column default -- cannot use more than one sequence in a column default
@ -215,6 +317,39 @@ CREATE SEQUENCE seq_9;
CREATE SEQUENCE seq_10; CREATE SEQUENCE seq_10;
CREATE TABLE seq_test_9 (x int, y int DEFAULT nextval('seq_9') - nextval('seq_10')); CREATE TABLE seq_test_9 (x int, y int DEFAULT nextval('seq_9') - nextval('seq_10'));
SELECT create_distributed_table('seq_test_9', 'x'); SELECT create_distributed_table('seq_test_9', 'x');
SELECT citus_add_local_table_to_metadata('seq_test_9');
ALTER TABLE seq_test_9 ALTER COLUMN y SET DEFAULT nextval('seq_9');
SELECT create_distributed_table('seq_test_9', 'x');
-- we can change the owner role of a sequence
CREATE ROLE seq_role_0;
CREATE ROLE seq_role_1;
ALTER SEQUENCE seq_10 OWNER TO seq_role_0;
SELECT sequencename, sequenceowner FROM pg_sequences WHERE sequencename = 'seq_10' ORDER BY 1, 2;
SELECT run_command_on_workers('CREATE ROLE seq_role_0');
SELECT run_command_on_workers('CREATE ROLE seq_role_1');
ALTER TABLE seq_test_9 ALTER COLUMN y SET DEFAULT nextval('seq_10');
ALTER SEQUENCE seq_10 OWNER TO seq_role_1;
SELECT sequencename, sequenceowner FROM pg_sequences WHERE sequencename = 'seq_10' ORDER BY 1, 2;
\c - - - :worker_1_port
SELECT sequencename, sequenceowner FROM pg_sequences WHERE sequencename = 'seq_10' ORDER BY 1, 2;
\c - - - :master_port
SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
-- check we can change the owner role of a sequence when we use ALTER TABLE
ALTER TABLE seq_10 OWNER TO seq_role_0;
SELECT sequencename, sequenceowner FROM pg_sequences WHERE sequencename = 'seq_10' ORDER BY 1, 2;
\c - - - :worker_1_port
SELECT sequencename, sequenceowner FROM pg_sequences WHERE sequencename = 'seq_10' ORDER BY 1, 2;
\c - - - :master_port
SET citus.shard_replication_factor TO 1;
SET search_path = sequence_default, public;
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
DROP SEQUENCE seq_10 CASCADE;
DROP ROLE seq_role_0, seq_role_1;
SELECT run_command_on_workers('DROP ROLE IF EXISTS seq_role_0, seq_role_1');
-- Check some cases when default is defined by -- Check some cases when default is defined by
@ -234,9 +369,11 @@ SELECT create_distributed_table('seq_test_11', 'col1');
INSERT INTO sequence_default.seq_test_10 VALUES (1); INSERT INTO sequence_default.seq_test_10 VALUES (1);
\c - - - :master_port \c - - - :master_port
-- clean up -- clean up
DROP TABLE sequence_default.seq_test_7_par; DROP TABLE sequence_default.seq_test_7_par;
DROP SCHEMA sequence_default CASCADE; DROP SCHEMA sequence_default CASCADE;
SELECT run_command_on_workers('DROP SCHEMA IF EXISTS sequence_default CASCADE'); SELECT run_command_on_workers('DROP SCHEMA IF EXISTS sequence_default CASCADE');
SELECT stop_metadata_sync_to_node('localhost', :worker_1_port); SELECT stop_metadata_sync_to_node('localhost', :worker_1_port);
SELECT master_remove_node('localhost', :master_port);
SET search_path TO public; SET search_path TO public;

View File

@ -86,7 +86,6 @@ CREATE SEQUENCE standalone_sequence;
ALTER SEQUENCE standalone_sequence OWNED BY testserialtable.group_id; ALTER SEQUENCE standalone_sequence OWNED BY testserialtable.group_id;
-- an edge case, but it's OK to change an owner to the same distributed table -- an edge case, but it's OK to change an owner to the same distributed table
-- EDIT: this doesn't work for now for a distributed sequence
ALTER SEQUENCE testserialtable_id_seq OWNED BY testserialtable.id; ALTER SEQUENCE testserialtable_id_seq OWNED BY testserialtable.id;
-- drop distributed table -- drop distributed table