From 58ffd406279857b2415d7688f97a4d7e7d98a237 Mon Sep 17 00:00:00 2001 From: Lukas Fittl Date: Fri, 7 Jul 2023 19:49:51 -0700 Subject: [PATCH 1/3] update_source task: Fix omission of pg_query_ruby_freebsd.sym Whilst we already fixed the actual file missing in 831173ca3b, the root cause here was that the update script missed this file needing to be backed up before rewriting the ext/ directory. --- Rakefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Rakefile b/Rakefile index 0616c9a..e56f587 100644 --- a/Rakefile +++ b/Rakefile @@ -55,7 +55,7 @@ task :update_source do # Backup important files from ext dir system("rm -fr #{extbakdir}") system("mkdir -p #{extbakdir}") - system("cp -a #{extdir}/pg_query_ruby.{c,sym} #{extdir}/extconf.rb #{extbakdir}") + system("cp -a #{extdir}/pg_query_ruby{.c,.sym,_freebsd.sym} #{extdir}/extconf.rb #{extbakdir}") FileUtils.rm_rf extdir @@ -85,5 +85,5 @@ task :update_source do # Other support files system("cp -a #{libdir}/testdata/* #{testfilesdir}") # Copy back the custom ext files - system("cp -a #{extbakdir}/pg_query_ruby.{c,sym} #{extbakdir}/extconf.rb #{extdir}") + system("cp -a #{extbakdir}/pg_query_ruby{.c,.sym,_freebsd.sym} #{extbakdir}/extconf.rb #{extdir}") end From ec3dd58c4c2fd823abc938ed041762d5bfe3ba63 Mon Sep 17 00:00:00 2001 From: Lukas Fittl Date: Fri, 7 Jul 2023 19:51:09 -0700 Subject: [PATCH 2/3] Update libpg_query to 15-4.2.2 In passing update the CFLAGS to match the ones used by pg_query_go, which avoid most warnings. --- Rakefile | 4 +- ext/pg_query/extconf.rb | 4 +- ext/pg_query/pg_query_deparse.c | 10636 +----------------- ext/pg_query/postgres_deparse.c | 10665 +++++++++++++++++++ ext/pg_query/postgres_deparse.h | 9 + spec/lib/pg_query/deparse_bad_tree_spec.rb | 2 +- 6 files changed, 10681 insertions(+), 10639 deletions(-) create mode 100644 ext/pg_query/postgres_deparse.c create mode 100644 ext/pg_query/postgres_deparse.h diff --git a/Rakefile b/Rakefile index e56f587..642a688 100644 --- a/Rakefile +++ b/Rakefile @@ -5,8 +5,8 @@ require 'rspec/core/rake_task' require 'rubocop/rake_task' require 'open-uri' -LIB_PG_QUERY_TAG = '15-4.2.1'.freeze -LIB_PG_QUERY_SHA256SUM = '5828124517d8fd3091336fad6897e16ab49ec0b0b188f5859b3b928fc91608c2'.freeze +LIB_PG_QUERY_TAG = '15-4.2.2'.freeze +LIB_PG_QUERY_SHA256SUM = '03d6631b4a5ea9cc26cb2569e0303b9cce2bc1c6b6e1488f5ab9d63e6bd5346d'.freeze Rake::ExtensionTask.new 'pg_query' do |ext| ext.lib_dir = 'lib/pg_query' diff --git a/ext/pg_query/extconf.rb b/ext/pg_query/extconf.rb index b7806a5..1a464f4 100644 --- a/ext/pg_query/extconf.rb +++ b/ext/pg_query/extconf.rb @@ -7,7 +7,9 @@ $objs = Dir.glob(File.join(__dir__, '*.c')).map { |f| Pathname.new(f).sub_ext('.o').to_s } -$CFLAGS << " -fvisibility=hidden -O3 -Wall -fno-strict-aliasing -fwrapv -fstack-protector -Wno-unused-function -Wno-unused-variable -Wno-clobbered -Wno-sign-compare -Wno-discarded-qualifiers -g" +# -Wno-deprecated-non-prototype avoids warnings on Clang 15.0+, this can be removed in Postgres 16: +# https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=1c27d16e6e5c1f463bbe1e9ece88dda811235165 +$CFLAGS << " -fvisibility=hidden -O3 -Wall -fno-strict-aliasing -fwrapv -fstack-protector -Wno-unused-function -Wno-unused-variable -Wno-clobbered -Wno-sign-compare -Wno-discarded-qualifiers -Wno-deprecated-non-prototype -Wno-unknown-warning-option -g" $INCFLAGS = "-I#{File.join(__dir__, 'include')} " + $INCFLAGS diff --git a/ext/pg_query/pg_query_deparse.c b/ext/pg_query/pg_query_deparse.c index 608a71b..6bf5e34 100644 --- a/ext/pg_query/pg_query_deparse.c +++ b/ext/pg_query/pg_query_deparse.c @@ -2,10641 +2,7 @@ #include "pg_query_internal.h" #include "pg_query_readfuncs.h" -#include "catalog/index.h" -#include "catalog/pg_am.h" -#include "catalog/pg_attribute.h" -#include "catalog/pg_class.h" -#include "catalog/pg_trigger.h" -#include "commands/trigger.h" -#include "common/keywords.h" -#include "common/kwlookup.h" -#include "lib/stringinfo.h" -#include "nodes/nodes.h" -#include "nodes/parsenodes.h" -#include "nodes/pg_list.h" -#include "utils/builtins.h" -#include "utils/datetime.h" -#include "utils/timestamp.h" -#include "utils/xml.h" - -typedef enum DeparseNodeContext { - DEPARSE_NODE_CONTEXT_NONE, - // Parent node type (and sometimes field) - DEPARSE_NODE_CONTEXT_INSERT_RELATION, - DEPARSE_NODE_CONTEXT_INSERT_ON_CONFLICT, - DEPARSE_NODE_CONTEXT_UPDATE, - DEPARSE_NODE_CONTEXT_RETURNING, - DEPARSE_NODE_CONTEXT_A_EXPR, - DEPARSE_NODE_CONTEXT_XMLATTRIBUTES, - DEPARSE_NODE_CONTEXT_XMLNAMESPACES, - DEPARSE_NODE_CONTEXT_CREATE_TYPE, - DEPARSE_NODE_CONTEXT_ALTER_TYPE, - DEPARSE_NODE_CONTEXT_SET_STATEMENT, - // Identifier vs constant context - DEPARSE_NODE_CONTEXT_IDENTIFIER, - DEPARSE_NODE_CONTEXT_CONSTANT -} DeparseNodeContext; - -static void -removeTrailingSpace(StringInfo str) -{ - if (str->len >= 1 && str->data[str->len - 1] == ' ') { - str->len -= 1; - str->data[str->len] = '\0'; - } -} - -/* - * Append a SQL string literal representing "val" to buf. - * - * Copied here from postgres_fdw/deparse.c to avoid adding - * many additional dependencies. - */ -static void -deparseStringLiteral(StringInfo buf, const char *val) -{ - const char *valptr; - - /* - * Rather than making assumptions about the remote server's value of - * standard_conforming_strings, always use E'foo' syntax if there are any - * backslashes. This will fail on remote servers before 8.1, but those - * are long out of support. - */ - if (strchr(val, '\\') != NULL) - appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX); - appendStringInfoChar(buf, '\''); - for (valptr = val; *valptr; valptr++) - { - char ch = *valptr; - - if (SQL_STR_DOUBLE(ch, true)) - appendStringInfoChar(buf, ch); - appendStringInfoChar(buf, ch); - } - appendStringInfoChar(buf, '\''); -} - -// Check whether the value is a reserved keyword, to determine escaping for output -// -// Note that since the parser lowercases all keywords, this does *not* match when the -// value is not all-lowercase and a reserved keyword. -static bool -isReservedKeyword(const char *val) -{ - int kwnum = ScanKeywordLookup(val, &ScanKeywords); - bool all_lower_case = true; - const char *cp; - - for (cp = val; *cp; cp++) - { - if (!( - (*cp >= 'a' && *cp <= 'z') || - (*cp >= '0' && *cp <= '9') || - (*cp == '_'))) - { - all_lower_case = false; - break; - } - } - - return all_lower_case && kwnum >= 0 && ScanKeywordCategories[kwnum] == RESERVED_KEYWORD; -} - -// Returns whether the given value consists only of operator characters -static bool -isOp(const char *val) -{ - const char *cp; - - Assert(strlen(val) > 0); - - for (cp = val; *cp; cp++) - { - if (!( - *cp == '~' || - *cp == '!' || - *cp == '@' || - *cp == '#' || - *cp == '^' || - *cp == '&' || - *cp == '|' || - *cp == '`' || - *cp == '?' || - *cp == '+' || - *cp == '-' || - *cp == '*' || - *cp == '/' || - *cp == '%' || - *cp == '<' || - *cp == '>' || - *cp == '=')) - return false; - } - - return true; -} - -static void deparseSelectStmt(StringInfo str, SelectStmt *stmt); -static void deparseIntoClause(StringInfo str, IntoClause *into_clause); -static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context); -static void deparseResTarget(StringInfo str, ResTarget *res_target, DeparseNodeContext context); -static void deparseRawStmt(StringInfo str, RawStmt *raw_stmt); -static void deparseAlias(StringInfo str, Alias *alias); -static void deparseWindowDef(StringInfo str, WindowDef* window_def); -static void deparseColumnRef(StringInfo str, ColumnRef* column_ref); -static void deparseSubLink(StringInfo str, SubLink* sub_link); -static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context); -static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr); -static void deparseAStar(StringInfo str, A_Star* a_star); -static void deparseCollateClause(StringInfo str, CollateClause* collate_clause); -static void deparseSortBy(StringInfo str, SortBy* sort_by); -static void deparseParamRef(StringInfo str, ParamRef* param_ref); -static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function); -static void deparseWithClause(StringInfo str, WithClause *with_clause); -static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr); -static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte); -static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect); -static void deparseRangeFunction(StringInfo str, RangeFunction *range_func); -static void deparseAArrayExpr(StringInfo str, A_ArrayExpr * array_expr); -static void deparseRowExpr(StringInfo str, RowExpr *row_expr); -static void deparseTypeCast(StringInfo str, TypeCast *type_cast, DeparseNodeContext context); -static void deparseTypeName(StringInfo str, TypeName *type_name); -static void deparseIntervalTypmods(StringInfo str, TypeName *type_name); -static void deparseNullTest(StringInfo str, NullTest *null_test); -static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr); -static void deparseCaseWhen(StringInfo str, CaseWhen *case_when); -static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection); -static void deparseAIndices(StringInfo str, A_Indices *a_indices); -static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr); -static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test); -static void deparseColumnDef(StringInfo str, ColumnDef *column_def); -static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt); -static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause); -static void deparseIndexElem(StringInfo str, IndexElem* index_elem); -static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt); -static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt); -static void deparseLockingClause(StringInfo str, LockingClause *locking_clause); -static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default); -static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt); -static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt); -static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter); -static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec); -static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt); -static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt); -static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt); -static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample); -static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func); -static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set); -static void deparseFuncCall(StringInfo str, FuncCall *func_call); -static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr); -static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr); -static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize); -static void deparseConstraint(StringInfo str, Constraint *constraint); -static void deparseSchemaStmt(StringInfo str, Node *node); -static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt); -static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition); -static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item); -static void deparseAConst(StringInfo str, A_Const *a_const); -static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr); -static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func); - -static void deparsePreparableStmt(StringInfo str, Node *node); -static void deparseRuleActionStmt(StringInfo str, Node *node); -static void deparseExplainableStmt(StringInfo str, Node *node); -static void deparseStmt(StringInfo str, Node *node); -static void deparseValue(StringInfo str, union ValUnion *value, DeparseNodeContext context); - -// "any_name" in gram.y -static void deparseAnyName(StringInfo str, List *parts) -{ - ListCell *lc = NULL; - - foreach(lc, parts) - { - Assert(IsA(lfirst(lc), String)); - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); - if (lnext(parts, lc)) - appendStringInfoChar(str, '.'); - } -} -static void deparseAnyNameSkipFirst(StringInfo str, List *parts) -{ - ListCell *lc = NULL; - - for_each_from(lc, parts, 1) - { - Assert(IsA(lfirst(lc), String)); - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); - if (lnext(parts, lc)) - appendStringInfoChar(str, '.'); - } -} -static void deparseAnyNameSkipLast(StringInfo str, List *parts) -{ - ListCell *lc = NULL; - - foreach (lc, parts) - { - if (lnext(parts, lc)) - { - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); - if (foreach_current_index(lc) < list_length(parts) - 2) - appendStringInfoChar(str, '.'); - } - } -} - -// "a_expr" / "b_expr" in gram.y -static void deparseExpr(StringInfo str, Node *node) -{ - if (node == NULL) - return; - switch (nodeTag(node)) - { - case T_FuncCall: - deparseFuncCall(str, castNode(FuncCall, node)); - break; - case T_XmlExpr: - deparseXmlExpr(str, castNode(XmlExpr, node)); - break; - case T_TypeCast: - deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); - break; - case T_A_Const: - deparseAConst(str, castNode(A_Const, node)); - break; - case T_ColumnRef: - deparseColumnRef(str, castNode(ColumnRef, node)); - break; - case T_A_Expr: - deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); - break; - case T_CaseExpr: - deparseCaseExpr(str, castNode(CaseExpr, node)); - break; - case T_A_ArrayExpr: - deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); - break; - case T_NullTest: - deparseNullTest(str, castNode(NullTest, node)); - break; - case T_XmlSerialize: - deparseXmlSerialize(str, castNode(XmlSerialize, node)); - break; - case T_ParamRef: - deparseParamRef(str, castNode(ParamRef, node)); - break; - case T_BoolExpr: - deparseBoolExpr(str, castNode(BoolExpr, node)); - break; - case T_SubLink: - deparseSubLink(str, castNode(SubLink, node)); - break; - case T_RowExpr: - deparseRowExpr(str, castNode(RowExpr, node)); - break; - case T_CoalesceExpr: - deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); - break; - case T_SetToDefault: - deparseSetToDefault(str, castNode(SetToDefault, node)); - break; - case T_A_Indirection: - deparseAIndirection(str, castNode(A_Indirection, node)); - break; - case T_CollateClause: - deparseCollateClause(str, castNode(CollateClause, node)); - break; - case T_CurrentOfExpr: - deparseCurrentOfExpr(str, castNode(CurrentOfExpr, node)); - break; - case T_SQLValueFunction: - deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); - break; - case T_MinMaxExpr: - deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); - break; - case T_BooleanTest: - deparseBooleanTest(str, castNode(BooleanTest, node)); - break; - case T_GroupingFunc: - deparseGroupingFunc(str, castNode(GroupingFunc, node)); - break; - default: - elog(ERROR, "deparse: unpermitted node type in a_expr/b_expr: %d", - (int) nodeTag(node)); - break; - } -} - -// "c_expr" in gram.y -static void deparseCExpr(StringInfo str, Node *node) -{ - switch (nodeTag(node)) - { - case T_ColumnRef: - deparseColumnRef(str, castNode(ColumnRef, node)); - break; - case T_A_Const: - deparseAConst(str, castNode(A_Const, node)); - break; - case T_TypeCast: - deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); - break; - case T_A_Expr: - appendStringInfoChar(str, '('); - deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ')'); - break; - case T_ParamRef: - deparseParamRef(str, castNode(ParamRef, node)); - break; - case T_A_Indirection: - deparseAIndirection(str, castNode(A_Indirection, node)); - break; - case T_CaseExpr: - deparseCaseExpr(str, castNode(CaseExpr, node)); - break; - case T_FuncCall: - deparseFuncCall(str, castNode(FuncCall, node)); - break; - case T_SubLink: - deparseSubLink(str, castNode(SubLink, node)); - break; - case T_A_ArrayExpr: - deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); - break; - case T_RowExpr: - deparseRowExpr(str, castNode(RowExpr, node)); - break; - case T_GroupingFunc: - deparseGroupingFunc(str, castNode(GroupingFunc, node)); - break; - default: - elog(ERROR, "deparse: unpermitted node type in c_expr: %d", - (int) nodeTag(node)); - break; - } -} - -// "expr_list" in gram.y -static void deparseExprList(StringInfo str, List *exprs) -{ - ListCell *lc; - foreach(lc, exprs) - { - deparseExpr(str, lfirst(lc)); - if (lnext(exprs, lc)) - appendStringInfoString(str, ", "); - } -} - -// "ColId", "name", "database_name", "access_method" and "index_name" in gram.y -static void deparseColId(StringInfo str, char *s) -{ - appendStringInfoString(str, quote_identifier(s)); -} - -// "ColLabel", "attr_name" -// -// Note this is kept separate from ColId in case we ever want to be more -// specific on how to handle keywords here -static void deparseColLabel(StringInfo str, char *s) -{ - appendStringInfoString(str, quote_identifier(s)); -} - -// "SignedIconst" and "Iconst" in gram.y -static void deparseSignedIconst(StringInfo str, Node *node) -{ - appendStringInfo(str, "%d", intVal(node)); -} - -// "indirection" and "opt_indirection" in gram.y -static void deparseOptIndirection(StringInfo str, List *indirection, int N) -{ - ListCell *lc = NULL; - - for_each_from(lc, indirection, N) - { - if (IsA(lfirst(lc), String)) - { - appendStringInfoChar(str, '.'); - deparseColLabel(str, strVal(lfirst(lc))); - } - else if (IsA(lfirst(lc), A_Star)) - { - appendStringInfoString(str, ".*"); - } - else if (IsA(lfirst(lc), A_Indices)) - { - deparseAIndices(str, castNode(A_Indices, lfirst(lc))); - } - else - { - // No other nodes should appear here - Assert(false); - } - } -} - -// "role_list" in gram.y -static void deparseRoleList(StringInfo str, List *roles) -{ - ListCell *lc; - - foreach(lc, roles) - { - RoleSpec *role_spec = castNode(RoleSpec, lfirst(lc)); - deparseRoleSpec(str, role_spec); - if (lnext(roles, lc)) - appendStringInfoString(str, ", "); - } -} - -// "SimpleTypename" in gram.y -static void deparseSimpleTypename(StringInfo str, Node *node) -{ - deparseTypeName(str, castNode(TypeName, node)); -} - -// "NumericOnly" in gram.y -static void deparseNumericOnly(StringInfo str, union ValUnion *value) -{ - switch (nodeTag(value)) - { - case T_Integer: - appendStringInfo(str, "%d", value->ival.ival); - break; - case T_Float: - appendStringInfoString(str, value->sval.sval); - break; - default: - Assert(false); - } -} - -// "NumericOnly_list" in gram.y -static void deparseNumericOnlyList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach(lc, l) - { - deparseNumericOnly(str, (union ValUnion *) lfirst(lc)); - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "SeqOptElem" in gram.y -static void deparseSeqOptElem(StringInfo str, DefElem *def_elem) -{ - ListCell *lc; - - if (strcmp(def_elem->defname, "as") == 0) - { - appendStringInfoString(str, "AS "); - deparseSimpleTypename(str, def_elem->arg); - } - else if (strcmp(def_elem->defname, "cache") == 0) - { - appendStringInfoString(str, "CACHE "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); - } - else if (strcmp(def_elem->defname, "cycle") == 0 && boolVal(def_elem->arg)) - { - appendStringInfoString(str, "CYCLE"); - } - else if (strcmp(def_elem->defname, "cycle") == 0 && !boolVal(def_elem->arg)) - { - appendStringInfoString(str, "NO CYCLE"); - } - else if (strcmp(def_elem->defname, "increment") == 0) - { - appendStringInfoString(str, "INCREMENT "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); - } - else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg != NULL) - { - appendStringInfoString(str, "MAXVALUE "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); - } - else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg == NULL) - { - appendStringInfoString(str, "NO MAXVALUE"); - } - else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg != NULL) - { - appendStringInfoString(str, "MINVALUE "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); - } - else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg == NULL) - { - appendStringInfoString(str, "NO MINVALUE"); - } - else if (strcmp(def_elem->defname, "owned_by") == 0) - { - appendStringInfoString(str, "OWNED BY "); - deparseAnyName(str, castNode(List, def_elem->arg)); - } - else if (strcmp(def_elem->defname, "sequence_name") == 0) - { - appendStringInfoString(str, "SEQUENCE NAME "); - deparseAnyName(str, castNode(List, def_elem->arg)); - } - else if (strcmp(def_elem->defname, "start") == 0) - { - appendStringInfoString(str, "START "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); - } - else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) - { - appendStringInfoString(str, "RESTART"); - } - else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) - { - appendStringInfoString(str, "RESTART "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); - } - else - { - Assert(false); - } -} - -// "SeqOptList" in gram.y -static void deparseSeqOptList(StringInfo str, List *options) -{ - ListCell *lc; - Assert(list_length(options) > 0); - foreach (lc, options) - { - deparseSeqOptElem(str, castNode(DefElem, lfirst(lc))); - appendStringInfoChar(str, ' '); - } -} - -// "OptSeqOptList" in gram.y -static void deparseOptSeqOptList(StringInfo str, List *options) -{ - if (list_length(options) > 0) - deparseSeqOptList(str, options); -} - -// "OptParenthesizedSeqOptList" in gram.y -static void deparseOptParenthesizedSeqOptList(StringInfo str, List *options) -{ - if (list_length(options) > 0) - { - appendStringInfoChar(str, '('); - deparseSeqOptList(str, options); - appendStringInfoChar(str, ')'); - } -} - -// "opt_drop_behavior" in gram.y -static void deparseOptDropBehavior(StringInfo str, DropBehavior behavior) -{ - switch (behavior) - { - case DROP_RESTRICT: - // Default - break; - case DROP_CASCADE: - appendStringInfoString(str, "CASCADE "); - break; - } -} - -// "any_operator" in gram.y -static void deparseAnyOperator(StringInfo str, List *op) -{ - Assert(isOp(strVal(llast(op)))); - if (list_length(op) == 2) - { - appendStringInfoString(str, quote_identifier(strVal(linitial(op)))); - appendStringInfoChar(str, '.'); - appendStringInfoString(str, strVal(llast(op))); - } - else if (list_length(op) == 1) - { - appendStringInfoString(str, strVal(llast(op))); - } - else - { - Assert(false); - } -} - -// "qual_Op" and "qual_all_Op" in gram.y -static void deparseQualOp(StringInfo str, List *op) -{ - if (list_length(op) == 1 && isOp(strVal(linitial(op)))) - { - appendStringInfoString(str, strVal(linitial(op))); - } - else - { - appendStringInfoString(str, "OPERATOR("); - deparseAnyOperator(str, op); - appendStringInfoString(str, ")"); - } -} - -// "subquery_Op" in gram.y -static void deparseSubqueryOp(StringInfo str, List *op) -{ - if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~") == 0) - { - appendStringInfoString(str, "LIKE"); - } - else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~") == 0) - { - appendStringInfoString(str, "NOT LIKE"); - } - else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~*") == 0) - { - appendStringInfoString(str, "ILIKE"); - } - else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~*") == 0) - { - appendStringInfoString(str, "NOT ILIKE"); - } - else if (list_length(op) == 1 && isOp(strVal(linitial(op)))) - { - appendStringInfoString(str, strVal(linitial(op))); - } - else - { - appendStringInfoString(str, "OPERATOR("); - deparseAnyOperator(str, op); - appendStringInfoString(str, ")"); - } -} - -// Not present directly in gram.y (usually matched by ColLabel) -static void deparseGenericDefElemName(StringInfo str, const char *in) -{ - Assert(in != NULL); - char *val = pstrdup(in); - for (unsigned char *p = (unsigned char *) val; *p; p++) - *p = pg_toupper(*p); - appendStringInfoString(str, val); - pfree(val); -} - -// "def_arg" and "operator_def_arg" in gram.y -static void deparseDefArg(StringInfo str, Node *arg, bool is_operator_def_arg) -{ - if (IsA(arg, TypeName)) // func_type - { - deparseTypeName(str, castNode(TypeName, arg)); - } - else if (IsA(arg, List)) // qual_all_Op - { - List *l = castNode(List, arg); - Assert(list_length(l) == 1 || list_length(l) == 2); - - // Schema qualified operator - if (list_length(l) == 2) - { - appendStringInfoString(str, "OPERATOR("); - deparseAnyOperator(str, l); - appendStringInfoChar(str, ')'); - } - else if (list_length(l) == 1) - { - appendStringInfoString(str, strVal(linitial(l))); - } - } - else if (IsA(arg, Float) || IsA(arg, Integer)) // NumericOnly - { - deparseValue(str, (union ValUnion *) arg, DEPARSE_NODE_CONTEXT_NONE); - } - else if (IsA(arg, String)) - { - char *s = strVal(arg); - if (!is_operator_def_arg && IsA(arg, String) && strcmp(s, "none") == 0) // NONE - { - appendStringInfoString(str, "NONE"); - } - else if (isReservedKeyword(s)) // reserved_keyword - { - appendStringInfoString(str, s); - } - else // Sconst - { - deparseStringLiteral(str, s); - } - } - else - { - Assert(false); - } -} - -// "definition" in gram.y -static void deparseDefinition(StringInfo str, List *options) -{ - ListCell *lc = NULL; - - appendStringInfoChar(str, '('); - foreach (lc, options) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - appendStringInfoString(str, quote_identifier(def_elem->defname)); - if (def_elem->arg != NULL) { - appendStringInfoString(str, " = "); - deparseDefArg(str, def_elem->arg, false); - } - - if (lnext(options, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); -} - -// "opt_definition" in gram.y -// -// Note this method adds a trailing space if a value is output -static void deparseOptDefinition(StringInfo str, List *options) -{ - if (list_length(options) > 0) - { - appendStringInfoString(str, "WITH "); - deparseDefinition(str, options); - } -} - -// "create_generic_options" in gram.y -static void deparseCreateGenericOptions(StringInfo str, List *options) -{ - ListCell *lc = NULL; - - if (options == NULL) - return; - - appendStringInfoString(str, "OPTIONS ("); - foreach(lc, options) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - appendStringInfoString(str, quote_identifier(def_elem->defname)); - appendStringInfoChar(str, ' '); - deparseStringLiteral(str, strVal(def_elem->arg)); - if (lnext(options, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoString(str, ") "); -} - -// "common_func_opt_item" in gram.y -static void deparseCommonFuncOptItem(StringInfo str, DefElem *def_elem) -{ - if (strcmp(def_elem->defname, "strict") == 0 && boolVal(def_elem->arg)) - { - appendStringInfoString(str, "RETURNS NULL ON NULL INPUT"); - } - else if (strcmp(def_elem->defname, "strict") == 0 && !boolVal(def_elem->arg)) - { - appendStringInfoString(str, "CALLED ON NULL INPUT"); - } - else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "immutable") == 0) - { - appendStringInfoString(str, "IMMUTABLE"); - } - else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "stable") == 0) - { - appendStringInfoString(str, "STABLE"); - } - else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "volatile") == 0) - { - appendStringInfoString(str, "VOLATILE"); - } - else if (strcmp(def_elem->defname, "security") == 0 && boolVal(def_elem->arg)) - { - appendStringInfoString(str, "SECURITY DEFINER"); - } - else if (strcmp(def_elem->defname, "security") == 0 && !boolVal(def_elem->arg)) - { - appendStringInfoString(str, "SECURITY INVOKER"); - } - else if (strcmp(def_elem->defname, "leakproof") == 0 && boolVal(def_elem->arg)) - { - appendStringInfoString(str, "LEAKPROOF"); - } - else if (strcmp(def_elem->defname, "leakproof") == 0 && !boolVal(def_elem->arg)) - { - appendStringInfoString(str, "NOT LEAKPROOF"); - } - else if (strcmp(def_elem->defname, "cost") == 0) - { - appendStringInfoString(str, "COST "); - deparseValue(str, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); - } - else if (strcmp(def_elem->defname, "rows") == 0) - { - appendStringInfoString(str, "ROWS "); - deparseValue(str, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); - } - else if (strcmp(def_elem->defname, "support") == 0) - { - appendStringInfoString(str, "SUPPORT "); - deparseAnyName(str, castNode(List, def_elem->arg)); - } - else if (strcmp(def_elem->defname, "set") == 0 && IsA(def_elem->arg, VariableSetStmt)) // FunctionSetResetClause - { - deparseVariableSetStmt(str, castNode(VariableSetStmt, def_elem->arg)); - } - else if (strcmp(def_elem->defname, "parallel") == 0) - { - appendStringInfoString(str, "PARALLEL "); - appendStringInfoString(str, quote_identifier(strVal(def_elem->arg))); - } - else - { - Assert(false); - } -} - -// "NonReservedWord_or_Sconst" in gram.y -// -// Note since both identifiers and string constants are allowed here, we -// currently always return an identifier, except: -// -// 1) when the string is empty (since an empty identifier can't be scanned) -// 2) when the value is equal or larger than NAMEDATALEN (64+ characters) -static void deparseNonReservedWordOrSconst(StringInfo str, const char *val) -{ - if (strlen(val) == 0) - appendStringInfoString(str, "''"); - else if (strlen(val) >= NAMEDATALEN) - deparseStringLiteral(str, val); - else - appendStringInfoString(str, quote_identifier(val)); -} - -// "func_as" in gram.y -static void deparseFuncAs(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach(lc, l) - { - char *strval = strVal(lfirst(lc)); - if (strstr(strval, "$$") == NULL) - { - appendStringInfoString(str, "$$"); - appendStringInfoString(str, strval); - appendStringInfoString(str, "$$"); - } - else - { - deparseStringLiteral(str, strval); - } - - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "createfunc_opt_item" in gram.y -static void deparseCreateFuncOptItem(StringInfo str, DefElem *def_elem) -{ - ListCell *lc = NULL; - - if (strcmp(def_elem->defname, "as") == 0) - { - appendStringInfoString(str, "AS "); - deparseFuncAs(str, castNode(List, def_elem->arg)); - } - else if (strcmp(def_elem->defname, "language") == 0) - { - appendStringInfoString(str, "LANGUAGE "); - deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); - } - else if (strcmp(def_elem->defname, "transform") == 0) - { - List *l = castNode(List, def_elem->arg); - appendStringInfoString(str, "TRANSFORM "); - foreach (lc, l) - { - appendStringInfoString(str, "FOR TYPE "); - deparseTypeName(str, castNode(TypeName, lfirst(lc))); - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } - } - else if (strcmp(def_elem->defname, "window") == 0) - { - appendStringInfoString(str, "WINDOW"); - } - else - { - deparseCommonFuncOptItem(str, def_elem); - } -} - -// "alter_generic_options" in gram.y -static void deparseAlterGenericOptions(StringInfo str, List *options) -{ - ListCell *lc = NULL; - - appendStringInfoString(str, "OPTIONS ("); - foreach(lc, options) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - switch (def_elem->defaction) - { - case DEFELEM_UNSPEC: - appendStringInfoString(str, quote_identifier(def_elem->defname)); - appendStringInfoChar(str, ' '); - deparseStringLiteral(str, strVal(def_elem->arg)); - break; - case DEFELEM_SET: - appendStringInfoString(str, "SET "); - appendStringInfoString(str, quote_identifier(def_elem->defname)); - appendStringInfoChar(str, ' '); - deparseStringLiteral(str, strVal(def_elem->arg)); - break; - case DEFELEM_ADD: - appendStringInfoString(str, "ADD "); - appendStringInfoString(str, quote_identifier(def_elem->defname)); - appendStringInfoChar(str, ' '); - deparseStringLiteral(str, strVal(def_elem->arg)); - break; - case DEFELEM_DROP: - appendStringInfoString(str, "DROP "); - appendStringInfoString(str, quote_identifier(def_elem->defname)); - break; - } - - if (lnext(options, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoString(str, ") "); -} - -// "func_name" in gram.y -static void deparseFuncName(StringInfo str, List *func_name) -{ - ListCell *lc = NULL; - - foreach(lc, func_name) - { - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); - if (lnext(func_name, lc)) - appendStringInfoChar(str, '.'); - } -} - -// "function_with_argtypes" in gram.y -static void deparseFunctionWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) -{ - ListCell *lc; - deparseFuncName(str, object_with_args->objname); - - if (!object_with_args->args_unspecified) - { - appendStringInfoChar(str, '('); - List *objargs = object_with_args->objargs; - if (object_with_args->objfuncargs) - objargs = object_with_args->objfuncargs; - - foreach(lc, objargs) - { - if (IsA(lfirst(lc), FunctionParameter)) - deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); - else - deparseTypeName(str, castNode(TypeName, lfirst(lc))); - if (lnext(objargs, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); - } -} - -// "function_with_argtypes_list" in gram.y -static void deparseFunctionWithArgtypesList(StringInfo str, List *l) -{ - ListCell *lc; - - foreach(lc, l) - { - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "operator_with_argtypes" in gram.y -static void deparseOperatorWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) -{ - deparseAnyOperator(str, object_with_args->objname); - - Assert(list_length(object_with_args->objargs) == 2); - appendStringInfoChar(str, '('); - if (linitial(object_with_args->objargs) == NULL) - appendStringInfoString(str, "NONE"); - else - deparseTypeName(str, castNode(TypeName, linitial(object_with_args->objargs))); - appendStringInfoString(str, ", "); - if (lsecond(object_with_args->objargs) == NULL) - appendStringInfoString(str, "NONE"); - else - deparseTypeName(str, castNode(TypeName, lsecond(object_with_args->objargs))); - appendStringInfoChar(str, ')'); -} - -// "aggr_args" in gram.y -static void deparseAggrArgs(StringInfo str, List *aggr_args) -{ - Assert(list_length(aggr_args) == 2); - - ListCell *lc = NULL; - List *args = linitial(aggr_args); - int order_by_pos = intVal(lsecond(aggr_args)); - - appendStringInfoChar(str, '('); - if (args == NULL) - { - appendStringInfoChar(str, '*'); - } - else - { - foreach(lc, args) - { - if (foreach_current_index(lc) == order_by_pos) - { - if (foreach_current_index(lc) > 0) - appendStringInfoChar(str, ' '); - appendStringInfoString(str, "ORDER BY "); - } - else if (foreach_current_index(lc) > 0) - { - appendStringInfoString(str, ", "); - } - - deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); - } - - // Repeat the last direct arg as a ordered arg to handle the - // simplification done by makeOrderedSetArgs in gram.y - if (order_by_pos == list_length(args)) - { - appendStringInfoString(str, " ORDER BY "); - deparseFunctionParameter(str, castNode(FunctionParameter, llast(args))); - } - } - appendStringInfoChar(str, ')'); -} - -// "aggregate_with_argtypes" in gram.y -static void deparseAggregateWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) -{ - ListCell *lc = NULL; - - deparseFuncName(str, object_with_args->objname); - - appendStringInfoChar(str, '('); - if (object_with_args->objargs == NULL && object_with_args->objfuncargs == NULL) - { - appendStringInfoChar(str, '*'); - } - else - { - List *objargs = object_with_args->objargs; - if (object_with_args->objfuncargs) - objargs = object_with_args->objfuncargs; - - foreach(lc, objargs) - { - if (IsA(lfirst(lc), FunctionParameter)) - deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); - else - deparseTypeName(str, castNode(TypeName, lfirst(lc))); - if (lnext(objargs, lc)) - appendStringInfoString(str, ", "); - } - } - appendStringInfoChar(str, ')'); -} - -// "columnList" in gram.y -static void deparseColumnList(StringInfo str, List *columns) -{ - ListCell *lc = NULL; - foreach(lc, columns) - { - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); - if (lnext(columns, lc)) - appendStringInfoString(str, ", "); - } -} - -// "OptTemp" in gram.y -// -// Note this method adds a trailing space if a value is output -static void deparseOptTemp(StringInfo str, char relpersistence) -{ - switch (relpersistence) - { - case RELPERSISTENCE_PERMANENT: - // Default - break; - case RELPERSISTENCE_UNLOGGED: - appendStringInfoString(str, "UNLOGGED "); - break; - case RELPERSISTENCE_TEMP: - appendStringInfoString(str, "TEMPORARY "); - break; - default: - Assert(false); - break; - } -} - -// "relation_expr_list" in gram.y -static void deparseRelationExprList(StringInfo str, List *relation_exprs) -{ - ListCell *lc = NULL; - foreach(lc, relation_exprs) - { - deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); - if (lnext(relation_exprs, lc)) - appendStringInfoString(str, ", "); - } -} - -// "handler_name" in gram.y -static void deparseHandlerName(StringInfo str, List *handler_name) -{ - ListCell *lc = NULL; - - foreach(lc, handler_name) - { - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); - if (lnext(handler_name, lc)) - appendStringInfoChar(str, '.'); - } -} - -// "fdw_options" in gram.y -static void deparseFdwOptions(StringInfo str, List *fdw_options) -{ - ListCell *lc = NULL; - - foreach (lc, fdw_options) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg != NULL) - { - appendStringInfoString(str, "HANDLER "); - deparseHandlerName(str, castNode(List, def_elem->arg)); - } - else if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg == NULL) - { - appendStringInfoString(str, "NO HANDLER "); - } - else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg != NULL) - { - appendStringInfoString(str, "VALIDATOR "); - deparseHandlerName(str, castNode(List, def_elem->arg)); - } - else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg == NULL) - { - appendStringInfoString(str, "NO VALIDATOR "); - } - else - { - Assert(false); - } - - if (lnext(fdw_options, lc)) - appendStringInfoChar(str, ' '); - } -} - -// "type_list" in gram.y -static void deparseTypeList(StringInfo str, List *type_list) -{ - ListCell *lc = NULL; - foreach(lc, type_list) - { - deparseTypeName(str, castNode(TypeName, lfirst(lc))); - if (lnext(type_list, lc)) - appendStringInfoString(str, ", "); - } -} - -// "opt_boolean_or_string" in gram.y -static void deparseOptBooleanOrString(StringInfo str, char *s) -{ - if (s == NULL) - return; // No value set - else if (strcmp(s, "true") == 0) - appendStringInfoString(str, "TRUE"); - else if (strcmp(s, "false") == 0) - appendStringInfoString(str, "FALSE"); - else if (strcmp(s, "on") == 0) - appendStringInfoString(str, "ON"); - else if (strcmp(s, "off") == 0) - appendStringInfoString(str, "OFF"); - else - deparseNonReservedWordOrSconst(str, s); -} - -static void deparseOptBoolean(StringInfo str, Node *node) -{ - if (node == NULL) - { - return; - } - - switch (nodeTag(node)) - { - case T_String: - appendStringInfo(str, " %s", strVal(node)); - break; - case T_Integer: - appendStringInfo(str, " %d", intVal(node)); - break; - case T_Boolean: - appendStringInfo(str, " %s", boolVal(node) ? "TRUE" : "FALSE"); - break; - default: - Assert(false); - break; - } -} - -bool optBooleanValue(Node *node) -{ - if (node == NULL) - { - return true; - } - - switch (nodeTag(node)) - { - case T_String: { - // Longest valid string is "off\0" - char lower[4]; - strncpy(lower, strVal(node), 4); - lower[3] = 0; - - if (strcmp(lower, "on") == 0) { - return true; - } else if (strcmp(lower, "off") == 0) { - return false; - } - - // No sane way to handle this. - return false; - } - case T_Integer: - return intVal(node) != 0; - case T_Boolean: - return boolVal(node); - default: - Assert(false); - return false; - } -} - -// "var_name" -// -// Note this is kept separate from ColId in case we want to improve the -// output of namespaced variable names -static void deparseVarName(StringInfo str, char *s) -{ - deparseColId(str, s); -} - -// "var_list" -static void deparseVarList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach(lc, l) - { - if (IsA(lfirst(lc), ParamRef)) - { - deparseParamRef(str, castNode(ParamRef, lfirst(lc))); - } - else if (IsA(lfirst(lc), A_Const)) - { - A_Const *a_const = castNode(A_Const, lfirst(lc)); - if (IsA(&a_const->val, Integer) || IsA(&a_const->val, Float)) - deparseNumericOnly(str, (union ValUnion *) &a_const->val); - else if (IsA(&a_const->val, String)) - deparseOptBooleanOrString(str, strVal(&a_const->val)); - else - Assert(false); - } - else if (IsA(lfirst(lc), TypeCast)) - { - deparseTypeCast(str, castNode(TypeCast, lfirst(lc)), DEPARSE_NODE_CONTEXT_SET_STATEMENT); - } - else - { - Assert(false); - } - - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "transaction_mode_list" in gram.y -static void deparseTransactionModeList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach (lc, l) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - - if (strcmp(def_elem->defname, "transaction_isolation") == 0) - { - char *s = strVal(&castNode(A_Const, def_elem->arg)->val); - appendStringInfoString(str, "ISOLATION LEVEL "); - if (strcmp(s, "read uncommitted") == 0) - appendStringInfoString(str, "READ UNCOMMITTED"); - else if (strcmp(s, "read committed") == 0) - appendStringInfoString(str, "READ COMMITTED"); - else if (strcmp(s, "repeatable read") == 0) - appendStringInfoString(str, "REPEATABLE READ"); - else if (strcmp(s, "serializable") == 0) - appendStringInfoString(str, "SERIALIZABLE"); - else - Assert(false); - } - else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) - { - appendStringInfoString(str, "READ ONLY"); - } - else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) - { - appendStringInfoString(str, "READ WRITE"); - } - else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) - { - appendStringInfoString(str, "DEFERRABLE"); - } - else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) - { - appendStringInfoString(str, "NOT DEFERRABLE"); - } - else - { - Assert(false); - } - - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "alter_identity_column_option_list" in gram.y -static void deparseAlterIdentityColumnOptionList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach (lc, l) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) - { - appendStringInfoString(str, "RESTART"); - } - else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) - { - appendStringInfoString(str, "RESTART "); - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); - } - else if (strcmp(def_elem->defname, "generated") == 0) - { - appendStringInfoString(str, "SET GENERATED "); - if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_ALWAYS) - appendStringInfoString(str, "ALWAYS"); - else if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_BY_DEFAULT) - appendStringInfoString(str, "BY DEFAULT"); - else - Assert(false); - } - else - { - appendStringInfoString(str, "SET "); - deparseSeqOptElem(str, def_elem); - } - if (lnext(l, lc)) - appendStringInfoChar(str, ' '); - } -} - -// "reloptions" in gram.y -static void deparseRelOptions(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - appendStringInfoChar(str, '('); - foreach(lc, l) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - if (def_elem->defnamespace != NULL) - { - appendStringInfoString(str, quote_identifier(def_elem->defnamespace)); - appendStringInfoChar(str, '.'); - } - if (def_elem->defname != NULL) - appendStringInfoString(str, quote_identifier(def_elem->defname)); - if (def_elem->defname != NULL && def_elem->arg != NULL) - appendStringInfoChar(str, '='); - if (def_elem->arg != NULL) - deparseDefArg(str, def_elem->arg, false); - - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); -} - -// "OptWith" and "opt_reloptions" in gram.y -// -// Note this method adds a trailing space if a value is output -static void deparseOptWith(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - if (list_length(l) > 0) - { - appendStringInfoString(str, "WITH "); - deparseRelOptions(str, l); - appendStringInfoChar(str, ' '); - } -} - -// "target_list" and "opt_target_list" in gram.y -static void deparseTargetList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach(lc, l) - { - ResTarget *res_target = castNode(ResTarget, lfirst(lc)); - - if (res_target->val == NULL) - elog(ERROR, "deparse: error in deparseTargetList: ResTarget without val"); - else if (IsA(res_target->val, ColumnRef)) - deparseColumnRef(str, castNode(ColumnRef, res_target->val)); - else - deparseExpr(str, res_target->val); - - if (res_target->name != NULL) { - appendStringInfoString(str, " AS "); - appendStringInfoString(str, quote_identifier(res_target->name)); - } - - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "insert_column_list" in gram.y -static void deparseInsertColumnList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach(lc, l) - { - ResTarget *res_target = castNode(ResTarget, lfirst(lc)); - Assert(res_target->name != NULL); - appendStringInfoString(str, quote_identifier(res_target->name)); - deparseOptIndirection(str, res_target->indirection, 0); - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "xml_attribute_list" in gram.y -static void deparseXmlAttributeList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach(lc, l) - { - ResTarget *res_target = castNode(ResTarget, lfirst(lc)); - Assert(res_target->val != NULL); - - deparseExpr(str, res_target->val); - - if (res_target->name != NULL) - { - appendStringInfoString(str, " AS "); - appendStringInfoString(str, quote_identifier(res_target->name)); - } - - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "xml_namespace_list" in gram.y -static void deparseXmlNamespaceList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach(lc, l) - { - ResTarget *res_target = castNode(ResTarget, lfirst(lc)); - Assert(res_target->val != NULL); - - if (res_target->name == NULL) - appendStringInfoString(str, "DEFAULT "); - - deparseExpr(str, res_target->val); - - if (res_target->name != NULL) - { - appendStringInfoString(str, " AS "); - appendStringInfoString(str, quote_identifier(res_target->name)); - } - - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "table_ref" in gram.y -static void deparseTableRef(StringInfo str, Node *node) -{ - switch (nodeTag(node)) - { - case T_RangeVar: - deparseRangeVar(str, castNode(RangeVar, node), DEPARSE_NODE_CONTEXT_NONE); - break; - case T_RangeTableSample: - deparseRangeTableSample(str, castNode(RangeTableSample, node)); - break; - case T_RangeFunction: - deparseRangeFunction(str, castNode(RangeFunction, node)); - break; - case T_RangeTableFunc: - deparseRangeTableFunc(str, castNode(RangeTableFunc, node)); - break; - case T_RangeSubselect: - deparseRangeSubselect(str, castNode(RangeSubselect, node)); - break; - case T_JoinExpr: - deparseJoinExpr(str, castNode(JoinExpr, node)); - break; - default: - Assert(false); - } -} - -// "from_list" in gram.y -static void deparseFromList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach(lc, l) - { - deparseTableRef(str, lfirst(lc)); - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "from_clause" in gram.y -// -// Note this method adds a trailing space if a value is output -static void deparseFromClause(StringInfo str, List *l) -{ - if (list_length(l) > 0) - { - appendStringInfoString(str, "FROM "); - deparseFromList(str, l); - appendStringInfoChar(str, ' '); - } -} - -// "where_clause" in gram.y -// -// Note this method adds a trailing space if a value is output -static void deparseWhereClause(StringInfo str, Node *node) -{ - if (node != NULL) - { - appendStringInfoString(str, "WHERE "); - deparseExpr(str, node); - appendStringInfoChar(str, ' '); - } -} - -// "group_by_list" in gram.y -static void deparseGroupByList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach(lc, l) - { - if (IsA(lfirst(lc), GroupingSet)) - deparseGroupingSet(str, castNode(GroupingSet, lfirst(lc))); - else - deparseExpr(str, lfirst(lc)); - - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "set_target" in gram.y -static void deparseSetTarget(StringInfo str, ResTarget *res_target) -{ - Assert(res_target->name != NULL); - deparseColId(str, res_target->name); - deparseOptIndirection(str, res_target->indirection, 0); -} - -// "any_name_list" in gram.y -static void deparseAnyNameList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach(lc, l) - { - deparseAnyName(str, castNode(List, lfirst(lc))); - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "name_list" in gram.y -static void deparseNameList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach(lc, l) - { - deparseColId(str, strVal(lfirst(lc))); - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "opt_sort_clause" in gram.y -// -// Note this method adds a trailing space if a value is output -static void deparseOptSortClause(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - if (list_length(l) > 0) - { - appendStringInfoString(str, "ORDER BY "); - - foreach(lc, l) - { - deparseSortBy(str, castNode(SortBy, lfirst(lc))); - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ' '); - } -} - -// "func_arg_expr" in gram.y -static void deparseFuncArgExpr(StringInfo str, Node *node) -{ - if (IsA(node, NamedArgExpr)) - { - NamedArgExpr *named_arg_expr = castNode(NamedArgExpr, node); - appendStringInfoString(str, named_arg_expr->name); - appendStringInfoString(str, " := "); - deparseExpr(str, (Node *) named_arg_expr->arg); - } - else - { - deparseExpr(str, node); - } -} - -// "set_clause_list" in gram.y -static void deparseSetClauseList(StringInfo str, List *target_list) -{ - ListCell *lc; - ListCell *lc2; - int skip_next_n_elems = 0; - - Assert(list_length(target_list) > 0); - - foreach(lc, target_list) - { - if (skip_next_n_elems > 0) - { - skip_next_n_elems--; - continue; - } - - if (foreach_current_index(lc) != 0) - appendStringInfoString(str, ", "); - - ResTarget *res_target = castNode(ResTarget, lfirst(lc)); - Assert(res_target->val != NULL); - - if (IsA(res_target->val, MultiAssignRef)) - { - MultiAssignRef *r = castNode(MultiAssignRef, res_target->val); - appendStringInfoString(str, "("); - for_each_cell(lc2, target_list, lc) - { - deparseSetTarget(str, castNode(ResTarget, lfirst(lc2))); - if (foreach_current_index(lc2) == r->ncolumns - 1) // Last element in this multi-assign - break; - else if (lnext(target_list, lc2)) - appendStringInfoString(str, ", "); - } - appendStringInfoString(str, ") = "); - deparseExpr(str, r->source); - skip_next_n_elems = r->ncolumns - 1; - } - else - { - deparseSetTarget(str, res_target); - appendStringInfoString(str, " = "); - deparseExpr(str, res_target->val); - } - } -} - -// "func_expr_windowless" in gram.y -static void deparseFuncExprWindowless(StringInfo str, Node* node) -{ - switch (nodeTag(node)) - { - case T_FuncCall: - deparseFuncCall(str, castNode(FuncCall, node)); - break; - case T_SQLValueFunction: - deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); - break; - case T_TypeCast: - deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); - break; - case T_CoalesceExpr: - deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); - break; - case T_MinMaxExpr: - deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); - break; - case T_XmlExpr: - deparseXmlExpr(str, castNode(XmlExpr, node)); - break; - case T_XmlSerialize: - deparseXmlSerialize(str, castNode(XmlSerialize, node)); - break; - default: - Assert(false); - } -} - -// "opt_collate" in gram.y -// -// Note this method adds a trailing space if a value is output -static void deparseOptCollate(StringInfo str, List *l) -{ - if (list_length(l) > 0) - { - appendStringInfoString(str, "COLLATE "); - deparseAnyName(str, l); - appendStringInfoChar(str, ' '); - } -} - -// "index_elem" in gram.y -static void deparseIndexElem(StringInfo str, IndexElem* index_elem) -{ - if (index_elem->name != NULL) - { - deparseColId(str, index_elem->name); - appendStringInfoChar(str, ' '); - } - else if (index_elem->expr != NULL) - { - switch (nodeTag(index_elem->expr)) - { - case T_FuncCall: - case T_SQLValueFunction: - case T_TypeCast: - case T_CoalesceExpr: - case T_MinMaxExpr: - case T_XmlExpr: - case T_XmlSerialize: - deparseFuncExprWindowless(str, index_elem->expr); - break; - default: - appendStringInfoChar(str, '('); - deparseExpr(str, index_elem->expr); - appendStringInfoString(str, ") "); - } - } - else - { - Assert(false); - } - - deparseOptCollate(str, index_elem->collation); - - if (list_length(index_elem->opclass) > 0) - { - deparseAnyName(str, index_elem->opclass); - - if (list_length(index_elem->opclassopts) > 0) - deparseRelOptions(str, index_elem->opclassopts); - - appendStringInfoChar(str, ' '); - } - - switch (index_elem->ordering) - { - case SORTBY_DEFAULT: - // Default - break; - case SORTBY_ASC: - appendStringInfoString(str, "ASC "); - break; - case SORTBY_DESC: - appendStringInfoString(str, "DESC "); - break; - case SORTBY_USING: - // Not allowed in CREATE INDEX - Assert(false); - break; - } - - switch (index_elem->nulls_ordering) - { - case SORTBY_NULLS_DEFAULT: - // Default - break; - case SORTBY_NULLS_FIRST: - appendStringInfoString(str, "NULLS FIRST "); - break; - case SORTBY_NULLS_LAST: - appendStringInfoString(str, "NULLS LAST "); - break; - } - - removeTrailingSpace(str); -} - -// "qualified_name_list" in gram.y -static void deparseQualifiedNameList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach(lc, l) - { - deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); - if (lnext(l, lc)) - appendStringInfoString(str, ", "); - } -} - -// "OptInherit" in gram.y -// -// Note this method adds a trailing space if a value is output -static void deparseOptInherit(StringInfo str, List *l) -{ - if (list_length(l) > 0) - { - appendStringInfoString(str, "INHERITS ("); - deparseQualifiedNameList(str, l); - appendStringInfoString(str, ") "); - } -} - -// "privilege_target" in gram.y -static void deparsePrivilegeTarget(StringInfo str, GrantTargetType targtype, ObjectType objtype, List *objs) -{ - switch (targtype) - { - case ACL_TARGET_OBJECT: - switch (objtype) - { - case OBJECT_TABLE: - deparseQualifiedNameList(str, objs); - break; - case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); - deparseQualifiedNameList(str, objs); - break; - case OBJECT_FDW: - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); - deparseNameList(str, objs); - break; - case OBJECT_FOREIGN_SERVER: - appendStringInfoString(str, "FOREIGN SERVER "); - deparseNameList(str, objs); - break; - case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - deparseFunctionWithArgtypesList(str, objs); - break; - case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - deparseFunctionWithArgtypesList(str, objs); - break; - case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - deparseFunctionWithArgtypesList(str, objs); - break; - case OBJECT_DATABASE: - appendStringInfoString(str, "DATABASE "); - deparseNameList(str, objs); - break; - case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); - deparseAnyNameList(str, objs); - break; - case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); - deparseNameList(str, objs); - break; - case OBJECT_LARGEOBJECT: - appendStringInfoString(str, "LARGE OBJECT "); - deparseNumericOnlyList(str, objs); - break; - case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); - deparseNameList(str, objs); - break; - case OBJECT_TABLESPACE: - appendStringInfoString(str, "TABLESPACE "); - deparseNameList(str, objs); - break; - case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); - deparseAnyNameList(str, objs); - break; - default: - // Other types are not supported here - Assert(false); - break; - } - break; - case ACL_TARGET_ALL_IN_SCHEMA: - switch (objtype) - { - case OBJECT_TABLE: - appendStringInfoString(str, "ALL TABLES IN SCHEMA "); - deparseNameList(str, objs); - break; - case OBJECT_SEQUENCE: - appendStringInfoString(str, "ALL SEQUENCES IN SCHEMA "); - deparseNameList(str, objs); - break; - case OBJECT_FUNCTION: - appendStringInfoString(str, "ALL FUNCTIONS IN SCHEMA "); - deparseNameList(str, objs); - break; - case OBJECT_PROCEDURE: - appendStringInfoString(str, "ALL PROCEDURES IN SCHEMA "); - deparseNameList(str, objs); - break; - case OBJECT_ROUTINE: - appendStringInfoString(str, "ALL ROUTINES IN SCHEMA "); - deparseNameList(str, objs); - break; - default: - // Other types are not supported here - Assert(false); - break; - } - break; - case ACL_TARGET_DEFAULTS: // defacl_privilege_target - switch (objtype) - { - case OBJECT_TABLE: - appendStringInfoString(str, "TABLES"); - break; - case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTIONS"); - break; - case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCES"); - break; - case OBJECT_TYPE: - appendStringInfoString(str, "TYPES"); - break; - case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMAS"); - break; - default: - // Other types are not supported here - Assert(false); - break; - } - break; - } -} - -// "opclass_item_list" in gram.y -static void deparseOpclassItemList(StringInfo str, List *items) -{ - ListCell *lc = NULL; - - foreach (lc, items) - { - deparseCreateOpClassItem(str, castNode(CreateOpClassItem, lfirst(lc))); - if (lnext(items, lc)) - appendStringInfoString(str, ", "); - } -} - -// "createdb_opt_list" in gram.y -static void deparseCreatedbOptList(StringInfo str, List *l) -{ - ListCell *lc = NULL; - - foreach (lc, l) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - if (strcmp(def_elem->defname, "connection_limit") == 0) - appendStringInfoString(str, "CONNECTION LIMIT"); - else - deparseGenericDefElemName(str, def_elem->defname); - - appendStringInfoChar(str, ' '); - - if (def_elem->arg == NULL) - appendStringInfoString(str, "DEFAULT"); - else if (IsA(def_elem->arg, Integer)) - deparseSignedIconst(str, def_elem->arg); - else if (IsA(def_elem->arg, String)) - deparseOptBooleanOrString(str, strVal(def_elem->arg)); - - if (lnext(l, lc)) - appendStringInfoChar(str, ' '); - } -} - -// "utility_option_list" in gram.y -static void deparseUtilityOptionList(StringInfo str, List *options) -{ - ListCell *lc = NULL; - char *defname = NULL; - - if (list_length(options) > 0) - { - appendStringInfoChar(str, '('); - foreach(lc, options) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - deparseGenericDefElemName(str, def_elem->defname); - - if (def_elem->arg != NULL) - { - appendStringInfoChar(str, ' '); - if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); - else if (IsA(def_elem->arg, String)) - deparseOptBooleanOrString(str, strVal(def_elem->arg)); - else - Assert(false); - } - - if (lnext(options, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoString(str, ") "); - } -} - -static void deparseSelectStmt(StringInfo str, SelectStmt *stmt) -{ - const ListCell *lc = NULL; - const ListCell *lc2 = NULL; - - if (stmt->withClause) - { - deparseWithClause(str, stmt->withClause); - appendStringInfoChar(str, ' '); - } - - switch (stmt->op) { - case SETOP_NONE: - if (list_length(stmt->valuesLists) > 0) - { - const ListCell *lc; - appendStringInfoString(str, "VALUES "); - - foreach(lc, stmt->valuesLists) - { - appendStringInfoChar(str, '('); - deparseExprList(str, lfirst(lc)); - appendStringInfoChar(str, ')'); - if (lnext(stmt->valuesLists, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ' '); - break; - } - - appendStringInfoString(str, "SELECT "); - - if (list_length(stmt->targetList) > 0) - { - if (stmt->distinctClause != NULL) - { - appendStringInfoString(str, "DISTINCT "); - - if (list_length(stmt->distinctClause) > 0 && linitial(stmt->distinctClause) != NULL) - { - appendStringInfoString(str, "ON ("); - deparseExprList(str, stmt->distinctClause); - appendStringInfoString(str, ") "); - } - } - - deparseTargetList(str, stmt->targetList); - appendStringInfoChar(str, ' '); - } - - if (stmt->intoClause != NULL) - { - appendStringInfoString(str, "INTO "); - deparseOptTemp(str, stmt->intoClause->rel->relpersistence); - deparseIntoClause(str, stmt->intoClause); - appendStringInfoChar(str, ' '); - } - - deparseFromClause(str, stmt->fromClause); - deparseWhereClause(str, stmt->whereClause); - - if (list_length(stmt->groupClause) > 0) - { - appendStringInfoString(str, "GROUP BY "); - if (stmt->groupDistinct) - appendStringInfoString(str, "DISTINCT "); - deparseGroupByList(str, stmt->groupClause); - appendStringInfoChar(str, ' '); - } - - if (stmt->havingClause != NULL) - { - appendStringInfoString(str, "HAVING "); - deparseExpr(str, stmt->havingClause); - appendStringInfoChar(str, ' '); - } - - if (stmt->windowClause != NULL) - { - appendStringInfoString(str, "WINDOW "); - foreach(lc, stmt->windowClause) - { - WindowDef *window_def = castNode(WindowDef, lfirst(lc)); - Assert(window_def->name != NULL); - appendStringInfoString(str, window_def->name); - appendStringInfoString(str, " AS "); - deparseWindowDef(str, window_def); - if (lnext(stmt->windowClause, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ' '); - } - break; - case SETOP_UNION: - case SETOP_INTERSECT: - case SETOP_EXCEPT: - { - bool need_larg_parens = - list_length(stmt->larg->sortClause) > 0 || - stmt->larg->limitOffset != NULL || - stmt->larg->limitCount != NULL || - list_length(stmt->larg->lockingClause) > 0 || - stmt->larg->withClause != NULL || - stmt->larg->op != SETOP_NONE; - bool need_rarg_parens = - list_length(stmt->rarg->sortClause) > 0 || - stmt->rarg->limitOffset != NULL || - stmt->rarg->limitCount != NULL || - list_length(stmt->rarg->lockingClause) > 0 || - stmt->rarg->withClause != NULL || - stmt->rarg->op != SETOP_NONE; - if (need_larg_parens) - appendStringInfoChar(str, '('); - deparseSelectStmt(str, stmt->larg); - if (need_larg_parens) - appendStringInfoChar(str, ')'); - switch (stmt->op) - { - case SETOP_UNION: - appendStringInfoString(str, " UNION "); - break; - case SETOP_INTERSECT: - appendStringInfoString(str, " INTERSECT "); - break; - case SETOP_EXCEPT: - appendStringInfoString(str, " EXCEPT "); - break; - default: - Assert(false); - } - if (stmt->all) - appendStringInfoString(str, "ALL "); - if (need_rarg_parens) - appendStringInfoChar(str, '('); - deparseSelectStmt(str, stmt->rarg); - if (need_rarg_parens) - appendStringInfoChar(str, ')'); - appendStringInfoChar(str, ' '); - } - break; - } - - deparseOptSortClause(str, stmt->sortClause); - - if (stmt->limitCount != NULL) - { - if (stmt->limitOption == LIMIT_OPTION_COUNT) - appendStringInfoString(str, "LIMIT "); - else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) - appendStringInfoString(str, "FETCH FIRST "); - - if (IsA(stmt->limitCount, A_Const) && castNode(A_Const, stmt->limitCount)->isnull) - appendStringInfoString(str, "ALL"); - else - deparseCExpr(str, stmt->limitCount); - - appendStringInfoChar(str, ' '); - - if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) - appendStringInfoString(str, "ROWS WITH TIES "); - } - - if (stmt->limitOffset != NULL) - { - appendStringInfoString(str, "OFFSET "); - deparseExpr(str, stmt->limitOffset); - appendStringInfoChar(str, ' '); - } - - if (list_length(stmt->lockingClause) > 0) - { - foreach(lc, stmt->lockingClause) - { - deparseLockingClause(str, castNode(LockingClause, lfirst(lc))); - if (lnext(stmt->lockingClause, lc)) - appendStringInfoString(str, " "); - } - appendStringInfoChar(str, ' '); - } - - removeTrailingSpace(str); -} - -static void deparseIntoClause(StringInfo str, IntoClause *into_clause) -{ - ListCell *lc; - - deparseRangeVar(str, into_clause->rel, DEPARSE_NODE_CONTEXT_NONE); /* target relation name */ - - if (list_length(into_clause->colNames) > 0) - { - appendStringInfoChar(str, '('); - deparseColumnList(str, into_clause->colNames); - appendStringInfoChar(str, ')'); - } - appendStringInfoChar(str, ' '); - - if (into_clause->accessMethod != NULL) - { - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(into_clause->accessMethod)); - appendStringInfoChar(str, ' '); - } - - deparseOptWith(str, into_clause->options); - - switch (into_clause->onCommit) - { - case ONCOMMIT_NOOP: - // No clause - break; - case ONCOMMIT_PRESERVE_ROWS: - appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); - break; - case ONCOMMIT_DELETE_ROWS: - appendStringInfoString(str, "ON COMMIT DELETE ROWS "); - break; - case ONCOMMIT_DROP: - appendStringInfoString(str, "ON COMMIT DROP "); - break; - } - - if (into_clause->tableSpaceName != NULL) - { - appendStringInfoString(str, "TABLESPACE "); - appendStringInfoString(str, quote_identifier(into_clause->tableSpaceName)); - appendStringInfoChar(str, ' '); - } - - removeTrailingSpace(str); -} - -static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context) -{ - if (!range_var->inh && context != DEPARSE_NODE_CONTEXT_CREATE_TYPE && context != DEPARSE_NODE_CONTEXT_ALTER_TYPE) - appendStringInfoString(str, "ONLY "); - - if (range_var->catalogname != NULL) - { - appendStringInfoString(str, quote_identifier(range_var->catalogname)); - appendStringInfoChar(str, '.'); - } - - if (range_var->schemaname != NULL) - { - appendStringInfoString(str, quote_identifier(range_var->schemaname)); - appendStringInfoChar(str, '.'); - } - - Assert(range_var->relname != NULL); - appendStringInfoString(str, quote_identifier(range_var->relname)); - appendStringInfoChar(str, ' '); - - if (range_var->alias != NULL) - { - if (context == DEPARSE_NODE_CONTEXT_INSERT_RELATION) - appendStringInfoString(str, "AS "); - deparseAlias(str, range_var->alias); - appendStringInfoChar(str, ' '); - } - - removeTrailingSpace(str); -} - -static void deparseRawStmt(StringInfo str, RawStmt *raw_stmt) -{ - if (raw_stmt->stmt == NULL) - elog(ERROR, "deparse error in deparseRawStmt: RawStmt with empty Stmt"); - - deparseStmt(str, raw_stmt->stmt); -} - -static void deparseAlias(StringInfo str, Alias *alias) -{ - appendStringInfoString(str, quote_identifier(alias->aliasname)); - - if (list_length(alias->colnames) > 0) - { - const ListCell *lc = NULL; - appendStringInfoChar(str, '('); - deparseNameList(str, alias->colnames); - appendStringInfoChar(str, ')'); - } -} - -static void deparseAConst(StringInfo str, A_Const *a_const) -{ - union ValUnion *val = a_const->isnull ? NULL : &a_const->val; - deparseValue(str, val, DEPARSE_NODE_CONTEXT_CONSTANT); -} - -static void deparseFuncCall(StringInfo str, FuncCall *func_call) -{ - const ListCell *lc = NULL; - - Assert(list_length(func_call->funcname) > 0); - - if (list_length(func_call->funcname) == 2 && - strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && - strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && - list_length(func_call->args) == 4) - { - /* - * Note that this is a bit odd, but "OVERLAY" is a keyword on its own merit, and only accepts the - * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) - */ - appendStringInfoString(str, "OVERLAY("); - deparseExpr(str, linitial(func_call->args)); - appendStringInfoString(str, " PLACING "); - deparseExpr(str, lsecond(func_call->args)); - appendStringInfoString(str, " FROM "); - deparseExpr(str, lthird(func_call->args)); - appendStringInfoString(str, " FOR "); - deparseExpr(str, lfourth(func_call->args)); - appendStringInfoChar(str, ')'); - return; - } else if (func_call->funcformat == COERCE_SQL_SYNTAX && - list_length(func_call->funcname) == 2 && - strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && - strcmp(strVal(lsecond(func_call->funcname)), "substring") == 0) - { - /* - * "SUBSTRING" is a keyword on its own merit, and only accepts the - * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.substring) - */ - Assert(list_length(func_call->args) == 2 || list_length(func_call->args) == 3); - appendStringInfoString(str, "SUBSTRING("); - deparseExpr(str, linitial(func_call->args)); - appendStringInfoString(str, " FROM "); - deparseExpr(str, lsecond(func_call->args)); - if (list_length(func_call->args) == 3) - { - appendStringInfoString(str, " FOR "); - deparseExpr(str, lthird(func_call->args)); - } - appendStringInfoChar(str, ')'); - return; - } else if (func_call->funcformat == COERCE_SQL_SYNTAX && - list_length(func_call->funcname) == 2 && - strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && - strcmp(strVal(lsecond(func_call->funcname)), "position") == 0 && - list_length(func_call->args) == 2) - { - /* - * "POSITION" is a keyword on its own merit, and only accepts the - * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.position) - * Note that the first and second arguments are switched in this format - */ - appendStringInfoString(str, "POSITION("); - deparseExpr(str, lsecond(func_call->args)); - appendStringInfoString(str, " IN "); - deparseExpr(str, linitial(func_call->args)); - appendStringInfoChar(str, ')'); - return; - } else if (func_call->funcformat == COERCE_SQL_SYNTAX && - list_length(func_call->funcname) == 2 && - strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && - strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && - list_length(func_call->args) == 3) - { - /* - * "OVERLAY" is a keyword on its own merit, and only accepts the - * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) - */ - appendStringInfoString(str, "overlay("); - deparseExpr(str, linitial(func_call->args)); - appendStringInfoString(str, " placing "); - deparseExpr(str, lsecond(func_call->args)); - appendStringInfoString(str, " from "); - deparseExpr(str, lthird(func_call->args)); - appendStringInfoChar(str, ')'); - return; - } else if (func_call->funcformat == COERCE_SQL_SYNTAX && - list_length(func_call->funcname) == 2 && - strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && - strcmp(strVal(lsecond(func_call->funcname)), "pg_collation_for") == 0 && - list_length(func_call->args) == 1) - { - /* - * "collation for" is a keyword on its own merit, and only accepts the - * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) - */ - appendStringInfoString(str, "collation for ("); - deparseExpr(str, linitial(func_call->args)); - appendStringInfoChar(str, ')'); - return; - } else if (func_call->funcformat == COERCE_SQL_SYNTAX && - list_length(func_call->funcname) == 2 && - strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && - strcmp(strVal(lsecond(func_call->funcname)), "extract") == 0 && - list_length(func_call->args) == 2) - { - /* - * "EXTRACT" is a keyword on its own merit, and only accepts the - * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.extract) - */ - appendStringInfoString(str, "extract ("); - deparseExpr(str, linitial(func_call->args)); - appendStringInfoString(str, " FROM "); - deparseExpr(str, lsecond(func_call->args)); - appendStringInfoChar(str, ')'); - return; - } else if (func_call->funcformat == COERCE_SQL_SYNTAX && - list_length(func_call->funcname) == 2 && - strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && - strcmp(strVal(lsecond(func_call->funcname)), "overlaps") == 0 && - list_length(func_call->args) == 4) - { - /* - * "OVERLAPS" is a keyword on its own merit, and only accepts the - * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlaps) - * format: (start_1, end_1) overlaps (start_2, end_2) - */ - appendStringInfoChar(str, '('); - deparseExpr(str, linitial(func_call->args)); - appendStringInfoString(str, ", "); - deparseExpr(str, lsecond(func_call->args)); - appendStringInfoString(str, ") "); - - appendStringInfoString(str, "overlaps "); - appendStringInfoChar(str, '('); - deparseExpr(str, lthird(func_call->args)); - appendStringInfoString(str, ", "); - deparseExpr(str, lfourth(func_call->args)); - appendStringInfoString(str, ") "); - return; - } else if (func_call->funcformat == COERCE_SQL_SYNTAX && - list_length(func_call->funcname) == 2 && - strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && - ( - strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0 || - strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0 || - strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0 - )) - { - /* - * "TRIM " is a keyword on its own merit, and only accepts the - * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.ltrim) - * Note that the first and second arguments are switched in this format - */ - Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); - appendStringInfoString(str, "TRIM ("); - if (strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0) - appendStringInfoString(str, "LEADING "); - else if (strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0) - appendStringInfoString(str, "BOTH "); - else if (strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0) - appendStringInfoString(str, "TRAILING "); - - if (list_length(func_call->args) == 2) - deparseExpr(str, lsecond(func_call->args)); - appendStringInfoString(str, " FROM "); - deparseExpr(str, linitial(func_call->args)); - appendStringInfoChar(str, ')'); - return; - } else if (func_call->funcformat == COERCE_SQL_SYNTAX && - list_length(func_call->funcname) == 2 && - strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && - strcmp(strVal(lsecond(func_call->funcname)), "timezone") == 0 && - list_length(func_call->args) == 2) - { - /* - * "AT TIME ZONE" is a keyword on its own merit, and only accepts the - * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.timezone) - * Note that the arguments are swapped in this case - */ - deparseExpr(str, lsecond(func_call->args)); - appendStringInfoString(str, " AT TIME ZONE "); - deparseExpr(str, linitial(func_call->args)); - return; - } else if (func_call->funcformat == COERCE_SQL_SYNTAX && - list_length(func_call->funcname) == 2 && - strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && - strcmp(strVal(lsecond(func_call->funcname)), "normalize") == 0) - { - /* - * "NORMALIZE" is a keyword on its own merit, and only accepts the - * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.normalize) - */ - Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); - appendStringInfoString(str, "normalize ("); - - deparseExpr(str, linitial(func_call->args)); - if (list_length(func_call->args) == 2) - { - appendStringInfoString(str, ", "); - Assert(IsA(lsecond(func_call->args), A_Const)); - A_Const *aconst = lsecond(func_call->args); - deparseValue(str, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); - } - appendStringInfoChar(str, ')'); - return; - } else if (func_call->funcformat == COERCE_SQL_SYNTAX && - list_length(func_call->funcname) == 2 && - strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && - strcmp(strVal(lsecond(func_call->funcname)), "is_normalized") == 0) - { - /* - * "IS NORMALIZED" is a keyword on its own merit, and only accepts the - * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.is_normalized) - */ - Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); - - deparseExpr(str, linitial(func_call->args)); - appendStringInfoString(str, " IS "); - if (list_length(func_call->args) == 2) - { - Assert(IsA(lsecond(func_call->args), A_Const)); - A_Const *aconst = lsecond(func_call->args); - deparseValue(str, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); - } - appendStringInfoString(str, " NORMALIZED "); - return; - } else if (func_call->funcformat == COERCE_SQL_SYNTAX && - list_length(func_call->funcname) == 2 && - strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && - strcmp(strVal(lsecond(func_call->funcname)), "xmlexists") == 0 && - list_length(func_call->args) == 2) - { - appendStringInfoString(str, "xmlexists ("); - deparseExpr(str, linitial(func_call->args)); - appendStringInfoString(str, " PASSING "); - deparseExpr(str, lsecond(func_call->args)); - appendStringInfoChar(str, ')'); - return; - } - - deparseFuncName(str, func_call->funcname); - appendStringInfoChar(str, '('); - - if (func_call->agg_distinct) - appendStringInfoString(str, "DISTINCT "); - - if (func_call->agg_star) - { - appendStringInfoChar(str, '*'); - } - else if (list_length(func_call->args) > 0) - { - foreach(lc, func_call->args) - { - if (func_call->func_variadic && !lnext(func_call->args, lc)) - appendStringInfoString(str, "VARIADIC "); - deparseFuncArgExpr(str, lfirst(lc)); - if (lnext(func_call->args, lc)) - appendStringInfoString(str, ", "); - } - } - appendStringInfoChar(str, ' '); - - if (func_call->agg_order != NULL && !func_call->agg_within_group) - { - deparseOptSortClause(str, func_call->agg_order); - } - - removeTrailingSpace(str); - appendStringInfoString(str, ") "); - - if (func_call->agg_order != NULL && func_call->agg_within_group) - { - appendStringInfoString(str, "WITHIN GROUP ("); - deparseOptSortClause(str, func_call->agg_order); - removeTrailingSpace(str); - appendStringInfoString(str, ") "); - } - - if (func_call->agg_filter) - { - appendStringInfoString(str, "FILTER (WHERE "); - deparseExpr(str, func_call->agg_filter); - appendStringInfoString(str, ") "); - } - - if (func_call->over) - { - appendStringInfoString(str, "OVER "); - if (func_call->over->name) - appendStringInfoString(str, func_call->over->name); - else - deparseWindowDef(str, func_call->over); - } - - removeTrailingSpace(str); -} - -static void deparseWindowDef(StringInfo str, WindowDef* window_def) -{ - ListCell *lc; - - // The parent node is responsible for outputting window_def->name - - appendStringInfoChar(str, '('); - - if (window_def->refname != NULL) - { - appendStringInfoString(str, quote_identifier(window_def->refname)); - appendStringInfoChar(str, ' '); - } - - if (list_length(window_def->partitionClause) > 0) - { - appendStringInfoString(str, "PARTITION BY "); - deparseExprList(str, window_def->partitionClause); - appendStringInfoChar(str, ' '); - } - - deparseOptSortClause(str, window_def->orderClause); - - if (window_def->frameOptions & FRAMEOPTION_NONDEFAULT) - { - if (window_def->frameOptions & FRAMEOPTION_RANGE) - appendStringInfoString(str, "RANGE "); - else if (window_def->frameOptions & FRAMEOPTION_ROWS) - appendStringInfoString(str, "ROWS "); - else if (window_def->frameOptions & FRAMEOPTION_GROUPS) - appendStringInfoString(str, "GROUPS "); - - if (window_def->frameOptions & FRAMEOPTION_BETWEEN) - appendStringInfoString(str, "BETWEEN "); - - // frame_start - if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) - { - appendStringInfoString(str, "UNBOUNDED PRECEDING "); - } - else if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) - { - Assert(false); // disallowed - } - else if (window_def->frameOptions & FRAMEOPTION_START_CURRENT_ROW) - { - appendStringInfoString(str, "CURRENT ROW "); - } - else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) - { - Assert(window_def->startOffset != NULL); - deparseExpr(str, window_def->startOffset); - appendStringInfoString(str, " PRECEDING "); - } - else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) - { - Assert(window_def->startOffset != NULL); - deparseExpr(str, window_def->startOffset); - appendStringInfoString(str, " FOLLOWING "); - } - - if (window_def->frameOptions & FRAMEOPTION_BETWEEN) - { - appendStringInfoString(str, "AND "); - - // frame_end - if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) - { - Assert(false); // disallowed - } - else if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) - { - appendStringInfoString(str, "UNBOUNDED FOLLOWING "); - } - else if (window_def->frameOptions & FRAMEOPTION_END_CURRENT_ROW) - { - appendStringInfoString(str, "CURRENT ROW "); - } - else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) - { - Assert(window_def->endOffset != NULL); - deparseExpr(str, window_def->endOffset); - appendStringInfoString(str, " PRECEDING "); - } - else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING) - { - Assert(window_def->endOffset != NULL); - deparseExpr(str, window_def->endOffset); - appendStringInfoString(str, " FOLLOWING "); - } - } - - if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) - appendStringInfoString(str, "EXCLUDE CURRENT ROW "); - else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_GROUP) - appendStringInfoString(str, "EXCLUDE GROUP "); - else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_TIES) - appendStringInfoString(str, "EXCLUDE TIES "); - } - - removeTrailingSpace(str); - appendStringInfoChar(str, ')'); -} - -static void deparseColumnRef(StringInfo str, ColumnRef* column_ref) -{ - Assert(list_length(column_ref->fields) >= 1); - - if (IsA(linitial(column_ref->fields), A_Star)) - deparseAStar(str, castNode(A_Star, linitial(column_ref->fields))); - else if (IsA(linitial(column_ref->fields), String)) - deparseColLabel(str, strVal(linitial(column_ref->fields))); - - deparseOptIndirection(str, column_ref->fields, 1); -} - -static void deparseSubLink(StringInfo str, SubLink* sub_link) -{ - switch (sub_link->subLinkType) { - case EXISTS_SUBLINK: - appendStringInfoString(str, "EXISTS ("); - deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); - appendStringInfoChar(str, ')'); - return; - case ALL_SUBLINK: - deparseExpr(str, sub_link->testexpr); - appendStringInfoChar(str, ' '); - deparseSubqueryOp(str, sub_link->operName); - appendStringInfoString(str, " ALL ("); - deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); - appendStringInfoChar(str, ')'); - return; - case ANY_SUBLINK: - deparseExpr(str, sub_link->testexpr); - if (list_length(sub_link->operName) > 0) - { - appendStringInfoChar(str, ' '); - deparseSubqueryOp(str, sub_link->operName); - appendStringInfoString(str, " ANY "); - } - else - { - appendStringInfoString(str, " IN "); - } - appendStringInfoChar(str, '('); - deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); - appendStringInfoChar(str, ')'); - return; - case ROWCOMPARE_SUBLINK: - // Not present in raw parse trees - Assert(false); - return; - case EXPR_SUBLINK: - appendStringInfoString(str, "("); - deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); - appendStringInfoChar(str, ')'); - return; - case MULTIEXPR_SUBLINK: - // Not present in raw parse trees - Assert(false); - return; - case ARRAY_SUBLINK: - appendStringInfoString(str, "ARRAY("); - deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); - appendStringInfoChar(str, ')'); - return; - case CTE_SUBLINK: /* for SubPlans only */ - // Not present in raw parse trees - Assert(false); - return; - } -} - -static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context) -{ - ListCell *lc; - char *name; - - bool need_lexpr_parens = a_expr->lexpr != NULL && (IsA(a_expr->lexpr, BoolExpr) || IsA(a_expr->lexpr, NullTest) || IsA(a_expr->lexpr, A_Expr)); - bool need_rexpr_parens = a_expr->rexpr != NULL && (IsA(a_expr->rexpr, BoolExpr) || IsA(a_expr->rexpr, NullTest) || IsA(a_expr->rexpr, A_Expr)); - - switch (a_expr->kind) { - case AEXPR_OP: /* normal operator */ - { - bool need_outer_parens = context == DEPARSE_NODE_CONTEXT_A_EXPR; - - if (need_outer_parens) - appendStringInfoChar(str, '('); - if (a_expr->lexpr != NULL) - { - if (need_lexpr_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, a_expr->lexpr); - if (need_lexpr_parens) - appendStringInfoChar(str, ')'); - appendStringInfoChar(str, ' '); - } - deparseQualOp(str, a_expr->name); - if (a_expr->rexpr != NULL) - { - appendStringInfoChar(str, ' '); - if (need_rexpr_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, a_expr->rexpr); - if (need_rexpr_parens) - appendStringInfoChar(str, ')'); - } - - if (need_outer_parens) - appendStringInfoChar(str, ')'); - } - return; - case AEXPR_OP_ANY: /* scalar op ANY (array) */ - deparseExpr(str, a_expr->lexpr); - appendStringInfoChar(str, ' '); - deparseSubqueryOp(str, a_expr->name); - appendStringInfoString(str, " ANY("); - deparseExpr(str, a_expr->rexpr); - appendStringInfoChar(str, ')'); - return; - case AEXPR_OP_ALL: /* scalar op ALL (array) */ - deparseExpr(str, a_expr->lexpr); - appendStringInfoChar(str, ' '); - deparseSubqueryOp(str, a_expr->name); - appendStringInfoString(str, " ALL("); - deparseExpr(str, a_expr->rexpr); - appendStringInfoChar(str, ')'); - return; - case AEXPR_DISTINCT: /* IS DISTINCT FROM - name must be "=" */ - Assert(list_length(a_expr->name) == 1); - Assert(IsA(linitial(a_expr->name), String)); - Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); - - if (need_lexpr_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, a_expr->lexpr); - if (need_lexpr_parens) - appendStringInfoChar(str, ')'); - appendStringInfoString(str, " IS DISTINCT FROM "); - if (need_rexpr_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, a_expr->rexpr); - if (need_rexpr_parens) - appendStringInfoChar(str, ')'); - return; - case AEXPR_NOT_DISTINCT: /* IS NOT DISTINCT FROM - name must be "=" */ - Assert(list_length(a_expr->name) == 1); - Assert(IsA(linitial(a_expr->name), String)); - Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); - - deparseExpr(str, a_expr->lexpr); - appendStringInfoString(str, " IS NOT DISTINCT FROM "); - deparseExpr(str, a_expr->rexpr); - return; - case AEXPR_NULLIF: /* NULLIF - name must be "=" */ - Assert(list_length(a_expr->name) == 1); - Assert(IsA(linitial(a_expr->name), String)); - Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); - - appendStringInfoString(str, "NULLIF("); - deparseExpr(str, a_expr->lexpr); - appendStringInfoString(str, ", "); - deparseExpr(str, a_expr->rexpr); - appendStringInfoChar(str, ')'); - return; - case AEXPR_IN: /* [NOT] IN - name must be "=" or "<>" */ - Assert(list_length(a_expr->name) == 1); - Assert(IsA(linitial(a_expr->name), String)); - Assert(IsA(a_expr->rexpr, List)); - deparseExpr(str, a_expr->lexpr); - appendStringInfoChar(str, ' '); - name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; - if (strcmp(name, "=") == 0) { - appendStringInfoString(str, "IN "); - } else if (strcmp(name, "<>") == 0) { - appendStringInfoString(str, "NOT IN "); - } else { - Assert(false); - } - appendStringInfoChar(str, '('); - if (IsA(a_expr->rexpr, SubLink)) - deparseSubLink(str, castNode(SubLink, a_expr->rexpr)); - else - deparseExprList(str, castNode(List, a_expr->rexpr)); - appendStringInfoChar(str, ')'); - return; - case AEXPR_LIKE: /* [NOT] LIKE - name must be "~~" or "!~~" */ - Assert(list_length(a_expr->name) == 1); - Assert(IsA(linitial(a_expr->name), String)); - deparseExpr(str, a_expr->lexpr); - appendStringInfoChar(str, ' '); - - name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; - if (strcmp(name, "~~") == 0) { - appendStringInfoString(str, "LIKE "); - } else if (strcmp(name, "!~~") == 0) { - appendStringInfoString(str, "NOT LIKE "); - } else { - Assert(false); - } - - deparseExpr(str, a_expr->rexpr); - return; - case AEXPR_ILIKE: /* [NOT] ILIKE - name must be "~~*" or "!~~*" */ - Assert(list_length(a_expr->name) == 1); - Assert(IsA(linitial(a_expr->name), String)); - deparseExpr(str, a_expr->lexpr); - appendStringInfoChar(str, ' '); - - name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; - if (strcmp(name, "~~*") == 0) { - appendStringInfoString(str, "ILIKE "); - } else if (strcmp(name, "!~~*") == 0) { - appendStringInfoString(str, "NOT ILIKE "); - } else { - Assert(false); - } - - deparseExpr(str, a_expr->rexpr); - return; - case AEXPR_SIMILAR: /* [NOT] SIMILAR - name must be "~" or "!~" */ - Assert(list_length(a_expr->name) == 1); - Assert(IsA(linitial(a_expr->name), String)); - deparseExpr(str, a_expr->lexpr); - appendStringInfoChar(str, ' '); - - name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; - if (strcmp(name, "~") == 0) { - appendStringInfoString(str, "SIMILAR TO "); - } else if (strcmp(name, "!~") == 0) { - appendStringInfoString(str, "NOT SIMILAR TO "); - } else { - Assert(false); - } - - FuncCall *n = castNode(FuncCall, a_expr->rexpr); - Assert(list_length(n->funcname) == 2); - Assert(strcmp(strVal(linitial(n->funcname)), "pg_catalog") == 0); - Assert(strcmp(strVal(lsecond(n->funcname)), "similar_to_escape") == 0); - Assert(list_length(n->args) == 1 || list_length(n->args) == 2); - - deparseExpr(str, linitial(n->args)); - if (list_length(n->args) == 2) - { - appendStringInfoString(str, " ESCAPE "); - deparseExpr(str, lsecond(n->args)); - } - - return; - case AEXPR_BETWEEN: /* name must be "BETWEEN" */ - case AEXPR_NOT_BETWEEN: /* name must be "NOT BETWEEN" */ - case AEXPR_BETWEEN_SYM: /* name must be "BETWEEN SYMMETRIC" */ - case AEXPR_NOT_BETWEEN_SYM: /* name must be "NOT BETWEEN SYMMETRIC" */ - Assert(list_length(a_expr->name) == 1); - Assert(IsA(linitial(a_expr->name), String)); - Assert(IsA(a_expr->rexpr, List)); - - deparseExpr(str, a_expr->lexpr); - appendStringInfoChar(str, ' '); - appendStringInfoString(str, strVal(linitial(a_expr->name))); - appendStringInfoChar(str, ' '); - - foreach(lc, castNode(List, a_expr->rexpr)) { - deparseExpr(str, lfirst(lc)); - if (lnext(castNode(List, a_expr->rexpr), lc)) - appendStringInfoString(str, " AND "); - } - return; - } -} - -static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr) -{ - const ListCell *lc = NULL; - switch (bool_expr->boolop) - { - case AND_EXPR: - foreach(lc, bool_expr->args) - { - // Put parantheses around AND + OR nodes that are inside - bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); - - if (need_parens) - appendStringInfoChar(str, '('); - - deparseExpr(str, lfirst(lc)); - - if (need_parens) - appendStringInfoChar(str, ')'); - - if (lnext(bool_expr->args, lc)) - appendStringInfoString(str, " AND "); - } - return; - case OR_EXPR: - foreach(lc, bool_expr->args) - { - // Put parantheses around AND + OR nodes that are inside - bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); - - if (need_parens) - appendStringInfoChar(str, '('); - - deparseExpr(str, lfirst(lc)); - - if (need_parens) - appendStringInfoChar(str, ')'); - - if (lnext(bool_expr->args, lc)) - appendStringInfoString(str, " OR "); - } - return; - case NOT_EXPR: - Assert(list_length(bool_expr->args) == 1); - bool need_parens = IsA(linitial(bool_expr->args), BoolExpr) && (castNode(BoolExpr, linitial(bool_expr->args))->boolop == AND_EXPR || castNode(BoolExpr, linitial(bool_expr->args))->boolop == OR_EXPR); - appendStringInfoString(str, "NOT "); - if (need_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, linitial(bool_expr->args)); - if (need_parens) - appendStringInfoChar(str, ')'); - return; - } -} - -static void deparseAStar(StringInfo str, A_Star *a_star) -{ - appendStringInfoChar(str, '*'); -} - -static void deparseCollateClause(StringInfo str, CollateClause* collate_clause) -{ - ListCell *lc; - if (collate_clause->arg != NULL) - { - bool need_parens = IsA(collate_clause->arg, A_Expr); - if (need_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, collate_clause->arg); - if (need_parens) - appendStringInfoChar(str, ')'); - appendStringInfoChar(str, ' '); - } - appendStringInfoString(str, "COLLATE "); - deparseAnyName(str, collate_clause->collname); -} - -static void deparseSortBy(StringInfo str, SortBy* sort_by) -{ - deparseExpr(str, sort_by->node); - appendStringInfoChar(str, ' '); - - switch (sort_by->sortby_dir) - { - case SORTBY_DEFAULT: - break; - case SORTBY_ASC: - appendStringInfoString(str, "ASC "); - break; - case SORTBY_DESC: - appendStringInfoString(str, "DESC "); - break; - case SORTBY_USING: - appendStringInfoString(str, "USING "); - deparseQualOp(str, sort_by->useOp); - break; - } - - switch (sort_by->sortby_nulls) - { - case SORTBY_NULLS_DEFAULT: - break; - case SORTBY_NULLS_FIRST: - appendStringInfoString(str, "NULLS FIRST "); - break; - case SORTBY_NULLS_LAST: - appendStringInfoString(str, "NULLS LAST "); - break; - } - - removeTrailingSpace(str); -} - -static void deparseParamRef(StringInfo str, ParamRef* param_ref) -{ - if (param_ref->number == 0) { - appendStringInfoChar(str, '?'); - } else { - appendStringInfo(str, "$%d", param_ref->number); - } -} - -static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function) -{ - switch (sql_value_function->op) - { - case SVFOP_CURRENT_DATE: - appendStringInfoString(str, "current_date"); - break; - case SVFOP_CURRENT_TIME: - appendStringInfoString(str, "current_time"); - break; - case SVFOP_CURRENT_TIME_N: - appendStringInfoString(str, "current_time"); // with precision - break; - case SVFOP_CURRENT_TIMESTAMP: - appendStringInfoString(str, "current_timestamp"); - break; - case SVFOP_CURRENT_TIMESTAMP_N: - appendStringInfoString(str, "current_timestamp"); // with precision - break; - case SVFOP_LOCALTIME: - appendStringInfoString(str, "localtime"); - break; - case SVFOP_LOCALTIME_N: - appendStringInfoString(str, "localtime"); // with precision - break; - case SVFOP_LOCALTIMESTAMP: - appendStringInfoString(str, "localtimestamp"); - break; - case SVFOP_LOCALTIMESTAMP_N: - appendStringInfoString(str, "localtimestamp"); // with precision - break; - case SVFOP_CURRENT_ROLE: - appendStringInfoString(str, "current_role"); - break; - case SVFOP_CURRENT_USER: - appendStringInfoString(str, "current_user"); - break; - case SVFOP_USER: - appendStringInfoString(str, "user"); - break; - case SVFOP_SESSION_USER: - appendStringInfoString(str, "session_user"); - break; - case SVFOP_CURRENT_CATALOG: - appendStringInfoString(str, "current_catalog"); - break; - case SVFOP_CURRENT_SCHEMA: - appendStringInfoString(str, "current_schema"); - break; - } - - if (sql_value_function->typmod != -1) - { - appendStringInfo(str, "(%d)", sql_value_function->typmod); - } -} - -static void deparseWithClause(StringInfo str, WithClause *with_clause) -{ - ListCell *lc; - - appendStringInfoString(str, "WITH "); - if (with_clause->recursive) - appendStringInfoString(str, "RECURSIVE "); - - foreach(lc, with_clause->ctes) { - deparseCommonTableExpr(str, castNode(CommonTableExpr, lfirst(lc))); - if (lnext(with_clause->ctes, lc)) - appendStringInfoString(str, ", "); - } - - removeTrailingSpace(str); -} - -static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr) -{ - ListCell *lc; - bool need_alias_parens = join_expr->alias != NULL; - bool need_rarg_parens = IsA(join_expr->rarg, JoinExpr) && castNode(JoinExpr, join_expr->rarg)->alias == NULL; - - if (need_alias_parens) - appendStringInfoChar(str, '('); - - deparseTableRef(str, join_expr->larg); - - appendStringInfoChar(str, ' '); - - if (join_expr->isNatural) - appendStringInfoString(str, "NATURAL "); - - switch (join_expr->jointype) - { - case JOIN_INNER: /* matching tuple pairs only */ - if (!join_expr->isNatural && join_expr->quals == NULL && list_length(join_expr->usingClause) == 0) - appendStringInfoString(str, "CROSS "); - break; - case JOIN_LEFT: /* pairs + unmatched LHS tuples */ - appendStringInfoString(str, "LEFT "); - break; - case JOIN_FULL: /* pairs + unmatched LHS + unmatched RHS */ - appendStringInfoString(str, "FULL "); - break; - case JOIN_RIGHT: /* pairs + unmatched RHS tuples */ - appendStringInfoString(str, "RIGHT "); - break; - case JOIN_SEMI: - case JOIN_ANTI: - case JOIN_UNIQUE_OUTER: - case JOIN_UNIQUE_INNER: - // Only used by the planner/executor, not seen in parser output - Assert(false); - break; - } - - appendStringInfoString(str, "JOIN "); - - if (need_rarg_parens) - appendStringInfoChar(str, '('); - deparseTableRef(str, join_expr->rarg); - if (need_rarg_parens) - appendStringInfoChar(str, ')'); - appendStringInfoChar(str, ' '); - - if (join_expr->quals != NULL) - { - appendStringInfoString(str, "ON "); - deparseExpr(str, join_expr->quals); - appendStringInfoChar(str, ' '); - } - - if (list_length(join_expr->usingClause) > 0) - { - appendStringInfoString(str, "USING ("); - deparseNameList(str, join_expr->usingClause); - appendStringInfoString(str, ") "); - - if (join_expr->join_using_alias) - { - appendStringInfoString(str, "AS "); - appendStringInfoString(str, join_expr->join_using_alias->aliasname); - } - } - - if (need_alias_parens) - appendStringInfoString(str, ") "); - - if (join_expr->alias != NULL) - deparseAlias(str, join_expr->alias); - - removeTrailingSpace(str); -} - -static void deparseCTESearchClause(StringInfo str, CTESearchClause *search_clause) -{ - appendStringInfoString(str, " SEARCH "); - if (search_clause->search_breadth_first) - appendStringInfoString(str, "BREADTH "); - else - appendStringInfoString(str, "DEPTH "); - - appendStringInfoString(str, "FIRST BY "); - - if (search_clause->search_col_list) - deparseColumnList(str, search_clause->search_col_list); - - appendStringInfoString(str, " SET "); - appendStringInfoString(str, quote_identifier(search_clause->search_seq_column)); -} - -static void deparseCTECycleClause(StringInfo str, CTECycleClause *cycle_clause) -{ - appendStringInfoString(str, " CYCLE "); - - if (cycle_clause->cycle_col_list) - deparseColumnList(str, cycle_clause->cycle_col_list); - - appendStringInfoString(str, " SET "); - appendStringInfoString(str, quote_identifier(cycle_clause->cycle_mark_column)); - - if (cycle_clause->cycle_mark_value) - { - appendStringInfoString(str, " TO "); - deparseExpr(str, cycle_clause->cycle_mark_value); - } - - if (cycle_clause->cycle_mark_default) - { - appendStringInfoString(str, " DEFAULT "); - deparseExpr(str, cycle_clause->cycle_mark_default); - } - - appendStringInfoString(str, " USING "); - appendStringInfoString(str, quote_identifier(cycle_clause->cycle_path_column)); -} - -static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte) -{ - deparseColId(str, cte->ctename); - - if (list_length(cte->aliascolnames) > 0) - { - appendStringInfoChar(str, '('); - deparseNameList(str, cte->aliascolnames); - appendStringInfoChar(str, ')'); - } - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "AS "); - switch (cte->ctematerialized) { - case CTEMaterializeDefault: /* no option specified */ - break; - case CTEMaterializeAlways: - appendStringInfoString(str, "MATERIALIZED "); - break; - case CTEMaterializeNever: - appendStringInfoString(str, "NOT MATERIALIZED "); - break; - } - - appendStringInfoChar(str, '('); - deparsePreparableStmt(str, cte->ctequery); - appendStringInfoChar(str, ')'); - - if (cte->search_clause) - deparseCTESearchClause(str, cte->search_clause); - if (cte->cycle_clause) - deparseCTECycleClause(str, cte->cycle_clause); -} - -static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect) -{ - if (range_subselect->lateral) - appendStringInfoString(str, "LATERAL "); - - appendStringInfoChar(str, '('); - deparseSelectStmt(str, castNode(SelectStmt, range_subselect->subquery)); - appendStringInfoChar(str, ')'); - - if (range_subselect->alias != NULL) - { - appendStringInfoChar(str, ' '); - deparseAlias(str, range_subselect->alias); - } -} - -static void deparseRangeFunction(StringInfo str, RangeFunction *range_func) -{ - ListCell *lc; - ListCell *lc2; - - if (range_func->lateral) - appendStringInfoString(str, "LATERAL "); - - if (range_func->is_rowsfrom) - { - appendStringInfoString(str, "ROWS FROM "); - appendStringInfoChar(str, '('); - foreach(lc, range_func->functions) - { - List *lfunc = castNode(List, lfirst(lc)); - Assert(list_length(lfunc) == 2); - deparseFuncExprWindowless(str, linitial(lfunc)); - appendStringInfoChar(str, ' '); - List *coldeflist = castNode(List, lsecond(lfunc)); - if (list_length(coldeflist) > 0) - { - appendStringInfoString(str, "AS ("); - foreach(lc2, coldeflist) - { - deparseColumnDef(str, castNode(ColumnDef, lfirst(lc2))); - if (lnext(coldeflist, lc2)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); - } - if (lnext(range_func->functions, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); - } - else - { - Assert(list_length(linitial(range_func->functions)) == 2); - deparseFuncExprWindowless(str, linitial(linitial(range_func->functions))); - } - appendStringInfoChar(str, ' '); - - if (range_func->ordinality) - appendStringInfoString(str, "WITH ORDINALITY "); - - if (range_func->alias != NULL) - { - deparseAlias(str, range_func->alias); - appendStringInfoChar(str, ' '); - } - - if (list_length(range_func->coldeflist) > 0) - { - if (range_func->alias == NULL) - appendStringInfoString(str, "AS "); - appendStringInfoChar(str, '('); - foreach(lc, range_func->coldeflist) - { - deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); - if (lnext(range_func->coldeflist, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); - } - - removeTrailingSpace(str); -} - -static void deparseAArrayExpr(StringInfo str, A_ArrayExpr *array_expr) -{ - ListCell *lc; - - appendStringInfoString(str, "ARRAY["); - deparseExprList(str, array_expr->elements); - appendStringInfoChar(str, ']'); -} - -static void deparseRowExpr(StringInfo str, RowExpr *row_expr) -{ - ListCell *lc; - - switch (row_expr->row_format) - { - case COERCE_EXPLICIT_CALL: - appendStringInfoString(str, "ROW"); - break; - case COERCE_SQL_SYNTAX: - case COERCE_EXPLICIT_CAST: - // Not present in raw parser output - Assert(false); - break; - case COERCE_IMPLICIT_CAST: - // No prefix - break; - } - - appendStringInfoString(str, "("); - deparseExprList(str, row_expr->args); - appendStringInfoChar(str, ')'); -} - -static void deparseTypeCast(StringInfo str, TypeCast *type_cast, DeparseNodeContext context) -{ - bool need_parens = false; - - Assert(type_cast->typeName != NULL); - - if (IsA(type_cast->arg, A_Expr)) - { - appendStringInfoString(str, "CAST("); - deparseExpr(str, type_cast->arg); - appendStringInfoString(str, " AS "); - deparseTypeName(str, type_cast->typeName); - appendStringInfoChar(str, ')'); - return; - } - - if (IsA(type_cast->arg, A_Const)) - { - A_Const *a_const = castNode(A_Const, type_cast->arg); - - if (list_length(type_cast->typeName->names) == 2 && - strcmp(strVal(linitial(type_cast->typeName->names)), "pg_catalog") == 0) - { - char *typename = strVal(lsecond(type_cast->typeName->names)); - if (strcmp(typename, "bpchar") == 0 && type_cast->typeName->typmods == NULL) - { - appendStringInfoString(str, "char "); - deparseAConst(str, a_const); - return; - } - else if (strcmp(typename, "bool") == 0 && IsA(&a_const->val, String)) - { - /* - * Handle "bool" or "false" in the statement, which is represented as a typecast - * (other boolean casts should be represented as a cast, i.e. don't need special handling) - */ - char *const_val = strVal(&a_const->val); - if (strcmp(const_val, "t") == 0) - { - appendStringInfoString(str, "true"); - return; - } - if (strcmp(const_val, "f") == 0) - { - appendStringInfoString(str, "false"); - return; - } - } - else if (strcmp(typename, "interval") == 0 && context == DEPARSE_NODE_CONTEXT_SET_STATEMENT && IsA(&a_const->val, String)) - { - appendStringInfoString(str, "interval "); - deparseAConst(str, a_const); - deparseIntervalTypmods(str, type_cast->typeName); - return; - } - } - - // Ensure negative values have wrapping parentheses - if (IsA(&a_const->val, Float) || (IsA(&a_const->val, Integer) && intVal(&a_const->val) < 0)) - { - need_parens = true; - } - - if (list_length(type_cast->typeName->names) == 1 && - strcmp(strVal(linitial(type_cast->typeName->names)), "point") == 0 && - a_const->location > type_cast->typeName->location) - { - appendStringInfoString(str, " point "); - deparseAConst(str, a_const); - return; - } - } - - - if (need_parens) - appendStringInfoChar(str, '('); - deparseExpr(str, type_cast->arg); - if (need_parens) - appendStringInfoChar(str, ')'); - - appendStringInfoString(str, "::"); - deparseTypeName(str, type_cast->typeName); -} - -static void deparseTypeName(StringInfo str, TypeName *type_name) -{ - ListCell *lc; - bool skip_typmods = false; - - if (type_name->setof) - appendStringInfoString(str, "SETOF "); - - if (list_length(type_name->names) == 2 && strcmp(strVal(linitial(type_name->names)), "pg_catalog") == 0) - { - const char *name = strVal(lsecond(type_name->names)); - if (strcmp(name, "bpchar") == 0) - { - appendStringInfoString(str, "char"); - } - else if (strcmp(name, "varchar") == 0) - { - appendStringInfoString(str, "varchar"); - } - else if (strcmp(name, "numeric") == 0) - { - appendStringInfoString(str, "numeric"); - } - else if (strcmp(name, "bool") == 0) - { - appendStringInfoString(str, "boolean"); - } - else if (strcmp(name, "int2") == 0) - { - appendStringInfoString(str, "smallint"); - } - else if (strcmp(name, "int4") == 0) - { - appendStringInfoString(str, "int"); - } - else if (strcmp(name, "int8") == 0) - { - appendStringInfoString(str, "bigint"); - } - else if (strcmp(name, "real") == 0 || strcmp(name, "float4") == 0) - { - appendStringInfoString(str, "real"); - } - else if (strcmp(name, "float8") == 0) - { - appendStringInfoString(str, "double precision"); - } - else if (strcmp(name, "time") == 0) - { - appendStringInfoString(str, "time"); - } - else if (strcmp(name, "timetz") == 0) - { - appendStringInfoString(str, "time "); - if (list_length(type_name->typmods) > 0) - { - appendStringInfoChar(str, '('); - foreach(lc, type_name->typmods) - { - deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); - if (lnext(type_name->typmods, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoString(str, ") "); - } - appendStringInfoString(str, "with time zone"); - skip_typmods = true; - } - else if (strcmp(name, "timestamp") == 0) - { - appendStringInfoString(str, "timestamp"); - } - else if (strcmp(name, "timestamptz") == 0) - { - appendStringInfoString(str, "timestamp "); - if (list_length(type_name->typmods) > 0) - { - appendStringInfoChar(str, '('); - foreach(lc, type_name->typmods) - { - deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); - if (lnext(type_name->typmods, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoString(str, ") "); - } - appendStringInfoString(str, "with time zone"); - skip_typmods = true; - } - else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) == 0) - { - appendStringInfoString(str, "interval"); - } - else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) >= 1) - { - appendStringInfoString(str, "interval"); - deparseIntervalTypmods(str, type_name); - - skip_typmods = true; - } - else - { - appendStringInfoString(str, "pg_catalog."); - appendStringInfoString(str, name); - } - } - else - { - deparseAnyName(str, type_name->names); - } - - if (list_length(type_name->typmods) > 0 && !skip_typmods) - { - appendStringInfoChar(str, '('); - foreach(lc, type_name->typmods) - { - if (IsA(lfirst(lc), A_Const)) - deparseAConst(str, lfirst(lc)); - else if (IsA(lfirst(lc), ParamRef)) - deparseParamRef(str, lfirst(lc)); - else if (IsA(lfirst(lc), ColumnRef)) - deparseColumnRef(str, lfirst(lc)); - else - Assert(false); - - if (lnext(type_name->typmods, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); - } - - foreach(lc, type_name->arrayBounds) - { - appendStringInfoChar(str, '['); - if (IsA(lfirst(lc), Integer) && intVal(lfirst(lc)) != -1) - deparseSignedIconst(str, lfirst(lc)); - appendStringInfoChar(str, ']'); - } - - if (type_name->pct_type) - appendStringInfoString(str, "%type"); -} - -// Handle typemods for Interval types separately -// so that they can be applied appropriately for different contexts. -// For example, when using `SET` a query like `INTERVAL 'x' hour TO minute` -// the `INTERVAL` keyword is specified first. -// In all other contexts, intervals use the `'x'::interval` style. -static void deparseIntervalTypmods(StringInfo str, TypeName *type_name) -{ - const char *name = strVal(lsecond(type_name->names)); - Assert(strcmp(name, "interval") == 0); - Assert(list_length(type_name->typmods) >= 1); - Assert(IsA(linitial(type_name->typmods), A_Const)); - Assert(IsA(&castNode(A_Const, linitial(type_name->typmods))->val, Integer)); - - int fields = intVal(&castNode(A_Const, linitial(type_name->typmods))->val); - - // This logic is based on intervaltypmodout in timestamp.c - switch (fields) - { - case INTERVAL_MASK(YEAR): - appendStringInfoString(str, " year"); - break; - case INTERVAL_MASK(MONTH): - appendStringInfoString(str, " month"); - break; - case INTERVAL_MASK(DAY): - appendStringInfoString(str, " day"); - break; - case INTERVAL_MASK(HOUR): - appendStringInfoString(str, " hour"); - break; - case INTERVAL_MASK(MINUTE): - appendStringInfoString(str, " minute"); - break; - case INTERVAL_MASK(SECOND): - appendStringInfoString(str, " second"); - break; - case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): - appendStringInfoString(str, " year to month"); - break; - case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): - appendStringInfoString(str, " day to hour"); - break; - case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): - appendStringInfoString(str, " day to minute"); - break; - case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): - appendStringInfoString(str, " day to second"); - break; - case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): - appendStringInfoString(str, " hour to minute"); - break; - case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): - appendStringInfoString(str, " hour to second"); - break; - case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): - appendStringInfoString(str, " minute to second"); - break; - case INTERVAL_FULL_RANGE: - // Nothing - break; - default: - Assert(false); - break; - } - - if (list_length(type_name->typmods) == 2) - { - int precision = intVal(&castNode(A_Const, lsecond(type_name->typmods))->val); - if (precision != INTERVAL_FULL_PRECISION) - appendStringInfo(str, "(%d)", precision); - } -} - -static void deparseNullTest(StringInfo str, NullTest *null_test) -{ - // argisrow is always false in raw parser output - Assert(null_test->argisrow == false); - - deparseExpr(str, (Node *) null_test->arg); - switch (null_test->nulltesttype) - { - case IS_NULL: - appendStringInfoString(str, " IS NULL"); - break; - case IS_NOT_NULL: - appendStringInfoString(str, " IS NOT NULL"); - break; - } -} - -static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr) -{ - ListCell *lc; - - appendStringInfoString(str, "CASE "); - - if (case_expr->arg != NULL) - { - deparseExpr(str, (Node *) case_expr->arg); - appendStringInfoChar(str, ' '); - } - - foreach(lc, case_expr->args) - { - deparseCaseWhen(str, castNode(CaseWhen, lfirst(lc))); - appendStringInfoChar(str, ' '); - } - - if (case_expr->defresult != NULL) - { - appendStringInfoString(str, "ELSE "); - deparseExpr(str, (Node *) case_expr->defresult); - appendStringInfoChar(str, ' '); - } - - appendStringInfoString(str, "END"); -} - -static void deparseCaseWhen(StringInfo str, CaseWhen *case_when) -{ - appendStringInfoString(str, "WHEN "); - deparseExpr(str, (Node *) case_when->expr); - appendStringInfoString(str, " THEN "); - deparseExpr(str, (Node *) case_when->result); -} - -static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection) -{ - ListCell *lc; - bool need_parens = - IsA(a_indirection->arg, A_Indirection) || - IsA(a_indirection->arg, FuncCall) || - IsA(a_indirection->arg, A_Expr) || - IsA(a_indirection->arg, TypeCast) || - IsA(a_indirection->arg, RowExpr) || - (IsA(a_indirection->arg, ColumnRef) && !IsA(linitial(a_indirection->indirection), A_Indices)); - - if (need_parens) - appendStringInfoChar(str, '('); - - deparseExpr(str, a_indirection->arg); - - if (need_parens) - appendStringInfoChar(str, ')'); - - deparseOptIndirection(str, a_indirection->indirection, 0); -} - -static void deparseAIndices(StringInfo str, A_Indices *a_indices) -{ - appendStringInfoChar(str, '['); - if (a_indices->lidx != NULL) - deparseExpr(str, a_indices->lidx); - if (a_indices->is_slice) - appendStringInfoChar(str, ':'); - if (a_indices->uidx != NULL) - deparseExpr(str, a_indices->uidx); - appendStringInfoChar(str, ']'); -} - -static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr) -{ - appendStringInfoString(str, "COALESCE("); - deparseExprList(str, coalesce_expr->args); - appendStringInfoChar(str, ')'); -} - -static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr) -{ - switch (min_max_expr->op) - { - case IS_GREATEST: - appendStringInfoString(str, "GREATEST("); - break; - case IS_LEAST: - appendStringInfoString(str, "LEAST("); - break; - } - deparseExprList(str, min_max_expr->args); - appendStringInfoChar(str, ')'); -} - -static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test) -{ - deparseExpr(str, (Node *) boolean_test->arg); - switch (boolean_test->booltesttype) - { - case IS_TRUE: - appendStringInfoString(str, " IS TRUE"); - break; - case IS_NOT_TRUE: - appendStringInfoString(str, " IS NOT TRUE"); - break; - case IS_FALSE: - appendStringInfoString(str, " IS FALSE"); - break; - case IS_NOT_FALSE: - appendStringInfoString(str, " IS NOT FALSE"); - break; - case IS_UNKNOWN: - appendStringInfoString(str, " IS UNKNOWN"); - break; - case IS_NOT_UNKNOWN: - appendStringInfoString(str, " IS NOT UNKNOWN"); - break; - default: - Assert(false); - } -} - -static void deparseColumnDef(StringInfo str, ColumnDef *column_def) -{ - ListCell *lc; - - if (column_def->colname != NULL) - { - appendStringInfoString(str, quote_identifier(column_def->colname)); - appendStringInfoChar(str, ' '); - } - - if (column_def->typeName != NULL) - { - deparseTypeName(str, column_def->typeName); - appendStringInfoChar(str, ' '); - } - - if (column_def->raw_default != NULL) - { - appendStringInfoString(str, "USING "); - deparseExpr(str, column_def->raw_default); - appendStringInfoChar(str, ' '); - } - - if (column_def->fdwoptions != NULL) - { - deparseCreateGenericOptions(str, column_def->fdwoptions); - appendStringInfoChar(str, ' '); - } - - foreach(lc, column_def->constraints) - { - deparseConstraint(str, castNode(Constraint, lfirst(lc))); - appendStringInfoChar(str, ' '); - } - - if (column_def->collClause != NULL) - { - deparseCollateClause(str, column_def->collClause); - } - - removeTrailingSpace(str); -} - -static void deparseInsertOverride(StringInfo str, OverridingKind override) -{ - switch (override) - { - case OVERRIDING_NOT_SET: - // Do nothing - break; - case OVERRIDING_USER_VALUE: - appendStringInfoString(str, "OVERRIDING USER VALUE "); - break; - case OVERRIDING_SYSTEM_VALUE: - appendStringInfoString(str, "OVERRIDING SYSTEM VALUE "); - break; - } -} - -static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt) -{ - ListCell *lc; - ListCell *lc2; - - if (insert_stmt->withClause != NULL) - { - deparseWithClause(str, insert_stmt->withClause); - appendStringInfoChar(str, ' '); - } - - appendStringInfoString(str, "INSERT INTO "); - deparseRangeVar(str, insert_stmt->relation, DEPARSE_NODE_CONTEXT_INSERT_RELATION); - appendStringInfoChar(str, ' '); - - if (list_length(insert_stmt->cols) > 0) - { - appendStringInfoChar(str, '('); - deparseInsertColumnList(str, insert_stmt->cols); - appendStringInfoString(str, ") "); - } - - deparseInsertOverride(str, insert_stmt->override); - - if (insert_stmt->selectStmt != NULL) - { - deparseSelectStmt(str, castNode(SelectStmt, insert_stmt->selectStmt)); - appendStringInfoChar(str, ' '); - } - else - { - appendStringInfoString(str, "DEFAULT VALUES "); - } - - if (insert_stmt->onConflictClause != NULL) - { - deparseOnConflictClause(str, insert_stmt->onConflictClause); - appendStringInfoChar(str, ' '); - } - - if (list_length(insert_stmt->returningList) > 0) - { - appendStringInfoString(str, "RETURNING "); - deparseTargetList(str, insert_stmt->returningList); - } - - removeTrailingSpace(str); -} - -static void deparseInferClause(StringInfo str, InferClause *infer_clause) -{ - ListCell *lc; - - if (list_length(infer_clause->indexElems) > 0) - { - appendStringInfoChar(str, '('); - foreach(lc, infer_clause->indexElems) - { - deparseIndexElem(str, lfirst(lc)); - if (lnext(infer_clause->indexElems, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoString(str, ") "); - } - - if (infer_clause->conname != NULL) - { - appendStringInfoString(str, "ON CONSTRAINT "); - appendStringInfoString(str, quote_identifier(infer_clause->conname)); - appendStringInfoChar(str, ' '); - } - - deparseWhereClause(str, infer_clause->whereClause); - - removeTrailingSpace(str); -} - -static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause) -{ - ListCell *lc; - - appendStringInfoString(str, "ON CONFLICT "); - - if (on_conflict_clause->infer != NULL) - { - deparseInferClause(str, on_conflict_clause->infer); - appendStringInfoChar(str, ' '); - } - - switch (on_conflict_clause->action) - { - case ONCONFLICT_NONE: - Assert(false); - break; - case ONCONFLICT_NOTHING: - appendStringInfoString(str, "DO NOTHING "); - break; - case ONCONFLICT_UPDATE: - appendStringInfoString(str, "DO UPDATE "); - break; - } - - if (list_length(on_conflict_clause->targetList) > 0) - { - appendStringInfoString(str, "SET "); - deparseSetClauseList(str, on_conflict_clause->targetList); - appendStringInfoChar(str, ' '); - } - - deparseWhereClause(str, on_conflict_clause->whereClause); - - removeTrailingSpace(str); -} - -static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt) -{ - ListCell* lc; - ListCell* lc2; - ListCell* lc3; - - if (update_stmt->withClause != NULL) - { - deparseWithClause(str, update_stmt->withClause); - appendStringInfoChar(str, ' '); - } - - appendStringInfoString(str, "UPDATE "); - deparseRangeVar(str, update_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - if (list_length(update_stmt->targetList) > 0) - { - appendStringInfoString(str, "SET "); - deparseSetClauseList(str, update_stmt->targetList); - appendStringInfoChar(str, ' '); - } - - deparseFromClause(str, update_stmt->fromClause); - deparseWhereClause(str, update_stmt->whereClause); - - if (list_length(update_stmt->returningList) > 0) - { - appendStringInfoString(str, "RETURNING "); - deparseTargetList(str, update_stmt->returningList); - } - - removeTrailingSpace(str); -} - -static void deparseMergeStmt(StringInfo str, MergeStmt *merge_stmt) -{ - if (merge_stmt->withClause != NULL) - { - deparseWithClause(str, merge_stmt->withClause); - appendStringInfoChar(str, ' '); - } - - appendStringInfoString(str, "MERGE INTO "); - deparseRangeVar(str, merge_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "USING "); - deparseTableRef(str, merge_stmt->sourceRelation); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "ON "); - deparseExpr(str, merge_stmt->joinCondition); - appendStringInfoChar(str, ' '); - - ListCell *lc, *lc2; - foreach (lc, merge_stmt->mergeWhenClauses) - { - MergeWhenClause *clause = castNode(MergeWhenClause, lfirst(lc)); - - appendStringInfoString(str, "WHEN "); - - if (!clause->matched) - { - appendStringInfoString(str, "NOT "); - } - - appendStringInfoString(str, "MATCHED "); - - if (clause->condition) - { - appendStringInfoString(str, "AND "); - deparseExpr(str, clause->condition); - appendStringInfoChar(str, ' '); - } - - appendStringInfoString(str, "THEN "); - - switch (clause->commandType) { - case CMD_INSERT: - appendStringInfoString(str, "INSERT "); - - if (clause->targetList) { - appendStringInfoChar(str, '('); - deparseInsertColumnList(str, clause->targetList); - appendStringInfoString(str, ") "); - } - - deparseInsertOverride(str, clause->override); - - if (clause->values) { - appendStringInfoString(str, "VALUES ("); - deparseExprList(str, clause->values); - appendStringInfoString(str, ")"); - } else { - appendStringInfoString(str, "DEFAULT VALUES "); - } - - break; - case CMD_UPDATE: - appendStringInfoString(str, "UPDATE SET "); - deparseSetClauseList(str, clause->targetList); - break; - case CMD_DELETE: - appendStringInfoString(str, "DELETE"); - break; - case CMD_NOTHING: - appendStringInfoString(str, "DO NOTHING"); - break; - default: - elog(ERROR, "deparse: unpermitted command type in merge statement: %d", clause->commandType); - break; - } - - if (lfirst(lc) != llast(merge_stmt->mergeWhenClauses)) - appendStringInfoChar(str, ' '); - } -} - -static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt) -{ - if (delete_stmt->withClause != NULL) - { - deparseWithClause(str, delete_stmt->withClause); - appendStringInfoChar(str, ' '); - } - - appendStringInfoString(str, "DELETE FROM "); - deparseRangeVar(str, delete_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - if (delete_stmt->usingClause != NULL) - { - appendStringInfoString(str, "USING "); - deparseFromList(str, delete_stmt->usingClause); - appendStringInfoChar(str, ' '); - } - - deparseWhereClause(str, delete_stmt->whereClause); - - if (list_length(delete_stmt->returningList) > 0) - { - appendStringInfoString(str, "RETURNING "); - deparseTargetList(str, delete_stmt->returningList); - } - - removeTrailingSpace(str); -} - -static void deparseLockingClause(StringInfo str, LockingClause *locking_clause) -{ - ListCell *lc; - - switch (locking_clause->strength) - { - case LCS_NONE: - /* no such clause - only used in PlanRowMark */ - Assert(false); - break; - case LCS_FORKEYSHARE: - appendStringInfoString(str, "FOR KEY SHARE "); - break; - case LCS_FORSHARE: - appendStringInfoString(str, "FOR SHARE "); - break; - case LCS_FORNOKEYUPDATE: - appendStringInfoString(str, "FOR NO KEY UPDATE "); - break; - case LCS_FORUPDATE: - appendStringInfoString(str, "FOR UPDATE "); - break; - } - - if (list_length(locking_clause->lockedRels) > 0) - { - appendStringInfoString(str, "OF "); - deparseQualifiedNameList(str, locking_clause->lockedRels); - } - - switch (locking_clause->waitPolicy) - { - case LockWaitError: - appendStringInfoString(str, "NOWAIT"); - break; - case LockWaitSkip: - appendStringInfoString(str, "SKIP LOCKED"); - break; - case LockWaitBlock: - // Default - break; - } - - removeTrailingSpace(str); -} - -static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default) -{ - appendStringInfoString(str, "DEFAULT"); -} - -static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt) -{ - ListCell *lc; - ListCell *lc2; - - appendStringInfoString(str, "CREATE CAST ("); - deparseTypeName(str, create_cast_stmt->sourcetype); - appendStringInfoString(str, " AS "); - deparseTypeName(str, create_cast_stmt->targettype); - appendStringInfoString(str, ") "); - - if (create_cast_stmt->func != NULL) - { - appendStringInfoString(str, "WITH FUNCTION "); - deparseFunctionWithArgtypes(str, create_cast_stmt->func); - appendStringInfoChar(str, ' '); - } - else if (create_cast_stmt->inout) - { - appendStringInfoString(str, "WITH INOUT "); - } - else - { - appendStringInfoString(str, "WITHOUT FUNCTION "); - } - - switch (create_cast_stmt->context) - { - case COERCION_IMPLICIT: - appendStringInfoString(str, "AS IMPLICIT"); - break; - case COERCION_ASSIGNMENT: - appendStringInfoString(str, "AS ASSIGNMENT"); - break; - case COERCION_PLPGSQL: - // Not present in raw parser output - Assert(false); - break; - case COERCION_EXPLICIT: - // Default - break; - } -} - -static void deparseCreateOpClassStmt(StringInfo str, CreateOpClassStmt *create_op_class_stmt) -{ - ListCell *lc = NULL; - - appendStringInfoString(str, "CREATE OPERATOR CLASS "); - - deparseAnyName(str, create_op_class_stmt->opclassname); - appendStringInfoChar(str, ' '); - - if (create_op_class_stmt->isDefault) - appendStringInfoString(str, "DEFAULT "); - - appendStringInfoString(str, "FOR TYPE "); - deparseTypeName(str, create_op_class_stmt->datatype); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(create_op_class_stmt->amname)); - appendStringInfoChar(str, ' '); - - if (create_op_class_stmt->opfamilyname != NULL) - { - appendStringInfoString(str, "FAMILY "); - deparseAnyName(str, create_op_class_stmt->opfamilyname); - appendStringInfoChar(str, ' '); - } - - appendStringInfoString(str, "AS "); - deparseOpclassItemList(str, create_op_class_stmt->items); -} - -static void deparseCreateOpFamilyStmt(StringInfo str, CreateOpFamilyStmt *create_op_family_stmt) -{ - appendStringInfoString(str, "CREATE OPERATOR FAMILY "); - - deparseAnyName(str, create_op_family_stmt->opfamilyname); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(create_op_family_stmt->amname)); -} - -static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item) -{ - ListCell *lc = NULL; - - switch (create_op_class_item->itemtype) - { - case OPCLASS_ITEM_OPERATOR: - appendStringInfoString(str, "OPERATOR "); - appendStringInfo(str, "%d ", create_op_class_item->number); - - if (create_op_class_item->name != NULL) - { - if (create_op_class_item->name->objargs != NULL) - deparseOperatorWithArgtypes(str, create_op_class_item->name); - else - deparseAnyOperator(str, create_op_class_item->name->objname); - appendStringInfoChar(str, ' '); - } - - if (create_op_class_item->order_family != NULL) - { - appendStringInfoString(str, "FOR ORDER BY "); - deparseAnyName(str, create_op_class_item->order_family); - } - - if (create_op_class_item->class_args != NULL) - { - appendStringInfoChar(str, '('); - deparseTypeList(str, create_op_class_item->class_args); - appendStringInfoChar(str, ')'); - } - removeTrailingSpace(str); - break; - case OPCLASS_ITEM_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - appendStringInfo(str, "%d ", create_op_class_item->number); - if (create_op_class_item->class_args != NULL) - { - appendStringInfoChar(str, '('); - deparseTypeList(str, create_op_class_item->class_args); - appendStringInfoString(str, ") "); - } - if (create_op_class_item->name != NULL) - deparseFunctionWithArgtypes(str, create_op_class_item->name); - removeTrailingSpace(str); - break; - case OPCLASS_ITEM_STORAGETYPE: - appendStringInfoString(str, "STORAGE "); - deparseTypeName(str, create_op_class_item->storedtype); - break; - default: - Assert(false); - } -} - -static void deparseTableLikeClause(StringInfo str, TableLikeClause *table_like_clause) -{ - appendStringInfoString(str, "LIKE "); - deparseRangeVar(str, table_like_clause->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - if (table_like_clause->options == CREATE_TABLE_LIKE_ALL) - appendStringInfoString(str, "INCLUDING ALL "); - else - { - if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) - appendStringInfoString(str, "INCLUDING COMMENTS "); - if (table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) - appendStringInfoString(str, "INCLUDING CONSTRAINTS "); - if (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS) - appendStringInfoString(str, "INCLUDING DEFAULTS "); - if (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY) - appendStringInfoString(str, "INCLUDING IDENTITY "); - if (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) - appendStringInfoString(str, "INCLUDING GENERATED "); - if (table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) - appendStringInfoString(str, "INCLUDING INDEXES "); - if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) - appendStringInfoString(str, "INCLUDING STATISTICS "); - if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) - appendStringInfoString(str, "INCLUDING STORAGE "); - } - removeTrailingSpace(str); -} - -static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt) -{ - ListCell *lc; - - Assert(create_domain_stmt->typeName != NULL); - - appendStringInfoString(str, "CREATE DOMAIN "); - deparseAnyName(str, create_domain_stmt->domainname); - appendStringInfoString(str, " AS "); - - deparseTypeName(str, create_domain_stmt->typeName); - appendStringInfoChar(str, ' '); - - if (create_domain_stmt->collClause != NULL) - { - deparseCollateClause(str, create_domain_stmt->collClause); - appendStringInfoChar(str, ' '); - } - - foreach(lc, create_domain_stmt->constraints) - { - deparseConstraint(str, castNode(Constraint, lfirst(lc))); - appendStringInfoChar(str, ' '); - } - - removeTrailingSpace(str); -} - -static void deparseCreateExtensionStmt(StringInfo str, CreateExtensionStmt *create_extension_stmt) -{ - ListCell *lc = NULL; - - appendStringInfoString(str, "CREATE EXTENSION "); - - if (create_extension_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); - - deparseColId(str, create_extension_stmt->extname); - appendStringInfoChar(str, ' '); - - foreach (lc, create_extension_stmt->options) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - - if (strcmp(def_elem->defname, "schema") == 0) - { - appendStringInfoString(str, "SCHEMA "); - deparseColId(str, strVal(def_elem->arg)); - } - else if (strcmp(def_elem->defname, "new_version") == 0) - { - appendStringInfoString(str, "VERSION "); - deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); - } - else if (strcmp(def_elem->defname, "cascade") == 0) - { - appendStringInfoString(str, "CASCADE"); - } - else - { - Assert(false); - } - - appendStringInfoChar(str, ' '); - } - - removeTrailingSpace(str); -} - -static void deparseConstraint(StringInfo str, Constraint *constraint) -{ - ListCell *lc; - - if (constraint->conname != NULL) - { - appendStringInfoString(str, "CONSTRAINT "); - appendStringInfoString(str, constraint->conname); - appendStringInfoChar(str, ' '); - } - - switch (constraint->contype) { - case CONSTR_NULL: - appendStringInfoString(str, "NULL "); - break; - case CONSTR_NOTNULL: - appendStringInfoString(str, "NOT NULL "); - break; - case CONSTR_DEFAULT: - appendStringInfoString(str, "DEFAULT "); - deparseExpr(str, constraint->raw_expr); - break; - case CONSTR_IDENTITY: - appendStringInfoString(str, "GENERATED "); - switch (constraint->generated_when) - { - case ATTRIBUTE_IDENTITY_ALWAYS: - appendStringInfoString(str, "ALWAYS "); - break; - case ATTRIBUTE_IDENTITY_BY_DEFAULT: - appendStringInfoString(str, "BY DEFAULT "); - break; - default: - Assert(false); - } - appendStringInfoString(str, "AS IDENTITY "); - deparseOptParenthesizedSeqOptList(str, constraint->options); - break; - case CONSTR_GENERATED: - Assert(constraint->generated_when == ATTRIBUTE_IDENTITY_ALWAYS); - appendStringInfoString(str, "GENERATED ALWAYS AS ("); - deparseExpr(str, constraint->raw_expr); - appendStringInfoString(str, ") STORED "); - break; - case CONSTR_CHECK: - appendStringInfoString(str, "CHECK ("); - deparseExpr(str, constraint->raw_expr); - appendStringInfoString(str, ") "); - break; - case CONSTR_PRIMARY: - appendStringInfoString(str, "PRIMARY KEY "); - break; - case CONSTR_UNIQUE: - appendStringInfoString(str, "UNIQUE "); - break; - case CONSTR_EXCLUSION: - appendStringInfoString(str, "EXCLUDE "); - if (strcmp(constraint->access_method, DEFAULT_INDEX_TYPE) != 0) - { - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(constraint->access_method)); - appendStringInfoChar(str, ' '); - } - appendStringInfoChar(str, '('); - foreach(lc, constraint->exclusions) - { - List *exclusion = castNode(List, lfirst(lc)); - Assert(list_length(exclusion) == 2); - deparseIndexElem(str, castNode(IndexElem, linitial(exclusion))); - appendStringInfoString(str, " WITH "); - deparseAnyOperator(str, castNode(List, lsecond(exclusion))); - if (lnext(constraint->exclusions, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoString(str, ") "); - if (constraint->where_clause != NULL) - { - appendStringInfoString(str, "WHERE ("); - deparseExpr(str, constraint->where_clause); - appendStringInfoString(str, ") "); - } - break; - case CONSTR_FOREIGN: - if (list_length(constraint->fk_attrs) > 0) - appendStringInfoString(str, "FOREIGN KEY "); - break; - case CONSTR_ATTR_DEFERRABLE: - appendStringInfoString(str, "DEFERRABLE "); - break; - case CONSTR_ATTR_NOT_DEFERRABLE: - appendStringInfoString(str, "NOT DEFERRABLE "); - break; - case CONSTR_ATTR_DEFERRED: - appendStringInfoString(str, "INITIALLY DEFERRED "); - break; - case CONSTR_ATTR_IMMEDIATE: - appendStringInfoString(str, "INITIALLY IMMEDIATE "); - break; - } - - if (list_length(constraint->keys) > 0) - { - appendStringInfoChar(str, '('); - deparseColumnList(str, constraint->keys); - appendStringInfoString(str, ") "); - } - - if (list_length(constraint->fk_attrs) > 0) - { - appendStringInfoChar(str, '('); - deparseColumnList(str, constraint->fk_attrs); - appendStringInfoString(str, ") "); - } - - if (constraint->pktable != NULL) - { - appendStringInfoString(str, "REFERENCES "); - deparseRangeVar(str, constraint->pktable, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - if (list_length(constraint->pk_attrs) > 0) - { - appendStringInfoChar(str, '('); - deparseColumnList(str, constraint->pk_attrs); - appendStringInfoString(str, ") "); - } - } - - switch (constraint->fk_matchtype) - { - case FKCONSTR_MATCH_SIMPLE: - // Default - break; - case FKCONSTR_MATCH_FULL: - appendStringInfoString(str, "MATCH FULL "); - break; - case FKCONSTR_MATCH_PARTIAL: - // Not implemented in Postgres - Assert(false); - break; - default: - // Not specified - break; - } - - switch (constraint->fk_upd_action) - { - case FKCONSTR_ACTION_NOACTION: - // Default - break; - case FKCONSTR_ACTION_RESTRICT: - appendStringInfoString(str, "ON UPDATE RESTRICT "); - break; - case FKCONSTR_ACTION_CASCADE: - appendStringInfoString(str, "ON UPDATE CASCADE "); - break; - case FKCONSTR_ACTION_SETNULL: - appendStringInfoString(str, "ON UPDATE SET NULL "); - break; - case FKCONSTR_ACTION_SETDEFAULT: - appendStringInfoString(str, "ON UPDATE SET DEFAULT "); - break; - default: - // Not specified - break; - } - - switch (constraint->fk_del_action) - { - case FKCONSTR_ACTION_NOACTION: - // Default - break; - case FKCONSTR_ACTION_RESTRICT: - appendStringInfoString(str, "ON DELETE RESTRICT "); - break; - case FKCONSTR_ACTION_CASCADE: - appendStringInfoString(str, "ON DELETE CASCADE "); - break; - case FKCONSTR_ACTION_SETNULL: - case FKCONSTR_ACTION_SETDEFAULT: - appendStringInfoString(str, "ON DELETE SET "); - - switch (constraint->fk_del_action) { - case FKCONSTR_ACTION_SETDEFAULT: appendStringInfoString(str, "DEFAULT "); break; - case FKCONSTR_ACTION_SETNULL: appendStringInfoString(str, "NULL "); break; - } - - if (constraint->fk_del_set_cols) { - appendStringInfoString(str, "("); - ListCell *lc; - foreach (lc, constraint->fk_del_set_cols) { - appendStringInfoString(str, strVal(lfirst(lc))); - if (lfirst(lc) != llast(constraint->fk_del_set_cols)) - appendStringInfoString(str, ", "); - } - appendStringInfoString(str, ")"); - } - break; - default: - // Not specified - break; - } - - if (list_length(constraint->including) > 0) - { - appendStringInfoString(str, "INCLUDE ("); - deparseColumnList(str, constraint->including); - appendStringInfoString(str, ") "); - } - - if (constraint->indexname != NULL) - appendStringInfo(str, "USING INDEX %s ", quote_identifier(constraint->indexname)); - - if (constraint->indexspace != NULL) - appendStringInfo(str, "USING INDEX TABLESPACE %s ", quote_identifier(constraint->indexspace)); - - if (constraint->deferrable) - appendStringInfoString(str, "DEFERRABLE "); - - if (constraint->initdeferred) - appendStringInfoString(str, "INITIALLY DEFERRED "); - - if (constraint->is_no_inherit) - appendStringInfoString(str, "NO INHERIT "); - - if (constraint->skip_validation) - appendStringInfoString(str, "NOT VALID "); - - removeTrailingSpace(str); -} - -static void deparseReturnStmt(StringInfo str, ReturnStmt *return_stmt) -{ - appendStringInfoString(str, "RETURN "); - deparseExpr(str, return_stmt->returnval); -} - -static void deparseCreateFunctionStmt(StringInfo str, CreateFunctionStmt *create_function_stmt) -{ - ListCell *lc; - bool tableFunc = false; - - appendStringInfoString(str, "CREATE "); - if (create_function_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); - if (create_function_stmt->is_procedure) - appendStringInfoString(str, "PROCEDURE "); - else - appendStringInfoString(str, "FUNCTION "); - - deparseFuncName(str, create_function_stmt->funcname); - - appendStringInfoChar(str, '('); - foreach(lc, create_function_stmt->parameters) - { - FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); - if (function_parameter->mode != FUNC_PARAM_TABLE) - { - deparseFunctionParameter(str, function_parameter); - if (lnext(create_function_stmt->parameters, lc) && castNode(FunctionParameter, lfirst(lnext(create_function_stmt->parameters, lc)))->mode != FUNC_PARAM_TABLE) - appendStringInfoString(str, ", "); - } - else - { - tableFunc = true; - } - } - appendStringInfoString(str, ") "); - - if (tableFunc) - { - appendStringInfoString(str, "RETURNS TABLE ("); - foreach(lc, create_function_stmt->parameters) - { - FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); - if (function_parameter->mode == FUNC_PARAM_TABLE) - { - deparseFunctionParameter(str, function_parameter); - if (lnext(create_function_stmt->parameters, lc)) - appendStringInfoString(str, ", "); - } - } - appendStringInfoString(str, ") "); - } - else if (create_function_stmt->returnType != NULL) - { - appendStringInfoString(str, "RETURNS "); - deparseTypeName(str, create_function_stmt->returnType); - appendStringInfoChar(str, ' '); - } - - foreach(lc, create_function_stmt->options) - { - deparseCreateFuncOptItem(str, castNode(DefElem, lfirst(lc))); - appendStringInfoChar(str, ' '); - } - - if (create_function_stmt->sql_body) - { - /* RETURN or BEGIN ... END - */ - if (IsA(create_function_stmt->sql_body, ReturnStmt)) - deparseReturnStmt(str, castNode(ReturnStmt, create_function_stmt->sql_body)); - else - { - appendStringInfoString(str, "BEGIN ATOMIC "); - deparseExprList(str, castNode(List, create_function_stmt->sql_body)); - appendStringInfoString(str, "END "); - } - } - - removeTrailingSpace(str); -} - -static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter) -{ - switch (function_parameter->mode) - { - case FUNC_PARAM_IN: /* input only */ - appendStringInfoString(str, "IN "); - break; - case FUNC_PARAM_OUT: /* output only */ - appendStringInfoString(str, "OUT "); - break; - case FUNC_PARAM_INOUT: /* both */ - appendStringInfoString(str, "INOUT "); - break; - case FUNC_PARAM_VARIADIC: /* variadic (always input) */ - appendStringInfoString(str, "VARIADIC "); - break; - case FUNC_PARAM_TABLE: /* table function output column */ - // No special annotation, the caller is expected to correctly put - // this into the RETURNS part of the CREATE FUNCTION statement - break; - case FUNC_PARAM_DEFAULT: - // Default - break; - default: - Assert(false); - break; - } - - if (function_parameter->name != NULL) - { - appendStringInfoString(str, function_parameter->name); - appendStringInfoChar(str, ' '); - } - - deparseTypeName(str, function_parameter->argType); - appendStringInfoChar(str, ' '); - - if (function_parameter->defexpr != NULL) - { - appendStringInfoString(str, "= "); - deparseExpr(str, function_parameter->defexpr); - } - - removeTrailingSpace(str); -} - -static void deparseCheckPointStmt(StringInfo str, CheckPointStmt *check_point_stmt) -{ - appendStringInfoString(str, "CHECKPOINT"); -} - -static void deparseCreateSchemaStmt(StringInfo str, CreateSchemaStmt *create_schema_stmt) -{ - ListCell *lc; - appendStringInfoString(str, "CREATE SCHEMA "); - - if (create_schema_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); - - if (create_schema_stmt->schemaname) - { - deparseColId(str, create_schema_stmt->schemaname); - appendStringInfoChar(str, ' '); - } - - if (create_schema_stmt->authrole != NULL) - { - appendStringInfoString(str, "AUTHORIZATION "); - deparseRoleSpec(str, create_schema_stmt->authrole); - appendStringInfoChar(str, ' '); - } - - if (create_schema_stmt->schemaElts) - { - foreach(lc, create_schema_stmt->schemaElts) - { - deparseSchemaStmt(str, lfirst(lc)); - if (lnext(create_schema_stmt->schemaElts, lc)) - appendStringInfoChar(str, ' '); - } - } - - removeTrailingSpace(str); -} - -static void deparseAlterRoleSetStmt(StringInfo str, AlterRoleSetStmt *alter_role_set_stmt) -{ - appendStringInfoString(str, "ALTER ROLE "); - - if (alter_role_set_stmt->role == NULL) - appendStringInfoString(str, "ALL"); - else - deparseRoleSpec(str, alter_role_set_stmt->role); - - appendStringInfoChar(str, ' '); - - if (alter_role_set_stmt->database != NULL) - { - appendStringInfoString(str, "IN DATABASE "); - appendStringInfoString(str, quote_identifier(alter_role_set_stmt->database)); - appendStringInfoChar(str, ' '); - } - - deparseVariableSetStmt(str, alter_role_set_stmt->setstmt); -} - -static void deparseCreateConversionStmt(StringInfo str, CreateConversionStmt *create_conversion_stmt) -{ - appendStringInfoString(str, "CREATE "); - if (create_conversion_stmt->def) - appendStringInfoString(str, "DEFAULT "); - - appendStringInfoString(str, "CONVERSION "); - deparseAnyName(str, create_conversion_stmt->conversion_name); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "FOR "); - deparseStringLiteral(str, create_conversion_stmt->for_encoding_name); - appendStringInfoString(str, " TO "); - deparseStringLiteral(str, create_conversion_stmt->to_encoding_name); - - appendStringInfoString(str, "FROM "); - deparseAnyName(str, create_conversion_stmt->func_name); -} - -static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec) -{ - switch (role_spec->roletype) - { - case ROLESPEC_CSTRING: - Assert(role_spec->rolename != NULL); - appendStringInfoString(str, quote_identifier(role_spec->rolename)); - break; - case ROLESPEC_CURRENT_ROLE: - appendStringInfoString(str, "CURRENT_ROLE"); - break; - case ROLESPEC_CURRENT_USER: - appendStringInfoString(str, "CURRENT_USER"); - break; - case ROLESPEC_SESSION_USER: - appendStringInfoString(str, "SESSION_USER"); - break; - case ROLESPEC_PUBLIC: - appendStringInfoString(str, "public"); - break; - } -} - -// "part_elem" in gram.y -static void deparsePartitionElem(StringInfo str, PartitionElem *partition_elem) -{ - ListCell *lc; - - if (partition_elem->name != NULL) - { - deparseColId(str, partition_elem->name); - appendStringInfoChar(str, ' '); - } - else if (partition_elem->expr != NULL) - { - appendStringInfoChar(str, '('); - deparseExpr(str, partition_elem->expr); - appendStringInfoString(str, ") "); - } - - deparseOptCollate(str, partition_elem->collation); - deparseAnyName(str, partition_elem->opclass); - - removeTrailingSpace(str); -} - -static void deparsePartitionSpec(StringInfo str, PartitionSpec *partition_spec) -{ - ListCell *lc; - - appendStringInfoString(str, "PARTITION BY "); - appendStringInfoString(str, partition_spec->strategy); - - appendStringInfoChar(str, '('); - foreach(lc, partition_spec->partParams) - { - deparsePartitionElem(str, castNode(PartitionElem, lfirst(lc))); - if (lnext(partition_spec->partParams, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); -} - -static void deparsePartitionBoundSpec(StringInfo str, PartitionBoundSpec *partition_bound_spec) -{ - ListCell *lc; - - if (partition_bound_spec->is_default) - { - appendStringInfoString(str, "DEFAULT"); - return; - } - - appendStringInfoString(str, "FOR VALUES "); - - switch (partition_bound_spec->strategy) - { - case PARTITION_STRATEGY_HASH: - appendStringInfo(str, "WITH (MODULUS %d, REMAINDER %d)", partition_bound_spec->modulus, partition_bound_spec->remainder); - break; - case PARTITION_STRATEGY_LIST: - appendStringInfoString(str, "IN ("); - deparseExprList(str, partition_bound_spec->listdatums); - appendStringInfoChar(str, ')'); - break; - case PARTITION_STRATEGY_RANGE: - appendStringInfoString(str, "FROM ("); - deparseExprList(str, partition_bound_spec->lowerdatums); - appendStringInfoString(str, ") TO ("); - deparseExprList(str, partition_bound_spec->upperdatums); - appendStringInfoChar(str, ')'); - break; - default: - Assert(false); - break; - } -} - -static void deparsePartitionCmd(StringInfo str, PartitionCmd *partition_cmd) -{ - deparseRangeVar(str, partition_cmd->name, DEPARSE_NODE_CONTEXT_NONE); - - if (partition_cmd->bound != NULL) - { - appendStringInfoChar(str, ' '); - deparsePartitionBoundSpec(str, partition_cmd->bound); - } - if (partition_cmd->concurrent) - appendStringInfoString(str, " CONCURRENTLY "); -} - -// "TableElement" in gram.y -static void deparseTableElement(StringInfo str, Node *node) -{ - switch (nodeTag(node)) - { - case T_ColumnDef: - deparseColumnDef(str, castNode(ColumnDef, node)); - break; - case T_TableLikeClause: - deparseTableLikeClause(str, castNode(TableLikeClause, node)); - break; - case T_Constraint: - deparseConstraint(str, castNode(Constraint, node)); - break; - default: - Assert(false); - } -} - -static void deparseCreateStmt(StringInfo str, CreateStmt *create_stmt, bool is_foreign_table) -{ - ListCell *lc; - - appendStringInfoString(str, "CREATE "); - - if (is_foreign_table) - appendStringInfoString(str, "FOREIGN "); - - deparseOptTemp(str, create_stmt->relation->relpersistence); - - appendStringInfoString(str, "TABLE "); - - if (create_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); - - deparseRangeVar(str, create_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - if (create_stmt->ofTypename != NULL) - { - appendStringInfoString(str, "OF "); - deparseTypeName(str, create_stmt->ofTypename); - appendStringInfoChar(str, ' '); - } - - if (create_stmt->partbound != NULL) - { - Assert(list_length(create_stmt->inhRelations) == 1); - appendStringInfoString(str, "PARTITION OF "); - deparseRangeVar(str, castNode(RangeVar, linitial(create_stmt->inhRelations)), DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - } - - if (list_length(create_stmt->tableElts) > 0) - { - // In raw parse output tableElts contains both columns and constraints - // (and the constraints field is NIL) - appendStringInfoChar(str, '('); - foreach(lc, create_stmt->tableElts) - { - deparseTableElement(str, lfirst(lc)); - if (lnext(create_stmt->tableElts, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoString(str, ") "); - } - else if (create_stmt->partbound == NULL && create_stmt->ofTypename == NULL) - { - appendStringInfoString(str, "() "); - } - - if (create_stmt->partbound != NULL) - { - deparsePartitionBoundSpec(str, create_stmt->partbound); - appendStringInfoChar(str, ' '); - } - else - { - deparseOptInherit(str, create_stmt->inhRelations); - } - - if (create_stmt->partspec != NULL) - { - deparsePartitionSpec(str, create_stmt->partspec); - appendStringInfoChar(str, ' '); - } - - if (create_stmt->accessMethod != NULL) - { - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(create_stmt->accessMethod)); - } - - deparseOptWith(str, create_stmt->options); - - switch (create_stmt->oncommit) - { - case ONCOMMIT_NOOP: - // No ON COMMIT clause - break; - case ONCOMMIT_PRESERVE_ROWS: - appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); - break; - case ONCOMMIT_DELETE_ROWS: - appendStringInfoString(str, "ON COMMIT DELETE ROWS "); - break; - case ONCOMMIT_DROP: - appendStringInfoString(str, "ON COMMIT DROP "); - break; - } - - if (create_stmt->tablespacename != NULL) - { - appendStringInfoString(str, "TABLESPACE "); - appendStringInfoString(str, quote_identifier(create_stmt->tablespacename)); - } - - removeTrailingSpace(str); -} - -static void deparseCreateFdwStmt(StringInfo str, CreateFdwStmt *create_fdw_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "CREATE FOREIGN DATA WRAPPER "); - appendStringInfoString(str, quote_identifier(create_fdw_stmt->fdwname)); - appendStringInfoChar(str, ' '); - - if (list_length(create_fdw_stmt->func_options) > 0) - { - deparseFdwOptions(str, create_fdw_stmt->func_options); - appendStringInfoChar(str, ' '); - } - - deparseCreateGenericOptions(str, create_fdw_stmt->options); - - removeTrailingSpace(str); -} - -static void deparseAlterFdwStmt(StringInfo str, AlterFdwStmt *alter_fdw_stmt) -{ - appendStringInfoString(str, "ALTER FOREIGN DATA WRAPPER "); - appendStringInfoString(str, quote_identifier(alter_fdw_stmt->fdwname)); - appendStringInfoChar(str, ' '); - - if (list_length(alter_fdw_stmt->func_options) > 0) - { - deparseFdwOptions(str, alter_fdw_stmt->func_options); - appendStringInfoChar(str, ' '); - } - - if (list_length(alter_fdw_stmt->options) > 0) - deparseAlterGenericOptions(str, alter_fdw_stmt->options); - - removeTrailingSpace(str); -} - -static void deparseCreateForeignServerStmt(StringInfo str, CreateForeignServerStmt *create_foreign_server_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "CREATE SERVER "); - if (create_foreign_server_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); - appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->servername)); - appendStringInfoChar(str, ' '); - - if (create_foreign_server_stmt->servertype != NULL) - { - appendStringInfoString(str, "TYPE "); - deparseStringLiteral(str, create_foreign_server_stmt->servertype); - appendStringInfoChar(str, ' '); - } - - if (create_foreign_server_stmt->version != NULL) - { - appendStringInfoString(str, "VERSION "); - deparseStringLiteral(str, create_foreign_server_stmt->version); - appendStringInfoChar(str, ' '); - } - - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); - appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->fdwname)); - appendStringInfoChar(str, ' '); - - deparseCreateGenericOptions(str, create_foreign_server_stmt->options); - - removeTrailingSpace(str); -} - -static void deparseAlterForeignServerStmt(StringInfo str, AlterForeignServerStmt *alter_foreign_server_stmt) -{ - appendStringInfoString(str, "ALTER SERVER "); - - appendStringInfoString(str, quote_identifier(alter_foreign_server_stmt->servername)); - appendStringInfoChar(str, ' '); - - if (alter_foreign_server_stmt->has_version) - { - appendStringInfoString(str, "VERSION "); - if (alter_foreign_server_stmt->version != NULL) - deparseStringLiteral(str, alter_foreign_server_stmt->version); - else - appendStringInfoString(str, "NULL"); - appendStringInfoChar(str, ' '); - } - - if (list_length(alter_foreign_server_stmt->options) > 0) - deparseAlterGenericOptions(str, alter_foreign_server_stmt->options); - - removeTrailingSpace(str); -} - -static void deparseCreateUserMappingStmt(StringInfo str, CreateUserMappingStmt *create_user_mapping_stmt) -{ - appendStringInfoString(str, "CREATE USER MAPPING "); - if (create_user_mapping_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); - - appendStringInfoString(str, "FOR "); - deparseRoleSpec(str, create_user_mapping_stmt->user); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "SERVER "); - appendStringInfoString(str, quote_identifier(create_user_mapping_stmt->servername)); - appendStringInfoChar(str, ' '); - - deparseCreateGenericOptions(str, create_user_mapping_stmt->options); - - removeTrailingSpace(str); -} - -static void deparseCreatedbStmt(StringInfo str, CreatedbStmt *createdb_stmt) -{ - appendStringInfoString(str, "CREATE DATABASE "); - deparseColId(str, createdb_stmt->dbname); - appendStringInfoChar(str, ' '); - deparseCreatedbOptList(str, createdb_stmt->options); - removeTrailingSpace(str); -} - -static void deparseAlterUserMappingStmt(StringInfo str, AlterUserMappingStmt *alter_user_mapping_stmt) -{ - appendStringInfoString(str, "ALTER USER MAPPING FOR "); - deparseRoleSpec(str, alter_user_mapping_stmt->user); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "SERVER "); - appendStringInfoString(str, quote_identifier(alter_user_mapping_stmt->servername)); - appendStringInfoChar(str, ' '); - - deparseAlterGenericOptions(str, alter_user_mapping_stmt->options); - - removeTrailingSpace(str); -} - -static void deparseDropUserMappingStmt(StringInfo str, DropUserMappingStmt *drop_user_mapping_stmt) -{ - appendStringInfoString(str, "DROP USER MAPPING "); - - if (drop_user_mapping_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - - appendStringInfoString(str, "FOR "); - deparseRoleSpec(str, drop_user_mapping_stmt->user); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "SERVER "); - appendStringInfoString(str, quote_identifier(drop_user_mapping_stmt->servername)); -} - -static void deparseSecLabelStmt(StringInfo str, SecLabelStmt *sec_label_stmt) -{ - ListCell *lc = NULL; - - appendStringInfoString(str, "SECURITY LABEL "); - - if (sec_label_stmt->provider != NULL) - { - appendStringInfoString(str, "FOR "); - appendStringInfoString(str, quote_identifier(sec_label_stmt->provider)); - appendStringInfoChar(str, ' '); - } - - appendStringInfoString(str, "ON "); - - switch (sec_label_stmt->objtype) - { - case OBJECT_COLUMN: - appendStringInfoString(str, "COLUMN "); - deparseAnyName(str, castNode(List, sec_label_stmt->object)); - break; - case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); - deparseAnyName(str, castNode(List, sec_label_stmt->object)); - break; - case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); - deparseAnyName(str, castNode(List, sec_label_stmt->object)); - break; - case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); - deparseAnyName(str, castNode(List, sec_label_stmt->object)); - break; - case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); - deparseAnyName(str, castNode(List, sec_label_stmt->object)); - break; - case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); - deparseAnyName(str, castNode(List, sec_label_stmt->object)); - break; - case OBJECT_DATABASE: - appendStringInfoString(str, "DATABASE "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); - break; - case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, "EVENT TRIGGER "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); - break; - case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); - break; - case OBJECT_PUBLICATION: - appendStringInfoString(str, "PUBLICATION "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); - break; - case OBJECT_ROLE: - appendStringInfoString(str, "ROLE "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); - break; - case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); - break; - case OBJECT_SUBSCRIPTION: - appendStringInfoString(str, "SUBSCRIPTION "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); - break; - case OBJECT_TABLESPACE: - appendStringInfoString(str, "TABLESPACE "); - appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); - break; - case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); - deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); - break; - case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); - deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); - break; - case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); - break; - case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); - break; - case OBJECT_LARGEOBJECT: - appendStringInfoString(str, "LARGE OBJECT "); - deparseValue(str, (union ValUnion *) sec_label_stmt->object, DEPARSE_NODE_CONTEXT_CONSTANT); - break; - case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); - break; - case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); - break; - default: - // Not supported in the parser - Assert(false); - break; - } - - appendStringInfoString(str, " IS "); - - if (sec_label_stmt->label != NULL) - deparseStringLiteral(str, sec_label_stmt->label); - else - appendStringInfoString(str, "NULL"); -} - -static void deparseCreateForeignTableStmt(StringInfo str, CreateForeignTableStmt *create_foreign_table_stmt) -{ - ListCell *lc; - - deparseCreateStmt(str, &create_foreign_table_stmt->base, true); - - appendStringInfoString(str, " SERVER "); - appendStringInfoString(str, quote_identifier(create_foreign_table_stmt->servername)); - appendStringInfoChar(str, ' '); - - if (list_length(create_foreign_table_stmt->options) > 0) - deparseAlterGenericOptions(str, create_foreign_table_stmt->options); - - removeTrailingSpace(str); -} - -static void deparseImportForeignSchemaStmt(StringInfo str, ImportForeignSchemaStmt *import_foreign_schema_stmt) -{ - appendStringInfoString(str, "IMPORT FOREIGN SCHEMA "); - - appendStringInfoString(str, import_foreign_schema_stmt->remote_schema); - appendStringInfoChar(str, ' '); - - switch (import_foreign_schema_stmt->list_type) - { - case FDW_IMPORT_SCHEMA_ALL: - // Default - break; - case FDW_IMPORT_SCHEMA_LIMIT_TO: - appendStringInfoString(str, "LIMIT TO ("); - deparseRelationExprList(str, import_foreign_schema_stmt->table_list); - appendStringInfoString(str, ") "); - break; - case FDW_IMPORT_SCHEMA_EXCEPT: - appendStringInfoString(str, "EXCEPT ("); - deparseRelationExprList(str, import_foreign_schema_stmt->table_list); - appendStringInfoString(str, ") "); - break; - } - - appendStringInfoString(str, "FROM SERVER "); - appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->server_name)); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "INTO "); - appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->local_schema)); - appendStringInfoChar(str, ' '); - - deparseCreateGenericOptions(str, import_foreign_schema_stmt->options); - - removeTrailingSpace(str); -} - -static void deparseCreateTableAsStmt(StringInfo str, CreateTableAsStmt *create_table_as_stmt) -{ - ListCell *lc; - appendStringInfoString(str, "CREATE "); - - deparseOptTemp(str, create_table_as_stmt->into->rel->relpersistence); - - switch (create_table_as_stmt->objtype) - { - case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); - break; - case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); - break; - default: - // Not supported here - Assert(false); - break; - } - - if (create_table_as_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); - - deparseIntoClause(str, create_table_as_stmt->into); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "AS "); - if (IsA(create_table_as_stmt->query, ExecuteStmt)) - deparseExecuteStmt(str, castNode(ExecuteStmt, create_table_as_stmt->query)); - else - deparseSelectStmt(str, castNode(SelectStmt, create_table_as_stmt->query)); - appendStringInfoChar(str, ' '); - - if (create_table_as_stmt->into->skipData) - appendStringInfoString(str, "WITH NO DATA "); - - removeTrailingSpace(str); -} - -static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "CREATE "); - - if (view_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); - - deparseOptTemp(str, view_stmt->view->relpersistence); - - appendStringInfoString(str, "VIEW "); - deparseRangeVar(str, view_stmt->view, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - if (list_length(view_stmt->aliases) > 0) - { - appendStringInfoChar(str, '('); - deparseColumnList(str, view_stmt->aliases); - appendStringInfoString(str, ") "); - } - - deparseOptWith(str, view_stmt->options); - - appendStringInfoString(str, "AS "); - deparseSelectStmt(str, castNode(SelectStmt, view_stmt->query)); - appendStringInfoChar(str, ' '); - - switch (view_stmt->withCheckOption) - { - case NO_CHECK_OPTION: - // Default - break; - case LOCAL_CHECK_OPTION: - appendStringInfoString(str, "WITH LOCAL CHECK OPTION "); - break; - case CASCADED_CHECK_OPTION: - appendStringInfoString(str, "WITH CHECK OPTION "); - break; - } - - removeTrailingSpace(str); -} - -static void deparseDropStmt(StringInfo str, DropStmt *drop_stmt) -{ - ListCell *lc; - List *l; - - appendStringInfoString(str, "DROP "); - - switch (drop_stmt->removeType) - { - case OBJECT_ACCESS_METHOD: - appendStringInfoString(str, "ACCESS METHOD "); - break; - case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); - break; - case OBJECT_CAST: - appendStringInfoString(str, "CAST "); - break; - case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); - break; - case OBJECT_CONVERSION: - appendStringInfoString(str, "CONVERSION "); - break; - case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); - break; - case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, "EVENT TRIGGER "); - break; - case OBJECT_EXTENSION: - appendStringInfoString(str, "EXTENSION "); - break; - case OBJECT_FDW: - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); - break; - case OBJECT_FOREIGN_SERVER: - appendStringInfoString(str, "SERVER "); - break; - case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); - break; - case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - break; - case OBJECT_INDEX: - appendStringInfoString(str, "INDEX "); - break; - case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); - break; - case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); - break; - case OBJECT_OPCLASS: - appendStringInfoString(str, "OPERATOR CLASS "); - break; - case OBJECT_OPERATOR: - appendStringInfoString(str, "OPERATOR "); - break; - case OBJECT_OPFAMILY: - appendStringInfoString(str, "OPERATOR FAMILY "); - break; - case OBJECT_POLICY: - appendStringInfoString(str, "POLICY "); - break; - case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - break; - case OBJECT_PUBLICATION: - appendStringInfoString(str, "PUBLICATION "); - break; - case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - break; - case OBJECT_RULE: - appendStringInfoString(str, "RULE "); - break; - case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); - break; - case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); - break; - case OBJECT_STATISTIC_EXT: - appendStringInfoString(str, "STATISTICS "); - break; - case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); - break; - case OBJECT_TRANSFORM: - appendStringInfoString(str, "TRANSFORM "); - break; - case OBJECT_TRIGGER: - appendStringInfoString(str, "TRIGGER "); - break; - case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); - break; - case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); - break; - case OBJECT_TSPARSER: - appendStringInfoString(str, "TEXT SEARCH PARSER "); - break; - case OBJECT_TSTEMPLATE: - appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); - break; - case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); - break; - case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); - break; - default: - // Other object types are not supported here in the parser - Assert(false); - } - - if (drop_stmt->concurrent) - appendStringInfoString(str, "CONCURRENTLY "); - - if (drop_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - - switch (drop_stmt->removeType) - { - // drop_type_any_name - case OBJECT_TABLE: - case OBJECT_SEQUENCE: - case OBJECT_VIEW: - case OBJECT_MATVIEW: - case OBJECT_INDEX: - case OBJECT_FOREIGN_TABLE: - case OBJECT_COLLATION: - case OBJECT_CONVERSION: - case OBJECT_STATISTIC_EXT: - case OBJECT_TSPARSER: - case OBJECT_TSDICTIONARY: - case OBJECT_TSTEMPLATE: - case OBJECT_TSCONFIGURATION: - deparseAnyNameList(str, drop_stmt->objects); - appendStringInfoChar(str, ' '); - break; - // drop_type_name - case OBJECT_ACCESS_METHOD: - case OBJECT_EVENT_TRIGGER: - case OBJECT_EXTENSION: - case OBJECT_FDW: - case OBJECT_PUBLICATION: - case OBJECT_SCHEMA: - case OBJECT_FOREIGN_SERVER: - deparseNameList(str, drop_stmt->objects); - appendStringInfoChar(str, ' '); - break; - // drop_type_name_on_any_name - case OBJECT_POLICY: - case OBJECT_RULE: - case OBJECT_TRIGGER: - Assert(list_length(drop_stmt->objects) == 1); - l = linitial(drop_stmt->objects); - deparseColId(str, strVal(llast(l))); - appendStringInfoString(str, " ON "); - deparseAnyNameSkipLast(str, l); - appendStringInfoChar(str, ' '); - break; - case OBJECT_CAST: - Assert(list_length(drop_stmt->objects) == 1); - l = linitial(drop_stmt->objects); - Assert(list_length(l) == 2); - appendStringInfoChar(str, '('); - deparseTypeName(str, castNode(TypeName, linitial(l))); - appendStringInfoString(str, " AS "); - deparseTypeName(str, castNode(TypeName, lsecond(l))); - appendStringInfoChar(str, ')'); - appendStringInfoChar(str, ' '); - break; - case OBJECT_OPFAMILY: - case OBJECT_OPCLASS: - Assert(list_length(drop_stmt->objects) == 1); - l = linitial(drop_stmt->objects); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - deparseColId(str, strVal(linitial(l))); - appendStringInfoChar(str, ' '); - break; - case OBJECT_TRANSFORM: - Assert(list_length(drop_stmt->objects) == 1); - l = linitial(drop_stmt->objects); - appendStringInfoString(str, "FOR "); - deparseTypeName(str, castNode(TypeName, linitial(l))); - appendStringInfoString(str, " LANGUAGE "); - deparseColId(str, strVal(lsecond(l))); - appendStringInfoChar(str, ' '); - break; - case OBJECT_LANGUAGE: - deparseNameList(str, drop_stmt->objects); - appendStringInfoChar(str, ' '); - break; - case OBJECT_TYPE: - case OBJECT_DOMAIN: - foreach(lc, drop_stmt->objects) - { - deparseTypeName(str, castNode(TypeName, lfirst(lc))); - if (lnext(drop_stmt->objects, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ' '); - break; - case OBJECT_AGGREGATE: - foreach(lc, drop_stmt->objects) - { - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); - if (lnext(drop_stmt->objects, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ' '); - break; - case OBJECT_FUNCTION: - case OBJECT_PROCEDURE: - case OBJECT_ROUTINE: - foreach(lc, drop_stmt->objects) - { - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); - if (lnext(drop_stmt->objects, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ' '); - break; - case OBJECT_OPERATOR: - foreach(lc, drop_stmt->objects) - { - deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); - if (lnext(drop_stmt->objects, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ' '); - break; - default: - Assert(false); - } - - deparseOptDropBehavior(str, drop_stmt->behavior); - - removeTrailingSpace(str); -} - -static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set) -{ - switch(grouping_set->kind) - { - case GROUPING_SET_EMPTY: - appendStringInfoString(str, "()"); - break; - case GROUPING_SET_SIMPLE: - // Not present in raw parse trees - Assert(false); - break; - case GROUPING_SET_ROLLUP: - appendStringInfoString(str, "ROLLUP ("); - deparseExprList(str, grouping_set->content); - appendStringInfoChar(str, ')'); - break; - case GROUPING_SET_CUBE: - appendStringInfoString(str, "CUBE ("); - deparseExprList(str, grouping_set->content); - appendStringInfoChar(str, ')'); - break; - case GROUPING_SET_SETS: - appendStringInfoString(str, "GROUPING SETS ("); - deparseGroupByList(str, grouping_set->content); - appendStringInfoChar(str, ')'); - break; - } -} - -static void deparseDropTableSpaceStmt(StringInfo str, DropTableSpaceStmt *drop_table_space_stmt) -{ - appendStringInfoString(str, "DROP TABLESPACE "); - - if (drop_table_space_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - - appendStringInfoString(str, drop_table_space_stmt->tablespacename); -} - -static void deparseAlterObjectDependsStmt(StringInfo str, AlterObjectDependsStmt *alter_object_depends_stmt) -{ - appendStringInfoString(str, "ALTER "); - - switch (alter_object_depends_stmt->objectType) - { - case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); - break; - case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); - break; - case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); - break; - case OBJECT_TRIGGER: - appendStringInfoString(str, "TRIGGER "); - deparseColId(str, strVal(linitial(castNode(List, alter_object_depends_stmt->object)))); - appendStringInfoString(str, " ON "); - deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - break; - case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); - deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - break; - case OBJECT_INDEX: - appendStringInfoString(str, "INDEX "); - deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - break; - default: - // No other object types supported here - Assert(false); - } - appendStringInfoChar(str, ' '); - - if (alter_object_depends_stmt->remove) - appendStringInfoString(str, "NO "); - - appendStringInfo(str, "DEPENDS ON EXTENSION %s", alter_object_depends_stmt->extname->sval); -} - -static void deparseAlterObjectSchemaStmt(StringInfo str, AlterObjectSchemaStmt *alter_object_schema_stmt) -{ - List *l = NULL; - ListCell *lc = NULL; - - appendStringInfoString(str, "ALTER "); - - switch (alter_object_schema_stmt->objectType) - { - case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); - break; - case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); - break; - case OBJECT_CONVERSION: - appendStringInfoString(str, "CONVERSION "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); - break; - case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); - break; - case OBJECT_EXTENSION: - appendStringInfoString(str, "EXTENSION "); - appendStringInfoString(str, quote_identifier(strVal(alter_object_schema_stmt->object))); - break; - case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); - break; - case OBJECT_OPERATOR: - appendStringInfoString(str, "OPERATOR "); - deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); - break; - case OBJECT_OPCLASS: - l = castNode(List, alter_object_schema_stmt->object); - appendStringInfoString(str, "OPERATOR CLASS "); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); - break; - case OBJECT_OPFAMILY: - l = castNode(List, alter_object_schema_stmt->object); - appendStringInfoString(str, "OPERATOR FAMILY "); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); - break; - case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); - break; - case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); - break; - case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); - if (alter_object_schema_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - break; - case OBJECT_STATISTIC_EXT: - appendStringInfoString(str, "STATISTICS "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); - break; - case OBJECT_TSPARSER: - appendStringInfoString(str, "TEXT SEARCH PARSER "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); - break; - case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); - break; - case OBJECT_TSTEMPLATE: - appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); - break; - case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); - break; - case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); - if (alter_object_schema_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - break; - case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); - if (alter_object_schema_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - break; - case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); - if (alter_object_schema_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - break; - case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); - if (alter_object_schema_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - break; - case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); - deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); - break; - default: - Assert(false); - break; - } - - appendStringInfoString(str, " SET SCHEMA "); - appendStringInfoString(str, quote_identifier(alter_object_schema_stmt->newschema)); -} - -static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, DeparseNodeContext context) -{ - ListCell *lc = NULL; - const char *options = NULL; - bool trailing_missing_ok = false; - - switch (alter_table_cmd->subtype) - { - case AT_AddColumn: /* add column */ - if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) - appendStringInfoString(str, "ADD ATTRIBUTE "); - else - appendStringInfoString(str, "ADD COLUMN "); - break; - case AT_AddColumnRecurse: /* internal to commands/tablecmds.c */ - Assert(false); - break; - case AT_AddColumnToView: /* implicitly via CREATE OR REPLACE VIEW */ - // Not present in raw parser output - Assert(false); - break; - case AT_ColumnDefault: /* alter column default */ - appendStringInfoString(str, "ALTER COLUMN "); - if (alter_table_cmd->def != NULL) - options = "SET DEFAULT"; - else - options = "DROP DEFAULT"; - break; - case AT_CookedColumnDefault: /* add a pre-cooked column default */ - // Not present in raw parser output - Assert(false); - break; - case AT_DropNotNull: /* alter column drop not null */ - appendStringInfoString(str, "ALTER COLUMN "); - options = "DROP NOT NULL"; - break; - case AT_SetNotNull: /* alter column set not null */ - appendStringInfoString(str, "ALTER COLUMN "); - options = "SET NOT NULL"; - break; - case AT_DropExpression: /* alter column drop expression */ - appendStringInfoString(str, "ALTER COLUMN "); - options = "DROP EXPRESSION"; - trailing_missing_ok = true; - break; - case AT_CheckNotNull: /* check column is already marked not null */ - // Not present in raw parser output - Assert(false); - break; - case AT_SetStatistics: /* alter column set statistics */ - appendStringInfoString(str, "ALTER COLUMN "); - options = "SET STATISTICS"; - break; - case AT_SetOptions: /* alter column set ( options ) */ - appendStringInfoString(str, "ALTER COLUMN "); - options = "SET"; - break; - case AT_ResetOptions: /* alter column reset ( options ) */ - appendStringInfoString(str, "ALTER COLUMN "); - options = "RESET"; - break; - case AT_SetStorage: /* alter column set storage */ - appendStringInfoString(str, "ALTER COLUMN "); - options = "SET STORAGE"; - break; - case AT_SetCompression: /* alter column set compression */ - appendStringInfoString(str, "ALTER COLUMN "); - options = "SET COMPRESSION"; - break; - case AT_DropColumn: /* drop column */ - if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) - appendStringInfoString(str, "DROP ATTRIBUTE "); - else - appendStringInfoString(str, "DROP "); - break; - case AT_DropColumnRecurse: /* internal to commands/tablecmds.c */ - Assert(false); - break; - case AT_AddIndex: /* add index */ - appendStringInfoString(str, "ADD INDEX "); - break; - case AT_ReAddIndex: /* internal to commands/tablecmds.c */ - Assert(false); - break; - case AT_AddConstraint: /* add constraint */ - appendStringInfoString(str, "ADD "); - break; - case AT_AddConstraintRecurse: /* internal to commands/tablecmds.c */ - Assert(false); - break; - case AT_ReAddConstraint: /* internal to commands/tablecmds.c */ - Assert(false); - break; - case AT_ReAddDomainConstraint: /* internal to commands/tablecmds.c */ - Assert(false); - break; - case AT_AlterConstraint: /* alter constraint */ - appendStringInfoString(str, "ALTER "); // CONSTRAINT keyword gets added by the Constraint itself (when deparsing def) - break; - case AT_ValidateConstraint: /* validate constraint */ - appendStringInfoString(str, "VALIDATE CONSTRAINT "); - break; - case AT_ValidateConstraintRecurse: /* internal to commands/tablecmds.c */ - Assert(false); - break; - case AT_AddIndexConstraint: /* add constraint using existing index */ - // Not present in raw parser output - Assert(false); - break; - case AT_DropConstraint: /* drop constraint */ - appendStringInfoString(str, "DROP CONSTRAINT "); - break; - case AT_DropConstraintRecurse: /* internal to commands/tablecmds.c */ - Assert(false); - break; - case AT_ReAddComment: /* internal to commands/tablecmds.c */ - case AT_ReAddStatistics: /* internal to commands/tablecmds.c */ - Assert(false); - break; - case AT_AlterColumnType: /* alter column type */ - if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) - appendStringInfoString(str, "ALTER ATTRIBUTE "); - else - appendStringInfoString(str, "ALTER COLUMN "); - options = "TYPE"; - break; - case AT_AlterColumnGenericOptions: /* alter column OPTIONS (...) */ - appendStringInfoString(str, "ALTER COLUMN "); - // Handled via special case in def handling - break; - case AT_ChangeOwner: /* change owner */ - appendStringInfoString(str, "OWNER TO "); - deparseRoleSpec(str, alter_table_cmd->newowner); - break; - case AT_ClusterOn: /* CLUSTER ON */ - appendStringInfoString(str, "CLUSTER ON "); - break; - case AT_DropCluster: /* SET WITHOUT CLUSTER */ - appendStringInfoString(str, "SET WITHOUT CLUSTER "); - break; - case AT_SetLogged: /* SET LOGGED */ - appendStringInfoString(str, "SET LOGGED "); - break; - case AT_SetUnLogged: /* SET UNLOGGED */ - appendStringInfoString(str, "SET UNLOGGED "); - break; - case AT_DropOids: /* SET WITHOUT OIDS */ - appendStringInfoString(str, "SET WITHOUT OIDS "); - break; - case AT_SetTableSpace: /* SET TABLESPACE */ - appendStringInfoString(str, "SET TABLESPACE "); - break; - case AT_SetRelOptions: /* SET (...) -- AM specific parameters */ - appendStringInfoString(str, "SET "); - break; - case AT_SetAccessMethod: - appendStringInfo(str, "SET ACCESS METHOD "); - break; - case AT_ResetRelOptions: /* RESET (...) -- AM specific parameters */ - appendStringInfoString(str, "RESET "); - break; - case AT_ReplaceRelOptions: /* replace reloption list in its entirety */ - // Not present in raw parser output - Assert(false); - break; - case AT_EnableTrig: /* ENABLE TRIGGER name */ - appendStringInfoString(str, "ENABLE TRIGGER "); - break; - case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */ - appendStringInfoString(str, "ENABLE ALWAYS TRIGGER "); - break; - case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */ - appendStringInfoString(str, "ENABLE REPLICA TRIGGER "); - break; - case AT_DisableTrig: /* DISABLE TRIGGER name */ - appendStringInfoString(str, "DISABLE TRIGGER "); - break; - case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */ - appendStringInfoString(str, "ENABLE TRIGGER "); - break; - case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */ - appendStringInfoString(str, "DISABLE TRIGGER ALL "); - break; - case AT_EnableTrigUser: /* ENABLE TRIGGER USER */ - appendStringInfoString(str, "ENABLE TRIGGER USER "); - break; - case AT_DisableTrigUser: /* DISABLE TRIGGER USER */ - appendStringInfoString(str, "DISABLE TRIGGER USER "); - break; - case AT_EnableRule: /* ENABLE RULE name */ - appendStringInfoString(str, "ENABLE RULE "); - break; - case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */ - appendStringInfoString(str, "ENABLE ALWAYS RULE "); - break; - case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */ - appendStringInfoString(str, "ENABLE REPLICA RULE "); - break; - case AT_DisableRule: /* DISABLE RULE name */ - appendStringInfoString(str, "DISABLE RULE "); - break; - case AT_AddInherit: /* INHERIT parent */ - appendStringInfoString(str, "INHERIT "); - break; - case AT_DropInherit: /* NO INHERIT parent */ - appendStringInfoString(str, "NO INHERIT "); - break; - case AT_AddOf: /* OF */ - appendStringInfoString(str, "OF "); - break; - case AT_DropOf: /* NOT OF */ - appendStringInfoString(str, "NOT OF "); - break; - case AT_ReplicaIdentity: /* REPLICA IDENTITY */ - appendStringInfoString(str, "REPLICA IDENTITY "); - break; - case AT_EnableRowSecurity: /* ENABLE ROW SECURITY */ - appendStringInfoString(str, "ENABLE ROW LEVEL SECURITY "); - break; - case AT_DisableRowSecurity: /* DISABLE ROW SECURITY */ - appendStringInfoString(str, "DISABLE ROW LEVEL SECURITY "); - break; - case AT_ForceRowSecurity: /* FORCE ROW SECURITY */ - appendStringInfoString(str, "FORCE ROW LEVEL SECURITY "); - break; - case AT_NoForceRowSecurity: /* NO FORCE ROW SECURITY */ - appendStringInfoString(str, "NO FORCE ROW LEVEL SECURITY "); - break; - case AT_GenericOptions: /* OPTIONS (...) */ - // Handled in def field handling - break; - case AT_AttachPartition: /* ATTACH PARTITION */ - appendStringInfoString(str, "ATTACH PARTITION "); - break; - case AT_DetachPartition: /* DETACH PARTITION */ - appendStringInfoString(str, "DETACH PARTITION "); - break; - case AT_DetachPartitionFinalize: /* DETACH PARTITION FINALIZE */ - appendStringInfoString(str, "DETACH PARTITION "); - break; - case AT_AddIdentity: /* ADD IDENTITY */ - appendStringInfoString(str, "ALTER "); - options = "ADD"; - // Other details are output via the constraint node (in def field) - break; - case AT_SetIdentity: /* SET identity column options */ - appendStringInfoString(str, "ALTER "); - break; - case AT_DropIdentity: /* DROP IDENTITY */ - appendStringInfoString(str, "ALTER COLUMN "); - options = "DROP IDENTITY"; - trailing_missing_ok = true; - break; - } - - if (alter_table_cmd->missing_ok && !trailing_missing_ok) - { - if (alter_table_cmd->subtype == AT_AddColumn) - appendStringInfoString(str, "IF NOT EXISTS "); - else - appendStringInfoString(str, "IF EXISTS "); - } - - if (alter_table_cmd->name != NULL) - { - appendStringInfoString(str, quote_identifier(alter_table_cmd->name)); - appendStringInfoChar(str, ' '); - } - - if (alter_table_cmd->num > 0) - appendStringInfo(str, "%d ", alter_table_cmd->num); - - if (options != NULL) - { - appendStringInfoString(str, options); - appendStringInfoChar(str, ' '); - } - - if (alter_table_cmd->missing_ok && trailing_missing_ok) - appendStringInfoString(str, "IF EXISTS "); - - switch (alter_table_cmd->subtype) - { - case AT_AttachPartition: - case AT_DetachPartition: - deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); - break; - case AT_DetachPartitionFinalize: - deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); - appendStringInfoString(str, "FINALIZE "); - break; - case AT_AddColumn: - case AT_AlterColumnType: - deparseColumnDef(str, castNode(ColumnDef, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); - break; - case AT_ColumnDefault: - if (alter_table_cmd->def != NULL) - { - deparseExpr(str, alter_table_cmd->def); - appendStringInfoChar(str, ' '); - } - break; - case AT_SetStatistics: - deparseSignedIconst(str, alter_table_cmd->def); - appendStringInfoChar(str, ' '); - break; - case AT_SetOptions: - case AT_ResetOptions: - case AT_SetRelOptions: - case AT_ResetRelOptions: - deparseRelOptions(str, castNode(List, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); - break; - case AT_SetStorage: - deparseColId(str, strVal(alter_table_cmd->def)); - appendStringInfoChar(str, ' '); - break; - case AT_SetCompression: - if (strcmp(strVal(alter_table_cmd->def), "default") == 0) - appendStringInfoString(str, "DEFAULT"); - else - deparseColId(str, strVal(alter_table_cmd->def)); - appendStringInfoChar(str, ' '); - break; - case AT_AddIdentity: - case AT_AddConstraint: - case AT_AlterConstraint: - deparseConstraint(str, castNode(Constraint, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); - break; - case AT_SetIdentity: - deparseAlterIdentityColumnOptionList(str, castNode(List, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); - break; - case AT_AlterColumnGenericOptions: - case AT_GenericOptions: - deparseAlterGenericOptions(str, castNode(List, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); - break; - case AT_AddInherit: - case AT_DropInherit: - deparseRangeVar(str, castNode(RangeVar, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - break; - case AT_AddOf: - deparseTypeName(str, castNode(TypeName, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); - break; - case AT_ReplicaIdentity: - deparseReplicaIdentityStmt(str, castNode(ReplicaIdentityStmt, alter_table_cmd->def)); - appendStringInfoChar(str, ' '); - break; - default: - Assert(alter_table_cmd->def == NULL); - break; - } - - deparseOptDropBehavior(str, alter_table_cmd->behavior); - - removeTrailingSpace(str); -} - -static DeparseNodeContext deparseAlterTableObjType(StringInfo str, ObjectType type) -{ - switch (type) - { - case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); - break; - case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); - break; - case OBJECT_INDEX: - appendStringInfoString(str, "INDEX "); - break; - case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); - break; - case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); - break; - case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); - break; - case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); - return DEPARSE_NODE_CONTEXT_ALTER_TYPE; - break; - default: - Assert(false); - break; - } - - return DEPARSE_NODE_CONTEXT_NONE; -} - -static void deparseAlterTableMoveAllStmt(StringInfo str, AlterTableMoveAllStmt *move_all_stmt) -{ - appendStringInfoString(str, "ALTER "); - deparseAlterTableObjType(str, move_all_stmt->objtype); - - appendStringInfoString(str, "ALL IN TABLESPACE "); - appendStringInfoString(str, move_all_stmt->orig_tablespacename); - appendStringInfoChar(str, ' '); - - if (move_all_stmt->roles) - { - appendStringInfoString(str, "OWNED BY "); - deparseRoleList(str, move_all_stmt->roles); - appendStringInfoChar(str, ' '); - } - - appendStringInfoString(str, "SET TABLESPACE "); - appendStringInfoString(str, move_all_stmt->new_tablespacename); - appendStringInfoChar(str, ' '); - - if (move_all_stmt->nowait) - { - appendStringInfoString(str, "NOWAIT"); - } -} - -static void deparseAlterTableStmt(StringInfo str, AlterTableStmt *alter_table_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "ALTER "); - DeparseNodeContext context = deparseAlterTableObjType(str, alter_table_stmt->objtype); - - if (alter_table_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - - deparseRangeVar(str, alter_table_stmt->relation, context); - appendStringInfoChar(str, ' '); - - foreach(lc, alter_table_stmt->cmds) - { - deparseAlterTableCmd(str, castNode(AlterTableCmd, lfirst(lc)), context); - if (lnext(alter_table_stmt->cmds, lc)) - appendStringInfoString(str, ", "); - } -} - -static void deparseAlterTableSpaceOptionsStmt(StringInfo str, AlterTableSpaceOptionsStmt *alter_table_space_options_stmt) -{ - appendStringInfoString(str, "ALTER TABLESPACE "); - deparseColId(str, alter_table_space_options_stmt->tablespacename); - appendStringInfoChar(str, ' '); - - if (alter_table_space_options_stmt->isReset) - appendStringInfoString(str, "RESET "); - else - appendStringInfoString(str, "SET "); - - deparseRelOptions(str, alter_table_space_options_stmt->options); -} - -static void deparseAlterDomainStmt(StringInfo str, AlterDomainStmt *alter_domain_stmt) -{ - appendStringInfoString(str, "ALTER DOMAIN "); - deparseAnyName(str, alter_domain_stmt->typeName); - appendStringInfoChar(str, ' '); - - switch (alter_domain_stmt->subtype) - { - case 'T': - if (alter_domain_stmt->def != NULL) - { - appendStringInfoString(str, "SET DEFAULT "); - deparseExpr(str, alter_domain_stmt->def); - } - else - { - appendStringInfoString(str, "DROP DEFAULT"); - } - break; - case 'N': - appendStringInfoString(str, "DROP NOT NULL"); - break; - case 'O': - appendStringInfoString(str, "SET NOT NULL"); - break; - case 'C': - appendStringInfoString(str, "ADD "); - deparseConstraint(str, castNode(Constraint, alter_domain_stmt->def)); - break; - case 'X': - appendStringInfoString(str, "DROP CONSTRAINT "); - if (alter_domain_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); - if (alter_domain_stmt->behavior == DROP_CASCADE) - appendStringInfoString(str, " CASCADE"); - break; - case 'V': - appendStringInfoString(str, "VALIDATE CONSTRAINT "); - appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); - break; - default: - // No other subtypes supported by the parser - Assert(false); - } -} - -static void deparseRenameStmt(StringInfo str, RenameStmt *rename_stmt) -{ - List *l = NULL; - - appendStringInfoString(str, "ALTER "); - - switch (rename_stmt->renameType) - { - case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); - break; - case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); - break; - case OBJECT_CONVERSION: - appendStringInfoString(str, "CONVERSION "); - break; - case OBJECT_DATABASE: - appendStringInfoString(str, "DATABASE "); - break; - case OBJECT_DOMAIN: - case OBJECT_DOMCONSTRAINT: - appendStringInfoString(str, "DOMAIN "); - break; - case OBJECT_FDW: - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); - break; - case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - break; - case OBJECT_ROLE: - appendStringInfoString(str, "ROLE "); - break; - case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); - break; - case OBJECT_OPCLASS: - appendStringInfoString(str, "OPERATOR CLASS "); - break; - case OBJECT_OPFAMILY: - appendStringInfoString(str, "OPERATOR FAMILY "); - break; - case OBJECT_POLICY: - appendStringInfoString(str, "POLICY "); - break; - case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - break; - case OBJECT_PUBLICATION: - appendStringInfoString(str, "PUBLICATION "); - break; - case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - break; - case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); - break; - case OBJECT_FOREIGN_SERVER: - appendStringInfoString(str, "SERVER "); - break; - case OBJECT_SUBSCRIPTION: - appendStringInfoString(str, "SUBSCRIPTION "); - break; - case OBJECT_TABLE: - case OBJECT_TABCONSTRAINT: - appendStringInfoString(str, "TABLE "); - break; - case OBJECT_COLUMN: - switch (rename_stmt->relationType) - { - case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); - break; - case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); - break; - case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); - break; - case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); - break; - default: - Assert(false); - } - break; - case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); - break; - case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); - break; - case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); - break; - case OBJECT_INDEX: - appendStringInfoString(str, "INDEX "); - break; - case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); - break; - case OBJECT_RULE: - appendStringInfoString(str, "RULE "); - break; - case OBJECT_TRIGGER: - appendStringInfoString(str, "TRIGGER "); - break; - case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, "EVENT TRIGGER "); - break; - case OBJECT_TABLESPACE: - appendStringInfoString(str, "TABLESPACE "); - break; - case OBJECT_STATISTIC_EXT: - appendStringInfoString(str, "STATISTICS "); - break; - case OBJECT_TSPARSER: - appendStringInfoString(str, "TEXT SEARCH PARSER "); - break; - case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); - break; - case OBJECT_TSTEMPLATE: - appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); - break; - case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); - break; - case OBJECT_TYPE: - case OBJECT_ATTRIBUTE: - appendStringInfoString(str, "TYPE "); - break; - default: - Assert(false); - break; - } - - if (rename_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - - switch (rename_stmt->renameType) - { - case OBJECT_AGGREGATE: - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); - appendStringInfoString(str, " RENAME "); - break; - case OBJECT_DOMCONSTRAINT: - deparseAnyName(str, castNode(List, rename_stmt->object)); - appendStringInfoString(str, " RENAME CONSTRAINT "); - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoChar(str, ' '); - break; - case OBJECT_OPCLASS: - case OBJECT_OPFAMILY: - l = castNode(List, rename_stmt->object); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); - appendStringInfoString(str, " RENAME "); - break; - case OBJECT_POLICY: - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoString(str, " ON "); - deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoString(str, " RENAME "); - break; - case OBJECT_FUNCTION: - case OBJECT_PROCEDURE: - case OBJECT_ROUTINE: - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); - appendStringInfoString(str, " RENAME "); - break; - case OBJECT_SUBSCRIPTION: - deparseColId(str, strVal(rename_stmt->object)); - appendStringInfoString(str, " RENAME "); - break; - case OBJECT_TABLE: - case OBJECT_SEQUENCE: - case OBJECT_VIEW: - case OBJECT_MATVIEW: - case OBJECT_INDEX: - case OBJECT_FOREIGN_TABLE: - deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoString(str, " RENAME "); - break; - case OBJECT_COLUMN: - deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoString(str, " RENAME COLUMN "); - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoChar(str, ' '); - break; - case OBJECT_TABCONSTRAINT: - deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoString(str, " RENAME CONSTRAINT "); - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoChar(str, ' '); - break; - case OBJECT_RULE: - case OBJECT_TRIGGER: - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoString(str, " ON "); - deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoString(str, " RENAME "); - break; - case OBJECT_FDW: - case OBJECT_LANGUAGE: - case OBJECT_PUBLICATION: - case OBJECT_FOREIGN_SERVER: - case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, quote_identifier(strVal(rename_stmt->object))); - appendStringInfoString(str, " RENAME "); - break; - case OBJECT_DATABASE: - case OBJECT_ROLE: - case OBJECT_SCHEMA: - case OBJECT_TABLESPACE: - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoString(str, " RENAME "); - break; - case OBJECT_COLLATION: - case OBJECT_CONVERSION: - case OBJECT_DOMAIN: - case OBJECT_STATISTIC_EXT: - case OBJECT_TSPARSER: - case OBJECT_TSDICTIONARY: - case OBJECT_TSTEMPLATE: - case OBJECT_TSCONFIGURATION: - case OBJECT_TYPE: - deparseAnyName(str, castNode(List, rename_stmt->object)); - appendStringInfoString(str, " RENAME "); - break; - case OBJECT_ATTRIBUTE: - deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_ALTER_TYPE); - appendStringInfoString(str, " RENAME ATTRIBUTE "); - appendStringInfoString(str, quote_identifier(rename_stmt->subname)); - appendStringInfoChar(str, ' '); - break; - default: - Assert(false); - break; - } - - appendStringInfoString(str, "TO "); - appendStringInfoString(str, quote_identifier(rename_stmt->newname)); - appendStringInfoChar(str, ' '); - - deparseOptDropBehavior(str, rename_stmt->behavior); - - removeTrailingSpace(str); -} - -static void deparseTransactionStmt(StringInfo str, TransactionStmt *transaction_stmt) -{ - ListCell *lc; - switch (transaction_stmt->kind) - { - case TRANS_STMT_BEGIN: - appendStringInfoString(str, "BEGIN "); - deparseTransactionModeList(str, transaction_stmt->options); - break; - case TRANS_STMT_START: - appendStringInfoString(str, "START TRANSACTION "); - deparseTransactionModeList(str, transaction_stmt->options); - break; - case TRANS_STMT_COMMIT: - appendStringInfoString(str, "COMMIT "); - if (transaction_stmt->chain) - appendStringInfoString(str, "AND CHAIN "); - break; - case TRANS_STMT_ROLLBACK: - appendStringInfoString(str, "ROLLBACK "); - if (transaction_stmt->chain) - appendStringInfoString(str, "AND CHAIN "); - break; - case TRANS_STMT_SAVEPOINT: - appendStringInfoString(str, "SAVEPOINT "); - appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); - break; - case TRANS_STMT_RELEASE: - appendStringInfoString(str, "RELEASE "); - appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); - break; - case TRANS_STMT_ROLLBACK_TO: - appendStringInfoString(str, "ROLLBACK "); - appendStringInfoString(str, "TO SAVEPOINT "); - appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); - break; - case TRANS_STMT_PREPARE: - appendStringInfoString(str, "PREPARE TRANSACTION "); - deparseStringLiteral(str, transaction_stmt->gid); - break; - case TRANS_STMT_COMMIT_PREPARED: - appendStringInfoString(str, "COMMIT PREPARED "); - deparseStringLiteral(str, transaction_stmt->gid); - break; - case TRANS_STMT_ROLLBACK_PREPARED: - appendStringInfoString(str, "ROLLBACK PREPARED "); - deparseStringLiteral(str, transaction_stmt->gid); - break; - } - - removeTrailingSpace(str); -} - -// Determine if we hit SET TIME ZONE INTERVAL, that has special syntax not -// supported for other SET statements -static bool isSetTimeZoneInterval(VariableSetStmt* stmt) -{ - if (!(strcmp(stmt->name, "timezone") == 0 && - list_length(stmt->args) == 1 && - IsA(linitial(stmt->args), TypeCast))) - return false; - - TypeName* typeName = castNode(TypeCast, linitial(stmt->args))->typeName; - - return (list_length(typeName->names) == 2 && - strcmp(strVal(linitial(typeName->names)), "pg_catalog") == 0 && - strcmp(strVal(llast(typeName->names)), "interval") == 0); -} - -static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt) -{ - ListCell *lc; - - switch (variable_set_stmt->kind) - { - case VAR_SET_VALUE: /* SET var = value */ - appendStringInfoString(str, "SET "); - if (variable_set_stmt->is_local) - appendStringInfoString(str, "LOCAL "); - if (isSetTimeZoneInterval(variable_set_stmt)) - { - appendStringInfoString(str, "TIME ZONE "); - deparseVarList(str, variable_set_stmt->args); - } - else - { - deparseVarName(str, variable_set_stmt->name); - appendStringInfoString(str, " TO "); - deparseVarList(str, variable_set_stmt->args); - } - break; - case VAR_SET_DEFAULT: /* SET var TO DEFAULT */ - appendStringInfoString(str, "SET "); - if (variable_set_stmt->is_local) - appendStringInfoString(str, "LOCAL "); - deparseVarName(str, variable_set_stmt->name); - appendStringInfoString(str, " TO DEFAULT"); - break; - case VAR_SET_CURRENT: /* SET var FROM CURRENT */ - appendStringInfoString(str, "SET "); - if (variable_set_stmt->is_local) - appendStringInfoString(str, "LOCAL "); - deparseVarName(str, variable_set_stmt->name); - appendStringInfoString(str, " FROM CURRENT"); - break; - case VAR_SET_MULTI: /* special case for SET TRANSACTION ... */ - Assert(variable_set_stmt->name != NULL); - appendStringInfoString(str, "SET "); - if (variable_set_stmt->is_local) - appendStringInfoString(str, "LOCAL "); - if (strcmp(variable_set_stmt->name, "TRANSACTION") == 0) - { - appendStringInfoString(str, "TRANSACTION "); - deparseTransactionModeList(str, variable_set_stmt->args); - } - else if (strcmp(variable_set_stmt->name, "SESSION CHARACTERISTICS") == 0) - { - appendStringInfoString(str, "SESSION CHARACTERISTICS AS TRANSACTION "); - deparseTransactionModeList(str, variable_set_stmt->args); - } - else if (strcmp(variable_set_stmt->name, "TRANSACTION SNAPSHOT") == 0) - { - appendStringInfoString(str, "TRANSACTION SNAPSHOT "); - deparseStringLiteral(str, strVal(&castNode(A_Const, linitial(variable_set_stmt->args))->val)); - } - else - { - Assert(false); - } - break; - case VAR_RESET: /* RESET var */ - appendStringInfoString(str, "RESET "); - deparseVarName(str, variable_set_stmt->name); - break; - case VAR_RESET_ALL: /* RESET ALL */ - appendStringInfoString(str, "RESET ALL"); - break; - } -} - -static void deparseDropdbStmt(StringInfo str, DropdbStmt *dropdb_stmt) -{ - ListCell *lc = NULL; - - appendStringInfoString(str, "DROP DATABASE "); - if (dropdb_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - - appendStringInfoString(str, quote_identifier(dropdb_stmt->dbname)); - appendStringInfoChar(str, ' '); - - if (list_length(dropdb_stmt->options) > 0) - { - appendStringInfoChar(str, '('); - foreach(lc, dropdb_stmt->options) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - if (strcmp(def_elem->defname, "force") == 0) - appendStringInfoString(str, "FORCE"); - else - Assert(false); // Currently there are other supported values - - if (lnext(dropdb_stmt->options, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); - } - - removeTrailingSpace(str); -} - -static void deparseVacuumStmt(StringInfo str, VacuumStmt *vacuum_stmt) -{ - ListCell *lc = NULL; - ListCell *lc2 = NULL; - - if (vacuum_stmt->is_vacuumcmd) - appendStringInfoString(str, "VACUUM "); - else - appendStringInfoString(str, "ANALYZE "); - - deparseUtilityOptionList(str, vacuum_stmt->options); - - foreach(lc, vacuum_stmt->rels) - { - Assert(IsA(lfirst(lc), VacuumRelation)); - VacuumRelation *rel = castNode(VacuumRelation, lfirst(lc)); - - deparseRangeVar(str, rel->relation, DEPARSE_NODE_CONTEXT_NONE); - if (list_length(rel->va_cols) > 0) - { - appendStringInfoChar(str, '('); - foreach(lc2, rel->va_cols) - { - appendStringInfoString(str, quote_identifier(strVal(lfirst(lc2)))); - if (lnext(rel->va_cols, lc2)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); - } - - if (lnext(vacuum_stmt->rels, lc)) - appendStringInfoString(str, ", "); - } - - removeTrailingSpace(str); -} - -static void deparseLoadStmt(StringInfo str, LoadStmt *load_stmt) -{ - appendStringInfoString(str, "LOAD "); - deparseStringLiteral(str, load_stmt->filename); -} - -static void deparseLockStmt(StringInfo str, LockStmt *lock_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "LOCK TABLE "); - - deparseRelationExprList(str, lock_stmt->relations); - appendStringInfoChar(str, ' '); - - if (lock_stmt->mode != AccessExclusiveLock) - { - appendStringInfoString(str, "IN "); - switch (lock_stmt->mode) - { - case AccessShareLock: - appendStringInfoString(str, "ACCESS SHARE "); - break; - case RowShareLock: - appendStringInfoString(str, "ROW SHARE "); - break; - case RowExclusiveLock: - appendStringInfoString(str, "ROW EXCLUSIVE "); - break; - case ShareUpdateExclusiveLock: - appendStringInfoString(str, "SHARE UPDATE EXCLUSIVE "); - break; - case ShareLock: - appendStringInfoString(str, "SHARE "); - break; - case ShareRowExclusiveLock: - appendStringInfoString(str, "SHARE ROW EXCLUSIVE "); - break; - case ExclusiveLock: - appendStringInfoString(str, "EXCLUSIVE "); - break; - case AccessExclusiveLock: - appendStringInfoString(str, "ACCESS EXCLUSIVE "); - break; - default: - Assert(false); - break; - } - appendStringInfoString(str, "MODE "); - } - - if (lock_stmt->nowait) - appendStringInfoString(str, "NOWAIT "); - - removeTrailingSpace(str); -} - -static void deparseConstraintsSetStmt(StringInfo str, ConstraintsSetStmt *constraints_set_stmt) -{ - appendStringInfoString(str, "SET CONSTRAINTS "); - - if (list_length(constraints_set_stmt->constraints) > 0) - { - deparseQualifiedNameList(str, constraints_set_stmt->constraints); - appendStringInfoChar(str, ' '); - } - else - { - appendStringInfoString(str, "ALL "); - } - - if (constraints_set_stmt->deferred) - appendStringInfoString(str, "DEFERRED"); - else - appendStringInfoString(str, "IMMEDIATE"); -} - -static void deparseExplainStmt(StringInfo str, ExplainStmt *explain_stmt) -{ - ListCell *lc = NULL; - char *defname = NULL; - - appendStringInfoString(str, "EXPLAIN "); - - deparseUtilityOptionList(str, explain_stmt->options); - - deparseExplainableStmt(str, explain_stmt->query); -} - -static void deparseCopyStmt(StringInfo str, CopyStmt *copy_stmt) -{ - ListCell *lc = NULL; - ListCell *lc2 = NULL; - - appendStringInfoString(str, "COPY "); - - if (copy_stmt->relation != NULL) - { - deparseRangeVar(str, copy_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - if (list_length(copy_stmt->attlist) > 0) - { - appendStringInfoChar(str, '('); - deparseColumnList(str, copy_stmt->attlist); - appendStringInfoChar(str, ')'); - } - appendStringInfoChar(str, ' '); - } - - if (copy_stmt->query != NULL) - { - appendStringInfoChar(str, '('); - deparsePreparableStmt(str, copy_stmt->query); - appendStringInfoString(str, ") "); - } - - if (copy_stmt->is_from) - appendStringInfoString(str, "FROM "); - else - appendStringInfoString(str, "TO "); - - if (copy_stmt->is_program) - appendStringInfoString(str, "PROGRAM "); - - if (copy_stmt->filename != NULL) - { - deparseStringLiteral(str, copy_stmt->filename); - appendStringInfoChar(str, ' '); - } - else - { - if (copy_stmt->is_from) - appendStringInfoString(str, "STDIN "); - else - appendStringInfoString(str, "STDOUT "); - } - - if (list_length(copy_stmt->options) > 0) - { - // In some cases, equivalent expressions may have slightly different parse trees for `COPY` - // statements. For example the following two statements result in different (but equivalent) parse - // trees: - // - // - COPY foo FROM STDIN CSV FREEZE - // - COPY foo FROM STDIN WITH (FORMAT CSV, FREEZE) - // - // In order to make sure we deparse to the "correct" version, we always try to deparse to the older - // compact syntax first. - // - // The old syntax can be seen here in the Postgres 8.4 Reference: - // https://www.postgresql.org/docs/8.4/sql-copy.html - - bool old_fmt = true; - - // Loop over the options to see if any require the new `WITH (...)` syntax. - foreach(lc, copy_stmt->options) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - - if (strcmp(def_elem->defname, "freeze") == 0 && optBooleanValue(def_elem->arg)) - {} - else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) - {} - else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) - {} - else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) - {} - else - { - old_fmt = false; - break; - } - } - - // Branch to differing output modes, depending on if we can use the old syntax. - if (old_fmt) { - foreach(lc, copy_stmt->options) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - - if (strcmp(def_elem->defname, "freeze") == 0 && optBooleanValue(def_elem->arg)) - { - appendStringInfoString(str, "FREEZE "); - } - else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) - { - appendStringInfoString(str, "HEADER "); - } - else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) - { - appendStringInfoString(str, "CSV "); - } - else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) - { - appendStringInfoString(str, "FORCE QUOTE "); - deparseColumnList(str, castNode(List, def_elem->arg)); - } - else - { - // This isn't reachable, the conditions here are exactly the same as the first loop above. - Assert(false); - } - } - } else { - appendStringInfoString(str, "WITH ("); - foreach(lc, copy_stmt->options) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - - if (strcmp(def_elem->defname, "format") == 0) - { - appendStringInfoString(str, "FORMAT "); - - char *format = strVal(def_elem->arg); - if (strcmp(format, "binary") == 0) - appendStringInfoString(str, "BINARY"); - else if (strcmp(format, "csv") == 0) - appendStringInfoString(str, "CSV"); - else - Assert(false); - } - else if (strcmp(def_elem->defname, "freeze") == 0) - { - appendStringInfoString(str, "FREEZE"); - deparseOptBoolean(str, def_elem->arg); - } - else if (strcmp(def_elem->defname, "delimiter") == 0) - { - appendStringInfoString(str, "DELIMITER "); - deparseStringLiteral(str, strVal(def_elem->arg)); - } - else if (strcmp(def_elem->defname, "null") == 0) - { - appendStringInfoString(str, "NULL "); - deparseStringLiteral(str, strVal(def_elem->arg)); - } - else if (strcmp(def_elem->defname, "header") == 0) - { - appendStringInfoString(str, "HEADER"); - deparseOptBoolean(str, def_elem->arg); - } - else if (strcmp(def_elem->defname, "quote") == 0) - { - appendStringInfoString(str, "QUOTE "); - deparseStringLiteral(str, strVal(def_elem->arg)); - } - else if (strcmp(def_elem->defname, "escape") == 0) - { - appendStringInfoString(str, "ESCAPE "); - deparseStringLiteral(str, strVal(def_elem->arg)); - } - else if (strcmp(def_elem->defname, "force_quote") == 0) - { - appendStringInfoString(str, "FORCE_QUOTE "); - if (IsA(def_elem->arg, A_Star)) - { - appendStringInfoChar(str, '*'); - } - else if (IsA(def_elem->arg, List)) - { - appendStringInfoChar(str, '('); - deparseColumnList(str, castNode(List, def_elem->arg)); - appendStringInfoChar(str, ')'); - } - else - { - Assert(false); - } - } - else if (strcmp(def_elem->defname, "force_not_null") == 0) - { - appendStringInfoString(str, "FORCE_NOT_NULL ("); - deparseColumnList(str, castNode(List, def_elem->arg)); - appendStringInfoChar(str, ')'); - } - else if (strcmp(def_elem->defname, "force_null") == 0) - { - appendStringInfoString(str, "FORCE_NULL ("); - deparseColumnList(str, castNode(List, def_elem->arg)); - appendStringInfoChar(str, ')'); - } - else if (strcmp(def_elem->defname, "encoding") == 0) - { - appendStringInfoString(str, "ENCODING "); - deparseStringLiteral(str, strVal(def_elem->arg)); - } - else - { - appendStringInfoString(str, quote_identifier(def_elem->defname)); - if (def_elem->arg != NULL) - appendStringInfoChar(str, ' '); - - if (def_elem->arg == NULL) - { - // Nothing - } - else if (IsA(def_elem->arg, String)) - { - deparseOptBooleanOrString(str, strVal(def_elem->arg)); - } - else if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) - { - deparseNumericOnly(str, (union ValUnion *) def_elem->arg); - } - else if (IsA(def_elem->arg, A_Star)) - { - deparseAStar(str, castNode(A_Star, def_elem->arg)); - } - else if (IsA(def_elem->arg, List)) - { - List *l = castNode(List, def_elem->arg); - appendStringInfoChar(str, '('); - foreach(lc2, l) - { - deparseOptBooleanOrString(str, strVal(lfirst(lc2))); - if (lnext(l, lc2)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); - } - } - - if (lnext(copy_stmt->options, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoString(str, ") "); - } - } - - deparseWhereClause(str, copy_stmt->whereClause); - - removeTrailingSpace(str); -} - -static void deparseDoStmt(StringInfo str, DoStmt *do_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "DO "); - - foreach (lc, do_stmt->args) - { - DefElem *defel = castNode(DefElem, lfirst(lc)); - if (strcmp(defel->defname, "language") == 0) - { - appendStringInfoString(str, "LANGUAGE "); - appendStringInfoString(str, quote_identifier(strVal(defel->arg))); - appendStringInfoChar(str, ' '); - } - else if (strcmp(defel->defname, "as") == 0) - { - char *strval = strVal(defel->arg); - const char *delim = "$$"; - if (strstr(strval, "$$") != NULL) - delim = "$outer$"; - appendStringInfoString(str, delim); - appendStringInfoString(str, strval); - appendStringInfoString(str, delim); - appendStringInfoChar(str, ' '); - } - } - - removeTrailingSpace(str); -} - -static void deparseDiscardStmt(StringInfo str, DiscardStmt *discard_stmt) -{ - appendStringInfoString(str, "DISCARD "); - switch (discard_stmt->target) - { - case DISCARD_ALL: - appendStringInfoString(str, "ALL"); - break; - case DISCARD_PLANS: - appendStringInfoString(str, "PLANS"); - break; - case DISCARD_SEQUENCES: - appendStringInfoString(str, "SEQUENCES"); - break; - case DISCARD_TEMP: - appendStringInfoString(str, "TEMP"); - break; - } -} - -static void deparseDefineStmt(StringInfo str, DefineStmt *define_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "CREATE "); - - if (define_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); - - switch (define_stmt->kind) - { - case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); - break; - case OBJECT_OPERATOR: - appendStringInfoString(str, "OPERATOR "); - break; - case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); - break; - case OBJECT_TSPARSER: - appendStringInfoString(str, "TEXT SEARCH PARSER "); - break; - case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); - break; - case OBJECT_TSTEMPLATE: - appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); - break; - case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); - break; - case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); - break; - default: - // This shouldn't happen - Assert(false); - break; - } - - if (define_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); - - switch (define_stmt->kind) - { - case OBJECT_AGGREGATE: - deparseFuncName(str, define_stmt->defnames); - break; - case OBJECT_OPERATOR: - deparseAnyOperator(str, define_stmt->defnames); - break; - case OBJECT_TYPE: - case OBJECT_TSPARSER: - case OBJECT_TSDICTIONARY: - case OBJECT_TSTEMPLATE: - case OBJECT_TSCONFIGURATION: - case OBJECT_COLLATION: - deparseAnyName(str, define_stmt->defnames); - break; - default: - Assert(false); - } - appendStringInfoChar(str, ' '); - - if (!define_stmt->oldstyle && define_stmt->kind == OBJECT_AGGREGATE) - { - deparseAggrArgs(str, define_stmt->args); - appendStringInfoChar(str, ' '); - } - - if (define_stmt->kind == OBJECT_COLLATION && - list_length(define_stmt->definition) == 1 && - strcmp(castNode(DefElem, linitial(define_stmt->definition))->defname, "from") == 0) - { - appendStringInfoString(str, "FROM "); - deparseAnyName(str, castNode(List, castNode(DefElem, linitial(define_stmt->definition))->arg)); - } - else if (list_length(define_stmt->definition) > 0) - { - deparseDefinition(str, define_stmt->definition); - } - - removeTrailingSpace(str); -} - -static void deparseCompositeTypeStmt(StringInfo str, CompositeTypeStmt *composite_type_stmt) -{ - ListCell *lc; - RangeVar *typevar; - - appendStringInfoString(str, "CREATE TYPE "); - deparseRangeVar(str, composite_type_stmt->typevar, DEPARSE_NODE_CONTEXT_CREATE_TYPE); - - appendStringInfoString(str, " AS ("); - foreach(lc, composite_type_stmt->coldeflist) - { - deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); - if (lnext(composite_type_stmt->coldeflist, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); -} - -static void deparseCreateEnumStmt(StringInfo str, CreateEnumStmt *create_enum_stmt) -{ - ListCell *lc; - appendStringInfoString(str, "CREATE TYPE "); - - deparseAnyName(str, create_enum_stmt->typeName); - appendStringInfoString(str, " AS ENUM ("); - foreach(lc, create_enum_stmt->vals) - { - deparseStringLiteral(str, strVal(lfirst(lc))); - if (lnext(create_enum_stmt->vals, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); -} - -static void deparseCreateRangeStmt(StringInfo str, CreateRangeStmt *create_range_stmt) -{ - appendStringInfoString(str, "CREATE TYPE "); - deparseAnyName(str, create_range_stmt->typeName); - appendStringInfoString(str, " AS RANGE "); - deparseDefinition(str, create_range_stmt->params); -} - -static void deparseAlterEnumStmt(StringInfo str, AlterEnumStmt *alter_enum_stmt) -{ - appendStringInfoString(str, "ALTER TYPE "); - deparseAnyName(str, alter_enum_stmt->typeName); - appendStringInfoChar(str, ' '); - - if (alter_enum_stmt->oldVal == NULL) - { - appendStringInfoString(str, "ADD VALUE "); - if (alter_enum_stmt->skipIfNewValExists) - appendStringInfoString(str, "IF NOT EXISTS "); - - deparseStringLiteral(str, alter_enum_stmt->newVal); - appendStringInfoChar(str, ' '); - - if (alter_enum_stmt->newValNeighbor) - { - if (alter_enum_stmt->newValIsAfter) - appendStringInfoString(str, "AFTER "); - else - appendStringInfoString(str, "BEFORE "); - deparseStringLiteral(str, alter_enum_stmt->newValNeighbor); - } - } - else - { - appendStringInfoString(str, "RENAME VALUE "); - deparseStringLiteral(str, alter_enum_stmt->oldVal); - appendStringInfoString(str, " TO "); - deparseStringLiteral(str, alter_enum_stmt->newVal); - } - - removeTrailingSpace(str); -} - -static void deparseAlterExtensionStmt(StringInfo str, AlterExtensionStmt *alter_extension_stmt) -{ - ListCell *lc = NULL; - - appendStringInfoString(str, "ALTER EXTENSION "); - deparseColId(str, alter_extension_stmt->extname); - appendStringInfoString(str, " UPDATE "); - foreach (lc, alter_extension_stmt->options) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - if (strcmp(def_elem->defname, "new_version") == 0) - { - appendStringInfoString(str, "TO "); - deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); - } - else - { - Assert(false); - } - appendStringInfoChar(str, ' '); - } - removeTrailingSpace(str); -} - -static void deparseAlterExtensionContentsStmt(StringInfo str, AlterExtensionContentsStmt *alter_extension_contents_stmt) -{ - List *l = NULL; - - appendStringInfoString(str, "ALTER EXTENSION "); - deparseColId(str, alter_extension_contents_stmt->extname); - appendStringInfoChar(str, ' '); - - if (alter_extension_contents_stmt->action == 1) - appendStringInfoString(str, "ADD "); - else if (alter_extension_contents_stmt->action == -1) - appendStringInfoString(str, "DROP "); - else - Assert(false); - - switch (alter_extension_contents_stmt->objtype) - { - case OBJECT_ACCESS_METHOD: - appendStringInfoString(str, "ACCESS METHOD "); - break; - case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); - break; - case OBJECT_CAST: - appendStringInfoString(str, "CAST "); - break; - case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); - break; - case OBJECT_CONVERSION: - appendStringInfoString(str, "CONVERSION "); - break; - case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); - break; - case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - break; - case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); - break; - case OBJECT_OPERATOR: - appendStringInfoString(str, "OPERATOR "); - break; - case OBJECT_OPCLASS: - appendStringInfoString(str, "OPERATOR CLASS "); - break; - case OBJECT_OPFAMILY: - appendStringInfoString(str, "OPERATOR FAMILY "); - break; - case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - break; - case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - break; - case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); - break; - case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, "EVENT TRIGGER "); - break; - case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); - break; - case OBJECT_TSPARSER: - appendStringInfoString(str, "TEXT SEARCH PARSER "); - break; - case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); - break; - case OBJECT_TSTEMPLATE: - appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); - break; - case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); - break; - case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); - break; - case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); - break; - case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); - break; - case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); - break; - case OBJECT_FDW: - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); - break; - case OBJECT_FOREIGN_SERVER: - appendStringInfoString(str, "SERVER "); - break; - case OBJECT_TRANSFORM: - appendStringInfoString(str, "TRANSFORM "); - break; - case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); - break; - default: - // No other object types are supported here in the parser - Assert(false); - break; - } - - switch (alter_extension_contents_stmt->objtype) - { - // any_name - case OBJECT_COLLATION: - case OBJECT_CONVERSION: - case OBJECT_TABLE: - case OBJECT_TSPARSER: - case OBJECT_TSDICTIONARY: - case OBJECT_TSTEMPLATE: - case OBJECT_TSCONFIGURATION: - case OBJECT_SEQUENCE: - case OBJECT_VIEW: - case OBJECT_MATVIEW: - case OBJECT_FOREIGN_TABLE: - deparseAnyName(str, castNode(List, alter_extension_contents_stmt->object)); - break; - // name - case OBJECT_ACCESS_METHOD: - case OBJECT_LANGUAGE: - case OBJECT_SCHEMA: - case OBJECT_EVENT_TRIGGER: - case OBJECT_FDW: - case OBJECT_FOREIGN_SERVER: - deparseColId(str, strVal(alter_extension_contents_stmt->object)); - break; - case OBJECT_AGGREGATE: - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); - break; - case OBJECT_CAST: - l = castNode(List, alter_extension_contents_stmt->object); - Assert(list_length(l) == 2); - appendStringInfoChar(str, '('); - deparseTypeName(str, castNode(TypeName, linitial(l))); - appendStringInfoString(str, " AS "); - deparseTypeName(str, castNode(TypeName, lsecond(l))); - appendStringInfoChar(str, ')'); - break; - case OBJECT_DOMAIN: - case OBJECT_TYPE: - deparseTypeName(str, castNode(TypeName, alter_extension_contents_stmt->object)); - break; - case OBJECT_FUNCTION: - case OBJECT_PROCEDURE: - case OBJECT_ROUTINE: - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); - break; - case OBJECT_OPERATOR: - deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); - break; - case OBJECT_OPFAMILY: - case OBJECT_OPCLASS: - l = castNode(List, alter_extension_contents_stmt->object); - Assert(list_length(l) == 2); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - deparseColId(str, strVal(linitial(l))); - break; - case OBJECT_TRANSFORM: - l = castNode(List, alter_extension_contents_stmt->object); - appendStringInfoString(str, "FOR "); - deparseTypeName(str, castNode(TypeName, linitial(l))); - appendStringInfoString(str, " LANGUAGE "); - deparseColId(str, strVal(lsecond(l))); - break; - default: - Assert(false); - break; - } -} - -static void deparseAccessPriv(StringInfo str, AccessPriv *access_priv) -{ - ListCell *lc; - - if (access_priv->priv_name != NULL) - { - if (strcmp(access_priv->priv_name, "select") == 0) - appendStringInfoString(str, "select"); - else if (strcmp(access_priv->priv_name, "references") == 0) - appendStringInfoString(str, "references"); - else if (strcmp(access_priv->priv_name, "create") == 0) - appendStringInfoString(str, "create"); - else - appendStringInfoString(str, quote_identifier(access_priv->priv_name)); - } - else - { - appendStringInfoString(str, "ALL"); - } - appendStringInfoChar(str, ' '); - - if (list_length(access_priv->cols) > 0) - { - appendStringInfoChar(str, '('); - deparseColumnList(str, access_priv->cols); - appendStringInfoChar(str, ')'); - } - - removeTrailingSpace(str); -} - -static void deparseGrantStmt(StringInfo str, GrantStmt *grant_stmt) -{ - ListCell *lc; - if (grant_stmt->is_grant) - appendStringInfoString(str, "GRANT "); - else - appendStringInfoString(str, "REVOKE "); - - if (!grant_stmt->is_grant && grant_stmt->grant_option) - appendStringInfoString(str, "GRANT OPTION FOR "); - - if (list_length(grant_stmt->privileges) > 0) - { - foreach(lc, grant_stmt->privileges) - { - deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); - if (lnext(grant_stmt->privileges, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ' '); - } - else - { - appendStringInfoString(str, "ALL "); - } - - appendStringInfoString(str, "ON "); - - deparsePrivilegeTarget(str, grant_stmt->targtype, grant_stmt->objtype, grant_stmt->objects); - appendStringInfoChar(str, ' '); - - if (grant_stmt->is_grant) - appendStringInfoString(str, "TO "); - else - appendStringInfoString(str, "FROM "); - - foreach(lc, grant_stmt->grantees) - { - deparseRoleSpec(str, castNode(RoleSpec, lfirst(lc))); - if (lnext(grant_stmt->grantees, lc)) - appendStringInfoChar(str, ','); - appendStringInfoChar(str, ' '); - } - - if (grant_stmt->is_grant && grant_stmt->grant_option) - appendStringInfoString(str, "WITH GRANT OPTION "); - - deparseOptDropBehavior(str, grant_stmt->behavior); - - if (grant_stmt->grantor) - { - appendStringInfoString(str, "GRANTED BY "); - deparseRoleSpec(str, castNode(RoleSpec, grant_stmt->grantor)); - } - - removeTrailingSpace(str); -} - -static void deparseGrantRoleStmt(StringInfo str, GrantRoleStmt *grant_role_stmt) -{ - ListCell *lc; - - if (grant_role_stmt->is_grant) - appendStringInfoString(str, "GRANT "); - else - appendStringInfoString(str, "REVOKE "); - - if (!grant_role_stmt->is_grant && grant_role_stmt->admin_opt) - appendStringInfoString(str, "ADMIN OPTION FOR "); - - foreach(lc, grant_role_stmt->granted_roles) - { - deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); - if (lnext(grant_role_stmt->granted_roles, lc)) - appendStringInfoChar(str, ','); - appendStringInfoChar(str, ' '); - } - - if (grant_role_stmt->is_grant) - appendStringInfoString(str, "TO "); - else - appendStringInfoString(str, "FROM "); - - deparseRoleList(str, grant_role_stmt->grantee_roles); - appendStringInfoChar(str, ' '); - - if (grant_role_stmt->is_grant && grant_role_stmt->admin_opt) - appendStringInfoString(str, "WITH ADMIN OPTION "); - - if (grant_role_stmt->grantor) - { - appendStringInfoString(str, "GRANTED BY "); - deparseRoleSpec(str, castNode(RoleSpec, grant_role_stmt->grantor)); - } - - removeTrailingSpace(str); -} - -static void deparseDropRoleStmt(StringInfo str, DropRoleStmt *drop_role_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "DROP ROLE "); - - if (drop_role_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - - deparseRoleList(str, drop_role_stmt->roles); -} - -static void deparseIndexStmt(StringInfo str, IndexStmt *index_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "CREATE "); - - if (index_stmt->unique) - appendStringInfoString(str, "UNIQUE "); - - appendStringInfoString(str, "INDEX "); - - if (index_stmt->concurrent) - appendStringInfoString(str, "CONCURRENTLY "); - - if (index_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); - - if (index_stmt->idxname != NULL) - { - appendStringInfoString(str, quote_identifier(index_stmt->idxname)); - appendStringInfoChar(str, ' '); - } - - appendStringInfoString(str, "ON "); - deparseRangeVar(str, index_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - if (index_stmt->accessMethod != NULL) - { - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(index_stmt->accessMethod)); - appendStringInfoChar(str, ' '); - } - - appendStringInfoChar(str, '('); - foreach (lc, index_stmt->indexParams) - { - deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); - if (lnext(index_stmt->indexParams, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoString(str, ") "); - - if (list_length(index_stmt->indexIncludingParams) > 0) - { - appendStringInfoString(str, "INCLUDE ("); - foreach (lc, index_stmt->indexIncludingParams) - { - deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); - if (lnext(index_stmt->indexIncludingParams, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoString(str, ") "); - } - - if (index_stmt->nulls_not_distinct) - { - appendStringInfoString(str, "NULLS NOT DISTINCT "); - } - - deparseOptWith(str, index_stmt->options); - - if (index_stmt->tableSpace != NULL) - { - appendStringInfoString(str, "TABLESPACE "); - appendStringInfoString(str, quote_identifier(index_stmt->tableSpace)); - appendStringInfoChar(str, ' '); - } - - deparseWhereClause(str, index_stmt->whereClause); - - removeTrailingSpace(str); -} - -static void deparseAlterOpFamilyStmt(StringInfo str, AlterOpFamilyStmt *alter_op_family_stmt) -{ - appendStringInfoString(str, "ALTER OPERATOR FAMILY "); - deparseAnyName(str, alter_op_family_stmt->opfamilyname); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(alter_op_family_stmt->amname)); - appendStringInfoChar(str, ' '); - - if (alter_op_family_stmt->isDrop) - appendStringInfoString(str, "DROP "); - else - appendStringInfoString(str, "ADD "); - - deparseOpclassItemList(str, alter_op_family_stmt->items); -} - -static void deparsePrepareStmt(StringInfo str, PrepareStmt *prepare_stmt) -{ - ListCell *lc = NULL; - - appendStringInfoString(str, "PREPARE "); - deparseColId(str, prepare_stmt->name); - if (list_length(prepare_stmt->argtypes) > 0) - { - appendStringInfoChar(str, '('); - deparseTypeList(str, prepare_stmt->argtypes); - appendStringInfoChar(str, ')'); - } - appendStringInfoString(str, " AS "); - deparsePreparableStmt(str, prepare_stmt->query); -} - -static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "EXECUTE "); - appendStringInfoString(str, quote_identifier(execute_stmt->name)); - if (list_length(execute_stmt->params) > 0) - { - appendStringInfoChar(str, '('); - deparseExprList(str, execute_stmt->params); - appendStringInfoChar(str, ')'); - } -} - -static void deparseDeallocateStmt(StringInfo str, DeallocateStmt *deallocate_stmt) -{ - appendStringInfoString(str, "DEALLOCATE "); - if (deallocate_stmt->name != NULL) - appendStringInfoString(str, quote_identifier(deallocate_stmt->name)); - else - appendStringInfoString(str, "ALL"); -} - -// "AlterOptRoleElem" in gram.y -static void deparseAlterRoleElem(StringInfo str, DefElem *def_elem) -{ - if (strcmp(def_elem->defname, "password") == 0) - { - appendStringInfoString(str, "PASSWORD "); - if (def_elem->arg == NULL) - { - appendStringInfoString(str, "NULL"); - } - else if (IsA(def_elem->arg, ParamRef)) - { - deparseParamRef(str, castNode(ParamRef, def_elem->arg)); - } - else if (IsA(def_elem->arg, String)) - { - deparseStringLiteral(str, strVal(def_elem->arg)); - } - else - { - Assert(false); - } - } - else if (strcmp(def_elem->defname, "connectionlimit") == 0) - { - appendStringInfo(str, "CONNECTION LIMIT %d", intVal(def_elem->arg)); - } - else if (strcmp(def_elem->defname, "validUntil") == 0) - { - appendStringInfoString(str, "VALID UNTIL "); - deparseStringLiteral(str, strVal(def_elem->arg)); - } - else if (strcmp(def_elem->defname, "superuser") == 0 && boolVal(def_elem->arg)) - { - appendStringInfoString(str, "SUPERUSER"); - } - else if (strcmp(def_elem->defname, "superuser") == 0 && !boolVal(def_elem->arg)) - { - appendStringInfoString(str, "NOSUPERUSER"); - } - else if (strcmp(def_elem->defname, "createrole") == 0 && boolVal(def_elem->arg)) - { - appendStringInfoString(str, "CREATEROLE"); - } - else if (strcmp(def_elem->defname, "createrole") == 0 && !boolVal(def_elem->arg)) - { - appendStringInfoString(str, "NOCREATEROLE"); - } - else if (strcmp(def_elem->defname, "isreplication") == 0 && boolVal(def_elem->arg)) - { - appendStringInfoString(str, "REPLICATION"); - } - else if (strcmp(def_elem->defname, "isreplication") == 0 && !boolVal(def_elem->arg)) - { - appendStringInfoString(str, "NOREPLICATION"); - } - else if (strcmp(def_elem->defname, "createdb") == 0 && boolVal(def_elem->arg)) - { - appendStringInfoString(str, "CREATEDB"); - } - else if (strcmp(def_elem->defname, "createdb") == 0 && !boolVal(def_elem->arg)) - { - appendStringInfoString(str, "NOCREATEDB"); - } - else if (strcmp(def_elem->defname, "canlogin") == 0 && boolVal(def_elem->arg)) - { - appendStringInfoString(str, "LOGIN"); - } - else if (strcmp(def_elem->defname, "canlogin") == 0 && !boolVal(def_elem->arg)) - { - appendStringInfoString(str, "NOLOGIN"); - } - else if (strcmp(def_elem->defname, "bypassrls") == 0 && boolVal(def_elem->arg)) - { - appendStringInfoString(str, "BYPASSRLS"); - } - else if (strcmp(def_elem->defname, "bypassrls") == 0 && !boolVal(def_elem->arg)) - { - appendStringInfoString(str, "NOBYPASSRLS"); - } - else if (strcmp(def_elem->defname, "inherit") == 0 && boolVal(def_elem->arg)) - { - appendStringInfoString(str, "INHERIT"); - } - else if (strcmp(def_elem->defname, "inherit") == 0 && !boolVal(def_elem->arg)) - { - appendStringInfoString(str, "NOINHERIT"); - } - else - { - Assert(false); - } -} - -// "CreateOptRoleElem" in gram.y -static void deparseCreateRoleElem(StringInfo str, DefElem *def_elem) -{ - if (strcmp(def_elem->defname, "sysid") == 0) - { - appendStringInfo(str, "SYSID %d", intVal(def_elem->arg)); - } - else if (strcmp(def_elem->defname, "adminmembers") == 0) - { - appendStringInfoString(str, "ADMIN "); - deparseRoleList(str, castNode(List, def_elem->arg)); - } - else if (strcmp(def_elem->defname, "rolemembers") == 0) - { - appendStringInfoString(str, "ROLE "); - deparseRoleList(str, castNode(List, def_elem->arg)); - } - else if (strcmp(def_elem->defname, "addroleto") == 0) - { - appendStringInfoString(str, "IN ROLE "); - deparseRoleList(str, castNode(List, def_elem->arg)); - } - else - { - deparseAlterRoleElem(str, def_elem); - } -} - -static void deparseCreatePLangStmt(StringInfo str, CreatePLangStmt *create_p_lang_stmt) -{ - appendStringInfoString(str, "CREATE "); - - if (create_p_lang_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); - - if (create_p_lang_stmt->pltrusted) - appendStringInfoString(str, "TRUSTED "); - - appendStringInfoString(str, "LANGUAGE "); - deparseNonReservedWordOrSconst(str, create_p_lang_stmt->plname); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "HANDLER "); - deparseHandlerName(str, create_p_lang_stmt->plhandler); - appendStringInfoChar(str, ' '); - - if (create_p_lang_stmt->plinline) - { - appendStringInfoString(str, "INLINE "); - deparseHandlerName(str, create_p_lang_stmt->plinline); - appendStringInfoChar(str, ' '); - } - - if (create_p_lang_stmt->plvalidator) - { - appendStringInfoString(str, "VALIDATOR "); - deparseHandlerName(str, create_p_lang_stmt->plvalidator); - appendStringInfoChar(str, ' '); - } - - removeTrailingSpace(str); -} - -static void deparseCreateRoleStmt(StringInfo str, CreateRoleStmt *create_role_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "CREATE "); - - switch (create_role_stmt->stmt_type) - { - case ROLESTMT_ROLE: - appendStringInfoString(str, "ROLE "); - break; - case ROLESTMT_USER: - appendStringInfoString(str, "USER "); - break; - case ROLESTMT_GROUP: - appendStringInfoString(str, "GROUP "); - break; - } - - appendStringInfoString(str, quote_identifier(create_role_stmt->role)); - appendStringInfoChar(str, ' '); - - if (create_role_stmt->options != NULL) - { - appendStringInfoString(str, "WITH "); - foreach (lc, create_role_stmt->options) - { - deparseCreateRoleElem(str, castNode(DefElem, lfirst(lc))); - appendStringInfoChar(str, ' '); - } - } - - removeTrailingSpace(str); -} - -static void deparseAlterRoleStmt(StringInfo str, AlterRoleStmt *alter_role_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "ALTER "); - - if (list_length(alter_role_stmt->options) == 1 && strcmp(castNode(DefElem, linitial(alter_role_stmt->options))->defname, "rolemembers") == 0) - { - appendStringInfoString(str, "GROUP "); - deparseRoleSpec(str, alter_role_stmt->role); - appendStringInfoChar(str, ' '); - - if (alter_role_stmt->action == 1) - { - appendStringInfoString(str, "ADD USER "); - } - else if (alter_role_stmt->action == -1) - { - appendStringInfoString(str, "DROP USER "); - } - else - { - Assert(false); - } - - deparseRoleList(str, castNode(List, castNode(DefElem, linitial(alter_role_stmt->options))->arg)); - } - else - { - appendStringInfoString(str, "ROLE "); - deparseRoleSpec(str, alter_role_stmt->role); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "WITH "); - foreach (lc, alter_role_stmt->options) - { - deparseAlterRoleElem(str, castNode(DefElem, lfirst(lc))); - appendStringInfoChar(str, ' '); - } - } - - removeTrailingSpace(str); -} - -static void deparseDeclareCursorStmt(StringInfo str, DeclareCursorStmt *declare_cursor_stmt) -{ - appendStringInfoString(str, "DECLARE "); - appendStringInfoString(str, quote_identifier(declare_cursor_stmt->portalname)); - appendStringInfoChar(str, ' '); - - if (declare_cursor_stmt->options & CURSOR_OPT_BINARY) - appendStringInfoString(str, "BINARY "); - - if (declare_cursor_stmt->options & CURSOR_OPT_SCROLL) - appendStringInfoString(str, "SCROLL "); - - if (declare_cursor_stmt->options & CURSOR_OPT_NO_SCROLL) - appendStringInfoString(str, "NO SCROLL "); - - if (declare_cursor_stmt->options & CURSOR_OPT_INSENSITIVE) - appendStringInfoString(str, "INSENSITIVE "); - - appendStringInfoString(str, "CURSOR "); - - if (declare_cursor_stmt->options & CURSOR_OPT_HOLD) - appendStringInfoString(str, "WITH HOLD "); - - appendStringInfoString(str, "FOR "); - - deparseSelectStmt(str, castNode(SelectStmt, declare_cursor_stmt->query)); -} - -static void deparseFetchStmt(StringInfo str, FetchStmt *fetch_stmt) -{ - if (fetch_stmt->ismove) - appendStringInfoString(str, "MOVE "); - else - appendStringInfoString(str, "FETCH "); - - switch (fetch_stmt->direction) - { - case FETCH_FORWARD: - if (fetch_stmt->howMany == 1) - { - // Default - } - else if (fetch_stmt->howMany == FETCH_ALL) - { - appendStringInfoString(str, "ALL "); - } - else - { - appendStringInfo(str, "FORWARD %ld ", fetch_stmt->howMany); - } - break; - case FETCH_BACKWARD: - if (fetch_stmt->howMany == 1) - { - appendStringInfoString(str, "PRIOR "); - } - else if (fetch_stmt->howMany == FETCH_ALL) - { - appendStringInfoString(str, "BACKWARD ALL "); - } - else - { - appendStringInfo(str, "BACKWARD %ld ", fetch_stmt->howMany); - } - break; - case FETCH_ABSOLUTE: - if (fetch_stmt->howMany == 1) - { - appendStringInfoString(str, "FIRST "); - } - else if (fetch_stmt->howMany == -1) - { - appendStringInfoString(str, "LAST "); - } - else - { - appendStringInfo(str, "ABSOLUTE %ld ", fetch_stmt->howMany); - } - break; - case FETCH_RELATIVE: - appendStringInfo(str, "RELATIVE %ld ", fetch_stmt->howMany); - } - - appendStringInfoString(str, fetch_stmt->portalname); -} - -static void deparseAlterDefaultPrivilegesStmt(StringInfo str, AlterDefaultPrivilegesStmt *alter_default_privileges_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "ALTER DEFAULT PRIVILEGES "); - - foreach (lc, alter_default_privileges_stmt->options) - { - DefElem *defelem = castNode(DefElem, lfirst(lc)); - if (strcmp(defelem->defname, "schemas") == 0) - { - appendStringInfoString(str, "IN SCHEMA "); - deparseNameList(str, castNode(List, defelem->arg)); - appendStringInfoChar(str, ' '); - } - else if (strcmp(defelem->defname, "roles") == 0) - { - appendStringInfoString(str, "FOR ROLE "); - deparseRoleList(str, castNode(List, defelem->arg)); - appendStringInfoChar(str, ' '); - } - else - { - // No other DefElems are supported - Assert(false); - } - } - - deparseGrantStmt(str, alter_default_privileges_stmt->action); -} - -static void deparseReindexStmt(StringInfo str, ReindexStmt *reindex_stmt) -{ - appendStringInfoString(str, "REINDEX "); - - deparseUtilityOptionList(str, reindex_stmt->params); - - switch (reindex_stmt->kind) - { - case REINDEX_OBJECT_INDEX: - appendStringInfoString(str, "INDEX "); - break; - case REINDEX_OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); - break; - case REINDEX_OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); - break; - case REINDEX_OBJECT_SYSTEM: - appendStringInfoString(str, "SYSTEM "); - break; - case REINDEX_OBJECT_DATABASE: - appendStringInfoString(str, "DATABASE "); - break; - } - - if (reindex_stmt->relation != NULL) - { - deparseRangeVar(str, reindex_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - } - else if (reindex_stmt->name != NULL) - { - appendStringInfoString(str, quote_identifier(reindex_stmt->name)); - } -} - -static void deparseRuleStmt(StringInfo str, RuleStmt* rule_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "CREATE "); - - if (rule_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); - - appendStringInfoString(str, "RULE "); - appendStringInfoString(str, quote_identifier(rule_stmt->rulename)); - appendStringInfoString(str, " AS ON "); - - switch (rule_stmt->event) - { - case CMD_UNKNOWN: - case CMD_UTILITY: - case CMD_NOTHING: - // Not supported here - Assert(false); - break; - case CMD_SELECT: - appendStringInfoString(str, "SELECT "); - break; - case CMD_UPDATE: - appendStringInfoString(str, "UPDATE "); - break; - case CMD_INSERT: - appendStringInfoString(str, "INSERT "); - break; - case CMD_DELETE: - appendStringInfoString(str, "DELETE "); - break; - case CMD_MERGE: - appendStringInfoString(str, "MERGE "); - break; - } - - appendStringInfoString(str, "TO "); - deparseRangeVar(str, rule_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - deparseWhereClause(str, rule_stmt->whereClause); - - appendStringInfoString(str, "DO "); - - if (rule_stmt->instead) - appendStringInfoString(str, "INSTEAD "); - - if (list_length(rule_stmt->actions) == 0) - { - appendStringInfoString(str, "NOTHING"); - } - else if (list_length(rule_stmt->actions) == 1) - { - deparseRuleActionStmt(str, linitial(rule_stmt->actions)); - } - else - { - appendStringInfoChar(str, '('); - foreach (lc, rule_stmt->actions) - { - deparseRuleActionStmt(str, lfirst(lc)); - if (lnext(rule_stmt->actions, lc)) - appendStringInfoString(str, "; "); - } - appendStringInfoChar(str, ')'); - } -} - -static void deparseNotifyStmt(StringInfo str, NotifyStmt *notify_stmt) -{ - appendStringInfoString(str, "NOTIFY "); - appendStringInfoString(str, quote_identifier(notify_stmt->conditionname)); - - if (notify_stmt->payload != NULL) - { - appendStringInfoString(str, ", "); - deparseStringLiteral(str, notify_stmt->payload); - } -} - -static void deparseListenStmt(StringInfo str, ListenStmt *listen_stmt) -{ - appendStringInfoString(str, "LISTEN "); - appendStringInfoString(str, quote_identifier(listen_stmt->conditionname)); -} - -static void deparseUnlistenStmt(StringInfo str, UnlistenStmt *unlisten_stmt) -{ - appendStringInfoString(str, "UNLISTEN "); - if (unlisten_stmt->conditionname == NULL) - appendStringInfoString(str, "*"); - else - appendStringInfoString(str, quote_identifier(unlisten_stmt->conditionname)); -} - -static void deparseCreateSeqStmt(StringInfo str, CreateSeqStmt *create_seq_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "CREATE "); - - deparseOptTemp(str, create_seq_stmt->sequence->relpersistence); - - appendStringInfoString(str, "SEQUENCE "); - - if (create_seq_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); - - deparseRangeVar(str, create_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - deparseOptSeqOptList(str, create_seq_stmt->options); - - removeTrailingSpace(str); -} - -static void deparseAlterFunctionStmt(StringInfo str, AlterFunctionStmt *alter_function_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "ALTER "); - - switch (alter_function_stmt->objtype) - { - case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - break; - case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - break; - case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - break; - default: - // Not supported here - Assert(false); - break; - } - - deparseFunctionWithArgtypes(str, alter_function_stmt->func); - appendStringInfoChar(str, ' '); - - foreach (lc, alter_function_stmt->actions) - { - deparseCommonFuncOptItem(str, castNode(DefElem, lfirst(lc))); - if (lnext(alter_function_stmt->actions, lc)) - appendStringInfoChar(str, ' '); - } -} - -static void deparseTruncateStmt(StringInfo str, TruncateStmt *truncate_stmt) -{ - appendStringInfoString(str, "TRUNCATE "); - - deparseRelationExprList(str, truncate_stmt->relations); - appendStringInfoChar(str, ' '); - - if (truncate_stmt->restart_seqs) - appendStringInfoString(str, "RESTART IDENTITY "); - - deparseOptDropBehavior(str, truncate_stmt->behavior); - - removeTrailingSpace(str); -} - -static void deparseCreateEventTrigStmt(StringInfo str, CreateEventTrigStmt *create_event_trig_stmt) -{ - ListCell *lc = NULL; - ListCell *lc2 = NULL; - - appendStringInfoString(str, "CREATE EVENT TRIGGER "); - appendStringInfoString(str, quote_identifier(create_event_trig_stmt->trigname)); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "ON "); - appendStringInfoString(str, quote_identifier(create_event_trig_stmt->eventname)); - appendStringInfoChar(str, ' '); - - if (create_event_trig_stmt->whenclause) - { - appendStringInfoString(str, "WHEN "); - - foreach (lc, create_event_trig_stmt->whenclause) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - List *l = castNode(List, def_elem->arg); - appendStringInfoString(str, quote_identifier(def_elem->defname)); - appendStringInfoString(str, " IN ("); - foreach (lc2, l) - { - deparseStringLiteral(str, strVal(lfirst(lc2))); - if (lnext(l, lc2)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); - if (lnext(create_event_trig_stmt->whenclause, lc)) - appendStringInfoString(str, " AND "); - } - - appendStringInfoChar(str, ' '); - } - - appendStringInfoString(str, "EXECUTE FUNCTION "); - deparseFuncName(str, create_event_trig_stmt->funcname); - appendStringInfoString(str, "()"); -} - -static void deparseAlterEventTrigStmt(StringInfo str, AlterEventTrigStmt *alter_event_trig_stmt) -{ - appendStringInfoString(str, "ALTER EVENT TRIGGER "); - appendStringInfoString(str, quote_identifier(alter_event_trig_stmt->trigname)); - appendStringInfoChar(str, ' '); - - switch (alter_event_trig_stmt->tgenabled) - { - case TRIGGER_FIRES_ON_ORIGIN: - appendStringInfoString(str, "ENABLE"); - break; - case TRIGGER_FIRES_ON_REPLICA: - appendStringInfoString(str, "ENABLE REPLICA"); - break; - case TRIGGER_FIRES_ALWAYS: - appendStringInfoString(str, "ENABLE ALWAYS"); - break; - case TRIGGER_DISABLED: - appendStringInfoString(str, "DISABLE"); - break; - } -} - -static void deparseRefreshMatViewStmt(StringInfo str, RefreshMatViewStmt *refresh_mat_view_stmt) -{ - appendStringInfoString(str, "REFRESH MATERIALIZED VIEW "); - - if (refresh_mat_view_stmt->concurrent) - appendStringInfoString(str, "CONCURRENTLY "); - - deparseRangeVar(str, refresh_mat_view_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - if (refresh_mat_view_stmt->skipData) - appendStringInfoString(str, "WITH NO DATA "); - - removeTrailingSpace(str); -} - -static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt) -{ - switch (replica_identity_stmt->identity_type) - { - case REPLICA_IDENTITY_NOTHING: - appendStringInfoString(str, "NOTHING "); - break; - case REPLICA_IDENTITY_FULL: - appendStringInfoString(str, "FULL "); - break; - case REPLICA_IDENTITY_DEFAULT: - appendStringInfoString(str, "DEFAULT "); - break; - case REPLICA_IDENTITY_INDEX: - Assert(replica_identity_stmt->name != NULL); - appendStringInfoString(str, "USING INDEX "); - appendStringInfoString(str, quote_identifier(replica_identity_stmt->name)); - break; - } -} - -static void deparseCreatePolicyStmt(StringInfo str, CreatePolicyStmt *create_policy_stmt) -{ - ListCell *lc = NULL; - - appendStringInfoString(str, "CREATE POLICY "); - deparseColId(str, create_policy_stmt->policy_name); - appendStringInfoString(str, " ON "); - deparseRangeVar(str, create_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - if (!create_policy_stmt->permissive) - appendStringInfoString(str, "AS RESTRICTIVE "); - - if (strcmp(create_policy_stmt->cmd_name, "all") == 0) - Assert(true); // Default - else if (strcmp(create_policy_stmt->cmd_name, "select") == 0) - appendStringInfoString(str, "FOR SELECT "); - else if (strcmp(create_policy_stmt->cmd_name, "insert") == 0) - appendStringInfoString(str, "FOR INSERT "); - else if (strcmp(create_policy_stmt->cmd_name, "update") == 0) - appendStringInfoString(str, "FOR UPDATE "); - else if (strcmp(create_policy_stmt->cmd_name, "delete") == 0) - appendStringInfoString(str, "FOR DELETE "); - else - Assert(false); - - appendStringInfoString(str, "TO "); - deparseRoleList(str, create_policy_stmt->roles); - appendStringInfoChar(str, ' '); - - if (create_policy_stmt->qual != NULL) - { - appendStringInfoString(str, "USING ("); - deparseExpr(str, create_policy_stmt->qual); - appendStringInfoString(str, ") "); - } - - if (create_policy_stmt->with_check != NULL) - { - appendStringInfoString(str, "WITH CHECK ("); - deparseExpr(str, create_policy_stmt->with_check); - appendStringInfoString(str, ") "); - } -} - -static void deparseAlterPolicyStmt(StringInfo str, AlterPolicyStmt *alter_policy_stmt) -{ - appendStringInfoString(str, "ALTER POLICY "); - appendStringInfoString(str, quote_identifier(alter_policy_stmt->policy_name)); - appendStringInfoString(str, " ON "); - deparseRangeVar(str, alter_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - if (list_length(alter_policy_stmt->roles) > 0) - { - appendStringInfoString(str, "TO "); - deparseRoleList(str, alter_policy_stmt->roles); - appendStringInfoChar(str, ' '); - } - - if (alter_policy_stmt->qual != NULL) - { - appendStringInfoString(str, "USING ("); - deparseExpr(str, alter_policy_stmt->qual); - appendStringInfoString(str, ") "); - } - - if (alter_policy_stmt->with_check != NULL) - { - appendStringInfoString(str, "WITH CHECK ("); - deparseExpr(str, alter_policy_stmt->with_check); - appendStringInfoString(str, ") "); - } -} - -static void deparseCreateTableSpaceStmt(StringInfo str, CreateTableSpaceStmt *create_table_space_stmt) -{ - appendStringInfoString(str, "CREATE TABLESPACE "); - deparseColId(str, create_table_space_stmt->tablespacename); - appendStringInfoChar(str, ' '); - - if (create_table_space_stmt->owner != NULL) - { - appendStringInfoString(str, "OWNER "); - deparseRoleSpec(str, create_table_space_stmt->owner); - appendStringInfoChar(str, ' '); - } - - appendStringInfoString(str, "LOCATION "); - - if (create_table_space_stmt->location != NULL) - deparseStringLiteral(str, create_table_space_stmt->location); - else - appendStringInfoString(str, "''"); - - appendStringInfoChar(str, ' '); - - deparseOptWith(str, create_table_space_stmt->options); - - removeTrailingSpace(str); -} - -static void deparseCreateTransformStmt(StringInfo str, CreateTransformStmt *create_transform_stmt) -{ - appendStringInfoString(str, "CREATE "); - if (create_transform_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); - - appendStringInfoString(str, "TRANSFORM FOR "); - deparseTypeName(str, create_transform_stmt->type_name); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "LANGUAGE "); - appendStringInfoString(str, quote_identifier(create_transform_stmt->lang)); - appendStringInfoChar(str, ' '); - - appendStringInfoChar(str, '('); - - if (create_transform_stmt->fromsql) - { - appendStringInfoString(str, "FROM SQL WITH FUNCTION "); - deparseFunctionWithArgtypes(str, create_transform_stmt->fromsql); - } - - if (create_transform_stmt->fromsql && create_transform_stmt->tosql) - appendStringInfoString(str, ", "); - - if (create_transform_stmt->tosql) - { - appendStringInfoString(str, "TO SQL WITH FUNCTION "); - deparseFunctionWithArgtypes(str, create_transform_stmt->tosql); - } - - appendStringInfoChar(str, ')'); -} - -static void deparseCreateAmStmt(StringInfo str, CreateAmStmt *create_am_stmt) -{ - appendStringInfoString(str, "CREATE ACCESS METHOD "); - appendStringInfoString(str, quote_identifier(create_am_stmt->amname)); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "TYPE "); - switch (create_am_stmt->amtype) - { - case AMTYPE_INDEX: - appendStringInfoString(str, "INDEX "); - break; - case AMTYPE_TABLE: - appendStringInfoString(str, "TABLE "); - break; - } - - appendStringInfoString(str, "HANDLER "); - deparseHandlerName(str, create_am_stmt->handler_name); -} - -static void deparsePublicationObjectList(StringInfo str, List *pubobjects) { - const ListCell *lc; - foreach(lc, pubobjects) { - PublicationObjSpec *obj = lfirst(lc); - - switch (obj->pubobjtype) { - case PUBLICATIONOBJ_TABLE: - appendStringInfoString(str, "TABLE "); - deparseRangeVar(str, obj->pubtable->relation, DEPARSE_NODE_CONTEXT_NONE); - - if (obj->pubtable->columns) - { - appendStringInfoChar(str, '('); - deparseColumnList(str, obj->pubtable->columns); - appendStringInfoChar(str, ')'); - } - - if (obj->pubtable->whereClause) - { - appendStringInfoString(str, " WHERE ("); - deparseExpr(str, obj->pubtable->whereClause); - appendStringInfoString(str, ")"); - } - - break; - case PUBLICATIONOBJ_TABLES_IN_SCHEMA: - appendStringInfoString(str, "TABLES IN SCHEMA "); - appendStringInfoString(str, quote_identifier(obj->name)); - break; - case PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA: - appendStringInfoString(str, "TABLES IN SCHEMA CURRENT_SCHEMA"); - break; - case PUBLICATIONOBJ_CONTINUATION: - // This should be unreachable, the parser merges these before we can even get here. - Assert(false); - break; - } - - if (lnext(pubobjects, lc)) { - appendStringInfoString(str, ", "); - } - } -} - -static void deparseCreatePublicationStmt(StringInfo str, CreatePublicationStmt *create_publication_stmt) -{ - ListCell *lc = NULL; - - appendStringInfoString(str, "CREATE PUBLICATION "); - appendStringInfoString(str, quote_identifier(create_publication_stmt->pubname)); - appendStringInfoChar(str, ' '); - - if (list_length(create_publication_stmt->pubobjects) > 0) - { - appendStringInfoString(str, "FOR "); - deparsePublicationObjectList(str, create_publication_stmt->pubobjects); - appendStringInfoChar(str, ' '); - } - else if (create_publication_stmt->for_all_tables) - { - appendStringInfoString(str, "FOR ALL TABLES "); - } - - deparseOptDefinition(str, create_publication_stmt->options); - removeTrailingSpace(str); -} - -static void deparseAlterPublicationStmt(StringInfo str, AlterPublicationStmt *alter_publication_stmt) -{ - appendStringInfoString(str, "ALTER PUBLICATION "); - deparseColId(str, alter_publication_stmt->pubname); - appendStringInfoChar(str, ' '); - - if (list_length(alter_publication_stmt->pubobjects) > 0) - { - switch (alter_publication_stmt->action) - { - case AP_SetObjects: - appendStringInfoString(str, "SET "); - break; - case AP_AddObjects: - appendStringInfoString(str, "ADD "); - break; - case AP_DropObjects: - appendStringInfoString(str, "DROP "); - break; - } - - deparsePublicationObjectList(str, alter_publication_stmt->pubobjects); - } - else if (list_length(alter_publication_stmt->options) > 0) - { - appendStringInfoString(str, "SET "); - deparseDefinition(str, alter_publication_stmt->options); - } - else - { - Assert(false); - } -} - -static void deparseAlterSeqStmt(StringInfo str, AlterSeqStmt *alter_seq_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "ALTER SEQUENCE "); - - if (alter_seq_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - - deparseRangeVar(str, alter_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - deparseSeqOptList(str, alter_seq_stmt->options); - - removeTrailingSpace(str); -} - -static void deparseAlterSystemStmt(StringInfo str, AlterSystemStmt *alter_system_stmt) -{ - appendStringInfoString(str, "ALTER SYSTEM "); - deparseVariableSetStmt(str, alter_system_stmt->setstmt); -} - -static void deparseCommentStmt(StringInfo str, CommentStmt *comment_stmt) -{ - ListCell *lc; - List *l; - - appendStringInfoString(str, "COMMENT ON "); - - switch (comment_stmt->objtype) - { - case OBJECT_COLUMN: - appendStringInfoString(str, "COLUMN "); - break; - case OBJECT_INDEX: - appendStringInfoString(str, "INDEX "); - break; - case OBJECT_SEQUENCE: - appendStringInfoString(str, "SEQUENCE "); - break; - case OBJECT_STATISTIC_EXT: - appendStringInfoString(str, "STATISTICS "); - break; - case OBJECT_TABLE: - appendStringInfoString(str, "TABLE "); - break; - case OBJECT_VIEW: - appendStringInfoString(str, "VIEW "); - break; - case OBJECT_MATVIEW: - appendStringInfoString(str, "MATERIALIZED VIEW "); - break; - case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); - break; - case OBJECT_CONVERSION: - appendStringInfoString(str, "CONVERSION "); - break; - case OBJECT_FOREIGN_TABLE: - appendStringInfoString(str, "FOREIGN TABLE "); - break; - case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); - break; - case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); - break; - case OBJECT_TSPARSER: - appendStringInfoString(str, "TEXT SEARCH PARSER "); - break; - case OBJECT_TSTEMPLATE: - appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); - break; - case OBJECT_ACCESS_METHOD: - appendStringInfoString(str, "ACCESS METHOD "); - break; - case OBJECT_DATABASE: - appendStringInfoString(str, "DATABASE "); - break; - case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, "EVENT TRIGGER "); - break; - case OBJECT_EXTENSION: - appendStringInfoString(str, "EXTENSION "); - break; - case OBJECT_FDW: - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); - break; - case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); - break; - case OBJECT_PUBLICATION: - appendStringInfoString(str, "PUBLICATION "); - break; - case OBJECT_ROLE: - appendStringInfoString(str, "ROLE "); - break; - case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); - break; - case OBJECT_FOREIGN_SERVER: - appendStringInfoString(str, "SERVER "); - break; - case OBJECT_SUBSCRIPTION: - appendStringInfoString(str, "SUBSCRIPTION "); - break; - case OBJECT_TABLESPACE: - appendStringInfoString(str, "TABLESPACE "); - break; - case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); - break; - case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); - break; - case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); - break; - case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - break; - case OBJECT_OPERATOR: - appendStringInfoString(str, "OPERATOR "); - break; - case OBJECT_TABCONSTRAINT: - appendStringInfoString(str, "CONSTRAINT "); - break; - case OBJECT_DOMCONSTRAINT: - appendStringInfoString(str, "CONSTRAINT "); - break; - case OBJECT_POLICY: - appendStringInfoString(str, "POLICY "); - break; - case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - break; - case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - break; - case OBJECT_RULE: - appendStringInfoString(str, "RULE "); - break; - case OBJECT_TRANSFORM: - appendStringInfoString(str, "TRANSFORM "); - break; - case OBJECT_TRIGGER: - appendStringInfoString(str, "TRIGGER "); - break; - case OBJECT_OPCLASS: - appendStringInfoString(str, "OPERATOR CLASS "); - break; - case OBJECT_OPFAMILY: - appendStringInfoString(str, "OPERATOR FAMILY "); - break; - case OBJECT_LARGEOBJECT: - appendStringInfoString(str, "LARGE OBJECT "); - break; - case OBJECT_CAST: - appendStringInfoString(str, "CAST "); - break; - default: - // No other cases are supported in the parser - Assert(false); - break; - } - - switch (comment_stmt->objtype) - { - case OBJECT_COLUMN: - case OBJECT_INDEX: - case OBJECT_SEQUENCE: - case OBJECT_STATISTIC_EXT: - case OBJECT_TABLE: - case OBJECT_VIEW: - case OBJECT_MATVIEW: - case OBJECT_COLLATION: - case OBJECT_CONVERSION: - case OBJECT_FOREIGN_TABLE: - case OBJECT_TSCONFIGURATION: - case OBJECT_TSDICTIONARY: - case OBJECT_TSPARSER: - case OBJECT_TSTEMPLATE: - deparseAnyName(str, castNode(List, comment_stmt->object)); - break; - case OBJECT_ACCESS_METHOD: - case OBJECT_DATABASE: - case OBJECT_EVENT_TRIGGER: - case OBJECT_EXTENSION: - case OBJECT_FDW: - case OBJECT_LANGUAGE: - case OBJECT_PUBLICATION: - case OBJECT_ROLE: - case OBJECT_SCHEMA: - case OBJECT_FOREIGN_SERVER: - case OBJECT_SUBSCRIPTION: - case OBJECT_TABLESPACE: - appendStringInfoString(str, quote_identifier(strVal(comment_stmt->object))); - break; - case OBJECT_TYPE: - case OBJECT_DOMAIN: - deparseTypeName(str, castNode(TypeName, comment_stmt->object)); - break; - case OBJECT_AGGREGATE: - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); - break; - case OBJECT_FUNCTION: - case OBJECT_PROCEDURE: - case OBJECT_ROUTINE: - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); - break; - case OBJECT_OPERATOR: - deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); - break; - case OBJECT_TABCONSTRAINT: - case OBJECT_POLICY: - case OBJECT_RULE: - case OBJECT_TRIGGER: - l = castNode(List, comment_stmt->object); - appendStringInfoString(str, quote_identifier(strVal(llast(l)))); - appendStringInfoString(str, " ON "); - deparseAnyNameSkipLast(str, l); - break; - case OBJECT_DOMCONSTRAINT: - l = castNode(List, comment_stmt->object); - appendStringInfoString(str, quote_identifier(strVal(llast(l)))); - appendStringInfoString(str, " ON DOMAIN "); - deparseTypeName(str, linitial(l)); - break; - case OBJECT_TRANSFORM: - l = castNode(List, comment_stmt->object); - appendStringInfoString(str, "FOR "); - deparseTypeName(str, castNode(TypeName, linitial(l))); - appendStringInfoString(str, " LANGUAGE "); - appendStringInfoString(str, quote_identifier(strVal(lsecond(l)))); - break; - case OBJECT_OPCLASS: - case OBJECT_OPFAMILY: - l = castNode(List, comment_stmt->object); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); - break; - case OBJECT_LARGEOBJECT: - deparseValue(str, (union ValUnion *) comment_stmt->object, DEPARSE_NODE_CONTEXT_NONE); - break; - case OBJECT_CAST: - l = castNode(List, comment_stmt->object); - appendStringInfoChar(str, '('); - deparseTypeName(str, castNode(TypeName, linitial(l))); - appendStringInfoString(str, " AS "); - deparseTypeName(str, castNode(TypeName, lsecond(l))); - appendStringInfoChar(str, ')'); - break; - default: - // No other cases are supported in the parser - Assert(false); - break; - } - - appendStringInfoString(str, " IS "); - - if (comment_stmt->comment != NULL) - deparseStringLiteral(str, comment_stmt->comment); - else - appendStringInfoString(str, "NULL"); -} - -static void deparseStatsElem(StringInfo str, StatsElem *stats_elem) -{ - // only one of stats_elem->name or stats_elem->expr can be non-null - if (stats_elem->name) - appendStringInfoString(str, stats_elem->name); - else if (stats_elem->expr) - { - appendStringInfoChar(str, '('); - deparseExpr(str, stats_elem->expr); - appendStringInfoChar(str, ')'); - } -} - -static void deparseCreateStatsStmt(StringInfo str, CreateStatsStmt *create_stats_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "CREATE STATISTICS "); - - if (create_stats_stmt->if_not_exists) - appendStringInfoString(str, "IF NOT EXISTS "); - - deparseAnyName(str, create_stats_stmt->defnames); - appendStringInfoChar(str, ' '); - - if (list_length(create_stats_stmt->stat_types) > 0) - { - appendStringInfoChar(str, '('); - deparseNameList(str, create_stats_stmt->stat_types); - appendStringInfoString(str, ") "); - } - - appendStringInfoString(str, "ON "); - foreach (lc, create_stats_stmt->exprs) - { - deparseStatsElem(str, lfirst(lc)); - if (lnext(create_stats_stmt->exprs, lc)) - appendStringInfoString(str, ", "); - } - - appendStringInfoString(str, " FROM "); - deparseFromList(str, create_stats_stmt->relations); -} - -static void deparseAlterCollationStmt(StringInfo str, AlterCollationStmt *alter_collation_stmt) -{ - appendStringInfoString(str, "ALTER COLLATION "); - deparseAnyName(str, alter_collation_stmt->collname); - appendStringInfoString(str, " REFRESH VERSION"); -} - -static void deparseAlterDatabaseStmt(StringInfo str, AlterDatabaseStmt *alter_database_stmt) -{ - appendStringInfoString(str, "ALTER DATABASE "); - deparseColId(str, alter_database_stmt->dbname); - appendStringInfoChar(str, ' '); - deparseCreatedbOptList(str, alter_database_stmt->options); - removeTrailingSpace(str); -} - -static void deparseAlterDatabaseSetStmt(StringInfo str, AlterDatabaseSetStmt *alter_database_set_stmt) -{ - appendStringInfoString(str, "ALTER DATABASE "); - deparseColId(str, alter_database_set_stmt->dbname); - appendStringInfoChar(str, ' '); - deparseVariableSetStmt(str, alter_database_set_stmt->setstmt); -} - -static void deparseAlterStatsStmt(StringInfo str, AlterStatsStmt *alter_stats_stmt) -{ - appendStringInfoString(str, "ALTER STATISTICS "); - - if (alter_stats_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - - deparseAnyName(str, alter_stats_stmt->defnames); - appendStringInfoChar(str, ' '); - - appendStringInfo(str, "SET STATISTICS %d", alter_stats_stmt->stxstattarget); -} - -static void deparseAlterTSDictionaryStmt(StringInfo str, AlterTSDictionaryStmt *alter_ts_dictionary_stmt) -{ - appendStringInfoString(str, "ALTER TEXT SEARCH DICTIONARY "); - - deparseAnyName(str, alter_ts_dictionary_stmt->dictname); - appendStringInfoChar(str, ' '); - - deparseDefinition(str, alter_ts_dictionary_stmt->options); -} - -static void deparseAlterTSConfigurationStmt(StringInfo str, AlterTSConfigurationStmt *alter_ts_configuration_stmt) -{ - ListCell *lc = NULL; - - appendStringInfoString(str, "ALTER TEXT SEARCH CONFIGURATION "); - deparseAnyName(str, alter_ts_configuration_stmt->cfgname); - appendStringInfoChar(str, ' '); - - switch (alter_ts_configuration_stmt->kind) - { - case ALTER_TSCONFIG_ADD_MAPPING: - appendStringInfoString(str, "ADD MAPPING FOR "); - deparseNameList(str, alter_ts_configuration_stmt->tokentype); - appendStringInfoString(str, " WITH "); - deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); - break; - case ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN: - appendStringInfoString(str, "ALTER MAPPING FOR "); - deparseNameList(str, alter_ts_configuration_stmt->tokentype); - appendStringInfoString(str, " WITH "); - deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); - break; - case ALTER_TSCONFIG_REPLACE_DICT: - appendStringInfoString(str, "ALTER MAPPING REPLACE "); - deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); - appendStringInfoString(str, " WITH "); - deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); - break; - case ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN: - appendStringInfoString(str, "ALTER MAPPING FOR "); - deparseNameList(str, alter_ts_configuration_stmt->tokentype); - appendStringInfoString(str, " REPLACE "); - deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); - appendStringInfoString(str, " WITH "); - deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); - break; - case ALTER_TSCONFIG_DROP_MAPPING: - appendStringInfoString(str, "DROP MAPPING "); - if (alter_ts_configuration_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - appendStringInfoString(str, "FOR "); - deparseNameList(str, alter_ts_configuration_stmt->tokentype); - break; - } -} - -static void deparseVariableShowStmt(StringInfo str, VariableShowStmt *variable_show_stmt) -{ - appendStringInfoString(str, "SHOW "); - - if (strcmp(variable_show_stmt->name, "timezone") == 0) - appendStringInfoString(str, "TIME ZONE"); - else if (strcmp(variable_show_stmt->name, "transaction_isolation") == 0) - appendStringInfoString(str, "TRANSACTION ISOLATION LEVEL"); - else if (strcmp(variable_show_stmt->name, "session_authorization") == 0) - appendStringInfoString(str, "SESSION AUTHORIZATION"); - else if (strcmp(variable_show_stmt->name, "all") == 0) - appendStringInfoString(str, "SESSION ALL"); - else - appendStringInfoString(str, quote_identifier(variable_show_stmt->name)); -} - -static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample) -{ - deparseRangeVar(str, castNode(RangeVar, range_table_sample->relation), DEPARSE_NODE_CONTEXT_NONE); - - appendStringInfoString(str, " TABLESAMPLE "); - - deparseFuncName(str, range_table_sample->method); - appendStringInfoChar(str, '('); - deparseExprList(str, range_table_sample->args); - appendStringInfoString(str, ") "); - - if (range_table_sample->repeatable != NULL) - { - appendStringInfoString(str, "REPEATABLE ("); - deparseExpr(str, range_table_sample->repeatable); - appendStringInfoString(str, ") "); - } - - removeTrailingSpace(str); -} - -static void deparseCreateSubscriptionStmt(StringInfo str, CreateSubscriptionStmt *create_subscription_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "CREATE SUBSCRIPTION "); - appendStringInfoString(str, quote_identifier(create_subscription_stmt->subname)); - - appendStringInfoString(str, " CONNECTION "); - if (create_subscription_stmt->conninfo != NULL) - deparseStringLiteral(str, create_subscription_stmt->conninfo); - else - appendStringInfoString(str, "''"); - - appendStringInfoString(str, " PUBLICATION "); - - foreach(lc, create_subscription_stmt->publication) - { - deparseColLabel(str, strVal(lfirst(lc))); - if (lnext(create_subscription_stmt->publication, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ' '); - - deparseOptDefinition(str, create_subscription_stmt->options); - removeTrailingSpace(str); -} - -static void deparseAlterSubscriptionStmt(StringInfo str, AlterSubscriptionStmt *alter_subscription_stmt) -{ - ListCell *lc; - - appendStringInfoString(str, "ALTER SUBSCRIPTION "); - appendStringInfoString(str, quote_identifier(alter_subscription_stmt->subname)); - appendStringInfoChar(str, ' '); - - switch (alter_subscription_stmt->kind) - { - case ALTER_SUBSCRIPTION_OPTIONS: - appendStringInfoString(str, "SET "); - deparseDefinition(str, alter_subscription_stmt->options); - break; - case ALTER_SUBSCRIPTION_SKIP: - appendStringInfoString(str, "SKIP "); - deparseDefinition(str, alter_subscription_stmt->options); - break; - case ALTER_SUBSCRIPTION_CONNECTION: - appendStringInfoString(str, "CONNECTION "); - deparseStringLiteral(str, alter_subscription_stmt->conninfo); - appendStringInfoChar(str, ' '); - break; - case ALTER_SUBSCRIPTION_REFRESH: - appendStringInfoString(str, "REFRESH PUBLICATION "); - deparseOptDefinition(str, alter_subscription_stmt->options); - break; - case ALTER_SUBSCRIPTION_ADD_PUBLICATION: - appendStringInfoString(str, "ADD PUBLICATION "); - foreach(lc, alter_subscription_stmt->publication) - { - deparseColLabel(str, strVal(lfirst(lc))); - if (lnext(alter_subscription_stmt->publication, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ' '); - deparseOptDefinition(str, alter_subscription_stmt->options); - break; - case ALTER_SUBSCRIPTION_DROP_PUBLICATION: - appendStringInfoString(str, "DROP PUBLICATION "); - foreach(lc, alter_subscription_stmt->publication) - { - deparseColLabel(str, strVal(lfirst(lc))); - if (lnext(alter_subscription_stmt->publication, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ' '); - deparseOptDefinition(str, alter_subscription_stmt->options); - break; - case ALTER_SUBSCRIPTION_SET_PUBLICATION: - appendStringInfoString(str, "SET PUBLICATION "); - foreach(lc, alter_subscription_stmt->publication) - { - deparseColLabel(str, strVal(lfirst(lc))); - if (lnext(alter_subscription_stmt->publication, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ' '); - deparseOptDefinition(str, alter_subscription_stmt->options); - break; - case ALTER_SUBSCRIPTION_ENABLED: - Assert(list_length(alter_subscription_stmt->options) == 1); - DefElem *defelem = castNode(DefElem, linitial(alter_subscription_stmt->options)); - Assert(strcmp(defelem->defname, "enabled") == 0); - if (optBooleanValue(defelem->arg)) - { - appendStringInfoString(str, " ENABLE "); - } - else - { - appendStringInfoString(str, " DISABLE "); - } - break; - } - - removeTrailingSpace(str); -} - -static void deparseDropSubscriptionStmt(StringInfo str, DropSubscriptionStmt *drop_subscription_stmt) -{ - appendStringInfoString(str, "DROP SUBSCRIPTION "); - - if (drop_subscription_stmt->missing_ok) - appendStringInfoString(str, "IF EXISTS "); - - appendStringInfoString(str, drop_subscription_stmt->subname); -} - -static void deparseCallStmt(StringInfo str, CallStmt *call_stmt) -{ - appendStringInfoString(str, "CALL "); - deparseFuncCall(str, call_stmt->funccall); -} - -static void deparseAlterOwnerStmt(StringInfo str, AlterOwnerStmt *alter_owner_stmt) -{ - List *l = NULL; - - appendStringInfoString(str, "ALTER "); - - switch (alter_owner_stmt->objectType) - { - case OBJECT_AGGREGATE: - appendStringInfoString(str, "AGGREGATE "); - deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); - break; - case OBJECT_COLLATION: - appendStringInfoString(str, "COLLATION "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); - break; - case OBJECT_CONVERSION: - appendStringInfoString(str, "CONVERSION "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); - break; - case OBJECT_DATABASE: - appendStringInfoString(str, "DATABASE "); - deparseColId(str, strVal(alter_owner_stmt->object)); - break; - case OBJECT_DOMAIN: - appendStringInfoString(str, "DOMAIN "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); - break; - case OBJECT_FUNCTION: - appendStringInfoString(str, "FUNCTION "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); - break; - case OBJECT_LANGUAGE: - appendStringInfoString(str, "LANGUAGE "); - deparseColId(str, strVal(alter_owner_stmt->object)); - break; - case OBJECT_LARGEOBJECT: - appendStringInfoString(str, "LARGE OBJECT "); - deparseNumericOnly(str, (union ValUnion *) alter_owner_stmt->object); - break; - case OBJECT_OPERATOR: - appendStringInfoString(str, "OPERATOR "); - deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); - break; - case OBJECT_OPCLASS: - l = castNode(List, alter_owner_stmt->object); - appendStringInfoString(str, "OPERATOR CLASS "); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - deparseColId(str, strVal(linitial(l))); - break; - case OBJECT_OPFAMILY: - l = castNode(List, alter_owner_stmt->object); - appendStringInfoString(str, "OPERATOR FAMILY "); - deparseAnyNameSkipFirst(str, l); - appendStringInfoString(str, " USING "); - deparseColId(str, strVal(linitial(l))); - break; - case OBJECT_PROCEDURE: - appendStringInfoString(str, "PROCEDURE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); - break; - case OBJECT_ROUTINE: - appendStringInfoString(str, "ROUTINE "); - deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); - break; - case OBJECT_SCHEMA: - appendStringInfoString(str, "SCHEMA "); - deparseColId(str, strVal(alter_owner_stmt->object)); - break; - case OBJECT_TYPE: - appendStringInfoString(str, "TYPE "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); - break; - case OBJECT_TABLESPACE: - appendStringInfoString(str, "TABLESPACE "); - deparseColId(str, strVal(alter_owner_stmt->object)); - break; - case OBJECT_STATISTIC_EXT: - appendStringInfoString(str, "STATISTICS "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); - break; - case OBJECT_TSDICTIONARY: - appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); - break; - case OBJECT_TSCONFIGURATION: - appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); - deparseAnyName(str, castNode(List, alter_owner_stmt->object)); - break; - case OBJECT_FDW: - appendStringInfoString(str, "FOREIGN DATA WRAPPER "); - deparseColId(str, strVal(alter_owner_stmt->object)); - break; - case OBJECT_FOREIGN_SERVER: - appendStringInfoString(str, "SERVER "); - deparseColId(str, strVal(alter_owner_stmt->object)); - break; - case OBJECT_EVENT_TRIGGER: - appendStringInfoString(str, "EVENT TRIGGER "); - deparseColId(str, strVal(alter_owner_stmt->object)); - break; - case OBJECT_PUBLICATION: - appendStringInfoString(str, "PUBLICATION "); - deparseColId(str, strVal(alter_owner_stmt->object)); - break; - case OBJECT_SUBSCRIPTION: - appendStringInfoString(str, "SUBSCRIPTION "); - deparseColId(str, strVal(alter_owner_stmt->object)); - break; - default: - Assert(false); - } - - appendStringInfoString(str, " OWNER TO "); - deparseRoleSpec(str, alter_owner_stmt->newowner); -} - -// "operator_def_list" in gram.y -static void deparseOperatorDefList(StringInfo str, List *defs) -{ - ListCell *lc = NULL; - - foreach (lc, defs) - { - DefElem *def_elem = castNode(DefElem, lfirst(lc)); - appendStringInfoString(str, quote_identifier(def_elem->defname)); - appendStringInfoString(str, " = "); - if (def_elem->arg != NULL) - deparseDefArg(str, def_elem->arg, true); - else - appendStringInfoString(str, "NONE"); - - if (lnext(defs, lc)) - appendStringInfoString(str, ", "); - } -} - -static void deparseAlterOperatorStmt(StringInfo str, AlterOperatorStmt *alter_operator_stmt) -{ - appendStringInfoString(str, "ALTER OPERATOR "); - deparseOperatorWithArgtypes(str, alter_operator_stmt->opername); - appendStringInfoString(str, " SET ("); - deparseOperatorDefList(str, alter_operator_stmt->options); - appendStringInfoChar(str, ')'); -} - -static void deparseAlterTypeStmt(StringInfo str, AlterTypeStmt *alter_type_stmt) -{ - appendStringInfoString(str, "ALTER TYPE "); - deparseAnyName(str, alter_type_stmt->typeName); - appendStringInfoString(str, " SET ("); - deparseOperatorDefList(str, alter_type_stmt->options); - appendStringInfoChar(str, ')'); -} - -static void deparseDropOwnedStmt(StringInfo str, DropOwnedStmt *drop_owned_stmt) -{ - appendStringInfoString(str, "DROP OWNED BY "); - deparseRoleList(str, drop_owned_stmt->roles); - appendStringInfoChar(str, ' '); - deparseOptDropBehavior(str, drop_owned_stmt->behavior); - removeTrailingSpace(str); -} - -static void deparseReassignOwnedStmt(StringInfo str, ReassignOwnedStmt *reassigned_owned_stmt) -{ - appendStringInfoString(str, "REASSIGN OWNED BY "); - - deparseRoleList(str, reassigned_owned_stmt->roles); - appendStringInfoChar(str, ' '); - - appendStringInfoString(str, "TO "); - deparseRoleSpec(str, reassigned_owned_stmt->newrole); -} - -static void deparseClosePortalStmt(StringInfo str, ClosePortalStmt *close_portal_stmt) -{ - appendStringInfoString(str, "CLOSE "); - if (close_portal_stmt->portalname != NULL) - { - appendStringInfoString(str, quote_identifier(close_portal_stmt->portalname)); - } - else - { - appendStringInfoString(str, "ALL"); - } -} - -static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr) -{ - appendStringInfoString(str, "CURRENT OF "); - appendStringInfoString(str, quote_identifier(current_of_expr->cursor_name)); -} - -static void deparseCreateTrigStmt(StringInfo str, CreateTrigStmt *create_trig_stmt) -{ - ListCell *lc; - bool skip_events_or = true; - - appendStringInfoString(str, "CREATE "); - if (create_trig_stmt->replace) - appendStringInfoString(str, "OR REPLACE "); - if (create_trig_stmt->isconstraint) - appendStringInfoString(str, "CONSTRAINT "); - appendStringInfoString(str, "TRIGGER "); - - appendStringInfoString(str, quote_identifier(create_trig_stmt->trigname)); - appendStringInfoChar(str, ' '); - - switch (create_trig_stmt->timing) - { - case TRIGGER_TYPE_BEFORE: - appendStringInfoString(str, "BEFORE "); - break; - case TRIGGER_TYPE_AFTER: - appendStringInfoString(str, "AFTER "); - break; - case TRIGGER_TYPE_INSTEAD: - appendStringInfoString(str, "INSTEAD OF "); - break; - default: - Assert(false); - } - - if (TRIGGER_FOR_INSERT(create_trig_stmt->events)) - { - appendStringInfoString(str, "INSERT "); - skip_events_or = false; - } - if (TRIGGER_FOR_DELETE(create_trig_stmt->events)) - { - if (!skip_events_or) - appendStringInfoString(str, "OR "); - appendStringInfoString(str, "DELETE "); - skip_events_or = false; - } - if (TRIGGER_FOR_UPDATE(create_trig_stmt->events)) - { - if (!skip_events_or) - appendStringInfoString(str, "OR "); - appendStringInfoString(str, "UPDATE "); - if (list_length(create_trig_stmt->columns) > 0) - { - appendStringInfoString(str, "OF "); - deparseColumnList(str, create_trig_stmt->columns); - appendStringInfoChar(str, ' '); - } - skip_events_or = false; - } - if (TRIGGER_FOR_TRUNCATE(create_trig_stmt->events)) - { - if (!skip_events_or) - appendStringInfoString(str, "OR "); - appendStringInfoString(str, "TRUNCATE "); - } - - appendStringInfoString(str, "ON "); - deparseRangeVar(str, create_trig_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - - if (create_trig_stmt->transitionRels != NULL) - { - appendStringInfoString(str, "REFERENCING "); - foreach(lc, create_trig_stmt->transitionRels) - { - deparseTriggerTransition(str, castNode(TriggerTransition, lfirst(lc))); - appendStringInfoChar(str, ' '); - } - } - - if (create_trig_stmt->constrrel != NULL) - { - appendStringInfoString(str, "FROM "); - deparseRangeVar(str, create_trig_stmt->constrrel, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - } - - if (create_trig_stmt->deferrable) - appendStringInfoString(str, "DEFERRABLE "); - - if (create_trig_stmt->initdeferred) - appendStringInfoString(str, "INITIALLY DEFERRED "); - - if (create_trig_stmt->row) - appendStringInfoString(str, "FOR EACH ROW "); - - if (create_trig_stmt->whenClause) - { - appendStringInfoString(str, "WHEN ("); - deparseExpr(str, create_trig_stmt->whenClause); - appendStringInfoString(str, ") "); - } - - appendStringInfoString(str, "EXECUTE FUNCTION "); - deparseFuncName(str, create_trig_stmt->funcname); - appendStringInfoChar(str, '('); - foreach(lc, create_trig_stmt->args) - { - deparseStringLiteral(str, strVal(lfirst(lc))); - if (lnext(create_trig_stmt->args, lc)) - appendStringInfoString(str, ", "); - } - appendStringInfoChar(str, ')'); -} - -static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition) -{ - if (trigger_transition->isNew) - appendStringInfoString(str, "NEW "); - else - appendStringInfoString(str, "OLD "); - - if (trigger_transition->isTable) - appendStringInfoString(str, "TABLE "); - else - appendStringInfoString(str, "ROW "); - - appendStringInfoString(str, quote_identifier(trigger_transition->name)); -} - -static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr) -{ - switch (xml_expr->op) - { - case IS_XMLCONCAT: /* XMLCONCAT(args) */ - appendStringInfoString(str, "xmlconcat("); - deparseExprList(str, xml_expr->args); - appendStringInfoChar(str, ')'); - break; - case IS_XMLELEMENT: /* XMLELEMENT(name, xml_attributes, args) */ - appendStringInfoString(str, "xmlelement(name "); - appendStringInfoString(str, quote_identifier(xml_expr->name)); - if (xml_expr->named_args != NULL) - { - appendStringInfoString(str, ", xmlattributes("); - deparseXmlAttributeList(str, xml_expr->named_args); - appendStringInfoString(str, ")"); - } - if (xml_expr->args != NULL) - { - appendStringInfoString(str, ", "); - deparseExprList(str, xml_expr->args); - } - appendStringInfoString(str, ")"); - break; - case IS_XMLFOREST: /* XMLFOREST(xml_attributes) */ - appendStringInfoString(str, "xmlforest("); - deparseXmlAttributeList(str, xml_expr->named_args); - appendStringInfoChar(str, ')'); - break; - case IS_XMLPARSE: /* XMLPARSE(text, is_doc, preserve_ws) */ - Assert(list_length(xml_expr->args) == 2); - appendStringInfoString(str, "xmlparse("); - switch (xml_expr->xmloption) - { - case XMLOPTION_DOCUMENT: - appendStringInfoString(str, "document "); - break; - case XMLOPTION_CONTENT: - appendStringInfoString(str, "content "); - break; - default: - Assert(false); - } - deparseExpr(str, linitial(xml_expr->args)); - appendStringInfoChar(str, ')'); - break; - case IS_XMLPI: /* XMLPI(name [, args]) */ - appendStringInfoString(str, "xmlpi(name "); - appendStringInfoString(str, quote_identifier(xml_expr->name)); - if (xml_expr->args != NULL) - { - appendStringInfoString(str, ", "); - deparseExpr(str, linitial(xml_expr->args)); - } - appendStringInfoChar(str, ')'); - break; - case IS_XMLROOT: /* XMLROOT(xml, version, standalone) */ - appendStringInfoString(str, "xmlroot("); - deparseExpr(str, linitial(xml_expr->args)); - appendStringInfoString(str, ", version "); - if (castNode(A_Const, lsecond(xml_expr->args))->isnull) - appendStringInfoString(str, "NO VALUE"); - else - deparseExpr(str, lsecond(xml_expr->args)); - if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_YES) - appendStringInfoString(str, ", STANDALONE YES"); - else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO) - appendStringInfoString(str, ", STANDALONE NO"); - else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO_VALUE) - appendStringInfoString(str, ", STANDALONE NO VALUE"); - appendStringInfoChar(str, ')'); - break; - case IS_XMLSERIALIZE: /* XMLSERIALIZE(is_document, xmlval) */ - // These are represented as XmlSerialize in raw parse trees - Assert(false); - break; - case IS_DOCUMENT: /* xmlval IS DOCUMENT */ - Assert(list_length(xml_expr->args) == 1); - deparseExpr(str, linitial(xml_expr->args)); - appendStringInfoString(str, " IS DOCUMENT"); - break; - } -} - -static void deparseRangeTableFuncCol(StringInfo str, RangeTableFuncCol* range_table_func_col) -{ - appendStringInfoString(str, quote_identifier(range_table_func_col->colname)); - appendStringInfoChar(str, ' '); - - if (range_table_func_col->for_ordinality) - { - appendStringInfoString(str, "FOR ORDINALITY "); - } - else - { - deparseTypeName(str, range_table_func_col->typeName); - appendStringInfoChar(str, ' '); - - if (range_table_func_col->colexpr) - { - appendStringInfoString(str, "PATH "); - deparseExpr(str, range_table_func_col->colexpr); - appendStringInfoChar(str, ' '); - } - - if (range_table_func_col->coldefexpr) - { - appendStringInfoString(str, "DEFAULT "); - deparseExpr(str, range_table_func_col->coldefexpr); - appendStringInfoChar(str, ' '); - } - - if (range_table_func_col->is_not_null) - appendStringInfoString(str, "NOT NULL "); - } - - removeTrailingSpace(str); -} - -static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func) -{ - ListCell *lc; - - if (range_table_func->lateral) - appendStringInfoString(str, "LATERAL "); - - appendStringInfoString(str, "xmltable("); - if (range_table_func->namespaces) - { - appendStringInfoString(str, "xmlnamespaces("); - deparseXmlNamespaceList(str, range_table_func->namespaces); - appendStringInfoString(str, "), "); - } - - appendStringInfoChar(str, '('); - deparseExpr(str, range_table_func->rowexpr); - appendStringInfoChar(str, ')'); - - appendStringInfoString(str, " PASSING "); - deparseExpr(str, range_table_func->docexpr); - - appendStringInfoString(str, " COLUMNS "); - foreach(lc, range_table_func->columns) - { - deparseRangeTableFuncCol(str, castNode(RangeTableFuncCol, lfirst(lc))); - if (lnext(range_table_func->columns, lc)) - appendStringInfoString(str, ", "); - } - - appendStringInfoString(str, ") "); - - if (range_table_func->alias) - { - appendStringInfoString(str, "AS "); - deparseAlias(str, range_table_func->alias); - } - - removeTrailingSpace(str); -} - -static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize) -{ - appendStringInfoString(str, "xmlserialize("); - switch (xml_serialize->xmloption) - { - case XMLOPTION_DOCUMENT: - appendStringInfoString(str, "document "); - break; - case XMLOPTION_CONTENT: - appendStringInfoString(str, "content "); - break; - default: - Assert(false); - } - deparseExpr(str, xml_serialize->expr); - appendStringInfoString(str, " AS "); - deparseTypeName(str, xml_serialize->typeName); - appendStringInfoString(str, ")"); -} - -static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func) -{ - appendStringInfoString(str, "GROUPING("); - deparseExprList(str, grouping_func->args); - appendStringInfoChar(str, ')'); -} - -static void deparseClusterStmt(StringInfo str, ClusterStmt *cluster_stmt) -{ - appendStringInfoString(str, "CLUSTER "); - - deparseUtilityOptionList(str, cluster_stmt->params); - - if (cluster_stmt->relation != NULL) - { - deparseRangeVar(str, cluster_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); - appendStringInfoChar(str, ' '); - } - - if (cluster_stmt->indexname != NULL) - { - appendStringInfoString(str, "USING "); - appendStringInfoString(str, quote_identifier(cluster_stmt->indexname)); - appendStringInfoChar(str, ' '); - } - - removeTrailingSpace(str); -} - -static void deparseValue(StringInfo str, union ValUnion *value, DeparseNodeContext context) -{ - if (!value) { - appendStringInfoString(str, "NULL"); - return; - } - - switch (nodeTag(value)) - { - case T_Integer: - case T_Float: - deparseNumericOnly(str, value); - break; - case T_Boolean: - appendStringInfoString(str, value->boolval.boolval ? "true" : "false"); - break; - case T_String: - if (context == DEPARSE_NODE_CONTEXT_IDENTIFIER) { - appendStringInfoString(str, quote_identifier(value->sval.sval)); - } else if (context == DEPARSE_NODE_CONTEXT_CONSTANT) { - deparseStringLiteral(str, value->sval.sval); - } else { - appendStringInfoString(str, value->sval.sval); - } - break; - case T_BitString: - if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'x') - { - appendStringInfoChar(str, 'x'); - deparseStringLiteral(str, value->sval.sval + 1); - } - else if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'b') - { - appendStringInfoChar(str, 'b'); - deparseStringLiteral(str, value->sval.sval + 1); - } - else - { - Assert(false); - } - break; - default: - elog(ERROR, "deparse: unrecognized value node type: %d", - (int) nodeTag(value)); - break; - } -} - -// "PrepareableStmt" in gram.y -static void deparsePreparableStmt(StringInfo str, Node *node) -{ - switch (nodeTag(node)) - { - case T_SelectStmt: - deparseSelectStmt(str, castNode(SelectStmt, node)); - break; - case T_InsertStmt: - deparseInsertStmt(str, castNode(InsertStmt, node)); - break; - case T_UpdateStmt: - deparseUpdateStmt(str, castNode(UpdateStmt, node)); - break; - case T_DeleteStmt: - deparseDeleteStmt(str, castNode(DeleteStmt, node)); - break; - case T_MergeStmt: - deparseMergeStmt(str, castNode(MergeStmt, node)); - break; - default: - Assert(false); - } -} - -// "RuleActionStmt" in gram.y -static void deparseRuleActionStmt(StringInfo str, Node *node) -{ - switch (nodeTag(node)) - { - case T_SelectStmt: - deparseSelectStmt(str, castNode(SelectStmt, node)); - break; - case T_InsertStmt: - deparseInsertStmt(str, castNode(InsertStmt, node)); - break; - case T_UpdateStmt: - deparseUpdateStmt(str, castNode(UpdateStmt, node)); - break; - case T_DeleteStmt: - deparseDeleteStmt(str, castNode(DeleteStmt, node)); - break; - case T_NotifyStmt: - deparseNotifyStmt(str, castNode(NotifyStmt, node)); - break; - default: - Assert(false); - } -} - -// "ExplainableStmt" in gram.y -static void deparseExplainableStmt(StringInfo str, Node *node) -{ - switch (nodeTag(node)) - { - case T_SelectStmt: - deparseSelectStmt(str, castNode(SelectStmt, node)); - break; - case T_InsertStmt: - deparseInsertStmt(str, castNode(InsertStmt, node)); - break; - case T_UpdateStmt: - deparseUpdateStmt(str, castNode(UpdateStmt, node)); - break; - case T_DeleteStmt: - deparseDeleteStmt(str, castNode(DeleteStmt, node)); - break; - case T_DeclareCursorStmt: - deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); - break; - case T_CreateTableAsStmt: - deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); - break; - case T_RefreshMatViewStmt: - deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); - break; - case T_ExecuteStmt: - deparseExecuteStmt(str, castNode(ExecuteStmt, node)); - break; - case T_MergeStmt: - deparseMergeStmt(str, castNode(MergeStmt, node)); - break; - default: - Assert(false); - } -} - -// "schema_stmt" in gram.y -static void deparseSchemaStmt(StringInfo str, Node *node) -{ - switch (nodeTag(node)) - { - case T_CreateStmt: - deparseCreateStmt(str, castNode(CreateStmt, node), false); - break; - case T_IndexStmt: - deparseIndexStmt(str, castNode(IndexStmt, node)); - break; - case T_CreateSeqStmt: - deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); - break; - case T_CreateTrigStmt: - deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); - break; - case T_GrantStmt: - deparseGrantStmt(str, castNode(GrantStmt, node)); - break; - case T_ViewStmt: - deparseViewStmt(str, castNode(ViewStmt, node)); - break; - default: - Assert(false); - } -} - -// "stmt" in gram.y -static void deparseStmt(StringInfo str, Node *node) -{ - // Note the following grammar names are missing in the list, because they - // get mapped to other node types: - // - // - AlterForeignTableStmt (=> AlterTableStmt) - // - AlterGroupStmt (=> AlterRoleStmt) - // - AlterCompositeTypeStmt (=> AlterTableStmt) - // - AnalyzeStmt (=> VacuumStmt) - // - CreateGroupStmt (=> CreateRoleStmt) - // - CreateMatViewStmt (=> CreateTableAsStmt) - // - CreateUserStmt (=> CreateRoleStmt) - // - DropCastStmt (=> DropStmt) - // - DropOpClassStmt (=> DropStmt) - // - DropOpFamilyStmt (=> DropStmt) - // - DropPLangStmt (=> DropPLangStmt) - // - DropTransformStmt (=> DropStmt) - // - RemoveAggrStmt (=> DropStmt) - // - RemoveFuncStmt (=> DropStmt) - // - RemoveOperStmt (=> DropStmt) - // - RevokeStmt (=> GrantStmt) - // - RevokeRoleStmt (=> GrantRoleStmt) - // - VariableResetStmt (=> VariableSetStmt) - // - // And the following grammar names error out in the parser: - // - CreateAssertionStmt (not supported yet) - switch (nodeTag(node)) - { - case T_AlterEventTrigStmt: - deparseAlterEventTrigStmt(str, castNode(AlterEventTrigStmt, node)); - break; - case T_AlterCollationStmt: - deparseAlterCollationStmt(str, castNode(AlterCollationStmt, node)); - break; - case T_AlterDatabaseStmt: - deparseAlterDatabaseStmt(str, castNode(AlterDatabaseStmt, node)); - break; - case T_AlterDatabaseSetStmt: - deparseAlterDatabaseSetStmt(str, castNode(AlterDatabaseSetStmt, node)); - break; - case T_AlterDefaultPrivilegesStmt: - deparseAlterDefaultPrivilegesStmt(str, castNode(AlterDefaultPrivilegesStmt, node)); - break; - case T_AlterDomainStmt: - deparseAlterDomainStmt(str, castNode(AlterDomainStmt, node)); - break; - case T_AlterEnumStmt: - deparseAlterEnumStmt(str, castNode(AlterEnumStmt, node)); - break; - case T_AlterExtensionStmt: - deparseAlterExtensionStmt(str, castNode(AlterExtensionStmt, node)); - break; - case T_AlterExtensionContentsStmt: - deparseAlterExtensionContentsStmt(str, castNode(AlterExtensionContentsStmt, node)); - break; - case T_AlterFdwStmt: - deparseAlterFdwStmt(str, castNode(AlterFdwStmt, node)); - break; - case T_AlterForeignServerStmt: - deparseAlterForeignServerStmt(str, castNode(AlterForeignServerStmt, node)); - break; - case T_AlterFunctionStmt: - deparseAlterFunctionStmt(str, castNode(AlterFunctionStmt, node)); - break; - case T_AlterObjectDependsStmt: - deparseAlterObjectDependsStmt(str, castNode(AlterObjectDependsStmt, node)); - break; - case T_AlterObjectSchemaStmt: - deparseAlterObjectSchemaStmt(str, castNode(AlterObjectSchemaStmt, node)); - break; - case T_AlterOwnerStmt: - deparseAlterOwnerStmt(str, castNode(AlterOwnerStmt, node)); - break; - case T_AlterOperatorStmt: - deparseAlterOperatorStmt(str, castNode(AlterOperatorStmt, node)); - break; - case T_AlterTypeStmt: - deparseAlterTypeStmt(str, castNode(AlterTypeStmt, node)); - break; - case T_AlterPolicyStmt: - deparseAlterPolicyStmt(str, castNode(AlterPolicyStmt, node)); - break; - case T_AlterSeqStmt: - deparseAlterSeqStmt(str, castNode(AlterSeqStmt, node)); - break; - case T_AlterSystemStmt: - deparseAlterSystemStmt(str, castNode(AlterSystemStmt, node)); - break; - case T_AlterTableMoveAllStmt: - deparseAlterTableMoveAllStmt(str, castNode(AlterTableMoveAllStmt, node)); - break; - case T_AlterTableStmt: - deparseAlterTableStmt(str, castNode(AlterTableStmt, node)); - break; - case T_AlterTableSpaceOptionsStmt: // "AlterTblSpcStmt" in gram.y - deparseAlterTableSpaceOptionsStmt(str, castNode(AlterTableSpaceOptionsStmt, node)); - break; - case T_AlterPublicationStmt: - deparseAlterPublicationStmt(str, castNode(AlterPublicationStmt, node)); - break; - case T_AlterRoleSetStmt: - deparseAlterRoleSetStmt(str, castNode(AlterRoleSetStmt, node)); - break; - case T_AlterRoleStmt: - deparseAlterRoleStmt(str, castNode(AlterRoleStmt, node)); - break; - case T_AlterSubscriptionStmt: - deparseAlterSubscriptionStmt(str, castNode(AlterSubscriptionStmt, node)); - break; - case T_AlterStatsStmt: - deparseAlterStatsStmt(str, castNode(AlterStatsStmt, node)); - break; - case T_AlterTSConfigurationStmt: - deparseAlterTSConfigurationStmt(str, castNode(AlterTSConfigurationStmt, node)); - break; - case T_AlterTSDictionaryStmt: - deparseAlterTSDictionaryStmt(str, castNode(AlterTSDictionaryStmt, node)); - break; - case T_AlterUserMappingStmt: - deparseAlterUserMappingStmt(str, castNode(AlterUserMappingStmt, node)); - break; - case T_CallStmt: - deparseCallStmt(str, castNode(CallStmt, node)); - break; - case T_CheckPointStmt: - deparseCheckPointStmt(str, castNode(CheckPointStmt, node)); - break; - case T_ClosePortalStmt: - deparseClosePortalStmt(str, castNode(ClosePortalStmt, node)); - break; - case T_ClusterStmt: - deparseClusterStmt(str, castNode(ClusterStmt, node)); - break; - case T_CommentStmt: - deparseCommentStmt(str, castNode(CommentStmt, node)); - break; - case T_ConstraintsSetStmt: - deparseConstraintsSetStmt(str, castNode(ConstraintsSetStmt, node)); - break; - case T_CopyStmt: - deparseCopyStmt(str, castNode(CopyStmt, node)); - break; - case T_CreateAmStmt: - deparseCreateAmStmt(str, castNode(CreateAmStmt, node)); - break; - case T_CreateTableAsStmt: // "CreateAsStmt" in gram.y - deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); - break; - case T_CreateCastStmt: - deparseCreateCastStmt(str, castNode(CreateCastStmt, node)); - break; - case T_CreateConversionStmt: - deparseCreateConversionStmt(str, castNode(CreateConversionStmt, node)); - break; - case T_CreateDomainStmt: - deparseCreateDomainStmt(str, castNode(CreateDomainStmt, node)); - break; - case T_CreateExtensionStmt: - deparseCreateExtensionStmt(str, castNode(CreateExtensionStmt, node)); - break; - case T_CreateFdwStmt: - deparseCreateFdwStmt(str, castNode(CreateFdwStmt, node)); - break; - case T_CreateForeignServerStmt: - deparseCreateForeignServerStmt(str, castNode(CreateForeignServerStmt, node)); - break; - case T_CreateForeignTableStmt: - deparseCreateForeignTableStmt(str, castNode(CreateForeignTableStmt, node)); - break; - case T_CreateFunctionStmt: - deparseCreateFunctionStmt(str, castNode(CreateFunctionStmt, node)); - break; - case T_CreateOpClassStmt: - deparseCreateOpClassStmt(str, castNode(CreateOpClassStmt, node)); - break; - case T_CreateOpFamilyStmt: - deparseCreateOpFamilyStmt(str, castNode(CreateOpFamilyStmt, node)); - break; - case T_CreatePublicationStmt: - deparseCreatePublicationStmt(str, castNode(CreatePublicationStmt, node)); - break; - case T_AlterOpFamilyStmt: - deparseAlterOpFamilyStmt(str, castNode(AlterOpFamilyStmt, node)); - break; - case T_CreatePolicyStmt: - deparseCreatePolicyStmt(str, castNode(CreatePolicyStmt, node)); - break; - case T_CreatePLangStmt: - deparseCreatePLangStmt(str, castNode(CreatePLangStmt, node)); - break; - case T_CreateSchemaStmt: - deparseCreateSchemaStmt(str, castNode(CreateSchemaStmt, node)); - break; - case T_CreateSeqStmt: - deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); - break; - case T_CreateStmt: - deparseCreateStmt(str, castNode(CreateStmt, node), false); - break; - case T_CreateSubscriptionStmt: - deparseCreateSubscriptionStmt(str, castNode(CreateSubscriptionStmt, node)); - break; - case T_CreateStatsStmt: - deparseCreateStatsStmt(str, castNode(CreateStatsStmt, node)); - break; - case T_CreateTableSpaceStmt: - deparseCreateTableSpaceStmt(str, castNode(CreateTableSpaceStmt, node)); - break; - case T_CreateTransformStmt: - deparseCreateTransformStmt(str, castNode(CreateTransformStmt, node)); - break; - case T_CreateTrigStmt: - deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); - break; - case T_CreateEventTrigStmt: - deparseCreateEventTrigStmt(str, castNode(CreateEventTrigStmt, node)); - break; - case T_CreateRoleStmt: - deparseCreateRoleStmt(str, castNode(CreateRoleStmt, node)); - break; - case T_CreateUserMappingStmt: - deparseCreateUserMappingStmt(str, castNode(CreateUserMappingStmt, node)); - break; - case T_CreatedbStmt: - deparseCreatedbStmt(str, castNode(CreatedbStmt, node)); - break; - case T_DeallocateStmt: - deparseDeallocateStmt(str, castNode(DeallocateStmt, node)); - break; - case T_DeclareCursorStmt: - deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); - break; - case T_DefineStmt: - deparseDefineStmt(str, castNode(DefineStmt, node)); - break; - case T_DeleteStmt: - deparseDeleteStmt(str, castNode(DeleteStmt, node)); - break; - case T_DiscardStmt: - deparseDiscardStmt(str, castNode(DiscardStmt, node)); - break; - case T_DoStmt: - deparseDoStmt(str, castNode(DoStmt, node)); - break; - case T_DropOwnedStmt: - deparseDropOwnedStmt(str, castNode(DropOwnedStmt, node)); - break; - case T_DropStmt: - deparseDropStmt(str, castNode(DropStmt, node)); - break; - case T_DropSubscriptionStmt: - deparseDropSubscriptionStmt(str, castNode(DropSubscriptionStmt, node)); - break; - case T_DropTableSpaceStmt: - deparseDropTableSpaceStmt(str, castNode(DropTableSpaceStmt, node)); - break; - case T_DropRoleStmt: - deparseDropRoleStmt(str, castNode(DropRoleStmt, node)); - break; - case T_DropUserMappingStmt: - deparseDropUserMappingStmt(str, castNode(DropUserMappingStmt, node)); - break; - case T_DropdbStmt: - deparseDropdbStmt(str, castNode(DropdbStmt, node)); - break; - case T_ExecuteStmt: - deparseExecuteStmt(str, castNode(ExecuteStmt, node)); - break; - case T_ExplainStmt: - deparseExplainStmt(str, castNode(ExplainStmt, node)); - break; - case T_FetchStmt: - deparseFetchStmt(str, castNode(FetchStmt, node)); - break; - case T_GrantStmt: - deparseGrantStmt(str, castNode(GrantStmt, node)); - break; - case T_GrantRoleStmt: - deparseGrantRoleStmt(str, castNode(GrantRoleStmt, node)); - break; - case T_ImportForeignSchemaStmt: - deparseImportForeignSchemaStmt(str, castNode(ImportForeignSchemaStmt, node)); - break; - case T_IndexStmt: - deparseIndexStmt(str, castNode(IndexStmt, node)); - break; - case T_InsertStmt: - deparseInsertStmt(str, castNode(InsertStmt, node)); - break; - case T_ListenStmt: - deparseListenStmt(str, castNode(ListenStmt, node)); - break; - case T_RefreshMatViewStmt: - deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); - break; - case T_LoadStmt: - deparseLoadStmt(str, castNode(LoadStmt, node)); - break; - case T_LockStmt: - deparseLockStmt(str, castNode(LockStmt, node)); - break; - case T_MergeStmt: - deparseMergeStmt(str, castNode(MergeStmt, node)); - break; - case T_NotifyStmt: - deparseNotifyStmt(str, castNode(NotifyStmt, node)); - break; - case T_PrepareStmt: - deparsePrepareStmt(str, castNode(PrepareStmt, node)); - break; - case T_ReassignOwnedStmt: - deparseReassignOwnedStmt(str, castNode(ReassignOwnedStmt, node)); - break; - case T_ReindexStmt: - deparseReindexStmt(str, castNode(ReindexStmt, node)); - break; - case T_RenameStmt: - deparseRenameStmt(str, castNode(RenameStmt, node)); - break; - case T_RuleStmt: - deparseRuleStmt(str, castNode(RuleStmt, node)); - break; - case T_SecLabelStmt: - deparseSecLabelStmt(str, castNode(SecLabelStmt, node)); - break; - case T_SelectStmt: - deparseSelectStmt(str, castNode(SelectStmt, node)); - break; - case T_TransactionStmt: - deparseTransactionStmt(str, castNode(TransactionStmt, node)); - break; - case T_TruncateStmt: - deparseTruncateStmt(str, castNode(TruncateStmt, node)); - break; - case T_UnlistenStmt: - deparseUnlistenStmt(str, castNode(UnlistenStmt, node)); - break; - case T_UpdateStmt: - deparseUpdateStmt(str, castNode(UpdateStmt, node)); - break; - case T_VacuumStmt: - deparseVacuumStmt(str, castNode(VacuumStmt, node)); - break; - case T_VariableSetStmt: - deparseVariableSetStmt(str, castNode(VariableSetStmt, node)); - break; - case T_VariableShowStmt: - deparseVariableShowStmt(str, castNode(VariableShowStmt, node)); - break; - case T_ViewStmt: - deparseViewStmt(str, castNode(ViewStmt, node)); - break; - // These node types are created by DefineStmt grammar for CREATE TYPE in some cases - case T_CompositeTypeStmt: - deparseCompositeTypeStmt(str, castNode(CompositeTypeStmt, node)); - break; - case T_CreateEnumStmt: - deparseCreateEnumStmt(str, castNode(CreateEnumStmt, node)); - break; - case T_CreateRangeStmt: - deparseCreateRangeStmt(str, castNode(CreateRangeStmt, node)); - break; - default: - elog(ERROR, "deparse: unsupported top-level node type: %u", nodeTag(node)); - } -} +#include "postgres_deparse.h" PgQueryDeparseResult pg_query_deparse_protobuf(PgQueryProtobuf parse_tree) { diff --git a/ext/pg_query/postgres_deparse.c b/ext/pg_query/postgres_deparse.c new file mode 100644 index 0000000..054500e --- /dev/null +++ b/ext/pg_query/postgres_deparse.c @@ -0,0 +1,10665 @@ +#include "postgres.h" +#include "catalog/index.h" +#include "catalog/pg_am.h" +#include "catalog/pg_attribute.h" +#include "catalog/pg_class.h" +#include "catalog/pg_trigger.h" +#include "commands/trigger.h" +#include "common/keywords.h" +#include "common/kwlookup.h" +#include "lib/stringinfo.h" +#include "nodes/nodes.h" +#include "nodes/parsenodes.h" +#include "nodes/pg_list.h" +#include "utils/builtins.h" +#include "utils/datetime.h" +#include "utils/timestamp.h" +#include "utils/xml.h" + +typedef enum DeparseNodeContext { + DEPARSE_NODE_CONTEXT_NONE, + // Parent node type (and sometimes field) + DEPARSE_NODE_CONTEXT_INSERT_RELATION, + DEPARSE_NODE_CONTEXT_INSERT_ON_CONFLICT, + DEPARSE_NODE_CONTEXT_UPDATE, + DEPARSE_NODE_CONTEXT_RETURNING, + DEPARSE_NODE_CONTEXT_A_EXPR, + DEPARSE_NODE_CONTEXT_XMLATTRIBUTES, + DEPARSE_NODE_CONTEXT_XMLNAMESPACES, + DEPARSE_NODE_CONTEXT_CREATE_TYPE, + DEPARSE_NODE_CONTEXT_ALTER_TYPE, + DEPARSE_NODE_CONTEXT_SET_STATEMENT, + // Identifier vs constant context + DEPARSE_NODE_CONTEXT_IDENTIFIER, + DEPARSE_NODE_CONTEXT_CONSTANT +} DeparseNodeContext; + +static void +removeTrailingSpace(StringInfo str) +{ + if (str->len >= 1 && str->data[str->len - 1] == ' ') { + str->len -= 1; + str->data[str->len] = '\0'; + } +} + +/* + * Append a SQL string literal representing "val" to buf. + * + * Copied here from postgres_fdw/deparse.c to avoid adding + * many additional dependencies. + */ +static void +deparseStringLiteral(StringInfo buf, const char *val) +{ + const char *valptr; + + /* + * Rather than making assumptions about the remote server's value of + * standard_conforming_strings, always use E'foo' syntax if there are any + * backslashes. This will fail on remote servers before 8.1, but those + * are long out of support. + */ + if (strchr(val, '\\') != NULL) + appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX); + appendStringInfoChar(buf, '\''); + for (valptr = val; *valptr; valptr++) + { + char ch = *valptr; + + if (SQL_STR_DOUBLE(ch, true)) + appendStringInfoChar(buf, ch); + appendStringInfoChar(buf, ch); + } + appendStringInfoChar(buf, '\''); +} + +// Check whether the value is a reserved keyword, to determine escaping for output +// +// Note that since the parser lowercases all keywords, this does *not* match when the +// value is not all-lowercase and a reserved keyword. +static bool +isReservedKeyword(const char *val) +{ + int kwnum = ScanKeywordLookup(val, &ScanKeywords); + bool all_lower_case = true; + const char *cp; + + for (cp = val; *cp; cp++) + { + if (!( + (*cp >= 'a' && *cp <= 'z') || + (*cp >= '0' && *cp <= '9') || + (*cp == '_'))) + { + all_lower_case = false; + break; + } + } + + return all_lower_case && kwnum >= 0 && ScanKeywordCategories[kwnum] == RESERVED_KEYWORD; +} + +// Returns whether the given value consists only of operator characters +static bool +isOp(const char *val) +{ + const char *cp; + + Assert(strlen(val) > 0); + + for (cp = val; *cp; cp++) + { + if (!( + *cp == '~' || + *cp == '!' || + *cp == '@' || + *cp == '#' || + *cp == '^' || + *cp == '&' || + *cp == '|' || + *cp == '`' || + *cp == '?' || + *cp == '+' || + *cp == '-' || + *cp == '*' || + *cp == '/' || + *cp == '%' || + *cp == '<' || + *cp == '>' || + *cp == '=')) + return false; + } + + return true; +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt); +static void deparseIntoClause(StringInfo str, IntoClause *into_clause); +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context); +static void deparseResTarget(StringInfo str, ResTarget *res_target, DeparseNodeContext context); +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt); +static void deparseAlias(StringInfo str, Alias *alias); +static void deparseWindowDef(StringInfo str, WindowDef* window_def); +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref); +static void deparseSubLink(StringInfo str, SubLink* sub_link); +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context); +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr); +static void deparseAStar(StringInfo str, A_Star* a_star); +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause); +static void deparseSortBy(StringInfo str, SortBy* sort_by); +static void deparseParamRef(StringInfo str, ParamRef* param_ref); +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function); +static void deparseWithClause(StringInfo str, WithClause *with_clause); +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr); +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte); +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect); +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func); +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr * array_expr); +static void deparseRowExpr(StringInfo str, RowExpr *row_expr); +static void deparseTypeCast(StringInfo str, TypeCast *type_cast, DeparseNodeContext context); +static void deparseTypeName(StringInfo str, TypeName *type_name); +static void deparseIntervalTypmods(StringInfo str, TypeName *type_name); +static void deparseNullTest(StringInfo str, NullTest *null_test); +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr); +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when); +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection); +static void deparseAIndices(StringInfo str, A_Indices *a_indices); +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr); +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test); +static void deparseColumnDef(StringInfo str, ColumnDef *column_def); +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt); +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause); +static void deparseIndexElem(StringInfo str, IndexElem* index_elem); +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt); +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt); +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause); +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default); +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt); +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt); +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter); +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec); +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt); +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt); +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt); +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample); +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func); +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set); +static void deparseFuncCall(StringInfo str, FuncCall *func_call); +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr); +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr); +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize); +static void deparseConstraint(StringInfo str, Constraint *constraint); +static void deparseSchemaStmt(StringInfo str, Node *node); +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt); +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition); +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item); +static void deparseAConst(StringInfo str, A_Const *a_const); +static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr); +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func); + +static void deparsePreparableStmt(StringInfo str, Node *node); +static void deparseRuleActionStmt(StringInfo str, Node *node); +static void deparseExplainableStmt(StringInfo str, Node *node); +static void deparseStmt(StringInfo str, Node *node); +static void deparseValue(StringInfo str, union ValUnion *value, DeparseNodeContext context); + + +// "any_name" in gram.y +static void deparseAnyName(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + foreach(lc, parts) + { + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipFirst(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + for_each_from(lc, parts, 1) + { + Assert(IsA(lfirst(lc), String)); + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(parts, lc)) + appendStringInfoChar(str, '.'); + } +} +static void deparseAnyNameSkipLast(StringInfo str, List *parts) +{ + ListCell *lc = NULL; + + foreach (lc, parts) + { + if (lnext(parts, lc)) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (foreach_current_index(lc) < list_length(parts) - 2) + appendStringInfoChar(str, '.'); + } + } +} + +// "a_expr" / "b_expr" in gram.y +static void deparseExpr(StringInfo str, Node *node) +{ + if (node == NULL) + return; + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_A_Const: + deparseAConst(str, castNode(A_Const, node)); + break; + case T_ColumnRef: + deparseColumnRef(str, castNode(ColumnRef, node)); + break; + case T_A_Expr: + deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_CaseExpr: + deparseCaseExpr(str, castNode(CaseExpr, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + break; + case T_NullTest: + deparseNullTest(str, castNode(NullTest, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + case T_ParamRef: + deparseParamRef(str, castNode(ParamRef, node)); + break; + case T_BoolExpr: + deparseBoolExpr(str, castNode(BoolExpr, node)); + break; + case T_SubLink: + deparseSubLink(str, castNode(SubLink, node)); + break; + case T_RowExpr: + deparseRowExpr(str, castNode(RowExpr, node)); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_SetToDefault: + deparseSetToDefault(str, castNode(SetToDefault, node)); + break; + case T_A_Indirection: + deparseAIndirection(str, castNode(A_Indirection, node)); + break; + case T_CollateClause: + deparseCollateClause(str, castNode(CollateClause, node)); + break; + case T_CurrentOfExpr: + deparseCurrentOfExpr(str, castNode(CurrentOfExpr, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_BooleanTest: + deparseBooleanTest(str, castNode(BooleanTest, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(str, castNode(GroupingFunc, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in a_expr/b_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "c_expr" in gram.y +static void deparseCExpr(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnRef: + deparseColumnRef(str, castNode(ColumnRef, node)); + break; + case T_A_Const: + deparseAConst(str, castNode(A_Const, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_A_Expr: + appendStringInfoChar(str, '('); + deparseAExpr(str, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ')'); + break; + case T_ParamRef: + deparseParamRef(str, castNode(ParamRef, node)); + break; + case T_A_Indirection: + deparseAIndirection(str, castNode(A_Indirection, node)); + break; + case T_CaseExpr: + deparseCaseExpr(str, castNode(CaseExpr, node)); + break; + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SubLink: + deparseSubLink(str, castNode(SubLink, node)); + break; + case T_A_ArrayExpr: + deparseAArrayExpr(str, castNode(A_ArrayExpr, node)); + break; + case T_RowExpr: + deparseRowExpr(str, castNode(RowExpr, node)); + break; + case T_GroupingFunc: + deparseGroupingFunc(str, castNode(GroupingFunc, node)); + break; + default: + elog(ERROR, "deparse: unpermitted node type in c_expr: %d", + (int) nodeTag(node)); + break; + } +} + +// "expr_list" in gram.y +static void deparseExprList(StringInfo str, List *exprs) +{ + ListCell *lc; + foreach(lc, exprs) + { + deparseExpr(str, lfirst(lc)); + if (lnext(exprs, lc)) + appendStringInfoString(str, ", "); + } +} + +// "ColId", "name", "database_name", "access_method" and "index_name" in gram.y +static void deparseColId(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "ColLabel", "attr_name" +// +// Note this is kept separate from ColId in case we ever want to be more +// specific on how to handle keywords here +static void deparseColLabel(StringInfo str, char *s) +{ + appendStringInfoString(str, quote_identifier(s)); +} + +// "SignedIconst" and "Iconst" in gram.y +static void deparseSignedIconst(StringInfo str, Node *node) +{ + appendStringInfo(str, "%d", intVal(node)); +} + +// "indirection" and "opt_indirection" in gram.y +static void deparseOptIndirection(StringInfo str, List *indirection, int N) +{ + ListCell *lc = NULL; + + for_each_from(lc, indirection, N) + { + if (IsA(lfirst(lc), String)) + { + appendStringInfoChar(str, '.'); + deparseColLabel(str, strVal(lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Star)) + { + appendStringInfoString(str, ".*"); + } + else if (IsA(lfirst(lc), A_Indices)) + { + deparseAIndices(str, castNode(A_Indices, lfirst(lc))); + } + else + { + // No other nodes should appear here + Assert(false); + } + } +} + +// "role_list" in gram.y +static void deparseRoleList(StringInfo str, List *roles) +{ + ListCell *lc; + + foreach(lc, roles) + { + RoleSpec *role_spec = castNode(RoleSpec, lfirst(lc)); + deparseRoleSpec(str, role_spec); + if (lnext(roles, lc)) + appendStringInfoString(str, ", "); + } +} + +// "SimpleTypename" in gram.y +static void deparseSimpleTypename(StringInfo str, Node *node) +{ + deparseTypeName(str, castNode(TypeName, node)); +} + +// "NumericOnly" in gram.y +static void deparseNumericOnly(StringInfo str, union ValUnion *value) +{ + switch (nodeTag(value)) + { + case T_Integer: + appendStringInfo(str, "%d", value->ival.ival); + break; + case T_Float: + appendStringInfoString(str, value->sval.sval); + break; + default: + Assert(false); + } +} + +// "NumericOnly_list" in gram.y +static void deparseNumericOnlyList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseNumericOnly(str, (union ValUnion *) lfirst(lc)); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "SeqOptElem" in gram.y +static void deparseSeqOptElem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseSimpleTypename(str, def_elem->arg); + } + else if (strcmp(def_elem->defname, "cache") == 0) + { + appendStringInfoString(str, "CACHE "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "CYCLE"); + } + else if (strcmp(def_elem->defname, "cycle") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NO CYCLE"); + } + else if (strcmp(def_elem->defname, "increment") == 0) + { + appendStringInfoString(str, "INCREMENT "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MAXVALUE "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MAXVALUE"); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "MINVALUE "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO MINVALUE"); + } + else if (strcmp(def_elem->defname, "owned_by") == 0) + { + appendStringInfoString(str, "OWNED BY "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "sequence_name") == 0) + { + appendStringInfoString(str, "SEQUENCE NAME "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "start") == 0) + { + appendStringInfoString(str, "START "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else + { + Assert(false); + } +} + +// "SeqOptList" in gram.y +static void deparseSeqOptList(StringInfo str, List *options) +{ + ListCell *lc; + Assert(list_length(options) > 0); + foreach (lc, options) + { + deparseSeqOptElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } +} + +// "OptSeqOptList" in gram.y +static void deparseOptSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + deparseSeqOptList(str, options); +} + +// "OptParenthesizedSeqOptList" in gram.y +static void deparseOptParenthesizedSeqOptList(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoChar(str, '('); + deparseSeqOptList(str, options); + appendStringInfoChar(str, ')'); + } +} + +// "opt_drop_behavior" in gram.y +static void deparseOptDropBehavior(StringInfo str, DropBehavior behavior) +{ + switch (behavior) + { + case DROP_RESTRICT: + // Default + break; + case DROP_CASCADE: + appendStringInfoString(str, "CASCADE "); + break; + } +} + +// "any_operator" in gram.y +static void deparseAnyOperator(StringInfo str, List *op) +{ + Assert(isOp(strVal(llast(op)))); + if (list_length(op) == 2) + { + appendStringInfoString(str, quote_identifier(strVal(linitial(op)))); + appendStringInfoChar(str, '.'); + appendStringInfoString(str, strVal(llast(op))); + } + else if (list_length(op) == 1) + { + appendStringInfoString(str, strVal(llast(op))); + } + else + { + Assert(false); + } +} + +// "qual_Op" and "qual_all_Op" in gram.y +static void deparseQualOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// "subquery_Op" in gram.y +static void deparseSubqueryOp(StringInfo str, List *op) +{ + if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~") == 0) + { + appendStringInfoString(str, "LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~") == 0) + { + appendStringInfoString(str, "NOT LIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~*") == 0) + { + appendStringInfoString(str, "ILIKE"); + } + else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~*") == 0) + { + appendStringInfoString(str, "NOT ILIKE"); + } + else if (list_length(op) == 1 && isOp(strVal(linitial(op)))) + { + appendStringInfoString(str, strVal(linitial(op))); + } + else + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, op); + appendStringInfoString(str, ")"); + } +} + +// Not present directly in gram.y (usually matched by ColLabel) +static void deparseGenericDefElemName(StringInfo str, const char *in) +{ + Assert(in != NULL); + char *val = pstrdup(in); + for (unsigned char *p = (unsigned char *) val; *p; p++) + *p = pg_toupper(*p); + appendStringInfoString(str, val); + pfree(val); +} + +// "def_arg" and "operator_def_arg" in gram.y +static void deparseDefArg(StringInfo str, Node *arg, bool is_operator_def_arg) +{ + if (IsA(arg, TypeName)) // func_type + { + deparseTypeName(str, castNode(TypeName, arg)); + } + else if (IsA(arg, List)) // qual_all_Op + { + List *l = castNode(List, arg); + Assert(list_length(l) == 1 || list_length(l) == 2); + + // Schema qualified operator + if (list_length(l) == 2) + { + appendStringInfoString(str, "OPERATOR("); + deparseAnyOperator(str, l); + appendStringInfoChar(str, ')'); + } + else if (list_length(l) == 1) + { + appendStringInfoString(str, strVal(linitial(l))); + } + } + else if (IsA(arg, Float) || IsA(arg, Integer)) // NumericOnly + { + deparseValue(str, (union ValUnion *) arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (IsA(arg, String)) + { + char *s = strVal(arg); + if (!is_operator_def_arg && IsA(arg, String) && strcmp(s, "none") == 0) // NONE + { + appendStringInfoString(str, "NONE"); + } + else if (isReservedKeyword(s)) // reserved_keyword + { + appendStringInfoString(str, s); + } + else // Sconst + { + deparseStringLiteral(str, s); + } + } + else + { + Assert(false); + } +} + +// "definition" in gram.y +static void deparseDefinition(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach (lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) { + appendStringInfoString(str, " = "); + deparseDefArg(str, def_elem->arg, false); + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "opt_definition" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptDefinition(StringInfo str, List *options) +{ + if (list_length(options) > 0) + { + appendStringInfoString(str, "WITH "); + deparseDefinition(str, options); + } +} + +// "create_generic_options" in gram.y +static void deparseCreateGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + if (options == NULL) + return; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ")"); +} + +// "common_func_opt_item" in gram.y +static void deparseCommonFuncOptItem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "strict") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "RETURNS NULL ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "strict") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "CALLED ON NULL INPUT"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "immutable") == 0) + { + appendStringInfoString(str, "IMMUTABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "stable") == 0) + { + appendStringInfoString(str, "STABLE"); + } + else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "volatile") == 0) + { + appendStringInfoString(str, "VOLATILE"); + } + else if (strcmp(def_elem->defname, "security") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "SECURITY DEFINER"); + } + else if (strcmp(def_elem->defname, "security") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "SECURITY INVOKER"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "leakproof") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOT LEAKPROOF"); + } + else if (strcmp(def_elem->defname, "cost") == 0) + { + appendStringInfoString(str, "COST "); + deparseValue(str, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "rows") == 0) + { + appendStringInfoString(str, "ROWS "); + deparseValue(str, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); + } + else if (strcmp(def_elem->defname, "support") == 0) + { + appendStringInfoString(str, "SUPPORT "); + deparseAnyName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "set") == 0 && IsA(def_elem->arg, VariableSetStmt)) // FunctionSetResetClause + { + deparseVariableSetStmt(str, castNode(VariableSetStmt, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "parallel") == 0) + { + appendStringInfoString(str, "PARALLEL "); + appendStringInfoString(str, quote_identifier(strVal(def_elem->arg))); + } + else + { + Assert(false); + } +} + +// "NonReservedWord_or_Sconst" in gram.y +// +// Note since both identifiers and string constants are allowed here, we +// currently always return an identifier, except: +// +// 1) when the string is empty (since an empty identifier can't be scanned) +// 2) when the value is equal or larger than NAMEDATALEN (64+ characters) +static void deparseNonReservedWordOrSconst(StringInfo str, const char *val) +{ + if (strlen(val) == 0) + appendStringInfoString(str, "''"); + else if (strlen(val) >= NAMEDATALEN) + deparseStringLiteral(str, val); + else + appendStringInfoString(str, quote_identifier(val)); +} + +// "func_as" in gram.y +static void deparseFuncAs(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + char *strval = strVal(lfirst(lc)); + if (strstr(strval, "$$") == NULL) + { + appendStringInfoString(str, "$$"); + appendStringInfoString(str, strval); + appendStringInfoString(str, "$$"); + } + else + { + deparseStringLiteral(str, strval); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "createfunc_opt_item" in gram.y +static void deparseCreateFuncOptItem(StringInfo str, DefElem *def_elem) +{ + ListCell *lc = NULL; + + if (strcmp(def_elem->defname, "as") == 0) + { + appendStringInfoString(str, "AS "); + deparseFuncAs(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "transform") == 0) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, "TRANSFORM "); + foreach (lc, l) + { + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + } + else if (strcmp(def_elem->defname, "window") == 0) + { + appendStringInfoString(str, "WINDOW"); + } + else + { + deparseCommonFuncOptItem(str, def_elem); + } +} + +// "alter_generic_options" in gram.y +static void deparseAlterGenericOptions(StringInfo str, List *options) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "OPTIONS ("); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + switch (def_elem->defaction) + { + case DEFELEM_UNSPEC: + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_SET: + appendStringInfoString(str, "SET "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_ADD: + appendStringInfoString(str, "ADD "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoChar(str, ' '); + deparseStringLiteral(str, strVal(def_elem->arg)); + break; + case DEFELEM_DROP: + appendStringInfoString(str, "DROP "); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + break; + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); +} + +// "func_name" in gram.y +static void deparseFuncName(StringInfo str, List *func_name) +{ + ListCell *lc = NULL; + + foreach(lc, func_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(func_name, lc)) + appendStringInfoChar(str, '.'); + } +} + +// "function_with_argtypes" in gram.y +static void deparseFunctionWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc; + deparseFuncName(str, object_with_args->objname); + + if (!object_with_args->args_unspecified) + { + appendStringInfoChar(str, '('); + List *objargs = object_with_args->objargs; + if (object_with_args->objfuncargs) + objargs = object_with_args->objfuncargs; + + foreach(lc, objargs) + { + if (IsA(lfirst(lc), FunctionParameter)) + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + else + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(objargs, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } +} + +// "function_with_argtypes_list" in gram.y +static void deparseFunctionWithArgtypesList(StringInfo str, List *l) +{ + ListCell *lc; + + foreach(lc, l) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "operator_with_argtypes" in gram.y +static void deparseOperatorWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + deparseAnyOperator(str, object_with_args->objname); + + Assert(list_length(object_with_args->objargs) == 2); + appendStringInfoChar(str, '('); + if (linitial(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, linitial(object_with_args->objargs))); + appendStringInfoString(str, ", "); + if (lsecond(object_with_args->objargs) == NULL) + appendStringInfoString(str, "NONE"); + else + deparseTypeName(str, castNode(TypeName, lsecond(object_with_args->objargs))); + appendStringInfoChar(str, ')'); +} + +// "aggr_args" in gram.y +static void deparseAggrArgs(StringInfo str, List *aggr_args) +{ + Assert(list_length(aggr_args) == 2); + + ListCell *lc = NULL; + List *args = linitial(aggr_args); + int order_by_pos = intVal(lsecond(aggr_args)); + + appendStringInfoChar(str, '('); + if (args == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + foreach(lc, args) + { + if (foreach_current_index(lc) == order_by_pos) + { + if (foreach_current_index(lc) > 0) + appendStringInfoChar(str, ' '); + appendStringInfoString(str, "ORDER BY "); + } + else if (foreach_current_index(lc) > 0) + { + appendStringInfoString(str, ", "); + } + + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + } + + // Repeat the last direct arg as a ordered arg to handle the + // simplification done by makeOrderedSetArgs in gram.y + if (order_by_pos == list_length(args)) + { + appendStringInfoString(str, " ORDER BY "); + deparseFunctionParameter(str, castNode(FunctionParameter, llast(args))); + } + } + appendStringInfoChar(str, ')'); +} + +// "aggregate_with_argtypes" in gram.y +static void deparseAggregateWithArgtypes(StringInfo str, ObjectWithArgs *object_with_args) +{ + ListCell *lc = NULL; + + deparseFuncName(str, object_with_args->objname); + + appendStringInfoChar(str, '('); + if (object_with_args->objargs == NULL && object_with_args->objfuncargs == NULL) + { + appendStringInfoChar(str, '*'); + } + else + { + List *objargs = object_with_args->objargs; + if (object_with_args->objfuncargs) + objargs = object_with_args->objfuncargs; + + foreach(lc, objargs) + { + if (IsA(lfirst(lc), FunctionParameter)) + deparseFunctionParameter(str, castNode(FunctionParameter, lfirst(lc))); + else + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(objargs, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ')'); +} + +// "columnList" in gram.y +static void deparseColumnList(StringInfo str, List *columns) +{ + ListCell *lc = NULL; + foreach(lc, columns) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(columns, lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptTemp" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptTemp(StringInfo str, char relpersistence) +{ + switch (relpersistence) + { + case RELPERSISTENCE_PERMANENT: + // Default + break; + case RELPERSISTENCE_UNLOGGED: + appendStringInfoString(str, "UNLOGGED "); + break; + case RELPERSISTENCE_TEMP: + appendStringInfoString(str, "TEMPORARY "); + break; + default: + Assert(false); + break; + } +} + +// "relation_expr_list" in gram.y +static void deparseRelationExprList(StringInfo str, List *relation_exprs) +{ + ListCell *lc = NULL; + foreach(lc, relation_exprs) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(relation_exprs, lc)) + appendStringInfoString(str, ", "); + } +} + +// "handler_name" in gram.y +static void deparseHandlerName(StringInfo str, List *handler_name) +{ + ListCell *lc = NULL; + + foreach(lc, handler_name) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc)))); + if (lnext(handler_name, lc)) + appendStringInfoChar(str, '.'); + } +} + +// "fdw_options" in gram.y +static void deparseFdwOptions(StringInfo str, List *fdw_options) +{ + ListCell *lc = NULL; + + foreach (lc, fdw_options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO HANDLER "); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "NO VALIDATOR "); + } + else + { + Assert(false); + } + + if (lnext(fdw_options, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "type_list" in gram.y +static void deparseTypeList(StringInfo str, List *type_list) +{ + ListCell *lc = NULL; + foreach(lc, type_list) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(type_list, lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_boolean_or_string" in gram.y +static void deparseOptBooleanOrString(StringInfo str, char *s) +{ + if (s == NULL) + return; // No value set + else if (strcmp(s, "true") == 0) + appendStringInfoString(str, "TRUE"); + else if (strcmp(s, "false") == 0) + appendStringInfoString(str, "FALSE"); + else if (strcmp(s, "on") == 0) + appendStringInfoString(str, "ON"); + else if (strcmp(s, "off") == 0) + appendStringInfoString(str, "OFF"); + else + deparseNonReservedWordOrSconst(str, s); +} + +static void deparseOptBoolean(StringInfo str, Node *node) +{ + if (node == NULL) + { + return; + } + + switch (nodeTag(node)) + { + case T_String: + appendStringInfo(str, " %s", strVal(node)); + break; + case T_Integer: + appendStringInfo(str, " %d", intVal(node)); + break; + case T_Boolean: + appendStringInfo(str, " %s", boolVal(node) ? "TRUE" : "FALSE"); + break; + default: + Assert(false); + break; + } +} + +bool optBooleanValue(Node *node) +{ + if (node == NULL) + { + return true; + } + + switch (nodeTag(node)) + { + case T_String: { + // Longest valid string is "off\0" + char lower[4]; + strncpy(lower, strVal(node), 4); + lower[3] = 0; + + if (strcmp(lower, "on") == 0) { + return true; + } else if (strcmp(lower, "off") == 0) { + return false; + } + + // No sane way to handle this. + return false; + } + case T_Integer: + return intVal(node) != 0; + case T_Boolean: + return boolVal(node); + default: + Assert(false); + return false; + } +} + +// "var_name" +// +// Note this is kept separate from ColId in case we want to improve the +// output of namespaced variable names +static void deparseVarName(StringInfo str, char *s) +{ + deparseColId(str, s); +} + +// "var_list" +static void deparseVarList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, lfirst(lc))); + } + else if (IsA(lfirst(lc), A_Const)) + { + A_Const *a_const = castNode(A_Const, lfirst(lc)); + if (IsA(&a_const->val, Integer) || IsA(&a_const->val, Float)) + deparseNumericOnly(str, (union ValUnion *) &a_const->val); + else if (IsA(&a_const->val, String)) + deparseOptBooleanOrString(str, strVal(&a_const->val)); + else + Assert(false); + } + else if (IsA(lfirst(lc), TypeCast)) + { + deparseTypeCast(str, castNode(TypeCast, lfirst(lc)), DEPARSE_NODE_CONTEXT_SET_STATEMENT); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "transaction_mode_list" in gram.y +static void deparseTransactionModeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "transaction_isolation") == 0) + { + char *s = strVal(&castNode(A_Const, def_elem->arg)->val); + appendStringInfoString(str, "ISOLATION LEVEL "); + if (strcmp(s, "read uncommitted") == 0) + appendStringInfoString(str, "READ UNCOMMITTED"); + else if (strcmp(s, "read committed") == 0) + appendStringInfoString(str, "READ COMMITTED"); + else if (strcmp(s, "repeatable read") == 0) + appendStringInfoString(str, "REPEATABLE READ"); + else if (strcmp(s, "serializable") == 0) + appendStringInfoString(str, "SERIALIZABLE"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "READ ONLY"); + } + else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "READ WRITE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) + { + appendStringInfoString(str, "DEFERRABLE"); + } + else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) + { + appendStringInfoString(str, "NOT DEFERRABLE"); + } + else + { + Assert(false); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "alter_identity_column_option_list" in gram.y +static void deparseAlterIdentityColumnOptionList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) + { + appendStringInfoString(str, "RESTART"); + } + else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) + { + appendStringInfoString(str, "RESTART "); + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (strcmp(def_elem->defname, "generated") == 0) + { + appendStringInfoString(str, "SET GENERATED "); + if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_ALWAYS) + appendStringInfoString(str, "ALWAYS"); + else if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_BY_DEFAULT) + appendStringInfoString(str, "BY DEFAULT"); + else + Assert(false); + } + else + { + appendStringInfoString(str, "SET "); + deparseSeqOptElem(str, def_elem); + } + if (lnext(l, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "reloptions" in gram.y +static void deparseRelOptions(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + appendStringInfoChar(str, '('); + foreach(lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (def_elem->defnamespace != NULL) + { + appendStringInfoString(str, quote_identifier(def_elem->defnamespace)); + appendStringInfoChar(str, '.'); + } + if (def_elem->defname != NULL) + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->defname != NULL && def_elem->arg != NULL) + appendStringInfoChar(str, '='); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, false); + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +// "OptWith" and "opt_reloptions" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptWith(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "WITH "); + deparseRelOptions(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "target_list" and "opt_target_list" in gram.y +static void deparseTargetList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + + if (res_target->val == NULL) + elog(ERROR, "deparse: error in deparseTargetList: ResTarget without val"); + else if (IsA(res_target->val, ColumnRef)) + deparseColumnRef(str, castNode(ColumnRef, res_target->val)); + else + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "insert_column_list" in gram.y +static void deparseInsertColumnList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->name != NULL); + appendStringInfoString(str, quote_identifier(res_target->name)); + deparseOptIndirection(str, res_target->indirection, 0); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_attribute_list" in gram.y +static void deparseXmlAttributeList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "xml_namespace_list" in gram.y +static void deparseXmlNamespaceList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (res_target->name == NULL) + appendStringInfoString(str, "DEFAULT "); + + deparseExpr(str, res_target->val); + + if (res_target->name != NULL) + { + appendStringInfoString(str, " AS "); + appendStringInfoString(str, quote_identifier(res_target->name)); + } + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "table_ref" in gram.y +static void deparseTableRef(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_RangeVar: + deparseRangeVar(str, castNode(RangeVar, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_RangeTableSample: + deparseRangeTableSample(str, castNode(RangeTableSample, node)); + break; + case T_RangeFunction: + deparseRangeFunction(str, castNode(RangeFunction, node)); + break; + case T_RangeTableFunc: + deparseRangeTableFunc(str, castNode(RangeTableFunc, node)); + break; + case T_RangeSubselect: + deparseRangeSubselect(str, castNode(RangeSubselect, node)); + break; + case T_JoinExpr: + deparseJoinExpr(str, castNode(JoinExpr, node)); + break; + default: + Assert(false); + } +} + +// "from_list" in gram.y +static void deparseFromList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseTableRef(str, lfirst(lc)); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "from_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseFromClause(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "FROM "); + deparseFromList(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "where_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseWhereClause(StringInfo str, Node *node) +{ + if (node != NULL) + { + appendStringInfoString(str, "WHERE "); + deparseExpr(str, node); + appendStringInfoChar(str, ' '); + } +} + +// "group_by_list" in gram.y +static void deparseGroupByList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + if (IsA(lfirst(lc), GroupingSet)) + deparseGroupingSet(str, castNode(GroupingSet, lfirst(lc))); + else + deparseExpr(str, lfirst(lc)); + + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "set_target" in gram.y +static void deparseSetTarget(StringInfo str, ResTarget *res_target) +{ + Assert(res_target->name != NULL); + deparseColId(str, res_target->name); + deparseOptIndirection(str, res_target->indirection, 0); +} + +// "any_name_list" in gram.y +static void deparseAnyNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseAnyName(str, castNode(List, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "name_list" in gram.y +static void deparseNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseColId(str, strVal(lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "opt_sort_clause" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptSortClause(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + if (list_length(l) > 0) + { + appendStringInfoString(str, "ORDER BY "); + + foreach(lc, l) + { + deparseSortBy(str, castNode(SortBy, lfirst(lc))); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } +} + +// "func_arg_expr" in gram.y +static void deparseFuncArgExpr(StringInfo str, Node *node) +{ + if (IsA(node, NamedArgExpr)) + { + NamedArgExpr *named_arg_expr = castNode(NamedArgExpr, node); + appendStringInfoString(str, named_arg_expr->name); + appendStringInfoString(str, " := "); + deparseExpr(str, (Node *) named_arg_expr->arg); + } + else + { + deparseExpr(str, node); + } +} + +// "set_clause_list" in gram.y +static void deparseSetClauseList(StringInfo str, List *target_list) +{ + ListCell *lc; + ListCell *lc2; + int skip_next_n_elems = 0; + + Assert(list_length(target_list) > 0); + + foreach(lc, target_list) + { + if (skip_next_n_elems > 0) + { + skip_next_n_elems--; + continue; + } + + if (foreach_current_index(lc) != 0) + appendStringInfoString(str, ", "); + + ResTarget *res_target = castNode(ResTarget, lfirst(lc)); + Assert(res_target->val != NULL); + + if (IsA(res_target->val, MultiAssignRef)) + { + MultiAssignRef *r = castNode(MultiAssignRef, res_target->val); + appendStringInfoString(str, "("); + for_each_cell(lc2, target_list, lc) + { + deparseSetTarget(str, castNode(ResTarget, lfirst(lc2))); + if (foreach_current_index(lc2) == r->ncolumns - 1) // Last element in this multi-assign + break; + else if (lnext(target_list, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") = "); + deparseExpr(str, r->source); + skip_next_n_elems = r->ncolumns - 1; + } + else + { + deparseSetTarget(str, res_target); + appendStringInfoString(str, " = "); + deparseExpr(str, res_target->val); + } + } +} + +// "func_expr_windowless" in gram.y +static void deparseFuncExprWindowless(StringInfo str, Node* node) +{ + switch (nodeTag(node)) + { + case T_FuncCall: + deparseFuncCall(str, castNode(FuncCall, node)); + break; + case T_SQLValueFunction: + deparseSQLValueFunction(str, castNode(SQLValueFunction, node)); + break; + case T_TypeCast: + deparseTypeCast(str, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); + break; + case T_CoalesceExpr: + deparseCoalesceExpr(str, castNode(CoalesceExpr, node)); + break; + case T_MinMaxExpr: + deparseMinMaxExpr(str, castNode(MinMaxExpr, node)); + break; + case T_XmlExpr: + deparseXmlExpr(str, castNode(XmlExpr, node)); + break; + case T_XmlSerialize: + deparseXmlSerialize(str, castNode(XmlSerialize, node)); + break; + default: + Assert(false); + } +} + +// "opt_collate" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptCollate(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, l); + appendStringInfoChar(str, ' '); + } +} + +// "index_elem" in gram.y +static void deparseIndexElem(StringInfo str, IndexElem* index_elem) +{ + if (index_elem->name != NULL) + { + deparseColId(str, index_elem->name); + appendStringInfoChar(str, ' '); + } + else if (index_elem->expr != NULL) + { + switch (nodeTag(index_elem->expr)) + { + case T_FuncCall: + case T_SQLValueFunction: + case T_TypeCast: + case T_CoalesceExpr: + case T_MinMaxExpr: + case T_XmlExpr: + case T_XmlSerialize: + deparseFuncExprWindowless(str, index_elem->expr); + break; + default: + appendStringInfoChar(str, '('); + deparseExpr(str, index_elem->expr); + appendStringInfoString(str, ") "); + } + } + else + { + Assert(false); + } + + deparseOptCollate(str, index_elem->collation); + + if (list_length(index_elem->opclass) > 0) + { + deparseAnyName(str, index_elem->opclass); + + if (list_length(index_elem->opclassopts) > 0) + deparseRelOptions(str, index_elem->opclassopts); + + appendStringInfoChar(str, ' '); + } + + switch (index_elem->ordering) + { + case SORTBY_DEFAULT: + // Default + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + // Not allowed in CREATE INDEX + Assert(false); + break; + } + + switch (index_elem->nulls_ordering) + { + case SORTBY_NULLS_DEFAULT: + // Default + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +// "qualified_name_list" in gram.y +static void deparseQualifiedNameList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach(lc, l) + { + deparseRangeVar(str, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); + if (lnext(l, lc)) + appendStringInfoString(str, ", "); + } +} + +// "OptInherit" in gram.y +// +// Note this method adds a trailing space if a value is output +static void deparseOptInherit(StringInfo str, List *l) +{ + if (list_length(l) > 0) + { + appendStringInfoString(str, "INHERITS ("); + deparseQualifiedNameList(str, l); + appendStringInfoString(str, ") "); + } +} + +// "privilege_target" in gram.y +static void deparsePrivilegeTarget(StringInfo str, GrantTargetType targtype, ObjectType objtype, List *objs) +{ + switch (targtype) + { + case ACL_TARGET_OBJECT: + switch (objtype) + { + case OBJECT_TABLE: + deparseQualifiedNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseQualifiedNameList(str, objs); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseNameList(str, objs); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "FOREIGN SERVER "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypesList(str, objs); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseNameList(str, objs); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyNameList(str, objs); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseNameList(str, objs); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnlyList(str, objs); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseNameList(str, objs); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_ALL_IN_SCHEMA: + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "ALL TABLES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "ALL SEQUENCES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "ALL FUNCTIONS IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "ALL PROCEDURES IN SCHEMA "); + deparseNameList(str, objs); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ALL ROUTINES IN SCHEMA "); + deparseNameList(str, objs); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + case ACL_TARGET_DEFAULTS: // defacl_privilege_target + switch (objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLES"); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTIONS"); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCES"); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPES"); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMAS"); + break; + default: + // Other types are not supported here + Assert(false); + break; + } + break; + } +} + +// "opclass_item_list" in gram.y +static void deparseOpclassItemList(StringInfo str, List *items) +{ + ListCell *lc = NULL; + + foreach (lc, items) + { + deparseCreateOpClassItem(str, castNode(CreateOpClassItem, lfirst(lc))); + if (lnext(items, lc)) + appendStringInfoString(str, ", "); + } +} + +// "createdb_opt_list" in gram.y +static void deparseCreatedbOptList(StringInfo str, List *l) +{ + ListCell *lc = NULL; + + foreach (lc, l) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "connection_limit") == 0) + appendStringInfoString(str, "CONNECTION LIMIT"); + else + deparseGenericDefElemName(str, def_elem->defname); + + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + appendStringInfoString(str, "DEFAULT"); + else if (IsA(def_elem->arg, Integer)) + deparseSignedIconst(str, def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + + if (lnext(l, lc)) + appendStringInfoChar(str, ' '); + } +} + +// "utility_option_list" in gram.y +static void deparseUtilityOptionList(StringInfo str, List *options) +{ + ListCell *lc = NULL; + char *defname = NULL; + + if (list_length(options) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + deparseGenericDefElemName(str, def_elem->defname); + + if (def_elem->arg != NULL) + { + appendStringInfoChar(str, ' '); + if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + else if (IsA(def_elem->arg, String)) + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + else + Assert(false); + } + + if (lnext(options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } +} + +static void deparseSelectStmt(StringInfo str, SelectStmt *stmt) +{ + const ListCell *lc = NULL; + const ListCell *lc2 = NULL; + + if (stmt->withClause) + { + deparseWithClause(str, stmt->withClause); + appendStringInfoChar(str, ' '); + } + + switch (stmt->op) { + case SETOP_NONE: + if (list_length(stmt->valuesLists) > 0) + { + const ListCell *lc; + appendStringInfoString(str, "VALUES "); + + foreach(lc, stmt->valuesLists) + { + appendStringInfoChar(str, '('); + deparseExprList(str, lfirst(lc)); + appendStringInfoChar(str, ')'); + if (lnext(stmt->valuesLists, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + } + + appendStringInfoString(str, "SELECT "); + + if (list_length(stmt->targetList) > 0) + { + if (stmt->distinctClause != NULL) + { + appendStringInfoString(str, "DISTINCT "); + + if (list_length(stmt->distinctClause) > 0 && linitial(stmt->distinctClause) != NULL) + { + appendStringInfoString(str, "ON ("); + deparseExprList(str, stmt->distinctClause); + appendStringInfoString(str, ") "); + } + } + + deparseTargetList(str, stmt->targetList); + appendStringInfoChar(str, ' '); + } + + if (stmt->intoClause != NULL) + { + appendStringInfoString(str, "INTO "); + deparseOptTemp(str, stmt->intoClause->rel->relpersistence); + deparseIntoClause(str, stmt->intoClause); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, stmt->fromClause); + deparseWhereClause(str, stmt->whereClause); + + if (list_length(stmt->groupClause) > 0) + { + appendStringInfoString(str, "GROUP BY "); + if (stmt->groupDistinct) + appendStringInfoString(str, "DISTINCT "); + deparseGroupByList(str, stmt->groupClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->havingClause != NULL) + { + appendStringInfoString(str, "HAVING "); + deparseExpr(str, stmt->havingClause); + appendStringInfoChar(str, ' '); + } + + if (stmt->windowClause != NULL) + { + appendStringInfoString(str, "WINDOW "); + foreach(lc, stmt->windowClause) + { + WindowDef *window_def = castNode(WindowDef, lfirst(lc)); + Assert(window_def->name != NULL); + appendStringInfoString(str, window_def->name); + appendStringInfoString(str, " AS "); + deparseWindowDef(str, window_def); + if (lnext(stmt->windowClause, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + break; + case SETOP_UNION: + case SETOP_INTERSECT: + case SETOP_EXCEPT: + { + bool need_larg_parens = + list_length(stmt->larg->sortClause) > 0 || + stmt->larg->limitOffset != NULL || + stmt->larg->limitCount != NULL || + list_length(stmt->larg->lockingClause) > 0 || + stmt->larg->withClause != NULL || + stmt->larg->op != SETOP_NONE; + bool need_rarg_parens = + list_length(stmt->rarg->sortClause) > 0 || + stmt->rarg->limitOffset != NULL || + stmt->rarg->limitCount != NULL || + list_length(stmt->rarg->lockingClause) > 0 || + stmt->rarg->withClause != NULL || + stmt->rarg->op != SETOP_NONE; + if (need_larg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->larg); + if (need_larg_parens) + appendStringInfoChar(str, ')'); + switch (stmt->op) + { + case SETOP_UNION: + appendStringInfoString(str, " UNION "); + break; + case SETOP_INTERSECT: + appendStringInfoString(str, " INTERSECT "); + break; + case SETOP_EXCEPT: + appendStringInfoString(str, " EXCEPT "); + break; + default: + Assert(false); + } + if (stmt->all) + appendStringInfoString(str, "ALL "); + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseSelectStmt(str, stmt->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + break; + } + + deparseOptSortClause(str, stmt->sortClause); + + if (stmt->limitCount != NULL) + { + if (stmt->limitOption == LIMIT_OPTION_COUNT) + appendStringInfoString(str, "LIMIT "); + else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + appendStringInfoString(str, "FETCH FIRST "); + + if (IsA(stmt->limitCount, A_Const) && castNode(A_Const, stmt->limitCount)->isnull) + appendStringInfoString(str, "ALL"); + else + deparseCExpr(str, stmt->limitCount); + + appendStringInfoChar(str, ' '); + + if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) + appendStringInfoString(str, "ROWS WITH TIES "); + } + + if (stmt->limitOffset != NULL) + { + appendStringInfoString(str, "OFFSET "); + deparseExpr(str, stmt->limitOffset); + appendStringInfoChar(str, ' '); + } + + if (list_length(stmt->lockingClause) > 0) + { + foreach(lc, stmt->lockingClause) + { + deparseLockingClause(str, castNode(LockingClause, lfirst(lc))); + if (lnext(stmt->lockingClause, lc)) + appendStringInfoString(str, " "); + } + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseIntoClause(StringInfo str, IntoClause *into_clause) +{ + ListCell *lc; + + deparseRangeVar(str, into_clause->rel, DEPARSE_NODE_CONTEXT_NONE); /* target relation name */ + + if (list_length(into_clause->colNames) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, into_clause->colNames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + if (into_clause->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(into_clause->accessMethod)); + appendStringInfoChar(str, ' '); + } + + deparseOptWith(str, into_clause->options); + + switch (into_clause->onCommit) + { + case ONCOMMIT_NOOP: + // No clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (into_clause->tableSpaceName != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(into_clause->tableSpaceName)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseRangeVar(StringInfo str, RangeVar *range_var, DeparseNodeContext context) +{ + if (!range_var->inh && context != DEPARSE_NODE_CONTEXT_CREATE_TYPE && context != DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ONLY "); + + if (range_var->catalogname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->catalogname)); + appendStringInfoChar(str, '.'); + } + + if (range_var->schemaname != NULL) + { + appendStringInfoString(str, quote_identifier(range_var->schemaname)); + appendStringInfoChar(str, '.'); + } + + Assert(range_var->relname != NULL); + appendStringInfoString(str, quote_identifier(range_var->relname)); + appendStringInfoChar(str, ' '); + + if (range_var->alias != NULL) + { + if (context == DEPARSE_NODE_CONTEXT_INSERT_RELATION) + appendStringInfoString(str, "AS "); + deparseAlias(str, range_var->alias); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +void deparseRawStmt(StringInfo str, RawStmt *raw_stmt) +{ + if (raw_stmt->stmt == NULL) + elog(ERROR, "deparse error in deparseRawStmt: RawStmt with empty Stmt"); + + deparseStmt(str, raw_stmt->stmt); +} + +static void deparseAlias(StringInfo str, Alias *alias) +{ + appendStringInfoString(str, quote_identifier(alias->aliasname)); + + if (list_length(alias->colnames) > 0) + { + const ListCell *lc = NULL; + appendStringInfoChar(str, '('); + deparseNameList(str, alias->colnames); + appendStringInfoChar(str, ')'); + } +} + +static void deparseAConst(StringInfo str, A_Const *a_const) +{ + union ValUnion *val = a_const->isnull ? NULL : &a_const->val; + deparseValue(str, val, DEPARSE_NODE_CONTEXT_CONSTANT); +} + +static void deparseFuncCall(StringInfo str, FuncCall *func_call) +{ + const ListCell *lc = NULL; + + Assert(list_length(func_call->funcname) > 0); + + if (list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 4) + { + /* + * Note that this is a bit odd, but "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "OVERLAY("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " PLACING "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoString(str, " FOR "); + deparseExpr(str, lfourth(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "substring") == 0) + { + /* + * "SUBSTRING" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.substring) + */ + Assert(list_length(func_call->args) == 2 || list_length(func_call->args) == 3); + appendStringInfoString(str, "SUBSTRING("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lsecond(func_call->args)); + if (list_length(func_call->args) == 3) + { + appendStringInfoString(str, " FOR "); + deparseExpr(str, lthird(func_call->args)); + } + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "position") == 0 && + list_length(func_call->args) == 2) + { + /* + * "POSITION" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.position) + * Note that the first and second arguments are switched in this format + */ + appendStringInfoString(str, "POSITION("); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " IN "); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlay") == 0 && + list_length(func_call->args) == 3) + { + /* + * "OVERLAY" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "overlay("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " placing "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " from "); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "pg_collation_for") == 0 && + list_length(func_call->args) == 1) + { + /* + * "collation for" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlay) + */ + appendStringInfoString(str, "collation for ("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "extract") == 0 && + list_length(func_call->args) == 2) + { + /* + * "EXTRACT" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.extract) + */ + appendStringInfoString(str, "extract ("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "overlaps") == 0 && + list_length(func_call->args) == 4) + { + /* + * "OVERLAPS" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.overlaps) + * format: (start_1, end_1) overlaps (start_2, end_2) + */ + appendStringInfoChar(str, '('); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, ", "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, ") "); + + appendStringInfoString(str, "overlaps "); + appendStringInfoChar(str, '('); + deparseExpr(str, lthird(func_call->args)); + appendStringInfoString(str, ", "); + deparseExpr(str, lfourth(func_call->args)); + appendStringInfoString(str, ") "); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + ( + strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0 || + strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0 || + strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0 + )) + { + /* + * "TRIM " is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.ltrim) + * Note that the first and second arguments are switched in this format + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + appendStringInfoString(str, "TRIM ("); + if (strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0) + appendStringInfoString(str, "LEADING "); + else if (strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0) + appendStringInfoString(str, "BOTH "); + else if (strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0) + appendStringInfoString(str, "TRAILING "); + + if (list_length(func_call->args) == 2) + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " FROM "); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "timezone") == 0 && + list_length(func_call->args) == 2) + { + /* + * "AT TIME ZONE" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.timezone) + * Note that the arguments are swapped in this case + */ + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoString(str, " AT TIME ZONE "); + deparseExpr(str, linitial(func_call->args)); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "normalize") == 0) + { + /* + * "NORMALIZE" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.normalize) + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + appendStringInfoString(str, "normalize ("); + + deparseExpr(str, linitial(func_call->args)); + if (list_length(func_call->args) == 2) + { + appendStringInfoString(str, ", "); + Assert(IsA(lsecond(func_call->args), A_Const)); + A_Const *aconst = lsecond(func_call->args); + deparseValue(str, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + } + appendStringInfoChar(str, ')'); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "is_normalized") == 0) + { + /* + * "IS NORMALIZED" is a keyword on its own merit, and only accepts the + * keyword parameter style when its called as a keyword, not as a regular function (i.e. pg_catalog.is_normalized) + */ + Assert(list_length(func_call->args) == 1 || list_length(func_call->args) == 2); + + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " IS "); + if (list_length(func_call->args) == 2) + { + Assert(IsA(lsecond(func_call->args), A_Const)); + A_Const *aconst = lsecond(func_call->args); + deparseValue(str, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); + } + appendStringInfoString(str, " NORMALIZED "); + return; + } else if (func_call->funcformat == COERCE_SQL_SYNTAX && + list_length(func_call->funcname) == 2 && + strcmp(strVal(linitial(func_call->funcname)), "pg_catalog") == 0 && + strcmp(strVal(lsecond(func_call->funcname)), "xmlexists") == 0 && + list_length(func_call->args) == 2) + { + appendStringInfoString(str, "xmlexists ("); + deparseExpr(str, linitial(func_call->args)); + appendStringInfoString(str, " PASSING "); + deparseExpr(str, lsecond(func_call->args)); + appendStringInfoChar(str, ')'); + return; + } + + deparseFuncName(str, func_call->funcname); + appendStringInfoChar(str, '('); + + if (func_call->agg_distinct) + appendStringInfoString(str, "DISTINCT "); + + if (func_call->agg_star) + { + appendStringInfoChar(str, '*'); + } + else if (list_length(func_call->args) > 0) + { + foreach(lc, func_call->args) + { + if (func_call->func_variadic && !lnext(func_call->args, lc)) + appendStringInfoString(str, "VARIADIC "); + deparseFuncArgExpr(str, lfirst(lc)); + if (lnext(func_call->args, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoChar(str, ' '); + + if (func_call->agg_order != NULL && !func_call->agg_within_group) + { + deparseOptSortClause(str, func_call->agg_order); + } + + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + + if (func_call->agg_order != NULL && func_call->agg_within_group) + { + appendStringInfoString(str, "WITHIN GROUP ("); + deparseOptSortClause(str, func_call->agg_order); + removeTrailingSpace(str); + appendStringInfoString(str, ") "); + } + + if (func_call->agg_filter) + { + appendStringInfoString(str, "FILTER (WHERE "); + deparseExpr(str, func_call->agg_filter); + appendStringInfoString(str, ") "); + } + + if (func_call->over) + { + appendStringInfoString(str, "OVER "); + if (func_call->over->name) + appendStringInfoString(str, func_call->over->name); + else + deparseWindowDef(str, func_call->over); + } + + removeTrailingSpace(str); +} + +static void deparseWindowDef(StringInfo str, WindowDef* window_def) +{ + ListCell *lc; + + // The parent node is responsible for outputting window_def->name + + appendStringInfoChar(str, '('); + + if (window_def->refname != NULL) + { + appendStringInfoString(str, quote_identifier(window_def->refname)); + appendStringInfoChar(str, ' '); + } + + if (list_length(window_def->partitionClause) > 0) + { + appendStringInfoString(str, "PARTITION BY "); + deparseExprList(str, window_def->partitionClause); + appendStringInfoChar(str, ' '); + } + + deparseOptSortClause(str, window_def->orderClause); + + if (window_def->frameOptions & FRAMEOPTION_NONDEFAULT) + { + if (window_def->frameOptions & FRAMEOPTION_RANGE) + appendStringInfoString(str, "RANGE "); + else if (window_def->frameOptions & FRAMEOPTION_ROWS) + appendStringInfoString(str, "ROWS "); + else if (window_def->frameOptions & FRAMEOPTION_GROUPS) + appendStringInfoString(str, "GROUPS "); + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + appendStringInfoString(str, "BETWEEN "); + + // frame_start + if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) + { + appendStringInfoString(str, "UNBOUNDED PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_START_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) + { + Assert(window_def->startOffset != NULL); + deparseExpr(str, window_def->startOffset); + appendStringInfoString(str, " FOLLOWING "); + } + + if (window_def->frameOptions & FRAMEOPTION_BETWEEN) + { + appendStringInfoString(str, "AND "); + + // frame_end + if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) + { + Assert(false); // disallowed + } + else if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) + { + appendStringInfoString(str, "UNBOUNDED FOLLOWING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_CURRENT_ROW) + { + appendStringInfoString(str, "CURRENT ROW "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " PRECEDING "); + } + else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING) + { + Assert(window_def->endOffset != NULL); + deparseExpr(str, window_def->endOffset); + appendStringInfoString(str, " FOLLOWING "); + } + } + + if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) + appendStringInfoString(str, "EXCLUDE CURRENT ROW "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_GROUP) + appendStringInfoString(str, "EXCLUDE GROUP "); + else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_TIES) + appendStringInfoString(str, "EXCLUDE TIES "); + } + + removeTrailingSpace(str); + appendStringInfoChar(str, ')'); +} + +static void deparseColumnRef(StringInfo str, ColumnRef* column_ref) +{ + Assert(list_length(column_ref->fields) >= 1); + + if (IsA(linitial(column_ref->fields), A_Star)) + deparseAStar(str, castNode(A_Star, linitial(column_ref->fields))); + else if (IsA(linitial(column_ref->fields), String)) + deparseColLabel(str, strVal(linitial(column_ref->fields))); + + deparseOptIndirection(str, column_ref->fields, 1); +} + +static void deparseSubLink(StringInfo str, SubLink* sub_link) +{ + switch (sub_link->subLinkType) { + case EXISTS_SUBLINK: + appendStringInfoString(str, "EXISTS ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ALL_SUBLINK: + deparseExpr(str, sub_link->testexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ALL ("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ANY_SUBLINK: + deparseExpr(str, sub_link->testexpr); + if (list_length(sub_link->operName) > 0) + { + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, sub_link->operName); + appendStringInfoString(str, " ANY "); + } + else + { + appendStringInfoString(str, " IN "); + } + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case ROWCOMPARE_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case EXPR_SUBLINK: + appendStringInfoString(str, "("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case MULTIEXPR_SUBLINK: + // Not present in raw parse trees + Assert(false); + return; + case ARRAY_SUBLINK: + appendStringInfoString(str, "ARRAY("); + deparseSelectStmt(str, castNode(SelectStmt, sub_link->subselect)); + appendStringInfoChar(str, ')'); + return; + case CTE_SUBLINK: /* for SubPlans only */ + // Not present in raw parse trees + Assert(false); + return; + } +} + +static void deparseAExpr(StringInfo str, A_Expr* a_expr, DeparseNodeContext context) +{ + ListCell *lc; + char *name; + + bool need_lexpr_parens = a_expr->lexpr != NULL && (IsA(a_expr->lexpr, BoolExpr) || IsA(a_expr->lexpr, NullTest) || IsA(a_expr->lexpr, A_Expr)); + bool need_rexpr_parens = a_expr->rexpr != NULL && (IsA(a_expr->rexpr, BoolExpr) || IsA(a_expr->rexpr, NullTest) || IsA(a_expr->rexpr, A_Expr)); + + switch (a_expr->kind) { + case AEXPR_OP: /* normal operator */ + { + bool need_outer_parens = context == DEPARSE_NODE_CONTEXT_A_EXPR; + + if (need_outer_parens) + appendStringInfoChar(str, '('); + if (a_expr->lexpr != NULL) + { + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + deparseQualOp(str, a_expr->name); + if (a_expr->rexpr != NULL) + { + appendStringInfoChar(str, ' '); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + } + + if (need_outer_parens) + appendStringInfoChar(str, ')'); + } + return; + case AEXPR_OP_ANY: /* scalar op ANY (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ANY("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_OP_ALL: /* scalar op ALL (array) */ + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + deparseSubqueryOp(str, a_expr->name); + appendStringInfoString(str, " ALL("); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_DISTINCT: /* IS DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + if (need_lexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->lexpr); + if (need_lexpr_parens) + appendStringInfoChar(str, ')'); + appendStringInfoString(str, " IS DISTINCT FROM "); + if (need_rexpr_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, a_expr->rexpr); + if (need_rexpr_parens) + appendStringInfoChar(str, ')'); + return; + case AEXPR_NOT_DISTINCT: /* IS NOT DISTINCT FROM - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, " IS NOT DISTINCT FROM "); + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_NULLIF: /* NULLIF - name must be "=" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(strcmp(strVal(linitial(a_expr->name)), "=") == 0); + + appendStringInfoString(str, "NULLIF("); + deparseExpr(str, a_expr->lexpr); + appendStringInfoString(str, ", "); + deparseExpr(str, a_expr->rexpr); + appendStringInfoChar(str, ')'); + return; + case AEXPR_IN: /* [NOT] IN - name must be "=" or "<>" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "=") == 0) { + appendStringInfoString(str, "IN "); + } else if (strcmp(name, "<>") == 0) { + appendStringInfoString(str, "NOT IN "); + } else { + Assert(false); + } + appendStringInfoChar(str, '('); + if (IsA(a_expr->rexpr, SubLink)) + deparseSubLink(str, castNode(SubLink, a_expr->rexpr)); + else + deparseExprList(str, castNode(List, a_expr->rexpr)); + appendStringInfoChar(str, ')'); + return; + case AEXPR_LIKE: /* [NOT] LIKE - name must be "~~" or "!~~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~~") == 0) { + appendStringInfoString(str, "LIKE "); + } else if (strcmp(name, "!~~") == 0) { + appendStringInfoString(str, "NOT LIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_ILIKE: /* [NOT] ILIKE - name must be "~~*" or "!~~*" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~~*") == 0) { + appendStringInfoString(str, "ILIKE "); + } else if (strcmp(name, "!~~*") == 0) { + appendStringInfoString(str, "NOT ILIKE "); + } else { + Assert(false); + } + + deparseExpr(str, a_expr->rexpr); + return; + case AEXPR_SIMILAR: /* [NOT] SIMILAR - name must be "~" or "!~" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + + name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; + if (strcmp(name, "~") == 0) { + appendStringInfoString(str, "SIMILAR TO "); + } else if (strcmp(name, "!~") == 0) { + appendStringInfoString(str, "NOT SIMILAR TO "); + } else { + Assert(false); + } + + FuncCall *n = castNode(FuncCall, a_expr->rexpr); + Assert(list_length(n->funcname) == 2); + Assert(strcmp(strVal(linitial(n->funcname)), "pg_catalog") == 0); + Assert(strcmp(strVal(lsecond(n->funcname)), "similar_to_escape") == 0); + Assert(list_length(n->args) == 1 || list_length(n->args) == 2); + + deparseExpr(str, linitial(n->args)); + if (list_length(n->args) == 2) + { + appendStringInfoString(str, " ESCAPE "); + deparseExpr(str, lsecond(n->args)); + } + + return; + case AEXPR_BETWEEN: /* name must be "BETWEEN" */ + case AEXPR_NOT_BETWEEN: /* name must be "NOT BETWEEN" */ + case AEXPR_BETWEEN_SYM: /* name must be "BETWEEN SYMMETRIC" */ + case AEXPR_NOT_BETWEEN_SYM: /* name must be "NOT BETWEEN SYMMETRIC" */ + Assert(list_length(a_expr->name) == 1); + Assert(IsA(linitial(a_expr->name), String)); + Assert(IsA(a_expr->rexpr, List)); + + deparseExpr(str, a_expr->lexpr); + appendStringInfoChar(str, ' '); + appendStringInfoString(str, strVal(linitial(a_expr->name))); + appendStringInfoChar(str, ' '); + + foreach(lc, castNode(List, a_expr->rexpr)) { + deparseExpr(str, lfirst(lc)); + if (lnext(castNode(List, a_expr->rexpr), lc)) + appendStringInfoString(str, " AND "); + } + return; + } +} + +static void deparseBoolExpr(StringInfo str, BoolExpr *bool_expr) +{ + const ListCell *lc = NULL; + switch (bool_expr->boolop) + { + case AND_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(bool_expr->args, lc)) + appendStringInfoString(str, " AND "); + } + return; + case OR_EXPR: + foreach(lc, bool_expr->args) + { + // Put parantheses around AND + OR nodes that are inside + bool need_parens = IsA(lfirst(lc), BoolExpr) && (castNode(BoolExpr, lfirst(lc))->boolop == AND_EXPR || castNode(BoolExpr, lfirst(lc))->boolop == OR_EXPR); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, lfirst(lc)); + + if (need_parens) + appendStringInfoChar(str, ')'); + + if (lnext(bool_expr->args, lc)) + appendStringInfoString(str, " OR "); + } + return; + case NOT_EXPR: + Assert(list_length(bool_expr->args) == 1); + bool need_parens = IsA(linitial(bool_expr->args), BoolExpr) && (castNode(BoolExpr, linitial(bool_expr->args))->boolop == AND_EXPR || castNode(BoolExpr, linitial(bool_expr->args))->boolop == OR_EXPR); + appendStringInfoString(str, "NOT "); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, linitial(bool_expr->args)); + if (need_parens) + appendStringInfoChar(str, ')'); + return; + } +} + +static void deparseAStar(StringInfo str, A_Star *a_star) +{ + appendStringInfoChar(str, '*'); +} + +static void deparseCollateClause(StringInfo str, CollateClause* collate_clause) +{ + ListCell *lc; + if (collate_clause->arg != NULL) + { + bool need_parens = IsA(collate_clause->arg, A_Expr); + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, collate_clause->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + } + appendStringInfoString(str, "COLLATE "); + deparseAnyName(str, collate_clause->collname); +} + +static void deparseSortBy(StringInfo str, SortBy* sort_by) +{ + deparseExpr(str, sort_by->node); + appendStringInfoChar(str, ' '); + + switch (sort_by->sortby_dir) + { + case SORTBY_DEFAULT: + break; + case SORTBY_ASC: + appendStringInfoString(str, "ASC "); + break; + case SORTBY_DESC: + appendStringInfoString(str, "DESC "); + break; + case SORTBY_USING: + appendStringInfoString(str, "USING "); + deparseQualOp(str, sort_by->useOp); + break; + } + + switch (sort_by->sortby_nulls) + { + case SORTBY_NULLS_DEFAULT: + break; + case SORTBY_NULLS_FIRST: + appendStringInfoString(str, "NULLS FIRST "); + break; + case SORTBY_NULLS_LAST: + appendStringInfoString(str, "NULLS LAST "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseParamRef(StringInfo str, ParamRef* param_ref) +{ + if (param_ref->number == 0) { + appendStringInfoChar(str, '?'); + } else { + appendStringInfo(str, "$%d", param_ref->number); + } +} + +static void deparseSQLValueFunction(StringInfo str, SQLValueFunction* sql_value_function) +{ + switch (sql_value_function->op) + { + case SVFOP_CURRENT_DATE: + appendStringInfoString(str, "current_date"); + break; + case SVFOP_CURRENT_TIME: + appendStringInfoString(str, "current_time"); + break; + case SVFOP_CURRENT_TIME_N: + appendStringInfoString(str, "current_time"); // with precision + break; + case SVFOP_CURRENT_TIMESTAMP: + appendStringInfoString(str, "current_timestamp"); + break; + case SVFOP_CURRENT_TIMESTAMP_N: + appendStringInfoString(str, "current_timestamp"); // with precision + break; + case SVFOP_LOCALTIME: + appendStringInfoString(str, "localtime"); + break; + case SVFOP_LOCALTIME_N: + appendStringInfoString(str, "localtime"); // with precision + break; + case SVFOP_LOCALTIMESTAMP: + appendStringInfoString(str, "localtimestamp"); + break; + case SVFOP_LOCALTIMESTAMP_N: + appendStringInfoString(str, "localtimestamp"); // with precision + break; + case SVFOP_CURRENT_ROLE: + appendStringInfoString(str, "current_role"); + break; + case SVFOP_CURRENT_USER: + appendStringInfoString(str, "current_user"); + break; + case SVFOP_USER: + appendStringInfoString(str, "user"); + break; + case SVFOP_SESSION_USER: + appendStringInfoString(str, "session_user"); + break; + case SVFOP_CURRENT_CATALOG: + appendStringInfoString(str, "current_catalog"); + break; + case SVFOP_CURRENT_SCHEMA: + appendStringInfoString(str, "current_schema"); + break; + } + + if (sql_value_function->typmod != -1) + { + appendStringInfo(str, "(%d)", sql_value_function->typmod); + } +} + +static void deparseWithClause(StringInfo str, WithClause *with_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "WITH "); + if (with_clause->recursive) + appendStringInfoString(str, "RECURSIVE "); + + foreach(lc, with_clause->ctes) { + deparseCommonTableExpr(str, castNode(CommonTableExpr, lfirst(lc))); + if (lnext(with_clause->ctes, lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseJoinExpr(StringInfo str, JoinExpr *join_expr) +{ + ListCell *lc; + bool need_alias_parens = join_expr->alias != NULL; + bool need_rarg_parens = IsA(join_expr->rarg, JoinExpr) && castNode(JoinExpr, join_expr->rarg)->alias == NULL; + + if (need_alias_parens) + appendStringInfoChar(str, '('); + + deparseTableRef(str, join_expr->larg); + + appendStringInfoChar(str, ' '); + + if (join_expr->isNatural) + appendStringInfoString(str, "NATURAL "); + + switch (join_expr->jointype) + { + case JOIN_INNER: /* matching tuple pairs only */ + if (!join_expr->isNatural && join_expr->quals == NULL && list_length(join_expr->usingClause) == 0) + appendStringInfoString(str, "CROSS "); + break; + case JOIN_LEFT: /* pairs + unmatched LHS tuples */ + appendStringInfoString(str, "LEFT "); + break; + case JOIN_FULL: /* pairs + unmatched LHS + unmatched RHS */ + appendStringInfoString(str, "FULL "); + break; + case JOIN_RIGHT: /* pairs + unmatched RHS tuples */ + appendStringInfoString(str, "RIGHT "); + break; + case JOIN_SEMI: + case JOIN_ANTI: + case JOIN_UNIQUE_OUTER: + case JOIN_UNIQUE_INNER: + // Only used by the planner/executor, not seen in parser output + Assert(false); + break; + } + + appendStringInfoString(str, "JOIN "); + + if (need_rarg_parens) + appendStringInfoChar(str, '('); + deparseTableRef(str, join_expr->rarg); + if (need_rarg_parens) + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + + if (join_expr->quals != NULL) + { + appendStringInfoString(str, "ON "); + deparseExpr(str, join_expr->quals); + appendStringInfoChar(str, ' '); + } + + if (list_length(join_expr->usingClause) > 0) + { + appendStringInfoString(str, "USING ("); + deparseNameList(str, join_expr->usingClause); + appendStringInfoString(str, ") "); + + if (join_expr->join_using_alias) + { + appendStringInfoString(str, "AS "); + appendStringInfoString(str, join_expr->join_using_alias->aliasname); + } + } + + if (need_alias_parens) + appendStringInfoString(str, ") "); + + if (join_expr->alias != NULL) + deparseAlias(str, join_expr->alias); + + removeTrailingSpace(str); +} + +static void deparseCTESearchClause(StringInfo str, CTESearchClause *search_clause) +{ + appendStringInfoString(str, " SEARCH "); + if (search_clause->search_breadth_first) + appendStringInfoString(str, "BREADTH "); + else + appendStringInfoString(str, "DEPTH "); + + appendStringInfoString(str, "FIRST BY "); + + if (search_clause->search_col_list) + deparseColumnList(str, search_clause->search_col_list); + + appendStringInfoString(str, " SET "); + appendStringInfoString(str, quote_identifier(search_clause->search_seq_column)); +} + +static void deparseCTECycleClause(StringInfo str, CTECycleClause *cycle_clause) +{ + appendStringInfoString(str, " CYCLE "); + + if (cycle_clause->cycle_col_list) + deparseColumnList(str, cycle_clause->cycle_col_list); + + appendStringInfoString(str, " SET "); + appendStringInfoString(str, quote_identifier(cycle_clause->cycle_mark_column)); + + if (cycle_clause->cycle_mark_value) + { + appendStringInfoString(str, " TO "); + deparseExpr(str, cycle_clause->cycle_mark_value); + } + + if (cycle_clause->cycle_mark_default) + { + appendStringInfoString(str, " DEFAULT "); + deparseExpr(str, cycle_clause->cycle_mark_default); + } + + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(cycle_clause->cycle_path_column)); +} + +static void deparseCommonTableExpr(StringInfo str, CommonTableExpr *cte) +{ + deparseColId(str, cte->ctename); + + if (list_length(cte->aliascolnames) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, cte->aliascolnames); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + switch (cte->ctematerialized) { + case CTEMaterializeDefault: /* no option specified */ + break; + case CTEMaterializeAlways: + appendStringInfoString(str, "MATERIALIZED "); + break; + case CTEMaterializeNever: + appendStringInfoString(str, "NOT MATERIALIZED "); + break; + } + + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, cte->ctequery); + appendStringInfoChar(str, ')'); + + if (cte->search_clause) + deparseCTESearchClause(str, cte->search_clause); + if (cte->cycle_clause) + deparseCTECycleClause(str, cte->cycle_clause); +} + +static void deparseRangeSubselect(StringInfo str, RangeSubselect *range_subselect) +{ + if (range_subselect->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoChar(str, '('); + deparseSelectStmt(str, castNode(SelectStmt, range_subselect->subquery)); + appendStringInfoChar(str, ')'); + + if (range_subselect->alias != NULL) + { + appendStringInfoChar(str, ' '); + deparseAlias(str, range_subselect->alias); + } +} + +static void deparseRangeFunction(StringInfo str, RangeFunction *range_func) +{ + ListCell *lc; + ListCell *lc2; + + if (range_func->lateral) + appendStringInfoString(str, "LATERAL "); + + if (range_func->is_rowsfrom) + { + appendStringInfoString(str, "ROWS FROM "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->functions) + { + List *lfunc = castNode(List, lfirst(lc)); + Assert(list_length(lfunc) == 2); + deparseFuncExprWindowless(str, linitial(lfunc)); + appendStringInfoChar(str, ' '); + List *coldeflist = castNode(List, lsecond(lfunc)); + if (list_length(coldeflist) > 0) + { + appendStringInfoString(str, "AS ("); + foreach(lc2, coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc2))); + if (lnext(coldeflist, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + if (lnext(range_func->functions, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + else + { + Assert(list_length(linitial(range_func->functions)) == 2); + deparseFuncExprWindowless(str, linitial(linitial(range_func->functions))); + } + appendStringInfoChar(str, ' '); + + if (range_func->ordinality) + appendStringInfoString(str, "WITH ORDINALITY "); + + if (range_func->alias != NULL) + { + deparseAlias(str, range_func->alias); + appendStringInfoChar(str, ' '); + } + + if (list_length(range_func->coldeflist) > 0) + { + if (range_func->alias == NULL) + appendStringInfoString(str, "AS "); + appendStringInfoChar(str, '('); + foreach(lc, range_func->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(range_func->coldeflist, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseAArrayExpr(StringInfo str, A_ArrayExpr *array_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "ARRAY["); + deparseExprList(str, array_expr->elements); + appendStringInfoChar(str, ']'); +} + +static void deparseRowExpr(StringInfo str, RowExpr *row_expr) +{ + ListCell *lc; + + switch (row_expr->row_format) + { + case COERCE_EXPLICIT_CALL: + appendStringInfoString(str, "ROW"); + break; + case COERCE_SQL_SYNTAX: + case COERCE_EXPLICIT_CAST: + // Not present in raw parser output + Assert(false); + break; + case COERCE_IMPLICIT_CAST: + // No prefix + break; + } + + appendStringInfoString(str, "("); + deparseExprList(str, row_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseTypeCast(StringInfo str, TypeCast *type_cast, DeparseNodeContext context) +{ + bool need_parens = false; + + Assert(type_cast->typeName != NULL); + + if (IsA(type_cast->arg, A_Expr)) + { + appendStringInfoString(str, "CAST("); + deparseExpr(str, type_cast->arg); + appendStringInfoString(str, " AS "); + deparseTypeName(str, type_cast->typeName); + appendStringInfoChar(str, ')'); + return; + } + + if (IsA(type_cast->arg, A_Const)) + { + A_Const *a_const = castNode(A_Const, type_cast->arg); + + if (list_length(type_cast->typeName->names) == 2 && + strcmp(strVal(linitial(type_cast->typeName->names)), "pg_catalog") == 0) + { + char *typename = strVal(lsecond(type_cast->typeName->names)); + if (strcmp(typename, "bpchar") == 0 && type_cast->typeName->typmods == NULL) + { + appendStringInfoString(str, "char "); + deparseAConst(str, a_const); + return; + } + else if (strcmp(typename, "bool") == 0 && IsA(&a_const->val, String)) + { + /* + * Handle "bool" or "false" in the statement, which is represented as a typecast + * (other boolean casts should be represented as a cast, i.e. don't need special handling) + */ + char *const_val = strVal(&a_const->val); + if (strcmp(const_val, "t") == 0) + { + appendStringInfoString(str, "true"); + return; + } + if (strcmp(const_val, "f") == 0) + { + appendStringInfoString(str, "false"); + return; + } + } + else if (strcmp(typename, "interval") == 0 && context == DEPARSE_NODE_CONTEXT_SET_STATEMENT && IsA(&a_const->val, String)) + { + appendStringInfoString(str, "interval "); + deparseAConst(str, a_const); + deparseIntervalTypmods(str, type_cast->typeName); + return; + } + } + + // Ensure negative values have wrapping parentheses + if (IsA(&a_const->val, Float) || (IsA(&a_const->val, Integer) && intVal(&a_const->val) < 0)) + { + need_parens = true; + } + + if (list_length(type_cast->typeName->names) == 1 && + strcmp(strVal(linitial(type_cast->typeName->names)), "point") == 0 && + a_const->location > type_cast->typeName->location) + { + appendStringInfoString(str, " point "); + deparseAConst(str, a_const); + return; + } + } + + + if (need_parens) + appendStringInfoChar(str, '('); + deparseExpr(str, type_cast->arg); + if (need_parens) + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, "::"); + deparseTypeName(str, type_cast->typeName); +} + +static void deparseTypeName(StringInfo str, TypeName *type_name) +{ + ListCell *lc; + bool skip_typmods = false; + + if (type_name->setof) + appendStringInfoString(str, "SETOF "); + + if (list_length(type_name->names) == 2 && strcmp(strVal(linitial(type_name->names)), "pg_catalog") == 0) + { + const char *name = strVal(lsecond(type_name->names)); + if (strcmp(name, "bpchar") == 0) + { + appendStringInfoString(str, "char"); + } + else if (strcmp(name, "varchar") == 0) + { + appendStringInfoString(str, "varchar"); + } + else if (strcmp(name, "numeric") == 0) + { + appendStringInfoString(str, "numeric"); + } + else if (strcmp(name, "bool") == 0) + { + appendStringInfoString(str, "boolean"); + } + else if (strcmp(name, "int2") == 0) + { + appendStringInfoString(str, "smallint"); + } + else if (strcmp(name, "int4") == 0) + { + appendStringInfoString(str, "int"); + } + else if (strcmp(name, "int8") == 0) + { + appendStringInfoString(str, "bigint"); + } + else if (strcmp(name, "real") == 0 || strcmp(name, "float4") == 0) + { + appendStringInfoString(str, "real"); + } + else if (strcmp(name, "float8") == 0) + { + appendStringInfoString(str, "double precision"); + } + else if (strcmp(name, "time") == 0) + { + appendStringInfoString(str, "time"); + } + else if (strcmp(name, "timetz") == 0) + { + appendStringInfoString(str, "time "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "timestamp") == 0) + { + appendStringInfoString(str, "timestamp"); + } + else if (strcmp(name, "timestamptz") == 0) + { + appendStringInfoString(str, "timestamp "); + if (list_length(type_name->typmods) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + deparseSignedIconst(str, (Node *) &castNode(A_Const, lfirst(lc))->val); + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + appendStringInfoString(str, "with time zone"); + skip_typmods = true; + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) == 0) + { + appendStringInfoString(str, "interval"); + } + else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) >= 1) + { + appendStringInfoString(str, "interval"); + deparseIntervalTypmods(str, type_name); + + skip_typmods = true; + } + else + { + appendStringInfoString(str, "pg_catalog."); + appendStringInfoString(str, name); + } + } + else + { + deparseAnyName(str, type_name->names); + } + + if (list_length(type_name->typmods) > 0 && !skip_typmods) + { + appendStringInfoChar(str, '('); + foreach(lc, type_name->typmods) + { + if (IsA(lfirst(lc), A_Const)) + deparseAConst(str, lfirst(lc)); + else if (IsA(lfirst(lc), ParamRef)) + deparseParamRef(str, lfirst(lc)); + else if (IsA(lfirst(lc), ColumnRef)) + deparseColumnRef(str, lfirst(lc)); + else + Assert(false); + + if (lnext(type_name->typmods, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + foreach(lc, type_name->arrayBounds) + { + appendStringInfoChar(str, '['); + if (IsA(lfirst(lc), Integer) && intVal(lfirst(lc)) != -1) + deparseSignedIconst(str, lfirst(lc)); + appendStringInfoChar(str, ']'); + } + + if (type_name->pct_type) + appendStringInfoString(str, "%type"); +} + +// Handle typemods for Interval types separately +// so that they can be applied appropriately for different contexts. +// For example, when using `SET` a query like `INTERVAL 'x' hour TO minute` +// the `INTERVAL` keyword is specified first. +// In all other contexts, intervals use the `'x'::interval` style. +static void deparseIntervalTypmods(StringInfo str, TypeName *type_name) +{ + const char *name = strVal(lsecond(type_name->names)); + Assert(strcmp(name, "interval") == 0); + Assert(list_length(type_name->typmods) >= 1); + Assert(IsA(linitial(type_name->typmods), A_Const)); + Assert(IsA(&castNode(A_Const, linitial(type_name->typmods))->val, Integer)); + + int fields = intVal(&castNode(A_Const, linitial(type_name->typmods))->val); + + // This logic is based on intervaltypmodout in timestamp.c + switch (fields) + { + case INTERVAL_MASK(YEAR): + appendStringInfoString(str, " year"); + break; + case INTERVAL_MASK(MONTH): + appendStringInfoString(str, " month"); + break; + case INTERVAL_MASK(DAY): + appendStringInfoString(str, " day"); + break; + case INTERVAL_MASK(HOUR): + appendStringInfoString(str, " hour"); + break; + case INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " minute"); + break; + case INTERVAL_MASK(SECOND): + appendStringInfoString(str, " second"); + break; + case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): + appendStringInfoString(str, " year to month"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): + appendStringInfoString(str, " day to hour"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " day to minute"); + break; + case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " day to second"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): + appendStringInfoString(str, " hour to minute"); + break; + case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " hour to second"); + break; + case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): + appendStringInfoString(str, " minute to second"); + break; + case INTERVAL_FULL_RANGE: + // Nothing + break; + default: + Assert(false); + break; + } + + if (list_length(type_name->typmods) == 2) + { + int precision = intVal(&castNode(A_Const, lsecond(type_name->typmods))->val); + if (precision != INTERVAL_FULL_PRECISION) + appendStringInfo(str, "(%d)", precision); + } +} + +static void deparseNullTest(StringInfo str, NullTest *null_test) +{ + // argisrow is always false in raw parser output + Assert(null_test->argisrow == false); + + deparseExpr(str, (Node *) null_test->arg); + switch (null_test->nulltesttype) + { + case IS_NULL: + appendStringInfoString(str, " IS NULL"); + break; + case IS_NOT_NULL: + appendStringInfoString(str, " IS NOT NULL"); + break; + } +} + +static void deparseCaseExpr(StringInfo str, CaseExpr *case_expr) +{ + ListCell *lc; + + appendStringInfoString(str, "CASE "); + + if (case_expr->arg != NULL) + { + deparseExpr(str, (Node *) case_expr->arg); + appendStringInfoChar(str, ' '); + } + + foreach(lc, case_expr->args) + { + deparseCaseWhen(str, castNode(CaseWhen, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (case_expr->defresult != NULL) + { + appendStringInfoString(str, "ELSE "); + deparseExpr(str, (Node *) case_expr->defresult); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "END"); +} + +static void deparseCaseWhen(StringInfo str, CaseWhen *case_when) +{ + appendStringInfoString(str, "WHEN "); + deparseExpr(str, (Node *) case_when->expr); + appendStringInfoString(str, " THEN "); + deparseExpr(str, (Node *) case_when->result); +} + +static void deparseAIndirection(StringInfo str, A_Indirection *a_indirection) +{ + ListCell *lc; + bool need_parens = + IsA(a_indirection->arg, A_Indirection) || + IsA(a_indirection->arg, FuncCall) || + IsA(a_indirection->arg, A_Expr) || + IsA(a_indirection->arg, TypeCast) || + IsA(a_indirection->arg, RowExpr) || + (IsA(a_indirection->arg, ColumnRef) && !IsA(linitial(a_indirection->indirection), A_Indices)); + + if (need_parens) + appendStringInfoChar(str, '('); + + deparseExpr(str, a_indirection->arg); + + if (need_parens) + appendStringInfoChar(str, ')'); + + deparseOptIndirection(str, a_indirection->indirection, 0); +} + +static void deparseAIndices(StringInfo str, A_Indices *a_indices) +{ + appendStringInfoChar(str, '['); + if (a_indices->lidx != NULL) + deparseExpr(str, a_indices->lidx); + if (a_indices->is_slice) + appendStringInfoChar(str, ':'); + if (a_indices->uidx != NULL) + deparseExpr(str, a_indices->uidx); + appendStringInfoChar(str, ']'); +} + +static void deparseCoalesceExpr(StringInfo str, CoalesceExpr *coalesce_expr) +{ + appendStringInfoString(str, "COALESCE("); + deparseExprList(str, coalesce_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseMinMaxExpr(StringInfo str, MinMaxExpr *min_max_expr) +{ + switch (min_max_expr->op) + { + case IS_GREATEST: + appendStringInfoString(str, "GREATEST("); + break; + case IS_LEAST: + appendStringInfoString(str, "LEAST("); + break; + } + deparseExprList(str, min_max_expr->args); + appendStringInfoChar(str, ')'); +} + +static void deparseBooleanTest(StringInfo str, BooleanTest *boolean_test) +{ + deparseExpr(str, (Node *) boolean_test->arg); + switch (boolean_test->booltesttype) + { + case IS_TRUE: + appendStringInfoString(str, " IS TRUE"); + break; + case IS_NOT_TRUE: + appendStringInfoString(str, " IS NOT TRUE"); + break; + case IS_FALSE: + appendStringInfoString(str, " IS FALSE"); + break; + case IS_NOT_FALSE: + appendStringInfoString(str, " IS NOT FALSE"); + break; + case IS_UNKNOWN: + appendStringInfoString(str, " IS UNKNOWN"); + break; + case IS_NOT_UNKNOWN: + appendStringInfoString(str, " IS NOT UNKNOWN"); + break; + default: + Assert(false); + } +} + +static void deparseColumnDef(StringInfo str, ColumnDef *column_def) +{ + ListCell *lc; + + if (column_def->colname != NULL) + { + appendStringInfoString(str, quote_identifier(column_def->colname)); + appendStringInfoChar(str, ' '); + } + + if (column_def->typeName != NULL) + { + deparseTypeName(str, column_def->typeName); + appendStringInfoChar(str, ' '); + } + + if (column_def->raw_default != NULL) + { + appendStringInfoString(str, "USING "); + deparseExpr(str, column_def->raw_default); + appendStringInfoChar(str, ' '); + } + + if (column_def->fdwoptions != NULL) + { + deparseCreateGenericOptions(str, column_def->fdwoptions); + appendStringInfoChar(str, ' '); + } + + foreach(lc, column_def->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (column_def->collClause != NULL) + { + deparseCollateClause(str, column_def->collClause); + } + + removeTrailingSpace(str); +} + +static void deparseInsertOverride(StringInfo str, OverridingKind override) +{ + switch (override) + { + case OVERRIDING_NOT_SET: + // Do nothing + break; + case OVERRIDING_USER_VALUE: + appendStringInfoString(str, "OVERRIDING USER VALUE "); + break; + case OVERRIDING_SYSTEM_VALUE: + appendStringInfoString(str, "OVERRIDING SYSTEM VALUE "); + break; + } +} + +static void deparseInsertStmt(StringInfo str, InsertStmt *insert_stmt) +{ + ListCell *lc; + ListCell *lc2; + + if (insert_stmt->withClause != NULL) + { + deparseWithClause(str, insert_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "INSERT INTO "); + deparseRangeVar(str, insert_stmt->relation, DEPARSE_NODE_CONTEXT_INSERT_RELATION); + appendStringInfoChar(str, ' '); + + if (list_length(insert_stmt->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseInsertColumnList(str, insert_stmt->cols); + appendStringInfoString(str, ") "); + } + + deparseInsertOverride(str, insert_stmt->override); + + if (insert_stmt->selectStmt != NULL) + { + deparseSelectStmt(str, castNode(SelectStmt, insert_stmt->selectStmt)); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "DEFAULT VALUES "); + } + + if (insert_stmt->onConflictClause != NULL) + { + deparseOnConflictClause(str, insert_stmt->onConflictClause); + appendStringInfoChar(str, ' '); + } + + if (list_length(insert_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, insert_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseInferClause(StringInfo str, InferClause *infer_clause) +{ + ListCell *lc; + + if (list_length(infer_clause->indexElems) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, infer_clause->indexElems) + { + deparseIndexElem(str, lfirst(lc)); + if (lnext(infer_clause->indexElems, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + if (infer_clause->conname != NULL) + { + appendStringInfoString(str, "ON CONSTRAINT "); + appendStringInfoString(str, quote_identifier(infer_clause->conname)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, infer_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseOnConflictClause(StringInfo str, OnConflictClause *on_conflict_clause) +{ + ListCell *lc; + + appendStringInfoString(str, "ON CONFLICT "); + + if (on_conflict_clause->infer != NULL) + { + deparseInferClause(str, on_conflict_clause->infer); + appendStringInfoChar(str, ' '); + } + + switch (on_conflict_clause->action) + { + case ONCONFLICT_NONE: + Assert(false); + break; + case ONCONFLICT_NOTHING: + appendStringInfoString(str, "DO NOTHING "); + break; + case ONCONFLICT_UPDATE: + appendStringInfoString(str, "DO UPDATE "); + break; + } + + if (list_length(on_conflict_clause->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, on_conflict_clause->targetList); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, on_conflict_clause->whereClause); + + removeTrailingSpace(str); +} + +static void deparseUpdateStmt(StringInfo str, UpdateStmt *update_stmt) +{ + ListCell* lc; + ListCell* lc2; + ListCell* lc3; + + if (update_stmt->withClause != NULL) + { + deparseWithClause(str, update_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "UPDATE "); + deparseRangeVar(str, update_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(update_stmt->targetList) > 0) + { + appendStringInfoString(str, "SET "); + deparseSetClauseList(str, update_stmt->targetList); + appendStringInfoChar(str, ' '); + } + + deparseFromClause(str, update_stmt->fromClause); + deparseWhereClause(str, update_stmt->whereClause); + + if (list_length(update_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, update_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseMergeStmt(StringInfo str, MergeStmt *merge_stmt) +{ + if (merge_stmt->withClause != NULL) + { + deparseWithClause(str, merge_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "MERGE INTO "); + deparseRangeVar(str, merge_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + deparseTableRef(str, merge_stmt->sourceRelation); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "ON "); + deparseExpr(str, merge_stmt->joinCondition); + appendStringInfoChar(str, ' '); + + ListCell *lc, *lc2; + foreach (lc, merge_stmt->mergeWhenClauses) + { + MergeWhenClause *clause = castNode(MergeWhenClause, lfirst(lc)); + + appendStringInfoString(str, "WHEN "); + + if (!clause->matched) + { + appendStringInfoString(str, "NOT "); + } + + appendStringInfoString(str, "MATCHED "); + + if (clause->condition) + { + appendStringInfoString(str, "AND "); + deparseExpr(str, clause->condition); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "THEN "); + + switch (clause->commandType) { + case CMD_INSERT: + appendStringInfoString(str, "INSERT "); + + if (clause->targetList) { + appendStringInfoChar(str, '('); + deparseInsertColumnList(str, clause->targetList); + appendStringInfoString(str, ") "); + } + + deparseInsertOverride(str, clause->override); + + if (clause->values) { + appendStringInfoString(str, "VALUES ("); + deparseExprList(str, clause->values); + appendStringInfoString(str, ")"); + } else { + appendStringInfoString(str, "DEFAULT VALUES "); + } + + break; + case CMD_UPDATE: + appendStringInfoString(str, "UPDATE SET "); + deparseSetClauseList(str, clause->targetList); + break; + case CMD_DELETE: + appendStringInfoString(str, "DELETE"); + break; + case CMD_NOTHING: + appendStringInfoString(str, "DO NOTHING"); + break; + default: + elog(ERROR, "deparse: unpermitted command type in merge statement: %d", clause->commandType); + break; + } + + if (lfirst(lc) != llast(merge_stmt->mergeWhenClauses)) + appendStringInfoChar(str, ' '); + } +} + +static void deparseDeleteStmt(StringInfo str, DeleteStmt *delete_stmt) +{ + if (delete_stmt->withClause != NULL) + { + deparseWithClause(str, delete_stmt->withClause); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "DELETE FROM "); + deparseRangeVar(str, delete_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (delete_stmt->usingClause != NULL) + { + appendStringInfoString(str, "USING "); + deparseFromList(str, delete_stmt->usingClause); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, delete_stmt->whereClause); + + if (list_length(delete_stmt->returningList) > 0) + { + appendStringInfoString(str, "RETURNING "); + deparseTargetList(str, delete_stmt->returningList); + } + + removeTrailingSpace(str); +} + +static void deparseLockingClause(StringInfo str, LockingClause *locking_clause) +{ + ListCell *lc; + + switch (locking_clause->strength) + { + case LCS_NONE: + /* no such clause - only used in PlanRowMark */ + Assert(false); + break; + case LCS_FORKEYSHARE: + appendStringInfoString(str, "FOR KEY SHARE "); + break; + case LCS_FORSHARE: + appendStringInfoString(str, "FOR SHARE "); + break; + case LCS_FORNOKEYUPDATE: + appendStringInfoString(str, "FOR NO KEY UPDATE "); + break; + case LCS_FORUPDATE: + appendStringInfoString(str, "FOR UPDATE "); + break; + } + + if (list_length(locking_clause->lockedRels) > 0) + { + appendStringInfoString(str, "OF "); + deparseQualifiedNameList(str, locking_clause->lockedRels); + } + + switch (locking_clause->waitPolicy) + { + case LockWaitError: + appendStringInfoString(str, "NOWAIT"); + break; + case LockWaitSkip: + appendStringInfoString(str, "SKIP LOCKED"); + break; + case LockWaitBlock: + // Default + break; + } + + removeTrailingSpace(str); +} + +static void deparseSetToDefault(StringInfo str, SetToDefault *set_to_default) +{ + appendStringInfoString(str, "DEFAULT"); +} + +static void deparseCreateCastStmt(StringInfo str, CreateCastStmt *create_cast_stmt) +{ + ListCell *lc; + ListCell *lc2; + + appendStringInfoString(str, "CREATE CAST ("); + deparseTypeName(str, create_cast_stmt->sourcetype); + appendStringInfoString(str, " AS "); + deparseTypeName(str, create_cast_stmt->targettype); + appendStringInfoString(str, ") "); + + if (create_cast_stmt->func != NULL) + { + appendStringInfoString(str, "WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_cast_stmt->func); + appendStringInfoChar(str, ' '); + } + else if (create_cast_stmt->inout) + { + appendStringInfoString(str, "WITH INOUT "); + } + else + { + appendStringInfoString(str, "WITHOUT FUNCTION "); + } + + switch (create_cast_stmt->context) + { + case COERCION_IMPLICIT: + appendStringInfoString(str, "AS IMPLICIT"); + break; + case COERCION_ASSIGNMENT: + appendStringInfoString(str, "AS ASSIGNMENT"); + break; + case COERCION_PLPGSQL: + // Not present in raw parser output + Assert(false); + break; + case COERCION_EXPLICIT: + // Default + break; + } +} + +static void deparseCreateOpClassStmt(StringInfo str, CreateOpClassStmt *create_op_class_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE OPERATOR CLASS "); + + deparseAnyName(str, create_op_class_stmt->opclassname); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->isDefault) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "FOR TYPE "); + deparseTypeName(str, create_op_class_stmt->datatype); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_class_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (create_op_class_stmt->opfamilyname != NULL) + { + appendStringInfoString(str, "FAMILY "); + deparseAnyName(str, create_op_class_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "AS "); + deparseOpclassItemList(str, create_op_class_stmt->items); +} + +static void deparseCreateOpFamilyStmt(StringInfo str, CreateOpFamilyStmt *create_op_family_stmt) +{ + appendStringInfoString(str, "CREATE OPERATOR FAMILY "); + + deparseAnyName(str, create_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_op_family_stmt->amname)); +} + +static void deparseCreateOpClassItem(StringInfo str, CreateOpClassItem *create_op_class_item) +{ + ListCell *lc = NULL; + + switch (create_op_class_item->itemtype) + { + case OPCLASS_ITEM_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + appendStringInfo(str, "%d ", create_op_class_item->number); + + if (create_op_class_item->name != NULL) + { + if (create_op_class_item->name->objargs != NULL) + deparseOperatorWithArgtypes(str, create_op_class_item->name); + else + deparseAnyOperator(str, create_op_class_item->name->objname); + appendStringInfoChar(str, ' '); + } + + if (create_op_class_item->order_family != NULL) + { + appendStringInfoString(str, "FOR ORDER BY "); + deparseAnyName(str, create_op_class_item->order_family); + } + + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoChar(str, ')'); + } + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + appendStringInfo(str, "%d ", create_op_class_item->number); + if (create_op_class_item->class_args != NULL) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, create_op_class_item->class_args); + appendStringInfoString(str, ") "); + } + if (create_op_class_item->name != NULL) + deparseFunctionWithArgtypes(str, create_op_class_item->name); + removeTrailingSpace(str); + break; + case OPCLASS_ITEM_STORAGETYPE: + appendStringInfoString(str, "STORAGE "); + deparseTypeName(str, create_op_class_item->storedtype); + break; + default: + Assert(false); + } +} + +static void deparseTableLikeClause(StringInfo str, TableLikeClause *table_like_clause) +{ + appendStringInfoString(str, "LIKE "); + deparseRangeVar(str, table_like_clause->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (table_like_clause->options == CREATE_TABLE_LIKE_ALL) + appendStringInfoString(str, "INCLUDING ALL "); + else + { + if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) + appendStringInfoString(str, "INCLUDING COMMENTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) + appendStringInfoString(str, "INCLUDING CONSTRAINTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS) + appendStringInfoString(str, "INCLUDING DEFAULTS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY) + appendStringInfoString(str, "INCLUDING IDENTITY "); + if (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) + appendStringInfoString(str, "INCLUDING GENERATED "); + if (table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) + appendStringInfoString(str, "INCLUDING INDEXES "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) + appendStringInfoString(str, "INCLUDING STATISTICS "); + if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) + appendStringInfoString(str, "INCLUDING STORAGE "); + } + removeTrailingSpace(str); +} + +static void deparseCreateDomainStmt(StringInfo str, CreateDomainStmt *create_domain_stmt) +{ + ListCell *lc; + + Assert(create_domain_stmt->typeName != NULL); + + appendStringInfoString(str, "CREATE DOMAIN "); + deparseAnyName(str, create_domain_stmt->domainname); + appendStringInfoString(str, " AS "); + + deparseTypeName(str, create_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (create_domain_stmt->collClause != NULL) + { + deparseCollateClause(str, create_domain_stmt->collClause); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_domain_stmt->constraints) + { + deparseConstraint(str, castNode(Constraint, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateExtensionStmt(StringInfo str, CreateExtensionStmt *create_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE EXTENSION "); + + if (create_extension_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseColId(str, create_extension_stmt->extname); + appendStringInfoChar(str, ' '); + + foreach (lc, create_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "schema") == 0) + { + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "VERSION "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "cascade") == 0) + { + appendStringInfoString(str, "CASCADE"); + } + else + { + Assert(false); + } + + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseConstraint(StringInfo str, Constraint *constraint) +{ + ListCell *lc; + + if (constraint->conname != NULL) + { + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, quote_identifier(constraint->conname)); + appendStringInfoChar(str, ' '); + } + + switch (constraint->contype) { + case CONSTR_NULL: + appendStringInfoString(str, "NULL "); + break; + case CONSTR_NOTNULL: + appendStringInfoString(str, "NOT NULL "); + break; + case CONSTR_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + deparseExpr(str, constraint->raw_expr); + break; + case CONSTR_IDENTITY: + appendStringInfoString(str, "GENERATED "); + switch (constraint->generated_when) + { + case ATTRIBUTE_IDENTITY_ALWAYS: + appendStringInfoString(str, "ALWAYS "); + break; + case ATTRIBUTE_IDENTITY_BY_DEFAULT: + appendStringInfoString(str, "BY DEFAULT "); + break; + default: + Assert(false); + } + appendStringInfoString(str, "AS IDENTITY "); + deparseOptParenthesizedSeqOptList(str, constraint->options); + break; + case CONSTR_GENERATED: + Assert(constraint->generated_when == ATTRIBUTE_IDENTITY_ALWAYS); + appendStringInfoString(str, "GENERATED ALWAYS AS ("); + deparseExpr(str, constraint->raw_expr); + appendStringInfoString(str, ") STORED "); + break; + case CONSTR_CHECK: + appendStringInfoString(str, "CHECK ("); + deparseExpr(str, constraint->raw_expr); + appendStringInfoString(str, ") "); + break; + case CONSTR_PRIMARY: + appendStringInfoString(str, "PRIMARY KEY "); + break; + case CONSTR_UNIQUE: + appendStringInfoString(str, "UNIQUE "); + break; + case CONSTR_EXCLUSION: + appendStringInfoString(str, "EXCLUDE "); + if (strcmp(constraint->access_method, DEFAULT_INDEX_TYPE) != 0) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(constraint->access_method)); + appendStringInfoChar(str, ' '); + } + appendStringInfoChar(str, '('); + foreach(lc, constraint->exclusions) + { + List *exclusion = castNode(List, lfirst(lc)); + Assert(list_length(exclusion) == 2); + deparseIndexElem(str, castNode(IndexElem, linitial(exclusion))); + appendStringInfoString(str, " WITH "); + deparseAnyOperator(str, castNode(List, lsecond(exclusion))); + if (lnext(constraint->exclusions, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + if (constraint->where_clause != NULL) + { + appendStringInfoString(str, "WHERE ("); + deparseExpr(str, constraint->where_clause); + appendStringInfoString(str, ") "); + } + break; + case CONSTR_FOREIGN: + if (list_length(constraint->fk_attrs) > 0) + appendStringInfoString(str, "FOREIGN KEY "); + break; + case CONSTR_ATTR_DEFERRABLE: + appendStringInfoString(str, "DEFERRABLE "); + break; + case CONSTR_ATTR_NOT_DEFERRABLE: + appendStringInfoString(str, "NOT DEFERRABLE "); + break; + case CONSTR_ATTR_DEFERRED: + appendStringInfoString(str, "INITIALLY DEFERRED "); + break; + case CONSTR_ATTR_IMMEDIATE: + appendStringInfoString(str, "INITIALLY IMMEDIATE "); + break; + } + + if (list_length(constraint->keys) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->keys); + appendStringInfoString(str, ") "); + } + + if (list_length(constraint->fk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->fk_attrs); + appendStringInfoString(str, ") "); + } + + if (constraint->pktable != NULL) + { + appendStringInfoString(str, "REFERENCES "); + deparseRangeVar(str, constraint->pktable, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + if (list_length(constraint->pk_attrs) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, constraint->pk_attrs); + appendStringInfoString(str, ") "); + } + } + + switch (constraint->fk_matchtype) + { + case FKCONSTR_MATCH_SIMPLE: + // Default + break; + case FKCONSTR_MATCH_FULL: + appendStringInfoString(str, "MATCH FULL "); + break; + case FKCONSTR_MATCH_PARTIAL: + // Not implemented in Postgres + Assert(false); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_upd_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON UPDATE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON UPDATE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + appendStringInfoString(str, "ON UPDATE SET NULL "); + break; + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON UPDATE SET DEFAULT "); + break; + default: + // Not specified + break; + } + + switch (constraint->fk_del_action) + { + case FKCONSTR_ACTION_NOACTION: + // Default + break; + case FKCONSTR_ACTION_RESTRICT: + appendStringInfoString(str, "ON DELETE RESTRICT "); + break; + case FKCONSTR_ACTION_CASCADE: + appendStringInfoString(str, "ON DELETE CASCADE "); + break; + case FKCONSTR_ACTION_SETNULL: + case FKCONSTR_ACTION_SETDEFAULT: + appendStringInfoString(str, "ON DELETE SET "); + + switch (constraint->fk_del_action) { + case FKCONSTR_ACTION_SETDEFAULT: appendStringInfoString(str, "DEFAULT "); break; + case FKCONSTR_ACTION_SETNULL: appendStringInfoString(str, "NULL "); break; + } + + if (constraint->fk_del_set_cols) { + appendStringInfoString(str, "("); + ListCell *lc; + foreach (lc, constraint->fk_del_set_cols) { + appendStringInfoString(str, strVal(lfirst(lc))); + if (lfirst(lc) != llast(constraint->fk_del_set_cols)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ")"); + } + break; + default: + // Not specified + break; + } + + if (list_length(constraint->including) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + deparseColumnList(str, constraint->including); + appendStringInfoString(str, ") "); + } + + switch (constraint->contype) + { + case CONSTR_PRIMARY: + case CONSTR_UNIQUE: + case CONSTR_EXCLUSION: + deparseOptWith(str, constraint->options); + break; + default: + break; + } + + if (constraint->indexname != NULL) + appendStringInfo(str, "USING INDEX %s ", quote_identifier(constraint->indexname)); + + if (constraint->indexspace != NULL) + appendStringInfo(str, "USING INDEX TABLESPACE %s ", quote_identifier(constraint->indexspace)); + + if (constraint->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (constraint->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (constraint->is_no_inherit) + appendStringInfoString(str, "NO INHERIT "); + + if (constraint->skip_validation) + appendStringInfoString(str, "NOT VALID "); + + removeTrailingSpace(str); +} + +static void deparseReturnStmt(StringInfo str, ReturnStmt *return_stmt) +{ + appendStringInfoString(str, "RETURN "); + deparseExpr(str, return_stmt->returnval); +} + +static void deparseCreateFunctionStmt(StringInfo str, CreateFunctionStmt *create_function_stmt) +{ + ListCell *lc; + bool tableFunc = false; + + appendStringInfoString(str, "CREATE "); + if (create_function_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + if (create_function_stmt->is_procedure) + appendStringInfoString(str, "PROCEDURE "); + else + appendStringInfoString(str, "FUNCTION "); + + deparseFuncName(str, create_function_stmt->funcname); + + appendStringInfoChar(str, '('); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode != FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(create_function_stmt->parameters, lc) && castNode(FunctionParameter, lfirst(lnext(create_function_stmt->parameters, lc)))->mode != FUNC_PARAM_TABLE) + appendStringInfoString(str, ", "); + } + else + { + tableFunc = true; + } + } + appendStringInfoString(str, ") "); + + if (tableFunc) + { + appendStringInfoString(str, "RETURNS TABLE ("); + foreach(lc, create_function_stmt->parameters) + { + FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); + if (function_parameter->mode == FUNC_PARAM_TABLE) + { + deparseFunctionParameter(str, function_parameter); + if (lnext(create_function_stmt->parameters, lc)) + appendStringInfoString(str, ", "); + } + } + appendStringInfoString(str, ") "); + } + else if (create_function_stmt->returnType != NULL) + { + appendStringInfoString(str, "RETURNS "); + deparseTypeName(str, create_function_stmt->returnType); + appendStringInfoChar(str, ' '); + } + + foreach(lc, create_function_stmt->options) + { + deparseCreateFuncOptItem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + + if (create_function_stmt->sql_body) + { + /* RETURN or BEGIN ... END + */ + if (IsA(create_function_stmt->sql_body, ReturnStmt)) + deparseReturnStmt(str, castNode(ReturnStmt, create_function_stmt->sql_body)); + else + { + appendStringInfoString(str, "BEGIN ATOMIC "); + if (linitial(create_function_stmt->sql_body) != NULL) + { + List *body_stmt_list = castNode(List, linitial(create_function_stmt->sql_body)); + foreach(lc, body_stmt_list) + { + if (IsA(lfirst(lc), ReturnStmt)) + { + deparseReturnStmt(str, lfirst_node(ReturnStmt, lc)); + appendStringInfoString(str, "; "); + } + else + { + deparseStmt(str, lfirst(lc)); + appendStringInfoString(str, "; "); + } + } + } + + appendStringInfoString(str, "END "); + } + } + + removeTrailingSpace(str); +} + +static void deparseFunctionParameter(StringInfo str, FunctionParameter *function_parameter) +{ + switch (function_parameter->mode) + { + case FUNC_PARAM_IN: /* input only */ + appendStringInfoString(str, "IN "); + break; + case FUNC_PARAM_OUT: /* output only */ + appendStringInfoString(str, "OUT "); + break; + case FUNC_PARAM_INOUT: /* both */ + appendStringInfoString(str, "INOUT "); + break; + case FUNC_PARAM_VARIADIC: /* variadic (always input) */ + appendStringInfoString(str, "VARIADIC "); + break; + case FUNC_PARAM_TABLE: /* table function output column */ + // No special annotation, the caller is expected to correctly put + // this into the RETURNS part of the CREATE FUNCTION statement + break; + case FUNC_PARAM_DEFAULT: + // Default + break; + default: + Assert(false); + break; + } + + if (function_parameter->name != NULL) + { + appendStringInfoString(str, function_parameter->name); + appendStringInfoChar(str, ' '); + } + + deparseTypeName(str, function_parameter->argType); + appendStringInfoChar(str, ' '); + + if (function_parameter->defexpr != NULL) + { + appendStringInfoString(str, "= "); + deparseExpr(str, function_parameter->defexpr); + } + + removeTrailingSpace(str); +} + +static void deparseCheckPointStmt(StringInfo str, CheckPointStmt *check_point_stmt) +{ + appendStringInfoString(str, "CHECKPOINT"); +} + +static void deparseCreateSchemaStmt(StringInfo str, CreateSchemaStmt *create_schema_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE SCHEMA "); + + if (create_schema_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (create_schema_stmt->schemaname) + { + deparseColId(str, create_schema_stmt->schemaname); + appendStringInfoChar(str, ' '); + } + + if (create_schema_stmt->authrole != NULL) + { + appendStringInfoString(str, "AUTHORIZATION "); + deparseRoleSpec(str, create_schema_stmt->authrole); + appendStringInfoChar(str, ' '); + } + + if (create_schema_stmt->schemaElts) + { + foreach(lc, create_schema_stmt->schemaElts) + { + deparseSchemaStmt(str, lfirst(lc)); + if (lnext(create_schema_stmt->schemaElts, lc)) + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleSetStmt(StringInfo str, AlterRoleSetStmt *alter_role_set_stmt) +{ + appendStringInfoString(str, "ALTER ROLE "); + + if (alter_role_set_stmt->role == NULL) + appendStringInfoString(str, "ALL"); + else + deparseRoleSpec(str, alter_role_set_stmt->role); + + appendStringInfoChar(str, ' '); + + if (alter_role_set_stmt->database != NULL) + { + appendStringInfoString(str, "IN DATABASE "); + appendStringInfoString(str, quote_identifier(alter_role_set_stmt->database)); + appendStringInfoChar(str, ' '); + } + + deparseVariableSetStmt(str, alter_role_set_stmt->setstmt); +} + +static void deparseCreateConversionStmt(StringInfo str, CreateConversionStmt *create_conversion_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_conversion_stmt->def) + appendStringInfoString(str, "DEFAULT "); + + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, create_conversion_stmt->conversion_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "FOR "); + deparseStringLiteral(str, create_conversion_stmt->for_encoding_name); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, create_conversion_stmt->to_encoding_name); + + appendStringInfoString(str, "FROM "); + deparseAnyName(str, create_conversion_stmt->func_name); +} + +static void deparseRoleSpec(StringInfo str, RoleSpec *role_spec) +{ + switch (role_spec->roletype) + { + case ROLESPEC_CSTRING: + Assert(role_spec->rolename != NULL); + appendStringInfoString(str, quote_identifier(role_spec->rolename)); + break; + case ROLESPEC_CURRENT_ROLE: + appendStringInfoString(str, "CURRENT_ROLE"); + break; + case ROLESPEC_CURRENT_USER: + appendStringInfoString(str, "CURRENT_USER"); + break; + case ROLESPEC_SESSION_USER: + appendStringInfoString(str, "SESSION_USER"); + break; + case ROLESPEC_PUBLIC: + appendStringInfoString(str, "public"); + break; + } +} + +// "part_elem" in gram.y +static void deparsePartitionElem(StringInfo str, PartitionElem *partition_elem) +{ + ListCell *lc; + + if (partition_elem->name != NULL) + { + deparseColId(str, partition_elem->name); + appendStringInfoChar(str, ' '); + } + else if (partition_elem->expr != NULL) + { + appendStringInfoChar(str, '('); + deparseExpr(str, partition_elem->expr); + appendStringInfoString(str, ") "); + } + + deparseOptCollate(str, partition_elem->collation); + deparseAnyName(str, partition_elem->opclass); + + removeTrailingSpace(str); +} + +static void deparsePartitionSpec(StringInfo str, PartitionSpec *partition_spec) +{ + ListCell *lc; + + appendStringInfoString(str, "PARTITION BY "); + appendStringInfoString(str, partition_spec->strategy); + + appendStringInfoChar(str, '('); + foreach(lc, partition_spec->partParams) + { + deparsePartitionElem(str, castNode(PartitionElem, lfirst(lc))); + if (lnext(partition_spec->partParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparsePartitionBoundSpec(StringInfo str, PartitionBoundSpec *partition_bound_spec) +{ + ListCell *lc; + + if (partition_bound_spec->is_default) + { + appendStringInfoString(str, "DEFAULT"); + return; + } + + appendStringInfoString(str, "FOR VALUES "); + + switch (partition_bound_spec->strategy) + { + case PARTITION_STRATEGY_HASH: + appendStringInfo(str, "WITH (MODULUS %d, REMAINDER %d)", partition_bound_spec->modulus, partition_bound_spec->remainder); + break; + case PARTITION_STRATEGY_LIST: + appendStringInfoString(str, "IN ("); + deparseExprList(str, partition_bound_spec->listdatums); + appendStringInfoChar(str, ')'); + break; + case PARTITION_STRATEGY_RANGE: + appendStringInfoString(str, "FROM ("); + deparseExprList(str, partition_bound_spec->lowerdatums); + appendStringInfoString(str, ") TO ("); + deparseExprList(str, partition_bound_spec->upperdatums); + appendStringInfoChar(str, ')'); + break; + default: + Assert(false); + break; + } +} + +static void deparsePartitionCmd(StringInfo str, PartitionCmd *partition_cmd) +{ + deparseRangeVar(str, partition_cmd->name, DEPARSE_NODE_CONTEXT_NONE); + + if (partition_cmd->bound != NULL) + { + appendStringInfoChar(str, ' '); + deparsePartitionBoundSpec(str, partition_cmd->bound); + } + if (partition_cmd->concurrent) + appendStringInfoString(str, " CONCURRENTLY "); +} + +// "TableElement" in gram.y +static void deparseTableElement(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_ColumnDef: + deparseColumnDef(str, castNode(ColumnDef, node)); + break; + case T_TableLikeClause: + deparseTableLikeClause(str, castNode(TableLikeClause, node)); + break; + case T_Constraint: + deparseConstraint(str, castNode(Constraint, node)); + break; + default: + Assert(false); + } +} + +static void deparseCreateStmt(StringInfo str, CreateStmt *create_stmt, bool is_foreign_table) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (is_foreign_table) + appendStringInfoString(str, "FOREIGN "); + + deparseOptTemp(str, create_stmt->relation->relpersistence); + + appendStringInfoString(str, "TABLE "); + + if (create_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_stmt->ofTypename != NULL) + { + appendStringInfoString(str, "OF "); + deparseTypeName(str, create_stmt->ofTypename); + appendStringInfoChar(str, ' '); + } + + if (create_stmt->partbound != NULL) + { + Assert(list_length(create_stmt->inhRelations) == 1); + appendStringInfoString(str, "PARTITION OF "); + deparseRangeVar(str, castNode(RangeVar, linitial(create_stmt->inhRelations)), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (list_length(create_stmt->tableElts) > 0) + { + // In raw parse output tableElts contains both columns and constraints + // (and the constraints field is NIL) + appendStringInfoChar(str, '('); + foreach(lc, create_stmt->tableElts) + { + deparseTableElement(str, lfirst(lc)); + if (lnext(create_stmt->tableElts, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + else if (create_stmt->partbound == NULL && create_stmt->ofTypename == NULL) + { + appendStringInfoString(str, "() "); + } + + if (create_stmt->partbound != NULL) + { + deparsePartitionBoundSpec(str, create_stmt->partbound); + appendStringInfoChar(str, ' '); + } + else + { + deparseOptInherit(str, create_stmt->inhRelations); + } + + if (create_stmt->partspec != NULL) + { + deparsePartitionSpec(str, create_stmt->partspec); + appendStringInfoChar(str, ' '); + } + + if (create_stmt->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(create_stmt->accessMethod)); + } + + deparseOptWith(str, create_stmt->options); + + switch (create_stmt->oncommit) + { + case ONCOMMIT_NOOP: + // No ON COMMIT clause + break; + case ONCOMMIT_PRESERVE_ROWS: + appendStringInfoString(str, "ON COMMIT PRESERVE ROWS "); + break; + case ONCOMMIT_DELETE_ROWS: + appendStringInfoString(str, "ON COMMIT DELETE ROWS "); + break; + case ONCOMMIT_DROP: + appendStringInfoString(str, "ON COMMIT DROP "); + break; + } + + if (create_stmt->tablespacename != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(create_stmt->tablespacename)); + } + + removeTrailingSpace(str); +} + +static void deparseCreateFdwStmt(StringInfo str, CreateFdwStmt *create_fdw_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, create_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + deparseCreateGenericOptions(str, create_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFdwStmt(StringInfo str, AlterFdwStmt *alter_fdw_stmt) +{ + appendStringInfoString(str, "ALTER FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(alter_fdw_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + if (list_length(alter_fdw_stmt->func_options) > 0) + { + deparseFdwOptions(str, alter_fdw_stmt->func_options); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_fdw_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_fdw_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateForeignServerStmt(StringInfo str, CreateForeignServerStmt *create_foreign_server_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SERVER "); + if (create_foreign_server_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (create_foreign_server_stmt->servertype != NULL) + { + appendStringInfoString(str, "TYPE "); + deparseStringLiteral(str, create_foreign_server_stmt->servertype); + appendStringInfoChar(str, ' '); + } + + if (create_foreign_server_stmt->version != NULL) + { + appendStringInfoString(str, "VERSION "); + deparseStringLiteral(str, create_foreign_server_stmt->version); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + appendStringInfoString(str, quote_identifier(create_foreign_server_stmt->fdwname)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterForeignServerStmt(StringInfo str, AlterForeignServerStmt *alter_foreign_server_stmt) +{ + appendStringInfoString(str, "ALTER SERVER "); + + appendStringInfoString(str, quote_identifier(alter_foreign_server_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (alter_foreign_server_stmt->has_version) + { + appendStringInfoString(str, "VERSION "); + if (alter_foreign_server_stmt->version != NULL) + deparseStringLiteral(str, alter_foreign_server_stmt->version); + else + appendStringInfoString(str, "NULL"); + appendStringInfoChar(str, ' '); + } + + if (list_length(alter_foreign_server_stmt->options) > 0) + deparseAlterGenericOptions(str, alter_foreign_server_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateUserMappingStmt(StringInfo str, CreateUserMappingStmt *create_user_mapping_stmt) +{ + appendStringInfoString(str, "CREATE USER MAPPING "); + if (create_user_mapping_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, create_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(create_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, create_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreatedbStmt(StringInfo str, CreatedbStmt *createdb_stmt) +{ + appendStringInfoString(str, "CREATE DATABASE "); + deparseColId(str, createdb_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, createdb_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterUserMappingStmt(StringInfo str, AlterUserMappingStmt *alter_user_mapping_stmt) +{ + appendStringInfoString(str, "ALTER USER MAPPING FOR "); + deparseRoleSpec(str, alter_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(alter_user_mapping_stmt->servername)); + appendStringInfoChar(str, ' '); + + deparseAlterGenericOptions(str, alter_user_mapping_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseDropUserMappingStmt(StringInfo str, DropUserMappingStmt *drop_user_mapping_stmt) +{ + appendStringInfoString(str, "DROP USER MAPPING "); + + if (drop_user_mapping_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, "FOR "); + deparseRoleSpec(str, drop_user_mapping_stmt->user); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "SERVER "); + appendStringInfoString(str, quote_identifier(drop_user_mapping_stmt->servername)); +} + +static void deparseSecLabelStmt(StringInfo str, SecLabelStmt *sec_label_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "SECURITY LABEL "); + + if (sec_label_stmt->provider != NULL) + { + appendStringInfoString(str, "FOR "); + appendStringInfoString(str, quote_identifier(sec_label_stmt->provider)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + + switch (sec_label_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseAnyName(str, castNode(List, sec_label_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(strVal(sec_label_stmt->object))); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseTypeName(str, castNode(TypeName, sec_label_stmt->object)); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseValue(str, (union ValUnion *) sec_label_stmt->object, DEPARSE_NODE_CONTEXT_CONSTANT); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, sec_label_stmt->object)); + break; + default: + // Not supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (sec_label_stmt->label != NULL) + deparseStringLiteral(str, sec_label_stmt->label); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseCreateForeignTableStmt(StringInfo str, CreateForeignTableStmt *create_foreign_table_stmt) +{ + ListCell *lc; + + deparseCreateStmt(str, &create_foreign_table_stmt->base, true); + + appendStringInfoString(str, " SERVER "); + appendStringInfoString(str, quote_identifier(create_foreign_table_stmt->servername)); + appendStringInfoChar(str, ' '); + + if (list_length(create_foreign_table_stmt->options) > 0) + deparseAlterGenericOptions(str, create_foreign_table_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseImportForeignSchemaStmt(StringInfo str, ImportForeignSchemaStmt *import_foreign_schema_stmt) +{ + appendStringInfoString(str, "IMPORT FOREIGN SCHEMA "); + + appendStringInfoString(str, import_foreign_schema_stmt->remote_schema); + appendStringInfoChar(str, ' '); + + switch (import_foreign_schema_stmt->list_type) + { + case FDW_IMPORT_SCHEMA_ALL: + // Default + break; + case FDW_IMPORT_SCHEMA_LIMIT_TO: + appendStringInfoString(str, "LIMIT TO ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + case FDW_IMPORT_SCHEMA_EXCEPT: + appendStringInfoString(str, "EXCEPT ("); + deparseRelationExprList(str, import_foreign_schema_stmt->table_list); + appendStringInfoString(str, ") "); + break; + } + + appendStringInfoString(str, "FROM SERVER "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->server_name)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "INTO "); + appendStringInfoString(str, quote_identifier(import_foreign_schema_stmt->local_schema)); + appendStringInfoChar(str, ' '); + + deparseCreateGenericOptions(str, import_foreign_schema_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTableAsStmt(StringInfo str, CreateTableAsStmt *create_table_as_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_table_as_stmt->into->rel->relpersistence); + + switch (create_table_as_stmt->objtype) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + // Not supported here + Assert(false); + break; + } + + if (create_table_as_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseIntoClause(str, create_table_as_stmt->into); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "AS "); + if (IsA(create_table_as_stmt->query, ExecuteStmt)) + deparseExecuteStmt(str, castNode(ExecuteStmt, create_table_as_stmt->query)); + else + deparseSelectStmt(str, castNode(SelectStmt, create_table_as_stmt->query)); + appendStringInfoChar(str, ' '); + + if (create_table_as_stmt->into->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseViewStmt(StringInfo str, ViewStmt *view_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (view_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + deparseOptTemp(str, view_stmt->view->relpersistence); + + appendStringInfoString(str, "VIEW "); + deparseRangeVar(str, view_stmt->view, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(view_stmt->aliases) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, view_stmt->aliases); + appendStringInfoString(str, ") "); + } + + deparseOptWith(str, view_stmt->options); + + appendStringInfoString(str, "AS "); + deparseSelectStmt(str, castNode(SelectStmt, view_stmt->query)); + appendStringInfoChar(str, ' '); + + switch (view_stmt->withCheckOption) + { + case NO_CHECK_OPTION: + // Default + break; + case LOCAL_CHECK_OPTION: + appendStringInfoString(str, "WITH LOCAL CHECK OPTION "); + break; + case CASCADED_CHECK_OPTION: + appendStringInfoString(str, "WITH CHECK OPTION "); + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropStmt(StringInfo str, DropStmt *drop_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "DROP "); + + switch (drop_stmt->removeType) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + default: + // Other object types are not supported here in the parser + Assert(false); + } + + if (drop_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (drop_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (drop_stmt->removeType) + { + // drop_type_any_name + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + deparseAnyNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name + case OBJECT_ACCESS_METHOD: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_PUBLICATION: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + deparseNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + // drop_type_name_on_any_name + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseColId(str, strVal(llast(l))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + appendStringInfoChar(str, ' '); + break; + case OBJECT_CAST: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TRANSFORM: + Assert(list_length(drop_stmt->objects) == 1); + l = linitial(drop_stmt->objects); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + appendStringInfoChar(str, ' '); + break; + case OBJECT_LANGUAGE: + deparseNameList(str, drop_stmt->objects); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + foreach(lc, drop_stmt->objects) + { + deparseTypeName(str, castNode(TypeName, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_AGGREGATE: + foreach(lc, drop_stmt->objects) + { + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + foreach(lc, drop_stmt->objects) + { + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPERATOR: + foreach(lc, drop_stmt->objects) + { + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, lfirst(lc))); + if (lnext(drop_stmt->objects, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + } + + deparseOptDropBehavior(str, drop_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseGroupingSet(StringInfo str, GroupingSet *grouping_set) +{ + switch(grouping_set->kind) + { + case GROUPING_SET_EMPTY: + appendStringInfoString(str, "()"); + break; + case GROUPING_SET_SIMPLE: + // Not present in raw parse trees + Assert(false); + break; + case GROUPING_SET_ROLLUP: + appendStringInfoString(str, "ROLLUP ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_CUBE: + appendStringInfoString(str, "CUBE ("); + deparseExprList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + case GROUPING_SET_SETS: + appendStringInfoString(str, "GROUPING SETS ("); + deparseGroupByList(str, grouping_set->content); + appendStringInfoChar(str, ')'); + break; + } +} + +static void deparseDropTableSpaceStmt(StringInfo str, DropTableSpaceStmt *drop_table_space_stmt) +{ + appendStringInfoString(str, "DROP TABLESPACE "); + + if (drop_table_space_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_table_space_stmt->tablespacename); +} + +static void deparseAlterObjectDependsStmt(StringInfo str, AlterObjectDependsStmt *alter_object_depends_stmt) +{ + appendStringInfoString(str, "ALTER "); + + switch (alter_object_depends_stmt->objectType) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + deparseColId(str, strVal(linitial(castNode(List, alter_object_depends_stmt->object)))); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + deparseRangeVar(str, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + default: + // No other object types supported here + Assert(false); + } + appendStringInfoChar(str, ' '); + + if (alter_object_depends_stmt->remove) + appendStringInfoString(str, "NO "); + + appendStringInfo(str, "DEPENDS ON EXTENSION %s", alter_object_depends_stmt->extname->sval); +} + +static void deparseAlterObjectSchemaStmt(StringInfo str, AlterObjectSchemaStmt *alter_object_schema_stmt) +{ + List *l = NULL; + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_object_schema_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + appendStringInfoString(str, quote_identifier(strVal(alter_object_schema_stmt->object))); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_object_schema_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + if (alter_object_schema_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + deparseRangeVar(str, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_object_schema_stmt->object)); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, " SET SCHEMA "); + appendStringInfoString(str, quote_identifier(alter_object_schema_stmt->newschema)); +} + +static void deparseAlterTableCmd(StringInfo str, AlterTableCmd *alter_table_cmd, DeparseNodeContext context) +{ + ListCell *lc = NULL; + const char *options = NULL; + bool trailing_missing_ok = false; + + switch (alter_table_cmd->subtype) + { + case AT_AddColumn: /* add column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ADD ATTRIBUTE "); + else + appendStringInfoString(str, "ADD COLUMN "); + break; + case AT_AddColumnRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddColumnToView: /* implicitly via CREATE OR REPLACE VIEW */ + // Not present in raw parser output + Assert(false); + break; + case AT_ColumnDefault: /* alter column default */ + appendStringInfoString(str, "ALTER COLUMN "); + if (alter_table_cmd->def != NULL) + options = "SET DEFAULT"; + else + options = "DROP DEFAULT"; + break; + case AT_CookedColumnDefault: /* add a pre-cooked column default */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropNotNull: /* alter column drop not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP NOT NULL"; + break; + case AT_SetNotNull: /* alter column set not null */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET NOT NULL"; + break; + case AT_DropExpression: /* alter column drop expression */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP EXPRESSION"; + trailing_missing_ok = true; + break; + case AT_CheckNotNull: /* check column is already marked not null */ + // Not present in raw parser output + Assert(false); + break; + case AT_SetStatistics: /* alter column set statistics */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STATISTICS"; + break; + case AT_SetOptions: /* alter column set ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET"; + break; + case AT_ResetOptions: /* alter column reset ( options ) */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "RESET"; + break; + case AT_SetStorage: /* alter column set storage */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET STORAGE"; + break; + case AT_SetCompression: /* alter column set compression */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "SET COMPRESSION"; + break; + case AT_DropColumn: /* drop column */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "DROP ATTRIBUTE "); + else + appendStringInfoString(str, "DROP "); + break; + case AT_DropColumnRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddIndex: /* add index */ + appendStringInfoString(str, "ADD INDEX "); + break; + case AT_ReAddIndex: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddConstraint: /* add constraint */ + appendStringInfoString(str, "ADD "); + break; + case AT_AddConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddDomainConstraint: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterConstraint: /* alter constraint */ + appendStringInfoString(str, "ALTER "); // CONSTRAINT keyword gets added by the Constraint itself (when deparsing def) + break; + case AT_ValidateConstraint: /* validate constraint */ + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + break; + case AT_ValidateConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AddIndexConstraint: /* add constraint using existing index */ + // Not present in raw parser output + Assert(false); + break; + case AT_DropConstraint: /* drop constraint */ + appendStringInfoString(str, "DROP CONSTRAINT "); + break; + case AT_DropConstraintRecurse: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_ReAddComment: /* internal to commands/tablecmds.c */ + case AT_ReAddStatistics: /* internal to commands/tablecmds.c */ + Assert(false); + break; + case AT_AlterColumnType: /* alter column type */ + if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) + appendStringInfoString(str, "ALTER ATTRIBUTE "); + else + appendStringInfoString(str, "ALTER COLUMN "); + options = "TYPE"; + break; + case AT_AlterColumnGenericOptions: /* alter column OPTIONS (...) */ + appendStringInfoString(str, "ALTER COLUMN "); + // Handled via special case in def handling + break; + case AT_ChangeOwner: /* change owner */ + appendStringInfoString(str, "OWNER TO "); + deparseRoleSpec(str, alter_table_cmd->newowner); + break; + case AT_ClusterOn: /* CLUSTER ON */ + appendStringInfoString(str, "CLUSTER ON "); + break; + case AT_DropCluster: /* SET WITHOUT CLUSTER */ + appendStringInfoString(str, "SET WITHOUT CLUSTER "); + break; + case AT_SetLogged: /* SET LOGGED */ + appendStringInfoString(str, "SET LOGGED "); + break; + case AT_SetUnLogged: /* SET UNLOGGED */ + appendStringInfoString(str, "SET UNLOGGED "); + break; + case AT_DropOids: /* SET WITHOUT OIDS */ + appendStringInfoString(str, "SET WITHOUT OIDS "); + break; + case AT_SetTableSpace: /* SET TABLESPACE */ + appendStringInfoString(str, "SET TABLESPACE "); + break; + case AT_SetRelOptions: /* SET (...) -- AM specific parameters */ + appendStringInfoString(str, "SET "); + break; + case AT_SetAccessMethod: + appendStringInfo(str, "SET ACCESS METHOD "); + break; + case AT_ResetRelOptions: /* RESET (...) -- AM specific parameters */ + appendStringInfoString(str, "RESET "); + break; + case AT_ReplaceRelOptions: /* replace reloption list in its entirety */ + // Not present in raw parser output + Assert(false); + break; + case AT_EnableTrig: /* ENABLE TRIGGER name */ + appendStringInfoString(str, "ENABLE TRIGGER "); + break; + case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */ + appendStringInfoString(str, "ENABLE ALWAYS TRIGGER "); + break; + case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */ + appendStringInfoString(str, "ENABLE REPLICA TRIGGER "); + break; + case AT_DisableTrig: /* DISABLE TRIGGER name */ + appendStringInfoString(str, "DISABLE TRIGGER "); + break; + case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */ + appendStringInfoString(str, "ENABLE TRIGGER "); + break; + case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */ + appendStringInfoString(str, "DISABLE TRIGGER ALL "); + break; + case AT_EnableTrigUser: /* ENABLE TRIGGER USER */ + appendStringInfoString(str, "ENABLE TRIGGER USER "); + break; + case AT_DisableTrigUser: /* DISABLE TRIGGER USER */ + appendStringInfoString(str, "DISABLE TRIGGER USER "); + break; + case AT_EnableRule: /* ENABLE RULE name */ + appendStringInfoString(str, "ENABLE RULE "); + break; + case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */ + appendStringInfoString(str, "ENABLE ALWAYS RULE "); + break; + case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */ + appendStringInfoString(str, "ENABLE REPLICA RULE "); + break; + case AT_DisableRule: /* DISABLE RULE name */ + appendStringInfoString(str, "DISABLE RULE "); + break; + case AT_AddInherit: /* INHERIT parent */ + appendStringInfoString(str, "INHERIT "); + break; + case AT_DropInherit: /* NO INHERIT parent */ + appendStringInfoString(str, "NO INHERIT "); + break; + case AT_AddOf: /* OF */ + appendStringInfoString(str, "OF "); + break; + case AT_DropOf: /* NOT OF */ + appendStringInfoString(str, "NOT OF "); + break; + case AT_ReplicaIdentity: /* REPLICA IDENTITY */ + appendStringInfoString(str, "REPLICA IDENTITY "); + break; + case AT_EnableRowSecurity: /* ENABLE ROW SECURITY */ + appendStringInfoString(str, "ENABLE ROW LEVEL SECURITY "); + break; + case AT_DisableRowSecurity: /* DISABLE ROW SECURITY */ + appendStringInfoString(str, "DISABLE ROW LEVEL SECURITY "); + break; + case AT_ForceRowSecurity: /* FORCE ROW SECURITY */ + appendStringInfoString(str, "FORCE ROW LEVEL SECURITY "); + break; + case AT_NoForceRowSecurity: /* NO FORCE ROW SECURITY */ + appendStringInfoString(str, "NO FORCE ROW LEVEL SECURITY "); + break; + case AT_GenericOptions: /* OPTIONS (...) */ + // Handled in def field handling + break; + case AT_AttachPartition: /* ATTACH PARTITION */ + appendStringInfoString(str, "ATTACH PARTITION "); + break; + case AT_DetachPartition: /* DETACH PARTITION */ + appendStringInfoString(str, "DETACH PARTITION "); + break; + case AT_DetachPartitionFinalize: /* DETACH PARTITION FINALIZE */ + appendStringInfoString(str, "DETACH PARTITION "); + break; + case AT_AddIdentity: /* ADD IDENTITY */ + appendStringInfoString(str, "ALTER "); + options = "ADD"; + // Other details are output via the constraint node (in def field) + break; + case AT_SetIdentity: /* SET identity column options */ + appendStringInfoString(str, "ALTER "); + break; + case AT_DropIdentity: /* DROP IDENTITY */ + appendStringInfoString(str, "ALTER COLUMN "); + options = "DROP IDENTITY"; + trailing_missing_ok = true; + break; + } + + if (alter_table_cmd->missing_ok && !trailing_missing_ok) + { + if (alter_table_cmd->subtype == AT_AddColumn) + appendStringInfoString(str, "IF NOT EXISTS "); + else + appendStringInfoString(str, "IF EXISTS "); + } + + if (alter_table_cmd->name != NULL) + { + appendStringInfoString(str, quote_identifier(alter_table_cmd->name)); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->num > 0) + appendStringInfo(str, "%d ", alter_table_cmd->num); + + if (options != NULL) + { + appendStringInfoString(str, options); + appendStringInfoChar(str, ' '); + } + + if (alter_table_cmd->missing_ok && trailing_missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (alter_table_cmd->subtype) + { + case AT_AttachPartition: + case AT_DetachPartition: + deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_DetachPartitionFinalize: + deparsePartitionCmd(str, castNode(PartitionCmd, alter_table_cmd->def)); + appendStringInfoString(str, "FINALIZE "); + break; + case AT_AddColumn: + case AT_AlterColumnType: + deparseColumnDef(str, castNode(ColumnDef, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ColumnDefault: + if (alter_table_cmd->def != NULL) + { + deparseExpr(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + } + break; + case AT_SetStatistics: + deparseSignedIconst(str, alter_table_cmd->def); + appendStringInfoChar(str, ' '); + break; + case AT_SetOptions: + case AT_ResetOptions: + case AT_SetRelOptions: + case AT_ResetRelOptions: + deparseRelOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetStorage: + deparseColId(str, strVal(alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetCompression: + if (strcmp(strVal(alter_table_cmd->def), "default") == 0) + appendStringInfoString(str, "DEFAULT"); + else + deparseColId(str, strVal(alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddIdentity: + case AT_AddConstraint: + case AT_AlterConstraint: + deparseConstraint(str, castNode(Constraint, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_SetIdentity: + deparseAlterIdentityColumnOptionList(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AlterColumnGenericOptions: + case AT_GenericOptions: + deparseAlterGenericOptions(str, castNode(List, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_AddInherit: + case AT_DropInherit: + deparseRangeVar(str, castNode(RangeVar, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + break; + case AT_AddOf: + deparseTypeName(str, castNode(TypeName, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + case AT_ReplicaIdentity: + deparseReplicaIdentityStmt(str, castNode(ReplicaIdentityStmt, alter_table_cmd->def)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(alter_table_cmd->def == NULL); + break; + } + + deparseOptDropBehavior(str, alter_table_cmd->behavior); + + removeTrailingSpace(str); +} + +static DeparseNodeContext deparseAlterTableObjType(StringInfo str, ObjectType type) +{ + switch (type) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + return DEPARSE_NODE_CONTEXT_ALTER_TYPE; + break; + default: + Assert(false); + break; + } + + return DEPARSE_NODE_CONTEXT_NONE; +} + +static void deparseAlterTableMoveAllStmt(StringInfo str, AlterTableMoveAllStmt *move_all_stmt) +{ + appendStringInfoString(str, "ALTER "); + deparseAlterTableObjType(str, move_all_stmt->objtype); + + appendStringInfoString(str, "ALL IN TABLESPACE "); + appendStringInfoString(str, move_all_stmt->orig_tablespacename); + appendStringInfoChar(str, ' '); + + if (move_all_stmt->roles) + { + appendStringInfoString(str, "OWNED BY "); + deparseRoleList(str, move_all_stmt->roles); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "SET TABLESPACE "); + appendStringInfoString(str, move_all_stmt->new_tablespacename); + appendStringInfoChar(str, ' '); + + if (move_all_stmt->nowait) + { + appendStringInfoString(str, "NOWAIT"); + } +} + +static void deparseAlterTableStmt(StringInfo str, AlterTableStmt *alter_table_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + DeparseNodeContext context = deparseAlterTableObjType(str, alter_table_stmt->objtype); + + if (alter_table_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_table_stmt->relation, context); + appendStringInfoChar(str, ' '); + + foreach(lc, alter_table_stmt->cmds) + { + deparseAlterTableCmd(str, castNode(AlterTableCmd, lfirst(lc)), context); + if (lnext(alter_table_stmt->cmds, lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterTableSpaceOptionsStmt(StringInfo str, AlterTableSpaceOptionsStmt *alter_table_space_options_stmt) +{ + appendStringInfoString(str, "ALTER TABLESPACE "); + deparseColId(str, alter_table_space_options_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (alter_table_space_options_stmt->isReset) + appendStringInfoString(str, "RESET "); + else + appendStringInfoString(str, "SET "); + + deparseRelOptions(str, alter_table_space_options_stmt->options); +} + +static void deparseAlterDomainStmt(StringInfo str, AlterDomainStmt *alter_domain_stmt) +{ + appendStringInfoString(str, "ALTER DOMAIN "); + deparseAnyName(str, alter_domain_stmt->typeName); + appendStringInfoChar(str, ' '); + + switch (alter_domain_stmt->subtype) + { + case 'T': + if (alter_domain_stmt->def != NULL) + { + appendStringInfoString(str, "SET DEFAULT "); + deparseExpr(str, alter_domain_stmt->def); + } + else + { + appendStringInfoString(str, "DROP DEFAULT"); + } + break; + case 'N': + appendStringInfoString(str, "DROP NOT NULL"); + break; + case 'O': + appendStringInfoString(str, "SET NOT NULL"); + break; + case 'C': + appendStringInfoString(str, "ADD "); + deparseConstraint(str, castNode(Constraint, alter_domain_stmt->def)); + break; + case 'X': + appendStringInfoString(str, "DROP CONSTRAINT "); + if (alter_domain_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + if (alter_domain_stmt->behavior == DROP_CASCADE) + appendStringInfoString(str, " CASCADE"); + break; + case 'V': + appendStringInfoString(str, "VALIDATE CONSTRAINT "); + appendStringInfoString(str, quote_identifier(alter_domain_stmt->name)); + break; + default: + // No other subtypes supported by the parser + Assert(false); + } +} + +static void deparseRenameStmt(StringInfo str, RenameStmt *rename_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_DOMAIN: + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLE: + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_COLUMN: + switch (rename_stmt->relationType) + { + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + default: + Assert(false); + } + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TYPE: + case OBJECT_ATTRIBUTE: + appendStringInfoString(str, "TYPE "); + break; + default: + Assert(false); + break; + } + + if (rename_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + switch (rename_stmt->renameType) + { + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DOMCONSTRAINT: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, rename_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_SUBSCRIPTION: + deparseColId(str, strVal(rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_TABLE: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLUMN: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME COLUMN "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_TABCONSTRAINT: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME CONSTRAINT "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + case OBJECT_RULE: + case OBJECT_TRIGGER: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_FOREIGN_SERVER: + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, quote_identifier(strVal(rename_stmt->object))); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_DATABASE: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_DOMAIN: + case OBJECT_STATISTIC_EXT: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TYPE: + deparseAnyName(str, castNode(List, rename_stmt->object)); + appendStringInfoString(str, " RENAME "); + break; + case OBJECT_ATTRIBUTE: + deparseRangeVar(str, rename_stmt->relation, DEPARSE_NODE_CONTEXT_ALTER_TYPE); + appendStringInfoString(str, " RENAME ATTRIBUTE "); + appendStringInfoString(str, quote_identifier(rename_stmt->subname)); + appendStringInfoChar(str, ' '); + break; + default: + Assert(false); + break; + } + + appendStringInfoString(str, "TO "); + appendStringInfoString(str, quote_identifier(rename_stmt->newname)); + appendStringInfoChar(str, ' '); + + deparseOptDropBehavior(str, rename_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseTransactionStmt(StringInfo str, TransactionStmt *transaction_stmt) +{ + ListCell *lc; + switch (transaction_stmt->kind) + { + case TRANS_STMT_BEGIN: + appendStringInfoString(str, "BEGIN "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_START: + appendStringInfoString(str, "START TRANSACTION "); + deparseTransactionModeList(str, transaction_stmt->options); + break; + case TRANS_STMT_COMMIT: + appendStringInfoString(str, "COMMIT "); + if (transaction_stmt->chain) + appendStringInfoString(str, "AND CHAIN "); + break; + case TRANS_STMT_ROLLBACK: + appendStringInfoString(str, "ROLLBACK "); + if (transaction_stmt->chain) + appendStringInfoString(str, "AND CHAIN "); + break; + case TRANS_STMT_SAVEPOINT: + appendStringInfoString(str, "SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_RELEASE: + appendStringInfoString(str, "RELEASE "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_ROLLBACK_TO: + appendStringInfoString(str, "ROLLBACK "); + appendStringInfoString(str, "TO SAVEPOINT "); + appendStringInfoString(str, quote_identifier(transaction_stmt->savepoint_name)); + break; + case TRANS_STMT_PREPARE: + appendStringInfoString(str, "PREPARE TRANSACTION "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_COMMIT_PREPARED: + appendStringInfoString(str, "COMMIT PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + case TRANS_STMT_ROLLBACK_PREPARED: + appendStringInfoString(str, "ROLLBACK PREPARED "); + deparseStringLiteral(str, transaction_stmt->gid); + break; + } + + removeTrailingSpace(str); +} + +// Determine if we hit SET TIME ZONE INTERVAL, that has special syntax not +// supported for other SET statements +static bool isSetTimeZoneInterval(VariableSetStmt* stmt) +{ + if (!(strcmp(stmt->name, "timezone") == 0 && + list_length(stmt->args) == 1 && + IsA(linitial(stmt->args), TypeCast))) + return false; + + TypeName* typeName = castNode(TypeCast, linitial(stmt->args))->typeName; + + return (list_length(typeName->names) == 2 && + strcmp(strVal(linitial(typeName->names)), "pg_catalog") == 0 && + strcmp(strVal(llast(typeName->names)), "interval") == 0); +} + +static void deparseVariableSetStmt(StringInfo str, VariableSetStmt* variable_set_stmt) +{ + ListCell *lc; + + switch (variable_set_stmt->kind) + { + case VAR_SET_VALUE: /* SET var = value */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + if (isSetTimeZoneInterval(variable_set_stmt)) + { + appendStringInfoString(str, "TIME ZONE "); + deparseVarList(str, variable_set_stmt->args); + } + else + { + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO "); + deparseVarList(str, variable_set_stmt->args); + } + break; + case VAR_SET_DEFAULT: /* SET var TO DEFAULT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " TO DEFAULT"); + break; + case VAR_SET_CURRENT: /* SET var FROM CURRENT */ + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + deparseVarName(str, variable_set_stmt->name); + appendStringInfoString(str, " FROM CURRENT"); + break; + case VAR_SET_MULTI: /* special case for SET TRANSACTION ... */ + Assert(variable_set_stmt->name != NULL); + appendStringInfoString(str, "SET "); + if (variable_set_stmt->is_local) + appendStringInfoString(str, "LOCAL "); + if (strcmp(variable_set_stmt->name, "TRANSACTION") == 0) + { + appendStringInfoString(str, "TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "SESSION CHARACTERISTICS") == 0) + { + appendStringInfoString(str, "SESSION CHARACTERISTICS AS TRANSACTION "); + deparseTransactionModeList(str, variable_set_stmt->args); + } + else if (strcmp(variable_set_stmt->name, "TRANSACTION SNAPSHOT") == 0) + { + appendStringInfoString(str, "TRANSACTION SNAPSHOT "); + deparseStringLiteral(str, strVal(&castNode(A_Const, linitial(variable_set_stmt->args))->val)); + } + else + { + Assert(false); + } + break; + case VAR_RESET: /* RESET var */ + appendStringInfoString(str, "RESET "); + deparseVarName(str, variable_set_stmt->name); + break; + case VAR_RESET_ALL: /* RESET ALL */ + appendStringInfoString(str, "RESET ALL"); + break; + } +} + +static void deparseDropdbStmt(StringInfo str, DropdbStmt *dropdb_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "DROP DATABASE "); + if (dropdb_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, quote_identifier(dropdb_stmt->dbname)); + appendStringInfoChar(str, ' '); + + if (list_length(dropdb_stmt->options) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc, dropdb_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "force") == 0) + appendStringInfoString(str, "FORCE"); + else + Assert(false); // Currently there are other supported values + + if (lnext(dropdb_stmt->options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseVacuumStmt(StringInfo str, VacuumStmt *vacuum_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + if (vacuum_stmt->is_vacuumcmd) + appendStringInfoString(str, "VACUUM "); + else + appendStringInfoString(str, "ANALYZE "); + + deparseUtilityOptionList(str, vacuum_stmt->options); + + foreach(lc, vacuum_stmt->rels) + { + Assert(IsA(lfirst(lc), VacuumRelation)); + VacuumRelation *rel = castNode(VacuumRelation, lfirst(lc)); + + deparseRangeVar(str, rel->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(rel->va_cols) > 0) + { + appendStringInfoChar(str, '('); + foreach(lc2, rel->va_cols) + { + appendStringInfoString(str, quote_identifier(strVal(lfirst(lc2)))); + if (lnext(rel->va_cols, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + + if (lnext(vacuum_stmt->rels, lc)) + appendStringInfoString(str, ", "); + } + + removeTrailingSpace(str); +} + +static void deparseLoadStmt(StringInfo str, LoadStmt *load_stmt) +{ + appendStringInfoString(str, "LOAD "); + deparseStringLiteral(str, load_stmt->filename); +} + +static void deparseLockStmt(StringInfo str, LockStmt *lock_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "LOCK TABLE "); + + deparseRelationExprList(str, lock_stmt->relations); + appendStringInfoChar(str, ' '); + + if (lock_stmt->mode != AccessExclusiveLock) + { + appendStringInfoString(str, "IN "); + switch (lock_stmt->mode) + { + case AccessShareLock: + appendStringInfoString(str, "ACCESS SHARE "); + break; + case RowShareLock: + appendStringInfoString(str, "ROW SHARE "); + break; + case RowExclusiveLock: + appendStringInfoString(str, "ROW EXCLUSIVE "); + break; + case ShareUpdateExclusiveLock: + appendStringInfoString(str, "SHARE UPDATE EXCLUSIVE "); + break; + case ShareLock: + appendStringInfoString(str, "SHARE "); + break; + case ShareRowExclusiveLock: + appendStringInfoString(str, "SHARE ROW EXCLUSIVE "); + break; + case ExclusiveLock: + appendStringInfoString(str, "EXCLUSIVE "); + break; + case AccessExclusiveLock: + appendStringInfoString(str, "ACCESS EXCLUSIVE "); + break; + default: + Assert(false); + break; + } + appendStringInfoString(str, "MODE "); + } + + if (lock_stmt->nowait) + appendStringInfoString(str, "NOWAIT "); + + removeTrailingSpace(str); +} + +static void deparseConstraintsSetStmt(StringInfo str, ConstraintsSetStmt *constraints_set_stmt) +{ + appendStringInfoString(str, "SET CONSTRAINTS "); + + if (list_length(constraints_set_stmt->constraints) > 0) + { + deparseQualifiedNameList(str, constraints_set_stmt->constraints); + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + if (constraints_set_stmt->deferred) + appendStringInfoString(str, "DEFERRED"); + else + appendStringInfoString(str, "IMMEDIATE"); +} + +static void deparseExplainStmt(StringInfo str, ExplainStmt *explain_stmt) +{ + ListCell *lc = NULL; + char *defname = NULL; + + appendStringInfoString(str, "EXPLAIN "); + + deparseUtilityOptionList(str, explain_stmt->options); + + deparseExplainableStmt(str, explain_stmt->query); +} + +static void deparseCopyStmt(StringInfo str, CopyStmt *copy_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "COPY "); + + if (copy_stmt->relation != NULL) + { + deparseRangeVar(str, copy_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + if (list_length(copy_stmt->attlist) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, copy_stmt->attlist); + appendStringInfoChar(str, ')'); + } + appendStringInfoChar(str, ' '); + } + + if (copy_stmt->query != NULL) + { + appendStringInfoChar(str, '('); + deparsePreparableStmt(str, copy_stmt->query); + appendStringInfoString(str, ") "); + } + + if (copy_stmt->is_from) + appendStringInfoString(str, "FROM "); + else + appendStringInfoString(str, "TO "); + + if (copy_stmt->is_program) + appendStringInfoString(str, "PROGRAM "); + + if (copy_stmt->filename != NULL) + { + deparseStringLiteral(str, copy_stmt->filename); + appendStringInfoChar(str, ' '); + } + else + { + if (copy_stmt->is_from) + appendStringInfoString(str, "STDIN "); + else + appendStringInfoString(str, "STDOUT "); + } + + if (list_length(copy_stmt->options) > 0) + { + // In some cases, equivalent expressions may have slightly different parse trees for `COPY` + // statements. For example the following two statements result in different (but equivalent) parse + // trees: + // + // - COPY foo FROM STDIN CSV FREEZE + // - COPY foo FROM STDIN WITH (FORMAT CSV, FREEZE) + // + // In order to make sure we deparse to the "correct" version, we always try to deparse to the older + // compact syntax first. + // + // The old syntax can be seen here in the Postgres 8.4 Reference: + // https://www.postgresql.org/docs/8.4/sql-copy.html + + bool old_fmt = true; + + // Loop over the options to see if any require the new `WITH (...)` syntax. + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "freeze") == 0 && optBooleanValue(def_elem->arg)) + {} + else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) + {} + else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) + {} + else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) + {} + else + { + old_fmt = false; + break; + } + } + + // Branch to differing output modes, depending on if we can use the old syntax. + if (old_fmt) { + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "freeze") == 0 && optBooleanValue(def_elem->arg)) + { + appendStringInfoString(str, "FREEZE "); + } + else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) + { + appendStringInfoString(str, "HEADER "); + } + else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) + { + appendStringInfoString(str, "CSV "); + } + else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) + { + appendStringInfoString(str, "FORCE QUOTE "); + deparseColumnList(str, castNode(List, def_elem->arg)); + } + else + { + // This isn't reachable, the conditions here are exactly the same as the first loop above. + Assert(false); + } + } + } else { + appendStringInfoString(str, "WITH ("); + foreach(lc, copy_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + + if (strcmp(def_elem->defname, "format") == 0) + { + appendStringInfoString(str, "FORMAT "); + + char *format = strVal(def_elem->arg); + if (strcmp(format, "binary") == 0) + appendStringInfoString(str, "BINARY"); + else if (strcmp(format, "csv") == 0) + appendStringInfoString(str, "CSV"); + else + Assert(false); + } + else if (strcmp(def_elem->defname, "freeze") == 0) + { + appendStringInfoString(str, "FREEZE"); + deparseOptBoolean(str, def_elem->arg); + } + else if (strcmp(def_elem->defname, "delimiter") == 0) + { + appendStringInfoString(str, "DELIMITER "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "null") == 0) + { + appendStringInfoString(str, "NULL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "header") == 0) + { + appendStringInfoString(str, "HEADER"); + deparseOptBoolean(str, def_elem->arg); + } + else if (strcmp(def_elem->defname, "quote") == 0) + { + appendStringInfoString(str, "QUOTE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "escape") == 0) + { + appendStringInfoString(str, "ESCAPE "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "force_quote") == 0) + { + appendStringInfoString(str, "FORCE_QUOTE "); + if (IsA(def_elem->arg, A_Star)) + { + appendStringInfoChar(str, '*'); + } + else if (IsA(def_elem->arg, List)) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "force_not_null") == 0) + { + appendStringInfoString(str, "FORCE_NOT_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "force_null") == 0) + { + appendStringInfoString(str, "FORCE_NULL ("); + deparseColumnList(str, castNode(List, def_elem->arg)); + appendStringInfoChar(str, ')'); + } + else if (strcmp(def_elem->defname, "encoding") == 0) + { + appendStringInfoString(str, "ENCODING "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + appendStringInfoString(str, quote_identifier(def_elem->defname)); + if (def_elem->arg != NULL) + appendStringInfoChar(str, ' '); + + if (def_elem->arg == NULL) + { + // Nothing + } + else if (IsA(def_elem->arg, String)) + { + deparseOptBooleanOrString(str, strVal(def_elem->arg)); + } + else if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) + { + deparseNumericOnly(str, (union ValUnion *) def_elem->arg); + } + else if (IsA(def_elem->arg, A_Star)) + { + deparseAStar(str, castNode(A_Star, def_elem->arg)); + } + else if (IsA(def_elem->arg, List)) + { + List *l = castNode(List, def_elem->arg); + appendStringInfoChar(str, '('); + foreach(lc2, l) + { + deparseOptBooleanOrString(str, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + } + } + + if (lnext(copy_stmt->options, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + } + + deparseWhereClause(str, copy_stmt->whereClause); + + removeTrailingSpace(str); +} + +static void deparseDoStmt(StringInfo str, DoStmt *do_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DO "); + + foreach (lc, do_stmt->args) + { + DefElem *defel = castNode(DefElem, lfirst(lc)); + if (strcmp(defel->defname, "language") == 0) + { + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(defel->arg))); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defel->defname, "as") == 0) + { + char *strval = strVal(defel->arg); + const char *delim = "$$"; + if (strstr(strval, "$$") != NULL) + delim = "$outer$"; + appendStringInfoString(str, delim); + appendStringInfoString(str, strval); + appendStringInfoString(str, delim); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDiscardStmt(StringInfo str, DiscardStmt *discard_stmt) +{ + appendStringInfoString(str, "DISCARD "); + switch (discard_stmt->target) + { + case DISCARD_ALL: + appendStringInfoString(str, "ALL"); + break; + case DISCARD_PLANS: + appendStringInfoString(str, "PLANS"); + break; + case DISCARD_SEQUENCES: + appendStringInfoString(str, "SEQUENCES"); + break; + case DISCARD_TEMP: + appendStringInfoString(str, "TEMP"); + break; + } +} + +static void deparseDefineStmt(StringInfo str, DefineStmt *define_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (define_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + default: + // This shouldn't happen + Assert(false); + break; + } + + if (define_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + switch (define_stmt->kind) + { + case OBJECT_AGGREGATE: + deparseFuncName(str, define_stmt->defnames); + break; + case OBJECT_OPERATOR: + deparseAnyOperator(str, define_stmt->defnames); + break; + case OBJECT_TYPE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_COLLATION: + deparseAnyName(str, define_stmt->defnames); + break; + default: + Assert(false); + } + appendStringInfoChar(str, ' '); + + if (!define_stmt->oldstyle && define_stmt->kind == OBJECT_AGGREGATE) + { + deparseAggrArgs(str, define_stmt->args); + appendStringInfoChar(str, ' '); + } + + if (define_stmt->kind == OBJECT_COLLATION && + list_length(define_stmt->definition) == 1 && + strcmp(castNode(DefElem, linitial(define_stmt->definition))->defname, "from") == 0) + { + appendStringInfoString(str, "FROM "); + deparseAnyName(str, castNode(List, castNode(DefElem, linitial(define_stmt->definition))->arg)); + } + else if (list_length(define_stmt->definition) > 0) + { + deparseDefinition(str, define_stmt->definition); + } + + removeTrailingSpace(str); +} + +static void deparseCompositeTypeStmt(StringInfo str, CompositeTypeStmt *composite_type_stmt) +{ + ListCell *lc; + RangeVar *typevar; + + appendStringInfoString(str, "CREATE TYPE "); + deparseRangeVar(str, composite_type_stmt->typevar, DEPARSE_NODE_CONTEXT_CREATE_TYPE); + + appendStringInfoString(str, " AS ("); + foreach(lc, composite_type_stmt->coldeflist) + { + deparseColumnDef(str, castNode(ColumnDef, lfirst(lc))); + if (lnext(composite_type_stmt->coldeflist, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateEnumStmt(StringInfo str, CreateEnumStmt *create_enum_stmt) +{ + ListCell *lc; + appendStringInfoString(str, "CREATE TYPE "); + + deparseAnyName(str, create_enum_stmt->typeName); + appendStringInfoString(str, " AS ENUM ("); + foreach(lc, create_enum_stmt->vals) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(create_enum_stmt->vals, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseCreateRangeStmt(StringInfo str, CreateRangeStmt *create_range_stmt) +{ + appendStringInfoString(str, "CREATE TYPE "); + deparseAnyName(str, create_range_stmt->typeName); + appendStringInfoString(str, " AS RANGE "); + deparseDefinition(str, create_range_stmt->params); +} + +static void deparseAlterEnumStmt(StringInfo str, AlterEnumStmt *alter_enum_stmt) +{ + appendStringInfoString(str, "ALTER TYPE "); + deparseAnyName(str, alter_enum_stmt->typeName); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->oldVal == NULL) + { + appendStringInfoString(str, "ADD VALUE "); + if (alter_enum_stmt->skipIfNewValExists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseStringLiteral(str, alter_enum_stmt->newVal); + appendStringInfoChar(str, ' '); + + if (alter_enum_stmt->newValNeighbor) + { + if (alter_enum_stmt->newValIsAfter) + appendStringInfoString(str, "AFTER "); + else + appendStringInfoString(str, "BEFORE "); + deparseStringLiteral(str, alter_enum_stmt->newValNeighbor); + } + } + else + { + appendStringInfoString(str, "RENAME VALUE "); + deparseStringLiteral(str, alter_enum_stmt->oldVal); + appendStringInfoString(str, " TO "); + deparseStringLiteral(str, alter_enum_stmt->newVal); + } + + removeTrailingSpace(str); +} + +static void deparseAlterExtensionStmt(StringInfo str, AlterExtensionStmt *alter_extension_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_stmt->extname); + appendStringInfoString(str, " UPDATE "); + foreach (lc, alter_extension_stmt->options) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + if (strcmp(def_elem->defname, "new_version") == 0) + { + appendStringInfoString(str, "TO "); + deparseNonReservedWordOrSconst(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + appendStringInfoChar(str, ' '); + } + removeTrailingSpace(str); +} + +static void deparseAlterExtensionContentsStmt(StringInfo str, AlterExtensionContentsStmt *alter_extension_contents_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER EXTENSION "); + deparseColId(str, alter_extension_contents_stmt->extname); + appendStringInfoChar(str, ' '); + + if (alter_extension_contents_stmt->action == 1) + appendStringInfoString(str, "ADD "); + else if (alter_extension_contents_stmt->action == -1) + appendStringInfoString(str, "DROP "); + else + Assert(false); + + switch (alter_extension_contents_stmt->objtype) + { + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + default: + // No other object types are supported here in the parser + Assert(false); + break; + } + + switch (alter_extension_contents_stmt->objtype) + { + // any_name + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_TABLE: + case OBJECT_TSPARSER: + case OBJECT_TSDICTIONARY: + case OBJECT_TSTEMPLATE: + case OBJECT_TSCONFIGURATION: + case OBJECT_SEQUENCE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_FOREIGN_TABLE: + deparseAnyName(str, castNode(List, alter_extension_contents_stmt->object)); + break; + // name + case OBJECT_ACCESS_METHOD: + case OBJECT_LANGUAGE: + case OBJECT_SCHEMA: + case OBJECT_EVENT_TRIGGER: + case OBJECT_FDW: + case OBJECT_FOREIGN_SERVER: + deparseColId(str, strVal(alter_extension_contents_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_CAST: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + case OBJECT_DOMAIN: + case OBJECT_TYPE: + deparseTypeName(str, castNode(TypeName, alter_extension_contents_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); + break; + case OBJECT_OPFAMILY: + case OBJECT_OPCLASS: + l = castNode(List, alter_extension_contents_stmt->object); + Assert(list_length(l) == 2); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_TRANSFORM: + l = castNode(List, alter_extension_contents_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + deparseColId(str, strVal(lsecond(l))); + break; + default: + Assert(false); + break; + } +} + +static void deparseAccessPriv(StringInfo str, AccessPriv *access_priv) +{ + ListCell *lc; + + if (access_priv->priv_name != NULL) + { + if (strcmp(access_priv->priv_name, "select") == 0) + appendStringInfoString(str, "select"); + else if (strcmp(access_priv->priv_name, "references") == 0) + appendStringInfoString(str, "references"); + else if (strcmp(access_priv->priv_name, "create") == 0) + appendStringInfoString(str, "create"); + else + appendStringInfoString(str, quote_identifier(access_priv->priv_name)); + } + else + { + appendStringInfoString(str, "ALL"); + } + appendStringInfoChar(str, ' '); + + if (list_length(access_priv->cols) > 0) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, access_priv->cols); + appendStringInfoChar(str, ')'); + } + + removeTrailingSpace(str); +} + +static void deparseGrantStmt(StringInfo str, GrantStmt *grant_stmt) +{ + ListCell *lc; + if (grant_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + if (!grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "GRANT OPTION FOR "); + + if (list_length(grant_stmt->privileges) > 0) + { + foreach(lc, grant_stmt->privileges) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_stmt->privileges, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + } + else + { + appendStringInfoString(str, "ALL "); + } + + appendStringInfoString(str, "ON "); + + deparsePrivilegeTarget(str, grant_stmt->targtype, grant_stmt->objtype, grant_stmt->objects); + appendStringInfoChar(str, ' '); + + if (grant_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + foreach(lc, grant_stmt->grantees) + { + deparseRoleSpec(str, castNode(RoleSpec, lfirst(lc))); + if (lnext(grant_stmt->grantees, lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_stmt->is_grant && grant_stmt->grant_option) + appendStringInfoString(str, "WITH GRANT OPTION "); + + deparseOptDropBehavior(str, grant_stmt->behavior); + + if (grant_stmt->grantor) + { + appendStringInfoString(str, "GRANTED BY "); + deparseRoleSpec(str, castNode(RoleSpec, grant_stmt->grantor)); + } + + removeTrailingSpace(str); +} + +static void deparseGrantRoleStmt(StringInfo str, GrantRoleStmt *grant_role_stmt) +{ + ListCell *lc; + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "GRANT "); + else + appendStringInfoString(str, "REVOKE "); + + if (!grant_role_stmt->is_grant && grant_role_stmt->admin_opt) + appendStringInfoString(str, "ADMIN OPTION FOR "); + + foreach(lc, grant_role_stmt->granted_roles) + { + deparseAccessPriv(str, castNode(AccessPriv, lfirst(lc))); + if (lnext(grant_role_stmt->granted_roles, lc)) + appendStringInfoChar(str, ','); + appendStringInfoChar(str, ' '); + } + + if (grant_role_stmt->is_grant) + appendStringInfoString(str, "TO "); + else + appendStringInfoString(str, "FROM "); + + deparseRoleList(str, grant_role_stmt->grantee_roles); + appendStringInfoChar(str, ' '); + + if (grant_role_stmt->is_grant && grant_role_stmt->admin_opt) + appendStringInfoString(str, "WITH ADMIN OPTION "); + + if (grant_role_stmt->grantor) + { + appendStringInfoString(str, "GRANTED BY "); + deparseRoleSpec(str, castNode(RoleSpec, grant_role_stmt->grantor)); + } + + removeTrailingSpace(str); +} + +static void deparseDropRoleStmt(StringInfo str, DropRoleStmt *drop_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "DROP ROLE "); + + if (drop_role_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRoleList(str, drop_role_stmt->roles); +} + +static void deparseIndexStmt(StringInfo str, IndexStmt *index_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (index_stmt->unique) + appendStringInfoString(str, "UNIQUE "); + + appendStringInfoString(str, "INDEX "); + + if (index_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + if (index_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + if (index_stmt->idxname != NULL) + { + appendStringInfoString(str, quote_identifier(index_stmt->idxname)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, index_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (index_stmt->accessMethod != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(index_stmt->accessMethod)); + appendStringInfoChar(str, ' '); + } + + appendStringInfoChar(str, '('); + foreach (lc, index_stmt->indexParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + + if (list_length(index_stmt->indexIncludingParams) > 0) + { + appendStringInfoString(str, "INCLUDE ("); + foreach (lc, index_stmt->indexIncludingParams) + { + deparseIndexElem(str, castNode(IndexElem, lfirst(lc))); + if (lnext(index_stmt->indexIncludingParams, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoString(str, ") "); + } + + if (index_stmt->nulls_not_distinct) + { + appendStringInfoString(str, "NULLS NOT DISTINCT "); + } + + deparseOptWith(str, index_stmt->options); + + if (index_stmt->tableSpace != NULL) + { + appendStringInfoString(str, "TABLESPACE "); + appendStringInfoString(str, quote_identifier(index_stmt->tableSpace)); + appendStringInfoChar(str, ' '); + } + + deparseWhereClause(str, index_stmt->whereClause); + + removeTrailingSpace(str); +} + +static void deparseAlterOpFamilyStmt(StringInfo str, AlterOpFamilyStmt *alter_op_family_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR FAMILY "); + deparseAnyName(str, alter_op_family_stmt->opfamilyname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(alter_op_family_stmt->amname)); + appendStringInfoChar(str, ' '); + + if (alter_op_family_stmt->isDrop) + appendStringInfoString(str, "DROP "); + else + appendStringInfoString(str, "ADD "); + + deparseOpclassItemList(str, alter_op_family_stmt->items); +} + +static void deparsePrepareStmt(StringInfo str, PrepareStmt *prepare_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "PREPARE "); + deparseColId(str, prepare_stmt->name); + if (list_length(prepare_stmt->argtypes) > 0) + { + appendStringInfoChar(str, '('); + deparseTypeList(str, prepare_stmt->argtypes); + appendStringInfoChar(str, ')'); + } + appendStringInfoString(str, " AS "); + deparsePreparableStmt(str, prepare_stmt->query); +} + +static void deparseExecuteStmt(StringInfo str, ExecuteStmt *execute_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "EXECUTE "); + appendStringInfoString(str, quote_identifier(execute_stmt->name)); + if (list_length(execute_stmt->params) > 0) + { + appendStringInfoChar(str, '('); + deparseExprList(str, execute_stmt->params); + appendStringInfoChar(str, ')'); + } +} + +static void deparseDeallocateStmt(StringInfo str, DeallocateStmt *deallocate_stmt) +{ + appendStringInfoString(str, "DEALLOCATE "); + if (deallocate_stmt->name != NULL) + appendStringInfoString(str, quote_identifier(deallocate_stmt->name)); + else + appendStringInfoString(str, "ALL"); +} + +// "AlterOptRoleElem" in gram.y +static void deparseAlterRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "password") == 0) + { + appendStringInfoString(str, "PASSWORD "); + if (def_elem->arg == NULL) + { + appendStringInfoString(str, "NULL"); + } + else if (IsA(def_elem->arg, ParamRef)) + { + deparseParamRef(str, castNode(ParamRef, def_elem->arg)); + } + else if (IsA(def_elem->arg, String)) + { + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else + { + Assert(false); + } + } + else if (strcmp(def_elem->defname, "connectionlimit") == 0) + { + appendStringInfo(str, "CONNECTION LIMIT %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "validUntil") == 0) + { + appendStringInfoString(str, "VALID UNTIL "); + deparseStringLiteral(str, strVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "SUPERUSER"); + } + else if (strcmp(def_elem->defname, "superuser") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOSUPERUSER"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "CREATEROLE"); + } + else if (strcmp(def_elem->defname, "createrole") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOCREATEROLE"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "REPLICATION"); + } + else if (strcmp(def_elem->defname, "isreplication") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOREPLICATION"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "CREATEDB"); + } + else if (strcmp(def_elem->defname, "createdb") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOCREATEDB"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "LOGIN"); + } + else if (strcmp(def_elem->defname, "canlogin") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOLOGIN"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "BYPASSRLS"); + } + else if (strcmp(def_elem->defname, "bypassrls") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOBYPASSRLS"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && boolVal(def_elem->arg)) + { + appendStringInfoString(str, "INHERIT"); + } + else if (strcmp(def_elem->defname, "inherit") == 0 && !boolVal(def_elem->arg)) + { + appendStringInfoString(str, "NOINHERIT"); + } + else + { + Assert(false); + } +} + +// "CreateOptRoleElem" in gram.y +static void deparseCreateRoleElem(StringInfo str, DefElem *def_elem) +{ + if (strcmp(def_elem->defname, "sysid") == 0) + { + appendStringInfo(str, "SYSID %d", intVal(def_elem->arg)); + } + else if (strcmp(def_elem->defname, "adminmembers") == 0) + { + appendStringInfoString(str, "ADMIN "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else if (strcmp(def_elem->defname, "addroleto") == 0) + { + appendStringInfoString(str, "IN ROLE "); + deparseRoleList(str, castNode(List, def_elem->arg)); + } + else + { + deparseAlterRoleElem(str, def_elem); + } +} + +static void deparseCreatePLangStmt(StringInfo str, CreatePLangStmt *create_p_lang_stmt) +{ + appendStringInfoString(str, "CREATE "); + + if (create_p_lang_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + if (create_p_lang_stmt->pltrusted) + appendStringInfoString(str, "TRUSTED "); + + appendStringInfoString(str, "LANGUAGE "); + deparseNonReservedWordOrSconst(str, create_p_lang_stmt->plname); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_p_lang_stmt->plhandler); + appendStringInfoChar(str, ' '); + + if (create_p_lang_stmt->plinline) + { + appendStringInfoString(str, "INLINE "); + deparseHandlerName(str, create_p_lang_stmt->plinline); + appendStringInfoChar(str, ' '); + } + + if (create_p_lang_stmt->plvalidator) + { + appendStringInfoString(str, "VALIDATOR "); + deparseHandlerName(str, create_p_lang_stmt->plvalidator); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseCreateRoleStmt(StringInfo str, CreateRoleStmt *create_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + switch (create_role_stmt->stmt_type) + { + case ROLESTMT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case ROLESTMT_USER: + appendStringInfoString(str, "USER "); + break; + case ROLESTMT_GROUP: + appendStringInfoString(str, "GROUP "); + break; + } + + appendStringInfoString(str, quote_identifier(create_role_stmt->role)); + appendStringInfoChar(str, ' '); + + if (create_role_stmt->options != NULL) + { + appendStringInfoString(str, "WITH "); + foreach (lc, create_role_stmt->options) + { + deparseCreateRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseAlterRoleStmt(StringInfo str, AlterRoleStmt *alter_role_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + if (list_length(alter_role_stmt->options) == 1 && strcmp(castNode(DefElem, linitial(alter_role_stmt->options))->defname, "rolemembers") == 0) + { + appendStringInfoString(str, "GROUP "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + if (alter_role_stmt->action == 1) + { + appendStringInfoString(str, "ADD USER "); + } + else if (alter_role_stmt->action == -1) + { + appendStringInfoString(str, "DROP USER "); + } + else + { + Assert(false); + } + + deparseRoleList(str, castNode(List, castNode(DefElem, linitial(alter_role_stmt->options))->arg)); + } + else + { + appendStringInfoString(str, "ROLE "); + deparseRoleSpec(str, alter_role_stmt->role); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "WITH "); + foreach (lc, alter_role_stmt->options) + { + deparseAlterRoleElem(str, castNode(DefElem, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + removeTrailingSpace(str); +} + +static void deparseDeclareCursorStmt(StringInfo str, DeclareCursorStmt *declare_cursor_stmt) +{ + appendStringInfoString(str, "DECLARE "); + appendStringInfoString(str, quote_identifier(declare_cursor_stmt->portalname)); + appendStringInfoChar(str, ' '); + + if (declare_cursor_stmt->options & CURSOR_OPT_BINARY) + appendStringInfoString(str, "BINARY "); + + if (declare_cursor_stmt->options & CURSOR_OPT_SCROLL) + appendStringInfoString(str, "SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_NO_SCROLL) + appendStringInfoString(str, "NO SCROLL "); + + if (declare_cursor_stmt->options & CURSOR_OPT_INSENSITIVE) + appendStringInfoString(str, "INSENSITIVE "); + + appendStringInfoString(str, "CURSOR "); + + if (declare_cursor_stmt->options & CURSOR_OPT_HOLD) + appendStringInfoString(str, "WITH HOLD "); + + appendStringInfoString(str, "FOR "); + + deparseSelectStmt(str, castNode(SelectStmt, declare_cursor_stmt->query)); +} + +static void deparseFetchStmt(StringInfo str, FetchStmt *fetch_stmt) +{ + if (fetch_stmt->ismove) + appendStringInfoString(str, "MOVE "); + else + appendStringInfoString(str, "FETCH "); + + switch (fetch_stmt->direction) + { + case FETCH_FORWARD: + if (fetch_stmt->howMany == 1) + { + // Default + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "ALL "); + } + else + { + appendStringInfo(str, "FORWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_BACKWARD: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "PRIOR "); + } + else if (fetch_stmt->howMany == FETCH_ALL) + { + appendStringInfoString(str, "BACKWARD ALL "); + } + else + { + appendStringInfo(str, "BACKWARD %ld ", fetch_stmt->howMany); + } + break; + case FETCH_ABSOLUTE: + if (fetch_stmt->howMany == 1) + { + appendStringInfoString(str, "FIRST "); + } + else if (fetch_stmt->howMany == -1) + { + appendStringInfoString(str, "LAST "); + } + else + { + appendStringInfo(str, "ABSOLUTE %ld ", fetch_stmt->howMany); + } + break; + case FETCH_RELATIVE: + appendStringInfo(str, "RELATIVE %ld ", fetch_stmt->howMany); + } + + appendStringInfoString(str, fetch_stmt->portalname); +} + +static void deparseAlterDefaultPrivilegesStmt(StringInfo str, AlterDefaultPrivilegesStmt *alter_default_privileges_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER DEFAULT PRIVILEGES "); + + foreach (lc, alter_default_privileges_stmt->options) + { + DefElem *defelem = castNode(DefElem, lfirst(lc)); + if (strcmp(defelem->defname, "schemas") == 0) + { + appendStringInfoString(str, "IN SCHEMA "); + deparseNameList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else if (strcmp(defelem->defname, "roles") == 0) + { + appendStringInfoString(str, "FOR ROLE "); + deparseRoleList(str, castNode(List, defelem->arg)); + appendStringInfoChar(str, ' '); + } + else + { + // No other DefElems are supported + Assert(false); + } + } + + deparseGrantStmt(str, alter_default_privileges_stmt->action); +} + +static void deparseReindexStmt(StringInfo str, ReindexStmt *reindex_stmt) +{ + appendStringInfoString(str, "REINDEX "); + + deparseUtilityOptionList(str, reindex_stmt->params); + + switch (reindex_stmt->kind) + { + case REINDEX_OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case REINDEX_OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case REINDEX_OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case REINDEX_OBJECT_SYSTEM: + appendStringInfoString(str, "SYSTEM "); + break; + case REINDEX_OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + } + + if (reindex_stmt->relation != NULL) + { + deparseRangeVar(str, reindex_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + } + else if (reindex_stmt->name != NULL) + { + appendStringInfoString(str, quote_identifier(reindex_stmt->name)); + } +} + +static void deparseRuleStmt(StringInfo str, RuleStmt* rule_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + if (rule_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "RULE "); + appendStringInfoString(str, quote_identifier(rule_stmt->rulename)); + appendStringInfoString(str, " AS ON "); + + switch (rule_stmt->event) + { + case CMD_UNKNOWN: + case CMD_UTILITY: + case CMD_NOTHING: + // Not supported here + Assert(false); + break; + case CMD_SELECT: + appendStringInfoString(str, "SELECT "); + break; + case CMD_UPDATE: + appendStringInfoString(str, "UPDATE "); + break; + case CMD_INSERT: + appendStringInfoString(str, "INSERT "); + break; + case CMD_DELETE: + appendStringInfoString(str, "DELETE "); + break; + case CMD_MERGE: + appendStringInfoString(str, "MERGE "); + break; + } + + appendStringInfoString(str, "TO "); + deparseRangeVar(str, rule_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseWhereClause(str, rule_stmt->whereClause); + + appendStringInfoString(str, "DO "); + + if (rule_stmt->instead) + appendStringInfoString(str, "INSTEAD "); + + if (list_length(rule_stmt->actions) == 0) + { + appendStringInfoString(str, "NOTHING"); + } + else if (list_length(rule_stmt->actions) == 1) + { + deparseRuleActionStmt(str, linitial(rule_stmt->actions)); + } + else + { + appendStringInfoChar(str, '('); + foreach (lc, rule_stmt->actions) + { + deparseRuleActionStmt(str, lfirst(lc)); + if (lnext(rule_stmt->actions, lc)) + appendStringInfoString(str, "; "); + } + appendStringInfoChar(str, ')'); + } +} + +static void deparseNotifyStmt(StringInfo str, NotifyStmt *notify_stmt) +{ + appendStringInfoString(str, "NOTIFY "); + appendStringInfoString(str, quote_identifier(notify_stmt->conditionname)); + + if (notify_stmt->payload != NULL) + { + appendStringInfoString(str, ", "); + deparseStringLiteral(str, notify_stmt->payload); + } +} + +static void deparseListenStmt(StringInfo str, ListenStmt *listen_stmt) +{ + appendStringInfoString(str, "LISTEN "); + appendStringInfoString(str, quote_identifier(listen_stmt->conditionname)); +} + +static void deparseUnlistenStmt(StringInfo str, UnlistenStmt *unlisten_stmt) +{ + appendStringInfoString(str, "UNLISTEN "); + if (unlisten_stmt->conditionname == NULL) + appendStringInfoString(str, "*"); + else + appendStringInfoString(str, quote_identifier(unlisten_stmt->conditionname)); +} + +static void deparseCreateSeqStmt(StringInfo str, CreateSeqStmt *create_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE "); + + deparseOptTemp(str, create_seq_stmt->sequence->relpersistence); + + appendStringInfoString(str, "SEQUENCE "); + + if (create_seq_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseRangeVar(str, create_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseOptSeqOptList(str, create_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterFunctionStmt(StringInfo str, AlterFunctionStmt *alter_function_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER "); + + switch (alter_function_stmt->objtype) + { + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + default: + // Not supported here + Assert(false); + break; + } + + deparseFunctionWithArgtypes(str, alter_function_stmt->func); + appendStringInfoChar(str, ' '); + + foreach (lc, alter_function_stmt->actions) + { + deparseCommonFuncOptItem(str, castNode(DefElem, lfirst(lc))); + if (lnext(alter_function_stmt->actions, lc)) + appendStringInfoChar(str, ' '); + } +} + +static void deparseTruncateStmt(StringInfo str, TruncateStmt *truncate_stmt) +{ + appendStringInfoString(str, "TRUNCATE "); + + deparseRelationExprList(str, truncate_stmt->relations); + appendStringInfoChar(str, ' '); + + if (truncate_stmt->restart_seqs) + appendStringInfoString(str, "RESTART IDENTITY "); + + deparseOptDropBehavior(str, truncate_stmt->behavior); + + removeTrailingSpace(str); +} + +static void deparseCreateEventTrigStmt(StringInfo str, CreateEventTrigStmt *create_event_trig_stmt) +{ + ListCell *lc = NULL; + ListCell *lc2 = NULL; + + appendStringInfoString(str, "CREATE EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "ON "); + appendStringInfoString(str, quote_identifier(create_event_trig_stmt->eventname)); + appendStringInfoChar(str, ' '); + + if (create_event_trig_stmt->whenclause) + { + appendStringInfoString(str, "WHEN "); + + foreach (lc, create_event_trig_stmt->whenclause) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + List *l = castNode(List, def_elem->arg); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " IN ("); + foreach (lc2, l) + { + deparseStringLiteral(str, strVal(lfirst(lc2))); + if (lnext(l, lc2)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); + if (lnext(create_event_trig_stmt->whenclause, lc)) + appendStringInfoString(str, " AND "); + } + + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_event_trig_stmt->funcname); + appendStringInfoString(str, "()"); +} + +static void deparseAlterEventTrigStmt(StringInfo str, AlterEventTrigStmt *alter_event_trig_stmt) +{ + appendStringInfoString(str, "ALTER EVENT TRIGGER "); + appendStringInfoString(str, quote_identifier(alter_event_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (alter_event_trig_stmt->tgenabled) + { + case TRIGGER_FIRES_ON_ORIGIN: + appendStringInfoString(str, "ENABLE"); + break; + case TRIGGER_FIRES_ON_REPLICA: + appendStringInfoString(str, "ENABLE REPLICA"); + break; + case TRIGGER_FIRES_ALWAYS: + appendStringInfoString(str, "ENABLE ALWAYS"); + break; + case TRIGGER_DISABLED: + appendStringInfoString(str, "DISABLE"); + break; + } +} + +static void deparseRefreshMatViewStmt(StringInfo str, RefreshMatViewStmt *refresh_mat_view_stmt) +{ + appendStringInfoString(str, "REFRESH MATERIALIZED VIEW "); + + if (refresh_mat_view_stmt->concurrent) + appendStringInfoString(str, "CONCURRENTLY "); + + deparseRangeVar(str, refresh_mat_view_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (refresh_mat_view_stmt->skipData) + appendStringInfoString(str, "WITH NO DATA "); + + removeTrailingSpace(str); +} + +static void deparseReplicaIdentityStmt(StringInfo str, ReplicaIdentityStmt *replica_identity_stmt) +{ + switch (replica_identity_stmt->identity_type) + { + case REPLICA_IDENTITY_NOTHING: + appendStringInfoString(str, "NOTHING "); + break; + case REPLICA_IDENTITY_FULL: + appendStringInfoString(str, "FULL "); + break; + case REPLICA_IDENTITY_DEFAULT: + appendStringInfoString(str, "DEFAULT "); + break; + case REPLICA_IDENTITY_INDEX: + Assert(replica_identity_stmt->name != NULL); + appendStringInfoString(str, "USING INDEX "); + appendStringInfoString(str, quote_identifier(replica_identity_stmt->name)); + break; + } +} + +static void deparseCreatePolicyStmt(StringInfo str, CreatePolicyStmt *create_policy_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE POLICY "); + deparseColId(str, create_policy_stmt->policy_name); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, create_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (!create_policy_stmt->permissive) + appendStringInfoString(str, "AS RESTRICTIVE "); + + if (strcmp(create_policy_stmt->cmd_name, "all") == 0) + Assert(true); // Default + else if (strcmp(create_policy_stmt->cmd_name, "select") == 0) + appendStringInfoString(str, "FOR SELECT "); + else if (strcmp(create_policy_stmt->cmd_name, "insert") == 0) + appendStringInfoString(str, "FOR INSERT "); + else if (strcmp(create_policy_stmt->cmd_name, "update") == 0) + appendStringInfoString(str, "FOR UPDATE "); + else if (strcmp(create_policy_stmt->cmd_name, "delete") == 0) + appendStringInfoString(str, "FOR DELETE "); + else + Assert(false); + + appendStringInfoString(str, "TO "); + deparseRoleList(str, create_policy_stmt->roles); + appendStringInfoChar(str, ' '); + + if (create_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, create_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (create_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, create_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseAlterPolicyStmt(StringInfo str, AlterPolicyStmt *alter_policy_stmt) +{ + appendStringInfoString(str, "ALTER POLICY "); + appendStringInfoString(str, quote_identifier(alter_policy_stmt->policy_name)); + appendStringInfoString(str, " ON "); + deparseRangeVar(str, alter_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (list_length(alter_policy_stmt->roles) > 0) + { + appendStringInfoString(str, "TO "); + deparseRoleList(str, alter_policy_stmt->roles); + appendStringInfoChar(str, ' '); + } + + if (alter_policy_stmt->qual != NULL) + { + appendStringInfoString(str, "USING ("); + deparseExpr(str, alter_policy_stmt->qual); + appendStringInfoString(str, ") "); + } + + if (alter_policy_stmt->with_check != NULL) + { + appendStringInfoString(str, "WITH CHECK ("); + deparseExpr(str, alter_policy_stmt->with_check); + appendStringInfoString(str, ") "); + } +} + +static void deparseCreateTableSpaceStmt(StringInfo str, CreateTableSpaceStmt *create_table_space_stmt) +{ + appendStringInfoString(str, "CREATE TABLESPACE "); + deparseColId(str, create_table_space_stmt->tablespacename); + appendStringInfoChar(str, ' '); + + if (create_table_space_stmt->owner != NULL) + { + appendStringInfoString(str, "OWNER "); + deparseRoleSpec(str, create_table_space_stmt->owner); + appendStringInfoChar(str, ' '); + } + + appendStringInfoString(str, "LOCATION "); + + if (create_table_space_stmt->location != NULL) + deparseStringLiteral(str, create_table_space_stmt->location); + else + appendStringInfoString(str, "''"); + + appendStringInfoChar(str, ' '); + + deparseOptWith(str, create_table_space_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseCreateTransformStmt(StringInfo str, CreateTransformStmt *create_transform_stmt) +{ + appendStringInfoString(str, "CREATE "); + if (create_transform_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + + appendStringInfoString(str, "TRANSFORM FOR "); + deparseTypeName(str, create_transform_stmt->type_name); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "LANGUAGE "); + appendStringInfoString(str, quote_identifier(create_transform_stmt->lang)); + appendStringInfoChar(str, ' '); + + appendStringInfoChar(str, '('); + + if (create_transform_stmt->fromsql) + { + appendStringInfoString(str, "FROM SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->fromsql); + } + + if (create_transform_stmt->fromsql && create_transform_stmt->tosql) + appendStringInfoString(str, ", "); + + if (create_transform_stmt->tosql) + { + appendStringInfoString(str, "TO SQL WITH FUNCTION "); + deparseFunctionWithArgtypes(str, create_transform_stmt->tosql); + } + + appendStringInfoChar(str, ')'); +} + +static void deparseCreateAmStmt(StringInfo str, CreateAmStmt *create_am_stmt) +{ + appendStringInfoString(str, "CREATE ACCESS METHOD "); + appendStringInfoString(str, quote_identifier(create_am_stmt->amname)); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TYPE "); + switch (create_am_stmt->amtype) + { + case AMTYPE_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case AMTYPE_TABLE: + appendStringInfoString(str, "TABLE "); + break; + } + + appendStringInfoString(str, "HANDLER "); + deparseHandlerName(str, create_am_stmt->handler_name); +} + +static void deparsePublicationObjectList(StringInfo str, List *pubobjects) { + const ListCell *lc; + foreach(lc, pubobjects) { + PublicationObjSpec *obj = lfirst(lc); + + switch (obj->pubobjtype) { + case PUBLICATIONOBJ_TABLE: + appendStringInfoString(str, "TABLE "); + deparseRangeVar(str, obj->pubtable->relation, DEPARSE_NODE_CONTEXT_NONE); + + if (obj->pubtable->columns) + { + appendStringInfoChar(str, '('); + deparseColumnList(str, obj->pubtable->columns); + appendStringInfoChar(str, ')'); + } + + if (obj->pubtable->whereClause) + { + appendStringInfoString(str, " WHERE ("); + deparseExpr(str, obj->pubtable->whereClause); + appendStringInfoString(str, ")"); + } + + break; + case PUBLICATIONOBJ_TABLES_IN_SCHEMA: + appendStringInfoString(str, "TABLES IN SCHEMA "); + appendStringInfoString(str, quote_identifier(obj->name)); + break; + case PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA: + appendStringInfoString(str, "TABLES IN SCHEMA CURRENT_SCHEMA"); + break; + case PUBLICATIONOBJ_CONTINUATION: + // This should be unreachable, the parser merges these before we can even get here. + Assert(false); + break; + } + + if (lnext(pubobjects, lc)) { + appendStringInfoString(str, ", "); + } + } +} + +static void deparseCreatePublicationStmt(StringInfo str, CreatePublicationStmt *create_publication_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "CREATE PUBLICATION "); + appendStringInfoString(str, quote_identifier(create_publication_stmt->pubname)); + appendStringInfoChar(str, ' '); + + if (list_length(create_publication_stmt->pubobjects) > 0) + { + appendStringInfoString(str, "FOR "); + deparsePublicationObjectList(str, create_publication_stmt->pubobjects); + appendStringInfoChar(str, ' '); + } + else if (create_publication_stmt->for_all_tables) + { + appendStringInfoString(str, "FOR ALL TABLES "); + } + + deparseOptDefinition(str, create_publication_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterPublicationStmt(StringInfo str, AlterPublicationStmt *alter_publication_stmt) +{ + appendStringInfoString(str, "ALTER PUBLICATION "); + deparseColId(str, alter_publication_stmt->pubname); + appendStringInfoChar(str, ' '); + + if (list_length(alter_publication_stmt->pubobjects) > 0) + { + switch (alter_publication_stmt->action) + { + case AP_SetObjects: + appendStringInfoString(str, "SET "); + break; + case AP_AddObjects: + appendStringInfoString(str, "ADD "); + break; + case AP_DropObjects: + appendStringInfoString(str, "DROP "); + break; + } + + deparsePublicationObjectList(str, alter_publication_stmt->pubobjects); + } + else if (list_length(alter_publication_stmt->options) > 0) + { + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_publication_stmt->options); + } + else + { + Assert(false); + } +} + +static void deparseAlterSeqStmt(StringInfo str, AlterSeqStmt *alter_seq_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SEQUENCE "); + + if (alter_seq_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseRangeVar(str, alter_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + deparseSeqOptList(str, alter_seq_stmt->options); + + removeTrailingSpace(str); +} + +static void deparseAlterSystemStmt(StringInfo str, AlterSystemStmt *alter_system_stmt) +{ + appendStringInfoString(str, "ALTER SYSTEM "); + deparseVariableSetStmt(str, alter_system_stmt->setstmt); +} + +static void deparseCommentStmt(StringInfo str, CommentStmt *comment_stmt) +{ + ListCell *lc; + List *l; + + appendStringInfoString(str, "COMMENT ON "); + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + appendStringInfoString(str, "COLUMN "); + break; + case OBJECT_INDEX: + appendStringInfoString(str, "INDEX "); + break; + case OBJECT_SEQUENCE: + appendStringInfoString(str, "SEQUENCE "); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + break; + case OBJECT_TABLE: + appendStringInfoString(str, "TABLE "); + break; + case OBJECT_VIEW: + appendStringInfoString(str, "VIEW "); + break; + case OBJECT_MATVIEW: + appendStringInfoString(str, "MATERIALIZED VIEW "); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + break; + case OBJECT_FOREIGN_TABLE: + appendStringInfoString(str, "FOREIGN TABLE "); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + break; + case OBJECT_TSPARSER: + appendStringInfoString(str, "TEXT SEARCH PARSER "); + break; + case OBJECT_TSTEMPLATE: + appendStringInfoString(str, "TEXT SEARCH TEMPLATE "); + break; + case OBJECT_ACCESS_METHOD: + appendStringInfoString(str, "ACCESS METHOD "); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + break; + case OBJECT_EXTENSION: + appendStringInfoString(str, "EXTENSION "); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + break; + case OBJECT_ROLE: + appendStringInfoString(str, "ROLE "); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + break; + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + break; + case OBJECT_TABCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_DOMCONSTRAINT: + appendStringInfoString(str, "CONSTRAINT "); + break; + case OBJECT_POLICY: + appendStringInfoString(str, "POLICY "); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + break; + case OBJECT_RULE: + appendStringInfoString(str, "RULE "); + break; + case OBJECT_TRANSFORM: + appendStringInfoString(str, "TRANSFORM "); + break; + case OBJECT_TRIGGER: + appendStringInfoString(str, "TRIGGER "); + break; + case OBJECT_OPCLASS: + appendStringInfoString(str, "OPERATOR CLASS "); + break; + case OBJECT_OPFAMILY: + appendStringInfoString(str, "OPERATOR FAMILY "); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + break; + case OBJECT_CAST: + appendStringInfoString(str, "CAST "); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + switch (comment_stmt->objtype) + { + case OBJECT_COLUMN: + case OBJECT_INDEX: + case OBJECT_SEQUENCE: + case OBJECT_STATISTIC_EXT: + case OBJECT_TABLE: + case OBJECT_VIEW: + case OBJECT_MATVIEW: + case OBJECT_COLLATION: + case OBJECT_CONVERSION: + case OBJECT_FOREIGN_TABLE: + case OBJECT_TSCONFIGURATION: + case OBJECT_TSDICTIONARY: + case OBJECT_TSPARSER: + case OBJECT_TSTEMPLATE: + deparseAnyName(str, castNode(List, comment_stmt->object)); + break; + case OBJECT_ACCESS_METHOD: + case OBJECT_DATABASE: + case OBJECT_EVENT_TRIGGER: + case OBJECT_EXTENSION: + case OBJECT_FDW: + case OBJECT_LANGUAGE: + case OBJECT_PUBLICATION: + case OBJECT_ROLE: + case OBJECT_SCHEMA: + case OBJECT_FOREIGN_SERVER: + case OBJECT_SUBSCRIPTION: + case OBJECT_TABLESPACE: + appendStringInfoString(str, quote_identifier(strVal(comment_stmt->object))); + break; + case OBJECT_TYPE: + case OBJECT_DOMAIN: + deparseTypeName(str, castNode(TypeName, comment_stmt->object)); + break; + case OBJECT_AGGREGATE: + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_FUNCTION: + case OBJECT_PROCEDURE: + case OBJECT_ROUTINE: + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_OPERATOR: + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, comment_stmt->object)); + break; + case OBJECT_TABCONSTRAINT: + case OBJECT_POLICY: + case OBJECT_RULE: + case OBJECT_TRIGGER: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON "); + deparseAnyNameSkipLast(str, l); + break; + case OBJECT_DOMCONSTRAINT: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, quote_identifier(strVal(llast(l)))); + appendStringInfoString(str, " ON DOMAIN "); + deparseTypeName(str, linitial(l)); + break; + case OBJECT_TRANSFORM: + l = castNode(List, comment_stmt->object); + appendStringInfoString(str, "FOR "); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " LANGUAGE "); + appendStringInfoString(str, quote_identifier(strVal(lsecond(l)))); + break; + case OBJECT_OPCLASS: + case OBJECT_OPFAMILY: + l = castNode(List, comment_stmt->object); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + appendStringInfoString(str, quote_identifier(strVal(linitial(l)))); + break; + case OBJECT_LARGEOBJECT: + deparseValue(str, (union ValUnion *) comment_stmt->object, DEPARSE_NODE_CONTEXT_NONE); + break; + case OBJECT_CAST: + l = castNode(List, comment_stmt->object); + appendStringInfoChar(str, '('); + deparseTypeName(str, castNode(TypeName, linitial(l))); + appendStringInfoString(str, " AS "); + deparseTypeName(str, castNode(TypeName, lsecond(l))); + appendStringInfoChar(str, ')'); + break; + default: + // No other cases are supported in the parser + Assert(false); + break; + } + + appendStringInfoString(str, " IS "); + + if (comment_stmt->comment != NULL) + deparseStringLiteral(str, comment_stmt->comment); + else + appendStringInfoString(str, "NULL"); +} + +static void deparseStatsElem(StringInfo str, StatsElem *stats_elem) +{ + // only one of stats_elem->name or stats_elem->expr can be non-null + if (stats_elem->name) + appendStringInfoString(str, stats_elem->name); + else if (stats_elem->expr) + { + appendStringInfoChar(str, '('); + deparseExpr(str, stats_elem->expr); + appendStringInfoChar(str, ')'); + } +} + +static void deparseCreateStatsStmt(StringInfo str, CreateStatsStmt *create_stats_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE STATISTICS "); + + if (create_stats_stmt->if_not_exists) + appendStringInfoString(str, "IF NOT EXISTS "); + + deparseAnyName(str, create_stats_stmt->defnames); + appendStringInfoChar(str, ' '); + + if (list_length(create_stats_stmt->stat_types) > 0) + { + appendStringInfoChar(str, '('); + deparseNameList(str, create_stats_stmt->stat_types); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "ON "); + foreach (lc, create_stats_stmt->exprs) + { + deparseStatsElem(str, lfirst(lc)); + if (lnext(create_stats_stmt->exprs, lc)) + appendStringInfoString(str, ", "); + } + + appendStringInfoString(str, " FROM "); + deparseFromList(str, create_stats_stmt->relations); +} + +static void deparseAlterCollationStmt(StringInfo str, AlterCollationStmt *alter_collation_stmt) +{ + appendStringInfoString(str, "ALTER COLLATION "); + deparseAnyName(str, alter_collation_stmt->collname); + appendStringInfoString(str, " REFRESH VERSION"); +} + +static void deparseAlterDatabaseStmt(StringInfo str, AlterDatabaseStmt *alter_database_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseCreatedbOptList(str, alter_database_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterDatabaseSetStmt(StringInfo str, AlterDatabaseSetStmt *alter_database_set_stmt) +{ + appendStringInfoString(str, "ALTER DATABASE "); + deparseColId(str, alter_database_set_stmt->dbname); + appendStringInfoChar(str, ' '); + deparseVariableSetStmt(str, alter_database_set_stmt->setstmt); +} + +static void deparseAlterStatsStmt(StringInfo str, AlterStatsStmt *alter_stats_stmt) +{ + appendStringInfoString(str, "ALTER STATISTICS "); + + if (alter_stats_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + deparseAnyName(str, alter_stats_stmt->defnames); + appendStringInfoChar(str, ' '); + + appendStringInfo(str, "SET STATISTICS %d", alter_stats_stmt->stxstattarget); +} + +static void deparseAlterTSDictionaryStmt(StringInfo str, AlterTSDictionaryStmt *alter_ts_dictionary_stmt) +{ + appendStringInfoString(str, "ALTER TEXT SEARCH DICTIONARY "); + + deparseAnyName(str, alter_ts_dictionary_stmt->dictname); + appendStringInfoChar(str, ' '); + + deparseDefinition(str, alter_ts_dictionary_stmt->options); +} + +static void deparseAlterTSConfigurationStmt(StringInfo str, AlterTSConfigurationStmt *alter_ts_configuration_stmt) +{ + ListCell *lc = NULL; + + appendStringInfoString(str, "ALTER TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, alter_ts_configuration_stmt->cfgname); + appendStringInfoChar(str, ' '); + + switch (alter_ts_configuration_stmt->kind) + { + case ALTER_TSCONFIG_ADD_MAPPING: + appendStringInfoString(str, "ADD MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " WITH "); + deparseAnyNameList(str, alter_ts_configuration_stmt->dicts); + break; + case ALTER_TSCONFIG_REPLACE_DICT: + appendStringInfoString(str, "ALTER MAPPING REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN: + appendStringInfoString(str, "ALTER MAPPING FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + appendStringInfoString(str, " REPLACE "); + deparseAnyName(str, linitial(alter_ts_configuration_stmt->dicts)); + appendStringInfoString(str, " WITH "); + deparseAnyName(str, lsecond(alter_ts_configuration_stmt->dicts)); + break; + case ALTER_TSCONFIG_DROP_MAPPING: + appendStringInfoString(str, "DROP MAPPING "); + if (alter_ts_configuration_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + appendStringInfoString(str, "FOR "); + deparseNameList(str, alter_ts_configuration_stmt->tokentype); + break; + } +} + +static void deparseVariableShowStmt(StringInfo str, VariableShowStmt *variable_show_stmt) +{ + appendStringInfoString(str, "SHOW "); + + if (strcmp(variable_show_stmt->name, "timezone") == 0) + appendStringInfoString(str, "TIME ZONE"); + else if (strcmp(variable_show_stmt->name, "transaction_isolation") == 0) + appendStringInfoString(str, "TRANSACTION ISOLATION LEVEL"); + else if (strcmp(variable_show_stmt->name, "session_authorization") == 0) + appendStringInfoString(str, "SESSION AUTHORIZATION"); + else if (strcmp(variable_show_stmt->name, "all") == 0) + appendStringInfoString(str, "ALL"); + else + appendStringInfoString(str, quote_identifier(variable_show_stmt->name)); +} + +static void deparseRangeTableSample(StringInfo str, RangeTableSample *range_table_sample) +{ + deparseRangeVar(str, castNode(RangeVar, range_table_sample->relation), DEPARSE_NODE_CONTEXT_NONE); + + appendStringInfoString(str, " TABLESAMPLE "); + + deparseFuncName(str, range_table_sample->method); + appendStringInfoChar(str, '('); + deparseExprList(str, range_table_sample->args); + appendStringInfoString(str, ") "); + + if (range_table_sample->repeatable != NULL) + { + appendStringInfoString(str, "REPEATABLE ("); + deparseExpr(str, range_table_sample->repeatable); + appendStringInfoString(str, ") "); + } + + removeTrailingSpace(str); +} + +static void deparseCreateSubscriptionStmt(StringInfo str, CreateSubscriptionStmt *create_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "CREATE SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(create_subscription_stmt->subname)); + + appendStringInfoString(str, " CONNECTION "); + if (create_subscription_stmt->conninfo != NULL) + deparseStringLiteral(str, create_subscription_stmt->conninfo); + else + appendStringInfoString(str, "''"); + + appendStringInfoString(str, " PUBLICATION "); + + foreach(lc, create_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(create_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + + deparseOptDefinition(str, create_subscription_stmt->options); + removeTrailingSpace(str); +} + +static void deparseAlterSubscriptionStmt(StringInfo str, AlterSubscriptionStmt *alter_subscription_stmt) +{ + ListCell *lc; + + appendStringInfoString(str, "ALTER SUBSCRIPTION "); + appendStringInfoString(str, quote_identifier(alter_subscription_stmt->subname)); + appendStringInfoChar(str, ' '); + + switch (alter_subscription_stmt->kind) + { + case ALTER_SUBSCRIPTION_OPTIONS: + appendStringInfoString(str, "SET "); + deparseDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_SKIP: + appendStringInfoString(str, "SKIP "); + deparseDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_CONNECTION: + appendStringInfoString(str, "CONNECTION "); + deparseStringLiteral(str, alter_subscription_stmt->conninfo); + appendStringInfoChar(str, ' '); + break; + case ALTER_SUBSCRIPTION_REFRESH: + appendStringInfoString(str, "REFRESH PUBLICATION "); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ADD_PUBLICATION: + appendStringInfoString(str, "ADD PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_DROP_PUBLICATION: + appendStringInfoString(str, "DROP PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_SET_PUBLICATION: + appendStringInfoString(str, "SET PUBLICATION "); + foreach(lc, alter_subscription_stmt->publication) + { + deparseColLabel(str, strVal(lfirst(lc))); + if (lnext(alter_subscription_stmt->publication, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ' '); + deparseOptDefinition(str, alter_subscription_stmt->options); + break; + case ALTER_SUBSCRIPTION_ENABLED: + Assert(list_length(alter_subscription_stmt->options) == 1); + DefElem *defelem = castNode(DefElem, linitial(alter_subscription_stmt->options)); + Assert(strcmp(defelem->defname, "enabled") == 0); + if (optBooleanValue(defelem->arg)) + { + appendStringInfoString(str, " ENABLE "); + } + else + { + appendStringInfoString(str, " DISABLE "); + } + break; + } + + removeTrailingSpace(str); +} + +static void deparseDropSubscriptionStmt(StringInfo str, DropSubscriptionStmt *drop_subscription_stmt) +{ + appendStringInfoString(str, "DROP SUBSCRIPTION "); + + if (drop_subscription_stmt->missing_ok) + appendStringInfoString(str, "IF EXISTS "); + + appendStringInfoString(str, drop_subscription_stmt->subname); +} + +static void deparseCallStmt(StringInfo str, CallStmt *call_stmt) +{ + appendStringInfoString(str, "CALL "); + deparseFuncCall(str, call_stmt->funccall); +} + +static void deparseAlterOwnerStmt(StringInfo str, AlterOwnerStmt *alter_owner_stmt) +{ + List *l = NULL; + + appendStringInfoString(str, "ALTER "); + + switch (alter_owner_stmt->objectType) + { + case OBJECT_AGGREGATE: + appendStringInfoString(str, "AGGREGATE "); + deparseAggregateWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_COLLATION: + appendStringInfoString(str, "COLLATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_CONVERSION: + appendStringInfoString(str, "CONVERSION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_DATABASE: + appendStringInfoString(str, "DATABASE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_DOMAIN: + appendStringInfoString(str, "DOMAIN "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FUNCTION: + appendStringInfoString(str, "FUNCTION "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_LANGUAGE: + appendStringInfoString(str, "LANGUAGE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_LARGEOBJECT: + appendStringInfoString(str, "LARGE OBJECT "); + deparseNumericOnly(str, (union ValUnion *) alter_owner_stmt->object); + break; + case OBJECT_OPERATOR: + appendStringInfoString(str, "OPERATOR "); + deparseOperatorWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_OPCLASS: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR CLASS "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_OPFAMILY: + l = castNode(List, alter_owner_stmt->object); + appendStringInfoString(str, "OPERATOR FAMILY "); + deparseAnyNameSkipFirst(str, l); + appendStringInfoString(str, " USING "); + deparseColId(str, strVal(linitial(l))); + break; + case OBJECT_PROCEDURE: + appendStringInfoString(str, "PROCEDURE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_ROUTINE: + appendStringInfoString(str, "ROUTINE "); + deparseFunctionWithArgtypes(str, castNode(ObjectWithArgs, alter_owner_stmt->object)); + break; + case OBJECT_SCHEMA: + appendStringInfoString(str, "SCHEMA "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_TYPE: + appendStringInfoString(str, "TYPE "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TABLESPACE: + appendStringInfoString(str, "TABLESPACE "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_STATISTIC_EXT: + appendStringInfoString(str, "STATISTICS "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSDICTIONARY: + appendStringInfoString(str, "TEXT SEARCH DICTIONARY "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_TSCONFIGURATION: + appendStringInfoString(str, "TEXT SEARCH CONFIGURATION "); + deparseAnyName(str, castNode(List, alter_owner_stmt->object)); + break; + case OBJECT_FDW: + appendStringInfoString(str, "FOREIGN DATA WRAPPER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_FOREIGN_SERVER: + appendStringInfoString(str, "SERVER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_EVENT_TRIGGER: + appendStringInfoString(str, "EVENT TRIGGER "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_PUBLICATION: + appendStringInfoString(str, "PUBLICATION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + case OBJECT_SUBSCRIPTION: + appendStringInfoString(str, "SUBSCRIPTION "); + deparseColId(str, strVal(alter_owner_stmt->object)); + break; + default: + Assert(false); + } + + appendStringInfoString(str, " OWNER TO "); + deparseRoleSpec(str, alter_owner_stmt->newowner); +} + +// "operator_def_list" in gram.y +static void deparseOperatorDefList(StringInfo str, List *defs) +{ + ListCell *lc = NULL; + + foreach (lc, defs) + { + DefElem *def_elem = castNode(DefElem, lfirst(lc)); + appendStringInfoString(str, quote_identifier(def_elem->defname)); + appendStringInfoString(str, " = "); + if (def_elem->arg != NULL) + deparseDefArg(str, def_elem->arg, true); + else + appendStringInfoString(str, "NONE"); + + if (lnext(defs, lc)) + appendStringInfoString(str, ", "); + } +} + +static void deparseAlterOperatorStmt(StringInfo str, AlterOperatorStmt *alter_operator_stmt) +{ + appendStringInfoString(str, "ALTER OPERATOR "); + deparseOperatorWithArgtypes(str, alter_operator_stmt->opername); + appendStringInfoString(str, " SET ("); + deparseOperatorDefList(str, alter_operator_stmt->options); + appendStringInfoChar(str, ')'); +} + +static void deparseAlterTypeStmt(StringInfo str, AlterTypeStmt *alter_type_stmt) +{ + appendStringInfoString(str, "ALTER TYPE "); + deparseAnyName(str, alter_type_stmt->typeName); + appendStringInfoString(str, " SET ("); + deparseOperatorDefList(str, alter_type_stmt->options); + appendStringInfoChar(str, ')'); +} + +static void deparseDropOwnedStmt(StringInfo str, DropOwnedStmt *drop_owned_stmt) +{ + appendStringInfoString(str, "DROP OWNED BY "); + deparseRoleList(str, drop_owned_stmt->roles); + appendStringInfoChar(str, ' '); + deparseOptDropBehavior(str, drop_owned_stmt->behavior); + removeTrailingSpace(str); +} + +static void deparseReassignOwnedStmt(StringInfo str, ReassignOwnedStmt *reassigned_owned_stmt) +{ + appendStringInfoString(str, "REASSIGN OWNED BY "); + + deparseRoleList(str, reassigned_owned_stmt->roles); + appendStringInfoChar(str, ' '); + + appendStringInfoString(str, "TO "); + deparseRoleSpec(str, reassigned_owned_stmt->newrole); +} + +static void deparseClosePortalStmt(StringInfo str, ClosePortalStmt *close_portal_stmt) +{ + appendStringInfoString(str, "CLOSE "); + if (close_portal_stmt->portalname != NULL) + { + appendStringInfoString(str, quote_identifier(close_portal_stmt->portalname)); + } + else + { + appendStringInfoString(str, "ALL"); + } +} + +static void deparseCurrentOfExpr(StringInfo str, CurrentOfExpr *current_of_expr) +{ + appendStringInfoString(str, "CURRENT OF "); + appendStringInfoString(str, quote_identifier(current_of_expr->cursor_name)); +} + +static void deparseCreateTrigStmt(StringInfo str, CreateTrigStmt *create_trig_stmt) +{ + ListCell *lc; + bool skip_events_or = true; + + appendStringInfoString(str, "CREATE "); + if (create_trig_stmt->replace) + appendStringInfoString(str, "OR REPLACE "); + if (create_trig_stmt->isconstraint) + appendStringInfoString(str, "CONSTRAINT "); + appendStringInfoString(str, "TRIGGER "); + + appendStringInfoString(str, quote_identifier(create_trig_stmt->trigname)); + appendStringInfoChar(str, ' '); + + switch (create_trig_stmt->timing) + { + case TRIGGER_TYPE_BEFORE: + appendStringInfoString(str, "BEFORE "); + break; + case TRIGGER_TYPE_AFTER: + appendStringInfoString(str, "AFTER "); + break; + case TRIGGER_TYPE_INSTEAD: + appendStringInfoString(str, "INSTEAD OF "); + break; + default: + Assert(false); + } + + if (TRIGGER_FOR_INSERT(create_trig_stmt->events)) + { + appendStringInfoString(str, "INSERT "); + skip_events_or = false; + } + if (TRIGGER_FOR_DELETE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "DELETE "); + skip_events_or = false; + } + if (TRIGGER_FOR_UPDATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "UPDATE "); + if (list_length(create_trig_stmt->columns) > 0) + { + appendStringInfoString(str, "OF "); + deparseColumnList(str, create_trig_stmt->columns); + appendStringInfoChar(str, ' '); + } + skip_events_or = false; + } + if (TRIGGER_FOR_TRUNCATE(create_trig_stmt->events)) + { + if (!skip_events_or) + appendStringInfoString(str, "OR "); + appendStringInfoString(str, "TRUNCATE "); + } + + appendStringInfoString(str, "ON "); + deparseRangeVar(str, create_trig_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + + if (create_trig_stmt->transitionRels != NULL) + { + appendStringInfoString(str, "REFERENCING "); + foreach(lc, create_trig_stmt->transitionRels) + { + deparseTriggerTransition(str, castNode(TriggerTransition, lfirst(lc))); + appendStringInfoChar(str, ' '); + } + } + + if (create_trig_stmt->constrrel != NULL) + { + appendStringInfoString(str, "FROM "); + deparseRangeVar(str, create_trig_stmt->constrrel, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (create_trig_stmt->deferrable) + appendStringInfoString(str, "DEFERRABLE "); + + if (create_trig_stmt->initdeferred) + appendStringInfoString(str, "INITIALLY DEFERRED "); + + if (create_trig_stmt->row) + appendStringInfoString(str, "FOR EACH ROW "); + + if (create_trig_stmt->whenClause) + { + appendStringInfoString(str, "WHEN ("); + deparseExpr(str, create_trig_stmt->whenClause); + appendStringInfoString(str, ") "); + } + + appendStringInfoString(str, "EXECUTE FUNCTION "); + deparseFuncName(str, create_trig_stmt->funcname); + appendStringInfoChar(str, '('); + foreach(lc, create_trig_stmt->args) + { + deparseStringLiteral(str, strVal(lfirst(lc))); + if (lnext(create_trig_stmt->args, lc)) + appendStringInfoString(str, ", "); + } + appendStringInfoChar(str, ')'); +} + +static void deparseTriggerTransition(StringInfo str, TriggerTransition *trigger_transition) +{ + if (trigger_transition->isNew) + appendStringInfoString(str, "NEW "); + else + appendStringInfoString(str, "OLD "); + + if (trigger_transition->isTable) + appendStringInfoString(str, "TABLE "); + else + appendStringInfoString(str, "ROW "); + + appendStringInfoString(str, quote_identifier(trigger_transition->name)); +} + +static void deparseXmlExpr(StringInfo str, XmlExpr* xml_expr) +{ + switch (xml_expr->op) + { + case IS_XMLCONCAT: /* XMLCONCAT(args) */ + appendStringInfoString(str, "xmlconcat("); + deparseExprList(str, xml_expr->args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLELEMENT: /* XMLELEMENT(name, xml_attributes, args) */ + appendStringInfoString(str, "xmlelement(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->named_args != NULL) + { + appendStringInfoString(str, ", xmlattributes("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoString(str, ")"); + } + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExprList(str, xml_expr->args); + } + appendStringInfoString(str, ")"); + break; + case IS_XMLFOREST: /* XMLFOREST(xml_attributes) */ + appendStringInfoString(str, "xmlforest("); + deparseXmlAttributeList(str, xml_expr->named_args); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPARSE: /* XMLPARSE(text, is_doc, preserve_ws) */ + Assert(list_length(xml_expr->args) == 2); + appendStringInfoString(str, "xmlparse("); + switch (xml_expr->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoChar(str, ')'); + break; + case IS_XMLPI: /* XMLPI(name [, args]) */ + appendStringInfoString(str, "xmlpi(name "); + appendStringInfoString(str, quote_identifier(xml_expr->name)); + if (xml_expr->args != NULL) + { + appendStringInfoString(str, ", "); + deparseExpr(str, linitial(xml_expr->args)); + } + appendStringInfoChar(str, ')'); + break; + case IS_XMLROOT: /* XMLROOT(xml, version, standalone) */ + appendStringInfoString(str, "xmlroot("); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, ", version "); + if (castNode(A_Const, lsecond(xml_expr->args))->isnull) + appendStringInfoString(str, "NO VALUE"); + else + deparseExpr(str, lsecond(xml_expr->args)); + if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_YES) + appendStringInfoString(str, ", STANDALONE YES"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO) + appendStringInfoString(str, ", STANDALONE NO"); + else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO_VALUE) + appendStringInfoString(str, ", STANDALONE NO VALUE"); + appendStringInfoChar(str, ')'); + break; + case IS_XMLSERIALIZE: /* XMLSERIALIZE(is_document, xmlval) */ + // These are represented as XmlSerialize in raw parse trees + Assert(false); + break; + case IS_DOCUMENT: /* xmlval IS DOCUMENT */ + Assert(list_length(xml_expr->args) == 1); + deparseExpr(str, linitial(xml_expr->args)); + appendStringInfoString(str, " IS DOCUMENT"); + break; + } +} + +static void deparseRangeTableFuncCol(StringInfo str, RangeTableFuncCol* range_table_func_col) +{ + appendStringInfoString(str, quote_identifier(range_table_func_col->colname)); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->for_ordinality) + { + appendStringInfoString(str, "FOR ORDINALITY "); + } + else + { + deparseTypeName(str, range_table_func_col->typeName); + appendStringInfoChar(str, ' '); + + if (range_table_func_col->colexpr) + { + appendStringInfoString(str, "PATH "); + deparseExpr(str, range_table_func_col->colexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->coldefexpr) + { + appendStringInfoString(str, "DEFAULT "); + deparseExpr(str, range_table_func_col->coldefexpr); + appendStringInfoChar(str, ' '); + } + + if (range_table_func_col->is_not_null) + appendStringInfoString(str, "NOT NULL "); + } + + removeTrailingSpace(str); +} + +static void deparseRangeTableFunc(StringInfo str, RangeTableFunc* range_table_func) +{ + ListCell *lc; + + if (range_table_func->lateral) + appendStringInfoString(str, "LATERAL "); + + appendStringInfoString(str, "xmltable("); + if (range_table_func->namespaces) + { + appendStringInfoString(str, "xmlnamespaces("); + deparseXmlNamespaceList(str, range_table_func->namespaces); + appendStringInfoString(str, "), "); + } + + appendStringInfoChar(str, '('); + deparseExpr(str, range_table_func->rowexpr); + appendStringInfoChar(str, ')'); + + appendStringInfoString(str, " PASSING "); + deparseExpr(str, range_table_func->docexpr); + + appendStringInfoString(str, " COLUMNS "); + foreach(lc, range_table_func->columns) + { + deparseRangeTableFuncCol(str, castNode(RangeTableFuncCol, lfirst(lc))); + if (lnext(range_table_func->columns, lc)) + appendStringInfoString(str, ", "); + } + + appendStringInfoString(str, ") "); + + if (range_table_func->alias) + { + appendStringInfoString(str, "AS "); + deparseAlias(str, range_table_func->alias); + } + + removeTrailingSpace(str); +} + +static void deparseXmlSerialize(StringInfo str, XmlSerialize *xml_serialize) +{ + appendStringInfoString(str, "xmlserialize("); + switch (xml_serialize->xmloption) + { + case XMLOPTION_DOCUMENT: + appendStringInfoString(str, "document "); + break; + case XMLOPTION_CONTENT: + appendStringInfoString(str, "content "); + break; + default: + Assert(false); + } + deparseExpr(str, xml_serialize->expr); + appendStringInfoString(str, " AS "); + deparseTypeName(str, xml_serialize->typeName); + appendStringInfoString(str, ")"); +} + +static void deparseGroupingFunc(StringInfo str, GroupingFunc *grouping_func) +{ + appendStringInfoString(str, "GROUPING("); + deparseExprList(str, grouping_func->args); + appendStringInfoChar(str, ')'); +} + +static void deparseClusterStmt(StringInfo str, ClusterStmt *cluster_stmt) +{ + appendStringInfoString(str, "CLUSTER "); + + deparseUtilityOptionList(str, cluster_stmt->params); + + if (cluster_stmt->relation != NULL) + { + deparseRangeVar(str, cluster_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); + appendStringInfoChar(str, ' '); + } + + if (cluster_stmt->indexname != NULL) + { + appendStringInfoString(str, "USING "); + appendStringInfoString(str, quote_identifier(cluster_stmt->indexname)); + appendStringInfoChar(str, ' '); + } + + removeTrailingSpace(str); +} + +static void deparseValue(StringInfo str, union ValUnion *value, DeparseNodeContext context) +{ + if (!value) { + appendStringInfoString(str, "NULL"); + return; + } + + switch (nodeTag(value)) + { + case T_Integer: + case T_Float: + deparseNumericOnly(str, value); + break; + case T_Boolean: + appendStringInfoString(str, value->boolval.boolval ? "true" : "false"); + break; + case T_String: + if (context == DEPARSE_NODE_CONTEXT_IDENTIFIER) { + appendStringInfoString(str, quote_identifier(value->sval.sval)); + } else if (context == DEPARSE_NODE_CONTEXT_CONSTANT) { + deparseStringLiteral(str, value->sval.sval); + } else { + appendStringInfoString(str, value->sval.sval); + } + break; + case T_BitString: + if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'x') + { + appendStringInfoChar(str, 'x'); + deparseStringLiteral(str, value->sval.sval + 1); + } + else if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'b') + { + appendStringInfoChar(str, 'b'); + deparseStringLiteral(str, value->sval.sval + 1); + } + else + { + Assert(false); + } + break; + default: + elog(ERROR, "deparse: unrecognized value node type: %d", + (int) nodeTag(value)); + break; + } +} + +// "PrepareableStmt" in gram.y +static void deparsePreparableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(str, castNode(MergeStmt, node)); + break; + default: + Assert(false); + } +} + +// "RuleActionStmt" in gram.y +static void deparseRuleActionStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + default: + Assert(false); + } +} + +// "ExplainableStmt" in gram.y +static void deparseExplainableStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_CreateTableAsStmt: + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(str, castNode(MergeStmt, node)); + break; + default: + Assert(false); + } +} + +// "schema_stmt" in gram.y +static void deparseSchemaStmt(StringInfo str, Node *node) +{ + switch (nodeTag(node)) + { + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + default: + Assert(false); + } +} + +// "stmt" in gram.y +static void deparseStmt(StringInfo str, Node *node) +{ + // Note the following grammar names are missing in the list, because they + // get mapped to other node types: + // + // - AlterForeignTableStmt (=> AlterTableStmt) + // - AlterGroupStmt (=> AlterRoleStmt) + // - AlterCompositeTypeStmt (=> AlterTableStmt) + // - AnalyzeStmt (=> VacuumStmt) + // - CreateGroupStmt (=> CreateRoleStmt) + // - CreateMatViewStmt (=> CreateTableAsStmt) + // - CreateUserStmt (=> CreateRoleStmt) + // - DropCastStmt (=> DropStmt) + // - DropOpClassStmt (=> DropStmt) + // - DropOpFamilyStmt (=> DropStmt) + // - DropPLangStmt (=> DropPLangStmt) + // - DropTransformStmt (=> DropStmt) + // - RemoveAggrStmt (=> DropStmt) + // - RemoveFuncStmt (=> DropStmt) + // - RemoveOperStmt (=> DropStmt) + // - RevokeStmt (=> GrantStmt) + // - RevokeRoleStmt (=> GrantRoleStmt) + // - VariableResetStmt (=> VariableSetStmt) + // + // And the following grammar names error out in the parser: + // - CreateAssertionStmt (not supported yet) + switch (nodeTag(node)) + { + case T_AlterEventTrigStmt: + deparseAlterEventTrigStmt(str, castNode(AlterEventTrigStmt, node)); + break; + case T_AlterCollationStmt: + deparseAlterCollationStmt(str, castNode(AlterCollationStmt, node)); + break; + case T_AlterDatabaseStmt: + deparseAlterDatabaseStmt(str, castNode(AlterDatabaseStmt, node)); + break; + case T_AlterDatabaseSetStmt: + deparseAlterDatabaseSetStmt(str, castNode(AlterDatabaseSetStmt, node)); + break; + case T_AlterDefaultPrivilegesStmt: + deparseAlterDefaultPrivilegesStmt(str, castNode(AlterDefaultPrivilegesStmt, node)); + break; + case T_AlterDomainStmt: + deparseAlterDomainStmt(str, castNode(AlterDomainStmt, node)); + break; + case T_AlterEnumStmt: + deparseAlterEnumStmt(str, castNode(AlterEnumStmt, node)); + break; + case T_AlterExtensionStmt: + deparseAlterExtensionStmt(str, castNode(AlterExtensionStmt, node)); + break; + case T_AlterExtensionContentsStmt: + deparseAlterExtensionContentsStmt(str, castNode(AlterExtensionContentsStmt, node)); + break; + case T_AlterFdwStmt: + deparseAlterFdwStmt(str, castNode(AlterFdwStmt, node)); + break; + case T_AlterForeignServerStmt: + deparseAlterForeignServerStmt(str, castNode(AlterForeignServerStmt, node)); + break; + case T_AlterFunctionStmt: + deparseAlterFunctionStmt(str, castNode(AlterFunctionStmt, node)); + break; + case T_AlterObjectDependsStmt: + deparseAlterObjectDependsStmt(str, castNode(AlterObjectDependsStmt, node)); + break; + case T_AlterObjectSchemaStmt: + deparseAlterObjectSchemaStmt(str, castNode(AlterObjectSchemaStmt, node)); + break; + case T_AlterOwnerStmt: + deparseAlterOwnerStmt(str, castNode(AlterOwnerStmt, node)); + break; + case T_AlterOperatorStmt: + deparseAlterOperatorStmt(str, castNode(AlterOperatorStmt, node)); + break; + case T_AlterTypeStmt: + deparseAlterTypeStmt(str, castNode(AlterTypeStmt, node)); + break; + case T_AlterPolicyStmt: + deparseAlterPolicyStmt(str, castNode(AlterPolicyStmt, node)); + break; + case T_AlterSeqStmt: + deparseAlterSeqStmt(str, castNode(AlterSeqStmt, node)); + break; + case T_AlterSystemStmt: + deparseAlterSystemStmt(str, castNode(AlterSystemStmt, node)); + break; + case T_AlterTableMoveAllStmt: + deparseAlterTableMoveAllStmt(str, castNode(AlterTableMoveAllStmt, node)); + break; + case T_AlterTableStmt: + deparseAlterTableStmt(str, castNode(AlterTableStmt, node)); + break; + case T_AlterTableSpaceOptionsStmt: // "AlterTblSpcStmt" in gram.y + deparseAlterTableSpaceOptionsStmt(str, castNode(AlterTableSpaceOptionsStmt, node)); + break; + case T_AlterPublicationStmt: + deparseAlterPublicationStmt(str, castNode(AlterPublicationStmt, node)); + break; + case T_AlterRoleSetStmt: + deparseAlterRoleSetStmt(str, castNode(AlterRoleSetStmt, node)); + break; + case T_AlterRoleStmt: + deparseAlterRoleStmt(str, castNode(AlterRoleStmt, node)); + break; + case T_AlterSubscriptionStmt: + deparseAlterSubscriptionStmt(str, castNode(AlterSubscriptionStmt, node)); + break; + case T_AlterStatsStmt: + deparseAlterStatsStmt(str, castNode(AlterStatsStmt, node)); + break; + case T_AlterTSConfigurationStmt: + deparseAlterTSConfigurationStmt(str, castNode(AlterTSConfigurationStmt, node)); + break; + case T_AlterTSDictionaryStmt: + deparseAlterTSDictionaryStmt(str, castNode(AlterTSDictionaryStmt, node)); + break; + case T_AlterUserMappingStmt: + deparseAlterUserMappingStmt(str, castNode(AlterUserMappingStmt, node)); + break; + case T_CallStmt: + deparseCallStmt(str, castNode(CallStmt, node)); + break; + case T_CheckPointStmt: + deparseCheckPointStmt(str, castNode(CheckPointStmt, node)); + break; + case T_ClosePortalStmt: + deparseClosePortalStmt(str, castNode(ClosePortalStmt, node)); + break; + case T_ClusterStmt: + deparseClusterStmt(str, castNode(ClusterStmt, node)); + break; + case T_CommentStmt: + deparseCommentStmt(str, castNode(CommentStmt, node)); + break; + case T_ConstraintsSetStmt: + deparseConstraintsSetStmt(str, castNode(ConstraintsSetStmt, node)); + break; + case T_CopyStmt: + deparseCopyStmt(str, castNode(CopyStmt, node)); + break; + case T_CreateAmStmt: + deparseCreateAmStmt(str, castNode(CreateAmStmt, node)); + break; + case T_CreateTableAsStmt: // "CreateAsStmt" in gram.y + deparseCreateTableAsStmt(str, castNode(CreateTableAsStmt, node)); + break; + case T_CreateCastStmt: + deparseCreateCastStmt(str, castNode(CreateCastStmt, node)); + break; + case T_CreateConversionStmt: + deparseCreateConversionStmt(str, castNode(CreateConversionStmt, node)); + break; + case T_CreateDomainStmt: + deparseCreateDomainStmt(str, castNode(CreateDomainStmt, node)); + break; + case T_CreateExtensionStmt: + deparseCreateExtensionStmt(str, castNode(CreateExtensionStmt, node)); + break; + case T_CreateFdwStmt: + deparseCreateFdwStmt(str, castNode(CreateFdwStmt, node)); + break; + case T_CreateForeignServerStmt: + deparseCreateForeignServerStmt(str, castNode(CreateForeignServerStmt, node)); + break; + case T_CreateForeignTableStmt: + deparseCreateForeignTableStmt(str, castNode(CreateForeignTableStmt, node)); + break; + case T_CreateFunctionStmt: + deparseCreateFunctionStmt(str, castNode(CreateFunctionStmt, node)); + break; + case T_CreateOpClassStmt: + deparseCreateOpClassStmt(str, castNode(CreateOpClassStmt, node)); + break; + case T_CreateOpFamilyStmt: + deparseCreateOpFamilyStmt(str, castNode(CreateOpFamilyStmt, node)); + break; + case T_CreatePublicationStmt: + deparseCreatePublicationStmt(str, castNode(CreatePublicationStmt, node)); + break; + case T_AlterOpFamilyStmt: + deparseAlterOpFamilyStmt(str, castNode(AlterOpFamilyStmt, node)); + break; + case T_CreatePolicyStmt: + deparseCreatePolicyStmt(str, castNode(CreatePolicyStmt, node)); + break; + case T_CreatePLangStmt: + deparseCreatePLangStmt(str, castNode(CreatePLangStmt, node)); + break; + case T_CreateSchemaStmt: + deparseCreateSchemaStmt(str, castNode(CreateSchemaStmt, node)); + break; + case T_CreateSeqStmt: + deparseCreateSeqStmt(str, castNode(CreateSeqStmt, node)); + break; + case T_CreateStmt: + deparseCreateStmt(str, castNode(CreateStmt, node), false); + break; + case T_CreateSubscriptionStmt: + deparseCreateSubscriptionStmt(str, castNode(CreateSubscriptionStmt, node)); + break; + case T_CreateStatsStmt: + deparseCreateStatsStmt(str, castNode(CreateStatsStmt, node)); + break; + case T_CreateTableSpaceStmt: + deparseCreateTableSpaceStmt(str, castNode(CreateTableSpaceStmt, node)); + break; + case T_CreateTransformStmt: + deparseCreateTransformStmt(str, castNode(CreateTransformStmt, node)); + break; + case T_CreateTrigStmt: + deparseCreateTrigStmt(str, castNode(CreateTrigStmt, node)); + break; + case T_CreateEventTrigStmt: + deparseCreateEventTrigStmt(str, castNode(CreateEventTrigStmt, node)); + break; + case T_CreateRoleStmt: + deparseCreateRoleStmt(str, castNode(CreateRoleStmt, node)); + break; + case T_CreateUserMappingStmt: + deparseCreateUserMappingStmt(str, castNode(CreateUserMappingStmt, node)); + break; + case T_CreatedbStmt: + deparseCreatedbStmt(str, castNode(CreatedbStmt, node)); + break; + case T_DeallocateStmt: + deparseDeallocateStmt(str, castNode(DeallocateStmt, node)); + break; + case T_DeclareCursorStmt: + deparseDeclareCursorStmt(str, castNode(DeclareCursorStmt, node)); + break; + case T_DefineStmt: + deparseDefineStmt(str, castNode(DefineStmt, node)); + break; + case T_DeleteStmt: + deparseDeleteStmt(str, castNode(DeleteStmt, node)); + break; + case T_DiscardStmt: + deparseDiscardStmt(str, castNode(DiscardStmt, node)); + break; + case T_DoStmt: + deparseDoStmt(str, castNode(DoStmt, node)); + break; + case T_DropOwnedStmt: + deparseDropOwnedStmt(str, castNode(DropOwnedStmt, node)); + break; + case T_DropStmt: + deparseDropStmt(str, castNode(DropStmt, node)); + break; + case T_DropSubscriptionStmt: + deparseDropSubscriptionStmt(str, castNode(DropSubscriptionStmt, node)); + break; + case T_DropTableSpaceStmt: + deparseDropTableSpaceStmt(str, castNode(DropTableSpaceStmt, node)); + break; + case T_DropRoleStmt: + deparseDropRoleStmt(str, castNode(DropRoleStmt, node)); + break; + case T_DropUserMappingStmt: + deparseDropUserMappingStmt(str, castNode(DropUserMappingStmt, node)); + break; + case T_DropdbStmt: + deparseDropdbStmt(str, castNode(DropdbStmt, node)); + break; + case T_ExecuteStmt: + deparseExecuteStmt(str, castNode(ExecuteStmt, node)); + break; + case T_ExplainStmt: + deparseExplainStmt(str, castNode(ExplainStmt, node)); + break; + case T_FetchStmt: + deparseFetchStmt(str, castNode(FetchStmt, node)); + break; + case T_GrantStmt: + deparseGrantStmt(str, castNode(GrantStmt, node)); + break; + case T_GrantRoleStmt: + deparseGrantRoleStmt(str, castNode(GrantRoleStmt, node)); + break; + case T_ImportForeignSchemaStmt: + deparseImportForeignSchemaStmt(str, castNode(ImportForeignSchemaStmt, node)); + break; + case T_IndexStmt: + deparseIndexStmt(str, castNode(IndexStmt, node)); + break; + case T_InsertStmt: + deparseInsertStmt(str, castNode(InsertStmt, node)); + break; + case T_ListenStmt: + deparseListenStmt(str, castNode(ListenStmt, node)); + break; + case T_RefreshMatViewStmt: + deparseRefreshMatViewStmt(str, castNode(RefreshMatViewStmt, node)); + break; + case T_LoadStmt: + deparseLoadStmt(str, castNode(LoadStmt, node)); + break; + case T_LockStmt: + deparseLockStmt(str, castNode(LockStmt, node)); + break; + case T_MergeStmt: + deparseMergeStmt(str, castNode(MergeStmt, node)); + break; + case T_NotifyStmt: + deparseNotifyStmt(str, castNode(NotifyStmt, node)); + break; + case T_PrepareStmt: + deparsePrepareStmt(str, castNode(PrepareStmt, node)); + break; + case T_ReassignOwnedStmt: + deparseReassignOwnedStmt(str, castNode(ReassignOwnedStmt, node)); + break; + case T_ReindexStmt: + deparseReindexStmt(str, castNode(ReindexStmt, node)); + break; + case T_RenameStmt: + deparseRenameStmt(str, castNode(RenameStmt, node)); + break; + case T_RuleStmt: + deparseRuleStmt(str, castNode(RuleStmt, node)); + break; + case T_SecLabelStmt: + deparseSecLabelStmt(str, castNode(SecLabelStmt, node)); + break; + case T_SelectStmt: + deparseSelectStmt(str, castNode(SelectStmt, node)); + break; + case T_TransactionStmt: + deparseTransactionStmt(str, castNode(TransactionStmt, node)); + break; + case T_TruncateStmt: + deparseTruncateStmt(str, castNode(TruncateStmt, node)); + break; + case T_UnlistenStmt: + deparseUnlistenStmt(str, castNode(UnlistenStmt, node)); + break; + case T_UpdateStmt: + deparseUpdateStmt(str, castNode(UpdateStmt, node)); + break; + case T_VacuumStmt: + deparseVacuumStmt(str, castNode(VacuumStmt, node)); + break; + case T_VariableSetStmt: + deparseVariableSetStmt(str, castNode(VariableSetStmt, node)); + break; + case T_VariableShowStmt: + deparseVariableShowStmt(str, castNode(VariableShowStmt, node)); + break; + case T_ViewStmt: + deparseViewStmt(str, castNode(ViewStmt, node)); + break; + // These node types are created by DefineStmt grammar for CREATE TYPE in some cases + case T_CompositeTypeStmt: + deparseCompositeTypeStmt(str, castNode(CompositeTypeStmt, node)); + break; + case T_CreateEnumStmt: + deparseCreateEnumStmt(str, castNode(CreateEnumStmt, node)); + break; + case T_CreateRangeStmt: + deparseCreateRangeStmt(str, castNode(CreateRangeStmt, node)); + break; + default: + elog(ERROR, "deparse: unsupported top-level node type: %u", nodeTag(node)); + } +} diff --git a/ext/pg_query/postgres_deparse.h b/ext/pg_query/postgres_deparse.h new file mode 100644 index 0000000..76a6e70 --- /dev/null +++ b/ext/pg_query/postgres_deparse.h @@ -0,0 +1,9 @@ +#ifndef POSTGRES_DEPARSE_H +#define POSTGRES_DEPARSE_H + +#include "lib/stringinfo.h" +#include "nodes/parsenodes.h" + +extern void deparseRawStmt(StringInfo str, RawStmt *raw_stmt); + +#endif diff --git a/spec/lib/pg_query/deparse_bad_tree_spec.rb b/spec/lib/pg_query/deparse_bad_tree_spec.rb index c0cead0..d502473 100644 --- a/spec/lib/pg_query/deparse_bad_tree_spec.rb +++ b/spec/lib/pg_query/deparse_bad_tree_spec.rb @@ -25,7 +25,7 @@ expect { PgQuery.deparse(tree) }.to raise_error do |error| expect(error).to be_a(described_class::ParseError) - expect(error.message).to eq "deparse: error in deparseTargetList: ResTarget without val (pg_query_deparse.c:1491)" + expect(error.message).to eq "deparse: error in deparseTargetList: ResTarget without val (postgres_deparse.c:1489)" end end end From 47678bb857a747f5d6c02bffe709c221e77cbf8a Mon Sep 17 00:00:00 2001 From: Lukas Fittl Date: Fri, 7 Jul 2023 19:51:57 -0700 Subject: [PATCH 3/3] Release 4.2.2 --- CHANGELOG.md | 10 ++++++++++ Gemfile.lock | 2 +- lib/pg_query/version.rb | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64a2a81..b24d065 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ * ... +## 4.2.2 2023-07-07 + +* Update to libpg_query 15-4.2.2 + - Deparser: Add support for multi-statement CREATE PROCEDURE definitions + - Deparser: Correctly quote identifier in ALTER TABLE ... ADD CONSTRAINT [x] + - Deparser: Add support for index fillfactor within CREATE TABLE, fix SHOW ALL +* Fix builds on FreeBSD ([#292](https://github.com/pganalyze/pg_query/pull/292)) + - This was broken since 4.2.0, due to pg_query_ruby_freebsd.sym being removed by accident + + ## 4.2.1 2023-05-19 * Parse: Fix `ALTER INDEX my_index_name` to return `tables=[]` ([#285](https://github.com/pganalyze/pg_query/pull/285)) diff --git a/Gemfile.lock b/Gemfile.lock index 8b3032c..97a8659 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - pg_query (4.2.1) + pg_query (4.2.2) google-protobuf (>= 3.22.3) GEM diff --git a/lib/pg_query/version.rb b/lib/pg_query/version.rb index 5135d3e..862d06b 100644 --- a/lib/pg_query/version.rb +++ b/lib/pg_query/version.rb @@ -1,3 +1,3 @@ module PgQuery - VERSION = '4.2.1'.freeze + VERSION = '4.2.2'.freeze end