citus/src/backend/distributed/deparser/deparse_view_stmts.c

312 lines
7.1 KiB
C

/*-------------------------------------------------------------------------
*
* deparse_view_stmts.c
*
* All routines to deparse view statements.
*
* Copyright (c), Citus Data, Inc.
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "catalog/namespace.h"
#include "commands/defrem.h"
#include "lib/stringinfo.h"
#include "nodes/parsenodes.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "distributed/citus_ruleutils.h"
#include "distributed/commands.h"
#include "distributed/deparser.h"
#include "distributed/listutils.h"
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.
*/
char *
DeparseDropViewStmt(Node *node)
{
DropStmt *stmt = castNode(DropStmt, node);
StringInfoData str = { 0 };
initStringInfo(&str);
Assert(stmt->removeType == OBJECT_VIEW);
AppendDropViewStmt(&str, stmt);
return str.data;
}
/*
* AppendDropViewStmt appends the deparsed representation of given drop stmt
* to the given string info buffer.
*/
static void
AppendDropViewStmt(StringInfo buf, DropStmt *stmt)
{
/*
* already tested at call site, but for future it might be collapsed in a
* DeparseDropStmt so be safe and check again
*/
Assert(stmt->removeType == OBJECT_VIEW);
appendStringInfo(buf, "DROP VIEW ");
if (stmt->missing_ok)
{
appendStringInfoString(buf, "IF EXISTS ");
}
AppendViewNameList(buf, stmt->objects);
if (stmt->behavior == DROP_CASCADE)
{
appendStringInfoString(buf, " CASCADE");
}
appendStringInfoString(buf, ";");
}
/*
* AppendViewNameList appends the qualified view names by constructing them from the given
* objects list to the given string info buffer. Note that, objects must hold schema
* qualified view names as its' members.
*/
static void
AppendViewNameList(StringInfo buf, List *viewNamesList)
{
bool isFirstView = true;
List *qualifiedViewName = NULL;
foreach_declared_ptr(qualifiedViewName, viewNamesList)
{
char *quotedQualifiedVieName = NameListToQuotedString(qualifiedViewName);
if (!isFirstView)
{
appendStringInfo(buf, ", ");
}
appendStringInfoString(buf, quotedQualifiedVieName);
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));
}