mirror of https://github.com/citusdata/citus.git
Add ALTER VIEW support
Adds support for propagation ALTER VIEW commands to - Change owner of view - SET/RESET option - Rename view and view's column name - Change schema of the view Since PG also supports targeting views with ALTER TABLE commands, related code also added to direct such ALTER TABLE commands to ALTER VIEW commands while sending them to workers.pull/5914/head
parent
1f17fa8b63
commit
1875516ae9
|
@ -828,6 +828,22 @@ static DistributeObjectOps Type_AlterObjectSchema = {
|
|||
.address = AlterTypeSchemaStmtObjectAddress,
|
||||
.markDistributed = false,
|
||||
};
|
||||
|
||||
/*
|
||||
* PreprocessAlterViewSchemaStmt and PostprocessAlterViewSchemaStmt functions can be called
|
||||
* internally by ALTER TABLE view_name SET SCHEMA ... if the ALTER TABLE command targets a
|
||||
* view. In other words ALTER VIEW view_name SET SCHEMA will use the View_AlterObjectSchema
|
||||
* but ALTER TABLE view_name SET SCHEMA will use Table_AlterObjectSchema but call process
|
||||
* functions of View_AlterObjectSchema internally.
|
||||
*/
|
||||
static DistributeObjectOps View_AlterObjectSchema = {
|
||||
.deparse = DeparseAlterViewSchemaStmt,
|
||||
.qualify = QualifyAlterViewSchemaStmt,
|
||||
.preprocess = PreprocessAlterViewSchemaStmt,
|
||||
.postprocess = PostprocessAlterViewSchemaStmt,
|
||||
.address = AlterViewSchemaStmtObjectAddress,
|
||||
.markDistributed = false,
|
||||
};
|
||||
static DistributeObjectOps Type_AlterOwner = {
|
||||
.deparse = DeparseAlterTypeOwnerStmt,
|
||||
.qualify = QualifyAlterTypeOwnerStmt,
|
||||
|
@ -844,6 +860,22 @@ static DistributeObjectOps Type_AlterTable = {
|
|||
.address = AlterTypeStmtObjectAddress,
|
||||
.markDistributed = false,
|
||||
};
|
||||
|
||||
/*
|
||||
* PreprocessAlterViewStmt and PostprocessAlterViewStmt functions can be called internally
|
||||
* by ALTER TABLE view_name SET/RESET ... if the ALTER TABLE command targets a view. In
|
||||
* other words ALTER VIEW view_name SET/RESET will use the View_AlterView
|
||||
* but ALTER TABLE view_name SET/RESET will use Table_AlterTable but call process
|
||||
* functions of View_AlterView internally.
|
||||
*/
|
||||
static DistributeObjectOps View_AlterView = {
|
||||
.deparse = DeparseAlterViewStmt,
|
||||
.qualify = QualifyAlterViewStmt,
|
||||
.preprocess = PreprocessAlterViewStmt,
|
||||
.postprocess = PostprocessAlterViewStmt,
|
||||
.address = AlterViewStmtObjectAddress,
|
||||
.markDistributed = false,
|
||||
};
|
||||
static DistributeObjectOps Type_Drop = {
|
||||
.deparse = DeparseDropTypeStmt,
|
||||
.qualify = NULL,
|
||||
|
@ -868,6 +900,21 @@ static DistributeObjectOps Type_Rename = {
|
|||
.address = RenameTypeStmtObjectAddress,
|
||||
.markDistributed = false,
|
||||
};
|
||||
|
||||
/*
|
||||
* PreprocessRenameViewStmt function can be called internally by ALTER TABLE view_name
|
||||
* RENAME ... if the ALTER TABLE command targets a view or a view's column. In other words
|
||||
* ALTER VIEW view_name RENAME will use the View_Rename but ALTER TABLE view_name RENAME
|
||||
* will use Any_Rename but call process functions of View_Rename internally.
|
||||
*/
|
||||
static DistributeObjectOps View_Rename = {
|
||||
.deparse = DeparseRenameViewStmt,
|
||||
.qualify = QualifyRenameViewStmt,
|
||||
.preprocess = PreprocessRenameViewStmt,
|
||||
.postprocess = NULL,
|
||||
.address = RenameViewStmtObjectAddress,
|
||||
.markDistributed = false,
|
||||
};
|
||||
static DistributeObjectOps Trigger_Rename = {
|
||||
.deparse = NULL,
|
||||
.qualify = NULL,
|
||||
|
@ -1021,6 +1068,11 @@ GetDistributeObjectOps(Node *node)
|
|||
return &Type_AlterObjectSchema;
|
||||
}
|
||||
|
||||
case OBJECT_VIEW:
|
||||
{
|
||||
return &View_AlterObjectSchema;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return &NoDistributeOps;
|
||||
|
@ -1157,6 +1209,11 @@ GetDistributeObjectOps(Node *node)
|
|||
return &Sequence_AlterOwner;
|
||||
}
|
||||
|
||||
case OBJECT_VIEW:
|
||||
{
|
||||
return &View_AlterView;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return &NoDistributeOps;
|
||||
|
@ -1512,6 +1569,27 @@ GetDistributeObjectOps(Node *node)
|
|||
return &Trigger_Rename;
|
||||
}
|
||||
|
||||
case OBJECT_VIEW:
|
||||
{
|
||||
return &View_Rename;
|
||||
}
|
||||
|
||||
case OBJECT_COLUMN:
|
||||
{
|
||||
switch (stmt->relationType)
|
||||
{
|
||||
case OBJECT_VIEW:
|
||||
{
|
||||
return &View_Rename;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return &Any_Rename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return &Any_Rename;
|
||||
|
|
|
@ -36,11 +36,12 @@ PreprocessRenameStmt(Node *node, const char *renameCommand,
|
|||
|
||||
/*
|
||||
* We only support some of the PostgreSQL supported RENAME statements, and
|
||||
* our list include only renaming table and index (related) objects.
|
||||
* our list include only renaming table, index, policy and view (related) objects.
|
||||
*/
|
||||
if (!IsAlterTableRenameStmt(renameStmt) &&
|
||||
!IsIndexRenameStmt(renameStmt) &&
|
||||
!IsPolicyRenameStmt(renameStmt))
|
||||
!IsPolicyRenameStmt(renameStmt) &&
|
||||
!IsViewRenameStmt(renameStmt))
|
||||
{
|
||||
return NIL;
|
||||
}
|
||||
|
@ -48,7 +49,7 @@ PreprocessRenameStmt(Node *node, const char *renameCommand,
|
|||
/*
|
||||
* The lock levels here should be same as the ones taken in
|
||||
* RenameRelation(), renameatt() and RenameConstraint(). However, since all
|
||||
* three statements have identical lock levels, we just use a single statement.
|
||||
* four statements have identical lock levels, we just use a single statement.
|
||||
*/
|
||||
objectRelationId = RangeVarGetRelid(renameStmt->relation,
|
||||
AccessExclusiveLock,
|
||||
|
@ -63,14 +64,31 @@ PreprocessRenameStmt(Node *node, const char *renameCommand,
|
|||
return NIL;
|
||||
}
|
||||
|
||||
/* check whether we are dealing with a sequence here */
|
||||
if (get_rel_relkind(objectRelationId) == RELKIND_SEQUENCE)
|
||||
/*
|
||||
* Check whether we are dealing with a sequence or view here and route queries
|
||||
* accordingly to the right processor function. We need to check both objects here
|
||||
* since PG supports targeting sequences and views with ALTER TABLE commands.
|
||||
*/
|
||||
char relKind = get_rel_relkind(objectRelationId);
|
||||
if (relKind == RELKIND_SEQUENCE)
|
||||
{
|
||||
RenameStmt *stmtCopy = copyObject(renameStmt);
|
||||
stmtCopy->renameType = OBJECT_SEQUENCE;
|
||||
return PreprocessRenameSequenceStmt((Node *) stmtCopy, renameCommand,
|
||||
processUtilityContext);
|
||||
}
|
||||
else if (relKind == RELKIND_VIEW)
|
||||
{
|
||||
RenameStmt *stmtCopy = copyObject(renameStmt);
|
||||
stmtCopy->relationType = OBJECT_VIEW;
|
||||
if (stmtCopy->renameType == OBJECT_TABLE)
|
||||
{
|
||||
stmtCopy->renameType = OBJECT_VIEW;
|
||||
}
|
||||
|
||||
return PreprocessRenameViewStmt((Node *) stmtCopy, renameCommand,
|
||||
processUtilityContext);
|
||||
}
|
||||
|
||||
/* we have no planning to do unless the table is distributed */
|
||||
switch (renameStmt->renameType)
|
||||
|
|
|
@ -651,12 +651,21 @@ PostprocessAlterTableSchemaStmt(Node *node, const char *queryString)
|
|||
*/
|
||||
ObjectAddress tableAddress = GetObjectAddressFromParseTree((Node *) stmt, true);
|
||||
|
||||
/* check whether we are dealing with a sequence here */
|
||||
if (get_rel_relkind(tableAddress.objectId) == RELKIND_SEQUENCE)
|
||||
/*
|
||||
* Check whether we are dealing with a sequence or view here and route queries
|
||||
* accordingly to the right processor function.
|
||||
*/
|
||||
char relKind = get_rel_relkind(tableAddress.objectId);
|
||||
if (relKind == RELKIND_SEQUENCE)
|
||||
{
|
||||
stmt->objectType = OBJECT_SEQUENCE;
|
||||
return PostprocessAlterSequenceSchemaStmt((Node *) stmt, queryString);
|
||||
}
|
||||
else if (relKind == RELKIND_VIEW)
|
||||
{
|
||||
stmt->objectType = OBJECT_VIEW;
|
||||
return PostprocessAlterViewSchemaStmt((Node *) stmt, queryString);
|
||||
}
|
||||
|
||||
if (!ShouldPropagate() || !IsCitusTable(tableAddress.objectId))
|
||||
{
|
||||
|
@ -699,18 +708,26 @@ PreprocessAlterTableStmt(Node *node, const char *alterTableCommand,
|
|||
}
|
||||
|
||||
/*
|
||||
* check whether we are dealing with a sequence here
|
||||
* check whether we are dealing with a sequence or view here
|
||||
* if yes, it must be ALTER TABLE .. OWNER TO .. command
|
||||
* since this is the only ALTER command of a sequence that
|
||||
* since this is the only ALTER command of a sequence or view that
|
||||
* passes through an AlterTableStmt
|
||||
*/
|
||||
if (get_rel_relkind(leftRelationId) == RELKIND_SEQUENCE)
|
||||
char relKind = get_rel_relkind(leftRelationId);
|
||||
if (relKind == RELKIND_SEQUENCE)
|
||||
{
|
||||
AlterTableStmt *stmtCopy = copyObject(alterTableStatement);
|
||||
AlterTableStmtObjType_compat(stmtCopy) = OBJECT_SEQUENCE;
|
||||
return PreprocessAlterSequenceOwnerStmt((Node *) stmtCopy, alterTableCommand,
|
||||
processUtilityContext);
|
||||
}
|
||||
else if (relKind == RELKIND_VIEW)
|
||||
{
|
||||
AlterTableStmt *stmtCopy = copyObject(alterTableStatement);
|
||||
AlterTableStmtObjType_compat(stmtCopy) = OBJECT_VIEW;
|
||||
return PreprocessAlterViewStmt((Node *) stmtCopy, alterTableCommand,
|
||||
processUtilityContext);
|
||||
}
|
||||
|
||||
/*
|
||||
* AlterTableStmt applies also to INDEX relations, and we have support for
|
||||
|
@ -1758,18 +1775,31 @@ PreprocessAlterTableSchemaStmt(Node *node, const char *queryString,
|
|||
{
|
||||
return NIL;
|
||||
}
|
||||
|
||||
ObjectAddress address = GetObjectAddressFromParseTree((Node *) stmt,
|
||||
stmt->missing_ok);
|
||||
Oid relationId = address.objectId;
|
||||
|
||||
/* check whether we are dealing with a sequence here */
|
||||
if (get_rel_relkind(relationId) == RELKIND_SEQUENCE)
|
||||
/*
|
||||
* Check whether we are dealing with a sequence or view here and route queries
|
||||
* accordingly to the right processor function. We need to check both objects here
|
||||
* since PG supports targeting sequences and views with ALTER TABLE commands.
|
||||
*/
|
||||
char relKind = get_rel_relkind(relationId);
|
||||
if (relKind == RELKIND_SEQUENCE)
|
||||
{
|
||||
AlterObjectSchemaStmt *stmtCopy = copyObject(stmt);
|
||||
stmtCopy->objectType = OBJECT_SEQUENCE;
|
||||
return PreprocessAlterSequenceSchemaStmt((Node *) stmtCopy, queryString,
|
||||
processUtilityContext);
|
||||
}
|
||||
else if (relKind == RELKIND_VIEW)
|
||||
{
|
||||
AlterObjectSchemaStmt *stmtCopy = copyObject(stmt);
|
||||
stmtCopy->objectType = OBJECT_VIEW;
|
||||
return PreprocessAlterViewSchemaStmt((Node *) stmtCopy, queryString,
|
||||
processUtilityContext);
|
||||
}
|
||||
|
||||
/* first check whether a distributed relation is affected */
|
||||
if (!OidIsValid(relationId) || !IsCitusTable(relationId))
|
||||
|
@ -1939,12 +1969,19 @@ PostprocessAlterTableStmt(AlterTableStmt *alterTableStatement)
|
|||
* since this is the only ALTER command of a sequence that
|
||||
* passes through an AlterTableStmt
|
||||
*/
|
||||
if (get_rel_relkind(relationId) == RELKIND_SEQUENCE)
|
||||
char relKind = get_rel_relkind(relationId);
|
||||
if (relKind == RELKIND_SEQUENCE)
|
||||
{
|
||||
AlterTableStmtObjType_compat(alterTableStatement) = OBJECT_SEQUENCE;
|
||||
PostprocessAlterSequenceOwnerStmt((Node *) alterTableStatement, NULL);
|
||||
return;
|
||||
}
|
||||
else if (relKind == RELKIND_VIEW)
|
||||
{
|
||||
AlterTableStmtObjType_compat(alterTableStatement) = OBJECT_VIEW;
|
||||
PostprocessAlterViewStmt((Node *) alterTableStatement, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Before ensuring each dependency exist, update dependent sequences
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
static List * FilterNameListForDistributedViews(List *viewNamesList, bool missing_ok);
|
||||
static void AppendQualifiedViewNameToCreateViewCommand(StringInfo buf, Oid viewOid);
|
||||
static void AppendViewDefinitionToCreateViewCommand(StringInfo buf, Oid viewOid);
|
||||
static void AppendAliasesToCreateViewCommand(StringInfo createViewCommand, Oid viewOid);
|
||||
static void AppendOptionsToCreateViewCommand(StringInfo createViewCommand, Oid viewOid);
|
||||
|
||||
|
@ -101,45 +102,9 @@ PostprocessViewStmt(Node *node, const char *queryString)
|
|||
}
|
||||
|
||||
/* If the view has any unsupported dependency, create it locally */
|
||||
DeferredErrorMessage *errMsg = DeferErrorIfHasUnsupportedDependency(&viewAddress);
|
||||
|
||||
if (errMsg != NULL)
|
||||
if (ErrorOrWarnIfObjectHasUnsupportedDependency(&viewAddress))
|
||||
{
|
||||
/*
|
||||
* Don't need to give any warning/error messages if there is no worker nodes in
|
||||
* the cluster as user's experience won't be affected on the single node even
|
||||
* if the view won't be distributed.
|
||||
*/
|
||||
if (!HasAnyNodes())
|
||||
{
|
||||
return NIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since Citus drops and recreates views while converting a table type, giving a
|
||||
* NOTICE message is enough if the process in table type conversion function call
|
||||
*/
|
||||
if (InTableTypeConversionFunctionCall)
|
||||
{
|
||||
RaiseDeferredError(errMsg, DEBUG1);
|
||||
return NIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the view is already distributed, we should provide an error to not have
|
||||
* different definition of view on coordinator and worker nodes. If the view
|
||||
* is not distributed yet, we can create it locally to not affect user's local
|
||||
* usage experience.
|
||||
*/
|
||||
if (IsObjectDistributed(&viewAddress))
|
||||
{
|
||||
RaiseDeferredError(errMsg, ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
RaiseDeferredError(errMsg, WARNING);
|
||||
return NIL;
|
||||
}
|
||||
return NIL;
|
||||
}
|
||||
|
||||
EnsureDependenciesExistOnAllNodes(&viewAddress);
|
||||
|
@ -409,7 +374,7 @@ AppendOptionsToCreateViewCommand(StringInfo createViewCommand, Oid viewOid)
|
|||
* AppendViewDefinitionToCreateViewCommand adds the definition of the given view to the
|
||||
* given create view command.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
AppendViewDefinitionToCreateViewCommand(StringInfo buf, Oid viewOid)
|
||||
{
|
||||
/*
|
||||
|
@ -460,3 +425,250 @@ AlterViewOwnerCommand(Oid viewOid)
|
|||
|
||||
return alterOwnerCommand->data;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PreprocessAlterViewStmt is invoked for alter view statements.
|
||||
*/
|
||||
List *
|
||||
PreprocessAlterViewStmt(Node *node, const char *queryString, ProcessUtilityContext
|
||||
processUtilityContext)
|
||||
{
|
||||
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
|
||||
|
||||
ObjectAddress viewAddress = GetObjectAddressFromParseTree((Node *) stmt, true);
|
||||
if (!ShouldPropagateObject(&viewAddress))
|
||||
{
|
||||
return NIL;
|
||||
}
|
||||
|
||||
QualifyTreeNode((Node *) stmt);
|
||||
|
||||
EnsureCoordinator();
|
||||
EnsureSequentialMode(OBJECT_VIEW);
|
||||
|
||||
/* reconstruct alter statement in a portable fashion */
|
||||
const char *alterViewStmtSql = DeparseTreeNode((Node *) stmt);
|
||||
|
||||
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||
(void *) alterViewStmtSql,
|
||||
ENABLE_DDL_PROPAGATION);
|
||||
|
||||
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PostprocessAlterViewStmt is invoked for alter view statements.
|
||||
*/
|
||||
List *
|
||||
PostprocessAlterViewStmt(Node *node, const char *queryString)
|
||||
{
|
||||
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
|
||||
Assert(AlterTableStmtObjType_compat(stmt) == OBJECT_VIEW);
|
||||
|
||||
ObjectAddress viewAddress = GetObjectAddressFromParseTree((Node *) stmt, true);
|
||||
if (!ShouldPropagateObject(&viewAddress))
|
||||
{
|
||||
return NIL;
|
||||
}
|
||||
|
||||
if (IsObjectAddressOwnedByExtension(&viewAddress, NULL))
|
||||
{
|
||||
return NIL;
|
||||
}
|
||||
|
||||
/* If the view has any unsupported dependency, create it locally */
|
||||
if (ErrorOrWarnIfObjectHasUnsupportedDependency(&viewAddress))
|
||||
{
|
||||
return NIL;
|
||||
}
|
||||
|
||||
EnsureDependenciesExistOnAllNodes(&viewAddress);
|
||||
|
||||
return NIL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AlterViewStmtObjectAddress returns the ObjectAddress for the subject of the
|
||||
* ALTER VIEW statement.
|
||||
*/
|
||||
ObjectAddress
|
||||
AlterViewStmtObjectAddress(Node *node, bool missing_ok)
|
||||
{
|
||||
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
|
||||
Oid viewOid = RangeVarGetRelid(stmt->relation, NoLock, missing_ok);
|
||||
|
||||
ObjectAddress viewAddress = { 0 };
|
||||
ObjectAddressSet(viewAddress, RelationRelationId, viewOid);
|
||||
|
||||
return viewAddress;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PreprocessRenameViewStmt is called when the user is renaming the view or the column of
|
||||
* the view.
|
||||
*/
|
||||
List *
|
||||
PreprocessRenameViewStmt(Node *node, const char *queryString,
|
||||
ProcessUtilityContext processUtilityContext)
|
||||
{
|
||||
ObjectAddress typeAddress = GetObjectAddressFromParseTree(node, true);
|
||||
if (!ShouldPropagateObject(&typeAddress))
|
||||
{
|
||||
return NIL;
|
||||
}
|
||||
|
||||
EnsureCoordinator();
|
||||
|
||||
/* fully qualify */
|
||||
QualifyTreeNode(node);
|
||||
|
||||
/* deparse sql*/
|
||||
const char *renameStmtSql = DeparseTreeNode(node);
|
||||
|
||||
EnsureSequentialMode(OBJECT_VIEW);
|
||||
|
||||
/* to prevent recursion with mx we disable ddl propagation */
|
||||
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||
(void *) renameStmtSql,
|
||||
ENABLE_DDL_PROPAGATION);
|
||||
|
||||
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RenameViewStmtObjectAddress returns the ObjectAddress of the view that is the object
|
||||
* of the RenameStmt. Errors if missing_ok is false.
|
||||
*/
|
||||
ObjectAddress
|
||||
RenameViewStmtObjectAddress(Node *node, bool missing_ok)
|
||||
{
|
||||
RenameStmt *stmt = castNode(RenameStmt, node);
|
||||
|
||||
Oid viewOid = RangeVarGetRelid(stmt->relation, NoLock, missing_ok);
|
||||
|
||||
ObjectAddress viewAddress = { 0 };
|
||||
ObjectAddressSet(viewAddress, RelationRelationId, viewOid);
|
||||
|
||||
return viewAddress;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PreprocessAlterViewSchemaStmt is executed before the statement is applied to the local
|
||||
* postgres instance.
|
||||
*/
|
||||
List *
|
||||
PreprocessAlterViewSchemaStmt(Node *node, const char *queryString,
|
||||
ProcessUtilityContext processUtilityContext)
|
||||
{
|
||||
AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node);
|
||||
|
||||
ObjectAddress typeAddress = GetObjectAddressFromParseTree((Node *) stmt, true);
|
||||
if (!ShouldPropagateObject(&typeAddress))
|
||||
{
|
||||
return NIL;
|
||||
}
|
||||
|
||||
EnsureCoordinator();
|
||||
EnsureSequentialMode(OBJECT_VIEW);
|
||||
|
||||
QualifyTreeNode((Node *) stmt);
|
||||
|
||||
const char *sql = DeparseTreeNode((Node *) stmt);
|
||||
|
||||
List *commands = list_make3(DISABLE_DDL_PROPAGATION,
|
||||
(void *) sql,
|
||||
ENABLE_DDL_PROPAGATION);
|
||||
|
||||
return NodeDDLTaskList(NON_COORDINATOR_NODES, commands);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* PostprocessAlterViewSchemaStmt is executed after the change has been applied locally, we
|
||||
* can now use the new dependencies of the view to ensure all its dependencies exist on
|
||||
* the workers before we apply the commands remotely.
|
||||
*/
|
||||
List *
|
||||
PostprocessAlterViewSchemaStmt(Node *node, const char *queryString)
|
||||
{
|
||||
AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node);
|
||||
|
||||
ObjectAddress viewAddress = GetObjectAddressFromParseTree((Node *) stmt, true);
|
||||
if (!ShouldPropagateObject(&viewAddress))
|
||||
{
|
||||
return NIL;
|
||||
}
|
||||
|
||||
/* dependencies have changed (schema) let's ensure they exist */
|
||||
EnsureDependenciesExistOnAllNodes(&viewAddress);
|
||||
|
||||
return NIL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AlterViewSchemaStmtObjectAddress returns the ObjectAddress of the view that is the object
|
||||
* of the alter schema statement.
|
||||
*/
|
||||
ObjectAddress
|
||||
AlterViewSchemaStmtObjectAddress(Node *node, bool missing_ok)
|
||||
{
|
||||
AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node);
|
||||
|
||||
Oid viewOid = RangeVarGetRelid(stmt->relation, NoLock, true);
|
||||
|
||||
/*
|
||||
* Since it can be called both before and after executing the standardProcess utility,
|
||||
* we need to check both old and new schemas
|
||||
*/
|
||||
if (viewOid == InvalidOid)
|
||||
{
|
||||
Oid schemaId = get_namespace_oid(stmt->newschema, missing_ok);
|
||||
viewOid = get_relname_relid(stmt->relation->relname, schemaId);
|
||||
|
||||
/*
|
||||
* if the view is still invalid we couldn't find the view, error with the same
|
||||
* message postgres would error with it missing_ok is false (not ok to miss)
|
||||
*/
|
||||
if (!missing_ok && viewOid == InvalidOid)
|
||||
{
|
||||
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("view \"%s\" does not exist",
|
||||
stmt->relation->relname)));
|
||||
}
|
||||
}
|
||||
|
||||
ObjectAddress viewAddress = { 0 };
|
||||
ObjectAddressSet(viewAddress, RelationRelationId, viewOid);
|
||||
|
||||
return viewAddress;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IsViewRenameStmt returns whether the passed-in RenameStmt is the following
|
||||
* form:
|
||||
*
|
||||
* - ALTER VIEW RENAME
|
||||
* - ALTER VIEW RENAME COLUMN
|
||||
*/
|
||||
bool
|
||||
IsViewRenameStmt(RenameStmt *renameStmt)
|
||||
{
|
||||
bool isViewRenameStmt = false;
|
||||
|
||||
if (renameStmt->renameType == OBJECT_VIEW ||
|
||||
(renameStmt->renameType == OBJECT_COLUMN &&
|
||||
renameStmt->relationType == OBJECT_VIEW))
|
||||
{
|
||||
isViewRenameStmt = true;
|
||||
}
|
||||
|
||||
return isViewRenameStmt;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,13 @@
|
|||
|
||||
static void AppendDropViewStmt(StringInfo buf, DropStmt *stmt);
|
||||
static void AppendViewNameList(StringInfo buf, List *objects);
|
||||
static void AppendAlterViewStmt(StringInfo buf, AlterTableStmt *stmt);
|
||||
static void AppendAlterViewCmd(StringInfo buf, AlterTableCmd *alterTableCmd);
|
||||
static void AppendAlterViewOwnerStmt(StringInfo buf, AlterTableCmd *alterTableCmd);
|
||||
static void AppendAlterViewSetOptionsStmt(StringInfo buf, AlterTableCmd *alterTableCmd);
|
||||
static void AppendAlterViewResetOptionsStmt(StringInfo buf, AlterTableCmd *alterTableCmd);
|
||||
static void AppendRenameViewStmt(StringInfo buf, RenameStmt *stmt);
|
||||
static void AppendAlterViewSchemaStmt(StringInfo buf, AlterObjectSchemaStmt *stmt);
|
||||
|
||||
/*
|
||||
* DeparseDropViewStmt deparses the given DROP VIEW statement.
|
||||
|
@ -92,3 +99,212 @@ AppendViewNameList(StringInfo buf, List *viewNamesList)
|
|||
isFirstView = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DeparseAlterViewStmt deparses the given ALTER VIEW statement.
|
||||
*/
|
||||
char *
|
||||
DeparseAlterViewStmt(Node *node)
|
||||
{
|
||||
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
|
||||
StringInfoData str = { 0 };
|
||||
initStringInfo(&str);
|
||||
|
||||
AppendAlterViewStmt(&str, stmt);
|
||||
|
||||
return str.data;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
AppendAlterViewStmt(StringInfo buf, AlterTableStmt *stmt)
|
||||
{
|
||||
const char *identifier = quote_qualified_identifier(stmt->relation->schemaname,
|
||||
stmt->relation->relname);
|
||||
|
||||
appendStringInfo(buf, "ALTER VIEW %s ", identifier);
|
||||
|
||||
AlterTableCmd *alterTableCmd = castNode(AlterTableCmd, lfirst(list_head(stmt->cmds)));
|
||||
AppendAlterViewCmd(buf, alterTableCmd);
|
||||
|
||||
appendStringInfoString(buf, ";");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
AppendAlterViewCmd(StringInfo buf, AlterTableCmd *alterTableCmd)
|
||||
{
|
||||
switch (alterTableCmd->subtype)
|
||||
{
|
||||
case AT_ChangeOwner:
|
||||
{
|
||||
AppendAlterViewOwnerStmt(buf, alterTableCmd);
|
||||
break;
|
||||
}
|
||||
|
||||
case AT_SetRelOptions:
|
||||
{
|
||||
AppendAlterViewSetOptionsStmt(buf, alterTableCmd);
|
||||
break;
|
||||
}
|
||||
|
||||
case AT_ResetRelOptions:
|
||||
{
|
||||
AppendAlterViewResetOptionsStmt(buf, alterTableCmd);
|
||||
break;
|
||||
}
|
||||
|
||||
case AT_ColumnDefault:
|
||||
{
|
||||
elog(ERROR, "Citus doesn't support setting or resetting default values for a "
|
||||
"column of view");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
/*
|
||||
* ALTER VIEW command only supports for the cases checked above but an
|
||||
* ALTER TABLE commands targeting views may have different cases. To let
|
||||
* PG throw the right error locally, we don't throw any error here
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
AppendAlterViewOwnerStmt(StringInfo buf, AlterTableCmd *alterTableCmd)
|
||||
{
|
||||
appendStringInfo(buf, "OWNER TO %s", RoleSpecString(alterTableCmd->newowner, true));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
AppendAlterViewSetOptionsStmt(StringInfo buf, AlterTableCmd *alterTableCmd)
|
||||
{
|
||||
ListCell *lc = NULL;
|
||||
bool initialOption = true;
|
||||
foreach(lc, (List *) alterTableCmd->def)
|
||||
{
|
||||
DefElem *def = (DefElem *) lfirst(lc);
|
||||
|
||||
if (initialOption)
|
||||
{
|
||||
appendStringInfo(buf, "SET (");
|
||||
initialOption = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
appendStringInfo(buf, ",");
|
||||
}
|
||||
|
||||
appendStringInfo(buf, "%s", def->defname);
|
||||
if (def->arg != NULL)
|
||||
{
|
||||
appendStringInfo(buf, "=");
|
||||
appendStringInfo(buf, "%s", defGetString(def));
|
||||
}
|
||||
}
|
||||
|
||||
appendStringInfo(buf, ")");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
AppendAlterViewResetOptionsStmt(StringInfo buf, AlterTableCmd *alterTableCmd)
|
||||
{
|
||||
ListCell *lc = NULL;
|
||||
bool initialOption = true;
|
||||
foreach(lc, (List *) alterTableCmd->def)
|
||||
{
|
||||
DefElem *def = (DefElem *) lfirst(lc);
|
||||
|
||||
if (initialOption)
|
||||
{
|
||||
appendStringInfo(buf, "RESET (");
|
||||
initialOption = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
appendStringInfo(buf, ",");
|
||||
}
|
||||
|
||||
appendStringInfo(buf, "%s", def->defname);
|
||||
}
|
||||
|
||||
appendStringInfo(buf, ")");
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
DeparseRenameViewStmt(Node *node)
|
||||
{
|
||||
RenameStmt *stmt = castNode(RenameStmt, node);
|
||||
StringInfoData str = { 0 };
|
||||
initStringInfo(&str);
|
||||
|
||||
AppendRenameViewStmt(&str, stmt);
|
||||
|
||||
return str.data;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
AppendRenameViewStmt(StringInfo buf, RenameStmt *stmt)
|
||||
{
|
||||
switch (stmt->renameType)
|
||||
{
|
||||
case OBJECT_COLUMN:
|
||||
{
|
||||
const char *identifier =
|
||||
quote_qualified_identifier(stmt->relation->schemaname,
|
||||
stmt->relation->relname);
|
||||
appendStringInfo(buf, "ALTER VIEW %s RENAME COLUMN %s TO %s;", identifier,
|
||||
quote_identifier(stmt->subname), quote_identifier(
|
||||
stmt->newname));
|
||||
break;
|
||||
}
|
||||
|
||||
case OBJECT_VIEW:
|
||||
{
|
||||
const char *identifier =
|
||||
quote_qualified_identifier(stmt->relation->schemaname,
|
||||
stmt->relation->relname);
|
||||
appendStringInfo(buf, "ALTER VIEW %s RENAME TO %s;", identifier,
|
||||
quote_identifier(stmt->newname));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
ereport(ERROR, (errmsg("unsupported subtype for alter view rename command"),
|
||||
errdetail("sub command type: %d", stmt->renameType)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
DeparseAlterViewSchemaStmt(Node *node)
|
||||
{
|
||||
AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node);
|
||||
StringInfoData str = { 0 };
|
||||
initStringInfo(&str);
|
||||
|
||||
AppendAlterViewSchemaStmt(&str, stmt);
|
||||
|
||||
return str.data;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
AppendAlterViewSchemaStmt(StringInfo buf, AlterObjectSchemaStmt *stmt)
|
||||
{
|
||||
const char *identifier = quote_qualified_identifier(stmt->relation->schemaname,
|
||||
stmt->relation->relname);
|
||||
appendStringInfo(buf, "ALTER VIEW %s SET SCHEMA %s;", identifier, quote_identifier(
|
||||
stmt->newschema));
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "utils/guc.h"
|
||||
#include "utils/lsyscache.h"
|
||||
|
||||
static void QualifyViewRangeVar(RangeVar *view);
|
||||
|
||||
/*
|
||||
* QualifyDropViewStmt quailifies the view names of the DROP VIEW statement.
|
||||
*/
|
||||
|
@ -52,3 +54,54 @@ QualifyDropViewStmt(Node *node)
|
|||
|
||||
stmt->objects = qualifiedViewNames;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* QualifyAlterViewStmt quailifies the view name of the ALTER VIEW statement.
|
||||
*/
|
||||
void
|
||||
QualifyAlterViewStmt(Node *node)
|
||||
{
|
||||
AlterTableStmt *stmt = castNode(AlterTableStmt, node);
|
||||
RangeVar *view = stmt->relation;
|
||||
QualifyViewRangeVar(view);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* QualifyRenameViewStmt quailifies the view name of the ALTER VIEW ... RENAME statement.
|
||||
*/
|
||||
void
|
||||
QualifyRenameViewStmt(Node *node)
|
||||
{
|
||||
RenameStmt *stmt = castNode(RenameStmt, node);
|
||||
RangeVar *view = stmt->relation;
|
||||
QualifyViewRangeVar(view);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* QualifyAlterViewSchemaStmt quailifies the view name of the ALTER VIEW ... SET SCHEMA statement.
|
||||
*/
|
||||
void
|
||||
QualifyAlterViewSchemaStmt(Node *node)
|
||||
{
|
||||
AlterObjectSchemaStmt *stmt = castNode(AlterObjectSchemaStmt, node);
|
||||
RangeVar *view = stmt->relation;
|
||||
QualifyViewRangeVar(view);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* QualifyViewRangeVar qualifies the given view RangeVar if it is not qualified.
|
||||
*/
|
||||
static void
|
||||
QualifyViewRangeVar(RangeVar *view)
|
||||
{
|
||||
if (view->schemaname == NULL)
|
||||
{
|
||||
Oid viewOid = RelnameGetRelid(view->relname);
|
||||
Oid schemaOid = get_rel_namespace(viewOid);
|
||||
view->schemaname = get_namespace_name(schemaOid);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -766,6 +766,58 @@ SupportedDependencyByCitus(const ObjectAddress *address)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* ErrorOrWarnIfObjectHasUnsupportedDependency returns false without throwing any message if
|
||||
* object doesn't have any unsupported dependency, else throws a message with proper level
|
||||
* (except the cluster doesn't have any node) and return true.
|
||||
*/
|
||||
bool
|
||||
ErrorOrWarnIfObjectHasUnsupportedDependency(ObjectAddress *objectAddress)
|
||||
{
|
||||
DeferredErrorMessage *errMsg = DeferErrorIfHasUnsupportedDependency(objectAddress);
|
||||
if (errMsg != NULL)
|
||||
{
|
||||
/*
|
||||
* Don't need to give any messages if there is no worker nodes in
|
||||
* the cluster as user's experience won't be affected on the single node even
|
||||
* if the object won't be distributed.
|
||||
*/
|
||||
if (!HasAnyNodes())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since Citus drops and recreates some object while converting a table type
|
||||
* giving a DEBUG1 message is enough if the process in table type conversion
|
||||
* function call
|
||||
*/
|
||||
if (InTableTypeConversionFunctionCall)
|
||||
{
|
||||
RaiseDeferredError(errMsg, DEBUG1);
|
||||
}
|
||||
/*
|
||||
* If the view is object distributed, we should provide an error to not have
|
||||
* different definition of object on coordinator and worker nodes. If the object
|
||||
* is not distributed yet, we can create it locally to not affect user's local
|
||||
* usage experience.
|
||||
*/
|
||||
else if (IsObjectDistributed(objectAddress))
|
||||
{
|
||||
RaiseDeferredError(errMsg, ERROR);
|
||||
}
|
||||
else
|
||||
{
|
||||
RaiseDeferredError(errMsg, WARNING);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DeferErrorIfHasUnsupportedDependency returns deferred error message if the given
|
||||
* object has any undistributable dependency.
|
||||
|
|
|
@ -658,12 +658,25 @@ extern List * PreprocessViewStmt(Node *node, const char *queryString,
|
|||
ProcessUtilityContext processUtilityContext);
|
||||
extern List * PostprocessViewStmt(Node *node, const char *queryString);
|
||||
extern ObjectAddress ViewStmtObjectAddress(Node *node, bool missing_ok);
|
||||
extern ObjectAddress AlterViewStmtObjectAddress(Node *node, bool missing_ok);
|
||||
extern List * PreprocessDropViewStmt(Node *node, const char *queryString,
|
||||
ProcessUtilityContext processUtilityContext);
|
||||
extern char * CreateViewDDLCommand(Oid viewOid);
|
||||
extern char * AlterViewOwnerCommand(Oid viewOid);
|
||||
extern char * DeparseViewStmt(Node *node);
|
||||
extern char * DeparseDropViewStmt(Node *node);
|
||||
extern List * CreateViewDDLCommandsIdempotent(Oid viewOid);
|
||||
extern List * PreprocessAlterViewStmt(Node *node, const char *queryString,
|
||||
ProcessUtilityContext processUtilityContext);
|
||||
extern List * PostprocessAlterViewStmt(Node *node, const char *queryString);
|
||||
extern List * PreprocessRenameViewStmt(Node *node, const char *queryString,
|
||||
ProcessUtilityContext processUtilityContext);
|
||||
extern ObjectAddress RenameViewStmtObjectAddress(Node *node, bool missing_ok);
|
||||
extern List * PreprocessAlterViewSchemaStmt(Node *node, const char *queryString,
|
||||
ProcessUtilityContext processUtilityContext);
|
||||
extern List * PostprocessAlterViewSchemaStmt(Node *node, const char *queryString);
|
||||
extern ObjectAddress AlterViewSchemaStmtObjectAddress(Node *node, bool missing_ok);
|
||||
extern bool IsViewRenameStmt(RenameStmt *renameStmt);
|
||||
|
||||
/* trigger.c - forward declarations */
|
||||
extern List * GetExplicitTriggerCommandList(Oid relationId);
|
||||
|
|
|
@ -146,7 +146,14 @@ extern ObjectAddress RenameAttributeStmtObjectAddress(Node *stmt, bool missing_o
|
|||
|
||||
/* forward declarations for deparse_view_stmts.c */
|
||||
extern void QualifyDropViewStmt(Node *node);
|
||||
extern void AppendViewDefinitionToCreateViewCommand(StringInfo buf, Oid viewOid);
|
||||
extern void QualifyAlterViewStmt(Node *node);
|
||||
extern void QualifyRenameViewStmt(Node *node);
|
||||
extern void QualifyAlterViewSchemaStmt(Node *node);
|
||||
extern char * DeparseRenameViewStmt(Node *stmt);
|
||||
extern char * DeparseAlterViewStmt(Node *node);
|
||||
extern char * DeparseDropViewStmt(Node *node);
|
||||
extern char * DeparseAlterViewSchemaStmt(Node *node);
|
||||
|
||||
|
||||
/* forward declarations for deparse_function_stmts.c */
|
||||
extern char * DeparseDropFunctionStmt(Node *stmt);
|
||||
|
|
|
@ -22,6 +22,7 @@ extern List * GetUniqueDependenciesList(List *objectAddressesList);
|
|||
extern List * GetDependenciesForObject(const ObjectAddress *target);
|
||||
extern List * GetAllSupportedDependenciesForObject(const ObjectAddress *target);
|
||||
extern List * GetAllDependenciesForObject(const ObjectAddress *target);
|
||||
extern bool ErrorOrWarnIfObjectHasUnsupportedDependency(ObjectAddress *objectAddress);
|
||||
extern DeferredErrorMessage * DeferErrorIfHasUnsupportedDependency(const
|
||||
ObjectAddress *
|
||||
objectAddress);
|
||||
|
|
|
@ -435,6 +435,135 @@ ERROR: cannot change name of view column "id" to "a"
|
|||
HINT: Use ALTER VIEW ... RENAME COLUMN ... to change name of view column instead.
|
||||
CREATE OR REPLACE VIEW view_for_unsup_commands AS SELECT id FROM table_to_test_unsup_view;
|
||||
ERROR: cannot drop columns from view
|
||||
-- ALTER VIEW PROPAGATION
|
||||
CREATE TABLE alter_view_table(id int, val1 text);
|
||||
SELECT create_distributed_table('alter_view_table','id');
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
CREATE VIEW alter_view_1 AS SELECT * FROM alter_view_table;
|
||||
-- Set/drop default value is not supported by Citus
|
||||
ALTER VIEW alter_view_1 ALTER COLUMN val1 SET DEFAULT random()::text;
|
||||
ERROR: Citus doesn't support setting or resetting default values for a column of view
|
||||
ALTER TABLE alter_view_1 ALTER COLUMN val1 SET DEFAULT random()::text;
|
||||
ERROR: Citus doesn't support setting or resetting default values for a column of view
|
||||
ALTER VIEW alter_view_1 ALTER COLUMN val1 DROP DEFAULT;
|
||||
ERROR: Citus doesn't support setting or resetting default values for a column of view
|
||||
ALTER TABLE alter_view_1 ALTER COLUMN val1 DROP DEFAULT;
|
||||
ERROR: Citus doesn't support setting or resetting default values for a column of view
|
||||
-- Set/reset options view alter view/alter table commands
|
||||
ALTER VIEW alter_view_1 SET (check_option=cascaded);
|
||||
ALTER VIEW alter_view_1 SET (security_barrier);
|
||||
ALTER VIEW alter_view_1 SET (check_option=cascaded, security_barrier);
|
||||
ALTER VIEW alter_view_1 SET (check_option=cascaded, security_barrier = true);
|
||||
ALTER TABLE alter_view_1 SET (check_option=cascaded);
|
||||
ALTER TABLE alter_view_1 SET (security_barrier);
|
||||
ALTER TABLE alter_view_1 SET (check_option=cascaded, security_barrier);
|
||||
ALTER TABLE alter_view_1 SET (check_option=cascaded, security_barrier = true);
|
||||
-- Check the definition on both coordinator and worker node
|
||||
SELECT definition FROM pg_views WHERE viewname = 'alter_view_1';
|
||||
definition
|
||||
---------------------------------------------------------------------
|
||||
SELECT alter_view_table.id,+
|
||||
alter_view_table.val1 +
|
||||
FROM alter_view_table;
|
||||
(1 row)
|
||||
|
||||
SELECT relname, reloptions
|
||||
FROM pg_class
|
||||
WHERE oid = 'view_prop_schema.alter_view_1'::regclass::oid;
|
||||
relname | reloptions
|
||||
---------------------------------------------------------------------
|
||||
alter_view_1 | {check_option=cascaded,security_barrier=true}
|
||||
(1 row)
|
||||
|
||||
\c - - - :worker_1_port
|
||||
SELECT definition FROM pg_views WHERE viewname = 'alter_view_1';
|
||||
definition
|
||||
---------------------------------------------------------------------
|
||||
SELECT alter_view_table.id,+
|
||||
alter_view_table.val1 +
|
||||
FROM view_prop_schema.alter_view_table;
|
||||
(1 row)
|
||||
|
||||
SELECT relname, reloptions
|
||||
FROM pg_class
|
||||
WHERE oid = 'view_prop_schema.alter_view_1'::regclass::oid;
|
||||
relname | reloptions
|
||||
---------------------------------------------------------------------
|
||||
alter_view_1 | {check_option=cascaded,security_barrier=true}
|
||||
(1 row)
|
||||
|
||||
\c - - - :master_port
|
||||
SET search_path to view_prop_schema;
|
||||
ALTER TABLE alter_view_1 RESET (check_option, security_barrier);
|
||||
ALTER VIEW alter_view_1 RESET (check_option, security_barrier);
|
||||
-- Change the schema of the view
|
||||
ALTER TABLE alter_view_1 SET SCHEMA view_prop_schema_inner;
|
||||
ALTER VIEW view_prop_schema_inner.alter_view_1 SET SCHEMA view_prop_schema;
|
||||
-- Rename view and view's column name
|
||||
ALTER VIEW alter_view_1 RENAME COLUMN val1 TO val2;
|
||||
ALTER VIEW alter_view_1 RENAME val2 TO val1;
|
||||
ALTER VIEW alter_view_1 RENAME TO alter_view_2;
|
||||
ALTER TABLE alter_view_2 RENAME COLUMN val1 TO val2;
|
||||
ALTER TABLE alter_view_2 RENAME val2 TO val1;
|
||||
ALTER TABLE alter_view_2 RENAME TO alter_view_1;
|
||||
-- Alter owner vith alter view/alter table
|
||||
SET client_min_messages TO ERROR;
|
||||
CREATE USER alter_view_user;
|
||||
SELECT 1 FROM run_command_on_workers($$CREATE USER alter_view_user;$$);
|
||||
?column?
|
||||
---------------------------------------------------------------------
|
||||
1
|
||||
1
|
||||
(2 rows)
|
||||
|
||||
RESET client_min_messages;
|
||||
ALTER VIEW alter_view_1 OWNER TO alter_view_user;
|
||||
ALTER TABLE alter_view_1 OWNER TO alter_view_user;
|
||||
-- Alter view owned by extension
|
||||
CREATE TABLE table_for_ext_owned_view(id int);
|
||||
CREATE VIEW extension_owned_view AS SELECT * FROM table_for_ext_owned_view;
|
||||
WARNING: "view extension_owned_view" has dependency to "table table_for_ext_owned_view" that is not in Citus' metadata
|
||||
DETAIL: "view extension_owned_view" will be created only locally
|
||||
HINT: Distribute "table table_for_ext_owned_view" first to distribute "view extension_owned_view"
|
||||
CREATE EXTENSION seg;
|
||||
ALTER EXTENSION seg ADD VIEW extension_owned_view;
|
||||
NOTICE: Citus does not propagate adding/dropping member objects
|
||||
HINT: You can add/drop the member objects on the workers as well.
|
||||
SELECT create_distributed_table('table_for_ext_owned_view','id');
|
||||
create_distributed_table
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
CREATE OR REPLACE VIEW extension_owned_view AS SELECT * FROM table_for_ext_owned_view;
|
||||
-- Since the view is owned by extension Citus shouldn't propagate it
|
||||
SELECT * FROM (SELECT pg_identify_object_as_address(classid, objid, objsubid) as obj_identifier from pg_catalog.pg_dist_object) as obj_identifiers where obj_identifier::text like '%extension_owned_view%';
|
||||
obj_identifier
|
||||
---------------------------------------------------------------------
|
||||
(0 rows)
|
||||
|
||||
-- Try syncing metadata after running ALTER VIEW commands
|
||||
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
|
||||
start_metadata_sync_to_node
|
||||
---------------------------------------------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
-- Alter non-existing view
|
||||
ALTER VIEW IF EXISTS non_existing_view ALTER COLUMN val1 SET DEFAULT random()::text;
|
||||
NOTICE: relation "non_existing_view" does not exist, skipping
|
||||
ALTER VIEW IF EXISTS non_existing_view SET (check_option=cascaded);
|
||||
NOTICE: relation "non_existing_view" does not exist, skipping
|
||||
ALTER VIEW IF EXISTS non_existing_view RENAME COLUMN val1 TO val2;
|
||||
NOTICE: relation "non_existing_view" does not exist, skipping
|
||||
ALTER VIEW IF EXISTS non_existing_view RENAME val2 TO val1;
|
||||
NOTICE: relation "non_existing_view" does not exist, skipping
|
||||
ALTER VIEW IF EXISTS non_existing_view SET SCHEMA view_prop_schema;
|
||||
NOTICE: relation "non_existing_view" does not exist, skipping
|
||||
SET client_min_messages TO ERROR;
|
||||
DROP SCHEMA view_prop_schema_inner CASCADE;
|
||||
DROP SCHEMA view_prop_schema CASCADE;
|
||||
|
|
|
@ -268,6 +268,94 @@ CREATE VIEW view_for_unsup_commands AS SELECT * FROM table_to_test_unsup_view;
|
|||
CREATE OR REPLACE VIEW view_for_unsup_commands(a,b) AS SELECT * FROM table_to_test_unsup_view;
|
||||
CREATE OR REPLACE VIEW view_for_unsup_commands AS SELECT id FROM table_to_test_unsup_view;
|
||||
|
||||
-- ALTER VIEW PROPAGATION
|
||||
CREATE TABLE alter_view_table(id int, val1 text);
|
||||
SELECT create_distributed_table('alter_view_table','id');
|
||||
|
||||
CREATE VIEW alter_view_1 AS SELECT * FROM alter_view_table;
|
||||
|
||||
-- Set/drop default value is not supported by Citus
|
||||
ALTER VIEW alter_view_1 ALTER COLUMN val1 SET DEFAULT random()::text;
|
||||
ALTER TABLE alter_view_1 ALTER COLUMN val1 SET DEFAULT random()::text;
|
||||
|
||||
ALTER VIEW alter_view_1 ALTER COLUMN val1 DROP DEFAULT;
|
||||
ALTER TABLE alter_view_1 ALTER COLUMN val1 DROP DEFAULT;
|
||||
|
||||
-- Set/reset options view alter view/alter table commands
|
||||
ALTER VIEW alter_view_1 SET (check_option=cascaded);
|
||||
ALTER VIEW alter_view_1 SET (security_barrier);
|
||||
ALTER VIEW alter_view_1 SET (check_option=cascaded, security_barrier);
|
||||
ALTER VIEW alter_view_1 SET (check_option=cascaded, security_barrier = true);
|
||||
|
||||
ALTER TABLE alter_view_1 SET (check_option=cascaded);
|
||||
ALTER TABLE alter_view_1 SET (security_barrier);
|
||||
ALTER TABLE alter_view_1 SET (check_option=cascaded, security_barrier);
|
||||
ALTER TABLE alter_view_1 SET (check_option=cascaded, security_barrier = true);
|
||||
|
||||
-- Check the definition on both coordinator and worker node
|
||||
SELECT definition FROM pg_views WHERE viewname = 'alter_view_1';
|
||||
|
||||
SELECT relname, reloptions
|
||||
FROM pg_class
|
||||
WHERE oid = 'view_prop_schema.alter_view_1'::regclass::oid;
|
||||
|
||||
\c - - - :worker_1_port
|
||||
SELECT definition FROM pg_views WHERE viewname = 'alter_view_1';
|
||||
|
||||
SELECT relname, reloptions
|
||||
FROM pg_class
|
||||
WHERE oid = 'view_prop_schema.alter_view_1'::regclass::oid;
|
||||
|
||||
\c - - - :master_port
|
||||
SET search_path to view_prop_schema;
|
||||
|
||||
ALTER TABLE alter_view_1 RESET (check_option, security_barrier);
|
||||
ALTER VIEW alter_view_1 RESET (check_option, security_barrier);
|
||||
|
||||
-- Change the schema of the view
|
||||
ALTER TABLE alter_view_1 SET SCHEMA view_prop_schema_inner;
|
||||
ALTER VIEW view_prop_schema_inner.alter_view_1 SET SCHEMA view_prop_schema;
|
||||
|
||||
-- Rename view and view's column name
|
||||
ALTER VIEW alter_view_1 RENAME COLUMN val1 TO val2;
|
||||
ALTER VIEW alter_view_1 RENAME val2 TO val1;
|
||||
ALTER VIEW alter_view_1 RENAME TO alter_view_2;
|
||||
|
||||
ALTER TABLE alter_view_2 RENAME COLUMN val1 TO val2;
|
||||
ALTER TABLE alter_view_2 RENAME val2 TO val1;
|
||||
ALTER TABLE alter_view_2 RENAME TO alter_view_1;
|
||||
|
||||
-- Alter owner vith alter view/alter table
|
||||
SET client_min_messages TO ERROR;
|
||||
CREATE USER alter_view_user;
|
||||
SELECT 1 FROM run_command_on_workers($$CREATE USER alter_view_user;$$);
|
||||
RESET client_min_messages;
|
||||
ALTER VIEW alter_view_1 OWNER TO alter_view_user;
|
||||
ALTER TABLE alter_view_1 OWNER TO alter_view_user;
|
||||
|
||||
-- Alter view owned by extension
|
||||
CREATE TABLE table_for_ext_owned_view(id int);
|
||||
CREATE VIEW extension_owned_view AS SELECT * FROM table_for_ext_owned_view;
|
||||
|
||||
CREATE EXTENSION seg;
|
||||
ALTER EXTENSION seg ADD VIEW extension_owned_view;
|
||||
|
||||
SELECT create_distributed_table('table_for_ext_owned_view','id');
|
||||
CREATE OR REPLACE VIEW extension_owned_view AS SELECT * FROM table_for_ext_owned_view;
|
||||
|
||||
-- Since the view is owned by extension Citus shouldn't propagate it
|
||||
SELECT * FROM (SELECT pg_identify_object_as_address(classid, objid, objsubid) as obj_identifier from pg_catalog.pg_dist_object) as obj_identifiers where obj_identifier::text like '%extension_owned_view%';
|
||||
|
||||
-- Try syncing metadata after running ALTER VIEW commands
|
||||
SELECT start_metadata_sync_to_node('localhost', :worker_1_port);
|
||||
|
||||
-- Alter non-existing view
|
||||
ALTER VIEW IF EXISTS non_existing_view ALTER COLUMN val1 SET DEFAULT random()::text;
|
||||
ALTER VIEW IF EXISTS non_existing_view SET (check_option=cascaded);
|
||||
ALTER VIEW IF EXISTS non_existing_view RENAME COLUMN val1 TO val2;
|
||||
ALTER VIEW IF EXISTS non_existing_view RENAME val2 TO val1;
|
||||
ALTER VIEW IF EXISTS non_existing_view SET SCHEMA view_prop_schema;
|
||||
|
||||
SET client_min_messages TO ERROR;
|
||||
DROP SCHEMA view_prop_schema_inner CASCADE;
|
||||
DROP SCHEMA view_prop_schema CASCADE;
|
||||
|
|
Loading…
Reference in New Issue