Merge branch 'main' into alter_database_nonmain2

pull/7563/head
gurkanindibay 2024-03-20 01:15:17 +03:00
commit 879ab1821a
15 changed files with 258 additions and 383 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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, " (");

View File

@ -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();
}

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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?
---------------------------------------------------------------------

View File

@ -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)

View File

@ -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;

View File

@ -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 (

View File

@ -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)