diff --git a/src/backend/distributed/commands/non_main_db_distribute_object_ops.c b/src/backend/distributed/commands/non_main_db_distribute_object_ops.c index 393fd023b..b777936d3 100644 --- a/src/backend/distributed/commands/non_main_db_distribute_object_ops.c +++ b/src/backend/distributed/commands/non_main_db_distribute_object_ops.c @@ -11,8 +11,10 @@ * commands from non-main databases. * * To add support for a new command type, one needs to define a new - * NonMainDbDistributeObjectOps object and add it to - * GetNonMainDbDistributeObjectOps. + * NonMainDbDistributeObjectOps object within OperationArray. Also, if + * the command requires marking or unmarking some objects as distributed, + * the necessary operations can be implemented in + * RunPreprocessNonMainDBCommand and RunPostprocessNonMainDBCommand. * *------------------------------------------------------------------------- */ @@ -42,161 +44,82 @@ "SELECT pg_catalog.citus_unmark_object_distributed(%d, %d, %d, %s)" -/* - * Structs used to implement getMarkDistributedParams and - * getUnmarkDistributedParams callbacks for NonMainDbDistributeObjectOps. - * - * Main difference between these two is that while - * MarkDistributedGloballyParams contains the name of the object, the other - * doesn't. This is because, when marking an object -that is created from a - * non-main db- as distributed, citus_internal.mark_object_distributed() - * cannot find its name since the object is not visible to outer transaction - * (or, read as "the transaction in non-main db"). - */ -typedef struct MarkDistributedGloballyParams -{ - char *name; - Oid id; - uint16 catalogRelId; -} MarkDistributedGloballyParams; - -typedef struct UnmarkDistributedLocallyParams -{ - Oid id; - uint16 catalogRelId; -} UnmarkDistributedLocallyParams; - /* * NonMainDbDistributeObjectOps contains the necessary callbacks / flags to * support node-wide object management commands from non-main databases. * - * getMarkDistributedParams / getUnmarkDistributedParams: - * When creating a distributed object, we always have to mark such objects - * as "distributed" but while for some object types we can delegate this to - * main database, for some others we have to explicitly send a command to - * all nodes in this code-path to achieve this. Callers need to implement - * getMarkDistributedParams when that is the case. - * - * Similarly when dropping a distributed object, we always have to unmark - * the target object as "distributed" and our utility hook on remote nodes - * achieve this via UnmarkNodeWideObjectsDistributed() because the commands - * that we send to workers are executed via main db. However for the local - * node, this is not the case as we're not in the main db. For this reason, - * callers need to implement getUnmarkDistributedParams to unmark an object - * for local node as well. - * - * We don't expect both of these to be NULL at the same time. However, it's - * okay if both of these are NULL. - * - * Finally, while getMarkDistributedParams is expected to return "a list of - * objects", this is not the case for getUnmarkDistributedParams. This is - * because, while we expect that a drop command might drop multiple objects - * at once, we don't expect a create command to create multiple objects at - * once. - * * cannotBeExecutedInTransaction: * Indicates whether the statement cannot be executed in a transaction. If * this is set to true, the statement will be executed directly on the main * database because there are no transactional visibility issues for such * commands. * - * And when this is true, we don't expect getMarkDistributedParams and - * getUnmarkDistributedParams to be implemented. + * checkSupportedObjectType: + * Callback function that checks whether type of the object referred to by + * given statement is supported. Can be NULL if not applicable for the + * statement type. */ typedef struct NonMainDbDistributeObjectOps { - MarkDistributedGloballyParams * (*getMarkDistributedParams)(Node * parsetree); - List * (*getUnmarkDistributedParams)(Node * parsetree); bool cannotBeExecutedInTransaction; + bool (*checkSupportedObjectType)(Node *parsetree); } NonMainDbDistributeObjectOps; /* - * getMarkDistributedParams and getUnmarkDistributedParams callbacks for - * NonMainDbDistributeObjectOps. + * checkSupportedObjectType callbacks for OperationArray. */ -static MarkDistributedGloballyParams * CreateRoleStmtGetMarkDistributedParams( - Node *parsetree); -static List * DropRoleStmtGetUnmarkDistributedParams(Node *parsetree); - +static bool CreateDbStmtCheckSupportedObjectType(Node *node); +static bool DropDbStmtCheckSupportedObjectType(Node *node); +static bool GrantStmtCheckSupportedObjectType(Node *node); +static bool SecLabelStmtCheckSupportedObjectType(Node *node); /* - * NonMainDbDistributeObjectOps for different command types. - * - * Naming of these structs are stolen from distribute_object_ops.c. We use - * "Any" if the command doesn't have any other variations or if the struct - * implements it for all its variations. For example, while we name the struct - * for CreateRoleStmt as Any_CreateRole, we name the struct that implements - * SecLabelStmt for role objects as Role_SecLabel. + * OperationArray that holds NonMainDbDistributeObjectOps for different command types. */ -static const NonMainDbDistributeObjectOps Any_CreateRole = { - .getMarkDistributedParams = CreateRoleStmtGetMarkDistributedParams, - .getUnmarkDistributedParams = NULL, - .cannotBeExecutedInTransaction = false -}; -static const NonMainDbDistributeObjectOps Any_DropRole = { - .getMarkDistributedParams = NULL, - .getUnmarkDistributedParams = DropRoleStmtGetUnmarkDistributedParams, - .cannotBeExecutedInTransaction = false -}; -static const NonMainDbDistributeObjectOps Any_AlterRole = { - .getMarkDistributedParams = NULL, - .getUnmarkDistributedParams = NULL, - .cannotBeExecutedInTransaction = false -}; -static const NonMainDbDistributeObjectOps Any_GrantRole = { - .getMarkDistributedParams = NULL, - .getUnmarkDistributedParams = NULL, - .cannotBeExecutedInTransaction = false -}; -static const NonMainDbDistributeObjectOps Any_CreateDatabase = { - .getMarkDistributedParams = NULL, - .getUnmarkDistributedParams = NULL, - .cannotBeExecutedInTransaction = true -}; -static const NonMainDbDistributeObjectOps Any_DropDatabase = { - .getMarkDistributedParams = NULL, - .getUnmarkDistributedParams = NULL, - .cannotBeExecutedInTransaction = true -}; - -static const NonMainDbDistributeObjectOps Any_AlterDatabase = { - .getMarkDistributedParams = NULL, - .getUnmarkDistributedParams = NULL, - .cannotBeExecutedInTransaction = true -}; - -static const NonMainDbDistributeObjectOps Any_AlterDatabaseSet = { - .getMarkDistributedParams = NULL, - .getUnmarkDistributedParams = NULL, - .cannotBeExecutedInTransaction = true -}; - -#if PG_VERSION_NUM >= PG_VERSION_15 -static const NonMainDbDistributeObjectOps Any_AlterDatabaseRefreshColl = { - .getMarkDistributedParams = NULL, - .getUnmarkDistributedParams = NULL, - .cannotBeExecutedInTransaction = false -}; -#endif - -static const NonMainDbDistributeObjectOps Database_Grant = { - .getMarkDistributedParams = NULL, - .getUnmarkDistributedParams = NULL, - .cannotBeExecutedInTransaction = false -}; -static const NonMainDbDistributeObjectOps Role_SecLabel = { - .getMarkDistributedParams = NULL, - .getUnmarkDistributedParams = NULL, - .cannotBeExecutedInTransaction = false +static const NonMainDbDistributeObjectOps *const OperationArray[] = { + [T_CreateRoleStmt] = &(NonMainDbDistributeObjectOps) { + .cannotBeExecutedInTransaction = false, + .checkSupportedObjectType = NULL + }, + [T_DropRoleStmt] = &(NonMainDbDistributeObjectOps) { + .cannotBeExecutedInTransaction = false, + .checkSupportedObjectType = NULL + }, + [T_AlterRoleStmt] = &(NonMainDbDistributeObjectOps) { + .cannotBeExecutedInTransaction = false, + .checkSupportedObjectType = NULL + }, + [T_GrantRoleStmt] = &(NonMainDbDistributeObjectOps) { + .cannotBeExecutedInTransaction = false, + .checkSupportedObjectType = NULL + }, + [T_CreatedbStmt] = &(NonMainDbDistributeObjectOps) { + .cannotBeExecutedInTransaction = true, + .checkSupportedObjectType = CreateDbStmtCheckSupportedObjectType + }, + [T_DropdbStmt] = &(NonMainDbDistributeObjectOps) { + .cannotBeExecutedInTransaction = true, + .checkSupportedObjectType = DropDbStmtCheckSupportedObjectType + }, + [T_GrantStmt] = &(NonMainDbDistributeObjectOps) { + .cannotBeExecutedInTransaction = false, + .checkSupportedObjectType = GrantStmtCheckSupportedObjectType + }, + [T_SecLabelStmt] = &(NonMainDbDistributeObjectOps) { + .cannotBeExecutedInTransaction = false, + .checkSupportedObjectType = SecLabelStmtCheckSupportedObjectType + }, }; /* other static function declarations */ const NonMainDbDistributeObjectOps * GetNonMainDbDistributeObjectOps(Node *parsetree); -static void MarkObjectDistributedGloballyOnMainDbs( - MarkDistributedGloballyParams *markDistributedParams); -static void UnmarkObjectsDistributedOnLocalMainDb(List *unmarkDistributedParamsList); +static void CreateRoleStmtMarkDistGloballyOnMainDbs(CreateRoleStmt *createRoleStmt); +static void DropRoleStmtUnmarkDistOnLocalMainDb(DropRoleStmt *dropRoleStmt); +static void MarkObjectDistributedGloballyOnMainDbs(Oid catalogRelId, Oid objectId, + char *objectName); +static void UnmarkObjectDistributedOnLocalMainDb(uint16 catalogRelId, Oid objectId); /* @@ -249,10 +172,9 @@ RunPreprocessNonMainDBCommand(Node *parsetree) quote_literal_cstr(CurrentUserName())); RunCitusMainDBQuery(mainDBQuery->data); - if (ops->getUnmarkDistributedParams) + if (IsA(parsetree, DropRoleStmt)) { - List *unmarkDistributedParamsList = ops->getUnmarkDistributedParams(parsetree); - UnmarkObjectsDistributedOnLocalMainDb(unmarkDistributedParamsList); + DropRoleStmtUnmarkDistOnLocalMainDb((DropRoleStmt *) parsetree); } return false; @@ -266,22 +188,14 @@ RunPreprocessNonMainDBCommand(Node *parsetree) void RunPostprocessNonMainDBCommand(Node *parsetree) { - if (IsMainDB) + if (IsMainDB || !GetNonMainDbDistributeObjectOps(parsetree)) { return; } - const NonMainDbDistributeObjectOps *ops = GetNonMainDbDistributeObjectOps(parsetree); - if (!ops) + if (IsA(parsetree, CreateRoleStmt)) { - return; - } - - if (ops->getMarkDistributedParams) - { - MarkDistributedGloballyParams *markDistributedParams = - ops->getMarkDistributedParams(parsetree); - MarkObjectDistributedGloballyOnMainDbs(markDistributedParams); + CreateRoleStmtMarkDistGloballyOnMainDbs((CreateRoleStmt *) parsetree); } } @@ -294,137 +208,63 @@ RunPostprocessNonMainDBCommand(Node *parsetree) const NonMainDbDistributeObjectOps * GetNonMainDbDistributeObjectOps(Node *parsetree) { - switch (nodeTag(parsetree)) + NodeTag tag = nodeTag(parsetree); + if (tag >= lengthof(OperationArray)) { - case T_CreateRoleStmt: + return NULL; + } + + const NonMainDbDistributeObjectOps *ops = OperationArray[tag]; + + if (ops == NULL) + { + return NULL; + } + + if (!ops->checkSupportedObjectType || + ops->checkSupportedObjectType(parsetree)) + { + return ops; + } + + return NULL; +} + + +/* + * CreateRoleStmtMarkDistGloballyOnMainDbs marks the role as + * distributed on all main databases globally. + */ +static void +CreateRoleStmtMarkDistGloballyOnMainDbs(CreateRoleStmt *createRoleStmt) +{ + /* object must exist as we've just created it */ + bool missingOk = false; + Oid roleId = get_role_oid(createRoleStmt->role, missingOk); + + MarkObjectDistributedGloballyOnMainDbs(AuthIdRelationId, roleId, + createRoleStmt->role); +} + + +/* + * DropRoleStmtUnmarkDistOnLocalMainDb unmarks the roles as + * distributed on the local main database. + */ +static void +DropRoleStmtUnmarkDistOnLocalMainDb(DropRoleStmt *dropRoleStmt) +{ + RoleSpec *roleSpec = NULL; + foreach_ptr(roleSpec, dropRoleStmt->roles) + { + Oid roleOid = get_role_oid(roleSpec->rolename, + dropRoleStmt->missing_ok); + if (roleOid == InvalidOid) { - return &Any_CreateRole; + continue; } - case T_DropRoleStmt: - { - return &Any_DropRole; - } - - case T_AlterRoleStmt: - { - return &Any_AlterRole; - } - - case T_GrantRoleStmt: - { - return &Any_GrantRole; - } - - case T_CreatedbStmt: - { - CreatedbStmt *stmt = castNode(CreatedbStmt, parsetree); - - /* - * We don't try to send the query to the main database if the CREATE - * DATABASE command is for the main database itself, this is a very - * rare case but it's exercised by our test suite. - */ - if (strcmp(stmt->dbname, MainDb) != 0) - { - return &Any_CreateDatabase; - } - - return NULL; - } - - case T_DropdbStmt: - { - DropdbStmt *stmt = castNode(DropdbStmt, parsetree); - - /* - * We don't try to send the query to the main database if the DROP - * DATABASE command is for the main database itself, this is a very - * rare case but it's exercised by our test suite. - */ - if (strcmp(stmt->dbname, MainDb) != 0) - { - return &Any_DropDatabase; - } - - return NULL; - } - - case T_AlterDatabaseStmt: - { - AlterDatabaseStmt *stmt = castNode(AlterDatabaseStmt, parsetree); - - /* - * We don't try to send the query to the main database if the ALTER - * DATABASE command is for the main database itself, this is a very - * rare case but it's exercised by our test suite. - */ - if (strcmp(stmt->dbname, MainDb) != 0) - { - return &Any_AlterDatabase; - } - - return NULL; - } - - case T_AlterDatabaseSetStmt: - { - AlterDatabaseSetStmt *stmt = castNode(AlterDatabaseSetStmt, parsetree); - - /* - * We don't try to send the query to the main database if the ALTER - * DATABASE command is for the main database itself, this is a very - * rare case but it's exercised by our test suite. - */ - if (strcmp(stmt->dbname, MainDb) != 0) - { - return &Any_AlterDatabaseSet; - } - - return NULL; - } - -#if PG_VERSION_NUM >= PG_VERSION_15 - case T_AlterDatabaseRefreshCollStmt: - { - return &Any_AlterDatabaseRefreshColl; - } -#endif - - case T_GrantStmt: - { - GrantStmt *stmt = castNode(GrantStmt, parsetree); - - switch (stmt->objtype) - { - case OBJECT_DATABASE: - { - return &Database_Grant; - } - - default: - return NULL; - } - } - - case T_SecLabelStmt: - { - SecLabelStmt *stmt = castNode(SecLabelStmt, parsetree); - - switch (stmt->objtype) - { - case OBJECT_ROLE: - { - return &Role_SecLabel; - } - - default: - return NULL; - } - } - - default: - return NULL; + UnmarkObjectDistributedOnLocalMainDb(AuthIdRelationId, roleOid); } } @@ -434,90 +274,78 @@ GetNonMainDbDistributeObjectOps(Node *parsetree) * distributed on all main databases globally. */ static void -MarkObjectDistributedGloballyOnMainDbs( - MarkDistributedGloballyParams *markDistributedParams) +MarkObjectDistributedGloballyOnMainDbs(Oid catalogRelId, Oid objectId, char *objectName) { StringInfo mainDBQuery = makeStringInfo(); appendStringInfo(mainDBQuery, MARK_OBJECT_DISTRIBUTED, - markDistributedParams->catalogRelId, - quote_literal_cstr(markDistributedParams->name), - markDistributedParams->id, + catalogRelId, + quote_literal_cstr(objectName), + objectId, quote_literal_cstr(CurrentUserName())); RunCitusMainDBQuery(mainDBQuery->data); } /* - * UnmarkObjectsDistributedOnLocalMainDb unmarks a list of objects as + * UnmarkObjectDistributedOnLocalMainDb unmarks an object as * distributed on the local main database. */ static void -UnmarkObjectsDistributedOnLocalMainDb(List *unmarkDistributedParamsList) +UnmarkObjectDistributedOnLocalMainDb(uint16 catalogRelId, Oid objectId) { - int subObjectId = 0; - char *checkObjectExistence = "false"; + const int subObjectId = 0; + const char *checkObjectExistence = "false"; - UnmarkDistributedLocallyParams *unmarkDistributedParams = NULL; - foreach_ptr(unmarkDistributedParams, unmarkDistributedParamsList) - { - StringInfo query = makeStringInfo(); - appendStringInfo(query, - UNMARK_OBJECT_DISTRIBUTED, - unmarkDistributedParams->catalogRelId, - unmarkDistributedParams->id, - subObjectId, checkObjectExistence); - RunCitusMainDBQuery(query->data); - } + StringInfo query = makeStringInfo(); + appendStringInfo(query, + UNMARK_OBJECT_DISTRIBUTED, + catalogRelId, objectId, + subObjectId, checkObjectExistence); + RunCitusMainDBQuery(query->data); } /* - * getMarkDistributedParams and getUnmarkDistributedParams callback implementations - * for NonMainDbDistributeObjectOps start here. + * checkSupportedObjectTypes callbacks for OperationArray lie below. */ -static MarkDistributedGloballyParams * -CreateRoleStmtGetMarkDistributedParams(Node *parsetree) +static bool +CreateDbStmtCheckSupportedObjectType(Node *node) { - CreateRoleStmt *stmt = castNode(CreateRoleStmt, parsetree); - MarkDistributedGloballyParams *params = - (MarkDistributedGloballyParams *) palloc(sizeof(MarkDistributedGloballyParams)); - params->name = stmt->role; - params->catalogRelId = AuthIdRelationId; - - /* object must exist as we've just created it */ - bool missingOk = false; - params->id = get_role_oid(stmt->role, missingOk); - - return params; + /* + * We don't try to send the query to the main database if the CREATE + * DATABASE command is for the main database itself, this is a very + * rare case but it's exercised by our test suite. + */ + CreatedbStmt *stmt = castNode(CreatedbStmt, node); + return strcmp(stmt->dbname, MainDb) != 0; } -static List * -DropRoleStmtGetUnmarkDistributedParams(Node *parsetree) +static bool +DropDbStmtCheckSupportedObjectType(Node *node) { - DropRoleStmt *stmt = castNode(DropRoleStmt, parsetree); - - List *paramsList = NIL; - - RoleSpec *roleSpec = NULL; - foreach_ptr(roleSpec, stmt->roles) - { - UnmarkDistributedLocallyParams *params = - (UnmarkDistributedLocallyParams *) palloc( - sizeof(UnmarkDistributedLocallyParams)); - - Oid roleOid = get_role_oid(roleSpec->rolename, stmt->missing_ok); - if (roleOid == InvalidOid) - { - continue; - } - - params->id = roleOid; - params->catalogRelId = AuthIdRelationId; - - paramsList = lappend(paramsList, params); - } - - return paramsList; + /* + * We don't try to send the query to the main database if the DROP + * DATABASE command is for the main database itself, this is a very + * rare case but it's exercised by our test suite. + */ + DropdbStmt *stmt = castNode(DropdbStmt, node); + return strcmp(stmt->dbname, MainDb) != 0; +} + + +static bool +GrantStmtCheckSupportedObjectType(Node *node) +{ + GrantStmt *stmt = castNode(GrantStmt, node); + return stmt->objtype == OBJECT_DATABASE; +} + + +static bool +SecLabelStmtCheckSupportedObjectType(Node *node) +{ + SecLabelStmt *stmt = castNode(SecLabelStmt, node); + return stmt->objtype == OBJECT_ROLE; } diff --git a/src/backend/distributed/commands/role.c b/src/backend/distributed/commands/role.c index f2b567e6e..7f5f697f2 100644 --- a/src/backend/distributed/commands/role.c +++ b/src/backend/distributed/commands/role.c @@ -491,18 +491,17 @@ GenerateRoleOptionsList(HeapTuple tuple) options = lappend(options, makeDefElem("password", NULL, -1)); } - /* load valid unitl data from the heap tuple, use default of infinity if not set */ + /* load valid until data from the heap tuple */ Datum rolValidUntilDatum = SysCacheGetAttr(AUTHNAME, tuple, Anum_pg_authid_rolvaliduntil, &isNull); - char *rolValidUntil = "infinity"; if (!isNull) { - rolValidUntil = pstrdup((char *) timestamptz_to_str(rolValidUntilDatum)); - } + char *rolValidUntil = pstrdup((char *) timestamptz_to_str(rolValidUntilDatum)); - Node *validUntilStringNode = (Node *) makeString(rolValidUntil); - DefElem *validUntilOption = makeDefElem("validUntil", validUntilStringNode, -1); - options = lappend(options, validUntilOption); + Node *validUntilStringNode = (Node *) makeString(rolValidUntil); + DefElem *validUntilOption = makeDefElem("validUntil", validUntilStringNode, -1); + options = lappend(options, validUntilOption); + } return options; } diff --git a/src/backend/distributed/commands/table.c b/src/backend/distributed/commands/table.c index 074a789ed..30b028b79 100644 --- a/src/backend/distributed/commands/table.c +++ b/src/backend/distributed/commands/table.c @@ -3053,11 +3053,15 @@ ErrorUnsupportedAlterTableAddColumn(Oid relationId, AlterTableCmd *command, else if (constraint->contype == CONSTR_FOREIGN) { RangeVar *referencedTable = constraint->pktable; - char *referencedColumn = strVal(lfirst(list_head(constraint->pk_attrs))); Oid referencedRelationId = RangeVarGetRelid(referencedTable, NoLock, false); - appendStringInfo(errHint, "FOREIGN KEY (%s) REFERENCES %s(%s)", colName, - get_rel_name(referencedRelationId), referencedColumn); + appendStringInfo(errHint, "FOREIGN KEY (%s) REFERENCES %s", colName, + get_rel_name(referencedRelationId)); + + if (list_length(constraint->pk_attrs) > 0) + { + AppendColumnNameList(errHint, constraint->pk_attrs); + } if (constraint->fk_del_action == FKCONSTR_ACTION_SETNULL) { diff --git a/src/backend/distributed/deparser/deparse_table_stmts.c b/src/backend/distributed/deparser/deparse_table_stmts.c index e976b0e2f..5d184fa66 100644 --- a/src/backend/distributed/deparser/deparse_table_stmts.c +++ b/src/backend/distributed/deparser/deparse_table_stmts.c @@ -121,7 +121,7 @@ AppendAlterTableStmt(StringInfo buf, AlterTableStmt *stmt) * AppendColumnNameList converts a list of columns into comma separated string format * (colname_1, colname_2, .., colname_n). */ -static void +void AppendColumnNameList(StringInfo buf, List *columns) { appendStringInfoString(buf, " ("); diff --git a/src/backend/distributed/metadata/metadata_sync.c b/src/backend/distributed/metadata/metadata_sync.c index 14f5b4624..31d586e90 100644 --- a/src/backend/distributed/metadata/metadata_sync.c +++ b/src/backend/distributed/metadata/metadata_sync.c @@ -492,19 +492,7 @@ stop_metadata_sync_to_node(PG_FUNCTION_ARGS) bool ClusterHasKnownMetadataWorkers() { - bool workerWithMetadata = false; - - if (!IsCoordinator()) - { - workerWithMetadata = true; - } - - if (workerWithMetadata || HasMetadataWorkers()) - { - return true; - } - - return false; + return !IsCoordinator() || HasMetadataWorkers(); } diff --git a/src/backend/distributed/transaction/transaction_recovery.c b/src/backend/distributed/transaction/transaction_recovery.c index 653b962db..c31dc85a2 100644 --- a/src/backend/distributed/transaction/transaction_recovery.c +++ b/src/backend/distributed/transaction/transaction_recovery.c @@ -34,6 +34,7 @@ #include "utils/fmgroids.h" #include "utils/memutils.h" #include "utils/rel.h" +#include "utils/syscache.h" #include "utils/xid8.h" #include "pg_version_constants.h" @@ -261,11 +262,28 @@ RecoverWorkerTransactions(WorkerNode *workerNode) continue; } - /* Check if the transaction is created by an outer transaction from a non-main database */ bool outerXidIsNull = false; - Datum outerXidDatum = heap_getattr(heapTuple, - Anum_pg_dist_transaction_outerxid, - tupleDescriptor, &outerXidIsNull); + Datum outerXidDatum = 0; + if (EnableVersionChecks || + SearchSysCacheExistsAttName(DistTransactionRelationId(), "outer_xid")) + { + /* Check if the transaction is created by an outer transaction from a non-main database */ + outerXidDatum = heap_getattr(heapTuple, + Anum_pg_dist_transaction_outerxid, + tupleDescriptor, &outerXidIsNull); + } + else + { + /* + * Normally we don't try to recover prepared transactions when the + * binary version doesn't match the sql version. However, we skip + * those checks in regression tests by disabling + * citus.enable_version_checks. And when this is the case, while + * the C code looks for "outer_xid" attribute, pg_dist_transaction + * doesn't yet have it. + */ + Assert(!EnableVersionChecks); + } TransactionId outerXid = 0; if (!outerXidIsNull) diff --git a/src/include/distributed/deparser.h b/src/include/distributed/deparser.h index 437a9fd8e..4d4005c19 100644 --- a/src/include/distributed/deparser.h +++ b/src/include/distributed/deparser.h @@ -121,6 +121,8 @@ extern void AppendGrantedByInGrant(StringInfo buf, GrantStmt *stmt); extern void AppendGrantSharedPrefix(StringInfo buf, GrantStmt *stmt); extern void AppendGrantSharedSuffix(StringInfo buf, GrantStmt *stmt); +extern void AppendColumnNameList(StringInfo buf, List *columns); + /* Common deparser utils */ typedef struct DefElemOptionFormat diff --git a/src/test/regress/expected/alter_table_add_column.out b/src/test/regress/expected/alter_table_add_column.out index 61e7319d9..0408aeeab 100644 --- a/src/test/regress/expected/alter_table_add_column.out +++ b/src/test/regress/expected/alter_table_add_column.out @@ -44,6 +44,15 @@ ERROR: cannot execute ADD COLUMN command with PRIMARY KEY, UNIQUE, FOREIGN and DETAIL: Adding a column with a constraint in one command is not supported because all constraints in Citus must have explicit names HINT: You can issue each command separately such as ALTER TABLE referencing ADD COLUMN test_8 data_type; ALTER TABLE referencing ADD CONSTRAINT constraint_name CHECK (check_expression); ALTER TABLE referencing ADD COLUMN test_8 integer CONSTRAINT check_test_8 CHECK (test_8 > 0); +-- error out properly even if the REFERENCES does not include the column list of the referenced table +ALTER TABLE referencing ADD COLUMN test_9 bool, ADD COLUMN test_10 int REFERENCES referenced; +ERROR: cannot execute ADD COLUMN command with PRIMARY KEY, UNIQUE, FOREIGN and CHECK constraints +DETAIL: Adding a column with a constraint in one command is not supported because all constraints in Citus must have explicit names +HINT: You can issue each command separately such as ALTER TABLE referencing ADD COLUMN test_10 data_type; ALTER TABLE referencing ADD CONSTRAINT constraint_name FOREIGN KEY (test_10) REFERENCES referenced; +ALTER TABLE referencing ADD COLUMN test_9 bool, ADD COLUMN test_10 int REFERENCES referenced(int_col); +ERROR: cannot execute ADD COLUMN command with PRIMARY KEY, UNIQUE, FOREIGN and CHECK constraints +DETAIL: Adding a column with a constraint in one command is not supported because all constraints in Citus must have explicit names +HINT: You can issue each command separately such as ALTER TABLE referencing ADD COLUMN test_10 data_type; ALTER TABLE referencing ADD CONSTRAINT constraint_name FOREIGN KEY (test_10) REFERENCES referenced (int_col ); -- try to add test_6 again, but with IF NOT EXISTS ALTER TABLE referencing ADD COLUMN IF NOT EXISTS test_6 text; NOTICE: column "test_6" of relation "referencing" already exists, skipping diff --git a/src/test/regress/expected/create_role_propagation.out b/src/test/regress/expected/create_role_propagation.out index 90f2690ce..4d594ddab 100644 --- a/src/test/regress/expected/create_role_propagation.out +++ b/src/test/regress/expected/create_role_propagation.out @@ -121,17 +121,17 @@ SELECT 1 FROM master_add_node('localhost', :worker_2_port); SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, (rolpassword != '') as pass_not_empty, rolvaliduntil FROM pg_authid WHERE rolname LIKE 'create\_%' ORDER BY rolname; rolname | rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcanlogin | rolreplication | rolbypassrls | rolconnlimit | pass_not_empty | rolvaliduntil --------------------------------------------------------------------- - create_group | f | t | f | f | f | f | f | -1 | | infinity - create_group_2 | f | t | f | f | f | f | f | -1 | | infinity - create_role | f | t | f | f | f | f | f | -1 | | infinity - create_role"edge | f | t | f | f | f | f | f | -1 | | infinity - create_role'edge | f | t | f | f | f | f | f | -1 | | infinity - create_role_2 | f | t | f | f | f | f | f | -1 | | infinity - create_role_sysid | f | t | f | f | f | f | f | -1 | | infinity + create_group | f | t | f | f | f | f | f | -1 | | + create_group_2 | f | t | f | f | f | f | f | -1 | | + create_role | f | t | f | f | f | f | f | -1 | | + create_role"edge | f | t | f | f | f | f | f | -1 | | + create_role'edge | f | t | f | f | f | f | f | -1 | | + create_role_2 | f | t | f | f | f | f | f | -1 | | + create_role_sysid | f | t | f | f | f | f | f | -1 | | create_role_with_everything | t | t | t | t | t | t | t | 105 | t | Thu May 04 17:00:00 2045 PDT create_role_with_nothing | f | f | f | f | f | f | f | 3 | t | Mon May 04 17:00:00 2015 PDT - create_user | f | t | f | f | t | f | f | -1 | | infinity - create_user_2 | f | t | f | f | t | f | f | -1 | | infinity + create_user | f | t | f | f | t | f | f | -1 | | + create_user_2 | f | t | f | f | t | f | f | -1 | | (11 rows) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE 'create\_%' ORDER BY 1, 2; diff --git a/src/test/regress/expected/metadata_sync_from_non_maindb.out b/src/test/regress/expected/metadata_sync_from_non_maindb.out index 6630b39bd..2aac507bd 100644 --- a/src/test/regress/expected/metadata_sync_from_non_maindb.out +++ b/src/test/regress/expected/metadata_sync_from_non_maindb.out @@ -188,7 +188,6 @@ select 1 from citus_add_node('localhost', :worker_2_port); 1 (1 row) --- XXX: date is not correct on one of the workers due to https://github.com/citusdata/citus/issues/7533 select result FROM run_command_on_all_nodes($$ SELECT array_to_json(array_agg(row_to_json(t))) FROM ( @@ -200,11 +199,11 @@ select result FROM run_command_on_all_nodes($$ ORDER BY rolname ) t $$); - result + result --------------------------------------------------------------------- [{"rolname":"test_role1","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":true,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":true,"date":null},{"rolname":"test_role2-needs\\!escape","rolsuper":true,"rolinherit":true,"rolcreaterole":true,"rolcreatedb":true,"rolcanlogin":true,"rolreplication":true,"rolbypassrls":true,"rolconnlimit":10,"pass_not_empty":null,"date":"2023-01-01"},{"rolname":"test_role3","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":null,"date":null}] [{"rolname":"test_role1","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":true,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":true,"date":null},{"rolname":"test_role2-needs\\!escape","rolsuper":true,"rolinherit":true,"rolcreaterole":true,"rolcreatedb":true,"rolcanlogin":true,"rolreplication":true,"rolbypassrls":true,"rolconnlimit":10,"pass_not_empty":null,"date":"2023-01-01"},{"rolname":"test_role3","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":null,"date":null}] - [{"rolname":"test_role1","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":true,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":true,"date":"infinity"},{"rolname":"test_role2-needs\\!escape","rolsuper":true,"rolinherit":true,"rolcreaterole":true,"rolcreatedb":true,"rolcanlogin":true,"rolreplication":true,"rolbypassrls":true,"rolconnlimit":10,"pass_not_empty":null,"date":"2023-01-01"},{"rolname":"test_role3","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":null,"date":"infinity"}] + [{"rolname":"test_role1","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":true,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":true,"date":null},{"rolname":"test_role2-needs\\!escape","rolsuper":true,"rolinherit":true,"rolcreaterole":true,"rolcreatedb":true,"rolcanlogin":true,"rolreplication":true,"rolbypassrls":true,"rolconnlimit":10,"pass_not_empty":null,"date":"2023-01-01"},{"rolname":"test_role3","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":null,"date":null}] (3 rows) --test for alter user @@ -229,7 +228,6 @@ select 1 from citus_add_node('localhost', :worker_2_port); 1 (1 row) --- XXX: date is not correct on one of the workers due to https://github.com/citusdata/citus/issues/7533 select result FROM run_command_on_all_nodes($$ SELECT array_to_json(array_agg(row_to_json(t))) FROM ( @@ -241,11 +239,11 @@ select result FROM run_command_on_all_nodes($$ ORDER BY rolname ) t $$); - result + result --------------------------------------------------------------------- [{"rolname":"test_role1","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":true,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":true,"date":null},{"rolname":"test_role2-needs\\!escape","rolsuper":false,"rolinherit":false,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":5,"pass_not_empty":null,"date":"2024-01-01"},{"rolname":"test_role3","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":null,"date":null}] [{"rolname":"test_role1","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":true,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":true,"date":null},{"rolname":"test_role2-needs\\!escape","rolsuper":false,"rolinherit":false,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":5,"pass_not_empty":null,"date":"2024-01-01"},{"rolname":"test_role3","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":null,"date":null}] - [{"rolname":"test_role1","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":true,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":true,"date":"infinity"},{"rolname":"test_role2-needs\\!escape","rolsuper":false,"rolinherit":false,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":5,"pass_not_empty":null,"date":"2024-01-01"},{"rolname":"test_role3","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":null,"date":"infinity"}] + [{"rolname":"test_role1","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":true,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":true,"date":null},{"rolname":"test_role2-needs\\!escape","rolsuper":false,"rolinherit":false,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":5,"pass_not_empty":null,"date":"2024-01-01"},{"rolname":"test_role3","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":null,"date":null}] (3 rows) --test for drop user @@ -266,7 +264,6 @@ select 1 from citus_add_node('localhost', :worker_2_port); 1 (1 row) --- XXX: date is not correct on one of the workers due to https://github.com/citusdata/citus/issues/7533 select result FROM run_command_on_all_nodes($$ SELECT array_to_json(array_agg(row_to_json(t))) FROM ( @@ -278,11 +275,11 @@ select result FROM run_command_on_all_nodes($$ ORDER BY rolname ) t $$); - result + result --------------------------------------------------------------------- - [{"rolname":"test_role1","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":true,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":true,"date":"infinity"},{"rolname":"test_role2-needs\\!escape","rolsuper":false,"rolinherit":false,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":5,"pass_not_empty":null,"date":"2024-01-01"},{"rolname":"test_role3","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":null,"date":"infinity"}] + [{"rolname":"test_role1","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":true,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":true,"date":null},{"rolname":"test_role2-needs\\!escape","rolsuper":false,"rolinherit":false,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":5,"pass_not_empty":null,"date":"2024-01-01"},{"rolname":"test_role3","rolsuper":false,"rolinherit":true,"rolcreaterole":false,"rolcreatedb":false,"rolcanlogin":false,"rolreplication":false,"rolbypassrls":false,"rolconnlimit":-1,"pass_not_empty":null,"date":null}] (3 rows) -- Clean up: drop the database on worker node 2 diff --git a/src/test/regress/expected/seclabel.out b/src/test/regress/expected/seclabel.out index ae6589734..ca6c6f984 100644 --- a/src/test/regress/expected/seclabel.out +++ b/src/test/regress/expected/seclabel.out @@ -167,9 +167,9 @@ SELECT node_type, result FROM get_citus_tests_label_provider_labels('"user 2"') SET citus.log_remote_commands TO on; SET citus.grep_remote_commands = '%SECURITY LABEL%'; SELECT 1 FROM citus_add_node('localhost', :worker_2_port); -NOTICE: issuing SELECT worker_create_or_alter_role('user1', 'CREATE ROLE user1 NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT -1 PASSWORD NULL VALID UNTIL ''infinity''', 'ALTER ROLE user1 NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT -1 PASSWORD NULL VALID UNTIL ''infinity''');SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE user1 IS 'citus_classified' +NOTICE: issuing SELECT worker_create_or_alter_role('user1', 'CREATE ROLE user1 NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT -1 PASSWORD NULL', 'ALTER ROLE user1 NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT -1 PASSWORD NULL');SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE user1 IS 'citus_classified' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx -NOTICE: issuing SELECT worker_create_or_alter_role('user 2', 'CREATE ROLE "user 2" NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT -1 PASSWORD NULL VALID UNTIL ''infinity''', 'ALTER ROLE "user 2" NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT -1 PASSWORD NULL VALID UNTIL ''infinity''');SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus ''!unclassified' +NOTICE: issuing SELECT worker_create_or_alter_role('user 2', 'CREATE ROLE "user 2" NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT -1 PASSWORD NULL', 'ALTER ROLE "user 2" NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT -1 PASSWORD NULL');SECURITY LABEL FOR "citus '!tests_label_provider" ON ROLE "user 2" IS 'citus ''!unclassified' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx ?column? --------------------------------------------------------------------- diff --git a/src/test/regress/expected/upgrade_post_11_after.out b/src/test/regress/expected/upgrade_post_11_after.out index 422bc846f..49bd20432 100644 --- a/src/test/regress/expected/upgrade_post_11_after.out +++ b/src/test/regress/expected/upgrade_post_11_after.out @@ -67,6 +67,20 @@ SELECT 1 FROM run_command_on_workers($$SELECT pg_reload_conf()$$); 1 (2 rows) +-- In the version that we use for upgrade tests (v10.2.0), we propagate +-- "valid until" to the workers as "infinity" even if it's not set. And +-- given that "postgres" role is created in the older version, "valid until" +-- is set to "infinity" on the workers while this is not the case for +-- coordinator. See https://github.com/citusdata/citus/issues/7533. +-- +-- We're fixing this for new versions of Citus and we'll probably backport +-- this to some older versions too. However, v10.2.0 won't ever have this +-- fix. +-- +-- For this reason, here we set "valid until" to "infinity" for all the +-- nodes so that below query doesn't report any difference between the +-- metadata on coordinator and workers. +ALTER ROLE postgres WITH VALID UNTIL 'infinity'; -- make sure that the metadata is consistent across all nodes -- we exclude the distributed_object_data as they are -- not sorted in the same order (as OIDs differ on the nodes) diff --git a/src/test/regress/sql/alter_table_add_column.sql b/src/test/regress/sql/alter_table_add_column.sql index 255e7714f..355667842 100644 --- a/src/test/regress/sql/alter_table_add_column.sql +++ b/src/test/regress/sql/alter_table_add_column.sql @@ -41,6 +41,10 @@ ALTER TABLE referencing ADD COLUMN "test_\'!7" "simple_!\'custom_type"; ALTER TABLE referencing ADD COLUMN test_8 integer CHECK (test_8 > 0); ALTER TABLE referencing ADD COLUMN test_8 integer CONSTRAINT check_test_8 CHECK (test_8 > 0); +-- error out properly even if the REFERENCES does not include the column list of the referenced table +ALTER TABLE referencing ADD COLUMN test_9 bool, ADD COLUMN test_10 int REFERENCES referenced; +ALTER TABLE referencing ADD COLUMN test_9 bool, ADD COLUMN test_10 int REFERENCES referenced(int_col); + -- try to add test_6 again, but with IF NOT EXISTS ALTER TABLE referencing ADD COLUMN IF NOT EXISTS test_6 text; ALTER TABLE referencing ADD COLUMN IF NOT EXISTS test_6 integer; diff --git a/src/test/regress/sql/metadata_sync_from_non_maindb.sql b/src/test/regress/sql/metadata_sync_from_non_maindb.sql index 67e1e98d1..62760c6cc 100644 --- a/src/test/regress/sql/metadata_sync_from_non_maindb.sql +++ b/src/test/regress/sql/metadata_sync_from_non_maindb.sql @@ -100,7 +100,6 @@ create role test_role3; \c regression - - :master_port select 1 from citus_add_node('localhost', :worker_2_port); --- XXX: date is not correct on one of the workers due to https://github.com/citusdata/citus/issues/7533 select result FROM run_command_on_all_nodes($$ SELECT array_to_json(array_agg(row_to_json(t))) FROM ( @@ -128,7 +127,6 @@ LIMIT 5 VALID UNTIL '2024-01-01'; \c regression - - :master_port select 1 from citus_add_node('localhost', :worker_2_port); --- XXX: date is not correct on one of the workers due to https://github.com/citusdata/citus/issues/7533 select result FROM run_command_on_all_nodes($$ SELECT array_to_json(array_agg(row_to_json(t))) FROM ( @@ -153,7 +151,6 @@ DROP ROLE test_role3; \c regression - - :master_port select 1 from citus_add_node('localhost', :worker_2_port); --- XXX: date is not correct on one of the workers due to https://github.com/citusdata/citus/issues/7533 select result FROM run_command_on_all_nodes($$ SELECT array_to_json(array_agg(row_to_json(t))) FROM ( diff --git a/src/test/regress/sql/upgrade_post_11_after.sql b/src/test/regress/sql/upgrade_post_11_after.sql index ba9b12f3b..6d948ec34 100644 --- a/src/test/regress/sql/upgrade_post_11_after.sql +++ b/src/test/regress/sql/upgrade_post_11_after.sql @@ -27,6 +27,21 @@ SET datestyle = "ISO, YMD"; SELECT 1 FROM run_command_on_workers($$ALTER SYSTEM SET datestyle = "ISO, YMD";$$); SELECT 1 FROM run_command_on_workers($$SELECT pg_reload_conf()$$); +-- In the version that we use for upgrade tests (v10.2.0), we propagate +-- "valid until" to the workers as "infinity" even if it's not set. And +-- given that "postgres" role is created in the older version, "valid until" +-- is set to "infinity" on the workers while this is not the case for +-- coordinator. See https://github.com/citusdata/citus/issues/7533. +-- +-- We're fixing this for new versions of Citus and we'll probably backport +-- this to some older versions too. However, v10.2.0 won't ever have this +-- fix. +-- +-- For this reason, here we set "valid until" to "infinity" for all the +-- nodes so that below query doesn't report any difference between the +-- metadata on coordinator and workers. +ALTER ROLE postgres WITH VALID UNTIL 'infinity'; + -- make sure that the metadata is consistent across all nodes -- we exclude the distributed_object_data as they are -- not sorted in the same order (as OIDs differ on the nodes)