mirror of https://github.com/citusdata/citus.git
Propagate foreign server ops
parent
61b5fb1cfc
commit
042d45b263
|
@ -288,6 +288,11 @@ GetDependencyCreateDDLCommands(const ObjectAddress *dependency)
|
||||||
return CreateExtensionDDLCommand(dependency);
|
return CreateExtensionDDLCommand(dependency);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OCLASS_FOREIGN_SERVER:
|
||||||
|
{
|
||||||
|
return GetForeignServerCreateDDLCommand(dependency->objectId);
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -89,6 +89,14 @@ static DistributeObjectOps Any_AlterExtensionContents = {
|
||||||
.address = NULL,
|
.address = NULL,
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
|
static DistributeObjectOps Any_AlterForeignServer = {
|
||||||
|
.deparse = DeparseAlterForeignServerStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = PreprocessAlterForeignServerStmt,
|
||||||
|
.postprocess = NULL,
|
||||||
|
.address = NULL,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
static DistributeObjectOps Any_AlterFunction = {
|
static DistributeObjectOps Any_AlterFunction = {
|
||||||
.deparse = DeparseAlterFunctionStmt,
|
.deparse = DeparseAlterFunctionStmt,
|
||||||
.qualify = QualifyAlterFunctionStmt,
|
.qualify = QualifyAlterFunctionStmt,
|
||||||
|
@ -177,6 +185,14 @@ static DistributeObjectOps Any_CreatePolicy = {
|
||||||
.address = NULL,
|
.address = NULL,
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
|
static DistributeObjectOps Any_CreateForeignServer = {
|
||||||
|
.deparse = DeparseCreateForeignServerStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = PreprocessCreateForeignServerStmt,
|
||||||
|
.postprocess = PostprocessCreateForeignServerStmt,
|
||||||
|
.address = CreateForeignServerStmtObjectAddress,
|
||||||
|
.markDistributed = true,
|
||||||
|
};
|
||||||
static DistributeObjectOps Any_CreateStatistics = {
|
static DistributeObjectOps Any_CreateStatistics = {
|
||||||
.deparse = DeparseCreateStatisticsStmt,
|
.deparse = DeparseCreateStatisticsStmt,
|
||||||
.qualify = QualifyCreateStatisticsStmt,
|
.qualify = QualifyCreateStatisticsStmt,
|
||||||
|
@ -297,6 +313,30 @@ static DistributeObjectOps Extension_Drop = {
|
||||||
.address = NULL,
|
.address = NULL,
|
||||||
.markDistributed = false,
|
.markDistributed = false,
|
||||||
};
|
};
|
||||||
|
static DistributeObjectOps ForeignServer_Drop = {
|
||||||
|
.deparse = DeparseDropForeignServerStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = PreprocessDropForeignServerStmt,
|
||||||
|
.postprocess = NULL,
|
||||||
|
.address = NULL,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
|
static DistributeObjectOps ForeignServer_Rename = {
|
||||||
|
.deparse = DeparseAlterForeignServerRenameStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = PreprocessRenameForeignServerStmt,
|
||||||
|
.postprocess = NULL,
|
||||||
|
.address = NULL,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
|
static DistributeObjectOps ForeignServer_AlterOwner = {
|
||||||
|
.deparse = DeparseAlterForeignServerOwnerStmt,
|
||||||
|
.qualify = NULL,
|
||||||
|
.preprocess = PreprocessAlterForeignServerOwnerStmt,
|
||||||
|
.postprocess = PostprocessAlterForeignServerOwnerStmt,
|
||||||
|
.address = AlterForeignServerOwnerStmtObjectAddress,
|
||||||
|
.markDistributed = false,
|
||||||
|
};
|
||||||
static DistributeObjectOps ForeignTable_AlterTable = {
|
static DistributeObjectOps ForeignTable_AlterTable = {
|
||||||
.deparse = NULL,
|
.deparse = NULL,
|
||||||
.qualify = NULL,
|
.qualify = NULL,
|
||||||
|
@ -675,6 +715,11 @@ GetDistributeObjectOps(Node *node)
|
||||||
return &Any_AlterFunction;
|
return &Any_AlterFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case T_AlterForeignServerStmt:
|
||||||
|
{
|
||||||
|
return &Any_AlterForeignServer;
|
||||||
|
}
|
||||||
|
|
||||||
case T_AlterObjectDependsStmt:
|
case T_AlterObjectDependsStmt:
|
||||||
{
|
{
|
||||||
AlterObjectDependsStmt *stmt = castNode(AlterObjectDependsStmt, node);
|
AlterObjectDependsStmt *stmt = castNode(AlterObjectDependsStmt, node);
|
||||||
|
@ -789,6 +834,11 @@ GetDistributeObjectOps(Node *node)
|
||||||
return &Database_AlterOwner;
|
return &Database_AlterOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OBJECT_FOREIGN_SERVER:
|
||||||
|
{
|
||||||
|
return &ForeignServer_AlterOwner;
|
||||||
|
}
|
||||||
|
|
||||||
case OBJECT_FUNCTION:
|
case OBJECT_FUNCTION:
|
||||||
{
|
{
|
||||||
return &Function_AlterOwner;
|
return &Function_AlterOwner;
|
||||||
|
@ -915,6 +965,11 @@ GetDistributeObjectOps(Node *node)
|
||||||
return &Any_CreateFunction;
|
return &Any_CreateFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case T_CreateForeignServerStmt:
|
||||||
|
{
|
||||||
|
return &Any_CreateForeignServer;
|
||||||
|
}
|
||||||
|
|
||||||
case T_CreatePolicyStmt:
|
case T_CreatePolicyStmt:
|
||||||
{
|
{
|
||||||
return &Any_CreatePolicy;
|
return &Any_CreatePolicy;
|
||||||
|
@ -977,6 +1032,11 @@ GetDistributeObjectOps(Node *node)
|
||||||
return &Function_Drop;
|
return &Function_Drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OBJECT_FOREIGN_SERVER:
|
||||||
|
{
|
||||||
|
return &ForeignServer_Drop;
|
||||||
|
}
|
||||||
|
|
||||||
case OBJECT_INDEX:
|
case OBJECT_INDEX:
|
||||||
{
|
{
|
||||||
return &Index_Drop;
|
return &Index_Drop;
|
||||||
|
@ -1081,6 +1141,11 @@ GetDistributeObjectOps(Node *node)
|
||||||
return &Collation_Rename;
|
return &Collation_Rename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OBJECT_FOREIGN_SERVER:
|
||||||
|
{
|
||||||
|
return &ForeignServer_Rename;
|
||||||
|
}
|
||||||
|
|
||||||
case OBJECT_FUNCTION:
|
case OBJECT_FUNCTION:
|
||||||
{
|
{
|
||||||
return &Function_Rename;
|
return &Function_Rename;
|
||||||
|
|
|
@ -797,7 +797,7 @@ CreateExtensionDDLCommand(const ObjectAddress *extensionAddress)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RecreateEnumStmt returns a parsetree for a CREATE EXTENSION statement that would
|
* RecreateExtensionStmt returns a parsetree for a CREATE EXTENSION statement that would
|
||||||
* recreate the given extension on a new node.
|
* recreate the given extension on a new node.
|
||||||
*/
|
*/
|
||||||
static Node *
|
static Node *
|
||||||
|
|
|
@ -0,0 +1,364 @@
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* foreign_server.c
|
||||||
|
* Commands for FOREIGN SERVER statements.
|
||||||
|
*
|
||||||
|
* Copyright (c) Citus Data, Inc.
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "catalog/pg_foreign_server.h"
|
||||||
|
#include "distributed/commands/utility_hook.h"
|
||||||
|
#include "distributed/commands.h"
|
||||||
|
#include "distributed/deparser.h"
|
||||||
|
#include "distributed/listutils.h"
|
||||||
|
#include "distributed/metadata/distobject.h"
|
||||||
|
#include "distributed/metadata_sync.h"
|
||||||
|
#include "distributed/worker_transaction.h"
|
||||||
|
#include "foreign/foreign.h"
|
||||||
|
#include "nodes/makefuncs.h"
|
||||||
|
#include "nodes/parsenodes.h"
|
||||||
|
#include "nodes/primnodes.h"
|
||||||
|
|
||||||
|
static Node * RecreateForeignServerStmt(Oid serverId);
|
||||||
|
static bool NameListHasDistributedServer(List *serverNames);
|
||||||
|
static ObjectAddress GetObjectAddressByServerName(char *serverName, bool missing_ok);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PreprocessCreateForeignServerStmt is called during the planning phase for
|
||||||
|
* CREATE SERVER.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
PreprocessCreateForeignServerStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext processUtilityContext)
|
||||||
|
{
|
||||||
|
if (!ShouldPropagate())
|
||||||
|
{
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureCoordinator();
|
||||||
|
|
||||||
|
char *sql = DeparseTreeNode(node);
|
||||||
|
|
||||||
|
/* to prevent recursion with mx we disable ddl propagation */
|
||||||
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||||
|
(void *) sql,
|
||||||
|
ENABLE_DDL_PROPAGATION);
|
||||||
|
|
||||||
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PreprocessAlterForeignServerStmt is called during the planning phase for
|
||||||
|
* ALTER SERVER .. OPTIONS ..
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
PreprocessAlterForeignServerStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext processUtilityContext)
|
||||||
|
{
|
||||||
|
AlterForeignServerStmt *stmt = castNode(AlterForeignServerStmt, node);
|
||||||
|
|
||||||
|
ObjectAddress address = GetObjectAddressByServerName(stmt->servername, false);
|
||||||
|
|
||||||
|
if (!ShouldPropagateObject(&address))
|
||||||
|
{
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureCoordinator();
|
||||||
|
|
||||||
|
char *sql = DeparseTreeNode(node);
|
||||||
|
|
||||||
|
/* to prevent recursion with mx we disable ddl propagation */
|
||||||
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||||
|
(void *) sql,
|
||||||
|
ENABLE_DDL_PROPAGATION);
|
||||||
|
|
||||||
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PreprocessRenameForeignServerStmt is called during the planning phase for
|
||||||
|
* ALTER SERVER RENAME.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
PreprocessRenameForeignServerStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext processUtilityContext)
|
||||||
|
{
|
||||||
|
RenameStmt *stmt = castNode(RenameStmt, node);
|
||||||
|
Assert(stmt->renameType == OBJECT_FOREIGN_SERVER);
|
||||||
|
|
||||||
|
ObjectAddress address = GetObjectAddressByServerName(strVal(stmt->object), false);
|
||||||
|
|
||||||
|
/* filter distributed servers */
|
||||||
|
if (!ShouldPropagateObject(&address))
|
||||||
|
{
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureCoordinator();
|
||||||
|
|
||||||
|
char *sql = DeparseTreeNode(node);
|
||||||
|
|
||||||
|
/* to prevent recursion with mx we disable ddl propagation */
|
||||||
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||||
|
(void *) sql,
|
||||||
|
ENABLE_DDL_PROPAGATION);
|
||||||
|
|
||||||
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PreprocessAlterForeignServerOwnerStmt is called during the planning phase for
|
||||||
|
* ALTER SERVER .. OWNER TO.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
PreprocessAlterForeignServerOwnerStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext processUtilityContext)
|
||||||
|
{
|
||||||
|
AlterOwnerStmt *stmt = castNode(AlterOwnerStmt, node);
|
||||||
|
Assert(stmt->objectType == OBJECT_FOREIGN_SERVER);
|
||||||
|
|
||||||
|
ObjectAddress address = GetObjectAddressByServerName(strVal(stmt->object), false);
|
||||||
|
|
||||||
|
/* filter distributed servers */
|
||||||
|
if (!ShouldPropagateObject(&address))
|
||||||
|
{
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureCoordinator();
|
||||||
|
|
||||||
|
char *sql = DeparseTreeNode(node);
|
||||||
|
|
||||||
|
/* to prevent recursion with mx we disable ddl propagation */
|
||||||
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||||
|
(void *) sql,
|
||||||
|
ENABLE_DDL_PROPAGATION);
|
||||||
|
|
||||||
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PreprocessDropForeignServerStmt is called during the planning phase for
|
||||||
|
* DROP SERVER.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
PreprocessDropForeignServerStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext processUtilityContext)
|
||||||
|
{
|
||||||
|
DropStmt *stmt = castNode(DropStmt, node);
|
||||||
|
Assert(stmt->removeType == OBJECT_FOREIGN_SERVER);
|
||||||
|
|
||||||
|
bool includesDistributedServer = NameListHasDistributedServer(stmt->objects);
|
||||||
|
|
||||||
|
if (!includesDistributedServer)
|
||||||
|
{
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list_length(stmt->objects) > 1)
|
||||||
|
{
|
||||||
|
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("cannot drop distributed server with other servers"),
|
||||||
|
errhint("Try dropping each object in a separate DROP command")));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ShouldPropagate())
|
||||||
|
{
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureCoordinator();
|
||||||
|
|
||||||
|
Assert(list_length(stmt->objects) == 1);
|
||||||
|
|
||||||
|
Value *serverValue = linitial(stmt->objects);
|
||||||
|
ObjectAddress address = GetObjectAddressByServerName(strVal(serverValue), false);
|
||||||
|
|
||||||
|
/* unmark distributed server */
|
||||||
|
UnmarkObjectDistributed(&address);
|
||||||
|
|
||||||
|
const char *deparsedStmt = DeparseTreeNode((Node *) stmt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To prevent recursive propagation in mx architecture, we disable ddl
|
||||||
|
* propagation before sending the command to workers.
|
||||||
|
*/
|
||||||
|
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||||
|
(void *) deparsedStmt,
|
||||||
|
ENABLE_DDL_PROPAGATION);
|
||||||
|
|
||||||
|
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PostprocessCreateForeignServerStmt is called after a CREATE SERVER command has
|
||||||
|
* been executed by standard process utility.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
PostprocessCreateForeignServerStmt(Node *node, const char *queryString)
|
||||||
|
{
|
||||||
|
bool missingOk = false;
|
||||||
|
ObjectAddress address = GetObjectAddressFromParseTree(node, missingOk);
|
||||||
|
EnsureDependenciesExistOnAllNodes(&address);
|
||||||
|
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PostprocessAlterForeignServerOwnerStmt is called after a ALTER SERVER OWNER command
|
||||||
|
* has been executed by standard process utility.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
PostprocessAlterForeignServerOwnerStmt(Node *node, const char *queryString)
|
||||||
|
{
|
||||||
|
bool missingOk = false;
|
||||||
|
ObjectAddress address = GetObjectAddressFromParseTree(node, missingOk);
|
||||||
|
EnsureDependenciesExistOnAllNodes(&address);
|
||||||
|
|
||||||
|
return NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CreateForeignServerStmtObjectAddress finds the ObjectAddress for the server
|
||||||
|
* that is created by given CreateForeignServerStmt. If missingOk is false and if
|
||||||
|
* the server does not exist, then it errors out.
|
||||||
|
*
|
||||||
|
* Never returns NULL, but the objid in the address can be invalid if missingOk
|
||||||
|
* was set to true.
|
||||||
|
*/
|
||||||
|
ObjectAddress
|
||||||
|
CreateForeignServerStmtObjectAddress(Node *node, bool missing_ok)
|
||||||
|
{
|
||||||
|
CreateForeignServerStmt *stmt = castNode(CreateForeignServerStmt, node);
|
||||||
|
|
||||||
|
return GetObjectAddressByServerName(stmt->servername, missing_ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AlterForeignServerOwnerStmtObjectAddress finds the ObjectAddress for the server
|
||||||
|
* given in AlterOwnerStmt. If missingOk is false and if
|
||||||
|
* the server does not exist, then it errors out.
|
||||||
|
*
|
||||||
|
* Never returns NULL, but the objid in the address can be invalid if missingOk
|
||||||
|
* was set to true.
|
||||||
|
*/
|
||||||
|
ObjectAddress
|
||||||
|
AlterForeignServerOwnerStmtObjectAddress(Node *node, bool missing_ok)
|
||||||
|
{
|
||||||
|
AlterOwnerStmt *stmt = castNode(AlterOwnerStmt, node);
|
||||||
|
char *serverName = strVal(stmt->object);
|
||||||
|
|
||||||
|
return GetObjectAddressByServerName(serverName, missing_ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GetForeignServerCreateDDLCommand returns a list that includes the CREATE SERVER
|
||||||
|
* command that would recreate the given server on a new node.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
GetForeignServerCreateDDLCommand(Oid serverId)
|
||||||
|
{
|
||||||
|
/* generate a statement for creation of the server in "if not exists" construct */
|
||||||
|
Node *stmt = RecreateForeignServerStmt(serverId);
|
||||||
|
|
||||||
|
/* capture ddl command for the create statement */
|
||||||
|
const char *ddlCommand = DeparseTreeNode(stmt);
|
||||||
|
|
||||||
|
List *ddlCommands = list_make1((void *) ddlCommand);
|
||||||
|
|
||||||
|
return ddlCommands;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RecreateForeignServerStmt returns a parsetree for a CREATE SERVER statement
|
||||||
|
* that would recreate the given server on a new node.
|
||||||
|
*/
|
||||||
|
static Node *
|
||||||
|
RecreateForeignServerStmt(Oid serverId)
|
||||||
|
{
|
||||||
|
ForeignServer *server = GetForeignServer(serverId);
|
||||||
|
|
||||||
|
CreateForeignServerStmt *createStmt = makeNode(CreateForeignServerStmt);
|
||||||
|
|
||||||
|
/* set server name and if_not_exists fields */
|
||||||
|
createStmt->servername = pstrdup(server->servername);
|
||||||
|
createStmt->if_not_exists = true;
|
||||||
|
|
||||||
|
/* set foreign data wrapper */
|
||||||
|
ForeignDataWrapper *fdw = GetForeignDataWrapper(server->fdwid);
|
||||||
|
createStmt->fdwname = pstrdup(fdw->fdwname);
|
||||||
|
|
||||||
|
/* set all fields using the existing server */
|
||||||
|
if (server->servertype != NULL)
|
||||||
|
{
|
||||||
|
createStmt->servertype = pstrdup(server->servertype);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server->serverversion != NULL)
|
||||||
|
{
|
||||||
|
createStmt->version = pstrdup(server->serverversion);
|
||||||
|
}
|
||||||
|
|
||||||
|
createStmt->options = NIL;
|
||||||
|
|
||||||
|
int location = -1;
|
||||||
|
DefElem *option = NULL;
|
||||||
|
foreach_ptr(option, server->options)
|
||||||
|
{
|
||||||
|
DefElem *copyOption = makeDefElem(option->defname, option->arg, location);
|
||||||
|
createStmt->options = lappend(createStmt->options, copyOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (Node *) createStmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NameListHasDistributedServer takes a namelist of servers and returns true if at least
|
||||||
|
* one of them is distributed. Returns false otherwise.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
NameListHasDistributedServer(List *serverNames)
|
||||||
|
{
|
||||||
|
Value *serverValue = NULL;
|
||||||
|
foreach_ptr(serverValue, serverNames)
|
||||||
|
{
|
||||||
|
ObjectAddress address = GetObjectAddressByServerName(strVal(serverValue), false);
|
||||||
|
|
||||||
|
if (IsObjectDistributed(&address))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ObjectAddress
|
||||||
|
GetObjectAddressByServerName(char *serverName, bool missing_ok)
|
||||||
|
{
|
||||||
|
ForeignServer *server = GetForeignServerByName(serverName, missing_ok);
|
||||||
|
Oid serverOid = server->serverid;
|
||||||
|
ObjectAddress address = { 0 };
|
||||||
|
ObjectAddressSet(address, ForeignServerRelationId, serverOid);
|
||||||
|
|
||||||
|
return address;
|
||||||
|
}
|
|
@ -77,7 +77,6 @@
|
||||||
|
|
||||||
static void deparse_index_columns(StringInfo buffer, List *indexParameterList,
|
static void deparse_index_columns(StringInfo buffer, List *indexParameterList,
|
||||||
List *deparseContext);
|
List *deparseContext);
|
||||||
static void AppendOptionListToString(StringInfo stringData, List *options);
|
|
||||||
static void AppendStorageParametersToString(StringInfo stringBuffer,
|
static void AppendStorageParametersToString(StringInfo stringBuffer,
|
||||||
List *optionList);
|
List *optionList);
|
||||||
static void simple_quote_literal(StringInfo buf, const char *val);
|
static void simple_quote_literal(StringInfo buf, const char *val);
|
||||||
|
@ -1056,7 +1055,7 @@ generate_qualified_relation_name(Oid relid)
|
||||||
* AppendOptionListToString converts the option list to its textual format, and
|
* AppendOptionListToString converts the option list to its textual format, and
|
||||||
* appends this text to the given string buffer.
|
* appends this text to the given string buffer.
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
AppendOptionListToString(StringInfo stringBuffer, List *optionList)
|
AppendOptionListToString(StringInfo stringBuffer, List *optionList)
|
||||||
{
|
{
|
||||||
if (optionList != NIL)
|
if (optionList != NIL)
|
||||||
|
|
|
@ -0,0 +1,277 @@
|
||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* deparse_foreign_server_stmts.c
|
||||||
|
* All routines to deparse foreign server statements.
|
||||||
|
*
|
||||||
|
* Copyright (c) Citus Data, Inc.
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "commands/defrem.h"
|
||||||
|
#include "distributed/citus_ruleutils.h"
|
||||||
|
#include "distributed/deparser.h"
|
||||||
|
#include "distributed/listutils.h"
|
||||||
|
#include "distributed/relay_utility.h"
|
||||||
|
#include "lib/stringinfo.h"
|
||||||
|
#include "nodes/nodes.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
|
static void AppendCreateForeignServerStmt(StringInfo buf, CreateForeignServerStmt *stmt);
|
||||||
|
static void AppendAlterForeignServerStmt(StringInfo buf, AlterForeignServerStmt *stmt);
|
||||||
|
static void AppendAlterForeignServerOptions(StringInfo buf, AlterForeignServerStmt *stmt);
|
||||||
|
static void AppendAlterForeignServerRenameStmt(StringInfo buf, RenameStmt *stmt);
|
||||||
|
static void AppendAlterForeignServerOwnerStmt(StringInfo buf, AlterOwnerStmt *stmt);
|
||||||
|
static void AppendDropForeignServerStmt(StringInfo buf, DropStmt *stmt);
|
||||||
|
static void AppendServerNames(StringInfo buf, DropStmt *stmt);
|
||||||
|
static void AppendBehavior(StringInfo buf, DropStmt *stmt);
|
||||||
|
static char * GetDefElemActionString(DefElemAction action);
|
||||||
|
|
||||||
|
char *
|
||||||
|
DeparseCreateForeignServerStmt(Node *node)
|
||||||
|
{
|
||||||
|
CreateForeignServerStmt *stmt = castNode(CreateForeignServerStmt, node);
|
||||||
|
|
||||||
|
StringInfoData str;
|
||||||
|
initStringInfo(&str);
|
||||||
|
|
||||||
|
AppendCreateForeignServerStmt(&str, stmt);
|
||||||
|
|
||||||
|
return str.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *
|
||||||
|
DeparseAlterForeignServerStmt(Node *node)
|
||||||
|
{
|
||||||
|
AlterForeignServerStmt *stmt = castNode(AlterForeignServerStmt, node);
|
||||||
|
|
||||||
|
StringInfoData str;
|
||||||
|
initStringInfo(&str);
|
||||||
|
|
||||||
|
AppendAlterForeignServerStmt(&str, stmt);
|
||||||
|
|
||||||
|
return str.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *
|
||||||
|
DeparseAlterForeignServerRenameStmt(Node *node)
|
||||||
|
{
|
||||||
|
RenameStmt *stmt = castNode(RenameStmt, node);
|
||||||
|
|
||||||
|
Assert(stmt->renameType == OBJECT_FOREIGN_SERVER);
|
||||||
|
|
||||||
|
StringInfoData str;
|
||||||
|
initStringInfo(&str);
|
||||||
|
|
||||||
|
AppendAlterForeignServerRenameStmt(&str, stmt);
|
||||||
|
|
||||||
|
return str.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *
|
||||||
|
DeparseAlterForeignServerOwnerStmt(Node *node)
|
||||||
|
{
|
||||||
|
AlterOwnerStmt *stmt = castNode(AlterOwnerStmt, node);
|
||||||
|
|
||||||
|
Assert(stmt->objectType == OBJECT_FOREIGN_SERVER);
|
||||||
|
|
||||||
|
StringInfoData str;
|
||||||
|
initStringInfo(&str);
|
||||||
|
|
||||||
|
AppendAlterForeignServerOwnerStmt(&str, stmt);
|
||||||
|
|
||||||
|
return str.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *
|
||||||
|
DeparseDropForeignServerStmt(Node *node)
|
||||||
|
{
|
||||||
|
DropStmt *stmt = castNode(DropStmt, node);
|
||||||
|
|
||||||
|
Assert(stmt->removeType == OBJECT_FOREIGN_SERVER);
|
||||||
|
|
||||||
|
StringInfoData str;
|
||||||
|
initStringInfo(&str);
|
||||||
|
|
||||||
|
AppendDropForeignServerStmt(&str, stmt);
|
||||||
|
|
||||||
|
return str.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
AppendCreateForeignServerStmt(StringInfo buf, CreateForeignServerStmt *stmt)
|
||||||
|
{
|
||||||
|
appendStringInfoString(buf, "CREATE SERVER ");
|
||||||
|
|
||||||
|
if (stmt->if_not_exists)
|
||||||
|
{
|
||||||
|
appendStringInfoString(buf, "IF NOT EXISTS ");
|
||||||
|
}
|
||||||
|
|
||||||
|
appendStringInfo(buf, "%s ", quote_identifier(stmt->servername));
|
||||||
|
|
||||||
|
if (stmt->servertype)
|
||||||
|
{
|
||||||
|
appendStringInfo(buf, "TYPE %s ", quote_literal_cstr(stmt->servertype));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stmt->version)
|
||||||
|
{
|
||||||
|
appendStringInfo(buf, "VERSION %s ", quote_literal_cstr(stmt->version));
|
||||||
|
}
|
||||||
|
|
||||||
|
appendStringInfo(buf, "FOREIGN DATA WRAPPER %s ", quote_identifier(stmt->fdwname));
|
||||||
|
|
||||||
|
AppendOptionListToString(buf, stmt->options);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
AppendAlterForeignServerStmt(StringInfo buf, AlterForeignServerStmt *stmt)
|
||||||
|
{
|
||||||
|
appendStringInfo(buf, "ALTER SERVER %s ", quote_identifier(stmt->servername));
|
||||||
|
|
||||||
|
if (stmt->has_version)
|
||||||
|
{
|
||||||
|
appendStringInfo(buf, "VERSION %s ", quote_literal_cstr(stmt->version));
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendAlterForeignServerOptions(buf, stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
AppendAlterForeignServerOptions(StringInfo buf, AlterForeignServerStmt *stmt)
|
||||||
|
{
|
||||||
|
if (list_length(stmt->options) <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
appendStringInfoString(buf, "OPTIONS (");
|
||||||
|
|
||||||
|
DefElemAction action = DEFELEM_UNSPEC;
|
||||||
|
DefElem *def = NULL;
|
||||||
|
foreach_ptr(def, stmt->options)
|
||||||
|
{
|
||||||
|
if (def->defaction != DEFELEM_UNSPEC)
|
||||||
|
{
|
||||||
|
action = def->defaction;
|
||||||
|
char *actionString = GetDefElemActionString(action);
|
||||||
|
appendStringInfo(buf, "%s ", actionString);
|
||||||
|
}
|
||||||
|
|
||||||
|
appendStringInfo(buf, "%s", quote_identifier(def->defname));
|
||||||
|
|
||||||
|
if (action != DEFELEM_DROP)
|
||||||
|
{
|
||||||
|
const char *value = quote_literal_cstr(defGetString(def));
|
||||||
|
appendStringInfo(buf, " %s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (def != llast(stmt->options))
|
||||||
|
{
|
||||||
|
appendStringInfoString(buf, ", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appendStringInfoString(buf, ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
AppendAlterForeignServerRenameStmt(StringInfo buf, RenameStmt *stmt)
|
||||||
|
{
|
||||||
|
appendStringInfo(buf, "ALTER SERVER %s RENAME TO %s",
|
||||||
|
quote_identifier(strVal(stmt->object)),
|
||||||
|
quote_identifier(stmt->newname));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
AppendAlterForeignServerOwnerStmt(StringInfo buf, AlterOwnerStmt *stmt)
|
||||||
|
{
|
||||||
|
const char *servername = quote_identifier(strVal(stmt->object));
|
||||||
|
appendStringInfo(buf, "ALTER SERVER %s OWNER TO ", servername);
|
||||||
|
|
||||||
|
appendStringInfo(buf, "%s", RoleSpecString(stmt->newowner, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
AppendDropForeignServerStmt(StringInfo buf, DropStmt *stmt)
|
||||||
|
{
|
||||||
|
appendStringInfoString(buf, "DROP SERVER ");
|
||||||
|
|
||||||
|
if (stmt->missing_ok)
|
||||||
|
{
|
||||||
|
appendStringInfoString(buf, "IF EXISTS ");
|
||||||
|
}
|
||||||
|
|
||||||
|
AppendServerNames(buf, stmt);
|
||||||
|
|
||||||
|
AppendBehavior(buf, stmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
AppendServerNames(StringInfo buf, DropStmt *stmt)
|
||||||
|
{
|
||||||
|
Value *serverValue = NULL;
|
||||||
|
foreach_ptr(serverValue, stmt->objects)
|
||||||
|
{
|
||||||
|
const char *serverString = quote_identifier(strVal(serverValue));
|
||||||
|
appendStringInfo(buf, "%s", serverString);
|
||||||
|
|
||||||
|
if (serverValue != llast(stmt->objects))
|
||||||
|
{
|
||||||
|
appendStringInfoString(buf, ", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
AppendBehavior(StringInfo buf, DropStmt *stmt)
|
||||||
|
{
|
||||||
|
if (stmt->behavior == DROP_CASCADE)
|
||||||
|
{
|
||||||
|
appendStringInfoString(buf, " CASCADE");
|
||||||
|
}
|
||||||
|
else if (stmt->behavior == DROP_RESTRICT)
|
||||||
|
{
|
||||||
|
appendStringInfoString(buf, " RESTRICT");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
GetDefElemActionString(DefElemAction action)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case DEFELEM_ADD:
|
||||||
|
{
|
||||||
|
return "ADD";
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEFELEM_SET:
|
||||||
|
{
|
||||||
|
return "SET";
|
||||||
|
}
|
||||||
|
|
||||||
|
case DEFELEM_DROP:
|
||||||
|
{
|
||||||
|
return "DROP";
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
|
@ -612,6 +612,11 @@ SupportedDependencyByCitus(const ObjectAddress *address)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OCLASS_FOREIGN_SERVER:
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
case OCLASS_ROLE:
|
case OCLASS_ROLE:
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -456,6 +456,14 @@ ErrorIfCurrentUserCanNotDistributeObject(ObjectType type, ObjectAddress *addr,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OBJECT_FOREIGN_SERVER:
|
||||||
|
{
|
||||||
|
idToCheck = addr->objectId;
|
||||||
|
aclMaskResult = pg_foreign_server_aclmask(idToCheck, userId, ACL_USAGE,
|
||||||
|
ACLMASK_ANY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case OBJECT_SEQUENCE:
|
case OBJECT_SEQUENCE:
|
||||||
{
|
{
|
||||||
idToCheck = addr->objectId;
|
idToCheck = addr->objectId;
|
||||||
|
|
|
@ -65,6 +65,7 @@ extern char * generate_relation_name(Oid relid, List *namespaces);
|
||||||
extern char * generate_qualified_relation_name(Oid relid);
|
extern char * generate_qualified_relation_name(Oid relid);
|
||||||
extern char * generate_operator_name(Oid operid, Oid arg1, Oid arg2);
|
extern char * generate_operator_name(Oid operid, Oid arg1, Oid arg2);
|
||||||
extern List * getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype);
|
extern List * getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype);
|
||||||
|
extern void AppendOptionListToString(StringInfo stringData, List *options);
|
||||||
|
|
||||||
|
|
||||||
#endif /* CITUS_RULEUTILS_H */
|
#endif /* CITUS_RULEUTILS_H */
|
||||||
|
|
|
@ -225,6 +225,27 @@ extern Oid GetReferencedTableId(Oid foreignKeyId);
|
||||||
extern Oid GetReferencingTableId(Oid foreignKeyId);
|
extern Oid GetReferencingTableId(Oid foreignKeyId);
|
||||||
extern bool RelationInvolvedInAnyNonInheritedForeignKeys(Oid relationId);
|
extern bool RelationInvolvedInAnyNonInheritedForeignKeys(Oid relationId);
|
||||||
|
|
||||||
|
/* foreign_server.c - forward declarations */
|
||||||
|
extern List * PreprocessCreateForeignServerStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext
|
||||||
|
processUtilityContext);
|
||||||
|
extern List * PreprocessAlterForeignServerStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext processUtilityContext);
|
||||||
|
extern List * PreprocessRenameForeignServerStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext
|
||||||
|
processUtilityContext);
|
||||||
|
extern List * PreprocessAlterForeignServerOwnerStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext
|
||||||
|
processUtilityContext);
|
||||||
|
extern List * PreprocessDropForeignServerStmt(Node *node, const char *queryString,
|
||||||
|
ProcessUtilityContext
|
||||||
|
processUtilityContext);
|
||||||
|
extern List * PostprocessCreateForeignServerStmt(Node *node, const char *queryString);
|
||||||
|
extern List * PostprocessAlterForeignServerOwnerStmt(Node *node, const char *queryString);
|
||||||
|
extern ObjectAddress CreateForeignServerStmtObjectAddress(Node *node, bool missing_ok);
|
||||||
|
extern ObjectAddress AlterForeignServerOwnerStmtObjectAddress(Node *node, bool
|
||||||
|
missing_ok);
|
||||||
|
extern List * GetForeignServerCreateDDLCommand(Oid serverId);
|
||||||
|
|
||||||
/* function.c - forward declarations */
|
/* function.c - forward declarations */
|
||||||
extern List * PreprocessCreateFunctionStmt(Node *stmt, const char *queryString,
|
extern List * PreprocessCreateFunctionStmt(Node *stmt, const char *queryString,
|
||||||
|
|
|
@ -46,6 +46,13 @@ extern void QualifyRenameCollationStmt(Node *stmt);
|
||||||
extern void QualifyAlterCollationSchemaStmt(Node *stmt);
|
extern void QualifyAlterCollationSchemaStmt(Node *stmt);
|
||||||
extern void QualifyAlterCollationOwnerStmt(Node *stmt);
|
extern void QualifyAlterCollationOwnerStmt(Node *stmt);
|
||||||
|
|
||||||
|
/* forward declarations for deparse_foreign_server_stmts.c */
|
||||||
|
extern char * DeparseCreateForeignServerStmt(Node *node);
|
||||||
|
extern char * DeparseAlterForeignServerStmt(Node *node);
|
||||||
|
extern char * DeparseAlterForeignServerRenameStmt(Node *node);
|
||||||
|
extern char * DeparseAlterForeignServerOwnerStmt(Node *node);
|
||||||
|
extern char * DeparseDropForeignServerStmt(Node *node);
|
||||||
|
|
||||||
/* forward declarations for deparse_table_stmts.c */
|
/* forward declarations for deparse_table_stmts.c */
|
||||||
extern char * DeparseAlterTableSchemaStmt(Node *stmt);
|
extern char * DeparseAlterTableSchemaStmt(Node *stmt);
|
||||||
extern char * DeparseAlterTableStmt(Node *node);
|
extern char * DeparseAlterTableStmt(Node *node);
|
||||||
|
|
|
@ -612,7 +612,7 @@ SELECT create_distributed_function('eq_with_param_names(macaddr, macaddr)', dist
|
||||||
SELECT * FROM (SELECT unnest(master_metadata_snapshot()) as metadata_command order by 1) as innerResult WHERE metadata_command like '%distributed_object_data%';
|
SELECT * FROM (SELECT unnest(master_metadata_snapshot()) as metadata_command order by 1) as innerResult WHERE metadata_command like '%distributed_object_data%';
|
||||||
metadata_command
|
metadata_command
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
WITH distributed_object_data(typetext, objnames, objargs, distargumentindex, colocationid) AS (VALUES ('type', ARRAY['public.usage_access_type']::text[], ARRAY[]::text[], -1, 0), ('type', ARRAY['function_tests.dup_result']::text[], ARRAY[]::text[], -1, 0), ('function', ARRAY['public', 'usage_access_func']::text[], ARRAY['public.usage_access_type', 'integer[]']::text[], -1, 0), ('function', ARRAY['public', 'usage_access_func_third']::text[], ARRAY['integer', 'integer[]']::text[], 0, 50), ('function', ARRAY['function_tests', 'notice']::text[], ARRAY['pg_catalog.text']::text[], -1, 0), ('function', ARRAY['function_tests', 'dup']::text[], ARRAY['pg_catalog.macaddr']::text[], 0, 52), ('function', ARRAY['function_tests', 'eq_with_param_names']::text[], ARRAY['pg_catalog.macaddr', 'pg_catalog.macaddr']::text[], 0, 52), ('function', ARRAY['function_tests', 'eq_mi''xed_param_names']::text[], ARRAY['pg_catalog.macaddr', 'pg_catalog.macaddr']::text[], -1, 0), ('function', ARRAY['function_tests', 'agg_sfunc']::text[], ARRAY['integer', 'integer']::text[], -1, 0), ('function', ARRAY['function_tests', 'agg_invfunc']::text[], ARRAY['integer', 'integer']::text[], -1, 0), ('function', ARRAY['function_tests', 'agg_finalfunc']::text[], ARRAY['integer', 'integer']::text[], -1, 0), ('aggregate', ARRAY['function_tests', 'my_rank']::text[], ARRAY['pg_catalog."any"']::text[], -1, 0), ('function', ARRAY['function_tests', 'agg_names_sfunc']::text[], ARRAY['function_tests.dup_result', 'function_tests.dup_result', 'function_tests.dup_result']::text[], -1, 0), ('function', ARRAY['function_tests', 'agg_names_finalfunc']::text[], ARRAY['function_tests.dup_result']::text[], -1, 0), ('aggregate', ARRAY['function_tests', 'agg_names']::text[], ARRAY['function_tests.dup_result', 'function_tests.dup_result']::text[], -1, 0), ('sequence', ARRAY['public', 'user_defined_seq']::text[], ARRAY[]::text[], -1, 0), ('role', ARRAY['postgres']::text[], ARRAY[]::text[], -1, 0), ('database', ARRAY['regression']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['public']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['mx_testing_schema']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['mx_testing_schema_2']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['mx_test_schema_1']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['mx_test_schema_2']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['schema_colocation']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['function_tests']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['function_tests2']::text[], ARRAY[]::text[], -1, 0), ('extension', ARRAY['plpgsql']::text[], ARRAY[]::text[], -1, 0)) SELECT citus_internal_add_object_metadata(typetext, objnames, objargs, distargumentindex::int, colocationid::int) FROM distributed_object_data;
|
WITH distributed_object_data(typetext, objnames, objargs, distargumentindex, colocationid) AS (VALUES ('type', ARRAY['public.usage_access_type']::text[], ARRAY[]::text[], -1, 0), ('type', ARRAY['function_tests.dup_result']::text[], ARRAY[]::text[], -1, 0), ('function', ARRAY['public', 'usage_access_func']::text[], ARRAY['public.usage_access_type', 'integer[]']::text[], -1, 0), ('function', ARRAY['public', 'usage_access_func_third']::text[], ARRAY['integer', 'integer[]']::text[], 0, 50), ('function', ARRAY['function_tests', 'notice']::text[], ARRAY['pg_catalog.text']::text[], -1, 0), ('function', ARRAY['function_tests', 'dup']::text[], ARRAY['pg_catalog.macaddr']::text[], 0, 52), ('function', ARRAY['function_tests', 'eq_with_param_names']::text[], ARRAY['pg_catalog.macaddr', 'pg_catalog.macaddr']::text[], 0, 52), ('function', ARRAY['function_tests', 'eq_mi''xed_param_names']::text[], ARRAY['pg_catalog.macaddr', 'pg_catalog.macaddr']::text[], -1, 0), ('function', ARRAY['function_tests', 'agg_sfunc']::text[], ARRAY['integer', 'integer']::text[], -1, 0), ('function', ARRAY['function_tests', 'agg_invfunc']::text[], ARRAY['integer', 'integer']::text[], -1, 0), ('function', ARRAY['function_tests', 'agg_finalfunc']::text[], ARRAY['integer', 'integer']::text[], -1, 0), ('aggregate', ARRAY['function_tests', 'my_rank']::text[], ARRAY['pg_catalog."any"']::text[], -1, 0), ('function', ARRAY['function_tests', 'agg_names_sfunc']::text[], ARRAY['function_tests.dup_result', 'function_tests.dup_result', 'function_tests.dup_result']::text[], -1, 0), ('function', ARRAY['function_tests', 'agg_names_finalfunc']::text[], ARRAY['function_tests.dup_result']::text[], -1, 0), ('aggregate', ARRAY['function_tests', 'agg_names']::text[], ARRAY['function_tests.dup_result', 'function_tests.dup_result']::text[], -1, 0), ('sequence', ARRAY['public', 'user_defined_seq']::text[], ARRAY[]::text[], -1, 0), ('role', ARRAY['postgres']::text[], ARRAY[]::text[], -1, 0), ('database', ARRAY['regression']::text[], ARRAY[]::text[], -1, 0), ('server', ARRAY['fake_fdw_server']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['public']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['mx_testing_schema']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['mx_testing_schema_2']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['mx_test_schema_1']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['mx_test_schema_2']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['schema_colocation']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['function_tests']::text[], ARRAY[]::text[], -1, 0), ('schema', ARRAY['function_tests2']::text[], ARRAY[]::text[], -1, 0), ('extension', ARRAY['plpgsql']::text[], ARRAY[]::text[], -1, 0)) SELECT citus_internal_add_object_metadata(typetext, objnames, objargs, distargumentindex::int, colocationid::int) FROM distributed_object_data;
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
-- valid distribution with distribution_arg_index
|
-- valid distribution with distribution_arg_index
|
||||||
|
|
|
@ -62,6 +62,15 @@ RETURNS fdw_handler
|
||||||
AS 'citus'
|
AS 'citus'
|
||||||
LANGUAGE C STRICT;
|
LANGUAGE C STRICT;
|
||||||
CREATE FOREIGN DATA WRAPPER fake_fdw_1 HANDLER fake_fdw_handler;
|
CREATE FOREIGN DATA WRAPPER fake_fdw_1 HANDLER fake_fdw_handler;
|
||||||
|
SELECT run_command_on_workers($$
|
||||||
|
CREATE FOREIGN DATA WRAPPER fake_fdw_1 HANDLER fake_fdw_handler;
|
||||||
|
$$);
|
||||||
|
run_command_on_workers
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
(localhost,57637,t,"CREATE FOREIGN DATA WRAPPER")
|
||||||
|
(localhost,57638,t,"CREATE FOREIGN DATA WRAPPER")
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
CREATE SERVER fake_fdw_server_1 FOREIGN DATA WRAPPER fake_fdw_1;
|
CREATE SERVER fake_fdw_server_1 FOREIGN DATA WRAPPER fake_fdw_1;
|
||||||
CREATE FOREIGN TABLE foreign_table (
|
CREATE FOREIGN TABLE foreign_table (
|
||||||
key int,
|
key int,
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
CREATE SCHEMA propagate_foreign_server;
|
||||||
|
SET search_path TO propagate_foreign_server;
|
||||||
|
-- remove node to add later
|
||||||
|
SELECT citus_remove_node('localhost', :worker_1_port);
|
||||||
|
citus_remove_node
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- create schema, extension and foreign server while the worker is removed
|
||||||
|
SET citus.enable_ddl_propagation TO OFF;
|
||||||
|
CREATE SCHEMA test_dependent_schema;
|
||||||
|
CREATE EXTENSION postgres_fdw WITH SCHEMA test_dependent_schema;
|
||||||
|
SET citus.enable_ddl_propagation TO ON;
|
||||||
|
CREATE SERVER foreign_server_dependent_schema
|
||||||
|
FOREIGN DATA WRAPPER postgres_fdw
|
||||||
|
OPTIONS (host 'test');
|
||||||
|
SELECT 1 FROM citus_add_node('localhost', :worker_1_port);
|
||||||
|
?column?
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- verify the dependent schema and the foreign server are created on the newly added worker
|
||||||
|
SELECT run_command_on_workers(
|
||||||
|
$$SELECT COUNT(*) FROM pg_namespace WHERE nspname = 'test_dependent_schema';$$);
|
||||||
|
run_command_on_workers
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
(localhost,57637,t,1)
|
||||||
|
(localhost,57638,t,1)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT run_command_on_workers(
|
||||||
|
$$SELECT COUNT(*)=1 FROM pg_foreign_server WHERE srvname = 'foreign_server_dependent_schema';$$);
|
||||||
|
run_command_on_workers
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
(localhost,57637,t,t)
|
||||||
|
(localhost,57638,t,t)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
CREATE SERVER foreign_server_to_drop
|
||||||
|
FOREIGN DATA WRAPPER postgres_fdw
|
||||||
|
OPTIONS (host 'test');
|
||||||
|
--should error
|
||||||
|
DROP SERVER foreign_server_dependent_schema, foreign_server_to_drop;
|
||||||
|
ERROR: cannot drop distributed server with other servers
|
||||||
|
HINT: Try dropping each object in a separate DROP command
|
||||||
|
SET client_min_messages TO ERROR;
|
||||||
|
DROP SCHEMA test_dependent_schema CASCADE;
|
||||||
|
RESET client_min_messages;
|
||||||
|
-- test propagating foreign server creation
|
||||||
|
CREATE EXTENSION postgres_fdw;
|
||||||
|
CREATE SERVER foreign_server TYPE 'test_type' VERSION 'v1'
|
||||||
|
FOREIGN DATA WRAPPER postgres_fdw
|
||||||
|
OPTIONS (host 'testhost', port '5432', dbname 'testdb');
|
||||||
|
SELECT COUNT(*)=1 FROM pg_foreign_server WHERE srvname = 'foreign_server';
|
||||||
|
?column?
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- verify that the server is created on the worker
|
||||||
|
SELECT run_command_on_workers(
|
||||||
|
$$SELECT COUNT(*)=1 FROM pg_foreign_server WHERE srvname = 'foreign_server';$$);
|
||||||
|
run_command_on_workers
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
(localhost,57637,t,t)
|
||||||
|
(localhost,57638,t,t)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
ALTER SERVER foreign_server OPTIONS (ADD "fdw_startup_cost" '1000');
|
||||||
|
ALTER SERVER foreign_server OPTIONS (ADD passfile 'to_be_dropped');
|
||||||
|
ALTER SERVER foreign_server OPTIONS (SET host 'localhost');
|
||||||
|
ALTER SERVER foreign_server OPTIONS (DROP port, DROP dbname);
|
||||||
|
ALTER SERVER foreign_server OPTIONS (ADD port :'master_port', dbname 'regression', DROP passfile);
|
||||||
|
ALTER SERVER foreign_server RENAME TO "foreign'server_1!";
|
||||||
|
-- test alter owner
|
||||||
|
SELECT rolname FROM pg_roles JOIN pg_foreign_server ON (pg_roles.oid=pg_foreign_server.srvowner) WHERE srvname = 'foreign''server_1!';
|
||||||
|
rolname
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
postgres
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
ALTER SERVER "foreign'server_1!" OWNER TO pg_monitor;
|
||||||
|
-- verify that the server is renamed on the worker
|
||||||
|
SELECT run_command_on_workers(
|
||||||
|
$$SELECT srvoptions FROM pg_foreign_server WHERE srvname = 'foreign''server_1!';$$);
|
||||||
|
run_command_on_workers
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
(localhost,57637,t,"{host=localhost,fdw_startup_cost=1000,port=57636,dbname=regression}")
|
||||||
|
(localhost,57638,t,"{host=localhost,fdw_startup_cost=1000,port=57636,dbname=regression}")
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- verify the owner is changed
|
||||||
|
SELECT run_command_on_workers(
|
||||||
|
$$SELECT rolname FROM pg_roles WHERE oid IN (SELECT srvowner FROM pg_foreign_server WHERE srvname = 'foreign''server_1!');$$);
|
||||||
|
run_command_on_workers
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
(localhost,57637,t,pg_monitor)
|
||||||
|
(localhost,57638,t,pg_monitor)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- verify the owner is changed on the coordinator
|
||||||
|
SELECT rolname FROM pg_roles JOIN pg_foreign_server ON (pg_roles.oid=pg_foreign_server.srvowner) WHERE srvname = 'foreign''server_1!';
|
||||||
|
rolname
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
pg_monitor
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP SERVER IF EXISTS "foreign'server_1!" CASCADE;
|
||||||
|
-- verify that the server is dropped on the worker
|
||||||
|
SELECT run_command_on_workers(
|
||||||
|
$$SELECT COUNT(*)=0 FROM pg_foreign_server WHERE srvname = 'foreign''server_1!';$$);
|
||||||
|
run_command_on_workers
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
(localhost,57637,t,t)
|
||||||
|
(localhost,57638,t,t)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
\c - - - :worker_1_port
|
||||||
|
-- not allowed on the worker
|
||||||
|
ALTER SERVER foreign_server OPTIONS (ADD async_capable 'False');
|
||||||
|
ERROR: server "foreign_server" does not exist
|
||||||
|
CREATE SERVER foreign_server_1 TYPE 'test_type' VERSION 'v1'
|
||||||
|
FOREIGN DATA WRAPPER postgres_fdw
|
||||||
|
OPTIONS (host 'testhost', port '5432', dbname 'testdb');
|
||||||
|
ERROR: operation is not allowed on this node
|
||||||
|
HINT: Connect to the coordinator and run it again.
|
||||||
|
\c - - - :master_port
|
||||||
|
DROP SCHEMA propagate_foreign_server CASCADE;
|
||||||
|
NOTICE: drop cascades to extension postgres_fdw
|
|
@ -26,6 +26,7 @@ test: multi_cluster_management
|
||||||
# below tests are placed right after multi_cluster_management as we do
|
# below tests are placed right after multi_cluster_management as we do
|
||||||
# remove/add node operations and we do not want any preexisting objects
|
# remove/add node operations and we do not want any preexisting objects
|
||||||
test: non_super_user_object_metadata
|
test: non_super_user_object_metadata
|
||||||
|
test: propagate_foreign_servers
|
||||||
test: alter_role_propagation
|
test: alter_role_propagation
|
||||||
test: propagate_extension_commands
|
test: propagate_extension_commands
|
||||||
test: escape_extension_name
|
test: escape_extension_name
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
test: multi_test_helpers multi_test_helpers_superuser multi_create_fdw
|
test: multi_test_helpers multi_test_helpers_superuser
|
||||||
test: multi_cluster_management
|
test: multi_cluster_management
|
||||||
|
test: multi_create_fdw
|
||||||
test: multi_test_catalog_views
|
test: multi_test_catalog_views
|
||||||
test: replicated_table_disable_node
|
test: replicated_table_disable_node
|
||||||
|
|
||||||
|
|
|
@ -924,14 +924,6 @@ if (!$conninfo)
|
||||||
'-c', "CREATE FOREIGN DATA WRAPPER $fdw HANDLER $fdws{$fdw};")) == 0
|
'-c', "CREATE FOREIGN DATA WRAPPER $fdw HANDLER $fdws{$fdw};")) == 0
|
||||||
or die "Could not create foreign data wrapper $fdw on worker";
|
or die "Could not create foreign data wrapper $fdw on worker";
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $fdwServer (keys %fdwServers)
|
|
||||||
{
|
|
||||||
system(catfile($bindir, "psql"),
|
|
||||||
('-X', '-h', $host, '-p', $port, '-U', $user, "-d", "regression",
|
|
||||||
'-c', "CREATE SERVER $fdwServer FOREIGN DATA WRAPPER $fdwServers{$fdwServer};")) == 0
|
|
||||||
or die "Could not create server $fdwServer on worker";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -958,14 +950,6 @@ else
|
||||||
'-c', "SELECT run_command_on_workers('CREATE FOREIGN DATA WRAPPER $fdw HANDLER $fdws{$fdw};');")) == 0
|
'-c', "SELECT run_command_on_workers('CREATE FOREIGN DATA WRAPPER $fdw HANDLER $fdws{$fdw};');")) == 0
|
||||||
or die "Could not create foreign data wrapper $fdw on worker";
|
or die "Could not create foreign data wrapper $fdw on worker";
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $fdwServer (keys %fdwServers)
|
|
||||||
{
|
|
||||||
system(catfile($bindir, "psql"),
|
|
||||||
('-X', '-h', $host, '-p', $masterPort, '-U', $user, "-d", $dbname,
|
|
||||||
'-c', "SELECT run_command_on_workers('CREATE SERVER $fdwServer FOREIGN DATA WRAPPER $fdwServers{$fdwServer};');")) == 0
|
|
||||||
or die "Could not create server $fdwServer on worker";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Prepare pg_regress arguments
|
# Prepare pg_regress arguments
|
||||||
|
|
|
@ -40,6 +40,9 @@ RETURNS fdw_handler
|
||||||
AS 'citus'
|
AS 'citus'
|
||||||
LANGUAGE C STRICT;
|
LANGUAGE C STRICT;
|
||||||
CREATE FOREIGN DATA WRAPPER fake_fdw_1 HANDLER fake_fdw_handler;
|
CREATE FOREIGN DATA WRAPPER fake_fdw_1 HANDLER fake_fdw_handler;
|
||||||
|
SELECT run_command_on_workers($$
|
||||||
|
CREATE FOREIGN DATA WRAPPER fake_fdw_1 HANDLER fake_fdw_handler;
|
||||||
|
$$);
|
||||||
CREATE SERVER fake_fdw_server_1 FOREIGN DATA WRAPPER fake_fdw_1;
|
CREATE SERVER fake_fdw_server_1 FOREIGN DATA WRAPPER fake_fdw_1;
|
||||||
|
|
||||||
CREATE FOREIGN TABLE foreign_table (
|
CREATE FOREIGN TABLE foreign_table (
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
CREATE SCHEMA propagate_foreign_server;
|
||||||
|
SET search_path TO propagate_foreign_server;
|
||||||
|
|
||||||
|
-- remove node to add later
|
||||||
|
SELECT citus_remove_node('localhost', :worker_1_port);
|
||||||
|
|
||||||
|
-- create schema, extension and foreign server while the worker is removed
|
||||||
|
SET citus.enable_ddl_propagation TO OFF;
|
||||||
|
CREATE SCHEMA test_dependent_schema;
|
||||||
|
CREATE EXTENSION postgres_fdw WITH SCHEMA test_dependent_schema;
|
||||||
|
SET citus.enable_ddl_propagation TO ON;
|
||||||
|
CREATE SERVER foreign_server_dependent_schema
|
||||||
|
FOREIGN DATA WRAPPER postgres_fdw
|
||||||
|
OPTIONS (host 'test');
|
||||||
|
|
||||||
|
SELECT 1 FROM citus_add_node('localhost', :worker_1_port);
|
||||||
|
|
||||||
|
-- verify the dependent schema and the foreign server are created on the newly added worker
|
||||||
|
SELECT run_command_on_workers(
|
||||||
|
$$SELECT COUNT(*) FROM pg_namespace WHERE nspname = 'test_dependent_schema';$$);
|
||||||
|
SELECT run_command_on_workers(
|
||||||
|
$$SELECT COUNT(*)=1 FROM pg_foreign_server WHERE srvname = 'foreign_server_dependent_schema';$$);
|
||||||
|
|
||||||
|
CREATE SERVER foreign_server_to_drop
|
||||||
|
FOREIGN DATA WRAPPER postgres_fdw
|
||||||
|
OPTIONS (host 'test');
|
||||||
|
|
||||||
|
--should error
|
||||||
|
DROP SERVER foreign_server_dependent_schema, foreign_server_to_drop;
|
||||||
|
|
||||||
|
SET client_min_messages TO ERROR;
|
||||||
|
DROP SCHEMA test_dependent_schema CASCADE;
|
||||||
|
RESET client_min_messages;
|
||||||
|
|
||||||
|
-- test propagating foreign server creation
|
||||||
|
CREATE EXTENSION postgres_fdw;
|
||||||
|
CREATE SERVER foreign_server TYPE 'test_type' VERSION 'v1'
|
||||||
|
FOREIGN DATA WRAPPER postgres_fdw
|
||||||
|
OPTIONS (host 'testhost', port '5432', dbname 'testdb');
|
||||||
|
|
||||||
|
SELECT COUNT(*)=1 FROM pg_foreign_server WHERE srvname = 'foreign_server';
|
||||||
|
|
||||||
|
-- verify that the server is created on the worker
|
||||||
|
SELECT run_command_on_workers(
|
||||||
|
$$SELECT COUNT(*)=1 FROM pg_foreign_server WHERE srvname = 'foreign_server';$$);
|
||||||
|
|
||||||
|
ALTER SERVER foreign_server OPTIONS (ADD "fdw_startup_cost" '1000');
|
||||||
|
ALTER SERVER foreign_server OPTIONS (ADD passfile 'to_be_dropped');
|
||||||
|
ALTER SERVER foreign_server OPTIONS (SET host 'localhost');
|
||||||
|
ALTER SERVER foreign_server OPTIONS (DROP port, DROP dbname);
|
||||||
|
ALTER SERVER foreign_server OPTIONS (ADD port :'master_port', dbname 'regression', DROP passfile);
|
||||||
|
ALTER SERVER foreign_server RENAME TO "foreign'server_1!";
|
||||||
|
|
||||||
|
-- test alter owner
|
||||||
|
SELECT rolname FROM pg_roles JOIN pg_foreign_server ON (pg_roles.oid=pg_foreign_server.srvowner) WHERE srvname = 'foreign''server_1!';
|
||||||
|
ALTER SERVER "foreign'server_1!" OWNER TO pg_monitor;
|
||||||
|
|
||||||
|
-- verify that the server is renamed on the worker
|
||||||
|
SELECT run_command_on_workers(
|
||||||
|
$$SELECT srvoptions FROM pg_foreign_server WHERE srvname = 'foreign''server_1!';$$);
|
||||||
|
|
||||||
|
-- verify the owner is changed
|
||||||
|
SELECT run_command_on_workers(
|
||||||
|
$$SELECT rolname FROM pg_roles WHERE oid IN (SELECT srvowner FROM pg_foreign_server WHERE srvname = 'foreign''server_1!');$$);
|
||||||
|
|
||||||
|
-- verify the owner is changed on the coordinator
|
||||||
|
SELECT rolname FROM pg_roles JOIN pg_foreign_server ON (pg_roles.oid=pg_foreign_server.srvowner) WHERE srvname = 'foreign''server_1!';
|
||||||
|
DROP SERVER IF EXISTS "foreign'server_1!" CASCADE;
|
||||||
|
|
||||||
|
-- verify that the server is dropped on the worker
|
||||||
|
SELECT run_command_on_workers(
|
||||||
|
$$SELECT COUNT(*)=0 FROM pg_foreign_server WHERE srvname = 'foreign''server_1!';$$);
|
||||||
|
|
||||||
|
\c - - - :worker_1_port
|
||||||
|
-- not allowed on the worker
|
||||||
|
ALTER SERVER foreign_server OPTIONS (ADD async_capable 'False');
|
||||||
|
|
||||||
|
CREATE SERVER foreign_server_1 TYPE 'test_type' VERSION 'v1'
|
||||||
|
FOREIGN DATA WRAPPER postgres_fdw
|
||||||
|
OPTIONS (host 'testhost', port '5432', dbname 'testdb');
|
||||||
|
|
||||||
|
\c - - - :master_port
|
||||||
|
DROP SCHEMA propagate_foreign_server CASCADE;
|
Loading…
Reference in New Issue