mirror of https://github.com/citusdata/citus.git
phase3: generalize the fact that some commands cannot be exec in a xact
parent
fadee4e494
commit
3bdecb10a0
|
@ -62,7 +62,7 @@ typedef enum DistObjectOperation
|
||||||
typedef struct NonMainDbDistributedStatementInfo
|
typedef struct NonMainDbDistributedStatementInfo
|
||||||
{
|
{
|
||||||
int statementType;
|
int statementType;
|
||||||
DistObjectOperation DistObjectOperation;
|
DistObjectOperation distObjectOperation;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* checkSupportedObjectTypes is a callback function that checks whether
|
* checkSupportedObjectTypes is a callback function that checks whether
|
||||||
|
@ -71,6 +71,9 @@ typedef struct NonMainDbDistributedStatementInfo
|
||||||
* Can be NULL if not applicable for the statement type.
|
* Can be NULL if not applicable for the statement type.
|
||||||
*/
|
*/
|
||||||
bool (*checkSupportedObjectTypes)(Node *node);
|
bool (*checkSupportedObjectTypes)(Node *node);
|
||||||
|
|
||||||
|
/* indicates whether the statement cannot be executed in a transaction */
|
||||||
|
bool cannotBeExecutedInTransaction;
|
||||||
} NonMainDbDistributedStatementInfo;
|
} NonMainDbDistributedStatementInfo;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -90,6 +93,8 @@ typedef struct DistObjectOperationParams
|
||||||
* checkSupportedObjectTypes callbacks for
|
* checkSupportedObjectTypes callbacks for
|
||||||
* NonMainDbDistributedStatementInfo objects.
|
* NonMainDbDistributedStatementInfo objects.
|
||||||
*/
|
*/
|
||||||
|
static bool NonMainDbCheckSupportedObjectTypeForCreateDatabase(Node *node);
|
||||||
|
static bool NonMainDbCheckSupportedObjectTypeForDropDatabase(Node *node);
|
||||||
static bool NonMainDbCheckSupportedObjectTypeForGrant(Node *node);
|
static bool NonMainDbCheckSupportedObjectTypeForGrant(Node *node);
|
||||||
static bool NonMainDbCheckSupportedObjectTypeForSecLabel(Node *node);
|
static bool NonMainDbCheckSupportedObjectTypeForSecLabel(Node *node);
|
||||||
|
|
||||||
|
@ -99,49 +104,30 @@ static bool NonMainDbCheckSupportedObjectTypeForSecLabel(Node *node);
|
||||||
*/
|
*/
|
||||||
ObjectType supportedObjectTypesForGrantStmt[] = { OBJECT_DATABASE };
|
ObjectType supportedObjectTypesForGrantStmt[] = { OBJECT_DATABASE };
|
||||||
static const NonMainDbDistributedStatementInfo NonMainDbSupportedStatements[] = {
|
static const NonMainDbDistributedStatementInfo NonMainDbSupportedStatements[] = {
|
||||||
{ T_GrantRoleStmt, NO_DIST_OBJECT_OPERATION, NULL },
|
{ T_GrantRoleStmt, NO_DIST_OBJECT_OPERATION, NULL, false },
|
||||||
{ T_CreateRoleStmt, MARK_DISTRIBUTED_GLOBALLY, NULL },
|
{ T_CreateRoleStmt, MARK_DISTRIBUTED_GLOBALLY, NULL, false },
|
||||||
{ T_DropRoleStmt, UNMARK_DISTRIBUTED_LOCALLY, NULL },
|
{ T_DropRoleStmt, UNMARK_DISTRIBUTED_LOCALLY, NULL, false },
|
||||||
{ T_AlterRoleStmt, NO_DIST_OBJECT_OPERATION, NULL },
|
{ T_AlterRoleStmt, NO_DIST_OBJECT_OPERATION, NULL, false },
|
||||||
{ T_GrantStmt, NO_DIST_OBJECT_OPERATION, NonMainDbCheckSupportedObjectTypeForGrant },
|
{ T_GrantStmt, NO_DIST_OBJECT_OPERATION,
|
||||||
{ T_CreatedbStmt, NO_DIST_OBJECT_OPERATION, NULL },
|
NonMainDbCheckSupportedObjectTypeForGrant, false },
|
||||||
{ T_DropdbStmt, NO_DIST_OBJECT_OPERATION, NULL },
|
{ T_CreatedbStmt, NO_DIST_OBJECT_OPERATION,
|
||||||
|
NonMainDbCheckSupportedObjectTypeForCreateDatabase, true },
|
||||||
|
{ T_DropdbStmt, NO_DIST_OBJECT_OPERATION,
|
||||||
|
NonMainDbCheckSupportedObjectTypeForDropDatabase, true },
|
||||||
{ T_SecLabelStmt, NO_DIST_OBJECT_OPERATION,
|
{ T_SecLabelStmt, NO_DIST_OBJECT_OPERATION,
|
||||||
NonMainDbCheckSupportedObjectTypeForSecLabel },
|
NonMainDbCheckSupportedObjectTypeForSecLabel, false },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static bool IsStatementSupportedFromNonMainDb(Node *parsetree);
|
static bool IsStatementSupportedFromNonMainDb(Node *parsetree);
|
||||||
static bool StatementRequiresMarkDistributedGloballyFromNonMainDb(Node *parsetree);
|
static bool StatementRequiresMarkDistributedGloballyFromNonMainDb(Node *parsetree);
|
||||||
static bool StatementRequiresUnmarkDistributedLocallyFromNonMainDb(Node *parsetree);
|
static bool StatementRequiresUnmarkDistributedLocallyFromNonMainDb(Node *parsetree);
|
||||||
|
static bool StatementCannotBeExecutedInTransaction(Node *parsetree);
|
||||||
static void MarkObjectDistributedGloballyFromNonMainDb(Node *parsetree);
|
static void MarkObjectDistributedGloballyFromNonMainDb(Node *parsetree);
|
||||||
static void UnMarkObjectDistributedLocallyFromNonMainDb(List *unmarkDistributedList);
|
static void UnMarkObjectDistributedLocallyFromNonMainDb(List *unmarkDistributedList);
|
||||||
static List * GetDistObjectOperationParams(Node *parsetree);
|
static List * GetDistObjectOperationParams(Node *parsetree);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* IsCommandToCreateOrDropMainDB checks if this query creates or drops the
|
|
||||||
* main database, so we can make an exception and not send this query to
|
|
||||||
* the main database.
|
|
||||||
*/
|
|
||||||
bool
|
|
||||||
IsCommandToCreateOrDropMainDB(Node *parsetree)
|
|
||||||
{
|
|
||||||
if (IsA(parsetree, CreatedbStmt))
|
|
||||||
{
|
|
||||||
CreatedbStmt *createdbStmt = castNode(CreatedbStmt, parsetree);
|
|
||||||
return strcmp(createdbStmt->dbname, MainDb) == 0;
|
|
||||||
}
|
|
||||||
else if (IsA(parsetree, DropdbStmt))
|
|
||||||
{
|
|
||||||
DropdbStmt *dropdbStmt = castNode(DropdbStmt, parsetree);
|
|
||||||
return strcmp(dropdbStmt->dbname, MainDb) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RunPreprocessNonMainDBCommand runs the necessary commands for a query, in main
|
* RunPreprocessNonMainDBCommand runs the necessary commands for a query, in main
|
||||||
* database before query is run on the local node with PrevProcessUtility.
|
* database before query is run on the local node with PrevProcessUtility.
|
||||||
|
@ -157,25 +143,15 @@ RunPreprocessNonMainDBCommand(Node *parsetree)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsCommandToCreateOrDropMainDB(parsetree))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We don't try to send the query to the main database if the CREATE/DROP DATABASE
|
|
||||||
* command is for the main database itself, this is a very rare case but it's
|
|
||||||
* exercised by our test suite.
|
|
||||||
*/
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *queryString = DeparseTreeNode(parsetree);
|
char *queryString = DeparseTreeNode(parsetree);
|
||||||
|
|
||||||
if (IsA(parsetree, CreatedbStmt) || IsA(parsetree, DropdbStmt))
|
/*
|
||||||
|
* For the commands that cannot be executed in a transaction, there are no
|
||||||
|
* transactional visibility issues. We directly route them to main database
|
||||||
|
* so that we only have to consider one code-path when creating databases.
|
||||||
|
*/
|
||||||
|
if (StatementCannotBeExecutedInTransaction(parsetree))
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* We always execute CREATE/DROP DATABASE from the main database. There are no
|
|
||||||
* transactional visibility issues, since these commands are non-transactional.
|
|
||||||
* And this way we only have to consider one codepath when creating databases.
|
|
||||||
*/
|
|
||||||
IsMainDBCommandInXact = false;
|
IsMainDBCommandInXact = false;
|
||||||
RunCitusMainDBQuery((char *) queryString);
|
RunCitusMainDBQuery((char *) queryString);
|
||||||
return true;
|
return true;
|
||||||
|
@ -264,7 +240,7 @@ StatementRequiresMarkDistributedGloballyFromNonMainDb(Node *parsetree)
|
||||||
{
|
{
|
||||||
if (type == NonMainDbSupportedStatements[i].statementType)
|
if (type == NonMainDbSupportedStatements[i].statementType)
|
||||||
{
|
{
|
||||||
return NonMainDbSupportedStatements[i].DistObjectOperation ==
|
return NonMainDbSupportedStatements[i].distObjectOperation ==
|
||||||
MARK_DISTRIBUTED_GLOBALLY;
|
MARK_DISTRIBUTED_GLOBALLY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,7 +263,7 @@ StatementRequiresUnmarkDistributedLocallyFromNonMainDb(Node *parsetree)
|
||||||
{
|
{
|
||||||
if (type == NonMainDbSupportedStatements[i].statementType)
|
if (type == NonMainDbSupportedStatements[i].statementType)
|
||||||
{
|
{
|
||||||
return NonMainDbSupportedStatements[i].DistObjectOperation ==
|
return NonMainDbSupportedStatements[i].distObjectOperation ==
|
||||||
UNMARK_DISTRIBUTED_LOCALLY;
|
UNMARK_DISTRIBUTED_LOCALLY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,6 +272,28 @@ StatementRequiresUnmarkDistributedLocallyFromNonMainDb(Node *parsetree)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StatementCannotBeExecutedInTransaction returns true if the statement cannot be executed in a
|
||||||
|
* transaction.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
StatementCannotBeExecutedInTransaction(Node *parsetree)
|
||||||
|
{
|
||||||
|
NodeTag type = nodeTag(parsetree);
|
||||||
|
|
||||||
|
for (int i = 0; i < sizeof(NonMainDbSupportedStatements) /
|
||||||
|
sizeof(NonMainDbSupportedStatements[0]); i++)
|
||||||
|
{
|
||||||
|
if (type == NonMainDbSupportedStatements[i].statementType)
|
||||||
|
{
|
||||||
|
return NonMainDbSupportedStatements[i].cannotBeExecutedInTransaction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MarkObjectDistributedGloballyFromNonMainDb marks the given object as distributed on the
|
* MarkObjectDistributedGloballyFromNonMainDb marks the given object as distributed on the
|
||||||
* non-main database.
|
* non-main database.
|
||||||
|
@ -396,6 +394,38 @@ GetDistObjectOperationParams(Node *parsetree)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NonMainDbCheckSupportedObjectTypeForCreateDatabase implements checkSupportedObjectTypes
|
||||||
|
* callback for CreatedbStmt.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
NonMainDbCheckSupportedObjectTypeForCreateDatabase(Node *node)
|
||||||
|
{
|
||||||
|
CreatedbStmt *stmt = castNode(CreatedbStmt, node);
|
||||||
|
return strcmp(stmt->dbname, MainDb) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NonMainDbCheckSupportedObjectTypeForDropDatabase implements checkSupportedObjectTypes
|
||||||
|
* callback for DropdbStmt.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
NonMainDbCheckSupportedObjectTypeForDropDatabase(Node *node)
|
||||||
|
{
|
||||||
|
DropdbStmt *stmt = castNode(DropdbStmt, node);
|
||||||
|
return strcmp(stmt->dbname, MainDb) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NonMainDbCheckSupportedObjectTypeForGrant implements checkSupportedObjectTypes
|
* NonMainDbCheckSupportedObjectTypeForGrant implements checkSupportedObjectTypes
|
||||||
* callback for GrantStmt.
|
* callback for GrantStmt.
|
||||||
|
|
|
@ -105,7 +105,6 @@ typedef struct DistributeObjectOps
|
||||||
const DistributeObjectOps * GetDistributeObjectOps(Node *node);
|
const DistributeObjectOps * GetDistributeObjectOps(Node *node);
|
||||||
|
|
||||||
/* functions to support node-wide object management commands from non-main dbs */
|
/* functions to support node-wide object management commands from non-main dbs */
|
||||||
extern bool IsCommandToCreateOrDropMainDB(Node *parsetree);
|
|
||||||
extern bool RunPreprocessNonMainDBCommand(Node *parsetree);
|
extern bool RunPreprocessNonMainDBCommand(Node *parsetree);
|
||||||
extern void RunPostprocessNonMainDBCommand(Node *parsetree);
|
extern void RunPostprocessNonMainDBCommand(Node *parsetree);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue