mirror of https://github.com/citusdata/citus.git
Adds metadata sync for db and role
parent
db5f04c4e3
commit
dce02a49b0
|
@ -0,0 +1,111 @@
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "access/genam.h"
|
||||||
|
#include "access/htup_details.h"
|
||||||
|
#include "catalog/pg_shdescription.h"
|
||||||
|
|
||||||
|
#include "server/nodes/parsenodes.h"
|
||||||
|
#include "server/access/table.h"
|
||||||
|
#include "server/utils/rel.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
|
#include "distributed/comment.h"
|
||||||
|
|
||||||
|
|
||||||
|
const CommentStmtType commentStmtTypes[] = {
|
||||||
|
{ OBJECT_DATABASE, "DATABASE" },
|
||||||
|
{ OBJECT_ROLE, "ROLE" }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static char * GetCommentObjectType(ObjectType objectType);
|
||||||
|
static char * GetCommentForObject(Oid oid);
|
||||||
|
|
||||||
|
|
||||||
|
List *
|
||||||
|
GetCommentPropagationCommands(Oid oid,char *objectName, ObjectType objectType)
|
||||||
|
{
|
||||||
|
List *commands = NIL;
|
||||||
|
|
||||||
|
StringInfo commentStmt = makeStringInfo();
|
||||||
|
|
||||||
|
/* Get the comment for the database */
|
||||||
|
char *comment = GetCommentForObject(oid);
|
||||||
|
char *commentObjectType = GetCommentObjectType(objectType);
|
||||||
|
|
||||||
|
/* Create the SQL command to propagate the comment to other nodes */
|
||||||
|
if (comment == NULL)
|
||||||
|
{
|
||||||
|
appendStringInfo(commentStmt, "COMMENT ON %s %s IS NULL;", commentObjectType, quote_identifier(objectName));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appendStringInfo(commentStmt, "COMMENT ON %s %s IS %s;", commentObjectType, quote_identifier(objectName),
|
||||||
|
quote_literal_cstr(comment));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Add the command to the list */
|
||||||
|
commands = list_make1(commentStmt->data);
|
||||||
|
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char * GetCommentObjectType(ObjectType objectType){
|
||||||
|
char *objectName = NULL;
|
||||||
|
for(int i = 0; i < sizeof(commentStmtTypes)/sizeof(CommentStmtType); i++){
|
||||||
|
if(commentStmtTypes[i].objectType == objectType){
|
||||||
|
objectName = commentStmtTypes[i].objectName;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return objectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
GetCommentForObject(Oid oid)
|
||||||
|
{
|
||||||
|
Relation shdescRelation;
|
||||||
|
SysScanDesc scan;
|
||||||
|
HeapTuple tuple;
|
||||||
|
char *comment = NULL;
|
||||||
|
|
||||||
|
/* Open pg_shdescription catalog */
|
||||||
|
shdescRelation = table_open(SharedDescriptionRelationId, AccessShareLock);
|
||||||
|
|
||||||
|
/* Scan the table */
|
||||||
|
scan = systable_beginscan(shdescRelation, InvalidOid, false, NULL, 0, NULL);
|
||||||
|
while ((tuple = systable_getnext(scan)) != NULL)
|
||||||
|
{
|
||||||
|
Form_pg_shdescription shdesc = (Form_pg_shdescription) GETSTRUCT(tuple);
|
||||||
|
|
||||||
|
bool isNull = false;
|
||||||
|
|
||||||
|
TupleDesc tupdesc = RelationGetDescr(shdescRelation);
|
||||||
|
|
||||||
|
Datum descDatum = heap_getattr(tuple, Anum_pg_shdescription_description, tupdesc,
|
||||||
|
&isNull);
|
||||||
|
|
||||||
|
/* Check if the objoid matches the databaseOid */
|
||||||
|
if (shdesc->objoid == oid)
|
||||||
|
{
|
||||||
|
/* Add the command to the list */
|
||||||
|
if (!isNull)
|
||||||
|
{
|
||||||
|
comment = TextDatumGetCString(descDatum);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
comment = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End the scan and close the catalog */
|
||||||
|
systable_endscan(scan);
|
||||||
|
table_close(shdescRelation, AccessShareLock);
|
||||||
|
|
||||||
|
return comment;
|
||||||
|
}
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#include "distributed/adaptive_executor.h"
|
#include "distributed/adaptive_executor.h"
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
|
#include "distributed/comment.h"
|
||||||
#include "distributed/commands/utility_hook.h"
|
#include "distributed/commands/utility_hook.h"
|
||||||
#include "distributed/deparse_shard_query.h"
|
#include "distributed/deparse_shard_query.h"
|
||||||
#include "distributed/deparser.h"
|
#include "distributed/deparser.h"
|
||||||
|
@ -48,7 +49,6 @@
|
||||||
|
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
#include "access/table.h"
|
#include "access/table.h"
|
||||||
#include "catalog/pg_shdescription.h"
|
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ typedef struct DatabaseCollationInfo
|
||||||
#endif
|
#endif
|
||||||
} DatabaseCollationInfo;
|
} DatabaseCollationInfo;
|
||||||
|
|
||||||
|
|
||||||
static char * GenerateCreateDatabaseStatementFromPgDatabase(Form_pg_database
|
static char * GenerateCreateDatabaseStatementFromPgDatabase(Form_pg_database
|
||||||
databaseForm);
|
databaseForm);
|
||||||
static DatabaseCollationInfo GetDatabaseCollation(Oid dbOid);
|
static DatabaseCollationInfo GetDatabaseCollation(Oid dbOid);
|
||||||
|
@ -82,7 +83,6 @@ static ObjectAddress * GetDatabaseAddressFromDatabaseName(char *databaseName,
|
||||||
bool missingOk);
|
bool missingOk);
|
||||||
|
|
||||||
static Oid get_database_owner(Oid dbId);
|
static Oid get_database_owner(Oid dbId);
|
||||||
static List * GetDatabaseCommentPropagationCommands(Oid databaseOid);
|
|
||||||
|
|
||||||
|
|
||||||
/* controlled via GUC */
|
/* controlled via GUC */
|
||||||
|
@ -585,12 +585,14 @@ GetTablespaceName(Oid tablespaceOid)
|
||||||
List *
|
List *
|
||||||
GetDatabaseMetadataSyncCommands(Oid dbOid)
|
GetDatabaseMetadataSyncCommands(Oid dbOid)
|
||||||
{
|
{
|
||||||
|
char *databaseName = get_database_name(dbOid);
|
||||||
char *databaseDDLCommand = CreateDatabaseDDLCommand(dbOid);
|
char *databaseDDLCommand = CreateDatabaseDDLCommand(dbOid);
|
||||||
|
|
||||||
List *ddlCommands = list_make1(databaseDDLCommand);
|
List *ddlCommands = list_make1(databaseDDLCommand);
|
||||||
|
|
||||||
List *grantDDLCommands = GrantOnDatabaseDDLCommands(dbOid);
|
List *grantDDLCommands = GrantOnDatabaseDDLCommands(dbOid);
|
||||||
List *commentDDLCommands = GetDatabaseCommentPropagationCommands(dbOid);
|
List *commentDDLCommands = GetCommentPropagationCommands(dbOid, databaseName,
|
||||||
|
OBJECT_DATABASE);
|
||||||
|
|
||||||
ddlCommands = list_concat(ddlCommands, grantDDLCommands);
|
ddlCommands = list_concat(ddlCommands, grantDDLCommands);
|
||||||
ddlCommands = list_concat(ddlCommands, commentDDLCommands);
|
ddlCommands = list_concat(ddlCommands, commentDDLCommands);
|
||||||
|
@ -818,48 +820,3 @@ DatabaseCommentObjectAddress(Node *node, bool missing_ok, bool isPostprocess)
|
||||||
*objectAddressCopy = objectAddress;
|
*objectAddressCopy = objectAddress;
|
||||||
return list_make1(objectAddressCopy);
|
return list_make1(objectAddressCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static List *
|
|
||||||
GetDatabaseCommentPropagationCommands(Oid databaseOid)
|
|
||||||
{
|
|
||||||
Relation shdescRelation;
|
|
||||||
SysScanDesc scan;
|
|
||||||
HeapTuple tuple;
|
|
||||||
List *commands = NIL;
|
|
||||||
|
|
||||||
/* Open pg_shdescription catalog */
|
|
||||||
shdescRelation = table_open(SharedDescriptionRelationId, AccessShareLock);
|
|
||||||
|
|
||||||
/* Scan the table */
|
|
||||||
scan = systable_beginscan(shdescRelation, InvalidOid, false, NULL, 0, NULL);
|
|
||||||
while ((tuple = systable_getnext(scan)) != NULL)
|
|
||||||
{
|
|
||||||
Form_pg_shdescription shdesc = (Form_pg_shdescription) GETSTRUCT(tuple);
|
|
||||||
|
|
||||||
bool isNull = false;
|
|
||||||
|
|
||||||
TupleDesc tupdesc = RelationGetDescr(shdescRelation);
|
|
||||||
|
|
||||||
Datum descDatum = heap_getattr(tuple, Anum_pg_shdescription_description, tupdesc,
|
|
||||||
&isNull);
|
|
||||||
|
|
||||||
/* Check if the objoid matches the databaseOid */
|
|
||||||
if (shdesc->objoid == databaseOid)
|
|
||||||
{
|
|
||||||
/* Create the SQL command to propagate the comment to other nodes */
|
|
||||||
char *databaseName = get_database_name(databaseOid);
|
|
||||||
char *command = psprintf("COMMENT ON DATABASE %s IS '%s';", databaseName,
|
|
||||||
TextDatumGetCString(descDatum));
|
|
||||||
|
|
||||||
/* Add the command to the list */
|
|
||||||
commands = lappend(commands, command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* End the scan and close the catalog */
|
|
||||||
systable_endscan(scan);
|
|
||||||
table_close(shdescRelation, AccessShareLock);
|
|
||||||
|
|
||||||
return commands;
|
|
||||||
}
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "distributed/citus_ruleutils.h"
|
#include "distributed/citus_ruleutils.h"
|
||||||
#include "distributed/citus_safe_lib.h"
|
#include "distributed/citus_safe_lib.h"
|
||||||
#include "distributed/commands.h"
|
#include "distributed/commands.h"
|
||||||
|
#include "distributed/comment.h"
|
||||||
#include "distributed/commands/utility_hook.h"
|
#include "distributed/commands/utility_hook.h"
|
||||||
#include "distributed/coordinator_protocol.h"
|
#include "distributed/coordinator_protocol.h"
|
||||||
#include "distributed/deparser.h"
|
#include "distributed/deparser.h"
|
||||||
|
@ -582,6 +583,17 @@ GenerateCreateOrAlterRoleCommand(Oid roleOid)
|
||||||
{
|
{
|
||||||
completeRoleList = lappend(completeRoleList, DeparseTreeNode(stmt));
|
completeRoleList = lappend(completeRoleList, DeparseTreeNode(stmt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* append COMMENT ON ROLE commands for this specific user
|
||||||
|
* When we propagate user creation, we also want to make sure that we propagate
|
||||||
|
* all the comments it has been given. For this, we check pg_shdescription
|
||||||
|
* for the ROLE entry corresponding to roleOid, and generate the relevant
|
||||||
|
* Comment stmts to be run in the new node.
|
||||||
|
*/
|
||||||
|
List *commentStmts = GetCommentPropagationCommands(roleOid, rolename,
|
||||||
|
OBJECT_ROLE);
|
||||||
|
completeRoleList = list_concat(completeRoleList, commentStmts);
|
||||||
}
|
}
|
||||||
|
|
||||||
return completeRoleList;
|
return completeRoleList;
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "server/nodes/parsenodes.h"
|
||||||
|
|
||||||
|
typedef struct CommentStmtType
|
||||||
|
{
|
||||||
|
ObjectType objectType;
|
||||||
|
char *objectName;
|
||||||
|
} CommentStmtType;
|
||||||
|
|
||||||
|
|
||||||
|
extern List * GetCommentPropagationCommands(Oid oid, char *objectName, ObjectType objectType);
|
|
@ -48,6 +48,51 @@ SELECT result FROM run_command_on_all_nodes(
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
drop DATABASE "test1-\!escape";
|
||||||
|
--test metadata sync
|
||||||
|
select 1 from citus_remove_node('localhost', :worker_2_port);
|
||||||
|
?column?
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
create database "test1-\!escape";
|
||||||
|
comment on DATABASE "test1-\!escape" is 'test-comment';
|
||||||
|
SELECT result FROM run_command_on_all_nodes(
|
||||||
|
$$
|
||||||
|
SELECT ds.description AS database_comment
|
||||||
|
FROM pg_database d
|
||||||
|
LEFT JOIN pg_shdescription ds ON d.oid = ds.objoid
|
||||||
|
WHERE d.datname = 'test1-\!escape';
|
||||||
|
$$
|
||||||
|
);
|
||||||
|
result
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
test-comment
|
||||||
|
test-comment
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
select 1 from citus_add_node('localhost', :worker_2_port);
|
||||||
|
?column?
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT result FROM run_command_on_all_nodes(
|
||||||
|
$$
|
||||||
|
SELECT ds.description AS database_comment
|
||||||
|
FROM pg_database d
|
||||||
|
LEFT JOIN pg_shdescription ds ON d.oid = ds.objoid
|
||||||
|
WHERE d.datname = 'test1-\!escape';
|
||||||
|
$$
|
||||||
|
);
|
||||||
|
result
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
test-comment
|
||||||
|
test-comment
|
||||||
|
test-comment
|
||||||
(3 rows)
|
(3 rows)
|
||||||
|
|
||||||
drop DATABASE "test1-\!escape";
|
drop DATABASE "test1-\!escape";
|
||||||
|
|
|
@ -47,6 +47,51 @@ SELECT result FROM run_command_on_all_nodes(
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
drop role "role1-\!escape";
|
||||||
|
--test metadata sync
|
||||||
|
select 1 from citus_remove_node('localhost', :worker_2_port);
|
||||||
|
?column?
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
create role "role1-\!escape";
|
||||||
|
comment on ROLE "role1-\!escape" is 'test-comment';
|
||||||
|
SELECT result FROM run_command_on_all_nodes(
|
||||||
|
$$
|
||||||
|
SELECT ds.description AS role_comment
|
||||||
|
FROM pg_roles r
|
||||||
|
LEFT JOIN pg_shdescription ds ON r.oid = ds.objoid
|
||||||
|
WHERE r.rolname = 'role1-\!escape';
|
||||||
|
$$
|
||||||
|
);
|
||||||
|
result
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
test-comment
|
||||||
|
test-comment
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
select 1 from citus_add_node('localhost', :worker_2_port);
|
||||||
|
?column?
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT result FROM run_command_on_all_nodes(
|
||||||
|
$$
|
||||||
|
SELECT ds.description AS role_comment
|
||||||
|
FROM pg_roles r
|
||||||
|
LEFT JOIN pg_shdescription ds ON r.oid = ds.objoid
|
||||||
|
WHERE r.rolname = 'role1-\!escape';
|
||||||
|
$$
|
||||||
|
);
|
||||||
|
result
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
test-comment
|
||||||
|
test-comment
|
||||||
|
test-comment
|
||||||
(3 rows)
|
(3 rows)
|
||||||
|
|
||||||
drop role "role1-\!escape";
|
drop role "role1-\!escape";
|
||||||
|
|
|
@ -38,6 +38,8 @@ test: create_single_shard_table
|
||||||
test: create_drop_database_propagation
|
test: create_drop_database_propagation
|
||||||
test: create_drop_database_propagation_pg15
|
test: create_drop_database_propagation_pg15
|
||||||
test: create_drop_database_propagation_pg16
|
test: create_drop_database_propagation_pg16
|
||||||
|
test: comment_on_database
|
||||||
|
test: comment_on_role
|
||||||
# don't parallelize single_shard_table_udfs to make sure colocation ids are sequential
|
# don't parallelize single_shard_table_udfs to make sure colocation ids are sequential
|
||||||
test: single_shard_table_udfs
|
test: single_shard_table_udfs
|
||||||
test: schema_based_sharding
|
test: schema_based_sharding
|
||||||
|
@ -59,7 +61,7 @@ test: grant_on_database_propagation
|
||||||
test: alter_database_propagation
|
test: alter_database_propagation
|
||||||
|
|
||||||
test: citus_shards
|
test: citus_shards
|
||||||
test: comment_on_database comment_on_role
|
|
||||||
|
|
||||||
# ----------
|
# ----------
|
||||||
# multi_citus_tools tests utility functions written for citus tools
|
# multi_citus_tools tests utility functions written for citus tools
|
||||||
|
|
|
@ -39,6 +39,35 @@ SELECT result FROM run_command_on_all_nodes(
|
||||||
);
|
);
|
||||||
|
|
||||||
drop DATABASE "test1-\!escape";
|
drop DATABASE "test1-\!escape";
|
||||||
|
|
||||||
|
--test metadata sync
|
||||||
|
select 1 from citus_remove_node('localhost', :worker_2_port);
|
||||||
|
create database "test1-\!escape";
|
||||||
|
comment on DATABASE "test1-\!escape" is 'test-comment';
|
||||||
|
|
||||||
|
SELECT result FROM run_command_on_all_nodes(
|
||||||
|
$$
|
||||||
|
SELECT ds.description AS database_comment
|
||||||
|
FROM pg_database d
|
||||||
|
LEFT JOIN pg_shdescription ds ON d.oid = ds.objoid
|
||||||
|
WHERE d.datname = 'test1-\!escape';
|
||||||
|
$$
|
||||||
|
);
|
||||||
|
|
||||||
|
select 1 from citus_add_node('localhost', :worker_2_port);
|
||||||
|
|
||||||
|
SELECT result FROM run_command_on_all_nodes(
|
||||||
|
$$
|
||||||
|
SELECT ds.description AS database_comment
|
||||||
|
FROM pg_database d
|
||||||
|
LEFT JOIN pg_shdescription ds ON d.oid = ds.objoid
|
||||||
|
WHERE d.datname = 'test1-\!escape';
|
||||||
|
$$
|
||||||
|
);
|
||||||
|
|
||||||
|
drop DATABASE "test1-\!escape";
|
||||||
|
|
||||||
|
|
||||||
reset citus.enable_create_database_propagation;
|
reset citus.enable_create_database_propagation;
|
||||||
reset citus.grep_remote_commands;
|
reset citus.grep_remote_commands;
|
||||||
reset citus.log_remote_commands;
|
reset citus.log_remote_commands;
|
||||||
|
|
|
@ -38,5 +38,35 @@ SELECT result FROM run_command_on_all_nodes(
|
||||||
);
|
);
|
||||||
|
|
||||||
drop role "role1-\!escape";
|
drop role "role1-\!escape";
|
||||||
|
|
||||||
|
|
||||||
|
--test metadata sync
|
||||||
|
|
||||||
|
select 1 from citus_remove_node('localhost', :worker_2_port);
|
||||||
|
create role "role1-\!escape";
|
||||||
|
comment on ROLE "role1-\!escape" is 'test-comment';
|
||||||
|
|
||||||
|
SELECT result FROM run_command_on_all_nodes(
|
||||||
|
$$
|
||||||
|
SELECT ds.description AS role_comment
|
||||||
|
FROM pg_roles r
|
||||||
|
LEFT JOIN pg_shdescription ds ON r.oid = ds.objoid
|
||||||
|
WHERE r.rolname = 'role1-\!escape';
|
||||||
|
$$
|
||||||
|
);
|
||||||
|
|
||||||
|
select 1 from citus_add_node('localhost', :worker_2_port);
|
||||||
|
|
||||||
|
SELECT result FROM run_command_on_all_nodes(
|
||||||
|
$$
|
||||||
|
SELECT ds.description AS role_comment
|
||||||
|
FROM pg_roles r
|
||||||
|
LEFT JOIN pg_shdescription ds ON r.oid = ds.objoid
|
||||||
|
WHERE r.rolname = 'role1-\!escape';
|
||||||
|
$$
|
||||||
|
);
|
||||||
|
|
||||||
|
drop role "role1-\!escape";
|
||||||
|
|
||||||
reset citus.grep_remote_commands;
|
reset citus.grep_remote_commands;
|
||||||
reset citus.log_remote_commands;
|
reset citus.log_remote_commands;
|
||||||
|
|
Loading…
Reference in New Issue