mirror of https://github.com/citusdata/citus.git
256 lines
6.3 KiB
C
256 lines
6.3 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 "distributed/citus_ruleutils.h"
|
|
#include "distributed/commands.h"
|
|
#include "distributed/deparser.h"
|
|
#include "distributed/listutils.h"
|
|
#include "lib/stringinfo.h"
|
|
#include "nodes/parsenodes.h"
|
|
#include "utils/builtins.h"
|
|
#include "utils/lsyscache.h"
|
|
|
|
static void AppendAliasesFromViewStmtToCreateViewCommand(StringInfo buf, ViewStmt *stmt);
|
|
static void AppendOptionsFromViewStmtToCreateViewCommand(StringInfo buf, ViewStmt *stmt);
|
|
static void AppendDropViewStmt(StringInfo buf, DropStmt *stmt);
|
|
static void AppendViewNameList(StringInfo buf, List *objects);
|
|
|
|
/*
|
|
* DeparseViewStmt deparses the given CREATE OR REPLACE VIEW statement
|
|
*/
|
|
char *
|
|
DeparseViewStmt(Node *node)
|
|
{
|
|
ViewStmt *stmt = castNode(ViewStmt, node);
|
|
StringInfo viewString = makeStringInfo();
|
|
|
|
Oid viewOid = RangeVarGetRelid(stmt->view, NoLock, false);
|
|
|
|
if (stmt->replace)
|
|
{
|
|
appendStringInfoString(viewString, "CREATE OR REPLACE VIEW ");
|
|
}
|
|
else
|
|
{
|
|
appendStringInfoString(viewString, "CREATE VIEW ");
|
|
}
|
|
|
|
AppendQualifiedViewNameToCreateViewCommand(viewString, viewOid);
|
|
AppendAliasesFromViewStmtToCreateViewCommand(viewString, stmt);
|
|
AppendOptionsFromViewStmtToCreateViewCommand(viewString, stmt);
|
|
|
|
/*
|
|
* Note that Postgres converts CREATE RECURSIVE VIEW commands to
|
|
* CREATE VIEW ... WITH RECURSIVE and pg_get_viewdef return it properly.
|
|
* So, we don't need to RECURSIVE views separately while obtaining the
|
|
* view creation command
|
|
*/
|
|
AppendViewDefinitionToCreateViewCommand(viewString, viewOid);
|
|
|
|
return viewString->data;
|
|
}
|
|
|
|
|
|
/*
|
|
* AppendQualifiedViewNameToCreateViewCommand adds the qualified view of the given view
|
|
* oid to the given create view command.
|
|
*/
|
|
void
|
|
AppendQualifiedViewNameToCreateViewCommand(StringInfo buf, Oid viewOid)
|
|
{
|
|
char *viewName = get_rel_name(viewOid);
|
|
char *schemaName = get_namespace_name(get_rel_namespace(viewOid));
|
|
char *qualifiedViewName = quote_qualified_identifier(schemaName, viewName);
|
|
|
|
appendStringInfo(buf, "%s ", qualifiedViewName);
|
|
}
|
|
|
|
|
|
/*
|
|
* AppendAliasesFromViewStmtToCreateViewCommand appends aliases (if exists) of the given view statement
|
|
* to the given create view command.
|
|
*/
|
|
static void
|
|
AppendAliasesFromViewStmtToCreateViewCommand(StringInfo buf, ViewStmt *stmt)
|
|
{
|
|
if (stmt->aliases == NIL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
bool isFirstAlias = true;
|
|
ListCell *aliasItem;
|
|
foreach(aliasItem, stmt->aliases)
|
|
{
|
|
const char *columnAliasName = quote_identifier(strVal(lfirst(aliasItem)));
|
|
|
|
if (isFirstAlias)
|
|
{
|
|
appendStringInfoString(buf, "(");
|
|
isFirstAlias = false;
|
|
}
|
|
else
|
|
{
|
|
appendStringInfoString(buf, ",");
|
|
}
|
|
|
|
appendStringInfoString(buf, columnAliasName);
|
|
}
|
|
|
|
appendStringInfoString(buf, ") ");
|
|
}
|
|
|
|
|
|
/*
|
|
* AppendOptionsFromViewStmtToCreateViewCommand appends options (if exists) of the given view statement
|
|
* to the given create view command. Note that this function also handles
|
|
* WITH [CASCADED | LOCAL] CHECK OPTION part of the CREATE VIEW command.
|
|
*/
|
|
static void
|
|
AppendOptionsFromViewStmtToCreateViewCommand(StringInfo buf, ViewStmt *stmt)
|
|
{
|
|
if (list_length(stmt->options) == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
bool isFirstOption = true;
|
|
ListCell *optionCell;
|
|
foreach(optionCell, stmt->options)
|
|
{
|
|
DefElem *option = (DefElem *) lfirst(optionCell);
|
|
|
|
if (isFirstOption)
|
|
{
|
|
appendStringInfoString(buf, "WITH (");
|
|
isFirstOption = false;
|
|
}
|
|
else
|
|
{
|
|
appendStringInfoString(buf, ",");
|
|
}
|
|
|
|
appendStringInfoString(buf, option->defname);
|
|
if (option->arg != NULL)
|
|
{
|
|
appendStringInfoString(buf, "=");
|
|
appendStringInfoString(buf, defGetString(option));
|
|
}
|
|
}
|
|
|
|
appendStringInfoString(buf, ") ");
|
|
}
|
|
|
|
|
|
/*
|
|
* AppendViewDefinitionToCreateViewCommand adds the definition of the given view to the
|
|
* given create view command.
|
|
*/
|
|
void
|
|
AppendViewDefinitionToCreateViewCommand(StringInfo buf, Oid viewOid)
|
|
{
|
|
/*
|
|
* Set search_path to NIL so that all objects outside of pg_catalog will be
|
|
* schema-prefixed.
|
|
*/
|
|
OverrideSearchPath *overridePath = GetOverrideSearchPath(CurrentMemoryContext);
|
|
overridePath->schemas = NIL;
|
|
overridePath->addCatalog = true;
|
|
PushOverrideSearchPath(overridePath);
|
|
|
|
/*
|
|
* Push the transaction snapshot to be able to get vief definition with pg_get_viewdef
|
|
*/
|
|
PushActiveSnapshot(GetTransactionSnapshot());
|
|
|
|
Datum viewDefinitionDatum = DirectFunctionCall1(pg_get_viewdef,
|
|
ObjectIdGetDatum(viewOid));
|
|
char *viewDefinition = TextDatumGetCString(viewDefinitionDatum);
|
|
|
|
PopActiveSnapshot();
|
|
PopOverrideSearchPath();
|
|
|
|
appendStringInfo(buf, "AS %s ", viewDefinition);
|
|
}
|
|
|
|
|
|
/*
|
|
* 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_ptr(qualifiedViewName, viewNamesList)
|
|
{
|
|
char *quotedQualifiedVieName = NameListToQuotedString(qualifiedViewName);
|
|
if (!isFirstView)
|
|
{
|
|
appendStringInfo(buf, ", ");
|
|
}
|
|
|
|
appendStringInfoString(buf, quotedQualifiedVieName);
|
|
isFirstView = false;
|
|
}
|
|
}
|