#include "postgres_deparse.h" #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" /* * # Deparser overview * * The deparser works by walking the input parse tree and emitting into the * currently active "part" as pointed to (indirectly) by the state struct. * * A lot of the structure of the deparser described below is meant to support * the optional "pretty print" mode that can be enabled and configured through * the deparser options, and inserts whitespace (newlines/spaces) as needed to * make the output easier to read. * * ## Nesting levels * * Starting at the state struct we have a currently active "nesting level", * which indicates the base indentation, as well as contains one or more part * groups, each of which has one or more parts. * * Nesting levels are typically opened, or "increased", when processing a new * statement contained within other statements, or for certain statement-like * constructs (e.g. CASE clauses) that require custom indendation. * * Nesting levels are closed, or "decreased", when exiting such statements or * statement-like constructs. During this operation all parts and subparts get * flattened (turned into a simple list of parts), and are added to the parent * nesting level. * * At the end of the tree walk the parts of the top most nesting level get * emitted into the output string, formatted based on the deparse options. * * ## Part groups * * Part groups are usually started for each "major" keyword, which is chosen * for how the output is intended to be laid out. For example, the "FROM" * keyword in a SELECT statement is considered "major" and starts a new part * group, vs the "JOIN" keyword is not, and as such both regular tables and * JOIN clauses will be within one part group. * * ## Parts, indentation and merging * * The parts contained in part groups may be indented one additional level * beyond the base indentation of the currently active nesting level, to help * differentiate them from the major keywords. This can be turned off with * DEPARSE_PART_NO_INDENT, for example as needed to format WITH clauses * effectively. * * Parts may be merged with other parts within the same group, if the indent * mode is set to DEPARSE_PART_INDENT_AND_MERGE. This is utilized to put * certain items, for example the target list items in SELECT on one or more * lines, breaking at separators as needed to respect the maximum line limit. * * ## Node context * * Node context is used when the same function in the deparser needs to behave * differently depending on the parent node. For example, a SELECT statement * needs wrapping parenthesis in certain situations where the parent statement * uses a set operation (e.g. UNION). * * ## Comments * * Comments do not exist as nodes in a Postgres parse tree, and as such need to * be passed in separately through the deparser options. They are placed in the * output on a best effort basis, by matching against node locations. Comments * will only be output at most once, but may not be output at all in certain * cases, for example when the comment's specified match location is never * reached by any of the nodes visited. */ typedef enum DeparseNodeContext { DEPARSE_NODE_CONTEXT_NONE, // Parent node type (and sometimes field) DEPARSE_NODE_CONTEXT_INSERT_RELATION, DEPARSE_NODE_CONTEXT_INSERT_SELECT, DEPARSE_NODE_CONTEXT_A_EXPR, DEPARSE_NODE_CONTEXT_CREATE_TYPE, DEPARSE_NODE_CONTEXT_ALTER_TYPE, DEPARSE_NODE_CONTEXT_SET_STATEMENT, DEPARSE_NODE_CONTEXT_FUNC_EXPR, DEPARSE_NODE_CONTEXT_SELECT_SETOP, DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE, // Identifier vs constant context DEPARSE_NODE_CONTEXT_IDENTIFIER, DEPARSE_NODE_CONTEXT_CONSTANT } DeparseNodeContext; typedef enum DeparsePartIndentMode { /* Don't indent parts at all, used in special cases (e.g. WITH clauses) */ DEPARSE_PART_NO_INDENT, /* Indent parts but don't merge them (keep each on their own line) */ DEPARSE_PART_INDENT, /* Indent parts and merge them together up to the max line length */ DEPARSE_PART_INDENT_AND_MERGE } DeparsePartIndentMode; // Each part is typically one line to be emitted in pretty print mode typedef struct DeparseStatePart { StringInfo str; /* If this gets emitted as its own line, number of spaces to be added as indentation */ int indent; /* Allow merging this part with adjacent parts that are marked as mergeable */ bool mergeable; } DeparseStatePart; // A part group are typically all parts associated with a major keyword typedef struct DeparseStatePartGroup { const char *keyword; List *parts; DeparsePartIndentMode indent_mode; } DeparseStatePartGroup; // Nesting levels may be statements, or complex parts of statements that should be indented (e.g. CASE) typedef struct DeparseStateNestingLevel { /* List of DeparseStatePartGroup items */ List *part_groups; /* Add this much indentation to every part */ int base_indent; } DeparseStateNestingLevel; typedef struct DeparseState { DeparseStateNestingLevel *current; /* List of DeparseStatePart items */ List *result_parts; /* Deparse options originally passed in */ PostgresDeparseOpts opts; /* Set of indexes of comments already placed in the output query */ Bitmapset *emitted_comments; } DeparseState; static void deparseSelectStmt(DeparseState *state, SelectStmt *stmt, DeparseNodeContext context); static void deparseIntoClause(DeparseState *state, IntoClause *into_clause); static void deparseRangeVar(DeparseState *state, RangeVar *range_var, DeparseNodeContext context); static void deparseResTarget(DeparseState *state, ResTarget *res_target, DeparseNodeContext context); static void deparseAlias(DeparseState *state, Alias *alias); static void deparseWindowDef(DeparseState *state, WindowDef* window_def); static void deparseColumnRef(DeparseState *state, ColumnRef* column_ref); static void deparseSubLink(DeparseState *state, SubLink* sub_link); static void deparseAExpr(DeparseState *state, A_Expr* a_expr, DeparseNodeContext context); static void deparseBoolExpr(DeparseState *state, BoolExpr *bool_expr); static void deparseAStar(DeparseState *state, A_Star* a_star); static void deparseCollateClause(DeparseState *state, CollateClause* collate_clause); static void deparseSortBy(DeparseState *state, SortBy* sort_by); static void deparseParamRef(DeparseState *state, ParamRef* param_ref); static void deparseSQLValueFunction(DeparseState *state, SQLValueFunction* sql_value_function); static void deparseWithClause(DeparseState *state, WithClause *with_clause); static void deparseJoinExpr(DeparseState *state, JoinExpr *join_expr); static void deparseCommonTableExpr(DeparseState *state, CommonTableExpr *cte); static void deparseRangeSubselect(DeparseState *state, RangeSubselect *range_subselect); static void deparseRangeFunction(DeparseState *state, RangeFunction *range_func); static void deparseAArrayExpr(DeparseState *state, A_ArrayExpr * array_expr); static void deparseRowExpr(DeparseState *state, RowExpr *row_expr); static void deparseTypeCast(DeparseState *state, TypeCast *type_cast, DeparseNodeContext context); static void deparseTypeName(DeparseState *state, TypeName *type_name); static void deparseIntervalTypmods(DeparseState *state, TypeName *type_name); static void deparseNullTest(DeparseState *state, NullTest *null_test); static void deparseCaseExpr(DeparseState *state, CaseExpr *case_expr); static void deparseCaseWhen(DeparseState *state, CaseWhen *case_when); static void deparseAIndirection(DeparseState *state, A_Indirection *a_indirection); static void deparseAIndices(DeparseState *state, A_Indices *a_indices); static void deparseCoalesceExpr(DeparseState *state, CoalesceExpr *coalesce_expr); static void deparseBooleanTest(DeparseState *state, BooleanTest *boolean_test); static void deparseColumnDef(DeparseState *state, ColumnDef *column_def); static void deparseInsertStmt(DeparseState *state, InsertStmt *insert_stmt); static void deparseOnConflictClause(DeparseState *state, OnConflictClause *on_conflict_clause); static void deparseIndexElem(DeparseState *state, IndexElem* index_elem); static void deparseUpdateStmt(DeparseState *state, UpdateStmt *update_stmt); static void deparseDeleteStmt(DeparseState *state, DeleteStmt *delete_stmt); static void deparseLockingClause(DeparseState *state, LockingClause *locking_clause); static void deparseSetToDefault(DeparseState *state, SetToDefault *set_to_default); static void deparseCreateCastStmt(DeparseState *state, CreateCastStmt *create_cast_stmt); static void deparseCreateDomainStmt(DeparseState *state, CreateDomainStmt *create_domain_stmt); static void deparseFunctionParameter(DeparseState *state, FunctionParameter *function_parameter); static void deparseRoleSpec(DeparseState *state, RoleSpec *role_spec); static void deparseViewStmt(DeparseState *state, ViewStmt *view_stmt); static void deparseVariableSetStmt(DeparseState *state, VariableSetStmt* variable_set_stmt); static void deparseReplicaIdentityStmt(DeparseState *state, ReplicaIdentityStmt *replica_identity_stmt); static void deparseRangeTableSample(DeparseState *state, RangeTableSample *range_table_sample); static void deparseRangeTableFunc(DeparseState *state, RangeTableFunc* range_table_func); static void deparseGroupingSet(DeparseState *state, GroupingSet *grouping_set); static void deparseFuncCall(DeparseState *state, FuncCall *func_call, DeparseNodeContext context); static void deparseMinMaxExpr(DeparseState *state, MinMaxExpr *min_max_expr); static void deparseXmlExpr(DeparseState *state, XmlExpr* xml_expr, DeparseNodeContext context); static void deparseXmlSerialize(DeparseState *state, XmlSerialize *xml_serialize); static void deparseJsonIsPredicate(DeparseState *state, JsonIsPredicate *json_is_predicate); static void deparseJsonObjectAgg(DeparseState *state, JsonObjectAgg *json_object_agg); static void deparseJsonArrayAgg(DeparseState *state, JsonArrayAgg *json_array_agg); static void deparseJsonObjectConstructor(DeparseState *state, JsonObjectConstructor *json_object_constructor); static void deparseJsonArrayConstructor(DeparseState *state, JsonArrayConstructor *json_array_constructor); static void deparseJsonArrayQueryConstructor(DeparseState *state, JsonArrayQueryConstructor *json_array_query_constructor); static void deparseJsonValueExpr(DeparseState *state, JsonValueExpr *json_value_expr); static void deparseJsonOutput(DeparseState *state, JsonOutput *json_output); static void deparseJsonParseExpr(DeparseState *state, JsonParseExpr *json_parse_expr); static void deparseJsonScalarExpr(DeparseState *state, JsonScalarExpr *json_scalar_expr); static void deparseJsonSerializeExpr(DeparseState *state, JsonSerializeExpr *json_serialize_expr); static void deparseJsonTable(DeparseState *state, JsonTable *json_table); static void deparseJsonTableColumn(DeparseState *state, JsonTableColumn *json_table_column); static void deparseJsonTableColumns(DeparseState *state, List *json_table_columns); static void deparseJsonTablePathSpec(DeparseState *state, JsonTablePathSpec *json_table_path_spec); static void deparseJsonBehavior(DeparseState *state, JsonBehavior *json_behavior); static void deparseJsonFuncExpr(DeparseState *state, JsonFuncExpr *json_func_expr); static void deparseJsonQuotesClauseOpt(DeparseState *state, JsonQuotes quotes); static void deparseJsonOnErrorClauseOpt(DeparseState *state, JsonBehavior *behavior); static void deparseJsonOnEmptyClauseOpt(DeparseState *state, JsonBehavior *behavior); static void deparseConstraint(DeparseState *state, Constraint *constraint); static void deparseSchemaStmt(DeparseState *state, Node *node); static void deparseExecuteStmt(DeparseState *state, ExecuteStmt *execute_stmt); static void deparseTriggerTransition(DeparseState *state, TriggerTransition *trigger_transition); static void deparseCreateOpClassItem(DeparseState *state, CreateOpClassItem *create_op_class_item); static void deparseAConst(DeparseState *state, A_Const *a_const); static void deparseGroupingFunc(DeparseState *state, GroupingFunc *grouping_func); static void deparsePreparableStmt(DeparseState *state, Node *node); static void deparseRuleActionStmt(DeparseState *state, Node *node); static void deparseExplainableStmt(DeparseState *state, Node *node); static void deparseStmt(DeparseState *state, Node *node); static void deparseValue(DeparseState *state, union ValUnion *value, DeparseNodeContext context); static void removeTrailingSpaceFromStr(StringInfo str) { if (str->len >= 1 && str->data[str->len - 1] == ' ') { str->len -= 1; str->data[str->len] = '\0'; } } // 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 DeparseStatePart * makeDeparseStatePart(DeparseState *state, DeparseStateNestingLevel *level, DeparsePartIndentMode indent_mode) { DeparseStatePart *part = palloc(sizeof(DeparseStatePart)); part->str = makeStringInfo(); part->indent = level->base_indent; if (indent_mode != DEPARSE_PART_NO_INDENT) part->indent += state->opts.indent_size; part->mergeable = indent_mode == DEPARSE_PART_INDENT_AND_MERGE; return part; } static void freeDeparseStatePart(DeparseStatePart *part) { pfree(part->str->data); pfree(part->str); pfree(part); } // Returns current active part group, and initializes the first one (including an empty part) if needed static DeparseStatePartGroup * deparseGetCurrentPartGroup(DeparseState *state) { DeparseStateNestingLevel *level = state->current; if (level->part_groups) return (DeparseStatePartGroup *) llast(level->part_groups); DeparseStatePartGroup *part_group = palloc0(sizeof(DeparseStatePartGroup)); part_group->parts = lappend(part_group->parts, makeDeparseStatePart(state, level, part_group->indent_mode)); level->part_groups = lappend(level->part_groups, part_group); return part_group; } static DeparseStatePart * deparseGetCurrentPart(DeparseState *state) { DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); return (DeparseStatePart *) llast(part_group->parts); } static void deparseMarkCurrentPartNonMergable(DeparseState *state) { DeparseStatePart *part = deparseGetCurrentPart(state); part->mergeable = false; } static StringInfo deparseGetCurrentStringInfo(DeparseState *state) { DeparseStatePart *part = deparseGetCurrentPart(state); Assert(part != NULL); return part->str; } static void deparseAppendStringInfo(DeparseState *state, const char *fmt,...) { StringInfo str = deparseGetCurrentStringInfo(state); int save_errno = errno; for (;;) { va_list args; int needed; /* Try to format the data. */ errno = save_errno; va_start(args, fmt); needed = appendStringInfoVA(str, fmt, args); va_end(args); if (needed == 0) break; /* success */ /* Increase the buffer size and try again. */ enlargeStringInfo(str, needed); } } static void deparseAppendStringInfoString(DeparseState *state, const char *s) { StringInfo str = deparseGetCurrentStringInfo(state); appendStringInfoString(str, s); } static void deparseAppendStringInfoChar(DeparseState *state, char ch) { StringInfo str = deparseGetCurrentStringInfo(state); appendStringInfoChar(str, ch); } static void removeTrailingSpace(DeparseState *state) { StringInfo str = deparseGetCurrentStringInfo(state); removeTrailingSpaceFromStr(str); } static void deparseRemoveTrailingEmptyPart(DeparseState *state) { DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); DeparseStatePart *last_part = deparseGetCurrentPart(state); if (last_part->str->len == 0) { freeDeparseStatePart(last_part); part_group->parts = list_delete_last(part_group->parts); } } static void deparseAppendPart(DeparseState *state, bool deduplicate) { DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); // Remove previous part if its empty and we deduplicate. We don't keep // the existing part since it may have the wrong indent level or mode. if (deduplicate) deparseRemoveTrailingEmptyPart(state); part_group->parts = lappend(part_group->parts, makeDeparseStatePart(state, state->current, part_group->indent_mode)); } static void deparseAppendCommaAndPart(DeparseState *state) { if (state->opts.commas_start_of_line) { deparseAppendPart(state, true); deparseAppendStringInfoString(state, ", "); } else { deparseAppendStringInfoChar(state, ','); deparseAppendPart(state, true); } } static void deparseAppendPartGroup(DeparseState *state, const char *keyword, DeparsePartIndentMode indent_mode) { DeparseStateNestingLevel *level = state->current; DeparseStatePartGroup *part_group = palloc0(sizeof(DeparseStatePartGroup)); if (list_length(level->part_groups) > 0) removeTrailingSpace(state); part_group->keyword = keyword; part_group->parts = lappend(part_group->parts, makeDeparseStatePart(state, state->current, indent_mode)); part_group->indent_mode = indent_mode; level->part_groups = lappend(level->part_groups, part_group); } static void deparseAppendCommentsIfNeeded(DeparseState *state, ParseLoc location) { for (int i = 0; i < state->opts.comment_count; i++) { if (bms_is_member(i, state->emitted_comments)) continue; PostgresDeparseComment *comment = state->opts.comments[i]; if (comment->match_location > location) continue; // Emit one less leading newline if we already emitted one for formatting reasons int newlines_before_comment = comment->newlines_before_comment; if (state->opts.pretty_print && newlines_before_comment > 0 && deparseGetCurrentPartGroup(state)->keyword != NULL && deparseGetCurrentStringInfo(state)->len == 0) newlines_before_comment -= 1; for (int j = 0; j < newlines_before_comment; j++) { if (state->opts.pretty_print) deparseAppendPart(state, false); else deparseAppendStringInfoChar(state, '\n'); } deparseAppendStringInfoString(state, comment->str); /* never merge comments with other parts */ deparseMarkCurrentPartNonMergable(state); for (int j = 0; j < comment->newlines_after_comment; j++) { if (state->opts.pretty_print) deparseAppendPart(state, false); else deparseAppendStringInfoChar(state, '\n'); } state->emitted_comments = bms_add_member(state->emitted_comments, i); } } static void deparseEmit(DeparseState *state, StringInfo str) { ListCell *lc; /* If the last part is empty, drop it, so we don't confuse the newline output */ DeparseStatePart *last_part = (DeparseStatePart *) llast(state->result_parts); if (last_part && last_part->str->len == 0) { freeDeparseStatePart(last_part); state->result_parts = list_delete_last(state->result_parts); } foreach (lc, state->result_parts) { DeparseStatePart *part = (DeparseStatePart *) lfirst(lc); bool last_part = list_cell_number(state->result_parts, lc) == list_length(state->result_parts) - 1; if (!state->opts.pretty_print && part->str->len > 0 && (part->str->data[0] == ')' || part->str->data[0] == ';')) removeTrailingSpaceFromStr(str); if (state->opts.pretty_print) { for (int i = 0; i < part->indent; i++) appendStringInfoChar(str, ' '); } appendStringInfoString(str, part->str->data); removeTrailingSpaceFromStr(str); if (!last_part) { if (state->opts.pretty_print) appendStringInfoChar(str, '\n'); else if (str->data[str->len - 1] != '(') appendStringInfoChar(str, ' '); } freeDeparseStatePart(part); } list_free(state->result_parts); state->result_parts = NIL; if (state->opts.pretty_print && state->opts.trailing_newline) appendStringInfoChar(str, '\n'); } static DeparseStateNestingLevel * deparseStateIncreaseNestingLevel(DeparseState *state) { DeparseStateNestingLevel *parent = state->current; DeparseStateNestingLevel *level = palloc0(sizeof(DeparseStateNestingLevel)); if (parent) { DeparseStatePartGroup *part_group = deparseGetCurrentPartGroup(state); level->base_indent = parent->base_indent + state->opts.indent_size; if (part_group->indent_mode != DEPARSE_PART_NO_INDENT) /* Indent again if parts next to us are also indented */ level->base_indent += state->opts.indent_size; /* Parts with nested elements don't get merged, even if otherwise permitted */ deparseMarkCurrentPartNonMergable(state); } state->current = level; return parent; } static void deparseStateDecreaseNestingLevel(DeparseState *state, DeparseStateNestingLevel *parent_level) { ListCell *lc; ListCell *lc2; DeparseStateNestingLevel *level = state->current; Assert(level != NULL); foreach (lc, level->part_groups) { DeparseStatePartGroup *part_group = (DeparseStatePartGroup *) lfirst(lc); /* Merge parts */ if (part_group->indent_mode == DEPARSE_PART_INDENT_AND_MERGE && list_length(part_group->parts) > 1) { DeparseStatePart *target = (DeparseStatePart *) linitial(part_group->parts); for_each_from (lc2, part_group->parts, 1) { DeparseStatePart *part = (DeparseStatePart *) lfirst(lc2); removeTrailingSpaceFromStr(target->str); if (target->mergeable && part->mergeable && target->indent + target->str->len + 1 + part->str->len <= state->opts.max_line_length) { if (target->str->len > 0 && target->str->data[target->str->len - 1] != '(') appendStringInfoChar(target->str, ' '); appendStringInfoString(target->str, part->str->data); freeDeparseStatePart(part); part_group->parts = foreach_delete_current(part_group->parts, lc2); } else { target = part; } } } if (part_group->keyword != NULL) { DeparseStatePart *target = makeDeparseStatePart(state, level, false); appendStringInfoString(target->str, part_group->keyword); part_group->parts = list_insert_nth(part_group->parts, 0, target); if (list_length(part_group->parts) == 2 || part_group->indent_mode == DEPARSE_PART_NO_INDENT) { DeparseStatePart *part = (DeparseStatePart *) lsecond(part_group->parts); if (part->str->len > 0) appendStringInfo(target->str, " %s", part->str->data); freeDeparseStatePart(part); part_group->parts = list_delete_nth_cell(part_group->parts, 1); } } if (parent_level) { DeparseStatePartGroup *parent_part_group = (DeparseStatePartGroup *) llast(parent_level->part_groups); parent_part_group->parts = list_concat(parent_part_group->parts, part_group->parts); } else { // If its the top level, save as results instead state->result_parts = list_concat(state->result_parts, part_group->parts); } list_free(part_group->parts); pfree(part_group); } list_free(level->part_groups); pfree(level); state->current = parent_level; if (parent_level) { /* Make sure parent statement writes that follow are on their own line */ deparseAppendPart(state, true); /* Parts with nested elements don't get merged, even if otherwise permitted */ deparseMarkCurrentPartNonMergable(state); } } /* * Append a SQL string literal representing "val" to buf. * * Copied here from postgres_fdw/deparse.c to avoid adding * many additional dependencies, and modified to work with deparser * state. */ static void deparseStringLiteral(DeparseState *state, 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) deparseAppendStringInfoChar(state, ESCAPE_STRING_SYNTAX); deparseAppendStringInfoChar(state, '\''); for (valptr = val; *valptr; valptr++) { char ch = *valptr; if (SQL_STR_DOUBLE(ch, true)) deparseAppendStringInfoChar(state, ch); deparseAppendStringInfoChar(state, ch); } deparseAppendStringInfoChar(state, '\''); } // "any_name" in gram.y static void deparseAnyName(DeparseState *state, List *parts) { ListCell *lc = NULL; foreach(lc, parts) { Assert(IsA(lfirst(lc), String)); deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); if (lnext(parts, lc)) deparseAppendStringInfoChar(state, '.'); } } static void deparseAnyNameSkipFirst(DeparseState *state, List *parts) { ListCell *lc = NULL; for_each_from(lc, parts, 1) { Assert(IsA(lfirst(lc), String)); deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); if (lnext(parts, lc)) deparseAppendStringInfoChar(state, '.'); } } static void deparseAnyNameSkipLast(DeparseState *state, List *parts) { ListCell *lc = NULL; foreach (lc, parts) { if (lnext(parts, lc)) { deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); if (foreach_current_index(lc) < list_length(parts) - 2) deparseAppendStringInfoChar(state, '.'); } } } // "func_expr" in gram.y static void deparseFuncExpr(DeparseState *state, Node *node, DeparseNodeContext context) { switch (nodeTag(node)) { case T_FuncCall: deparseFuncCall(state, castNode(FuncCall, node), context); break; case T_SQLValueFunction: deparseSQLValueFunction(state, castNode(SQLValueFunction, node)); break; case T_MinMaxExpr: deparseMinMaxExpr(state, castNode(MinMaxExpr, node)); break; case T_CoalesceExpr: deparseCoalesceExpr(state, castNode(CoalesceExpr, node)); break; case T_XmlExpr: deparseXmlExpr(state, castNode(XmlExpr, node), context); break; case T_XmlSerialize: deparseXmlSerialize(state, castNode(XmlSerialize, node)); break; case T_JsonObjectAgg: deparseJsonObjectAgg(state, castNode(JsonObjectAgg, node)); break; case T_JsonArrayAgg: deparseJsonArrayAgg(state, castNode(JsonArrayAgg, node)); break; case T_JsonObjectConstructor: deparseJsonObjectConstructor(state, castNode(JsonObjectConstructor, node)); break; case T_JsonArrayConstructor: deparseJsonArrayConstructor(state, castNode(JsonArrayConstructor, node)); break; case T_JsonArrayQueryConstructor: deparseJsonArrayQueryConstructor(state, castNode(JsonArrayQueryConstructor, node)); break; default: elog(ERROR, "deparse: unpermitted node type in func_expr: %d", (int) nodeTag(node)); break; } } static void deparseCExpr(DeparseState *state, Node *node); // "a_expr" in gram.y static void deparseExpr(DeparseState *state, Node *node, DeparseNodeContext context) { if (node == NULL) return; switch (nodeTag(node)) { case T_ColumnRef: case T_A_Const: case T_ParamRef: case T_A_Indirection: case T_CaseExpr: case T_SubLink: case T_A_ArrayExpr: case T_RowExpr: case T_GroupingFunc: deparseCExpr(state, node); break; case T_TypeCast: deparseTypeCast(state, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); break; case T_CollateClause: deparseCollateClause(state, castNode(CollateClause, node)); break; case T_A_Expr: deparseAExpr(state, castNode(A_Expr, node), DEPARSE_NODE_CONTEXT_A_EXPR); break; case T_BoolExpr: deparseBoolExpr(state, castNode(BoolExpr, node)); break; case T_NullTest: deparseNullTest(state, castNode(NullTest, node)); break; case T_BooleanTest: deparseBooleanTest(state, castNode(BooleanTest, node)); break; case T_JsonIsPredicate: deparseJsonIsPredicate(state, castNode(JsonIsPredicate, node)); break; case T_SetToDefault: deparseSetToDefault(state, castNode(SetToDefault, node)); break; case T_MergeSupportFunc: deparseAppendStringInfoString(state, "merge_action() "); break; case T_JsonParseExpr: deparseJsonParseExpr(state, castNode(JsonParseExpr, node)); break; case T_JsonScalarExpr: deparseJsonScalarExpr(state, castNode(JsonScalarExpr, node)); break; case T_JsonSerializeExpr: deparseJsonSerializeExpr(state, castNode(JsonSerializeExpr, node)); break; case T_JsonFuncExpr: deparseJsonFuncExpr(state, castNode(JsonFuncExpr, node)); break; case T_FuncCall: case T_SQLValueFunction: case T_MinMaxExpr: case T_CoalesceExpr: case T_XmlExpr: case T_XmlSerialize: case T_JsonObjectAgg: case T_JsonArrayAgg: case T_JsonObjectConstructor: case T_JsonArrayConstructor: case T_JsonArrayQueryConstructor: deparseFuncExpr(state, node, context); break; default: // Note that this is also the fallthrough for deparseBExpr and deparseCExpr elog(ERROR, "deparse: unpermitted node type in a_expr/b_expr/c_expr: %d", (int) nodeTag(node)); break; } } // "b_expr" in gram.y static void deparseBExpr(DeparseState *state, Node *node) { if (IsA(node, XmlExpr)) { deparseXmlExpr(state, castNode(XmlExpr, node), DEPARSE_NODE_CONTEXT_NONE); return; } if (IsA(node, A_Expr)) { A_Expr *a_expr = castNode(A_Expr, node); // Other kinds are handled by "c_expr", with parens added around them if (a_expr->kind == AEXPR_OP || a_expr->kind == AEXPR_DISTINCT || a_expr->kind == AEXPR_NOT_DISTINCT) { deparseAExpr(state, a_expr, DEPARSE_NODE_CONTEXT_NONE); return; } } if (IsA(node, BoolExpr)) { BoolExpr *bool_expr = castNode(BoolExpr, node); if (bool_expr->boolop == NOT_EXPR) { deparseBoolExpr(state, bool_expr); return; } } deparseCExpr(state, node); } // "AexprConst" in gram.y static void deparseAexprConst(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_A_Const: deparseAConst(state, castNode(A_Const, node)); break; case T_TypeCast: deparseTypeCast(state, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_NONE); break; default: elog(ERROR, "deparse: unpermitted node type in AexprConst: %d", (int) nodeTag(node)); break; } } // "c_expr" in gram.y static void deparseCExpr(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_ColumnRef: deparseColumnRef(state, castNode(ColumnRef, node)); break; case T_A_Const: deparseAConst(state, castNode(A_Const, node)); break; case T_ParamRef: deparseParamRef(state, castNode(ParamRef, node)); break; case T_A_Indirection: deparseAIndirection(state, castNode(A_Indirection, node)); break; case T_CaseExpr: deparseCaseExpr(state, castNode(CaseExpr, node)); break; case T_SubLink: deparseSubLink(state, castNode(SubLink, node)); break; case T_A_ArrayExpr: deparseAArrayExpr(state, castNode(A_ArrayExpr, node)); break; case T_RowExpr: deparseRowExpr(state, castNode(RowExpr, node)); break; case T_GroupingFunc: deparseGroupingFunc(state, castNode(GroupingFunc, node)); break; case T_FuncCall: case T_SQLValueFunction: case T_MinMaxExpr: case T_CoalesceExpr: case T_XmlExpr: case T_XmlSerialize: case T_JsonObjectAgg: case T_JsonArrayAgg: case T_JsonObjectConstructor: case T_JsonArrayConstructor: case T_JsonArrayQueryConstructor: deparseFuncExpr(state, node, DEPARSE_NODE_CONTEXT_NONE); break; default: deparseAppendStringInfoChar(state, '('); // Because we wrap this in parenthesis, the expression inside follows "a_expr" parser rules deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ')'); break; } } // "expr_list" in gram.y static void deparseExprList(DeparseState *state, List *exprs) { ListCell *lc; foreach(lc, exprs) { deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); if (lnext(exprs, lc)) deparseAppendStringInfoString(state, ", "); } } // "ColId", "name", "database_name", "access_method" and "index_name" in gram.y static void deparseColId(DeparseState *state, char *s) { deparseAppendStringInfoString(state, 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(DeparseState *state, char *s) { deparseAppendStringInfoString(state, quote_identifier(s)); } // "SignedIconst" and "Iconst" in gram.y static void deparseSignedIconst(DeparseState *state, Node *node) { deparseAppendStringInfo(state, "%d", intVal(node)); } // "indirection" and "opt_indirection" in gram.y static void deparseOptIndirection(DeparseState *state, List *indirection, int N) { ListCell *lc = NULL; for_each_from(lc, indirection, N) { if (IsA(lfirst(lc), String)) { deparseAppendStringInfoChar(state, '.'); deparseColLabel(state, strVal(lfirst(lc))); } else if (IsA(lfirst(lc), A_Star)) { deparseAppendStringInfoString(state, ".*"); } else if (IsA(lfirst(lc), A_Indices)) { deparseAIndices(state, castNode(A_Indices, lfirst(lc))); } else { // No other nodes should appear here Assert(false); } } } // "role_list" in gram.y static void deparseRoleList(DeparseState *state, List *roles) { ListCell *lc; foreach(lc, roles) { RoleSpec *role_spec = castNode(RoleSpec, lfirst(lc)); deparseRoleSpec(state, role_spec); if (lnext(roles, lc)) deparseAppendStringInfoString(state, ", "); } } // "SimpleTypename" in gram.y static void deparseSimpleTypename(DeparseState *state, Node *node) { deparseTypeName(state, castNode(TypeName, node)); } // "NumericOnly" in gram.y static void deparseNumericOnly(DeparseState *state, union ValUnion *value) { switch (nodeTag(value)) { case T_Integer: deparseAppendStringInfo(state, "%d", value->ival.ival); break; case T_Float: deparseAppendStringInfoString(state, value->sval.sval); break; default: Assert(false); } } // "NumericOnly_list" in gram.y static void deparseNumericOnlyList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { deparseNumericOnly(state, (union ValUnion *) lfirst(lc)); if (lnext(l, lc)) deparseAppendStringInfoString(state, ", "); } } // "SeqOptElem" in gram.y static void deparseSeqOptElem(DeparseState *state, DefElem *def_elem) { ListCell *lc; if (strcmp(def_elem->defname, "as") == 0) { deparseAppendStringInfoString(state, "AS "); deparseSimpleTypename(state, def_elem->arg); } else if (strcmp(def_elem->defname, "cache") == 0) { deparseAppendStringInfoString(state, "CACHE "); deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (strcmp(def_elem->defname, "cycle") == 0 && boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "CYCLE"); } else if (strcmp(def_elem->defname, "cycle") == 0 && !boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "NO CYCLE"); } else if (strcmp(def_elem->defname, "increment") == 0) { deparseAppendStringInfoString(state, "INCREMENT "); deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg != NULL) { deparseAppendStringInfoString(state, "MAXVALUE "); deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (strcmp(def_elem->defname, "maxvalue") == 0 && def_elem->arg == NULL) { deparseAppendStringInfoString(state, "NO MAXVALUE"); } else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg != NULL) { deparseAppendStringInfoString(state, "MINVALUE "); deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (strcmp(def_elem->defname, "minvalue") == 0 && def_elem->arg == NULL) { deparseAppendStringInfoString(state, "NO MINVALUE"); } else if (strcmp(def_elem->defname, "owned_by") == 0) { deparseAppendStringInfoString(state, "OWNED BY "); deparseAnyName(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "sequence_name") == 0) { deparseAppendStringInfoString(state, "SEQUENCE NAME "); deparseAnyName(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "start") == 0) { deparseAppendStringInfoString(state, "START "); deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg == NULL) { deparseAppendStringInfoString(state, "RESTART"); } else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) { deparseAppendStringInfoString(state, "RESTART "); deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else { Assert(false); } } // "SeqOptList" in gram.y static void deparseSeqOptList(DeparseState *state, List *options) { ListCell *lc; Assert(list_length(options) > 0); foreach (lc, options) { deparseSeqOptElem(state, castNode(DefElem, lfirst(lc))); deparseAppendStringInfoChar(state, ' '); } } // "OptSeqOptList" in gram.y static void deparseOptSeqOptList(DeparseState *state, List *options) { if (list_length(options) > 0) deparseSeqOptList(state, options); } // "OptParenthesizedSeqOptList" in gram.y static void deparseOptParenthesizedSeqOptList(DeparseState *state, List *options) { if (list_length(options) > 0) { deparseAppendStringInfoChar(state, '('); deparseSeqOptList(state, options); deparseAppendStringInfoChar(state, ')'); } } // "opt_drop_behavior" in gram.y static void deparseOptDropBehavior(DeparseState *state, DropBehavior behavior) { switch (behavior) { case DROP_RESTRICT: // Default break; case DROP_CASCADE: deparseAppendStringInfoString(state, "CASCADE "); break; } } // "any_operator" in gram.y static void deparseAnyOperator(DeparseState *state, List *op) { Assert(isOp(strVal(llast(op)))); if (list_length(op) == 2) { deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(op)))); deparseAppendStringInfoChar(state, '.'); deparseAppendStringInfoString(state, strVal(llast(op))); } else if (list_length(op) == 1) { deparseAppendStringInfoString(state, strVal(llast(op))); } else { Assert(false); } } // "qual_Op" and "qual_all_Op" in gram.y static void deparseQualOp(DeparseState *state, List *op) { if (list_length(op) == 1 && isOp(strVal(linitial(op)))) { deparseAppendStringInfoString(state, strVal(linitial(op))); } else { deparseAppendStringInfoString(state, "OPERATOR("); deparseAnyOperator(state, op); deparseAppendStringInfoString(state, ")"); } } // "subquery_Op" in gram.y static void deparseSubqueryOp(DeparseState *state, List *op) { if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~") == 0) { deparseAppendStringInfoString(state, "LIKE"); } else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~") == 0) { deparseAppendStringInfoString(state, "NOT LIKE"); } else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "~~*") == 0) { deparseAppendStringInfoString(state, "ILIKE"); } else if (list_length(op) == 1 && strcmp(strVal(linitial(op)), "!~~*") == 0) { deparseAppendStringInfoString(state, "NOT ILIKE"); } else if (list_length(op) == 1 && isOp(strVal(linitial(op)))) { deparseAppendStringInfoString(state, strVal(linitial(op))); } else { deparseAppendStringInfoString(state, "OPERATOR("); deparseAnyOperator(state, op); deparseAppendStringInfoString(state, ")"); } } // Not present directly in gram.y (usually matched by ColLabel) static void deparseGenericDefElemName(DeparseState *state, const char *in) { Assert(in != NULL); char *val = pstrdup(in); for (unsigned char *p = (unsigned char *) val; *p; p++) *p = pg_toupper(*p); deparseAppendStringInfoString(state, val); pfree(val); } // "def_arg" and "operator_def_arg" in gram.y static void deparseDefArg(DeparseState *state, Node *arg, bool is_operator_def_arg) { if (IsA(arg, TypeName)) // func_type { deparseTypeName(state, 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) { deparseAppendStringInfoString(state, "OPERATOR("); deparseAnyOperator(state, l); deparseAppendStringInfoChar(state, ')'); } else if (list_length(l) == 1) { deparseAppendStringInfoString(state, strVal(linitial(l))); } } else if (IsA(arg, Float) || IsA(arg, Integer)) // NumericOnly { deparseValue(state, (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 { deparseAppendStringInfoString(state, "NONE"); } else if (isReservedKeyword(s)) // reserved_keyword { deparseAppendStringInfoString(state, s); } else // Sconst { deparseStringLiteral(state, s); } } else { Assert(false); } } // "definition" in gram.y static void deparseDefinition(DeparseState *state, List *options) { ListCell *lc = NULL; deparseAppendStringInfoChar(state, '('); foreach (lc, options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); if (def_elem->arg != NULL) { deparseAppendStringInfoString(state, " = "); deparseDefArg(state, def_elem->arg, false); } if (lnext(options, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); } // "opt_definition" in gram.y // // Note this method adds a trailing space if a value is output static void deparseOptDefinition(DeparseState *state, List *options) { if (list_length(options) > 0) { deparseAppendStringInfoString(state, "WITH "); deparseDefinition(state, options); } } // "create_generic_options" in gram.y static void deparseCreateGenericOptions(DeparseState *state, List *options) { ListCell *lc = NULL; if (options == NULL) return; deparseAppendStringInfoString(state, "OPTIONS ("); foreach(lc, options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); deparseAppendStringInfoChar(state, ' '); deparseStringLiteral(state, strVal(def_elem->arg)); if (lnext(options, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, ")"); } // "common_func_opt_item" in gram.y static void deparseCommonFuncOptItem(DeparseState *state, DefElem *def_elem) { if (strcmp(def_elem->defname, "strict") == 0 && boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "RETURNS NULL ON NULL INPUT"); } else if (strcmp(def_elem->defname, "strict") == 0 && !boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "CALLED ON NULL INPUT"); } else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "immutable") == 0) { deparseAppendStringInfoString(state, "IMMUTABLE"); } else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "stable") == 0) { deparseAppendStringInfoString(state, "STABLE"); } else if (strcmp(def_elem->defname, "volatility") == 0 && strcmp(strVal(def_elem->arg), "volatile") == 0) { deparseAppendStringInfoString(state, "VOLATILE"); } else if (strcmp(def_elem->defname, "security") == 0 && boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "SECURITY DEFINER"); } else if (strcmp(def_elem->defname, "security") == 0 && !boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "SECURITY INVOKER"); } else if (strcmp(def_elem->defname, "leakproof") == 0 && boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "LEAKPROOF"); } else if (strcmp(def_elem->defname, "leakproof") == 0 && !boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "NOT LEAKPROOF"); } else if (strcmp(def_elem->defname, "cost") == 0) { deparseAppendStringInfoString(state, "COST "); deparseValue(state, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); } else if (strcmp(def_elem->defname, "rows") == 0) { deparseAppendStringInfoString(state, "ROWS "); deparseValue(state, (union ValUnion *) def_elem->arg, DEPARSE_NODE_CONTEXT_NONE); } else if (strcmp(def_elem->defname, "support") == 0) { deparseAppendStringInfoString(state, "SUPPORT "); deparseAnyName(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "set") == 0 && IsA(def_elem->arg, VariableSetStmt)) // FunctionSetResetClause { deparseVariableSetStmt(state, castNode(VariableSetStmt, def_elem->arg)); } else if (strcmp(def_elem->defname, "parallel") == 0) { deparseAppendStringInfoString(state, "PARALLEL "); deparseAppendStringInfoString(state, 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(DeparseState *state, const char *val) { if (strlen(val) == 0) deparseAppendStringInfoString(state, "''"); else if (strlen(val) >= NAMEDATALEN) deparseStringLiteral(state, val); else deparseAppendStringInfoString(state, quote_identifier(val)); } // "func_as" in gram.y static void deparseFuncAs(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { char *strval = strVal(lfirst(lc)); if (strstr(strval, "$$") == NULL) { deparseAppendStringInfoString(state, "$$"); deparseAppendStringInfoString(state, strval); deparseAppendStringInfoString(state, "$$"); } else { deparseStringLiteral(state, strval); } if (lnext(l, lc)) deparseAppendStringInfoString(state, ", "); } } // "createfunc_opt_item" in gram.y static void deparseCreateFuncOptItem(DeparseState *state, DefElem *def_elem) { ListCell *lc = NULL; if (strcmp(def_elem->defname, "as") == 0) { deparseAppendStringInfoString(state, "AS "); deparseFuncAs(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "language") == 0) { deparseAppendStringInfoString(state, "LANGUAGE "); deparseNonReservedWordOrSconst(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "transform") == 0) { List *l = castNode(List, def_elem->arg); deparseAppendStringInfoString(state, "TRANSFORM "); foreach (lc, l) { deparseAppendStringInfoString(state, "FOR TYPE "); deparseTypeName(state, castNode(TypeName, lfirst(lc))); if (lnext(l, lc)) deparseAppendStringInfoString(state, ", "); } } else if (strcmp(def_elem->defname, "window") == 0) { deparseAppendStringInfoString(state, "WINDOW"); } else { deparseCommonFuncOptItem(state, def_elem); } } // "alter_generic_options" in gram.y static void deparseAlterGenericOptions(DeparseState *state, List *options) { ListCell *lc = NULL; deparseAppendStringInfoString(state, "OPTIONS ("); foreach(lc, options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); switch (def_elem->defaction) { case DEFELEM_UNSPEC: deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); deparseAppendStringInfoChar(state, ' '); deparseStringLiteral(state, strVal(def_elem->arg)); break; case DEFELEM_SET: deparseAppendStringInfoString(state, "SET "); deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); deparseAppendStringInfoChar(state, ' '); deparseStringLiteral(state, strVal(def_elem->arg)); break; case DEFELEM_ADD: deparseAppendStringInfoString(state, "ADD "); deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); deparseAppendStringInfoChar(state, ' '); deparseStringLiteral(state, strVal(def_elem->arg)); break; case DEFELEM_DROP: deparseAppendStringInfoString(state, "DROP "); deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); break; } if (lnext(options, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, ") "); } // "func_name" in gram.y static void deparseFuncName(DeparseState *state, List *func_name) { ListCell *lc = NULL; foreach(lc, func_name) { deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); if (lnext(func_name, lc)) deparseAppendStringInfoChar(state, '.'); } } // "function_with_argtypes" in gram.y static void deparseFunctionWithArgtypes(DeparseState *state, ObjectWithArgs *object_with_args) { ListCell *lc; deparseFuncName(state, object_with_args->objname); if (!object_with_args->args_unspecified) { deparseAppendStringInfoChar(state, '('); 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(state, castNode(FunctionParameter, lfirst(lc))); else deparseTypeName(state, castNode(TypeName, lfirst(lc))); if (lnext(objargs, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); } } // "function_with_argtypes_list" in gram.y static void deparseFunctionWithArgtypesList(DeparseState *state, List *l) { ListCell *lc; foreach(lc, l) { deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); if (lnext(l, lc)) deparseAppendStringInfoString(state, ", "); } } // "operator_with_argtypes" in gram.y static void deparseOperatorWithArgtypes(DeparseState *state, ObjectWithArgs *object_with_args) { deparseAnyOperator(state, object_with_args->objname); Assert(list_length(object_with_args->objargs) == 2); deparseAppendStringInfoChar(state, '('); if (linitial(object_with_args->objargs) == NULL) deparseAppendStringInfoString(state, "NONE"); else deparseTypeName(state, castNode(TypeName, linitial(object_with_args->objargs))); deparseAppendStringInfoString(state, ", "); if (lsecond(object_with_args->objargs) == NULL) deparseAppendStringInfoString(state, "NONE"); else deparseTypeName(state, castNode(TypeName, lsecond(object_with_args->objargs))); deparseAppendStringInfoChar(state, ')'); } // "aggr_args" in gram.y static void deparseAggrArgs(DeparseState *state, 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)); deparseAppendStringInfoChar(state, '('); if (args == NULL) { deparseAppendStringInfoChar(state, '*'); } else { foreach(lc, args) { if (foreach_current_index(lc) == order_by_pos) { if (foreach_current_index(lc) > 0) deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "ORDER BY "); } else if (foreach_current_index(lc) > 0) { deparseAppendStringInfoString(state, ", "); } deparseFunctionParameter(state, 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)) { deparseAppendStringInfoString(state, " ORDER BY "); deparseFunctionParameter(state, castNode(FunctionParameter, llast(args))); } } deparseAppendStringInfoChar(state, ')'); } // "aggregate_with_argtypes" in gram.y static void deparseAggregateWithArgtypes(DeparseState *state, ObjectWithArgs *object_with_args) { ListCell *lc = NULL; deparseFuncName(state, object_with_args->objname); deparseAppendStringInfoChar(state, '('); if (object_with_args->objargs == NULL && object_with_args->objfuncargs == NULL) { deparseAppendStringInfoChar(state, '*'); } 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(state, castNode(FunctionParameter, lfirst(lc))); else deparseTypeName(state, castNode(TypeName, lfirst(lc))); if (lnext(objargs, lc)) deparseAppendStringInfoString(state, ", "); } } deparseAppendStringInfoChar(state, ')'); } // "columnList" in gram.y static void deparseColumnList(DeparseState *state, List *columns) { ListCell *lc = NULL; foreach(lc, columns) { deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); if (lnext(columns, lc)) deparseAppendStringInfoString(state, ", "); } } // "OptTemp" in gram.y // // Note this method adds a trailing space if a value is output static void deparseOptTemp(DeparseState *state, char relpersistence) { switch (relpersistence) { case RELPERSISTENCE_PERMANENT: // Default break; case RELPERSISTENCE_UNLOGGED: deparseAppendStringInfoString(state, "UNLOGGED "); break; case RELPERSISTENCE_TEMP: deparseAppendStringInfoString(state, "TEMPORARY "); break; default: Assert(false); break; } } // "relation_expr_list" in gram.y static void deparseRelationExprList(DeparseState *state, List *relation_exprs) { ListCell *lc = NULL; foreach(lc, relation_exprs) { deparseRangeVar(state, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); if (lnext(relation_exprs, lc)) deparseAppendStringInfoString(state, ", "); } } // "handler_name" in gram.y static void deparseHandlerName(DeparseState *state, List *handler_name) { ListCell *lc = NULL; foreach(lc, handler_name) { deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc)))); if (lnext(handler_name, lc)) deparseAppendStringInfoChar(state, '.'); } } // "fdw_options" in gram.y static void deparseFdwOptions(DeparseState *state, 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) { deparseAppendStringInfoString(state, "HANDLER "); deparseHandlerName(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "handler") == 0 && def_elem->arg == NULL) { deparseAppendStringInfoString(state, "NO HANDLER "); } else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg != NULL) { deparseAppendStringInfoString(state, "VALIDATOR "); deparseHandlerName(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "validator") == 0 && def_elem->arg == NULL) { deparseAppendStringInfoString(state, "NO VALIDATOR "); } else { Assert(false); } if (lnext(fdw_options, lc)) deparseAppendStringInfoChar(state, ' '); } } // "type_list" in gram.y static void deparseTypeList(DeparseState *state, List *type_list) { ListCell *lc = NULL; foreach(lc, type_list) { deparseTypeName(state, castNode(TypeName, lfirst(lc))); if (lnext(type_list, lc)) deparseAppendStringInfoString(state, ", "); } } // "opt_boolean_or_string" in gram.y static void deparseOptBooleanOrString(DeparseState *state, char *s) { if (s == NULL) return; // No value set else if (strcmp(s, "true") == 0) deparseAppendStringInfoString(state, "TRUE"); else if (strcmp(s, "false") == 0) deparseAppendStringInfoString(state, "FALSE"); else if (strcmp(s, "on") == 0) deparseAppendStringInfoString(state, "ON"); else if (strcmp(s, "off") == 0) deparseAppendStringInfoString(state, "OFF"); else deparseNonReservedWordOrSconst(state, s); } static void deparseOptBoolean(DeparseState *state, Node *node) { if (node == NULL) { return; } switch (nodeTag(node)) { case T_String: deparseAppendStringInfo(state, " %s", strVal(node)); break; case T_Integer: deparseAppendStringInfo(state, " %d", intVal(node)); break; case T_Boolean: deparseAppendStringInfo(state, " %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(DeparseState *state, char *s) { deparseColId(state, s); } // "var_list" static void deparseVarList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { if (IsA(lfirst(lc), ParamRef)) { deparseParamRef(state, 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(state, (union ValUnion *) &a_const->val); else if (IsA(&a_const->val, String)) deparseOptBooleanOrString(state, strVal(&a_const->val)); else Assert(false); } else if (IsA(lfirst(lc), TypeCast)) { deparseTypeCast(state, castNode(TypeCast, lfirst(lc)), DEPARSE_NODE_CONTEXT_SET_STATEMENT); } else { Assert(false); } if (lnext(l, lc)) deparseAppendStringInfoString(state, ", "); } } // "transaction_mode_list" in gram.y static void deparseTransactionModeList(DeparseState *state, 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); deparseAppendStringInfoString(state, "ISOLATION LEVEL "); if (strcmp(s, "read uncommitted") == 0) deparseAppendStringInfoString(state, "READ UNCOMMITTED"); else if (strcmp(s, "read committed") == 0) deparseAppendStringInfoString(state, "READ COMMITTED"); else if (strcmp(s, "repeatable read") == 0) deparseAppendStringInfoString(state, "REPEATABLE READ"); else if (strcmp(s, "serializable") == 0) deparseAppendStringInfoString(state, "SERIALIZABLE"); else Assert(false); } else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) { deparseAppendStringInfoString(state, "READ ONLY"); } else if (strcmp(def_elem->defname, "transaction_read_only") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) { deparseAppendStringInfoString(state, "READ WRITE"); } else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 1) { deparseAppendStringInfoString(state, "DEFERRABLE"); } else if (strcmp(def_elem->defname, "transaction_deferrable") == 0 && intVal(&castNode(A_Const, def_elem->arg)->val) == 0) { deparseAppendStringInfoString(state, "NOT DEFERRABLE"); } else { Assert(false); } if (lnext(l, lc)) deparseAppendStringInfoString(state, ", "); } } // "alter_identity_column_option_list" in gram.y static void deparseAlterIdentityColumnOptionList(DeparseState *state, 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) { deparseAppendStringInfoString(state, "RESTART"); } else if (strcmp(def_elem->defname, "restart") == 0 && def_elem->arg != NULL) { deparseAppendStringInfoString(state, "RESTART "); deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (strcmp(def_elem->defname, "generated") == 0) { deparseAppendStringInfoString(state, "SET GENERATED "); if (def_elem->arg == NULL) elog(ERROR, "deparse: missing argument for identity generation specification"); if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_ALWAYS) deparseAppendStringInfoString(state, "ALWAYS"); else if (intVal(def_elem->arg) == ATTRIBUTE_IDENTITY_BY_DEFAULT) deparseAppendStringInfoString(state, "BY DEFAULT"); else Assert(false); } else { deparseAppendStringInfoString(state, "SET "); deparseSeqOptElem(state, def_elem); } if (lnext(l, lc)) deparseAppendStringInfoChar(state, ' '); } } // "reloptions" in gram.y static void deparseRelOptions(DeparseState *state, List *l) { ListCell *lc = NULL; deparseAppendStringInfoChar(state, '('); foreach(lc, l) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); if (def_elem->defnamespace != NULL) { deparseAppendStringInfoString(state, quote_identifier(def_elem->defnamespace)); deparseAppendStringInfoChar(state, '.'); } if (def_elem->defname != NULL) deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); if (def_elem->defname != NULL && def_elem->arg != NULL) deparseAppendStringInfoChar(state, '='); if (def_elem->arg != NULL) deparseDefArg(state, def_elem->arg, false); if (lnext(l, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); } // "OptWith" and "opt_reloptions" in gram.y // // Note this method adds a trailing space if a value is output static void deparseOptWith(DeparseState *state, List *l) { ListCell *lc = NULL; if (list_length(l) > 0) { deparseAppendStringInfoString(state, "WITH "); deparseRelOptions(state, l); deparseAppendStringInfoChar(state, ' '); } } // "target_list" and "opt_target_list" in gram.y static void deparseTargetList(DeparseState *state, 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(state, castNode(ColumnRef, res_target->val)); else deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); if (res_target->name != NULL) { deparseAppendStringInfoString(state, " AS "); deparseAppendStringInfoString(state, quote_identifier(res_target->name)); } if (lnext(l, lc)) deparseAppendCommaAndPart(state); } } // "insert_column_list" in gram.y static void deparseInsertColumnList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { ResTarget *res_target = castNode(ResTarget, lfirst(lc)); Assert(res_target->name != NULL); deparseAppendStringInfoString(state, quote_identifier(res_target->name)); deparseOptIndirection(state, res_target->indirection, 0); if (lnext(l, lc)) deparseAppendStringInfoString(state, ", "); } } // "xml_attribute_list" in gram.y static void deparseXmlAttributeList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { ResTarget *res_target = castNode(ResTarget, lfirst(lc)); Assert(res_target->val != NULL); deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); if (res_target->name != NULL) { deparseAppendStringInfoString(state, " AS "); deparseAppendStringInfoString(state, quote_identifier(res_target->name)); } if (lnext(l, lc)) deparseAppendStringInfoString(state, ", "); } } // "xml_namespace_list" in gram.y static void deparseXmlNamespaceList(DeparseState *state, 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) deparseAppendStringInfoString(state, "DEFAULT "); deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); if (res_target->name != NULL) { deparseAppendStringInfoString(state, " AS "); deparseAppendStringInfoString(state, quote_identifier(res_target->name)); } if (lnext(l, lc)) deparseAppendStringInfoString(state, ", "); } } // "table_ref" in gram.y static void deparseTableRef(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_RangeVar: deparseRangeVar(state, castNode(RangeVar, node), DEPARSE_NODE_CONTEXT_NONE); break; case T_RangeTableSample: deparseRangeTableSample(state, castNode(RangeTableSample, node)); break; case T_RangeFunction: deparseRangeFunction(state, castNode(RangeFunction, node)); break; case T_RangeTableFunc: deparseRangeTableFunc(state, castNode(RangeTableFunc, node)); break; case T_RangeSubselect: deparseRangeSubselect(state, castNode(RangeSubselect, node)); break; case T_JoinExpr: deparseJoinExpr(state, castNode(JoinExpr, node)); break; case T_JsonTable: deparseJsonTable(state, castNode(JsonTable, node)); break; default: Assert(false); } } // "from_list" in gram.y static void deparseFromList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { deparseTableRef(state, lfirst(lc)); if (lnext(l, lc)) deparseAppendCommaAndPart(state); } } // "from_clause" in gram.y // // Note this method adds a trailing space if a value is output static void deparseFromClause(DeparseState *state, List *l) { if (list_length(l) > 0) { deparseAppendPartGroup(state, "FROM", DEPARSE_PART_INDENT); deparseFromList(state, l); deparseAppendStringInfoChar(state, ' '); } } // "where_clause" in gram.y // // Note this method adds a trailing space if a value is output static void deparseWhereClause(DeparseState *state, Node *node) { if (node != NULL) { deparseAppendPartGroup(state, "WHERE", DEPARSE_PART_INDENT); deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ' '); } } // "where_or_current_clause" in gram.y // // Note this method adds a trailing space if a value is output static void deparseWhereOrCurrentClause(DeparseState *state, Node *node) { if (node == NULL) return; deparseAppendPartGroup(state, "WHERE", DEPARSE_PART_INDENT); if (IsA(node, CurrentOfExpr)) { CurrentOfExpr *current_of_expr = castNode(CurrentOfExpr, node); deparseAppendStringInfoString(state, "CURRENT OF "); deparseAppendStringInfoString(state, quote_identifier(current_of_expr->cursor_name)); } else { deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); } deparseAppendStringInfoChar(state, ' '); } // "group_by_list" in gram.y static void deparseGroupByList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { if (IsA(lfirst(lc), GroupingSet)) deparseGroupingSet(state, castNode(GroupingSet, lfirst(lc))); else deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); if (lnext(l, lc)) deparseAppendCommaAndPart(state); } } // "set_target" in gram.y static void deparseSetTarget(DeparseState *state, ResTarget *res_target) { Assert(res_target->name != NULL); deparseColId(state, res_target->name); deparseOptIndirection(state, res_target->indirection, 0); } // "any_name_list" in gram.y static void deparseAnyNameList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { deparseAnyName(state, castNode(List, lfirst(lc))); if (lnext(l, lc)) deparseAppendStringInfoString(state, ", "); } } // "name_list" in gram.y static void deparseNameList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { deparseColId(state, strVal(lfirst(lc))); if (lnext(l, lc)) deparseAppendStringInfoString(state, ", "); } } // "opt_sort_clause" and "json_array_aggregate_order_by_clause_opt" in gram.y // // Note this method adds a trailing space if a value is output static void deparseOptSortClause(DeparseState *state, List *l, DeparseNodeContext context) { ListCell *lc = NULL; if (list_length(l) > 0) { if (context == DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE) deparseAppendPartGroup(state, "ORDER BY", DEPARSE_PART_INDENT_AND_MERGE); else deparseAppendStringInfoString(state, "ORDER BY "); foreach(lc, l) { deparseSortBy(state, castNode(SortBy, lfirst(lc))); if (lnext(l, lc)) { if (context == DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE) deparseAppendCommaAndPart(state); else deparseAppendStringInfoString(state, ", "); } } deparseAppendStringInfoChar(state, ' '); } } // "func_arg_expr" in gram.y static void deparseFuncArgExpr(DeparseState *state, Node *node) { if (IsA(node, NamedArgExpr)) { NamedArgExpr *named_arg_expr = castNode(NamedArgExpr, node); deparseAppendStringInfoString(state, named_arg_expr->name); deparseAppendStringInfoString(state, " := "); deparseExpr(state, (Node *) named_arg_expr->arg, DEPARSE_NODE_CONTEXT_A_EXPR); } else { deparseExpr(state, node, DEPARSE_NODE_CONTEXT_A_EXPR); } } // "set_clause_list" in gram.y static void deparseSetClauseList(DeparseState *state, 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) deparseAppendCommaAndPart(state); 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); deparseAppendStringInfoString(state, "("); for_each_cell(lc2, target_list, lc) { deparseSetTarget(state, castNode(ResTarget, lfirst(lc2))); if ((foreach_current_index(lc2) - foreach_current_index(lc)) == r->ncolumns - 1) // Last element in this multi-assign break; else if (lnext(target_list, lc2)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, ") = "); deparseExpr(state, r->source, DEPARSE_NODE_CONTEXT_A_EXPR); skip_next_n_elems = r->ncolumns - 1; } else { deparseSetTarget(state, res_target); deparseAppendStringInfoString(state, " = "); deparseExpr(state, res_target->val, DEPARSE_NODE_CONTEXT_A_EXPR); } } } // "func_expr_windowless" in gram.y static void deparseFuncExprWindowless(DeparseState *state, Node* node) { switch (nodeTag(node)) { case T_FuncCall: deparseFuncCall(state, castNode(FuncCall, node), DEPARSE_NODE_CONTEXT_NONE /* we don't know which kind of expression */); break; case T_SQLValueFunction: deparseSQLValueFunction(state, castNode(SQLValueFunction, node)); break; case T_TypeCast: deparseTypeCast(state, castNode(TypeCast, node), DEPARSE_NODE_CONTEXT_FUNC_EXPR); break; case T_CoalesceExpr: deparseCoalesceExpr(state, castNode(CoalesceExpr, node)); break; case T_MinMaxExpr: deparseMinMaxExpr(state, castNode(MinMaxExpr, node)); break; case T_XmlExpr: deparseXmlExpr(state, castNode(XmlExpr, node), DEPARSE_NODE_CONTEXT_NONE /* we don't know which kind of expression */); break; case T_XmlSerialize: deparseXmlSerialize(state, 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(DeparseState *state, List *l) { if (list_length(l) > 0) { deparseAppendStringInfoString(state, "COLLATE "); deparseAnyName(state, l); deparseAppendStringInfoChar(state, ' '); } } // "index_elem" in gram.y static void deparseIndexElem(DeparseState *state, IndexElem* index_elem) { if (index_elem->name != NULL) { deparseColId(state, index_elem->name); deparseAppendStringInfoChar(state, ' '); } else if (index_elem->expr != NULL) { switch (nodeTag(index_elem->expr)) { // Simple function calls can be written without wrapping parens case T_FuncCall: // func_application case T_SQLValueFunction: // func_expr_common_subexpr case T_CoalesceExpr: // func_expr_common_subexpr case T_MinMaxExpr: // func_expr_common_subexpr case T_XmlExpr: // func_expr_common_subexpr case T_XmlSerialize: // func_expr_common_subexpr deparseFuncExprWindowless(state, index_elem->expr); deparseAppendStringInfoString(state, " "); break; default: deparseAppendStringInfoChar(state, '('); deparseExpr(state, index_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); } } else { Assert(false); } deparseOptCollate(state, index_elem->collation); if (list_length(index_elem->opclass) > 0) { deparseAnyName(state, index_elem->opclass); if (list_length(index_elem->opclassopts) > 0) deparseRelOptions(state, index_elem->opclassopts); deparseAppendStringInfoChar(state, ' '); } switch (index_elem->ordering) { case SORTBY_DEFAULT: // Default break; case SORTBY_ASC: deparseAppendStringInfoString(state, "ASC "); break; case SORTBY_DESC: deparseAppendStringInfoString(state, "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: deparseAppendStringInfoString(state, "NULLS FIRST "); break; case SORTBY_NULLS_LAST: deparseAppendStringInfoString(state, "NULLS LAST "); break; } removeTrailingSpace(state); } // "qualified_name_list" in gram.y static void deparseQualifiedNameList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach(lc, l) { deparseRangeVar(state, castNode(RangeVar, lfirst(lc)), DEPARSE_NODE_CONTEXT_NONE); if (lnext(l, lc)) deparseAppendStringInfoString(state, ", "); } } // "OptInherit" in gram.y // // Note this method adds a trailing space if a value is output static void deparseOptInherit(DeparseState *state, List *l) { if (list_length(l) > 0) { deparseAppendStringInfoString(state, "INHERITS ("); deparseQualifiedNameList(state, l); deparseAppendStringInfoString(state, ") "); } } // "privilege_target" in gram.y static void deparsePrivilegeTarget(DeparseState *state, GrantTargetType targtype, ObjectType objtype, List *objs) { switch (targtype) { case ACL_TARGET_OBJECT: switch (objtype) { case OBJECT_TABLE: deparseQualifiedNameList(state, objs); break; case OBJECT_SEQUENCE: deparseAppendStringInfoString(state, "SEQUENCE "); deparseQualifiedNameList(state, objs); break; case OBJECT_FDW: deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); deparseNameList(state, objs); break; case OBJECT_FOREIGN_SERVER: deparseAppendStringInfoString(state, "FOREIGN SERVER "); deparseNameList(state, objs); break; case OBJECT_FUNCTION: deparseAppendStringInfoString(state, "FUNCTION "); deparseFunctionWithArgtypesList(state, objs); break; case OBJECT_PROCEDURE: deparseAppendStringInfoString(state, "PROCEDURE "); deparseFunctionWithArgtypesList(state, objs); break; case OBJECT_ROUTINE: deparseAppendStringInfoString(state, "ROUTINE "); deparseFunctionWithArgtypesList(state, objs); break; case OBJECT_DATABASE: deparseAppendStringInfoString(state, "DATABASE "); deparseNameList(state, objs); break; case OBJECT_DOMAIN: deparseAppendStringInfoString(state, "DOMAIN "); deparseAnyNameList(state, objs); break; case OBJECT_LANGUAGE: deparseAppendStringInfoString(state, "LANGUAGE "); deparseNameList(state, objs); break; case OBJECT_LARGEOBJECT: deparseAppendStringInfoString(state, "LARGE OBJECT "); deparseNumericOnlyList(state, objs); break; case OBJECT_SCHEMA: deparseAppendStringInfoString(state, "SCHEMA "); deparseNameList(state, objs); break; case OBJECT_TABLESPACE: deparseAppendStringInfoString(state, "TABLESPACE "); deparseNameList(state, objs); break; case OBJECT_TYPE: deparseAppendStringInfoString(state, "TYPE "); deparseAnyNameList(state, objs); break; default: // Other types are not supported here Assert(false); break; } break; case ACL_TARGET_ALL_IN_SCHEMA: switch (objtype) { case OBJECT_TABLE: deparseAppendStringInfoString(state, "ALL TABLES IN SCHEMA "); deparseNameList(state, objs); break; case OBJECT_SEQUENCE: deparseAppendStringInfoString(state, "ALL SEQUENCES IN SCHEMA "); deparseNameList(state, objs); break; case OBJECT_FUNCTION: deparseAppendStringInfoString(state, "ALL FUNCTIONS IN SCHEMA "); deparseNameList(state, objs); break; case OBJECT_PROCEDURE: deparseAppendStringInfoString(state, "ALL PROCEDURES IN SCHEMA "); deparseNameList(state, objs); break; case OBJECT_ROUTINE: deparseAppendStringInfoString(state, "ALL ROUTINES IN SCHEMA "); deparseNameList(state, 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: deparseAppendStringInfoString(state, "TABLES"); break; case OBJECT_FUNCTION: deparseAppendStringInfoString(state, "FUNCTIONS"); break; case OBJECT_SEQUENCE: deparseAppendStringInfoString(state, "SEQUENCES"); break; case OBJECT_TYPE: deparseAppendStringInfoString(state, "TYPES"); break; case OBJECT_SCHEMA: deparseAppendStringInfoString(state, "SCHEMAS"); break; default: // Other types are not supported here Assert(false); break; } break; } } // "opclass_item_list" in gram.y static void deparseOpclassItemList(DeparseState *state, List *items) { ListCell *lc = NULL; foreach (lc, items) { deparseCreateOpClassItem(state, castNode(CreateOpClassItem, lfirst(lc))); if (lnext(items, lc)) deparseAppendStringInfoString(state, ", "); } } // "createdb_opt_list" in gram.y static void deparseCreatedbOptList(DeparseState *state, List *l) { ListCell *lc = NULL; foreach (lc, l) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); if (strcmp(def_elem->defname, "connection_limit") == 0) deparseAppendStringInfoString(state, "CONNECTION LIMIT"); else deparseGenericDefElemName(state, def_elem->defname); deparseAppendStringInfoChar(state, ' '); if (def_elem->arg == NULL) deparseAppendStringInfoString(state, "DEFAULT"); else if (IsA(def_elem->arg, Integer)) deparseSignedIconst(state, def_elem->arg); else if (IsA(def_elem->arg, String)) deparseOptBooleanOrString(state, strVal(def_elem->arg)); if (lnext(l, lc)) deparseAppendStringInfoChar(state, ' '); } } // "utility_option_list" in gram.y static void deparseUtilityOptionList(DeparseState *state, List *options) { ListCell *lc = NULL; char *defname = NULL; if (list_length(options) > 0) { deparseAppendStringInfoChar(state, '('); foreach(lc, options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); deparseGenericDefElemName(state, def_elem->defname); if (def_elem->arg != NULL) { deparseAppendStringInfoChar(state, ' '); if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) deparseNumericOnly(state, (union ValUnion *) def_elem->arg); else if (IsA(def_elem->arg, String)) deparseOptBooleanOrString(state, strVal(def_elem->arg)); else Assert(false); } if (lnext(options, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, ") "); } } static void deparseSelectStmt(DeparseState *state, SelectStmt *stmt, DeparseNodeContext context) { const ListCell *lc = NULL; const ListCell *lc2 = NULL; bool need_parens = context == DEPARSE_NODE_CONTEXT_SELECT_SETOP && ( list_length(stmt->sortClause) > 0 || stmt->limitOffset != NULL || stmt->limitCount != NULL || list_length(stmt->lockingClause) > 0 || stmt->withClause != NULL || stmt->op != SETOP_NONE); DeparseStateNestingLevel *parent_level = NULL; if (need_parens) { deparseAppendPart(state, true); deparseAppendStringInfoChar(state, '('); } if (need_parens || (context != DEPARSE_NODE_CONTEXT_SELECT_SETOP && context != DEPARSE_NODE_CONTEXT_INSERT_SELECT)) parent_level = deparseStateIncreaseNestingLevel(state); if (stmt->withClause) { deparseWithClause(state, stmt->withClause); deparseAppendStringInfoChar(state, ' '); } switch (stmt->op) { case SETOP_NONE: if (list_length(stmt->valuesLists) > 0) { const ListCell *lc; deparseAppendPartGroup(state, "VALUES", DEPARSE_PART_INDENT_AND_MERGE); foreach(lc, stmt->valuesLists) { deparseAppendStringInfoChar(state, '('); deparseExprList(state, lfirst(lc)); deparseAppendStringInfoChar(state, ')'); if (lnext(stmt->valuesLists, lc)) deparseAppendCommaAndPart(state); } deparseAppendStringInfoChar(state, ' '); break; } deparseAppendPartGroup(state, "SELECT", DEPARSE_PART_INDENT_AND_MERGE); if (list_length(stmt->targetList) > 0) { if (stmt->distinctClause != NULL) { deparseMarkCurrentPartNonMergable(state); deparseAppendStringInfoString(state, "DISTINCT "); if (list_length(stmt->distinctClause) > 0 && linitial(stmt->distinctClause) != NULL) { deparseAppendStringInfoString(state, "ON ("); deparseExprList(state, stmt->distinctClause); deparseAppendStringInfoString(state, ") "); } deparseAppendPart(state, true); } deparseTargetList(state, stmt->targetList); deparseAppendStringInfoChar(state, ' '); } if (stmt->intoClause != NULL) { deparseAppendPartGroup(state, "INTO", DEPARSE_PART_INDENT); deparseOptTemp(state, stmt->intoClause->rel->relpersistence); deparseIntoClause(state, stmt->intoClause); deparseAppendStringInfoChar(state, ' '); } deparseFromClause(state, stmt->fromClause); deparseWhereClause(state, stmt->whereClause); if (list_length(stmt->groupClause) > 0) { deparseAppendPartGroup(state, "GROUP BY", DEPARSE_PART_INDENT_AND_MERGE); if (stmt->groupDistinct) deparseAppendStringInfoString(state, "DISTINCT "); deparseGroupByList(state, stmt->groupClause); deparseAppendStringInfoChar(state, ' '); } if (stmt->havingClause != NULL) { deparseAppendPartGroup(state, "HAVING", DEPARSE_PART_INDENT); deparseExpr(state, stmt->havingClause, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ' '); } if (stmt->windowClause != NULL) { deparseAppendPartGroup(state, "WINDOW", DEPARSE_PART_INDENT); foreach(lc, stmt->windowClause) { WindowDef *window_def = castNode(WindowDef, lfirst(lc)); Assert(window_def->name != NULL); deparseAppendStringInfoString(state, window_def->name); deparseAppendStringInfoString(state, " AS "); deparseWindowDef(state, window_def); if (lnext(stmt->windowClause, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ' '); } break; case SETOP_UNION: case SETOP_INTERSECT: case SETOP_EXCEPT: { deparseSelectStmt(state, stmt->larg, DEPARSE_NODE_CONTEXT_SELECT_SETOP); switch (stmt->op) { case SETOP_UNION: if (stmt->all) deparseAppendPartGroup(state, "UNION ALL", DEPARSE_PART_NO_INDENT); else deparseAppendPartGroup(state, "UNION", DEPARSE_PART_NO_INDENT); break; case SETOP_INTERSECT: if (stmt->all) deparseAppendPartGroup(state, "INTERSECT ALL", DEPARSE_PART_NO_INDENT); else deparseAppendPartGroup(state, "INTERSECT", DEPARSE_PART_NO_INDENT); break; case SETOP_EXCEPT: if (stmt->all) deparseAppendPartGroup(state, "EXCEPT ALL", DEPARSE_PART_NO_INDENT); else deparseAppendPartGroup(state, "EXCEPT", DEPARSE_PART_NO_INDENT); break; default: Assert(false); } deparseAppendPart(state, true); deparseSelectStmt(state, stmt->rarg, DEPARSE_NODE_CONTEXT_SELECT_SETOP); deparseAppendStringInfoChar(state, ' '); } break; } deparseOptSortClause(state, stmt->sortClause, DEPARSE_NODE_CONTEXT_SELECT_SORT_CLAUSE); if (stmt->limitCount != NULL) { if (stmt->limitOption == LIMIT_OPTION_COUNT) deparseAppendPartGroup(state, "LIMIT", DEPARSE_PART_INDENT); else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) deparseAppendStringInfoString(state, "FETCH FIRST "); if (IsA(stmt->limitCount, A_Const) && castNode(A_Const, stmt->limitCount)->isnull) deparseAppendStringInfoString(state, "ALL"); else if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) deparseCExpr(state, stmt->limitCount); else deparseExpr(state, stmt->limitCount, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); deparseAppendStringInfoChar(state, ' '); if (stmt->limitOption == LIMIT_OPTION_WITH_TIES) deparseAppendStringInfoString(state, "ROWS WITH TIES "); } if (stmt->limitOffset != NULL) { deparseAppendPartGroup(state, "OFFSET", DEPARSE_PART_INDENT); deparseExpr(state, stmt->limitOffset, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ' '); } if (list_length(stmt->lockingClause) > 0) { foreach(lc, stmt->lockingClause) { deparseLockingClause(state, castNode(LockingClause, lfirst(lc))); if (lnext(stmt->lockingClause, lc)) deparseAppendStringInfoString(state, " "); } deparseAppendStringInfoChar(state, ' '); } removeTrailingSpace(state); /* Note that parent_level can be NULL, so we repeat the full if condition here */ if (need_parens || (context != DEPARSE_NODE_CONTEXT_SELECT_SETOP && context != DEPARSE_NODE_CONTEXT_INSERT_SELECT)) deparseStateDecreaseNestingLevel(state, parent_level); if (need_parens) deparseAppendStringInfoChar(state, ')'); } static void deparseIntoClause(DeparseState *state, IntoClause *into_clause) { ListCell *lc; deparseRangeVar(state, into_clause->rel, DEPARSE_NODE_CONTEXT_NONE); /* target relation name */ if (list_length(into_clause->colNames) > 0) { deparseAppendStringInfoChar(state, '('); deparseColumnList(state, into_clause->colNames); deparseAppendStringInfoChar(state, ')'); } deparseAppendStringInfoChar(state, ' '); if (into_clause->accessMethod != NULL) { deparseAppendStringInfoString(state, "USING "); deparseAppendStringInfoString(state, quote_identifier(into_clause->accessMethod)); deparseAppendStringInfoChar(state, ' '); } deparseOptWith(state, into_clause->options); switch (into_clause->onCommit) { case ONCOMMIT_NOOP: // No clause break; case ONCOMMIT_PRESERVE_ROWS: deparseAppendStringInfoString(state, "ON COMMIT PRESERVE ROWS "); break; case ONCOMMIT_DELETE_ROWS: deparseAppendStringInfoString(state, "ON COMMIT DELETE ROWS "); break; case ONCOMMIT_DROP: deparseAppendStringInfoString(state, "ON COMMIT DROP "); break; } if (into_clause->tableSpaceName != NULL) { deparseAppendStringInfoString(state, "TABLESPACE "); deparseAppendStringInfoString(state, quote_identifier(into_clause->tableSpaceName)); deparseAppendStringInfoChar(state, ' '); } removeTrailingSpace(state); } static void deparseRangeVar(DeparseState *state, RangeVar *range_var, DeparseNodeContext context) { if (!range_var->inh && context != DEPARSE_NODE_CONTEXT_CREATE_TYPE && context != DEPARSE_NODE_CONTEXT_ALTER_TYPE) deparseAppendStringInfoString(state, "ONLY "); if (range_var->catalogname != NULL) { deparseAppendStringInfoString(state, quote_identifier(range_var->catalogname)); deparseAppendStringInfoChar(state, '.'); } if (range_var->schemaname != NULL) { deparseAppendStringInfoString(state, quote_identifier(range_var->schemaname)); deparseAppendStringInfoChar(state, '.'); } Assert(range_var->relname != NULL); deparseAppendStringInfoString(state, quote_identifier(range_var->relname)); deparseAppendStringInfoChar(state, ' '); if (range_var->alias != NULL) { if (context == DEPARSE_NODE_CONTEXT_INSERT_RELATION) deparseAppendStringInfoString(state, "AS "); deparseAlias(state, range_var->alias); deparseAppendStringInfoChar(state, ' '); } removeTrailingSpace(state); } void deparseRawStmt(StringInfo str, struct RawStmt *raw_stmt) { PostgresDeparseOpts opts; MemSet(&opts, 0, sizeof(PostgresDeparseOpts)); // zero initialized means pretty print = false deparseRawStmtOpts(str, raw_stmt, opts); } void deparseRawStmtOpts(StringInfo str, struct RawStmt *raw_stmt, PostgresDeparseOpts opts) { DeparseState *state = NULL; if (raw_stmt->stmt == NULL) elog(ERROR, "deparse error in deparseRawStmt: RawStmt with empty Stmt"); state = palloc0(sizeof(DeparseState)); state->opts = opts; if (state->opts.indent_size == 0) state->opts.indent_size = 4; if (state->opts.max_line_length == 0) state->opts.max_line_length = 80; /* Check for any comments at the start of the statement */ if (state->opts.comment_count > 0) { /* * Filter out comments that are placed before this statement starts, this * avoids emitting comments multiple times in multi-statement queries. */ for (int i = 0; i < state->opts.comment_count; i++) { if (state->opts.comments[i]->match_location < raw_stmt->stmt_location) state->emitted_comments = bms_add_member(state->emitted_comments, i); } deparseStateIncreaseNestingLevel(state); deparseAppendCommentsIfNeeded(state, raw_stmt->stmt_location); deparseRemoveTrailingEmptyPart(state); deparseStateDecreaseNestingLevel(state, NULL); } deparseStmt(state, raw_stmt->stmt); deparseEmit(state, str); bms_free(state->emitted_comments); pfree(state); } static void deparseAlias(DeparseState *state, Alias *alias) { deparseAppendStringInfoString(state, quote_identifier(alias->aliasname)); if (list_length(alias->colnames) > 0) { const ListCell *lc = NULL; deparseAppendStringInfoChar(state, '('); deparseNameList(state, alias->colnames); deparseAppendStringInfoChar(state, ')'); } } static void deparseAConst(DeparseState *state, A_Const *a_const) { union ValUnion *val = a_const->isnull ? NULL : &a_const->val; deparseAppendCommentsIfNeeded(state, a_const->location); deparseValue(state, val, DEPARSE_NODE_CONTEXT_CONSTANT); } static void deparseFuncCall(DeparseState *state, FuncCall *func_call, DeparseNodeContext context) { 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) */ deparseAppendStringInfoString(state, "OVERLAY("); deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " PLACING "); deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " FROM "); deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " FOR "); deparseExpr(state, lfourth(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ')'); 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); deparseAppendStringInfoString(state, "SUBSTRING("); deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " FROM "); deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); if (list_length(func_call->args) == 3) { deparseAppendStringInfoString(state, " FOR "); deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); } deparseAppendStringInfoChar(state, ')'); 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 */ deparseAppendStringInfoString(state, "POSITION("); deparseBExpr(state, lsecond(func_call->args)); deparseAppendStringInfoString(state, " IN "); deparseBExpr(state, linitial(func_call->args)); deparseAppendStringInfoChar(state, ')'); 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) */ deparseAppendStringInfoString(state, "overlay("); deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " placing "); deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " from "); deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ')'); 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) */ deparseAppendStringInfoString(state, "collation for ("); deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ')'); 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) */ deparseAppendStringInfoString(state, "extract ("); deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " FROM "); deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ')'); 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) */ deparseAppendStringInfoChar(state, '('); deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ", "); deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); deparseAppendStringInfoString(state, "overlaps "); deparseAppendStringInfoChar(state, '('); deparseExpr(state, lthird(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ", "); deparseExpr(state, lfourth(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); 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); deparseAppendStringInfoString(state, "TRIM ("); if (strcmp(strVal(lsecond(func_call->funcname)), "ltrim") == 0) deparseAppendStringInfoString(state, "LEADING "); else if (strcmp(strVal(lsecond(func_call->funcname)), "btrim") == 0) deparseAppendStringInfoString(state, "BOTH "); else if (strcmp(strVal(lsecond(func_call->funcname)), "rtrim") == 0) deparseAppendStringInfoString(state, "TRAILING "); if (list_length(func_call->args) == 2) deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " FROM "); deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ')'); 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) > 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 */ Expr* e; bool isLocal = list_length(func_call->args) == 1; if (isLocal) e = linitial(func_call->args); else e = lsecond(func_call->args); // If we're not inside an a_expr context, we must add wrapping parenthesis around the AT ... syntax if (context != DEPARSE_NODE_CONTEXT_A_EXPR) { deparseAppendStringInfoChar(state, '('); } if (IsA(e, A_Expr)) { deparseAppendStringInfoChar(state, '('); } deparseExpr(state, (Node*) e, DEPARSE_NODE_CONTEXT_A_EXPR); if (IsA(e, A_Expr)) { deparseAppendStringInfoChar(state, ')'); } if (isLocal) deparseAppendStringInfoString(state, " AT LOCAL"); else { deparseAppendStringInfoString(state, " AT TIME ZONE "); deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); } if (context != DEPARSE_NODE_CONTEXT_A_EXPR) { deparseAppendStringInfoChar(state, ')'); } 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); deparseAppendStringInfoString(state, "normalize ("); deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); if (list_length(func_call->args) == 2) { deparseAppendStringInfoString(state, ", "); Assert(IsA(lsecond(func_call->args), A_Const)); A_Const *aconst = lsecond(func_call->args); deparseValue(state, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); } deparseAppendStringInfoChar(state, ')'); 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(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " IS "); if (list_length(func_call->args) == 2) { Assert(IsA(lsecond(func_call->args), A_Const)); A_Const *aconst = lsecond(func_call->args); deparseValue(state, &aconst->val, DEPARSE_NODE_CONTEXT_NONE); } deparseAppendStringInfoString(state, " 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) { deparseAppendStringInfoString(state, "xmlexists ("); deparseExpr(state, linitial(func_call->args), DEPARSE_NODE_CONTEXT_NONE /* c_expr */); deparseAppendStringInfoString(state, " PASSING "); deparseExpr(state, lsecond(func_call->args), DEPARSE_NODE_CONTEXT_NONE /* c_expr */); deparseAppendStringInfoChar(state, ')'); 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)), "system_user") == 0) { deparseAppendStringInfoString(state, "SYSTEM_USER"); return; } deparseFuncName(state, func_call->funcname); deparseAppendStringInfoChar(state, '('); if (func_call->agg_distinct) deparseAppendStringInfoString(state, "DISTINCT "); if (func_call->agg_star) { deparseAppendStringInfoChar(state, '*'); } else if (list_length(func_call->args) > 0) { foreach(lc, func_call->args) { if (func_call->func_variadic && !lnext(func_call->args, lc)) deparseAppendStringInfoString(state, "VARIADIC "); deparseFuncArgExpr(state, lfirst(lc)); if (lnext(func_call->args, lc)) deparseAppendStringInfoString(state, ", "); } } deparseAppendStringInfoChar(state, ' '); if (func_call->agg_order != NULL && !func_call->agg_within_group) { deparseOptSortClause(state, func_call->agg_order, DEPARSE_NODE_CONTEXT_NONE); } removeTrailingSpace(state); deparseAppendStringInfoString(state, ") "); if (func_call->agg_order != NULL && func_call->agg_within_group) { deparseAppendStringInfoString(state, "WITHIN GROUP ("); deparseOptSortClause(state, func_call->agg_order, DEPARSE_NODE_CONTEXT_NONE); removeTrailingSpace(state); deparseAppendStringInfoString(state, ") "); } if (func_call->agg_filter) { deparseAppendStringInfoString(state, "FILTER (WHERE "); deparseExpr(state, func_call->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); } if (func_call->over) { deparseAppendStringInfoString(state, "OVER "); if (func_call->over->name) deparseAppendStringInfoString(state, func_call->over->name); else deparseWindowDef(state, func_call->over); } removeTrailingSpace(state); } static void deparseWindowDef(DeparseState *state, WindowDef* window_def) { ListCell *lc; DeparseStateNestingLevel *parent_level = NULL; // The parent node is responsible for outputting window_def->name // Special case completely empty window clauses and return early if (!window_def->refname && list_length(window_def->partitionClause) == 0 && list_length(window_def->orderClause) == 0 && !(window_def->frameOptions & FRAMEOPTION_NONDEFAULT)) { deparseAppendStringInfoString(state, "()"); return; } deparseAppendStringInfoChar(state, '('); parent_level = deparseStateIncreaseNestingLevel(state); if (window_def->refname != NULL) { deparseAppendStringInfoString(state, quote_identifier(window_def->refname)); deparseAppendStringInfoChar(state, ' '); } if (list_length(window_def->partitionClause) > 0) { deparseAppendStringInfoString(state, "PARTITION BY "); deparseExprList(state, window_def->partitionClause); deparseAppendStringInfoChar(state, ' '); } removeTrailingSpace(state); deparseAppendPart(state, true); deparseOptSortClause(state, window_def->orderClause, DEPARSE_NODE_CONTEXT_NONE); if (window_def->frameOptions & FRAMEOPTION_NONDEFAULT) { deparseAppendPartGroup(state, NULL, DEPARSE_PART_NO_INDENT); if (window_def->frameOptions & FRAMEOPTION_RANGE) deparseAppendStringInfoString(state, "RANGE "); else if (window_def->frameOptions & FRAMEOPTION_ROWS) deparseAppendStringInfoString(state, "ROWS "); else if (window_def->frameOptions & FRAMEOPTION_GROUPS) deparseAppendStringInfoString(state, "GROUPS "); if (window_def->frameOptions & FRAMEOPTION_BETWEEN) deparseAppendStringInfoString(state, "BETWEEN "); // frame_start if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING) { deparseAppendStringInfoString(state, "UNBOUNDED PRECEDING "); } else if (window_def->frameOptions & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) { Assert(false); // disallowed } else if (window_def->frameOptions & FRAMEOPTION_START_CURRENT_ROW) { deparseAppendStringInfoString(state, "CURRENT ROW "); } else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING) { Assert(window_def->startOffset != NULL); deparseExpr(state, window_def->startOffset, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " PRECEDING "); } else if (window_def->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING) { Assert(window_def->startOffset != NULL); deparseExpr(state, window_def->startOffset, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " FOLLOWING "); } if (window_def->frameOptions & FRAMEOPTION_BETWEEN) { deparseAppendStringInfoString(state, "AND "); // frame_end if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING) { Assert(false); // disallowed } else if (window_def->frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) { deparseAppendStringInfoString(state, "UNBOUNDED FOLLOWING "); } else if (window_def->frameOptions & FRAMEOPTION_END_CURRENT_ROW) { deparseAppendStringInfoString(state, "CURRENT ROW "); } else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING) { Assert(window_def->endOffset != NULL); deparseExpr(state, window_def->endOffset, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " PRECEDING "); } else if (window_def->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING) { Assert(window_def->endOffset != NULL); deparseExpr(state, window_def->endOffset, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " FOLLOWING "); } } if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW) deparseAppendStringInfoString(state, "EXCLUDE CURRENT ROW "); else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_GROUP) deparseAppendStringInfoString(state, "EXCLUDE GROUP "); else if (window_def->frameOptions & FRAMEOPTION_EXCLUDE_TIES) deparseAppendStringInfoString(state, "EXCLUDE TIES "); } removeTrailingSpace(state); deparseStateDecreaseNestingLevel(state, parent_level); deparseAppendStringInfoChar(state, ')'); } static void deparseColumnRef(DeparseState *state, ColumnRef* column_ref) { Assert(list_length(column_ref->fields) >= 1); deparseAppendCommentsIfNeeded(state, column_ref->location); if (IsA(linitial(column_ref->fields), A_Star)) deparseAStar(state, castNode(A_Star, linitial(column_ref->fields))); else if (IsA(linitial(column_ref->fields), String)) deparseColLabel(state, strVal(linitial(column_ref->fields))); deparseOptIndirection(state, column_ref->fields, 1); } static void deparseSubLink(DeparseState *state, SubLink* sub_link) { switch (sub_link->subLinkType) { case EXISTS_SUBLINK: deparseAppendStringInfoString(state, "EXISTS ("); deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ')'); return; case ALL_SUBLINK: deparseExpr(state, sub_link->testexpr, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ' '); deparseSubqueryOp(state, sub_link->operName); deparseAppendStringInfoString(state, " ALL ("); deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ')'); return; case ANY_SUBLINK: deparseExpr(state, sub_link->testexpr, DEPARSE_NODE_CONTEXT_A_EXPR); if (list_length(sub_link->operName) > 0) { deparseAppendStringInfoChar(state, ' '); deparseSubqueryOp(state, sub_link->operName); deparseAppendStringInfoString(state, " ANY "); } else { deparseAppendStringInfoString(state, " IN "); } deparseAppendStringInfoChar(state, '('); deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ')'); return; case ROWCOMPARE_SUBLINK: // Not present in raw parse trees Assert(false); return; case EXPR_SUBLINK: deparseAppendStringInfoString(state, "("); deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ')'); return; case MULTIEXPR_SUBLINK: // Not present in raw parse trees Assert(false); return; case ARRAY_SUBLINK: deparseAppendStringInfoString(state, "ARRAY("); deparseSelectStmt(state, castNode(SelectStmt, sub_link->subselect), DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ')'); return; case CTE_SUBLINK: /* for SubPlans only */ // Not present in raw parse trees Assert(false); return; } } // Checks whether a node needs parens when used in a "b_expr" context (because the node is handled by the "a_expr" rule in gram.y) static bool needsParensAsBExpr(Node *node) { if (node == NULL) return false; return IsA(node, BoolExpr) || IsA(node, BooleanTest) || IsA(node, NullTest) || IsA(node, A_Expr); } // This handles "A_Expr" parse tree objects, which are a subset of the rules in "a_expr" (handled by deparseExpr) static void deparseAExpr(DeparseState *state, A_Expr* a_expr, DeparseNodeContext context) { ListCell *lc; char *name; bool need_lexpr_parens = needsParensAsBExpr(a_expr->lexpr); bool need_rexpr_parens = needsParensAsBExpr(a_expr->rexpr); switch (a_expr->kind) { case AEXPR_OP: /* normal operator */ { if (a_expr->lexpr != NULL) { if (need_lexpr_parens) deparseAppendStringInfoChar(state, '('); deparseExpr(state, a_expr->lexpr, context); if (need_lexpr_parens) deparseAppendStringInfoChar(state, ')'); deparseAppendStringInfoChar(state, ' '); } deparseQualOp(state, a_expr->name); if (a_expr->rexpr != NULL) { deparseAppendStringInfoChar(state, ' '); if (need_rexpr_parens) deparseAppendStringInfoChar(state, '('); deparseExpr(state, a_expr->rexpr, context); if (need_rexpr_parens) deparseAppendStringInfoChar(state, ')'); } } return; case AEXPR_OP_ANY: /* scalar op ANY (array) */ deparseExpr(state, a_expr->lexpr, context); deparseAppendStringInfoChar(state, ' '); deparseSubqueryOp(state, a_expr->name); deparseAppendStringInfoString(state, " ANY("); deparseExpr(state, a_expr->rexpr, context); deparseAppendStringInfoChar(state, ')'); return; case AEXPR_OP_ALL: /* scalar op ALL (array) */ deparseExpr(state, a_expr->lexpr, context); deparseAppendStringInfoChar(state, ' '); deparseSubqueryOp(state, a_expr->name); deparseAppendStringInfoString(state, " ALL("); deparseExpr(state, a_expr->rexpr, context); deparseAppendStringInfoChar(state, ')'); 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) deparseAppendStringInfoChar(state, '('); deparseExpr(state, a_expr->lexpr, context); if (need_lexpr_parens) deparseAppendStringInfoChar(state, ')'); deparseAppendStringInfoString(state, " IS DISTINCT FROM "); if (need_rexpr_parens) deparseAppendStringInfoChar(state, '('); deparseExpr(state, a_expr->rexpr, context); if (need_rexpr_parens) deparseAppendStringInfoChar(state, ')'); 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(state, a_expr->lexpr, context); deparseAppendStringInfoString(state, " IS NOT DISTINCT FROM "); deparseExpr(state, a_expr->rexpr, context); 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); deparseAppendStringInfoString(state, "NULLIF("); deparseExpr(state, a_expr->lexpr, context); deparseAppendStringInfoString(state, ", "); deparseExpr(state, a_expr->rexpr, context); deparseAppendStringInfoChar(state, ')'); 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(state, a_expr->lexpr, context); deparseAppendStringInfoChar(state, ' '); name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; if (strcmp(name, "=") == 0) { deparseAppendStringInfoString(state, "IN "); } else if (strcmp(name, "<>") == 0) { deparseAppendStringInfoString(state, "NOT IN "); } else { Assert(false); } deparseAppendStringInfoChar(state, '('); if (IsA(a_expr->rexpr, SubLink)) deparseSubLink(state, castNode(SubLink, a_expr->rexpr)); else deparseExprList(state, castNode(List, a_expr->rexpr)); deparseAppendStringInfoChar(state, ')'); 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(state, a_expr->lexpr, context); deparseAppendStringInfoChar(state, ' '); name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; if (strcmp(name, "~~") == 0) { deparseAppendStringInfoString(state, "LIKE "); } else if (strcmp(name, "!~~") == 0) { deparseAppendStringInfoString(state, "NOT LIKE "); } else { Assert(false); } deparseExpr(state, a_expr->rexpr, context); 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(state, a_expr->lexpr, context); deparseAppendStringInfoChar(state, ' '); name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; if (strcmp(name, "~~*") == 0) { deparseAppendStringInfoString(state, "ILIKE "); } else if (strcmp(name, "!~~*") == 0) { deparseAppendStringInfoString(state, "NOT ILIKE "); } else { Assert(false); } deparseExpr(state, a_expr->rexpr, context); 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(state, a_expr->lexpr, context); deparseAppendStringInfoChar(state, ' '); name = ((union ValUnion *) linitial(a_expr->name))->sval.sval; if (strcmp(name, "~") == 0) { deparseAppendStringInfoString(state, "SIMILAR TO "); } else if (strcmp(name, "!~") == 0) { deparseAppendStringInfoString(state, "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(state, linitial(n->args), context); if (list_length(n->args) == 2) { deparseAppendStringInfoString(state, " ESCAPE "); deparseExpr(state, lsecond(n->args), context); } 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(state, a_expr->lexpr, context); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, strVal(linitial(a_expr->name))); deparseAppendStringInfoChar(state, ' '); foreach(lc, castNode(List, a_expr->rexpr)) { deparseExpr(state, lfirst(lc), context); if (lnext(castNode(List, a_expr->rexpr), lc)) deparseAppendStringInfoString(state, " AND "); } return; } } static void deparseBoolExpr(DeparseState *state, 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) deparseAppendStringInfoChar(state, '('); deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); if (need_parens) deparseAppendStringInfoChar(state, ')'); if (lnext(bool_expr->args, lc)) { deparseAppendPart(state, true); deparseAppendStringInfoString(state, "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) deparseAppendStringInfoChar(state, '('); deparseExpr(state, lfirst(lc), DEPARSE_NODE_CONTEXT_A_EXPR); if (need_parens) deparseAppendStringInfoChar(state, ')'); if (lnext(bool_expr->args, lc)) deparseAppendStringInfoString(state, " 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); deparseAppendStringInfoString(state, "NOT "); if (need_parens) deparseAppendStringInfoChar(state, '('); deparseExpr(state, linitial(bool_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); if (need_parens) deparseAppendStringInfoChar(state, ')'); return; } } static void deparseAStar(DeparseState *state, A_Star *a_star) { deparseAppendStringInfoChar(state, '*'); } static void deparseCollateClause(DeparseState *state, CollateClause* collate_clause) { ListCell *lc; if (collate_clause->arg != NULL) { bool need_parens = IsA(collate_clause->arg, A_Expr); if (need_parens) deparseAppendStringInfoChar(state, '('); deparseExpr(state, collate_clause->arg, DEPARSE_NODE_CONTEXT_A_EXPR); if (need_parens) deparseAppendStringInfoChar(state, ')'); deparseAppendStringInfoChar(state, ' '); } deparseAppendStringInfoString(state, "COLLATE "); deparseAnyName(state, collate_clause->collname); } // "sortby" in gram.y static void deparseSortBy(DeparseState *state, SortBy* sort_by) { deparseExpr(state, sort_by->node, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ' '); switch (sort_by->sortby_dir) { case SORTBY_DEFAULT: break; case SORTBY_ASC: deparseAppendStringInfoString(state, "ASC "); break; case SORTBY_DESC: deparseAppendStringInfoString(state, "DESC "); break; case SORTBY_USING: deparseAppendStringInfoString(state, "USING "); deparseQualOp(state, sort_by->useOp); break; } switch (sort_by->sortby_nulls) { case SORTBY_NULLS_DEFAULT: break; case SORTBY_NULLS_FIRST: deparseAppendStringInfoString(state, "NULLS FIRST "); break; case SORTBY_NULLS_LAST: deparseAppendStringInfoString(state, "NULLS LAST "); break; } removeTrailingSpace(state); } static void deparseParamRef(DeparseState *state, ParamRef* param_ref) { if (param_ref->number == 0) { deparseAppendStringInfoChar(state, '?'); } else { deparseAppendStringInfo(state, "$%d", param_ref->number); } } static void deparseSQLValueFunction(DeparseState *state, SQLValueFunction* sql_value_function) { switch (sql_value_function->op) { case SVFOP_CURRENT_DATE: deparseAppendStringInfoString(state, "current_date"); break; case SVFOP_CURRENT_TIME: deparseAppendStringInfoString(state, "current_time"); break; case SVFOP_CURRENT_TIME_N: deparseAppendStringInfoString(state, "current_time"); // with precision break; case SVFOP_CURRENT_TIMESTAMP: deparseAppendStringInfoString(state, "current_timestamp"); break; case SVFOP_CURRENT_TIMESTAMP_N: deparseAppendStringInfoString(state, "current_timestamp"); // with precision break; case SVFOP_LOCALTIME: deparseAppendStringInfoString(state, "localtime"); break; case SVFOP_LOCALTIME_N: deparseAppendStringInfoString(state, "localtime"); // with precision break; case SVFOP_LOCALTIMESTAMP: deparseAppendStringInfoString(state, "localtimestamp"); break; case SVFOP_LOCALTIMESTAMP_N: deparseAppendStringInfoString(state, "localtimestamp"); // with precision break; case SVFOP_CURRENT_ROLE: deparseAppendStringInfoString(state, "current_role"); break; case SVFOP_CURRENT_USER: deparseAppendStringInfoString(state, "current_user"); break; case SVFOP_USER: deparseAppendStringInfoString(state, "user"); break; case SVFOP_SESSION_USER: deparseAppendStringInfoString(state, "session_user"); break; case SVFOP_CURRENT_CATALOG: deparseAppendStringInfoString(state, "current_catalog"); break; case SVFOP_CURRENT_SCHEMA: deparseAppendStringInfoString(state, "current_schema"); break; } if (sql_value_function->typmod != -1) { deparseAppendStringInfo(state, "(%d)", sql_value_function->typmod); } } static void deparseWithClause(DeparseState *state, WithClause *with_clause) { ListCell *lc; deparseAppendPartGroup(state, "WITH", DEPARSE_PART_NO_INDENT); if (with_clause->recursive) deparseAppendStringInfoString(state, "RECURSIVE "); foreach(lc, with_clause->ctes) { deparseCommonTableExpr(state, castNode(CommonTableExpr, lfirst(lc))); if (lnext(with_clause->ctes, lc)) deparseAppendStringInfoString(state, ", "); } removeTrailingSpace(state); } // "joined_table" in gram.y static void deparseJoinExpr(DeparseState *state, 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) deparseAppendStringInfoChar(state, '('); deparseTableRef(state, join_expr->larg); deparseAppendPart(state, true); if (join_expr->isNatural) deparseAppendStringInfoString(state, "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) deparseAppendStringInfoString(state, "CROSS "); break; case JOIN_LEFT: /* pairs + unmatched LHS tuples */ deparseAppendStringInfoString(state, "LEFT "); break; case JOIN_FULL: /* pairs + unmatched LHS + unmatched RHS */ deparseAppendStringInfoString(state, "FULL "); break; case JOIN_RIGHT: /* pairs + unmatched RHS tuples */ deparseAppendStringInfoString(state, "RIGHT "); break; case JOIN_SEMI: case JOIN_ANTI: case JOIN_RIGHT_ANTI: case JOIN_UNIQUE_OUTER: case JOIN_UNIQUE_INNER: // Only used by the planner/executor, not seen in parser output Assert(false); break; } deparseAppendStringInfoString(state, "JOIN "); if (need_rarg_parens) deparseAppendStringInfoChar(state, '('); deparseTableRef(state, join_expr->rarg); if (need_rarg_parens) deparseAppendStringInfoChar(state, ')'); deparseAppendStringInfoChar(state, ' '); if (join_expr->quals != NULL) { deparseAppendStringInfoString(state, "ON "); deparseExpr(state, join_expr->quals, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ' '); } if (list_length(join_expr->usingClause) > 0) { deparseAppendStringInfoString(state, "USING ("); deparseNameList(state, join_expr->usingClause); deparseAppendStringInfoString(state, ") "); if (join_expr->join_using_alias) { deparseAppendStringInfoString(state, "AS "); deparseAppendStringInfoString(state, join_expr->join_using_alias->aliasname); } } if (need_alias_parens) deparseAppendStringInfoString(state, ") "); if (join_expr->alias != NULL) deparseAlias(state, join_expr->alias); removeTrailingSpace(state); } static void deparseCTESearchClause(DeparseState *state, CTESearchClause *search_clause) { deparseAppendStringInfoString(state, " SEARCH "); if (search_clause->search_breadth_first) deparseAppendStringInfoString(state, "BREADTH "); else deparseAppendStringInfoString(state, "DEPTH "); deparseAppendStringInfoString(state, "FIRST BY "); if (search_clause->search_col_list) deparseColumnList(state, search_clause->search_col_list); deparseAppendStringInfoString(state, " SET "); deparseAppendStringInfoString(state, quote_identifier(search_clause->search_seq_column)); } // "opt_cycle_clause" in gram.y static void deparseCTECycleClause(DeparseState *state, CTECycleClause *cycle_clause) { deparseAppendStringInfoString(state, " CYCLE "); if (cycle_clause->cycle_col_list) deparseColumnList(state, cycle_clause->cycle_col_list); deparseAppendStringInfoString(state, " SET "); deparseAppendStringInfoString(state, quote_identifier(cycle_clause->cycle_mark_column)); if (cycle_clause->cycle_mark_value) { deparseAppendStringInfoString(state, " TO "); deparseAexprConst(state, cycle_clause->cycle_mark_value); } if (cycle_clause->cycle_mark_default) { deparseAppendStringInfoString(state, " DEFAULT "); deparseAexprConst(state, cycle_clause->cycle_mark_default); } deparseAppendStringInfoString(state, " USING "); deparseAppendStringInfoString(state, quote_identifier(cycle_clause->cycle_path_column)); } static void deparseCommonTableExpr(DeparseState *state, CommonTableExpr *cte) { deparseAppendCommentsIfNeeded(state, cte->location); deparseColId(state, cte->ctename); if (list_length(cte->aliascolnames) > 0) { deparseAppendStringInfoChar(state, '('); deparseNameList(state, cte->aliascolnames); deparseAppendStringInfoChar(state, ')'); } deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "AS "); switch (cte->ctematerialized) { case CTEMaterializeDefault: /* no option specified */ break; case CTEMaterializeAlways: deparseAppendStringInfoString(state, "MATERIALIZED "); break; case CTEMaterializeNever: deparseAppendStringInfoString(state, "NOT MATERIALIZED "); break; } deparseAppendStringInfoChar(state, '('); deparsePreparableStmt(state, cte->ctequery); deparseAppendStringInfoChar(state, ')'); if (cte->search_clause) deparseCTESearchClause(state, cte->search_clause); if (cte->cycle_clause) deparseCTECycleClause(state, cte->cycle_clause); } static void deparseRangeSubselect(DeparseState *state, RangeSubselect *range_subselect) { if (range_subselect->lateral) deparseAppendStringInfoString(state, "LATERAL "); deparseAppendStringInfoChar(state, '('); deparseSelectStmt(state, castNode(SelectStmt, range_subselect->subquery), DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ')'); if (range_subselect->alias != NULL) { deparseAppendStringInfoChar(state, ' '); deparseAlias(state, range_subselect->alias); } } static void deparseRangeFunction(DeparseState *state, RangeFunction *range_func) { ListCell *lc; ListCell *lc2; if (range_func->lateral) deparseAppendStringInfoString(state, "LATERAL "); if (range_func->is_rowsfrom) { deparseAppendStringInfoString(state, "ROWS FROM "); deparseAppendStringInfoChar(state, '('); foreach(lc, range_func->functions) { List *lfunc = castNode(List, lfirst(lc)); Assert(list_length(lfunc) == 2); deparseFuncExprWindowless(state, linitial(lfunc)); deparseAppendStringInfoChar(state, ' '); List *coldeflist = castNode(List, lsecond(lfunc)); if (list_length(coldeflist) > 0) { deparseAppendStringInfoString(state, "AS ("); foreach(lc2, coldeflist) { deparseColumnDef(state, castNode(ColumnDef, lfirst(lc2))); if (lnext(coldeflist, lc2)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); } if (lnext(range_func->functions, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); } else { Assert(list_length(linitial(range_func->functions)) == 2); deparseFuncExprWindowless(state, linitial(linitial(range_func->functions))); } deparseAppendStringInfoChar(state, ' '); if (range_func->ordinality) deparseAppendStringInfoString(state, "WITH ORDINALITY "); if (range_func->alias != NULL) { deparseAlias(state, range_func->alias); deparseAppendStringInfoChar(state, ' '); } if (list_length(range_func->coldeflist) > 0) { if (range_func->alias == NULL) deparseAppendStringInfoString(state, "AS "); deparseAppendStringInfoChar(state, '('); foreach(lc, range_func->coldeflist) { deparseColumnDef(state, castNode(ColumnDef, lfirst(lc))); if (lnext(range_func->coldeflist, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); } removeTrailingSpace(state); } static void deparseAArrayExpr(DeparseState *state, A_ArrayExpr *array_expr) { ListCell *lc; deparseAppendStringInfoString(state, "ARRAY["); deparseExprList(state, array_expr->elements); deparseAppendStringInfoChar(state, ']'); } static void deparseRowExpr(DeparseState *state, RowExpr *row_expr) { ListCell *lc; switch (row_expr->row_format) { case COERCE_EXPLICIT_CALL: deparseAppendStringInfoString(state, "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; } deparseAppendStringInfoString(state, "("); deparseExprList(state, row_expr->args); deparseAppendStringInfoChar(state, ')'); } static void deparseTypeCast(DeparseState *state, TypeCast *type_cast, DeparseNodeContext context) { bool need_parens = needsParensAsBExpr(type_cast->arg); Assert(type_cast->typeName != NULL); if (context == DEPARSE_NODE_CONTEXT_FUNC_EXPR) { deparseAppendStringInfoString(state, "CAST("); deparseExpr(state, type_cast->arg, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " AS "); deparseTypeName(state, type_cast->typeName); deparseAppendStringInfoChar(state, ')'); 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) { deparseAppendStringInfoString(state, "char "); deparseAConst(state, 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) { deparseAppendStringInfoString(state, "true"); return; } if (strcmp(const_val, "f") == 0) { deparseAppendStringInfoString(state, "false"); return; } } else if (strcmp(typename, "interval") == 0 && context == DEPARSE_NODE_CONTEXT_SET_STATEMENT && IsA(&a_const->val, String)) { deparseAppendStringInfoString(state, "interval "); deparseAConst(state, a_const); deparseIntervalTypmods(state, 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) { deparseAppendStringInfoString(state, " point "); deparseAConst(state, a_const); return; } } if (need_parens) deparseAppendStringInfoChar(state, '('); deparseExpr(state, type_cast->arg, DEPARSE_NODE_CONTEXT_NONE /* could be either a_expr or b_expr (we could pass this down, but that'd require two kinds of contexts most likely) */); if (need_parens) deparseAppendStringInfoChar(state, ')'); deparseAppendStringInfoString(state, "::"); deparseTypeName(state, type_cast->typeName); } static void deparseTypeName(DeparseState *state, TypeName *type_name) { ListCell *lc; bool skip_typmods = false; if (type_name->setof) deparseAppendStringInfoString(state, "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) { deparseAppendStringInfoString(state, "char"); } else if (strcmp(name, "varchar") == 0) { deparseAppendStringInfoString(state, "varchar"); } else if (strcmp(name, "numeric") == 0) { deparseAppendStringInfoString(state, "numeric"); } else if (strcmp(name, "bool") == 0) { deparseAppendStringInfoString(state, "boolean"); } else if (strcmp(name, "int2") == 0) { deparseAppendStringInfoString(state, "smallint"); } else if (strcmp(name, "int4") == 0) { deparseAppendStringInfoString(state, "int"); } else if (strcmp(name, "int8") == 0) { deparseAppendStringInfoString(state, "bigint"); } else if (strcmp(name, "real") == 0 || strcmp(name, "float4") == 0) { deparseAppendStringInfoString(state, "real"); } else if (strcmp(name, "float8") == 0) { deparseAppendStringInfoString(state, "double precision"); } else if (strcmp(name, "time") == 0) { deparseAppendStringInfoString(state, "time"); } else if (strcmp(name, "timetz") == 0) { deparseAppendStringInfoString(state, "time "); if (list_length(type_name->typmods) > 0) { deparseAppendStringInfoChar(state, '('); foreach(lc, type_name->typmods) { deparseSignedIconst(state, (Node *) &castNode(A_Const, lfirst(lc))->val); if (lnext(type_name->typmods, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, ") "); } deparseAppendStringInfoString(state, "with time zone"); skip_typmods = true; } else if (strcmp(name, "timestamp") == 0) { deparseAppendStringInfoString(state, "timestamp"); } else if (strcmp(name, "timestamptz") == 0) { deparseAppendStringInfoString(state, "timestamp "); if (list_length(type_name->typmods) > 0) { deparseAppendStringInfoChar(state, '('); foreach(lc, type_name->typmods) { deparseSignedIconst(state, (Node *) &castNode(A_Const, lfirst(lc))->val); if (lnext(type_name->typmods, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, ") "); } deparseAppendStringInfoString(state, "with time zone"); skip_typmods = true; } else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) == 0) { deparseAppendStringInfoString(state, "interval"); } else if (strcmp(name, "interval") == 0 && list_length(type_name->typmods) >= 1) { deparseAppendStringInfoString(state, "interval"); deparseIntervalTypmods(state, type_name); skip_typmods = true; } else { deparseAppendStringInfoString(state, "pg_catalog."); deparseAppendStringInfoString(state, name); } } else { deparseAnyName(state, type_name->names); } if (list_length(type_name->typmods) > 0 && !skip_typmods) { deparseAppendStringInfoChar(state, '('); foreach(lc, type_name->typmods) { if (IsA(lfirst(lc), A_Const)) deparseAConst(state, lfirst(lc)); else if (IsA(lfirst(lc), ParamRef)) deparseParamRef(state, lfirst(lc)); else if (IsA(lfirst(lc), ColumnRef)) deparseColumnRef(state, lfirst(lc)); else Assert(false); if (lnext(type_name->typmods, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); } foreach(lc, type_name->arrayBounds) { deparseAppendStringInfoChar(state, '['); if (IsA(lfirst(lc), Integer) && intVal(lfirst(lc)) != -1) deparseSignedIconst(state, lfirst(lc)); deparseAppendStringInfoChar(state, ']'); } if (type_name->pct_type) deparseAppendStringInfoString(state, "%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(DeparseState *state, 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): deparseAppendStringInfoString(state, " year"); break; case INTERVAL_MASK(MONTH): deparseAppendStringInfoString(state, " month"); break; case INTERVAL_MASK(DAY): deparseAppendStringInfoString(state, " day"); break; case INTERVAL_MASK(HOUR): deparseAppendStringInfoString(state, " hour"); break; case INTERVAL_MASK(MINUTE): deparseAppendStringInfoString(state, " minute"); break; case INTERVAL_MASK(SECOND): deparseAppendStringInfoString(state, " second"); break; case INTERVAL_MASK(YEAR) | INTERVAL_MASK(MONTH): deparseAppendStringInfoString(state, " year to month"); break; case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR): deparseAppendStringInfoString(state, " day to hour"); break; case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): deparseAppendStringInfoString(state, " day to minute"); break; case INTERVAL_MASK(DAY) | INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): deparseAppendStringInfoString(state, " day to second"); break; case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE): deparseAppendStringInfoString(state, " hour to minute"); break; case INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): deparseAppendStringInfoString(state, " hour to second"); break; case INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND): deparseAppendStringInfoString(state, " 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) deparseAppendStringInfo(state, "(%d)", precision); } } static void deparseNullTest(DeparseState *state, NullTest *null_test) { // argisrow is always false in raw parser output Assert(null_test->argisrow == false); deparseExpr(state, (Node *) null_test->arg, DEPARSE_NODE_CONTEXT_A_EXPR); switch (null_test->nulltesttype) { case IS_NULL: deparseAppendStringInfoString(state, " IS NULL"); break; case IS_NOT_NULL: deparseAppendStringInfoString(state, " IS NOT NULL"); break; } } // "case_expr" in gram.y static void deparseCaseExpr(DeparseState *state, CaseExpr *case_expr) { ListCell *lc; DeparseStateNestingLevel *parent_level = NULL; deparseAppendStringInfoString(state, "CASE "); if (case_expr->arg != NULL) { deparseExpr(state, (Node *) case_expr->arg, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ' '); } parent_level = deparseStateIncreaseNestingLevel(state); foreach(lc, case_expr->args) { deparseCaseWhen(state, castNode(CaseWhen, lfirst(lc))); } if (case_expr->defresult != NULL) { deparseAppendPartGroup(state, "ELSE", DEPARSE_PART_INDENT); deparseExpr(state, (Node *) case_expr->defresult, DEPARSE_NODE_CONTEXT_A_EXPR); } deparseAppendStringInfoChar(state, ' '); deparseStateDecreaseNestingLevel(state, parent_level); deparseAppendStringInfoString(state, "END"); } // "when_clause" in gram.y static void deparseCaseWhen(DeparseState *state, CaseWhen *case_when) { deparseAppendPartGroup(state, "WHEN", DEPARSE_PART_INDENT); deparseExpr(state, (Node *) case_when->expr, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " THEN "); deparseExpr(state, (Node *) case_when->result, DEPARSE_NODE_CONTEXT_A_EXPR); } static void deparseAIndirection(DeparseState *state, 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)) || IsA(a_indirection->arg, JsonFuncExpr); if (need_parens) deparseAppendStringInfoChar(state, '('); deparseExpr(state, a_indirection->arg, need_parens ? DEPARSE_NODE_CONTEXT_A_EXPR : DEPARSE_NODE_CONTEXT_NONE); if (need_parens) deparseAppendStringInfoChar(state, ')'); deparseOptIndirection(state, a_indirection->indirection, 0); } static void deparseAIndices(DeparseState *state, A_Indices *a_indices) { deparseAppendStringInfoChar(state, '['); if (a_indices->lidx != NULL) deparseExpr(state, a_indices->lidx, DEPARSE_NODE_CONTEXT_A_EXPR); if (a_indices->is_slice) deparseAppendStringInfoChar(state, ':'); if (a_indices->uidx != NULL) deparseExpr(state, a_indices->uidx, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ']'); } static void deparseCoalesceExpr(DeparseState *state, CoalesceExpr *coalesce_expr) { deparseAppendStringInfoString(state, "COALESCE("); deparseExprList(state, coalesce_expr->args); deparseAppendStringInfoChar(state, ')'); } static void deparseMinMaxExpr(DeparseState *state, MinMaxExpr *min_max_expr) { switch (min_max_expr->op) { case IS_GREATEST: deparseAppendStringInfoString(state, "GREATEST("); break; case IS_LEAST: deparseAppendStringInfoString(state, "LEAST("); break; } deparseExprList(state, min_max_expr->args); deparseAppendStringInfoChar(state, ')'); } static void deparseBooleanTest(DeparseState *state, BooleanTest *boolean_test) { bool need_parens = IsA(boolean_test->arg, BoolExpr); if (need_parens) deparseAppendStringInfoChar(state, '('); deparseExpr(state, (Node *) boolean_test->arg, DEPARSE_NODE_CONTEXT_A_EXPR); if (need_parens) deparseAppendStringInfoChar(state, ')'); switch (boolean_test->booltesttype) { case IS_TRUE: deparseAppendStringInfoString(state, " IS TRUE"); break; case IS_NOT_TRUE: deparseAppendStringInfoString(state, " IS NOT TRUE"); break; case IS_FALSE: deparseAppendStringInfoString(state, " IS FALSE"); break; case IS_NOT_FALSE: deparseAppendStringInfoString(state, " IS NOT FALSE"); break; case IS_UNKNOWN: deparseAppendStringInfoString(state, " IS UNKNOWN"); break; case IS_NOT_UNKNOWN: deparseAppendStringInfoString(state, " IS NOT UNKNOWN"); break; default: Assert(false); } } // "columnDef" and "alter_table_cmd" in gram.y static void deparseColumnDef(DeparseState *state, ColumnDef *column_def) { ListCell *lc; if (column_def->colname != NULL) { deparseAppendStringInfoString(state, quote_identifier(column_def->colname)); deparseAppendStringInfoChar(state, ' '); } if (column_def->typeName != NULL) { deparseTypeName(state, column_def->typeName); deparseAppendStringInfoChar(state, ' '); } if (column_def->storage_name) { deparseAppendStringInfoString(state, "STORAGE "); deparseAppendStringInfoString(state, column_def->storage_name); deparseAppendStringInfoChar(state, ' '); } if (column_def->raw_default != NULL) { deparseAppendStringInfoString(state, "USING "); deparseExpr(state, column_def->raw_default, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ' '); } if (column_def->compression != NULL) { deparseAppendStringInfoString(state, "COMPRESSION "); deparseAppendStringInfoString(state, column_def->compression); deparseAppendStringInfoChar(state, ' '); } if (column_def->fdwoptions != NULL) { deparseCreateGenericOptions(state, column_def->fdwoptions); deparseAppendStringInfoChar(state, ' '); } foreach(lc, column_def->constraints) { deparseConstraint(state, castNode(Constraint, lfirst(lc))); deparseAppendStringInfoChar(state, ' '); } if (column_def->collClause != NULL) { deparseCollateClause(state, column_def->collClause); } removeTrailingSpace(state); } static void deparseInsertOverride(DeparseState *state, OverridingKind override) { switch (override) { case OVERRIDING_NOT_SET: // Do nothing break; case OVERRIDING_USER_VALUE: deparseAppendStringInfoString(state, "OVERRIDING USER VALUE "); break; case OVERRIDING_SYSTEM_VALUE: deparseAppendStringInfoString(state, "OVERRIDING SYSTEM VALUE "); break; } } static void deparseInsertStmt(DeparseState *state, InsertStmt *insert_stmt) { ListCell *lc; ListCell *lc2; DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); if (insert_stmt->withClause != NULL) { deparseWithClause(state, insert_stmt->withClause); deparseAppendStringInfoChar(state, ' '); } deparseAppendPartGroup(state, "INSERT INTO", DEPARSE_PART_INDENT); deparseRangeVar(state, insert_stmt->relation, DEPARSE_NODE_CONTEXT_INSERT_RELATION); deparseAppendStringInfoChar(state, ' '); if (list_length(insert_stmt->cols) > 0) { deparseAppendStringInfoChar(state, '('); deparseInsertColumnList(state, insert_stmt->cols); deparseAppendStringInfoString(state, ") "); } deparseInsertOverride(state, insert_stmt->override); if (insert_stmt->selectStmt != NULL) { deparseSelectStmt(state, castNode(SelectStmt, insert_stmt->selectStmt), DEPARSE_NODE_CONTEXT_INSERT_SELECT); deparseAppendStringInfoChar(state, ' '); } else { deparseAppendStringInfoString(state, "DEFAULT VALUES "); } if (insert_stmt->onConflictClause != NULL) { deparseOnConflictClause(state, insert_stmt->onConflictClause); deparseAppendStringInfoChar(state, ' '); } if (list_length(insert_stmt->returningList) > 0) { deparseAppendPartGroup(state, "RETURNING", DEPARSE_PART_INDENT_AND_MERGE); deparseTargetList(state, insert_stmt->returningList); } removeTrailingSpace(state); deparseStateDecreaseNestingLevel(state, parent_level); } static void deparseInferClause(DeparseState *state, InferClause *infer_clause) { ListCell *lc; if (list_length(infer_clause->indexElems) > 0) { deparseAppendStringInfoChar(state, '('); foreach(lc, infer_clause->indexElems) { deparseIndexElem(state, lfirst(lc)); if (lnext(infer_clause->indexElems, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, ") "); } if (infer_clause->conname != NULL) { deparseAppendStringInfoString(state, "ON CONSTRAINT "); deparseAppendStringInfoString(state, quote_identifier(infer_clause->conname)); deparseAppendStringInfoChar(state, ' '); } deparseWhereClause(state, infer_clause->whereClause); removeTrailingSpace(state); } static void deparseOnConflictClause(DeparseState *state, OnConflictClause *on_conflict_clause) { ListCell *lc; deparseAppendPartGroup(state, "ON CONFLICT", DEPARSE_PART_INDENT); if (on_conflict_clause->infer != NULL) { deparseInferClause(state, on_conflict_clause->infer); deparseAppendStringInfoChar(state, ' '); } switch (on_conflict_clause->action) { case ONCONFLICT_NONE: Assert(false); break; case ONCONFLICT_NOTHING: deparseAppendStringInfoString(state, "DO NOTHING "); break; case ONCONFLICT_UPDATE: deparseAppendStringInfoString(state, "DO UPDATE "); break; } if (list_length(on_conflict_clause->targetList) > 0) { deparseAppendPartGroup(state, "SET", DEPARSE_PART_INDENT); deparseSetClauseList(state, on_conflict_clause->targetList); deparseAppendStringInfoChar(state, ' '); } deparseWhereClause(state, on_conflict_clause->whereClause); removeTrailingSpace(state); } static void deparseUpdateStmt(DeparseState *state, UpdateStmt *update_stmt) { ListCell* lc; ListCell* lc2; ListCell* lc3; DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); if (update_stmt->withClause != NULL) { deparseWithClause(state, update_stmt->withClause); deparseAppendStringInfoChar(state, ' '); } deparseAppendPartGroup(state, "UPDATE", DEPARSE_PART_INDENT); deparseRangeVar(state, update_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); if (list_length(update_stmt->targetList) > 0) { deparseAppendPartGroup(state, "SET", DEPARSE_PART_INDENT); deparseSetClauseList(state, update_stmt->targetList); deparseAppendStringInfoChar(state, ' '); } deparseFromClause(state, update_stmt->fromClause); deparseWhereOrCurrentClause(state, update_stmt->whereClause); if (list_length(update_stmt->returningList) > 0) { deparseAppendPartGroup(state, "RETURNING", DEPARSE_PART_INDENT_AND_MERGE); deparseTargetList(state, update_stmt->returningList); } removeTrailingSpace(state); deparseStateDecreaseNestingLevel(state, parent_level); } // "MergeStmt" in gram.y static void deparseMergeStmt(DeparseState *state, MergeStmt *merge_stmt) { DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); if (merge_stmt->withClause != NULL) { deparseWithClause(state, merge_stmt->withClause); deparseAppendStringInfoChar(state, ' '); } deparseAppendPartGroup(state, "MERGE", DEPARSE_PART_INDENT); deparseAppendStringInfoString(state, "INTO "); deparseRangeVar(state, merge_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); deparseAppendPartGroup(state, "USING", DEPARSE_PART_INDENT); deparseTableRef(state, merge_stmt->sourceRelation); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "ON "); deparseExpr(state, merge_stmt->joinCondition, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ' '); ListCell *lc; foreach (lc, merge_stmt->mergeWhenClauses) { MergeWhenClause *clause = castNode(MergeWhenClause, lfirst(lc)); deparseAppendStringInfoString(state, "WHEN "); switch (clause->matchKind) { case MERGE_WHEN_MATCHED: deparseAppendStringInfoString(state, "MATCHED "); break; case MERGE_WHEN_NOT_MATCHED_BY_SOURCE: deparseAppendStringInfoString(state, "NOT MATCHED BY SOURCE "); break; case MERGE_WHEN_NOT_MATCHED_BY_TARGET: deparseAppendStringInfoString(state, "NOT MATCHED "); break; } if (clause->condition) { deparseAppendStringInfoString(state, "AND "); deparseExpr(state, clause->condition, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ' '); } deparseAppendStringInfoString(state, "THEN "); switch (clause->commandType) { case CMD_INSERT: deparseAppendStringInfoString(state, "INSERT "); if (clause->targetList) { deparseAppendStringInfoChar(state, '('); deparseInsertColumnList(state, clause->targetList); deparseAppendStringInfoString(state, ") "); } deparseInsertOverride(state, clause->override); if (clause->values) { deparseAppendStringInfoString(state, "VALUES ("); deparseExprList(state, clause->values); deparseAppendStringInfoString(state, ")"); } else { deparseAppendStringInfoString(state, "DEFAULT VALUES "); } break; case CMD_UPDATE: deparseAppendStringInfoString(state, "UPDATE SET "); deparseSetClauseList(state, clause->targetList); break; case CMD_DELETE: deparseAppendStringInfoString(state, "DELETE"); break; case CMD_NOTHING: deparseAppendStringInfoString(state, "DO NOTHING"); break; default: elog(ERROR, "deparse: unpermitted command type in merge statement: %d", clause->commandType); break; } if (lfirst(lc) != llast(merge_stmt->mergeWhenClauses)) deparseAppendStringInfoChar(state, ' '); } if (merge_stmt->returningList) { deparseAppendPartGroup(state, "RETURNING", DEPARSE_PART_INDENT_AND_MERGE); deparseTargetList(state, merge_stmt->returningList); } deparseStateDecreaseNestingLevel(state, parent_level); } static void deparseDeleteStmt(DeparseState *state, DeleteStmt *delete_stmt) { DeparseStateNestingLevel *parent_level = deparseStateIncreaseNestingLevel(state); if (delete_stmt->withClause != NULL) { deparseWithClause(state, delete_stmt->withClause); deparseAppendStringInfoChar(state, ' '); } deparseAppendPartGroup(state, "DELETE", DEPARSE_PART_INDENT); deparseAppendStringInfoString(state, "FROM "); deparseRangeVar(state, delete_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); if (delete_stmt->usingClause != NULL) { deparseAppendPartGroup(state, "USING", DEPARSE_PART_INDENT); deparseFromList(state, delete_stmt->usingClause); deparseAppendStringInfoChar(state, ' '); } deparseWhereOrCurrentClause(state, delete_stmt->whereClause); if (list_length(delete_stmt->returningList) > 0) { deparseAppendPartGroup(state, "RETURNING", DEPARSE_PART_INDENT_AND_MERGE); deparseTargetList(state, delete_stmt->returningList); } removeTrailingSpace(state); deparseStateDecreaseNestingLevel(state, parent_level); } static void deparseLockingClause(DeparseState *state, 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: deparseAppendPartGroup(state, "FOR KEY SHARE", DEPARSE_PART_INDENT); break; case LCS_FORSHARE: deparseAppendPartGroup(state, "FOR SHARE", DEPARSE_PART_INDENT); break; case LCS_FORNOKEYUPDATE: deparseAppendPartGroup(state, "FOR NO KEY UPDATE", DEPARSE_PART_INDENT); break; case LCS_FORUPDATE: deparseAppendPartGroup(state, "FOR UPDATE", DEPARSE_PART_INDENT); break; } if (list_length(locking_clause->lockedRels) > 0) { deparseAppendStringInfoString(state, "OF "); deparseQualifiedNameList(state, locking_clause->lockedRels); deparseAppendStringInfoChar(state, ' '); } switch (locking_clause->waitPolicy) { case LockWaitError: deparseAppendStringInfoString(state, "NOWAIT"); break; case LockWaitSkip: deparseAppendStringInfoString(state, "SKIP LOCKED"); break; case LockWaitBlock: // Default break; } removeTrailingSpace(state); } static void deparseSetToDefault(DeparseState *state, SetToDefault *set_to_default) { deparseAppendStringInfoString(state, "DEFAULT"); } static void deparseCreateCastStmt(DeparseState *state, CreateCastStmt *create_cast_stmt) { ListCell *lc; ListCell *lc2; deparseAppendStringInfoString(state, "CREATE CAST ("); deparseTypeName(state, create_cast_stmt->sourcetype); deparseAppendStringInfoString(state, " AS "); deparseTypeName(state, create_cast_stmt->targettype); deparseAppendStringInfoString(state, ") "); if (create_cast_stmt->func != NULL) { deparseAppendStringInfoString(state, "WITH FUNCTION "); deparseFunctionWithArgtypes(state, create_cast_stmt->func); deparseAppendStringInfoChar(state, ' '); } else if (create_cast_stmt->inout) { deparseAppendStringInfoString(state, "WITH INOUT "); } else { deparseAppendStringInfoString(state, "WITHOUT FUNCTION "); } switch (create_cast_stmt->context) { case COERCION_IMPLICIT: deparseAppendStringInfoString(state, "AS IMPLICIT"); break; case COERCION_ASSIGNMENT: deparseAppendStringInfoString(state, "AS ASSIGNMENT"); break; case COERCION_PLPGSQL: // Not present in raw parser output Assert(false); break; case COERCION_EXPLICIT: // Default break; } } static void deparseCreateOpClassStmt(DeparseState *state, CreateOpClassStmt *create_op_class_stmt) { ListCell *lc = NULL; deparseAppendStringInfoString(state, "CREATE OPERATOR CLASS "); deparseAnyName(state, create_op_class_stmt->opclassname); deparseAppendStringInfoChar(state, ' '); if (create_op_class_stmt->isDefault) deparseAppendStringInfoString(state, "DEFAULT "); deparseAppendStringInfoString(state, "FOR TYPE "); deparseTypeName(state, create_op_class_stmt->datatype); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "USING "); deparseAppendStringInfoString(state, quote_identifier(create_op_class_stmt->amname)); deparseAppendStringInfoChar(state, ' '); if (create_op_class_stmt->opfamilyname != NULL) { deparseAppendStringInfoString(state, "FAMILY "); deparseAnyName(state, create_op_class_stmt->opfamilyname); deparseAppendStringInfoChar(state, ' '); } deparseAppendStringInfoString(state, "AS "); deparseOpclassItemList(state, create_op_class_stmt->items); } static void deparseCreateOpFamilyStmt(DeparseState *state, CreateOpFamilyStmt *create_op_family_stmt) { deparseAppendStringInfoString(state, "CREATE OPERATOR FAMILY "); deparseAnyName(state, create_op_family_stmt->opfamilyname); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "USING "); deparseAppendStringInfoString(state, quote_identifier(create_op_family_stmt->amname)); } static void deparseCreateOpClassItem(DeparseState *state, CreateOpClassItem *create_op_class_item) { ListCell *lc = NULL; switch (create_op_class_item->itemtype) { case OPCLASS_ITEM_OPERATOR: deparseAppendStringInfoString(state, "OPERATOR "); deparseAppendStringInfo(state, "%d ", create_op_class_item->number); if (create_op_class_item->name != NULL) { if (create_op_class_item->name->objargs != NULL) deparseOperatorWithArgtypes(state, create_op_class_item->name); else deparseAnyOperator(state, create_op_class_item->name->objname); deparseAppendStringInfoChar(state, ' '); } if (create_op_class_item->order_family != NULL) { deparseAppendStringInfoString(state, "FOR ORDER BY "); deparseAnyName(state, create_op_class_item->order_family); } if (create_op_class_item->class_args != NULL) { deparseAppendStringInfoChar(state, '('); deparseTypeList(state, create_op_class_item->class_args); deparseAppendStringInfoChar(state, ')'); } removeTrailingSpace(state); break; case OPCLASS_ITEM_FUNCTION: deparseAppendStringInfoString(state, "FUNCTION "); deparseAppendStringInfo(state, "%d ", create_op_class_item->number); if (create_op_class_item->class_args != NULL) { deparseAppendStringInfoChar(state, '('); deparseTypeList(state, create_op_class_item->class_args); deparseAppendStringInfoString(state, ") "); } if (create_op_class_item->name != NULL) deparseFunctionWithArgtypes(state, create_op_class_item->name); removeTrailingSpace(state); break; case OPCLASS_ITEM_STORAGETYPE: deparseAppendStringInfoString(state, "STORAGE "); deparseTypeName(state, create_op_class_item->storedtype); break; default: Assert(false); } } static void deparseTableLikeClause(DeparseState *state, TableLikeClause *table_like_clause) { deparseAppendStringInfoString(state, "LIKE "); deparseRangeVar(state, table_like_clause->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); if (table_like_clause->options == CREATE_TABLE_LIKE_ALL) deparseAppendStringInfoString(state, "INCLUDING ALL "); else { if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) deparseAppendStringInfoString(state, "INCLUDING COMMENTS "); if (table_like_clause->options & CREATE_TABLE_LIKE_COMPRESSION) deparseAppendStringInfoString(state, "INCLUDING COMPRESSION "); if (table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) deparseAppendStringInfoString(state, "INCLUDING CONSTRAINTS "); if (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS) deparseAppendStringInfoString(state, "INCLUDING DEFAULTS "); if (table_like_clause->options & CREATE_TABLE_LIKE_IDENTITY) deparseAppendStringInfoString(state, "INCLUDING IDENTITY "); if (table_like_clause->options & CREATE_TABLE_LIKE_GENERATED) deparseAppendStringInfoString(state, "INCLUDING GENERATED "); if (table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) deparseAppendStringInfoString(state, "INCLUDING INDEXES "); if (table_like_clause->options & CREATE_TABLE_LIKE_STATISTICS) deparseAppendStringInfoString(state, "INCLUDING STATISTICS "); if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE) deparseAppendStringInfoString(state, "INCLUDING STORAGE "); } removeTrailingSpace(state); } static void deparseCreateDomainStmt(DeparseState *state, CreateDomainStmt *create_domain_stmt) { ListCell *lc; Assert(create_domain_stmt->typeName != NULL); deparseAppendStringInfoString(state, "CREATE DOMAIN "); deparseAnyName(state, create_domain_stmt->domainname); deparseAppendStringInfoString(state, " AS "); deparseTypeName(state, create_domain_stmt->typeName); deparseAppendStringInfoChar(state, ' '); if (create_domain_stmt->collClause != NULL) { deparseCollateClause(state, create_domain_stmt->collClause); deparseAppendStringInfoChar(state, ' '); } foreach(lc, create_domain_stmt->constraints) { deparseConstraint(state, castNode(Constraint, lfirst(lc))); deparseAppendStringInfoChar(state, ' '); } removeTrailingSpace(state); } static void deparseCreateExtensionStmt(DeparseState *state, CreateExtensionStmt *create_extension_stmt) { ListCell *lc = NULL; deparseAppendStringInfoString(state, "CREATE EXTENSION "); if (create_extension_stmt->if_not_exists) deparseAppendStringInfoString(state, "IF NOT EXISTS "); deparseColId(state, create_extension_stmt->extname); deparseAppendStringInfoChar(state, ' '); foreach (lc, create_extension_stmt->options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); if (strcmp(def_elem->defname, "schema") == 0) { deparseAppendStringInfoString(state, "SCHEMA "); deparseColId(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "new_version") == 0) { deparseAppendStringInfoString(state, "VERSION "); deparseNonReservedWordOrSconst(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "cascade") == 0) { deparseAppendStringInfoString(state, "CASCADE"); } else { Assert(false); } deparseAppendStringInfoChar(state, ' '); } removeTrailingSpace(state); } // "ColConstraintElem" and "ConstraintElem" in gram.y static void deparseConstraint(DeparseState *state, Constraint *constraint) { ListCell *lc; if (constraint->conname != NULL) { deparseAppendStringInfoString(state, "CONSTRAINT "); deparseAppendStringInfoString(state, quote_identifier(constraint->conname)); deparseAppendStringInfoChar(state, ' '); } switch (constraint->contype) { case CONSTR_NULL: deparseAppendStringInfoString(state, "NULL "); break; case CONSTR_NOTNULL: deparseAppendStringInfoString(state, "NOT NULL "); break; case CONSTR_DEFAULT: deparseAppendStringInfoString(state, "DEFAULT "); deparseBExpr(state, constraint->raw_expr); break; case CONSTR_IDENTITY: deparseAppendStringInfoString(state, "GENERATED "); switch (constraint->generated_when) { case ATTRIBUTE_IDENTITY_ALWAYS: deparseAppendStringInfoString(state, "ALWAYS "); break; case ATTRIBUTE_IDENTITY_BY_DEFAULT: deparseAppendStringInfoString(state, "BY DEFAULT "); break; default: Assert(false); } deparseAppendStringInfoString(state, "AS IDENTITY "); deparseOptParenthesizedSeqOptList(state, constraint->options); break; case CONSTR_GENERATED: Assert(constraint->generated_when == ATTRIBUTE_IDENTITY_ALWAYS); deparseAppendStringInfoString(state, "GENERATED ALWAYS AS ("); deparseExpr(state, constraint->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") STORED "); break; case CONSTR_CHECK: deparseAppendStringInfoString(state, "CHECK ("); deparseExpr(state, constraint->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); break; case CONSTR_PRIMARY: deparseAppendStringInfoString(state, "PRIMARY KEY "); break; case CONSTR_UNIQUE: deparseAppendStringInfoString(state, "UNIQUE "); if (constraint->nulls_not_distinct) deparseAppendStringInfoString(state, "NULLS NOT DISTINCT "); break; case CONSTR_EXCLUSION: deparseAppendStringInfoString(state, "EXCLUDE "); if (strcmp(constraint->access_method, DEFAULT_INDEX_TYPE) != 0) { deparseAppendStringInfoString(state, "USING "); deparseAppendStringInfoString(state, quote_identifier(constraint->access_method)); deparseAppendStringInfoChar(state, ' '); } deparseAppendStringInfoChar(state, '('); foreach(lc, constraint->exclusions) { List *exclusion = castNode(List, lfirst(lc)); Assert(list_length(exclusion) == 2); deparseIndexElem(state, castNode(IndexElem, linitial(exclusion))); deparseAppendStringInfoString(state, " WITH "); deparseAnyOperator(state, castNode(List, lsecond(exclusion))); if (lnext(constraint->exclusions, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, ") "); if (constraint->where_clause != NULL) { deparseAppendStringInfoString(state, "WHERE ("); deparseExpr(state, constraint->where_clause, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); } break; case CONSTR_FOREIGN: if (list_length(constraint->fk_attrs) > 0) deparseAppendStringInfoString(state, "FOREIGN KEY "); break; case CONSTR_ATTR_DEFERRABLE: deparseAppendStringInfoString(state, "DEFERRABLE "); break; case CONSTR_ATTR_NOT_DEFERRABLE: deparseAppendStringInfoString(state, "NOT DEFERRABLE "); break; case CONSTR_ATTR_DEFERRED: deparseAppendStringInfoString(state, "INITIALLY DEFERRED "); break; case CONSTR_ATTR_IMMEDIATE: deparseAppendStringInfoString(state, "INITIALLY IMMEDIATE "); break; } if (list_length(constraint->keys) > 0) { bool valueOnly = false; if (list_length(constraint->keys) == 1) { Node* firstKey = constraint->keys->elements[0].ptr_value; valueOnly = IsA(firstKey, String) && !strcmp("value", ((String*)firstKey)->sval); } if (!valueOnly) { deparseAppendStringInfoChar(state, '('); deparseColumnList(state, constraint->keys); deparseAppendStringInfoString(state, ") "); } } if (list_length(constraint->fk_attrs) > 0) { deparseAppendStringInfoChar(state, '('); deparseColumnList(state, constraint->fk_attrs); deparseAppendStringInfoString(state, ") "); } if (constraint->pktable != NULL) { deparseAppendStringInfoString(state, "REFERENCES "); deparseRangeVar(state, constraint->pktable, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); if (list_length(constraint->pk_attrs) > 0) { deparseAppendStringInfoChar(state, '('); deparseColumnList(state, constraint->pk_attrs); deparseAppendStringInfoString(state, ") "); } } switch (constraint->fk_matchtype) { case FKCONSTR_MATCH_SIMPLE: // Default break; case FKCONSTR_MATCH_FULL: deparseAppendStringInfoString(state, "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: deparseAppendStringInfoString(state, "ON UPDATE RESTRICT "); break; case FKCONSTR_ACTION_CASCADE: deparseAppendStringInfoString(state, "ON UPDATE CASCADE "); break; case FKCONSTR_ACTION_SETNULL: deparseAppendStringInfoString(state, "ON UPDATE SET NULL "); break; case FKCONSTR_ACTION_SETDEFAULT: deparseAppendStringInfoString(state, "ON UPDATE SET DEFAULT "); break; default: // Not specified break; } switch (constraint->fk_del_action) { case FKCONSTR_ACTION_NOACTION: // Default break; case FKCONSTR_ACTION_RESTRICT: deparseAppendStringInfoString(state, "ON DELETE RESTRICT "); break; case FKCONSTR_ACTION_CASCADE: deparseAppendStringInfoString(state, "ON DELETE CASCADE "); break; case FKCONSTR_ACTION_SETNULL: case FKCONSTR_ACTION_SETDEFAULT: deparseAppendStringInfoString(state, "ON DELETE SET "); switch (constraint->fk_del_action) { case FKCONSTR_ACTION_SETDEFAULT: deparseAppendStringInfoString(state, "DEFAULT "); break; case FKCONSTR_ACTION_SETNULL: deparseAppendStringInfoString(state, "NULL "); break; } if (constraint->fk_del_set_cols) { deparseAppendStringInfoString(state, "("); ListCell *lc; foreach (lc, constraint->fk_del_set_cols) { deparseAppendStringInfoString(state, strVal(lfirst(lc))); if (lfirst(lc) != llast(constraint->fk_del_set_cols)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, ")"); } break; default: // Not specified break; } if (list_length(constraint->including) > 0) { deparseAppendStringInfoString(state, "INCLUDE ("); deparseColumnList(state, constraint->including); deparseAppendStringInfoString(state, ") "); } switch (constraint->contype) { case CONSTR_PRIMARY: case CONSTR_UNIQUE: case CONSTR_EXCLUSION: deparseOptWith(state, constraint->options); break; default: break; } if (constraint->indexname != NULL) deparseAppendStringInfo(state, "USING INDEX %s ", quote_identifier(constraint->indexname)); if (constraint->indexspace != NULL) deparseAppendStringInfo(state, "USING INDEX TABLESPACE %s ", quote_identifier(constraint->indexspace)); if (constraint->deferrable) deparseAppendStringInfoString(state, "DEFERRABLE "); if (constraint->initdeferred) deparseAppendStringInfoString(state, "INITIALLY DEFERRED "); if (constraint->is_no_inherit) deparseAppendStringInfoString(state, "NO INHERIT "); if (constraint->skip_validation) deparseAppendStringInfoString(state, "NOT VALID "); removeTrailingSpace(state); } // "ReturnStmt" in gram.y static void deparseReturnStmt(DeparseState *state, ReturnStmt *return_stmt) { deparseAppendStringInfoString(state, "RETURN "); deparseExpr(state, return_stmt->returnval, DEPARSE_NODE_CONTEXT_A_EXPR); } static void deparseCreateFunctionStmt(DeparseState *state, CreateFunctionStmt *create_function_stmt) { ListCell *lc; bool tableFunc = false; deparseAppendStringInfoString(state, "CREATE "); if (create_function_stmt->replace) deparseAppendStringInfoString(state, "OR REPLACE "); if (create_function_stmt->is_procedure) deparseAppendStringInfoString(state, "PROCEDURE "); else deparseAppendStringInfoString(state, "FUNCTION "); deparseFuncName(state, create_function_stmt->funcname); deparseAppendStringInfoChar(state, '('); foreach(lc, create_function_stmt->parameters) { FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); if (function_parameter->mode != FUNC_PARAM_TABLE) { deparseFunctionParameter(state, function_parameter); if (lnext(create_function_stmt->parameters, lc) && castNode(FunctionParameter, lfirst(lnext(create_function_stmt->parameters, lc)))->mode != FUNC_PARAM_TABLE) deparseAppendStringInfoString(state, ", "); } else { tableFunc = true; } } deparseAppendStringInfoString(state, ") "); if (tableFunc) { deparseAppendStringInfoString(state, "RETURNS TABLE ("); foreach(lc, create_function_stmt->parameters) { FunctionParameter *function_parameter = castNode(FunctionParameter, lfirst(lc)); if (function_parameter->mode == FUNC_PARAM_TABLE) { deparseFunctionParameter(state, function_parameter); if (lnext(create_function_stmt->parameters, lc)) deparseAppendStringInfoString(state, ", "); } } deparseAppendStringInfoString(state, ") "); } else if (create_function_stmt->returnType != NULL) { deparseAppendStringInfoString(state, "RETURNS "); deparseTypeName(state, create_function_stmt->returnType); deparseAppendStringInfoChar(state, ' '); } foreach(lc, create_function_stmt->options) { deparseCreateFuncOptItem(state, castNode(DefElem, lfirst(lc))); deparseAppendStringInfoChar(state, ' '); } if (create_function_stmt->sql_body) { /* RETURN or BEGIN ... END */ if (IsA(create_function_stmt->sql_body, ReturnStmt)) { deparseReturnStmt(state, castNode(ReturnStmt, create_function_stmt->sql_body)); } else { deparseAppendStringInfoString(state, "BEGIN ATOMIC "); if (IsA(create_function_stmt->sql_body, List), linitial((List *) create_function_stmt->sql_body) != NULL) { List *body_stmt_list = castNode(List, linitial((List *) create_function_stmt->sql_body)); foreach(lc, body_stmt_list) { if (IsA(lfirst(lc), ReturnStmt)) { deparseReturnStmt(state, lfirst_node(ReturnStmt, lc)); deparseAppendStringInfoString(state, "; "); } else { deparseStmt(state, lfirst(lc)); deparseAppendStringInfoString(state, "; "); } } } deparseAppendStringInfoString(state, "END "); } } removeTrailingSpace(state); } // "func_arg", "func_arg_with_default" and other places in gram.y static void deparseFunctionParameter(DeparseState *state, FunctionParameter *function_parameter) { switch (function_parameter->mode) { case FUNC_PARAM_IN: /* input only */ deparseAppendStringInfoString(state, "IN "); break; case FUNC_PARAM_OUT: /* output only */ deparseAppendStringInfoString(state, "OUT "); break; case FUNC_PARAM_INOUT: /* both */ deparseAppendStringInfoString(state, "INOUT "); break; case FUNC_PARAM_VARIADIC: /* variadic (always input) */ deparseAppendStringInfoString(state, "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) { deparseAppendStringInfoString(state, function_parameter->name); deparseAppendStringInfoChar(state, ' '); } deparseTypeName(state, function_parameter->argType); deparseAppendStringInfoChar(state, ' '); if (function_parameter->defexpr != NULL) { deparseAppendStringInfoString(state, "= "); deparseExpr(state, function_parameter->defexpr, DEPARSE_NODE_CONTEXT_A_EXPR); } removeTrailingSpace(state); } static void deparseCheckPointStmt(DeparseState *state, CheckPointStmt *check_point_stmt) { deparseAppendStringInfoString(state, "CHECKPOINT"); } static void deparseCreateSchemaStmt(DeparseState *state, CreateSchemaStmt *create_schema_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "CREATE SCHEMA "); if (create_schema_stmt->if_not_exists) deparseAppendStringInfoString(state, "IF NOT EXISTS "); if (create_schema_stmt->schemaname) { deparseColId(state, create_schema_stmt->schemaname); deparseAppendStringInfoChar(state, ' '); } if (create_schema_stmt->authrole != NULL) { deparseAppendStringInfoString(state, "AUTHORIZATION "); deparseRoleSpec(state, create_schema_stmt->authrole); deparseAppendStringInfoChar(state, ' '); } if (create_schema_stmt->schemaElts) { foreach(lc, create_schema_stmt->schemaElts) { deparseSchemaStmt(state, lfirst(lc)); if (lnext(create_schema_stmt->schemaElts, lc)) deparseAppendStringInfoChar(state, ' '); } } removeTrailingSpace(state); } static void deparseAlterRoleSetStmt(DeparseState *state, AlterRoleSetStmt *alter_role_set_stmt) { deparseAppendStringInfoString(state, "ALTER ROLE "); if (alter_role_set_stmt->role == NULL) deparseAppendStringInfoString(state, "ALL"); else deparseRoleSpec(state, alter_role_set_stmt->role); deparseAppendStringInfoChar(state, ' '); if (alter_role_set_stmt->database != NULL) { deparseAppendStringInfoString(state, "IN DATABASE "); deparseAppendStringInfoString(state, quote_identifier(alter_role_set_stmt->database)); deparseAppendStringInfoChar(state, ' '); } deparseVariableSetStmt(state, alter_role_set_stmt->setstmt); } static void deparseCreateConversionStmt(DeparseState *state, CreateConversionStmt *create_conversion_stmt) { deparseAppendStringInfoString(state, "CREATE "); if (create_conversion_stmt->def) deparseAppendStringInfoString(state, "DEFAULT "); deparseAppendStringInfoString(state, "CONVERSION "); deparseAnyName(state, create_conversion_stmt->conversion_name); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "FOR "); deparseStringLiteral(state, create_conversion_stmt->for_encoding_name); deparseAppendStringInfoString(state, " TO "); deparseStringLiteral(state, create_conversion_stmt->to_encoding_name); deparseAppendStringInfoString(state, "FROM "); deparseAnyName(state, create_conversion_stmt->func_name); } static void deparseRoleSpec(DeparseState *state, RoleSpec *role_spec) { switch (role_spec->roletype) { case ROLESPEC_CSTRING: Assert(role_spec->rolename != NULL); deparseAppendStringInfoString(state, quote_identifier(role_spec->rolename)); break; case ROLESPEC_CURRENT_ROLE: deparseAppendStringInfoString(state, "CURRENT_ROLE"); break; case ROLESPEC_CURRENT_USER: deparseAppendStringInfoString(state, "CURRENT_USER"); break; case ROLESPEC_SESSION_USER: deparseAppendStringInfoString(state, "SESSION_USER"); break; case ROLESPEC_PUBLIC: deparseAppendStringInfoString(state, "public"); break; } } // "part_elem" in gram.y static void deparsePartitionElem(DeparseState *state, PartitionElem *partition_elem) { ListCell *lc; if (partition_elem->name != NULL) { deparseColId(state, partition_elem->name); deparseAppendStringInfoChar(state, ' '); } else if (partition_elem->expr != NULL) { deparseAppendStringInfoChar(state, '('); deparseExpr(state, partition_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); } deparseOptCollate(state, partition_elem->collation); deparseAnyName(state, partition_elem->opclass); removeTrailingSpace(state); } static void deparsePartitionSpec(DeparseState *state, PartitionSpec *partition_spec) { ListCell *lc; deparseAppendPartGroup(state, "PARTITION BY", DEPARSE_PART_INDENT); switch (partition_spec->strategy) { case PARTITION_STRATEGY_LIST: deparseAppendStringInfoString(state, "LIST"); break; case PARTITION_STRATEGY_HASH: deparseAppendStringInfoString(state, "HASH"); break; case PARTITION_STRATEGY_RANGE: deparseAppendStringInfoString(state, "RANGE"); break; } deparseAppendStringInfoString(state, " ("); foreach(lc, partition_spec->partParams) { deparsePartitionElem(state, castNode(PartitionElem, lfirst(lc))); if (lnext(partition_spec->partParams, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); } static void deparsePartitionBoundSpec(DeparseState *state, PartitionBoundSpec *partition_bound_spec) { ListCell *lc; if (partition_bound_spec->is_default) { deparseAppendStringInfoString(state, "DEFAULT"); return; } deparseAppendStringInfoString(state, "FOR VALUES "); switch (partition_bound_spec->strategy) { case PARTITION_STRATEGY_HASH: deparseAppendStringInfo(state, "WITH (MODULUS %d, REMAINDER %d)", partition_bound_spec->modulus, partition_bound_spec->remainder); break; case PARTITION_STRATEGY_LIST: deparseAppendStringInfoString(state, "IN ("); deparseExprList(state, partition_bound_spec->listdatums); deparseAppendStringInfoChar(state, ')'); break; case PARTITION_STRATEGY_RANGE: deparseAppendStringInfoString(state, "FROM ("); deparseExprList(state, partition_bound_spec->lowerdatums); deparseAppendStringInfoString(state, ") TO ("); deparseExprList(state, partition_bound_spec->upperdatums); deparseAppendStringInfoChar(state, ')'); break; default: Assert(false); break; } } static void deparsePartitionCmd(DeparseState *state, PartitionCmd *partition_cmd) { deparseRangeVar(state, partition_cmd->name, DEPARSE_NODE_CONTEXT_NONE); if (partition_cmd->bound != NULL) { deparseAppendStringInfoChar(state, ' '); deparsePartitionBoundSpec(state, partition_cmd->bound); } if (partition_cmd->concurrent) deparseAppendStringInfoString(state, " CONCURRENTLY "); } // "TableElement" in gram.y static void deparseTableElement(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_ColumnDef: deparseColumnDef(state, castNode(ColumnDef, node)); break; case T_TableLikeClause: deparseTableLikeClause(state, castNode(TableLikeClause, node)); break; case T_Constraint: deparseConstraint(state, castNode(Constraint, node)); break; default: Assert(false); } } static void deparseCreateStmt(DeparseState *state, CreateStmt *create_stmt, bool is_foreign_table) { ListCell *lc; deparseAppendStringInfoString(state, "CREATE "); if (is_foreign_table) deparseAppendStringInfoString(state, "FOREIGN "); deparseOptTemp(state, create_stmt->relation->relpersistence); deparseAppendStringInfoString(state, "TABLE "); if (create_stmt->if_not_exists) deparseAppendStringInfoString(state, "IF NOT EXISTS "); deparseRangeVar(state, create_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); if (create_stmt->ofTypename != NULL) { deparseAppendStringInfoString(state, "OF "); deparseTypeName(state, create_stmt->ofTypename); deparseAppendStringInfoChar(state, ' '); } if (create_stmt->partbound != NULL) { Assert(list_length(create_stmt->inhRelations) == 1); deparseAppendStringInfoString(state, "PARTITION OF "); deparseRangeVar(state, castNode(RangeVar, linitial(create_stmt->inhRelations)), DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); } if (list_length(create_stmt->tableElts) > 0) { DeparseStateNestingLevel *parent_level = NULL; // In raw parse output tableElts contains both columns and constraints // (and the constraints field is NIL) deparseAppendStringInfoChar(state, '('); parent_level = deparseStateIncreaseNestingLevel(state); foreach(lc, create_stmt->tableElts) { deparseTableElement(state, lfirst(lc)); if (lnext(create_stmt->tableElts, lc)) deparseAppendCommaAndPart(state); } deparseStateDecreaseNestingLevel(state, parent_level); deparseAppendStringInfoString(state, ") "); } else if (create_stmt->partbound == NULL && create_stmt->ofTypename == NULL) { deparseAppendStringInfoString(state, "() "); } if (create_stmt->partbound != NULL) { deparsePartitionBoundSpec(state, create_stmt->partbound); deparseAppendStringInfoChar(state, ' '); } else { deparseOptInherit(state, create_stmt->inhRelations); } if (create_stmt->partspec != NULL) { deparsePartitionSpec(state, create_stmt->partspec); deparseAppendStringInfoChar(state, ' '); } if (create_stmt->accessMethod != NULL) { deparseAppendStringInfoString(state, "USING "); deparseAppendStringInfoString(state, quote_identifier(create_stmt->accessMethod)); } deparseOptWith(state, create_stmt->options); switch (create_stmt->oncommit) { case ONCOMMIT_NOOP: // No ON COMMIT clause break; case ONCOMMIT_PRESERVE_ROWS: deparseAppendStringInfoString(state, "ON COMMIT PRESERVE ROWS "); break; case ONCOMMIT_DELETE_ROWS: deparseAppendStringInfoString(state, "ON COMMIT DELETE ROWS "); break; case ONCOMMIT_DROP: deparseAppendStringInfoString(state, "ON COMMIT DROP "); break; } if (create_stmt->tablespacename != NULL) { deparseAppendStringInfoString(state, "TABLESPACE "); deparseAppendStringInfoString(state, quote_identifier(create_stmt->tablespacename)); } removeTrailingSpace(state); } static void deparseCreateFdwStmt(DeparseState *state, CreateFdwStmt *create_fdw_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "CREATE FOREIGN DATA WRAPPER "); deparseAppendStringInfoString(state, quote_identifier(create_fdw_stmt->fdwname)); deparseAppendStringInfoChar(state, ' '); if (list_length(create_fdw_stmt->func_options) > 0) { deparseFdwOptions(state, create_fdw_stmt->func_options); deparseAppendStringInfoChar(state, ' '); } deparseCreateGenericOptions(state, create_fdw_stmt->options); removeTrailingSpace(state); } static void deparseAlterFdwStmt(DeparseState *state, AlterFdwStmt *alter_fdw_stmt) { deparseAppendStringInfoString(state, "ALTER FOREIGN DATA WRAPPER "); deparseAppendStringInfoString(state, quote_identifier(alter_fdw_stmt->fdwname)); deparseAppendStringInfoChar(state, ' '); if (list_length(alter_fdw_stmt->func_options) > 0) { deparseFdwOptions(state, alter_fdw_stmt->func_options); deparseAppendStringInfoChar(state, ' '); } if (list_length(alter_fdw_stmt->options) > 0) deparseAlterGenericOptions(state, alter_fdw_stmt->options); removeTrailingSpace(state); } static void deparseCreateForeignServerStmt(DeparseState *state, CreateForeignServerStmt *create_foreign_server_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "CREATE SERVER "); if (create_foreign_server_stmt->if_not_exists) deparseAppendStringInfoString(state, "IF NOT EXISTS "); deparseAppendStringInfoString(state, quote_identifier(create_foreign_server_stmt->servername)); deparseAppendStringInfoChar(state, ' '); if (create_foreign_server_stmt->servertype != NULL) { deparseAppendStringInfoString(state, "TYPE "); deparseStringLiteral(state, create_foreign_server_stmt->servertype); deparseAppendStringInfoChar(state, ' '); } if (create_foreign_server_stmt->version != NULL) { deparseAppendStringInfoString(state, "VERSION "); deparseStringLiteral(state, create_foreign_server_stmt->version); deparseAppendStringInfoChar(state, ' '); } deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); deparseAppendStringInfoString(state, quote_identifier(create_foreign_server_stmt->fdwname)); deparseAppendStringInfoChar(state, ' '); deparseCreateGenericOptions(state, create_foreign_server_stmt->options); removeTrailingSpace(state); } static void deparseAlterForeignServerStmt(DeparseState *state, AlterForeignServerStmt *alter_foreign_server_stmt) { deparseAppendStringInfoString(state, "ALTER SERVER "); deparseAppendStringInfoString(state, quote_identifier(alter_foreign_server_stmt->servername)); deparseAppendStringInfoChar(state, ' '); if (alter_foreign_server_stmt->has_version) { deparseAppendStringInfoString(state, "VERSION "); if (alter_foreign_server_stmt->version != NULL) deparseStringLiteral(state, alter_foreign_server_stmt->version); else deparseAppendStringInfoString(state, "NULL"); deparseAppendStringInfoChar(state, ' '); } if (list_length(alter_foreign_server_stmt->options) > 0) deparseAlterGenericOptions(state, alter_foreign_server_stmt->options); removeTrailingSpace(state); } static void deparseCreateUserMappingStmt(DeparseState *state, CreateUserMappingStmt *create_user_mapping_stmt) { deparseAppendStringInfoString(state, "CREATE USER MAPPING "); if (create_user_mapping_stmt->if_not_exists) deparseAppendStringInfoString(state, "IF NOT EXISTS "); deparseAppendStringInfoString(state, "FOR "); deparseRoleSpec(state, create_user_mapping_stmt->user); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "SERVER "); deparseAppendStringInfoString(state, quote_identifier(create_user_mapping_stmt->servername)); deparseAppendStringInfoChar(state, ' '); deparseCreateGenericOptions(state, create_user_mapping_stmt->options); removeTrailingSpace(state); } static void deparseCreatedbStmt(DeparseState *state, CreatedbStmt *createdb_stmt) { deparseAppendStringInfoString(state, "CREATE DATABASE "); deparseColId(state, createdb_stmt->dbname); deparseAppendStringInfoChar(state, ' '); deparseCreatedbOptList(state, createdb_stmt->options); removeTrailingSpace(state); } static void deparseAlterUserMappingStmt(DeparseState *state, AlterUserMappingStmt *alter_user_mapping_stmt) { deparseAppendStringInfoString(state, "ALTER USER MAPPING FOR "); deparseRoleSpec(state, alter_user_mapping_stmt->user); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "SERVER "); deparseAppendStringInfoString(state, quote_identifier(alter_user_mapping_stmt->servername)); deparseAppendStringInfoChar(state, ' '); deparseAlterGenericOptions(state, alter_user_mapping_stmt->options); removeTrailingSpace(state); } static void deparseDropUserMappingStmt(DeparseState *state, DropUserMappingStmt *drop_user_mapping_stmt) { deparseAppendStringInfoString(state, "DROP USER MAPPING "); if (drop_user_mapping_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseAppendStringInfoString(state, "FOR "); deparseRoleSpec(state, drop_user_mapping_stmt->user); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "SERVER "); deparseAppendStringInfoString(state, quote_identifier(drop_user_mapping_stmt->servername)); } static void deparseSecLabelStmt(DeparseState *state, SecLabelStmt *sec_label_stmt) { ListCell *lc = NULL; deparseAppendStringInfoString(state, "SECURITY LABEL "); if (sec_label_stmt->provider != NULL) { deparseAppendStringInfoString(state, "FOR "); deparseAppendStringInfoString(state, quote_identifier(sec_label_stmt->provider)); deparseAppendStringInfoChar(state, ' '); } deparseAppendStringInfoString(state, "ON "); switch (sec_label_stmt->objtype) { case OBJECT_COLUMN: deparseAppendStringInfoString(state, "COLUMN "); deparseAnyName(state, castNode(List, sec_label_stmt->object)); break; case OBJECT_FOREIGN_TABLE: deparseAppendStringInfoString(state, "FOREIGN TABLE "); deparseAnyName(state, castNode(List, sec_label_stmt->object)); break; case OBJECT_SEQUENCE: deparseAppendStringInfoString(state, "SEQUENCE "); deparseAnyName(state, castNode(List, sec_label_stmt->object)); break; case OBJECT_TABLE: deparseAppendStringInfoString(state, "TABLE "); deparseAnyName(state, castNode(List, sec_label_stmt->object)); break; case OBJECT_VIEW: deparseAppendStringInfoString(state, "VIEW "); deparseAnyName(state, castNode(List, sec_label_stmt->object)); break; case OBJECT_MATVIEW: deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); deparseAnyName(state, castNode(List, sec_label_stmt->object)); break; case OBJECT_DATABASE: deparseAppendStringInfoString(state, "DATABASE "); deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_EVENT_TRIGGER: deparseAppendStringInfoString(state, "EVENT TRIGGER "); deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_LANGUAGE: deparseAppendStringInfoString(state, "LANGUAGE "); deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_PUBLICATION: deparseAppendStringInfoString(state, "PUBLICATION "); deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_ROLE: deparseAppendStringInfoString(state, "ROLE "); deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_SCHEMA: deparseAppendStringInfoString(state, "SCHEMA "); deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_SUBSCRIPTION: deparseAppendStringInfoString(state, "SUBSCRIPTION "); deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_TABLESPACE: deparseAppendStringInfoString(state, "TABLESPACE "); deparseAppendStringInfoString(state, quote_identifier(strVal(sec_label_stmt->object))); break; case OBJECT_TYPE: deparseAppendStringInfoString(state, "TYPE "); deparseTypeName(state, castNode(TypeName, sec_label_stmt->object)); break; case OBJECT_DOMAIN: deparseAppendStringInfoString(state, "DOMAIN "); deparseTypeName(state, castNode(TypeName, sec_label_stmt->object)); break; case OBJECT_AGGREGATE: deparseAppendStringInfoString(state, "AGGREGATE "); deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); break; case OBJECT_FUNCTION: deparseAppendStringInfoString(state, "FUNCTION "); deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); break; case OBJECT_LARGEOBJECT: deparseAppendStringInfoString(state, "LARGE OBJECT "); deparseValue(state, (union ValUnion *) sec_label_stmt->object, DEPARSE_NODE_CONTEXT_CONSTANT); break; case OBJECT_PROCEDURE: deparseAppendStringInfoString(state, "PROCEDURE "); deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); break; case OBJECT_ROUTINE: deparseAppendStringInfoString(state, "ROUTINE "); deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, sec_label_stmt->object)); break; default: // Not supported in the parser Assert(false); break; } deparseAppendStringInfoString(state, " IS "); if (sec_label_stmt->label != NULL) deparseStringLiteral(state, sec_label_stmt->label); else deparseAppendStringInfoString(state, "NULL"); } static void deparseCreateForeignTableStmt(DeparseState *state, CreateForeignTableStmt *create_foreign_table_stmt) { ListCell *lc; deparseCreateStmt(state, &create_foreign_table_stmt->base, true); deparseAppendStringInfoString(state, " SERVER "); deparseAppendStringInfoString(state, quote_identifier(create_foreign_table_stmt->servername)); deparseAppendStringInfoChar(state, ' '); if (list_length(create_foreign_table_stmt->options) > 0) deparseAlterGenericOptions(state, create_foreign_table_stmt->options); removeTrailingSpace(state); } static void deparseImportForeignSchemaStmt(DeparseState *state, ImportForeignSchemaStmt *import_foreign_schema_stmt) { deparseAppendStringInfoString(state, "IMPORT FOREIGN SCHEMA "); deparseAppendStringInfoString(state, import_foreign_schema_stmt->remote_schema); deparseAppendStringInfoChar(state, ' '); switch (import_foreign_schema_stmt->list_type) { case FDW_IMPORT_SCHEMA_ALL: // Default break; case FDW_IMPORT_SCHEMA_LIMIT_TO: deparseAppendStringInfoString(state, "LIMIT TO ("); deparseRelationExprList(state, import_foreign_schema_stmt->table_list); deparseAppendStringInfoString(state, ") "); break; case FDW_IMPORT_SCHEMA_EXCEPT: deparseAppendStringInfoString(state, "EXCEPT ("); deparseRelationExprList(state, import_foreign_schema_stmt->table_list); deparseAppendStringInfoString(state, ") "); break; } deparseAppendStringInfoString(state, "FROM SERVER "); deparseAppendStringInfoString(state, quote_identifier(import_foreign_schema_stmt->server_name)); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "INTO "); deparseAppendStringInfoString(state, quote_identifier(import_foreign_schema_stmt->local_schema)); deparseAppendStringInfoChar(state, ' '); deparseCreateGenericOptions(state, import_foreign_schema_stmt->options); removeTrailingSpace(state); } static void deparseCreateTableAsStmt(DeparseState *state, CreateTableAsStmt *create_table_as_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "CREATE "); deparseOptTemp(state, create_table_as_stmt->into->rel->relpersistence); switch (create_table_as_stmt->objtype) { case OBJECT_TABLE: deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_MATVIEW: deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; default: // Not supported here Assert(false); break; } if (create_table_as_stmt->if_not_exists) deparseAppendStringInfoString(state, "IF NOT EXISTS "); deparseIntoClause(state, create_table_as_stmt->into); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "AS "); if (IsA(create_table_as_stmt->query, ExecuteStmt)) deparseExecuteStmt(state, castNode(ExecuteStmt, create_table_as_stmt->query)); else deparseSelectStmt(state, castNode(SelectStmt, create_table_as_stmt->query), DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); if (create_table_as_stmt->into->skipData) deparseAppendStringInfoString(state, "WITH NO DATA "); removeTrailingSpace(state); } static void deparseViewStmt(DeparseState *state, ViewStmt *view_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "CREATE "); if (view_stmt->replace) deparseAppendStringInfoString(state, "OR REPLACE "); deparseOptTemp(state, view_stmt->view->relpersistence); deparseAppendStringInfoString(state, "VIEW "); deparseRangeVar(state, view_stmt->view, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); if (list_length(view_stmt->aliases) > 0) { deparseAppendStringInfoChar(state, '('); deparseColumnList(state, view_stmt->aliases); deparseAppendStringInfoString(state, ") "); } deparseOptWith(state, view_stmt->options); deparseAppendStringInfoString(state, "AS "); deparseSelectStmt(state, castNode(SelectStmt, view_stmt->query), DEPARSE_NODE_CONTEXT_NONE); switch (view_stmt->withCheckOption) { case NO_CHECK_OPTION: // Default break; case LOCAL_CHECK_OPTION: deparseAppendStringInfoString(state, "WITH LOCAL CHECK OPTION "); break; case CASCADED_CHECK_OPTION: deparseAppendStringInfoString(state, "WITH CHECK OPTION "); break; } removeTrailingSpace(state); } static void deparseDropStmt(DeparseState *state, DropStmt *drop_stmt) { ListCell *lc; List *l; deparseAppendStringInfoString(state, "DROP "); switch (drop_stmt->removeType) { case OBJECT_ACCESS_METHOD: deparseAppendStringInfoString(state, "ACCESS METHOD "); break; case OBJECT_AGGREGATE: deparseAppendStringInfoString(state, "AGGREGATE "); break; case OBJECT_CAST: deparseAppendStringInfoString(state, "CAST "); break; case OBJECT_COLLATION: deparseAppendStringInfoString(state, "COLLATION "); break; case OBJECT_CONVERSION: deparseAppendStringInfoString(state, "CONVERSION "); break; case OBJECT_DOMAIN: deparseAppendStringInfoString(state, "DOMAIN "); break; case OBJECT_EVENT_TRIGGER: deparseAppendStringInfoString(state, "EVENT TRIGGER "); break; case OBJECT_EXTENSION: deparseAppendStringInfoString(state, "EXTENSION "); break; case OBJECT_FDW: deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); break; case OBJECT_FOREIGN_SERVER: deparseAppendStringInfoString(state, "SERVER "); break; case OBJECT_FOREIGN_TABLE: deparseAppendStringInfoString(state, "FOREIGN TABLE "); break; case OBJECT_FUNCTION: deparseAppendStringInfoString(state, "FUNCTION "); break; case OBJECT_INDEX: deparseAppendStringInfoString(state, "INDEX "); break; case OBJECT_LANGUAGE: deparseAppendStringInfoString(state, "LANGUAGE "); break; case OBJECT_MATVIEW: deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; case OBJECT_OPCLASS: deparseAppendStringInfoString(state, "OPERATOR CLASS "); break; case OBJECT_OPERATOR: deparseAppendStringInfoString(state, "OPERATOR "); break; case OBJECT_OPFAMILY: deparseAppendStringInfoString(state, "OPERATOR FAMILY "); break; case OBJECT_POLICY: deparseAppendStringInfoString(state, "POLICY "); break; case OBJECT_PROCEDURE: deparseAppendStringInfoString(state, "PROCEDURE "); break; case OBJECT_PUBLICATION: deparseAppendStringInfoString(state, "PUBLICATION "); break; case OBJECT_ROUTINE: deparseAppendStringInfoString(state, "ROUTINE "); break; case OBJECT_RULE: deparseAppendStringInfoString(state, "RULE "); break; case OBJECT_SCHEMA: deparseAppendStringInfoString(state, "SCHEMA "); break; case OBJECT_SEQUENCE: deparseAppendStringInfoString(state, "SEQUENCE "); break; case OBJECT_STATISTIC_EXT: deparseAppendStringInfoString(state, "STATISTICS "); break; case OBJECT_TABLE: deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_TRANSFORM: deparseAppendStringInfoString(state, "TRANSFORM "); break; case OBJECT_TRIGGER: deparseAppendStringInfoString(state, "TRIGGER "); break; case OBJECT_TSCONFIGURATION: deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); break; case OBJECT_TSDICTIONARY: deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); break; case OBJECT_TSPARSER: deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); break; case OBJECT_TSTEMPLATE: deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); break; case OBJECT_TYPE: deparseAppendStringInfoString(state, "TYPE "); break; case OBJECT_VIEW: deparseAppendStringInfoString(state, "VIEW "); break; default: // Other object types are not supported here in the parser Assert(false); } if (drop_stmt->concurrent) deparseAppendStringInfoString(state, "CONCURRENTLY "); if (drop_stmt->missing_ok) deparseAppendStringInfoString(state, "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(state, drop_stmt->objects); deparseAppendStringInfoChar(state, ' '); 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(state, drop_stmt->objects); deparseAppendStringInfoChar(state, ' '); 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(state, strVal(llast(l))); deparseAppendStringInfoString(state, " ON "); deparseAnyNameSkipLast(state, l); deparseAppendStringInfoChar(state, ' '); break; case OBJECT_CAST: Assert(list_length(drop_stmt->objects) == 1); l = linitial(drop_stmt->objects); Assert(list_length(l) == 2); deparseAppendStringInfoChar(state, '('); deparseTypeName(state, castNode(TypeName, linitial(l))); deparseAppendStringInfoString(state, " AS "); deparseTypeName(state, castNode(TypeName, lsecond(l))); deparseAppendStringInfoChar(state, ')'); deparseAppendStringInfoChar(state, ' '); break; case OBJECT_OPFAMILY: case OBJECT_OPCLASS: Assert(list_length(drop_stmt->objects) == 1); l = linitial(drop_stmt->objects); deparseAnyNameSkipFirst(state, l); deparseAppendStringInfoString(state, " USING "); deparseColId(state, strVal(linitial(l))); deparseAppendStringInfoChar(state, ' '); break; case OBJECT_TRANSFORM: Assert(list_length(drop_stmt->objects) == 1); l = linitial(drop_stmt->objects); deparseAppendStringInfoString(state, "FOR "); deparseTypeName(state, castNode(TypeName, linitial(l))); deparseAppendStringInfoString(state, " LANGUAGE "); deparseColId(state, strVal(lsecond(l))); deparseAppendStringInfoChar(state, ' '); break; case OBJECT_LANGUAGE: deparseNameList(state, drop_stmt->objects); deparseAppendStringInfoChar(state, ' '); break; case OBJECT_TYPE: case OBJECT_DOMAIN: foreach(lc, drop_stmt->objects) { deparseTypeName(state, castNode(TypeName, lfirst(lc))); if (lnext(drop_stmt->objects, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ' '); break; case OBJECT_AGGREGATE: foreach(lc, drop_stmt->objects) { deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); if (lnext(drop_stmt->objects, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ' '); break; case OBJECT_FUNCTION: case OBJECT_PROCEDURE: case OBJECT_ROUTINE: foreach(lc, drop_stmt->objects) { deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); if (lnext(drop_stmt->objects, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ' '); break; case OBJECT_OPERATOR: foreach(lc, drop_stmt->objects) { deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, lfirst(lc))); if (lnext(drop_stmt->objects, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ' '); break; default: Assert(false); } deparseOptDropBehavior(state, drop_stmt->behavior); removeTrailingSpace(state); } static void deparseGroupingSet(DeparseState *state, GroupingSet *grouping_set) { switch(grouping_set->kind) { case GROUPING_SET_EMPTY: deparseAppendStringInfoString(state, "()"); break; case GROUPING_SET_SIMPLE: // Not present in raw parse trees Assert(false); break; case GROUPING_SET_ROLLUP: deparseAppendStringInfoString(state, "ROLLUP ("); deparseExprList(state, grouping_set->content); deparseAppendStringInfoChar(state, ')'); break; case GROUPING_SET_CUBE: deparseAppendStringInfoString(state, "CUBE ("); deparseExprList(state, grouping_set->content); deparseAppendStringInfoChar(state, ')'); break; case GROUPING_SET_SETS: deparseAppendStringInfoString(state, "GROUPING SETS ("); deparseGroupByList(state, grouping_set->content); deparseAppendStringInfoChar(state, ')'); break; } } static void deparseDropTableSpaceStmt(DeparseState *state, DropTableSpaceStmt *drop_table_space_stmt) { deparseAppendStringInfoString(state, "DROP TABLESPACE "); if (drop_table_space_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseAppendStringInfoString(state, drop_table_space_stmt->tablespacename); } static void deparseAlterObjectDependsStmt(DeparseState *state, AlterObjectDependsStmt *alter_object_depends_stmt) { deparseAppendStringInfoString(state, "ALTER "); switch (alter_object_depends_stmt->objectType) { case OBJECT_FUNCTION: deparseAppendStringInfoString(state, "FUNCTION "); deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); break; case OBJECT_PROCEDURE: deparseAppendStringInfoString(state, "PROCEDURE "); deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); break; case OBJECT_ROUTINE: deparseAppendStringInfoString(state, "ROUTINE "); deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_depends_stmt->object)); break; case OBJECT_TRIGGER: deparseAppendStringInfoString(state, "TRIGGER "); deparseColId(state, strVal(linitial(castNode(List, alter_object_depends_stmt->object)))); deparseAppendStringInfoString(state, " ON "); deparseRangeVar(state, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_MATVIEW: deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); deparseRangeVar(state, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_INDEX: deparseAppendStringInfoString(state, "INDEX "); deparseRangeVar(state, alter_object_depends_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; default: // No other object types supported here Assert(false); } deparseAppendStringInfoChar(state, ' '); if (alter_object_depends_stmt->remove) deparseAppendStringInfoString(state, "NO "); deparseAppendStringInfo(state, "DEPENDS ON EXTENSION %s", alter_object_depends_stmt->extname->sval); } static void deparseAlterObjectSchemaStmt(DeparseState *state, AlterObjectSchemaStmt *alter_object_schema_stmt) { List *l = NULL; ListCell *lc = NULL; deparseAppendStringInfoString(state, "ALTER "); switch (alter_object_schema_stmt->objectType) { case OBJECT_AGGREGATE: deparseAppendStringInfoString(state, "AGGREGATE "); deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); break; case OBJECT_COLLATION: deparseAppendStringInfoString(state, "COLLATION "); deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_CONVERSION: deparseAppendStringInfoString(state, "CONVERSION "); deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_DOMAIN: deparseAppendStringInfoString(state, "DOMAIN "); deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_EXTENSION: deparseAppendStringInfoString(state, "EXTENSION "); deparseAppendStringInfoString(state, quote_identifier(strVal(alter_object_schema_stmt->object))); break; case OBJECT_FUNCTION: deparseAppendStringInfoString(state, "FUNCTION "); deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); break; case OBJECT_OPERATOR: deparseAppendStringInfoString(state, "OPERATOR "); deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); break; case OBJECT_OPCLASS: l = castNode(List, alter_object_schema_stmt->object); deparseAppendStringInfoString(state, "OPERATOR CLASS "); deparseAnyNameSkipFirst(state, l); deparseAppendStringInfoString(state, " USING "); deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); break; case OBJECT_OPFAMILY: l = castNode(List, alter_object_schema_stmt->object); deparseAppendStringInfoString(state, "OPERATOR FAMILY "); deparseAnyNameSkipFirst(state, l); deparseAppendStringInfoString(state, " USING "); deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); break; case OBJECT_PROCEDURE: deparseAppendStringInfoString(state, "PROCEDURE "); deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); break; case OBJECT_ROUTINE: deparseAppendStringInfoString(state, "ROUTINE "); deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_object_schema_stmt->object)); break; case OBJECT_TABLE: deparseAppendStringInfoString(state, "TABLE "); if (alter_object_schema_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_STATISTIC_EXT: deparseAppendStringInfoString(state, "STATISTICS "); deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_TSPARSER: deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_TSDICTIONARY: deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_TSTEMPLATE: deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_TSCONFIGURATION: deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; case OBJECT_SEQUENCE: deparseAppendStringInfoString(state, "SEQUENCE "); if (alter_object_schema_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_VIEW: deparseAppendStringInfoString(state, "VIEW "); if (alter_object_schema_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_MATVIEW: deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); if (alter_object_schema_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_FOREIGN_TABLE: deparseAppendStringInfoString(state, "FOREIGN TABLE "); if (alter_object_schema_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseRangeVar(state, alter_object_schema_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_TYPE: deparseAppendStringInfoString(state, "TYPE "); deparseAnyName(state, castNode(List, alter_object_schema_stmt->object)); break; default: Assert(false); break; } deparseAppendStringInfoString(state, " SET SCHEMA "); deparseAppendStringInfoString(state, quote_identifier(alter_object_schema_stmt->newschema)); } // "alter_table_cmd" in gram.y static void deparseAlterTableCmd(DeparseState *state, 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) deparseAppendStringInfoString(state, "ADD ATTRIBUTE "); else deparseAppendStringInfoString(state, "ADD COLUMN "); 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 */ deparseAppendStringInfoString(state, "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 */ deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "DROP NOT NULL"; break; case AT_SetNotNull: /* alter column set not null */ deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "SET NOT NULL"; break; case AT_DropExpression: /* alter column drop expression */ deparseAppendStringInfoString(state, "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 */ deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "SET STATISTICS"; break; case AT_SetOptions: /* alter column set ( options ) */ deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "SET"; break; case AT_ResetOptions: /* alter column reset ( options ) */ deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "RESET"; break; case AT_SetStorage: /* alter column set storage */ deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "SET STORAGE"; break; case AT_SetCompression: /* alter column set compression */ deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "SET COMPRESSION"; break; case AT_DropColumn: /* drop column */ if (context == DEPARSE_NODE_CONTEXT_ALTER_TYPE) deparseAppendStringInfoString(state, "DROP ATTRIBUTE "); else deparseAppendStringInfoString(state, "DROP "); break; case AT_AddIndex: /* add index */ deparseAppendStringInfoString(state, "ADD INDEX "); break; case AT_ReAddIndex: /* internal to commands/tablecmds.c */ Assert(false); break; case AT_AddConstraint: /* add constraint */ deparseAppendStringInfoString(state, "ADD "); 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 */ deparseAppendStringInfoString(state, "ALTER "); // CONSTRAINT keyword gets added by the Constraint itself (when deparsing def) break; case AT_ValidateConstraint: /* validate constraint */ deparseAppendStringInfoString(state, "VALIDATE CONSTRAINT "); break; case AT_AddIndexConstraint: /* add constraint using existing index */ // Not present in raw parser output Assert(false); break; case AT_DropConstraint: /* drop constraint */ deparseAppendStringInfoString(state, "DROP CONSTRAINT "); 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) deparseAppendStringInfoString(state, "ALTER ATTRIBUTE "); else deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "TYPE"; break; case AT_AlterColumnGenericOptions: /* alter column OPTIONS (...) */ deparseAppendStringInfoString(state, "ALTER COLUMN "); // Handled via special case in def handling break; case AT_ChangeOwner: /* change owner */ deparseAppendStringInfoString(state, "OWNER TO "); deparseRoleSpec(state, alter_table_cmd->newowner); break; case AT_ClusterOn: /* CLUSTER ON */ deparseAppendStringInfoString(state, "CLUSTER ON "); break; case AT_DropCluster: /* SET WITHOUT CLUSTER */ deparseAppendStringInfoString(state, "SET WITHOUT CLUSTER "); break; case AT_SetLogged: /* SET LOGGED */ deparseAppendStringInfoString(state, "SET LOGGED "); break; case AT_SetUnLogged: /* SET UNLOGGED */ deparseAppendStringInfoString(state, "SET UNLOGGED "); break; case AT_DropOids: /* SET WITHOUT OIDS */ deparseAppendStringInfoString(state, "SET WITHOUT OIDS "); break; case AT_SetTableSpace: /* SET TABLESPACE */ deparseAppendStringInfoString(state, "SET TABLESPACE "); break; case AT_SetRelOptions: /* SET (...) -- AM specific parameters */ deparseAppendStringInfoString(state, "SET "); break; case AT_SetAccessMethod: deparseAppendStringInfo(state, "SET ACCESS METHOD "); break; case AT_ResetRelOptions: /* RESET (...) -- AM specific parameters */ deparseAppendStringInfoString(state, "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 */ deparseAppendStringInfoString(state, "ENABLE TRIGGER "); break; case AT_EnableAlwaysTrig: /* ENABLE ALWAYS TRIGGER name */ deparseAppendStringInfoString(state, "ENABLE ALWAYS TRIGGER "); break; case AT_EnableReplicaTrig: /* ENABLE REPLICA TRIGGER name */ deparseAppendStringInfoString(state, "ENABLE REPLICA TRIGGER "); break; case AT_DisableTrig: /* DISABLE TRIGGER name */ deparseAppendStringInfoString(state, "DISABLE TRIGGER "); break; case AT_EnableTrigAll: /* ENABLE TRIGGER ALL */ deparseAppendStringInfoString(state, "ENABLE TRIGGER ALL "); break; case AT_DisableTrigAll: /* DISABLE TRIGGER ALL */ deparseAppendStringInfoString(state, "DISABLE TRIGGER ALL "); break; case AT_EnableTrigUser: /* ENABLE TRIGGER USER */ deparseAppendStringInfoString(state, "ENABLE TRIGGER USER "); break; case AT_DisableTrigUser: /* DISABLE TRIGGER USER */ deparseAppendStringInfoString(state, "DISABLE TRIGGER USER "); break; case AT_EnableRule: /* ENABLE RULE name */ deparseAppendStringInfoString(state, "ENABLE RULE "); break; case AT_EnableAlwaysRule: /* ENABLE ALWAYS RULE name */ deparseAppendStringInfoString(state, "ENABLE ALWAYS RULE "); break; case AT_EnableReplicaRule: /* ENABLE REPLICA RULE name */ deparseAppendStringInfoString(state, "ENABLE REPLICA RULE "); break; case AT_DisableRule: /* DISABLE RULE name */ deparseAppendStringInfoString(state, "DISABLE RULE "); break; case AT_AddInherit: /* INHERIT parent */ deparseAppendStringInfoString(state, "INHERIT "); break; case AT_DropInherit: /* NO INHERIT parent */ deparseAppendStringInfoString(state, "NO INHERIT "); break; case AT_AddOf: /* OF */ deparseAppendStringInfoString(state, "OF "); break; case AT_DropOf: /* NOT OF */ deparseAppendStringInfoString(state, "NOT OF "); break; case AT_ReplicaIdentity: /* REPLICA IDENTITY */ deparseAppendStringInfoString(state, "REPLICA IDENTITY "); break; case AT_EnableRowSecurity: /* ENABLE ROW SECURITY */ deparseAppendStringInfoString(state, "ENABLE ROW LEVEL SECURITY "); break; case AT_DisableRowSecurity: /* DISABLE ROW SECURITY */ deparseAppendStringInfoString(state, "DISABLE ROW LEVEL SECURITY "); break; case AT_ForceRowSecurity: /* FORCE ROW SECURITY */ deparseAppendStringInfoString(state, "FORCE ROW LEVEL SECURITY "); break; case AT_NoForceRowSecurity: /* NO FORCE ROW SECURITY */ deparseAppendStringInfoString(state, "NO FORCE ROW LEVEL SECURITY "); break; case AT_GenericOptions: /* OPTIONS (...) */ // Handled in def field handling break; case AT_AttachPartition: /* ATTACH PARTITION */ deparseAppendStringInfoString(state, "ATTACH PARTITION "); break; case AT_DetachPartition: /* DETACH PARTITION */ deparseAppendStringInfoString(state, "DETACH PARTITION "); break; case AT_DetachPartitionFinalize: /* DETACH PARTITION FINALIZE */ deparseAppendStringInfoString(state, "DETACH PARTITION "); break; case AT_AddIdentity: /* ADD IDENTITY */ deparseAppendStringInfoString(state, "ALTER "); options = "ADD"; // Other details are output via the constraint node (in def field) break; case AT_SetIdentity: /* SET identity column options */ deparseAppendStringInfoString(state, "ALTER "); break; case AT_DropIdentity: /* DROP IDENTITY */ deparseAppendStringInfoString(state, "ALTER COLUMN "); options = "DROP IDENTITY"; trailing_missing_ok = true; break; case AT_SetExpression: deparseAppendStringInfoString(state, "ALTER COLUMN "); break; } if (alter_table_cmd->missing_ok && !trailing_missing_ok) { if (alter_table_cmd->subtype == AT_AddColumn) deparseAppendStringInfoString(state, "IF NOT EXISTS "); else deparseAppendStringInfoString(state, "IF EXISTS "); } if (alter_table_cmd->name != NULL) { deparseAppendStringInfoString(state, quote_identifier(alter_table_cmd->name)); deparseAppendStringInfoChar(state, ' '); } else if (alter_table_cmd->subtype == AT_SetAccessMethod) { deparseAppendStringInfoString(state, " DEFAULT"); } if (alter_table_cmd->num > 0) deparseAppendStringInfo(state, "%d ", alter_table_cmd->num); if (options != NULL) { deparseAppendStringInfoString(state, options); deparseAppendStringInfoChar(state, ' '); } if (alter_table_cmd->missing_ok && trailing_missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); switch (alter_table_cmd->subtype) { case AT_AttachPartition: case AT_DetachPartition: deparsePartitionCmd(state, castNode(PartitionCmd, alter_table_cmd->def)); deparseAppendStringInfoChar(state, ' '); break; case AT_DetachPartitionFinalize: deparsePartitionCmd(state, castNode(PartitionCmd, alter_table_cmd->def)); deparseAppendStringInfoString(state, "FINALIZE "); break; case AT_AddColumn: case AT_AlterColumnType: deparseColumnDef(state, castNode(ColumnDef, alter_table_cmd->def)); deparseAppendStringInfoChar(state, ' '); break; case AT_ColumnDefault: if (alter_table_cmd->def != NULL) { deparseExpr(state, alter_table_cmd->def, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ' '); } break; case AT_SetStatistics: if (alter_table_cmd->def != NULL) deparseSignedIconst(state, alter_table_cmd->def); else deparseAppendStringInfoString(state, "DEFAULT"); deparseAppendStringInfoChar(state, ' '); break; case AT_SetOptions: case AT_ResetOptions: case AT_SetRelOptions: case AT_ResetRelOptions: deparseRelOptions(state, castNode(List, alter_table_cmd->def)); deparseAppendStringInfoChar(state, ' '); break; case AT_SetStorage: deparseColId(state, strVal(alter_table_cmd->def)); deparseAppendStringInfoChar(state, ' '); break; case AT_SetCompression: if (strcmp(strVal(alter_table_cmd->def), "default") == 0) deparseAppendStringInfoString(state, "DEFAULT"); else deparseColId(state, strVal(alter_table_cmd->def)); deparseAppendStringInfoChar(state, ' '); break; case AT_AddIdentity: case AT_AddConstraint: case AT_AlterConstraint: deparseConstraint(state, castNode(Constraint, alter_table_cmd->def)); deparseAppendStringInfoChar(state, ' '); break; case AT_SetIdentity: deparseAlterIdentityColumnOptionList(state, castNode(List, alter_table_cmd->def)); deparseAppendStringInfoChar(state, ' '); break; case AT_AlterColumnGenericOptions: case AT_GenericOptions: deparseAlterGenericOptions(state, castNode(List, alter_table_cmd->def)); deparseAppendStringInfoChar(state, ' '); break; case AT_AddInherit: case AT_DropInherit: deparseRangeVar(state, castNode(RangeVar, alter_table_cmd->def), DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); break; case AT_AddOf: deparseTypeName(state, castNode(TypeName, alter_table_cmd->def)); deparseAppendStringInfoChar(state, ' '); break; case AT_ReplicaIdentity: deparseReplicaIdentityStmt(state, castNode(ReplicaIdentityStmt, alter_table_cmd->def)); deparseAppendStringInfoChar(state, ' '); break; case AT_SetExpression: deparseAppendStringInfoString(state, "SET EXPRESSION AS ("); deparseExpr(state, alter_table_cmd->def, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ')'); break; default: Assert(alter_table_cmd->def == NULL); break; } deparseOptDropBehavior(state, alter_table_cmd->behavior); removeTrailingSpace(state); } static DeparseNodeContext deparseAlterTableObjType(DeparseState *state, ObjectType type) { switch (type) { case OBJECT_TABLE: deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_FOREIGN_TABLE: deparseAppendStringInfoString(state, "FOREIGN TABLE "); break; case OBJECT_INDEX: deparseAppendStringInfoString(state, "INDEX "); break; case OBJECT_SEQUENCE: deparseAppendStringInfoString(state, "SEQUENCE "); break; case OBJECT_VIEW: deparseAppendStringInfoString(state, "VIEW "); break; case OBJECT_MATVIEW: deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; case OBJECT_TYPE: deparseAppendStringInfoString(state, "TYPE "); return DEPARSE_NODE_CONTEXT_ALTER_TYPE; break; default: Assert(false); break; } return DEPARSE_NODE_CONTEXT_NONE; } static void deparseAlterTableMoveAllStmt(DeparseState *state, AlterTableMoveAllStmt *move_all_stmt) { deparseAppendStringInfoString(state, "ALTER "); deparseAlterTableObjType(state, move_all_stmt->objtype); deparseAppendStringInfoString(state, "ALL IN TABLESPACE "); deparseAppendStringInfoString(state, move_all_stmt->orig_tablespacename); deparseAppendStringInfoChar(state, ' '); if (move_all_stmt->roles) { deparseAppendStringInfoString(state, "OWNED BY "); deparseRoleList(state, move_all_stmt->roles); deparseAppendStringInfoChar(state, ' '); } deparseAppendStringInfoString(state, "SET TABLESPACE "); deparseAppendStringInfoString(state, move_all_stmt->new_tablespacename); deparseAppendStringInfoChar(state, ' '); if (move_all_stmt->nowait) { deparseAppendStringInfoString(state, "NOWAIT"); } } static void deparseAlterTableStmt(DeparseState *state, AlterTableStmt *alter_table_stmt) { ListCell *lc; DeparseStateNestingLevel *parent_level = NULL; deparseAppendStringInfoString(state, "ALTER "); DeparseNodeContext context = deparseAlterTableObjType(state, alter_table_stmt->objtype); if (alter_table_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseRangeVar(state, alter_table_stmt->relation, context); deparseAppendStringInfoChar(state, ' '); parent_level = deparseStateIncreaseNestingLevel(state); foreach(lc, alter_table_stmt->cmds) { deparseAlterTableCmd(state, castNode(AlterTableCmd, lfirst(lc)), context); if (lnext(alter_table_stmt->cmds, lc)) deparseAppendCommaAndPart(state); } deparseStateDecreaseNestingLevel(state, parent_level); } static void deparseAlterTableSpaceOptionsStmt(DeparseState *state, AlterTableSpaceOptionsStmt *alter_table_space_options_stmt) { deparseAppendStringInfoString(state, "ALTER TABLESPACE "); deparseColId(state, alter_table_space_options_stmt->tablespacename); deparseAppendStringInfoChar(state, ' '); if (alter_table_space_options_stmt->isReset) deparseAppendStringInfoString(state, "RESET "); else deparseAppendStringInfoString(state, "SET "); deparseRelOptions(state, alter_table_space_options_stmt->options); } // "AlterDomainStmt" in gram.y static void deparseAlterDomainStmt(DeparseState *state, AlterDomainStmt *alter_domain_stmt) { deparseAppendStringInfoString(state, "ALTER DOMAIN "); deparseAnyName(state, alter_domain_stmt->typeName); deparseAppendStringInfoChar(state, ' '); switch (alter_domain_stmt->subtype) { case 'T': if (alter_domain_stmt->def != NULL) { deparseAppendStringInfoString(state, "SET DEFAULT "); deparseExpr(state, alter_domain_stmt->def, DEPARSE_NODE_CONTEXT_A_EXPR); } else { deparseAppendStringInfoString(state, "DROP DEFAULT"); } break; case 'N': deparseAppendStringInfoString(state, "DROP NOT NULL"); break; case 'O': deparseAppendStringInfoString(state, "SET NOT NULL"); break; case 'C': deparseAppendStringInfoString(state, "ADD "); deparseConstraint(state, castNode(Constraint, alter_domain_stmt->def)); break; case 'X': deparseAppendStringInfoString(state, "DROP CONSTRAINT "); if (alter_domain_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseAppendStringInfoString(state, quote_identifier(alter_domain_stmt->name)); if (alter_domain_stmt->behavior == DROP_CASCADE) deparseAppendStringInfoString(state, " CASCADE"); break; case 'V': deparseAppendStringInfoString(state, "VALIDATE CONSTRAINT "); deparseAppendStringInfoString(state, quote_identifier(alter_domain_stmt->name)); break; default: // No other subtypes supported by the parser Assert(false); } } static void deparseRenameStmt(DeparseState *state, RenameStmt *rename_stmt) { List *l = NULL; deparseAppendStringInfoString(state, "ALTER "); switch (rename_stmt->renameType) { case OBJECT_AGGREGATE: deparseAppendStringInfoString(state, "AGGREGATE "); break; case OBJECT_COLLATION: deparseAppendStringInfoString(state, "COLLATION "); break; case OBJECT_CONVERSION: deparseAppendStringInfoString(state, "CONVERSION "); break; case OBJECT_DATABASE: deparseAppendStringInfoString(state, "DATABASE "); break; case OBJECT_DOMAIN: case OBJECT_DOMCONSTRAINT: deparseAppendStringInfoString(state, "DOMAIN "); break; case OBJECT_FDW: deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); break; case OBJECT_FUNCTION: deparseAppendStringInfoString(state, "FUNCTION "); break; case OBJECT_ROLE: deparseAppendStringInfoString(state, "ROLE "); break; case OBJECT_LANGUAGE: deparseAppendStringInfoString(state, "LANGUAGE "); break; case OBJECT_OPCLASS: deparseAppendStringInfoString(state, "OPERATOR CLASS "); break; case OBJECT_OPFAMILY: deparseAppendStringInfoString(state, "OPERATOR FAMILY "); break; case OBJECT_POLICY: deparseAppendStringInfoString(state, "POLICY "); break; case OBJECT_PROCEDURE: deparseAppendStringInfoString(state, "PROCEDURE "); break; case OBJECT_PUBLICATION: deparseAppendStringInfoString(state, "PUBLICATION "); break; case OBJECT_ROUTINE: deparseAppendStringInfoString(state, "ROUTINE "); break; case OBJECT_SCHEMA: deparseAppendStringInfoString(state, "SCHEMA "); break; case OBJECT_FOREIGN_SERVER: deparseAppendStringInfoString(state, "SERVER "); break; case OBJECT_SUBSCRIPTION: deparseAppendStringInfoString(state, "SUBSCRIPTION "); break; case OBJECT_TABLE: case OBJECT_TABCONSTRAINT: deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_COLUMN: switch (rename_stmt->relationType) { case OBJECT_TABLE: deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_FOREIGN_TABLE: deparseAppendStringInfoString(state, "FOREIGN TABLE "); break; case OBJECT_VIEW: deparseAppendStringInfoString(state, "VIEW "); break; case OBJECT_MATVIEW: deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; default: Assert(false); } break; case OBJECT_SEQUENCE: deparseAppendStringInfoString(state, "SEQUENCE "); break; case OBJECT_VIEW: deparseAppendStringInfoString(state, "VIEW "); break; case OBJECT_MATVIEW: deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; case OBJECT_INDEX: deparseAppendStringInfoString(state, "INDEX "); break; case OBJECT_FOREIGN_TABLE: deparseAppendStringInfoString(state, "FOREIGN TABLE "); break; case OBJECT_RULE: deparseAppendStringInfoString(state, "RULE "); break; case OBJECT_TRIGGER: deparseAppendStringInfoString(state, "TRIGGER "); break; case OBJECT_EVENT_TRIGGER: deparseAppendStringInfoString(state, "EVENT TRIGGER "); break; case OBJECT_TABLESPACE: deparseAppendStringInfoString(state, "TABLESPACE "); break; case OBJECT_STATISTIC_EXT: deparseAppendStringInfoString(state, "STATISTICS "); break; case OBJECT_TSPARSER: deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); break; case OBJECT_TSDICTIONARY: deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); break; case OBJECT_TSTEMPLATE: deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); break; case OBJECT_TSCONFIGURATION: deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); break; case OBJECT_TYPE: case OBJECT_ATTRIBUTE: deparseAppendStringInfoString(state, "TYPE "); break; default: Assert(false); break; } if (rename_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); switch (rename_stmt->renameType) { case OBJECT_AGGREGATE: deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, rename_stmt->object)); deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_DOMCONSTRAINT: deparseAnyName(state, castNode(List, rename_stmt->object)); deparseAppendStringInfoString(state, " RENAME CONSTRAINT "); deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); deparseAppendStringInfoChar(state, ' '); break; case OBJECT_OPCLASS: case OBJECT_OPFAMILY: l = castNode(List, rename_stmt->object); deparseAnyNameSkipFirst(state, l); deparseAppendStringInfoString(state, " USING "); deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_POLICY: deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); deparseAppendStringInfoString(state, " ON "); deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_FUNCTION: case OBJECT_PROCEDURE: case OBJECT_ROUTINE: deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, rename_stmt->object)); deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_SUBSCRIPTION: deparseColId(state, strVal(rename_stmt->object)); deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_TABLE: case OBJECT_SEQUENCE: case OBJECT_VIEW: case OBJECT_MATVIEW: case OBJECT_INDEX: case OBJECT_FOREIGN_TABLE: deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_COLUMN: deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoString(state, " RENAME COLUMN "); deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); deparseAppendStringInfoChar(state, ' '); break; case OBJECT_TABCONSTRAINT: deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoString(state, " RENAME CONSTRAINT "); deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); deparseAppendStringInfoChar(state, ' '); break; case OBJECT_RULE: case OBJECT_TRIGGER: deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); deparseAppendStringInfoString(state, " ON "); deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_FDW: case OBJECT_LANGUAGE: case OBJECT_PUBLICATION: case OBJECT_FOREIGN_SERVER: case OBJECT_EVENT_TRIGGER: deparseAppendStringInfoString(state, quote_identifier(strVal(rename_stmt->object))); deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_DATABASE: case OBJECT_ROLE: case OBJECT_SCHEMA: case OBJECT_TABLESPACE: deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); deparseAppendStringInfoString(state, " 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(state, castNode(List, rename_stmt->object)); deparseAppendStringInfoString(state, " RENAME "); break; case OBJECT_ATTRIBUTE: deparseRangeVar(state, rename_stmt->relation, DEPARSE_NODE_CONTEXT_ALTER_TYPE); deparseAppendStringInfoString(state, " RENAME ATTRIBUTE "); deparseAppendStringInfoString(state, quote_identifier(rename_stmt->subname)); deparseAppendStringInfoChar(state, ' '); break; default: Assert(false); break; } deparseAppendStringInfoString(state, "TO "); deparseAppendStringInfoString(state, quote_identifier(rename_stmt->newname)); deparseAppendStringInfoChar(state, ' '); deparseOptDropBehavior(state, rename_stmt->behavior); removeTrailingSpace(state); } static void deparseTransactionStmt(DeparseState *state, TransactionStmt *transaction_stmt) { ListCell *lc; switch (transaction_stmt->kind) { case TRANS_STMT_BEGIN: deparseAppendStringInfoString(state, "BEGIN "); deparseTransactionModeList(state, transaction_stmt->options); break; case TRANS_STMT_START: deparseAppendStringInfoString(state, "START TRANSACTION "); deparseTransactionModeList(state, transaction_stmt->options); break; case TRANS_STMT_COMMIT: deparseAppendStringInfoString(state, "COMMIT "); if (transaction_stmt->chain) deparseAppendStringInfoString(state, "AND CHAIN "); break; case TRANS_STMT_ROLLBACK: deparseAppendStringInfoString(state, "ROLLBACK "); if (transaction_stmt->chain) deparseAppendStringInfoString(state, "AND CHAIN "); break; case TRANS_STMT_SAVEPOINT: deparseAppendStringInfoString(state, "SAVEPOINT "); deparseAppendStringInfoString(state, quote_identifier(transaction_stmt->savepoint_name)); break; case TRANS_STMT_RELEASE: deparseAppendStringInfoString(state, "RELEASE "); deparseAppendStringInfoString(state, quote_identifier(transaction_stmt->savepoint_name)); break; case TRANS_STMT_ROLLBACK_TO: deparseAppendStringInfoString(state, "ROLLBACK "); deparseAppendStringInfoString(state, "TO SAVEPOINT "); deparseAppendStringInfoString(state, quote_identifier(transaction_stmt->savepoint_name)); break; case TRANS_STMT_PREPARE: deparseAppendStringInfoString(state, "PREPARE TRANSACTION "); deparseStringLiteral(state, transaction_stmt->gid); break; case TRANS_STMT_COMMIT_PREPARED: deparseAppendStringInfoString(state, "COMMIT PREPARED "); deparseStringLiteral(state, transaction_stmt->gid); break; case TRANS_STMT_ROLLBACK_PREPARED: deparseAppendStringInfoString(state, "ROLLBACK PREPARED "); deparseStringLiteral(state, transaction_stmt->gid); break; } removeTrailingSpace(state); } // 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(DeparseState *state, VariableSetStmt* variable_set_stmt) { ListCell *lc; switch (variable_set_stmt->kind) { case VAR_SET_VALUE: /* SET var = value */ deparseAppendStringInfoString(state, "SET "); if (variable_set_stmt->is_local) deparseAppendStringInfoString(state, "LOCAL "); if (isSetTimeZoneInterval(variable_set_stmt)) { deparseAppendStringInfoString(state, "TIME ZONE "); deparseVarList(state, variable_set_stmt->args); } else { deparseVarName(state, variable_set_stmt->name); deparseAppendStringInfoString(state, " TO "); deparseVarList(state, variable_set_stmt->args); } break; case VAR_SET_DEFAULT: /* SET var TO DEFAULT */ deparseAppendStringInfoString(state, "SET "); if (variable_set_stmt->is_local) deparseAppendStringInfoString(state, "LOCAL "); deparseVarName(state, variable_set_stmt->name); deparseAppendStringInfoString(state, " TO DEFAULT"); break; case VAR_SET_CURRENT: /* SET var FROM CURRENT */ deparseAppendStringInfoString(state, "SET "); if (variable_set_stmt->is_local) deparseAppendStringInfoString(state, "LOCAL "); deparseVarName(state, variable_set_stmt->name); deparseAppendStringInfoString(state, " FROM CURRENT"); break; case VAR_SET_MULTI: /* special case for SET TRANSACTION ... */ Assert(variable_set_stmt->name != NULL); deparseAppendStringInfoString(state, "SET "); if (variable_set_stmt->is_local) deparseAppendStringInfoString(state, "LOCAL "); if (strcmp(variable_set_stmt->name, "TRANSACTION") == 0) { deparseAppendStringInfoString(state, "TRANSACTION "); deparseTransactionModeList(state, variable_set_stmt->args); } else if (strcmp(variable_set_stmt->name, "SESSION CHARACTERISTICS") == 0) { deparseAppendStringInfoString(state, "SESSION CHARACTERISTICS AS TRANSACTION "); deparseTransactionModeList(state, variable_set_stmt->args); } else if (strcmp(variable_set_stmt->name, "TRANSACTION SNAPSHOT") == 0) { deparseAppendStringInfoString(state, "TRANSACTION SNAPSHOT "); deparseStringLiteral(state, strVal(&castNode(A_Const, linitial(variable_set_stmt->args))->val)); } else { Assert(false); } break; case VAR_RESET: /* RESET var */ deparseAppendStringInfoString(state, "RESET "); deparseVarName(state, variable_set_stmt->name); break; case VAR_RESET_ALL: /* RESET ALL */ deparseAppendStringInfoString(state, "RESET ALL"); break; } } static void deparseDropdbStmt(DeparseState *state, DropdbStmt *dropdb_stmt) { ListCell *lc = NULL; deparseAppendStringInfoString(state, "DROP DATABASE "); if (dropdb_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseAppendStringInfoString(state, quote_identifier(dropdb_stmt->dbname)); deparseAppendStringInfoChar(state, ' '); if (list_length(dropdb_stmt->options) > 0) { deparseAppendStringInfoChar(state, '('); foreach(lc, dropdb_stmt->options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); if (strcmp(def_elem->defname, "force") == 0) deparseAppendStringInfoString(state, "FORCE"); else Assert(false); // Currently there are other supported values if (lnext(dropdb_stmt->options, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); } removeTrailingSpace(state); } static void deparseVacuumStmt(DeparseState *state, VacuumStmt *vacuum_stmt) { ListCell *lc = NULL; ListCell *lc2 = NULL; if (vacuum_stmt->is_vacuumcmd) deparseAppendStringInfoString(state, "VACUUM "); else deparseAppendStringInfoString(state, "ANALYZE "); deparseUtilityOptionList(state, vacuum_stmt->options); foreach(lc, vacuum_stmt->rels) { Assert(IsA(lfirst(lc), VacuumRelation)); VacuumRelation *rel = castNode(VacuumRelation, lfirst(lc)); deparseRangeVar(state, rel->relation, DEPARSE_NODE_CONTEXT_NONE); if (list_length(rel->va_cols) > 0) { deparseAppendStringInfoChar(state, '('); foreach(lc2, rel->va_cols) { deparseAppendStringInfoString(state, quote_identifier(strVal(lfirst(lc2)))); if (lnext(rel->va_cols, lc2)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); } if (lnext(vacuum_stmt->rels, lc)) deparseAppendStringInfoString(state, ", "); } removeTrailingSpace(state); } static void deparseLoadStmt(DeparseState *state, LoadStmt *load_stmt) { deparseAppendStringInfoString(state, "LOAD "); deparseStringLiteral(state, load_stmt->filename); } static void deparseLockStmt(DeparseState *state, LockStmt *lock_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "LOCK TABLE "); deparseRelationExprList(state, lock_stmt->relations); deparseAppendStringInfoChar(state, ' '); if (lock_stmt->mode != AccessExclusiveLock) { deparseAppendStringInfoString(state, "IN "); switch (lock_stmt->mode) { case AccessShareLock: deparseAppendStringInfoString(state, "ACCESS SHARE "); break; case RowShareLock: deparseAppendStringInfoString(state, "ROW SHARE "); break; case RowExclusiveLock: deparseAppendStringInfoString(state, "ROW EXCLUSIVE "); break; case ShareUpdateExclusiveLock: deparseAppendStringInfoString(state, "SHARE UPDATE EXCLUSIVE "); break; case ShareLock: deparseAppendStringInfoString(state, "SHARE "); break; case ShareRowExclusiveLock: deparseAppendStringInfoString(state, "SHARE ROW EXCLUSIVE "); break; case ExclusiveLock: deparseAppendStringInfoString(state, "EXCLUSIVE "); break; case AccessExclusiveLock: deparseAppendStringInfoString(state, "ACCESS EXCLUSIVE "); break; default: Assert(false); break; } deparseAppendStringInfoString(state, "MODE "); } if (lock_stmt->nowait) deparseAppendStringInfoString(state, "NOWAIT "); removeTrailingSpace(state); } static void deparseConstraintsSetStmt(DeparseState *state, ConstraintsSetStmt *constraints_set_stmt) { deparseAppendStringInfoString(state, "SET CONSTRAINTS "); if (list_length(constraints_set_stmt->constraints) > 0) { deparseQualifiedNameList(state, constraints_set_stmt->constraints); deparseAppendStringInfoChar(state, ' '); } else { deparseAppendStringInfoString(state, "ALL "); } if (constraints_set_stmt->deferred) deparseAppendStringInfoString(state, "DEFERRED"); else deparseAppendStringInfoString(state, "IMMEDIATE"); } static void deparseExplainStmt(DeparseState *state, ExplainStmt *explain_stmt) { ListCell *lc = NULL; char *defname = NULL; deparseAppendPartGroup(state, "EXPLAIN", DEPARSE_PART_NO_INDENT); deparseUtilityOptionList(state, explain_stmt->options); deparseExplainableStmt(state, explain_stmt->query); } static void deparseCopyStmt(DeparseState *state, CopyStmt *copy_stmt) { ListCell *lc = NULL; ListCell *lc2 = NULL; deparseAppendPartGroup(state, "COPY", DEPARSE_PART_INDENT); if (copy_stmt->relation != NULL) { deparseRangeVar(state, copy_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); if (list_length(copy_stmt->attlist) > 0) { deparseAppendStringInfoChar(state, '('); deparseColumnList(state, copy_stmt->attlist); deparseAppendStringInfoChar(state, ')'); } deparseAppendStringInfoChar(state, ' '); } if (copy_stmt->query != NULL) { deparseAppendStringInfoChar(state, '('); deparsePreparableStmt(state, copy_stmt->query); deparseAppendStringInfoString(state, ") "); } if (copy_stmt->is_from) deparseAppendStringInfoString(state, "FROM "); else deparseAppendStringInfoString(state, "TO "); if (copy_stmt->is_program) deparseAppendStringInfoString(state, "PROGRAM "); if (copy_stmt->filename != NULL) { deparseStringLiteral(state, copy_stmt->filename); deparseAppendStringInfoChar(state, ' '); } else { if (copy_stmt->is_from) deparseAppendStringInfoString(state, "STDIN "); else deparseAppendStringInfoString(state, "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)) { deparseAppendStringInfoString(state, "FREEZE "); } else if (strcmp(def_elem->defname, "header") == 0 && def_elem->arg && optBooleanValue(def_elem->arg)) { deparseAppendStringInfoString(state, "HEADER "); } else if (strcmp(def_elem->defname, "format") == 0 && strcmp(strVal(def_elem->arg), "csv") == 0) { deparseAppendStringInfoString(state, "CSV "); } else if (strcmp(def_elem->defname, "force_quote") == 0 && def_elem->arg && nodeTag(def_elem->arg) == T_List) { deparseAppendStringInfoString(state, "FORCE QUOTE "); deparseColumnList(state, 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 { deparseAppendStringInfoString(state, "WITH ("); foreach(lc, copy_stmt->options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); if (strcmp(def_elem->defname, "format") == 0) { deparseAppendStringInfoString(state, "FORMAT "); char *format = strVal(def_elem->arg); if (strcmp(format, "binary") == 0) deparseAppendStringInfoString(state, "BINARY"); else if (strcmp(format, "csv") == 0) deparseAppendStringInfoString(state, "CSV"); else if (strcmp(format, "text") == 0) deparseAppendStringInfoString(state, "TEXT"); else Assert(false); } else if (strcmp(def_elem->defname, "freeze") == 0) { deparseAppendStringInfoString(state, "FREEZE"); deparseOptBoolean(state, def_elem->arg); } else if (strcmp(def_elem->defname, "delimiter") == 0) { deparseAppendStringInfoString(state, "DELIMITER "); deparseStringLiteral(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "null") == 0) { deparseAppendStringInfoString(state, "NULL "); deparseStringLiteral(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "header") == 0) { deparseAppendStringInfoString(state, "HEADER"); deparseOptBoolean(state, def_elem->arg); } else if (strcmp(def_elem->defname, "quote") == 0) { deparseAppendStringInfoString(state, "QUOTE "); deparseStringLiteral(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "escape") == 0) { deparseAppendStringInfoString(state, "ESCAPE "); deparseStringLiteral(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "force_quote") == 0) { deparseAppendStringInfoString(state, "FORCE_QUOTE "); if (IsA(def_elem->arg, A_Star)) { deparseAppendStringInfoChar(state, '*'); } else if (IsA(def_elem->arg, List)) { deparseAppendStringInfoChar(state, '('); deparseColumnList(state, castNode(List, def_elem->arg)); deparseAppendStringInfoChar(state, ')'); } else { Assert(false); } } else if (strcmp(def_elem->defname, "force_not_null") == 0) { deparseAppendStringInfoString(state, "FORCE_NOT_NULL "); if (IsA(def_elem->arg, A_Star)) deparseAStar(state, castNode(A_Star, def_elem->arg)); else { deparseAppendStringInfoChar(state, '('); deparseColumnList(state, castNode(List, def_elem->arg)); deparseAppendStringInfoChar(state, ')'); } } else if (strcmp(def_elem->defname, "force_null") == 0) { deparseAppendStringInfoString(state, "FORCE_NULL "); if (IsA(def_elem->arg, A_Star)) deparseAStar(state, castNode(A_Star, def_elem->arg)); else { deparseAppendStringInfoChar(state, '('); deparseColumnList(state, castNode(List, def_elem->arg)); deparseAppendStringInfoChar(state, ')'); } } else if (strcmp(def_elem->defname, "encoding") == 0) { deparseAppendStringInfoString(state, "ENCODING "); deparseStringLiteral(state, strVal(def_elem->arg)); } else { deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); if (def_elem->arg != NULL) deparseAppendStringInfoChar(state, ' '); if (def_elem->arg == NULL) { // Nothing } else if (IsA(def_elem->arg, String)) { deparseOptBooleanOrString(state, strVal(def_elem->arg)); } else if (IsA(def_elem->arg, Integer) || IsA(def_elem->arg, Float)) { deparseNumericOnly(state, (union ValUnion *) def_elem->arg); } else if (IsA(def_elem->arg, A_Star)) { deparseAStar(state, castNode(A_Star, def_elem->arg)); } else if (IsA(def_elem->arg, List)) { List *l = castNode(List, def_elem->arg); deparseAppendStringInfoChar(state, '('); foreach(lc2, l) { deparseOptBooleanOrString(state, strVal(lfirst(lc2))); if (lnext(l, lc2)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); } } if (lnext(copy_stmt->options, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, ") "); } } deparseWhereClause(state, copy_stmt->whereClause); removeTrailingSpace(state); } static void deparseDoStmt(DeparseState *state, DoStmt *do_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "DO "); foreach (lc, do_stmt->args) { DefElem *defel = castNode(DefElem, lfirst(lc)); if (strcmp(defel->defname, "language") == 0) { deparseAppendStringInfoString(state, "LANGUAGE "); deparseAppendStringInfoString(state, quote_identifier(strVal(defel->arg))); deparseAppendStringInfoChar(state, ' '); } else if (strcmp(defel->defname, "as") == 0) { char *strval = strVal(defel->arg); const char *delim = "$$"; if (strstr(strval, "$$") != NULL) delim = "$outer$"; deparseAppendStringInfoString(state, delim); deparseAppendStringInfoString(state, strval); deparseAppendStringInfoString(state, delim); deparseAppendStringInfoChar(state, ' '); } } removeTrailingSpace(state); } static void deparseDiscardStmt(DeparseState *state, DiscardStmt *discard_stmt) { deparseAppendStringInfoString(state, "DISCARD "); switch (discard_stmt->target) { case DISCARD_ALL: deparseAppendStringInfoString(state, "ALL"); break; case DISCARD_PLANS: deparseAppendStringInfoString(state, "PLANS"); break; case DISCARD_SEQUENCES: deparseAppendStringInfoString(state, "SEQUENCES"); break; case DISCARD_TEMP: deparseAppendStringInfoString(state, "TEMP"); break; } } static void deparseDefineStmt(DeparseState *state, DefineStmt *define_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "CREATE "); if (define_stmt->replace) deparseAppendStringInfoString(state, "OR REPLACE "); switch (define_stmt->kind) { case OBJECT_AGGREGATE: deparseAppendStringInfoString(state, "AGGREGATE "); break; case OBJECT_OPERATOR: deparseAppendStringInfoString(state, "OPERATOR "); break; case OBJECT_TYPE: deparseAppendStringInfoString(state, "TYPE "); break; case OBJECT_TSPARSER: deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); break; case OBJECT_TSDICTIONARY: deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); break; case OBJECT_TSTEMPLATE: deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); break; case OBJECT_TSCONFIGURATION: deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); break; case OBJECT_COLLATION: deparseAppendStringInfoString(state, "COLLATION "); break; default: // This shouldn't happen Assert(false); break; } if (define_stmt->if_not_exists) deparseAppendStringInfoString(state, "IF NOT EXISTS "); switch (define_stmt->kind) { case OBJECT_AGGREGATE: deparseFuncName(state, define_stmt->defnames); break; case OBJECT_OPERATOR: deparseAnyOperator(state, define_stmt->defnames); break; case OBJECT_TYPE: case OBJECT_TSPARSER: case OBJECT_TSDICTIONARY: case OBJECT_TSTEMPLATE: case OBJECT_TSCONFIGURATION: case OBJECT_COLLATION: deparseAnyName(state, define_stmt->defnames); break; default: Assert(false); } deparseAppendStringInfoChar(state, ' '); if (!define_stmt->oldstyle && define_stmt->kind == OBJECT_AGGREGATE) { deparseAggrArgs(state, define_stmt->args); deparseAppendStringInfoChar(state, ' '); } if (define_stmt->kind == OBJECT_COLLATION && list_length(define_stmt->definition) == 1 && strcmp(castNode(DefElem, linitial(define_stmt->definition))->defname, "from") == 0) { deparseAppendStringInfoString(state, "FROM "); deparseAnyName(state, castNode(List, castNode(DefElem, linitial(define_stmt->definition))->arg)); } else if (list_length(define_stmt->definition) > 0) { deparseDefinition(state, define_stmt->definition); } removeTrailingSpace(state); } static void deparseCompositeTypeStmt(DeparseState *state, CompositeTypeStmt *composite_type_stmt) { ListCell *lc; RangeVar *typevar; DeparseStateNestingLevel *parent_level = NULL; deparseAppendStringInfoString(state, "CREATE TYPE "); deparseRangeVar(state, composite_type_stmt->typevar, DEPARSE_NODE_CONTEXT_CREATE_TYPE); deparseAppendStringInfoString(state, " AS ("); parent_level = deparseStateIncreaseNestingLevel(state); foreach(lc, composite_type_stmt->coldeflist) { deparseColumnDef(state, castNode(ColumnDef, lfirst(lc))); if (lnext(composite_type_stmt->coldeflist, lc)) deparseAppendCommaAndPart(state); } deparseStateDecreaseNestingLevel(state, parent_level); deparseAppendStringInfoChar(state, ')'); } static void deparseCreateEnumStmt(DeparseState *state, CreateEnumStmt *create_enum_stmt) { ListCell *lc; DeparseStateNestingLevel *parent_level = NULL; deparseAppendStringInfoString(state, "CREATE TYPE "); deparseAnyName(state, create_enum_stmt->typeName); deparseAppendStringInfoString(state, " AS ENUM ("); parent_level = deparseStateIncreaseNestingLevel(state); foreach(lc, create_enum_stmt->vals) { deparseStringLiteral(state, strVal(lfirst(lc))); if (lnext(create_enum_stmt->vals, lc)) deparseAppendCommaAndPart(state); } deparseStateDecreaseNestingLevel(state, parent_level); deparseAppendStringInfoChar(state, ')'); } static void deparseCreateRangeStmt(DeparseState *state, CreateRangeStmt *create_range_stmt) { deparseAppendStringInfoString(state, "CREATE TYPE "); deparseAnyName(state, create_range_stmt->typeName); deparseAppendStringInfoString(state, " AS RANGE "); deparseDefinition(state, create_range_stmt->params); } static void deparseAlterEnumStmt(DeparseState *state, AlterEnumStmt *alter_enum_stmt) { deparseAppendStringInfoString(state, "ALTER TYPE "); deparseAnyName(state, alter_enum_stmt->typeName); deparseAppendStringInfoChar(state, ' '); if (alter_enum_stmt->oldVal == NULL) { deparseAppendStringInfoString(state, "ADD VALUE "); if (alter_enum_stmt->skipIfNewValExists) deparseAppendStringInfoString(state, "IF NOT EXISTS "); deparseStringLiteral(state, alter_enum_stmt->newVal); deparseAppendStringInfoChar(state, ' '); if (alter_enum_stmt->newValNeighbor) { if (alter_enum_stmt->newValIsAfter) deparseAppendStringInfoString(state, "AFTER "); else deparseAppendStringInfoString(state, "BEFORE "); deparseStringLiteral(state, alter_enum_stmt->newValNeighbor); } } else { deparseAppendStringInfoString(state, "RENAME VALUE "); deparseStringLiteral(state, alter_enum_stmt->oldVal); deparseAppendStringInfoString(state, " TO "); deparseStringLiteral(state, alter_enum_stmt->newVal); } removeTrailingSpace(state); } static void deparseAlterExtensionStmt(DeparseState *state, AlterExtensionStmt *alter_extension_stmt) { ListCell *lc = NULL; deparseAppendStringInfoString(state, "ALTER EXTENSION "); deparseColId(state, alter_extension_stmt->extname); deparseAppendStringInfoString(state, " UPDATE "); foreach (lc, alter_extension_stmt->options) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); if (strcmp(def_elem->defname, "new_version") == 0) { deparseAppendStringInfoString(state, "TO "); deparseNonReservedWordOrSconst(state, strVal(def_elem->arg)); } else { Assert(false); } deparseAppendStringInfoChar(state, ' '); } removeTrailingSpace(state); } static void deparseAlterExtensionContentsStmt(DeparseState *state, AlterExtensionContentsStmt *alter_extension_contents_stmt) { List *l = NULL; deparseAppendStringInfoString(state, "ALTER EXTENSION "); deparseColId(state, alter_extension_contents_stmt->extname); deparseAppendStringInfoChar(state, ' '); if (alter_extension_contents_stmt->action == 1) deparseAppendStringInfoString(state, "ADD "); else if (alter_extension_contents_stmt->action == -1) deparseAppendStringInfoString(state, "DROP "); else Assert(false); switch (alter_extension_contents_stmt->objtype) { case OBJECT_ACCESS_METHOD: deparseAppendStringInfoString(state, "ACCESS METHOD "); break; case OBJECT_AGGREGATE: deparseAppendStringInfoString(state, "AGGREGATE "); break; case OBJECT_CAST: deparseAppendStringInfoString(state, "CAST "); break; case OBJECT_COLLATION: deparseAppendStringInfoString(state, "COLLATION "); break; case OBJECT_CONVERSION: deparseAppendStringInfoString(state, "CONVERSION "); break; case OBJECT_DOMAIN: deparseAppendStringInfoString(state, "DOMAIN "); break; case OBJECT_FUNCTION: deparseAppendStringInfoString(state, "FUNCTION "); break; case OBJECT_LANGUAGE: deparseAppendStringInfoString(state, "LANGUAGE "); break; case OBJECT_OPERATOR: deparseAppendStringInfoString(state, "OPERATOR "); break; case OBJECT_OPCLASS: deparseAppendStringInfoString(state, "OPERATOR CLASS "); break; case OBJECT_OPFAMILY: deparseAppendStringInfoString(state, "OPERATOR FAMILY "); break; case OBJECT_PROCEDURE: deparseAppendStringInfoString(state, "PROCEDURE "); break; case OBJECT_ROUTINE: deparseAppendStringInfoString(state, "ROUTINE "); break; case OBJECT_SCHEMA: deparseAppendStringInfoString(state, "SCHEMA "); break; case OBJECT_EVENT_TRIGGER: deparseAppendStringInfoString(state, "EVENT TRIGGER "); break; case OBJECT_TABLE: deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_TSPARSER: deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); break; case OBJECT_TSDICTIONARY: deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); break; case OBJECT_TSTEMPLATE: deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); break; case OBJECT_TSCONFIGURATION: deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); break; case OBJECT_SEQUENCE: deparseAppendStringInfoString(state, "SEQUENCE "); break; case OBJECT_VIEW: deparseAppendStringInfoString(state, "VIEW "); break; case OBJECT_MATVIEW: deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; case OBJECT_FOREIGN_TABLE: deparseAppendStringInfoString(state, "FOREIGN TABLE "); break; case OBJECT_FDW: deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); break; case OBJECT_FOREIGN_SERVER: deparseAppendStringInfoString(state, "SERVER "); break; case OBJECT_TRANSFORM: deparseAppendStringInfoString(state, "TRANSFORM "); break; case OBJECT_TYPE: deparseAppendStringInfoString(state, "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(state, 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(state, strVal(alter_extension_contents_stmt->object)); break; case OBJECT_AGGREGATE: deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); break; case OBJECT_CAST: l = castNode(List, alter_extension_contents_stmt->object); Assert(list_length(l) == 2); deparseAppendStringInfoChar(state, '('); deparseTypeName(state, castNode(TypeName, linitial(l))); deparseAppendStringInfoString(state, " AS "); deparseTypeName(state, castNode(TypeName, lsecond(l))); deparseAppendStringInfoChar(state, ')'); break; case OBJECT_DOMAIN: case OBJECT_TYPE: deparseTypeName(state, castNode(TypeName, alter_extension_contents_stmt->object)); break; case OBJECT_FUNCTION: case OBJECT_PROCEDURE: case OBJECT_ROUTINE: deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_extension_contents_stmt->object)); break; case OBJECT_OPERATOR: deparseOperatorWithArgtypes(state, 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(state, l); deparseAppendStringInfoString(state, " USING "); deparseColId(state, strVal(linitial(l))); break; case OBJECT_TRANSFORM: l = castNode(List, alter_extension_contents_stmt->object); deparseAppendStringInfoString(state, "FOR "); deparseTypeName(state, castNode(TypeName, linitial(l))); deparseAppendStringInfoString(state, " LANGUAGE "); deparseColId(state, strVal(lsecond(l))); break; default: Assert(false); break; } } static void deparseAccessPriv(DeparseState *state, AccessPriv *access_priv) { ListCell *lc; if (access_priv->priv_name != NULL) { if (strcmp(access_priv->priv_name, "select") == 0) deparseAppendStringInfoString(state, "select"); else if (strcmp(access_priv->priv_name, "references") == 0) deparseAppendStringInfoString(state, "references"); else if (strcmp(access_priv->priv_name, "create") == 0) deparseAppendStringInfoString(state, "create"); else deparseAppendStringInfoString(state, quote_identifier(access_priv->priv_name)); } else { deparseAppendStringInfoString(state, "ALL"); } deparseAppendStringInfoChar(state, ' '); if (list_length(access_priv->cols) > 0) { deparseAppendStringInfoChar(state, '('); deparseColumnList(state, access_priv->cols); deparseAppendStringInfoChar(state, ')'); } removeTrailingSpace(state); } static void deparseGrantStmt(DeparseState *state, GrantStmt *grant_stmt) { ListCell *lc; if (grant_stmt->is_grant) deparseAppendStringInfoString(state, "GRANT "); else deparseAppendStringInfoString(state, "REVOKE "); if (!grant_stmt->is_grant && grant_stmt->grant_option) deparseAppendStringInfoString(state, "GRANT OPTION FOR "); if (list_length(grant_stmt->privileges) > 0) { foreach(lc, grant_stmt->privileges) { deparseAccessPriv(state, castNode(AccessPriv, lfirst(lc))); if (lnext(grant_stmt->privileges, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ' '); } else { deparseAppendStringInfoString(state, "ALL "); } deparseAppendStringInfoString(state, "ON "); deparsePrivilegeTarget(state, grant_stmt->targtype, grant_stmt->objtype, grant_stmt->objects); deparseAppendStringInfoChar(state, ' '); if (grant_stmt->is_grant) deparseAppendStringInfoString(state, "TO "); else deparseAppendStringInfoString(state, "FROM "); foreach(lc, grant_stmt->grantees) { deparseRoleSpec(state, castNode(RoleSpec, lfirst(lc))); if (lnext(grant_stmt->grantees, lc)) deparseAppendStringInfoChar(state, ','); deparseAppendStringInfoChar(state, ' '); } if (grant_stmt->is_grant && grant_stmt->grant_option) deparseAppendStringInfoString(state, "WITH GRANT OPTION "); deparseOptDropBehavior(state, grant_stmt->behavior); if (grant_stmt->grantor) { deparseAppendStringInfoString(state, "GRANTED BY "); deparseRoleSpec(state, castNode(RoleSpec, grant_stmt->grantor)); } removeTrailingSpace(state); } static void deparseGrantRoleStmt(DeparseState *state, GrantRoleStmt *grant_role_stmt) { ListCell *lc; if (grant_role_stmt->is_grant) deparseAppendStringInfoString(state, "GRANT "); else deparseAppendStringInfoString(state, "REVOKE "); if (!grant_role_stmt->is_grant && list_length(grant_role_stmt->opt)) { DefElem *defelem = castNode(DefElem, linitial(grant_role_stmt->opt)); Assert(!castNode(Boolean, defelem->arg)->boolval); if (strcmp("admin", defelem->defname) == 0) { deparseAppendStringInfoString(state, "ADMIN "); } else if (strcmp("inherit", defelem->defname) == 0) { deparseAppendStringInfoString(state, "INHERIT "); } else if (strcmp("set", defelem->defname) == 0) { deparseAppendStringInfoString(state, "SET "); } deparseAppendStringInfoString(state, "OPTION FOR "); } foreach(lc, grant_role_stmt->granted_roles) { deparseAccessPriv(state, castNode(AccessPriv, lfirst(lc))); if (lnext(grant_role_stmt->granted_roles, lc)) deparseAppendStringInfoChar(state, ','); deparseAppendStringInfoChar(state, ' '); } if (grant_role_stmt->is_grant) deparseAppendStringInfoString(state, "TO "); else deparseAppendStringInfoString(state, "FROM "); deparseRoleList(state, grant_role_stmt->grantee_roles); deparseAppendStringInfoChar(state, ' '); if (grant_role_stmt->is_grant) { if (list_length(grant_role_stmt->opt) > 0) { deparseAppendStringInfoString(state, "WITH "); } foreach(lc, grant_role_stmt->opt) { DefElem *defelem = castNode(DefElem, lfirst(lc)); if (strcmp("admin", defelem->defname) == 0) { deparseAppendStringInfoString(state, "ADMIN "); deparseAppendStringInfoString(state, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); } else if (strcmp("inherit", defelem->defname) == 0) { deparseAppendStringInfoString(state, "INHERIT "); deparseAppendStringInfoString(state, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); } else if (strcmp("set", defelem->defname) == 0) { deparseAppendStringInfoString(state, "SET "); deparseAppendStringInfoString(state, castNode(Boolean, defelem->arg)->boolval ? "OPTION" : "FALSE"); } if (lnext(grant_role_stmt->opt, lc)) { deparseAppendStringInfoChar(state, ','); } deparseAppendStringInfoChar(state, ' '); } } if (grant_role_stmt->grantor) { deparseAppendStringInfoString(state, "GRANTED BY "); deparseRoleSpec(state, castNode(RoleSpec, grant_role_stmt->grantor)); } if (grant_role_stmt->behavior == DROP_CASCADE) { deparseAppendStringInfoString(state, "CASCADE "); } removeTrailingSpace(state); } static void deparseDropRoleStmt(DeparseState *state, DropRoleStmt *drop_role_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "DROP ROLE "); if (drop_role_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseRoleList(state, drop_role_stmt->roles); } static void deparseIndexStmt(DeparseState *state, IndexStmt *index_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "CREATE "); if (index_stmt->unique) deparseAppendStringInfoString(state, "UNIQUE "); deparseAppendStringInfoString(state, "INDEX "); if (index_stmt->concurrent) deparseAppendStringInfoString(state, "CONCURRENTLY "); if (index_stmt->if_not_exists) deparseAppendStringInfoString(state, "IF NOT EXISTS "); if (index_stmt->idxname != NULL) { deparseAppendStringInfoString(state, quote_identifier(index_stmt->idxname)); deparseAppendStringInfoChar(state, ' '); } deparseAppendPartGroup(state, "ON", DEPARSE_PART_INDENT); deparseRangeVar(state, index_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); if (index_stmt->accessMethod != NULL) { deparseAppendStringInfoString(state, "USING "); deparseAppendStringInfoString(state, quote_identifier(index_stmt->accessMethod)); deparseAppendStringInfoChar(state, ' '); } deparseAppendStringInfoChar(state, '('); foreach (lc, index_stmt->indexParams) { deparseIndexElem(state, castNode(IndexElem, lfirst(lc))); if (lnext(index_stmt->indexParams, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, ") "); if (list_length(index_stmt->indexIncludingParams) > 0) { deparseAppendStringInfoString(state, "INCLUDE ("); foreach (lc, index_stmt->indexIncludingParams) { deparseIndexElem(state, castNode(IndexElem, lfirst(lc))); if (lnext(index_stmt->indexIncludingParams, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, ") "); } if (index_stmt->nulls_not_distinct) { deparseAppendStringInfoString(state, "NULLS NOT DISTINCT "); } deparseOptWith(state, index_stmt->options); if (index_stmt->tableSpace != NULL) { deparseAppendStringInfoString(state, "TABLESPACE "); deparseAppendStringInfoString(state, quote_identifier(index_stmt->tableSpace)); deparseAppendStringInfoChar(state, ' '); } deparseWhereClause(state, index_stmt->whereClause); removeTrailingSpace(state); } static void deparseAlterOpFamilyStmt(DeparseState *state, AlterOpFamilyStmt *alter_op_family_stmt) { deparseAppendStringInfoString(state, "ALTER OPERATOR FAMILY "); deparseAnyName(state, alter_op_family_stmt->opfamilyname); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "USING "); deparseAppendStringInfoString(state, quote_identifier(alter_op_family_stmt->amname)); deparseAppendStringInfoChar(state, ' '); if (alter_op_family_stmt->isDrop) deparseAppendStringInfoString(state, "DROP "); else deparseAppendStringInfoString(state, "ADD "); deparseOpclassItemList(state, alter_op_family_stmt->items); } static void deparsePrepareStmt(DeparseState *state, PrepareStmt *prepare_stmt) { ListCell *lc = NULL; deparseAppendStringInfoString(state, "PREPARE "); deparseColId(state, prepare_stmt->name); if (list_length(prepare_stmt->argtypes) > 0) { deparseAppendStringInfoChar(state, '('); deparseTypeList(state, prepare_stmt->argtypes); deparseAppendStringInfoChar(state, ')'); } deparseAppendStringInfoString(state, " AS "); deparsePreparableStmt(state, prepare_stmt->query); } static void deparseExecuteStmt(DeparseState *state, ExecuteStmt *execute_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "EXECUTE "); deparseAppendStringInfoString(state, quote_identifier(execute_stmt->name)); if (list_length(execute_stmt->params) > 0) { deparseAppendStringInfoChar(state, '('); deparseExprList(state, execute_stmt->params); deparseAppendStringInfoChar(state, ')'); } } static void deparseDeallocateStmt(DeparseState *state, DeallocateStmt *deallocate_stmt) { deparseAppendStringInfoString(state, "DEALLOCATE "); if (deallocate_stmt->name != NULL) deparseAppendStringInfoString(state, quote_identifier(deallocate_stmt->name)); else deparseAppendStringInfoString(state, "ALL"); } // "AlterOptRoleElem" in gram.y static void deparseAlterRoleElem(DeparseState *state, DefElem *def_elem) { if (strcmp(def_elem->defname, "password") == 0) { deparseAppendStringInfoString(state, "PASSWORD "); if (def_elem->arg == NULL) { deparseAppendStringInfoString(state, "NULL"); } else if (IsA(def_elem->arg, ParamRef)) { deparseParamRef(state, castNode(ParamRef, def_elem->arg)); } else if (IsA(def_elem->arg, String)) { deparseStringLiteral(state, strVal(def_elem->arg)); } else { Assert(false); } } else if (strcmp(def_elem->defname, "connectionlimit") == 0) { deparseAppendStringInfo(state, "CONNECTION LIMIT %d", intVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "validUntil") == 0) { deparseAppendStringInfoString(state, "VALID UNTIL "); deparseStringLiteral(state, strVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "superuser") == 0 && boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "SUPERUSER"); } else if (strcmp(def_elem->defname, "superuser") == 0 && !boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "NOSUPERUSER"); } else if (strcmp(def_elem->defname, "createrole") == 0 && boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "CREATEROLE"); } else if (strcmp(def_elem->defname, "createrole") == 0 && !boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "NOCREATEROLE"); } else if (strcmp(def_elem->defname, "isreplication") == 0 && boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "REPLICATION"); } else if (strcmp(def_elem->defname, "isreplication") == 0 && !boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "NOREPLICATION"); } else if (strcmp(def_elem->defname, "createdb") == 0 && boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "CREATEDB"); } else if (strcmp(def_elem->defname, "createdb") == 0 && !boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "NOCREATEDB"); } else if (strcmp(def_elem->defname, "canlogin") == 0 && boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "LOGIN"); } else if (strcmp(def_elem->defname, "canlogin") == 0 && !boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "NOLOGIN"); } else if (strcmp(def_elem->defname, "bypassrls") == 0 && boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "BYPASSRLS"); } else if (strcmp(def_elem->defname, "bypassrls") == 0 && !boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "NOBYPASSRLS"); } else if (strcmp(def_elem->defname, "inherit") == 0 && boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "INHERIT"); } else if (strcmp(def_elem->defname, "inherit") == 0 && !boolVal(def_elem->arg)) { deparseAppendStringInfoString(state, "NOINHERIT"); } else { Assert(false); } } // "CreateOptRoleElem" in gram.y static void deparseCreateRoleElem(DeparseState *state, DefElem *def_elem) { if (strcmp(def_elem->defname, "sysid") == 0) { deparseAppendStringInfo(state, "SYSID %d", intVal(def_elem->arg)); } else if (strcmp(def_elem->defname, "adminmembers") == 0) { deparseAppendStringInfoString(state, "ADMIN "); deparseRoleList(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "rolemembers") == 0) { deparseAppendStringInfoString(state, "ROLE "); deparseRoleList(state, castNode(List, def_elem->arg)); } else if (strcmp(def_elem->defname, "addroleto") == 0) { deparseAppendStringInfoString(state, "IN ROLE "); deparseRoleList(state, castNode(List, def_elem->arg)); } else { deparseAlterRoleElem(state, def_elem); } } static void deparseCreatePLangStmt(DeparseState *state, CreatePLangStmt *create_p_lang_stmt) { deparseAppendStringInfoString(state, "CREATE "); if (create_p_lang_stmt->replace) deparseAppendStringInfoString(state, "OR REPLACE "); if (create_p_lang_stmt->pltrusted) deparseAppendStringInfoString(state, "TRUSTED "); deparseAppendStringInfoString(state, "LANGUAGE "); deparseNonReservedWordOrSconst(state, create_p_lang_stmt->plname); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "HANDLER "); deparseHandlerName(state, create_p_lang_stmt->plhandler); deparseAppendStringInfoChar(state, ' '); if (create_p_lang_stmt->plinline) { deparseAppendStringInfoString(state, "INLINE "); deparseHandlerName(state, create_p_lang_stmt->plinline); deparseAppendStringInfoChar(state, ' '); } if (create_p_lang_stmt->plvalidator) { deparseAppendStringInfoString(state, "VALIDATOR "); deparseHandlerName(state, create_p_lang_stmt->plvalidator); deparseAppendStringInfoChar(state, ' '); } removeTrailingSpace(state); } static void deparseCreateRoleStmt(DeparseState *state, CreateRoleStmt *create_role_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "CREATE "); switch (create_role_stmt->stmt_type) { case ROLESTMT_ROLE: deparseAppendStringInfoString(state, "ROLE "); break; case ROLESTMT_USER: deparseAppendStringInfoString(state, "USER "); break; case ROLESTMT_GROUP: deparseAppendStringInfoString(state, "GROUP "); break; } deparseAppendStringInfoString(state, quote_identifier(create_role_stmt->role)); deparseAppendStringInfoChar(state, ' '); if (create_role_stmt->options != NULL) { deparseAppendStringInfoString(state, "WITH "); foreach (lc, create_role_stmt->options) { deparseCreateRoleElem(state, castNode(DefElem, lfirst(lc))); deparseAppendStringInfoChar(state, ' '); } } removeTrailingSpace(state); } static void deparseAlterRoleStmt(DeparseState *state, AlterRoleStmt *alter_role_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "ALTER "); if (list_length(alter_role_stmt->options) == 1 && strcmp(castNode(DefElem, linitial(alter_role_stmt->options))->defname, "rolemembers") == 0) { deparseAppendStringInfoString(state, "GROUP "); deparseRoleSpec(state, alter_role_stmt->role); deparseAppendStringInfoChar(state, ' '); if (alter_role_stmt->action == 1) { deparseAppendStringInfoString(state, "ADD USER "); } else if (alter_role_stmt->action == -1) { deparseAppendStringInfoString(state, "DROP USER "); } else { Assert(false); } deparseRoleList(state, castNode(List, castNode(DefElem, linitial(alter_role_stmt->options))->arg)); } else { deparseAppendStringInfoString(state, "ROLE "); deparseRoleSpec(state, alter_role_stmt->role); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "WITH "); foreach (lc, alter_role_stmt->options) { deparseAlterRoleElem(state, castNode(DefElem, lfirst(lc))); deparseAppendStringInfoChar(state, ' '); } } removeTrailingSpace(state); } static void deparseDeclareCursorStmt(DeparseState *state, DeclareCursorStmt *declare_cursor_stmt) { deparseAppendStringInfoString(state, "DECLARE "); deparseAppendStringInfoString(state, quote_identifier(declare_cursor_stmt->portalname)); deparseAppendStringInfoChar(state, ' '); if (declare_cursor_stmt->options & CURSOR_OPT_BINARY) deparseAppendStringInfoString(state, "BINARY "); if (declare_cursor_stmt->options & CURSOR_OPT_SCROLL) deparseAppendStringInfoString(state, "SCROLL "); if (declare_cursor_stmt->options & CURSOR_OPT_NO_SCROLL) deparseAppendStringInfoString(state, "NO SCROLL "); if (declare_cursor_stmt->options & CURSOR_OPT_INSENSITIVE) deparseAppendStringInfoString(state, "INSENSITIVE "); deparseAppendStringInfoString(state, "CURSOR "); if (declare_cursor_stmt->options & CURSOR_OPT_HOLD) deparseAppendStringInfoString(state, "WITH HOLD "); deparseAppendStringInfoString(state, "FOR "); deparseSelectStmt(state, castNode(SelectStmt, declare_cursor_stmt->query), DEPARSE_NODE_CONTEXT_NONE); } static void deparseFetchStmt(DeparseState *state, FetchStmt *fetch_stmt) { if (fetch_stmt->ismove) deparseAppendStringInfoString(state, "MOVE "); else deparseAppendStringInfoString(state, "FETCH "); switch (fetch_stmt->direction) { case FETCH_FORWARD: if (fetch_stmt->howMany == 1) { // Default } else if (fetch_stmt->howMany == FETCH_ALL) { deparseAppendStringInfoString(state, "ALL "); } else { deparseAppendStringInfo(state, "FORWARD %ld ", fetch_stmt->howMany); } break; case FETCH_BACKWARD: if (fetch_stmt->howMany == 1) { deparseAppendStringInfoString(state, "PRIOR "); } else if (fetch_stmt->howMany == FETCH_ALL) { deparseAppendStringInfoString(state, "BACKWARD ALL "); } else { deparseAppendStringInfo(state, "BACKWARD %ld ", fetch_stmt->howMany); } break; case FETCH_ABSOLUTE: if (fetch_stmt->howMany == 1) { deparseAppendStringInfoString(state, "FIRST "); } else if (fetch_stmt->howMany == -1) { deparseAppendStringInfoString(state, "LAST "); } else { deparseAppendStringInfo(state, "ABSOLUTE %ld ", fetch_stmt->howMany); } break; case FETCH_RELATIVE: deparseAppendStringInfo(state, "RELATIVE %ld ", fetch_stmt->howMany); } deparseAppendStringInfoString(state, quote_identifier(fetch_stmt->portalname)); } static void deparseAlterDefaultPrivilegesStmt(DeparseState *state, AlterDefaultPrivilegesStmt *alter_default_privileges_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "ALTER DEFAULT PRIVILEGES "); foreach (lc, alter_default_privileges_stmt->options) { DefElem *defelem = castNode(DefElem, lfirst(lc)); if (strcmp(defelem->defname, "schemas") == 0) { deparseAppendStringInfoString(state, "IN SCHEMA "); deparseNameList(state, castNode(List, defelem->arg)); deparseAppendStringInfoChar(state, ' '); } else if (strcmp(defelem->defname, "roles") == 0) { deparseAppendStringInfoString(state, "FOR ROLE "); deparseRoleList(state, castNode(List, defelem->arg)); deparseAppendStringInfoChar(state, ' '); } else { // No other DefElems are supported Assert(false); } } deparseGrantStmt(state, alter_default_privileges_stmt->action); } static void deparseReindexStmt(DeparseState *state, ReindexStmt *reindex_stmt) { deparseAppendStringInfoString(state, "REINDEX "); deparseUtilityOptionList(state, reindex_stmt->params); switch (reindex_stmt->kind) { case REINDEX_OBJECT_INDEX: deparseAppendStringInfoString(state, "INDEX "); break; case REINDEX_OBJECT_TABLE: deparseAppendStringInfoString(state, "TABLE "); break; case REINDEX_OBJECT_SCHEMA: deparseAppendStringInfoString(state, "SCHEMA "); break; case REINDEX_OBJECT_SYSTEM: deparseAppendStringInfoString(state, "SYSTEM "); break; case REINDEX_OBJECT_DATABASE: deparseAppendStringInfoString(state, "DATABASE "); break; } if (reindex_stmt->relation != NULL) { deparseRangeVar(state, reindex_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); } else if (reindex_stmt->name != NULL) { deparseAppendStringInfoString(state, quote_identifier(reindex_stmt->name)); } } static void deparseRuleStmt(DeparseState *state, RuleStmt* rule_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "CREATE "); if (rule_stmt->replace) deparseAppendStringInfoString(state, "OR REPLACE "); deparseAppendStringInfoString(state, "RULE "); deparseAppendStringInfoString(state, quote_identifier(rule_stmt->rulename)); deparseAppendStringInfoString(state, " AS ON "); switch (rule_stmt->event) { case CMD_UNKNOWN: case CMD_UTILITY: case CMD_NOTHING: // Not supported here Assert(false); break; case CMD_SELECT: deparseAppendStringInfoString(state, "SELECT "); break; case CMD_UPDATE: deparseAppendStringInfoString(state, "UPDATE "); break; case CMD_INSERT: deparseAppendStringInfoString(state, "INSERT "); break; case CMD_DELETE: deparseAppendStringInfoString(state, "DELETE "); break; case CMD_MERGE: deparseAppendStringInfoString(state, "MERGE "); break; } deparseAppendStringInfoString(state, "TO "); deparseRangeVar(state, rule_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); deparseWhereClause(state, rule_stmt->whereClause); deparseAppendStringInfoString(state, "DO "); if (rule_stmt->instead) deparseAppendStringInfoString(state, "INSTEAD "); if (list_length(rule_stmt->actions) == 0) { deparseAppendStringInfoString(state, "NOTHING"); } else if (list_length(rule_stmt->actions) == 1) { deparseRuleActionStmt(state, linitial(rule_stmt->actions)); } else { deparseAppendStringInfoChar(state, '('); foreach (lc, rule_stmt->actions) { deparseRuleActionStmt(state, lfirst(lc)); if (lnext(rule_stmt->actions, lc)) deparseAppendStringInfoString(state, "; "); } deparseAppendStringInfoChar(state, ')'); } } static void deparseNotifyStmt(DeparseState *state, NotifyStmt *notify_stmt) { deparseAppendStringInfoString(state, "NOTIFY "); deparseAppendStringInfoString(state, quote_identifier(notify_stmt->conditionname)); if (notify_stmt->payload != NULL) { deparseAppendStringInfoString(state, ", "); deparseStringLiteral(state, notify_stmt->payload); } } static void deparseListenStmt(DeparseState *state, ListenStmt *listen_stmt) { deparseAppendStringInfoString(state, "LISTEN "); deparseAppendStringInfoString(state, quote_identifier(listen_stmt->conditionname)); } static void deparseUnlistenStmt(DeparseState *state, UnlistenStmt *unlisten_stmt) { deparseAppendStringInfoString(state, "UNLISTEN "); if (unlisten_stmt->conditionname == NULL) deparseAppendStringInfoString(state, "*"); else deparseAppendStringInfoString(state, quote_identifier(unlisten_stmt->conditionname)); } static void deparseCreateSeqStmt(DeparseState *state, CreateSeqStmt *create_seq_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "CREATE "); deparseOptTemp(state, create_seq_stmt->sequence->relpersistence); deparseAppendStringInfoString(state, "SEQUENCE "); if (create_seq_stmt->if_not_exists) deparseAppendStringInfoString(state, "IF NOT EXISTS "); deparseRangeVar(state, create_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); deparseOptSeqOptList(state, create_seq_stmt->options); removeTrailingSpace(state); } static void deparseAlterFunctionStmt(DeparseState *state, AlterFunctionStmt *alter_function_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "ALTER "); switch (alter_function_stmt->objtype) { case OBJECT_FUNCTION: deparseAppendStringInfoString(state, "FUNCTION "); break; case OBJECT_PROCEDURE: deparseAppendStringInfoString(state, "PROCEDURE "); break; case OBJECT_ROUTINE: deparseAppendStringInfoString(state, "ROUTINE "); break; default: // Not supported here Assert(false); break; } deparseFunctionWithArgtypes(state, alter_function_stmt->func); deparseAppendStringInfoChar(state, ' '); foreach (lc, alter_function_stmt->actions) { deparseCommonFuncOptItem(state, castNode(DefElem, lfirst(lc))); if (lnext(alter_function_stmt->actions, lc)) deparseAppendStringInfoChar(state, ' '); } } static void deparseTruncateStmt(DeparseState *state, TruncateStmt *truncate_stmt) { deparseAppendStringInfoString(state, "TRUNCATE "); deparseRelationExprList(state, truncate_stmt->relations); deparseAppendStringInfoChar(state, ' '); if (truncate_stmt->restart_seqs) deparseAppendStringInfoString(state, "RESTART IDENTITY "); deparseOptDropBehavior(state, truncate_stmt->behavior); removeTrailingSpace(state); } static void deparseCreateEventTrigStmt(DeparseState *state, CreateEventTrigStmt *create_event_trig_stmt) { ListCell *lc = NULL; ListCell *lc2 = NULL; deparseAppendStringInfoString(state, "CREATE EVENT TRIGGER "); deparseAppendStringInfoString(state, quote_identifier(create_event_trig_stmt->trigname)); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "ON "); deparseAppendStringInfoString(state, quote_identifier(create_event_trig_stmt->eventname)); deparseAppendStringInfoChar(state, ' '); if (create_event_trig_stmt->whenclause) { deparseAppendStringInfoString(state, "WHEN "); foreach (lc, create_event_trig_stmt->whenclause) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); List *l = castNode(List, def_elem->arg); deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); deparseAppendStringInfoString(state, " IN ("); foreach (lc2, l) { deparseStringLiteral(state, strVal(lfirst(lc2))); if (lnext(l, lc2)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); if (lnext(create_event_trig_stmt->whenclause, lc)) deparseAppendStringInfoString(state, " AND "); } deparseAppendStringInfoChar(state, ' '); } deparseAppendStringInfoString(state, "EXECUTE FUNCTION "); deparseFuncName(state, create_event_trig_stmt->funcname); deparseAppendStringInfoString(state, "()"); } static void deparseAlterEventTrigStmt(DeparseState *state, AlterEventTrigStmt *alter_event_trig_stmt) { deparseAppendStringInfoString(state, "ALTER EVENT TRIGGER "); deparseAppendStringInfoString(state, quote_identifier(alter_event_trig_stmt->trigname)); deparseAppendStringInfoChar(state, ' '); switch (alter_event_trig_stmt->tgenabled) { case TRIGGER_FIRES_ON_ORIGIN: deparseAppendStringInfoString(state, "ENABLE"); break; case TRIGGER_FIRES_ON_REPLICA: deparseAppendStringInfoString(state, "ENABLE REPLICA"); break; case TRIGGER_FIRES_ALWAYS: deparseAppendStringInfoString(state, "ENABLE ALWAYS"); break; case TRIGGER_DISABLED: deparseAppendStringInfoString(state, "DISABLE"); break; } } static void deparseRefreshMatViewStmt(DeparseState *state, RefreshMatViewStmt *refresh_mat_view_stmt) { deparseAppendStringInfoString(state, "REFRESH MATERIALIZED VIEW "); if (refresh_mat_view_stmt->concurrent) deparseAppendStringInfoString(state, "CONCURRENTLY "); deparseRangeVar(state, refresh_mat_view_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); if (refresh_mat_view_stmt->skipData) deparseAppendStringInfoString(state, "WITH NO DATA "); removeTrailingSpace(state); } static void deparseReplicaIdentityStmt(DeparseState *state, ReplicaIdentityStmt *replica_identity_stmt) { switch (replica_identity_stmt->identity_type) { case REPLICA_IDENTITY_NOTHING: deparseAppendStringInfoString(state, "NOTHING "); break; case REPLICA_IDENTITY_FULL: deparseAppendStringInfoString(state, "FULL "); break; case REPLICA_IDENTITY_DEFAULT: deparseAppendStringInfoString(state, "DEFAULT "); break; case REPLICA_IDENTITY_INDEX: Assert(replica_identity_stmt->name != NULL); deparseAppendStringInfoString(state, "USING INDEX "); deparseAppendStringInfoString(state, quote_identifier(replica_identity_stmt->name)); break; } } // "CreatePolicyStmt" in gram.y static void deparseCreatePolicyStmt(DeparseState *state, CreatePolicyStmt *create_policy_stmt) { ListCell *lc = NULL; deparseAppendStringInfoString(state, "CREATE POLICY "); deparseColId(state, create_policy_stmt->policy_name); deparseAppendStringInfoString(state, " ON "); deparseRangeVar(state, create_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); if (!create_policy_stmt->permissive) deparseAppendStringInfoString(state, "AS RESTRICTIVE "); if (strcmp(create_policy_stmt->cmd_name, "all") == 0) Assert(true); // Default else if (strcmp(create_policy_stmt->cmd_name, "select") == 0) deparseAppendStringInfoString(state, "FOR SELECT "); else if (strcmp(create_policy_stmt->cmd_name, "insert") == 0) deparseAppendStringInfoString(state, "FOR INSERT "); else if (strcmp(create_policy_stmt->cmd_name, "update") == 0) deparseAppendStringInfoString(state, "FOR UPDATE "); else if (strcmp(create_policy_stmt->cmd_name, "delete") == 0) deparseAppendStringInfoString(state, "FOR DELETE "); else Assert(false); deparseAppendStringInfoString(state, "TO "); deparseRoleList(state, create_policy_stmt->roles); deparseAppendStringInfoChar(state, ' '); if (create_policy_stmt->qual != NULL) { deparseAppendStringInfoString(state, "USING ("); deparseExpr(state, create_policy_stmt->qual, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); } if (create_policy_stmt->with_check != NULL) { deparseAppendStringInfoString(state, "WITH CHECK ("); deparseExpr(state, create_policy_stmt->with_check, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); } } // "AlterPolicyStmt" in gram.y static void deparseAlterPolicyStmt(DeparseState *state, AlterPolicyStmt *alter_policy_stmt) { deparseAppendStringInfoString(state, "ALTER POLICY "); deparseAppendStringInfoString(state, quote_identifier(alter_policy_stmt->policy_name)); deparseAppendStringInfoString(state, " ON "); deparseRangeVar(state, alter_policy_stmt->table, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); if (list_length(alter_policy_stmt->roles) > 0) { deparseAppendStringInfoString(state, "TO "); deparseRoleList(state, alter_policy_stmt->roles); deparseAppendStringInfoChar(state, ' '); } if (alter_policy_stmt->qual != NULL) { deparseAppendStringInfoString(state, "USING ("); deparseExpr(state, alter_policy_stmt->qual, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); } if (alter_policy_stmt->with_check != NULL) { deparseAppendStringInfoString(state, "WITH CHECK ("); deparseExpr(state, alter_policy_stmt->with_check, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); } } static void deparseCreateTableSpaceStmt(DeparseState *state, CreateTableSpaceStmt *create_table_space_stmt) { deparseAppendStringInfoString(state, "CREATE TABLESPACE "); deparseColId(state, create_table_space_stmt->tablespacename); deparseAppendStringInfoChar(state, ' '); if (create_table_space_stmt->owner != NULL) { deparseAppendStringInfoString(state, "OWNER "); deparseRoleSpec(state, create_table_space_stmt->owner); deparseAppendStringInfoChar(state, ' '); } deparseAppendStringInfoString(state, "LOCATION "); if (create_table_space_stmt->location != NULL) deparseStringLiteral(state, create_table_space_stmt->location); else deparseAppendStringInfoString(state, "''"); deparseAppendStringInfoChar(state, ' '); deparseOptWith(state, create_table_space_stmt->options); removeTrailingSpace(state); } static void deparseCreateTransformStmt(DeparseState *state, CreateTransformStmt *create_transform_stmt) { deparseAppendStringInfoString(state, "CREATE "); if (create_transform_stmt->replace) deparseAppendStringInfoString(state, "OR REPLACE "); deparseAppendStringInfoString(state, "TRANSFORM FOR "); deparseTypeName(state, create_transform_stmt->type_name); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "LANGUAGE "); deparseAppendStringInfoString(state, quote_identifier(create_transform_stmt->lang)); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoChar(state, '('); if (create_transform_stmt->fromsql) { deparseAppendStringInfoString(state, "FROM SQL WITH FUNCTION "); deparseFunctionWithArgtypes(state, create_transform_stmt->fromsql); } if (create_transform_stmt->fromsql && create_transform_stmt->tosql) deparseAppendStringInfoString(state, ", "); if (create_transform_stmt->tosql) { deparseAppendStringInfoString(state, "TO SQL WITH FUNCTION "); deparseFunctionWithArgtypes(state, create_transform_stmt->tosql); } deparseAppendStringInfoChar(state, ')'); } static void deparseCreateAmStmt(DeparseState *state, CreateAmStmt *create_am_stmt) { deparseAppendStringInfoString(state, "CREATE ACCESS METHOD "); deparseAppendStringInfoString(state, quote_identifier(create_am_stmt->amname)); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "TYPE "); switch (create_am_stmt->amtype) { case AMTYPE_INDEX: deparseAppendStringInfoString(state, "INDEX "); break; case AMTYPE_TABLE: deparseAppendStringInfoString(state, "TABLE "); break; } deparseAppendStringInfoString(state, "HANDLER "); deparseHandlerName(state, create_am_stmt->handler_name); } // "pub_obj_list" in gram.y static void deparsePublicationObjectList(DeparseState *state, List *pubobjects) { const ListCell *lc; foreach(lc, pubobjects) { PublicationObjSpec *obj = lfirst(lc); switch (obj->pubobjtype) { case PUBLICATIONOBJ_TABLE: deparseAppendStringInfoString(state, "TABLE "); deparseRangeVar(state, obj->pubtable->relation, DEPARSE_NODE_CONTEXT_NONE); if (obj->pubtable->columns) { deparseAppendStringInfoChar(state, '('); deparseColumnList(state, obj->pubtable->columns); deparseAppendStringInfoChar(state, ')'); } if (obj->pubtable->whereClause) { deparseAppendStringInfoString(state, " WHERE ("); deparseExpr(state, obj->pubtable->whereClause, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ")"); } break; case PUBLICATIONOBJ_TABLES_IN_SCHEMA: deparseAppendStringInfoString(state, "TABLES IN SCHEMA "); deparseAppendStringInfoString(state, quote_identifier(obj->name)); break; case PUBLICATIONOBJ_TABLES_IN_CUR_SCHEMA: deparseAppendStringInfoString(state, "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)) { deparseAppendStringInfoString(state, ", "); } } } static void deparseCreatePublicationStmt(DeparseState *state, CreatePublicationStmt *create_publication_stmt) { ListCell *lc = NULL; deparseAppendStringInfoString(state, "CREATE PUBLICATION "); deparseAppendStringInfoString(state, quote_identifier(create_publication_stmt->pubname)); deparseAppendStringInfoChar(state, ' '); if (list_length(create_publication_stmt->pubobjects) > 0) { deparseAppendStringInfoString(state, "FOR "); deparsePublicationObjectList(state, create_publication_stmt->pubobjects); deparseAppendStringInfoChar(state, ' '); } else if (create_publication_stmt->for_all_tables) { deparseAppendStringInfoString(state, "FOR ALL TABLES "); } deparseOptDefinition(state, create_publication_stmt->options); removeTrailingSpace(state); } static void deparseAlterPublicationStmt(DeparseState *state, AlterPublicationStmt *alter_publication_stmt) { deparseAppendStringInfoString(state, "ALTER PUBLICATION "); deparseColId(state, alter_publication_stmt->pubname); deparseAppendStringInfoChar(state, ' '); if (list_length(alter_publication_stmt->pubobjects) > 0) { switch (alter_publication_stmt->action) { case AP_SetObjects: deparseAppendStringInfoString(state, "SET "); break; case AP_AddObjects: deparseAppendStringInfoString(state, "ADD "); break; case AP_DropObjects: deparseAppendStringInfoString(state, "DROP "); break; } deparsePublicationObjectList(state, alter_publication_stmt->pubobjects); } else if (list_length(alter_publication_stmt->options) > 0) { deparseAppendStringInfoString(state, "SET "); deparseDefinition(state, alter_publication_stmt->options); } else { Assert(false); } } static void deparseAlterSeqStmt(DeparseState *state, AlterSeqStmt *alter_seq_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "ALTER SEQUENCE "); if (alter_seq_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseRangeVar(state, alter_seq_stmt->sequence, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); deparseSeqOptList(state, alter_seq_stmt->options); removeTrailingSpace(state); } static void deparseAlterSystemStmt(DeparseState *state, AlterSystemStmt *alter_system_stmt) { deparseAppendStringInfoString(state, "ALTER SYSTEM "); deparseVariableSetStmt(state, alter_system_stmt->setstmt); } static void deparseCommentStmt(DeparseState *state, CommentStmt *comment_stmt) { ListCell *lc; List *l; deparseAppendStringInfoString(state, "COMMENT ON "); switch (comment_stmt->objtype) { case OBJECT_COLUMN: deparseAppendStringInfoString(state, "COLUMN "); break; case OBJECT_INDEX: deparseAppendStringInfoString(state, "INDEX "); break; case OBJECT_SEQUENCE: deparseAppendStringInfoString(state, "SEQUENCE "); break; case OBJECT_STATISTIC_EXT: deparseAppendStringInfoString(state, "STATISTICS "); break; case OBJECT_TABLE: deparseAppendStringInfoString(state, "TABLE "); break; case OBJECT_VIEW: deparseAppendStringInfoString(state, "VIEW "); break; case OBJECT_MATVIEW: deparseAppendStringInfoString(state, "MATERIALIZED VIEW "); break; case OBJECT_COLLATION: deparseAppendStringInfoString(state, "COLLATION "); break; case OBJECT_CONVERSION: deparseAppendStringInfoString(state, "CONVERSION "); break; case OBJECT_FOREIGN_TABLE: deparseAppendStringInfoString(state, "FOREIGN TABLE "); break; case OBJECT_TSCONFIGURATION: deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); break; case OBJECT_TSDICTIONARY: deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); break; case OBJECT_TSPARSER: deparseAppendStringInfoString(state, "TEXT SEARCH PARSER "); break; case OBJECT_TSTEMPLATE: deparseAppendStringInfoString(state, "TEXT SEARCH TEMPLATE "); break; case OBJECT_ACCESS_METHOD: deparseAppendStringInfoString(state, "ACCESS METHOD "); break; case OBJECT_DATABASE: deparseAppendStringInfoString(state, "DATABASE "); break; case OBJECT_EVENT_TRIGGER: deparseAppendStringInfoString(state, "EVENT TRIGGER "); break; case OBJECT_EXTENSION: deparseAppendStringInfoString(state, "EXTENSION "); break; case OBJECT_FDW: deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); break; case OBJECT_LANGUAGE: deparseAppendStringInfoString(state, "LANGUAGE "); break; case OBJECT_PUBLICATION: deparseAppendStringInfoString(state, "PUBLICATION "); break; case OBJECT_ROLE: deparseAppendStringInfoString(state, "ROLE "); break; case OBJECT_SCHEMA: deparseAppendStringInfoString(state, "SCHEMA "); break; case OBJECT_FOREIGN_SERVER: deparseAppendStringInfoString(state, "SERVER "); break; case OBJECT_SUBSCRIPTION: deparseAppendStringInfoString(state, "SUBSCRIPTION "); break; case OBJECT_TABLESPACE: deparseAppendStringInfoString(state, "TABLESPACE "); break; case OBJECT_TYPE: deparseAppendStringInfoString(state, "TYPE "); break; case OBJECT_DOMAIN: deparseAppendStringInfoString(state, "DOMAIN "); break; case OBJECT_AGGREGATE: deparseAppendStringInfoString(state, "AGGREGATE "); break; case OBJECT_FUNCTION: deparseAppendStringInfoString(state, "FUNCTION "); break; case OBJECT_OPERATOR: deparseAppendStringInfoString(state, "OPERATOR "); break; case OBJECT_TABCONSTRAINT: deparseAppendStringInfoString(state, "CONSTRAINT "); break; case OBJECT_DOMCONSTRAINT: deparseAppendStringInfoString(state, "CONSTRAINT "); break; case OBJECT_POLICY: deparseAppendStringInfoString(state, "POLICY "); break; case OBJECT_PROCEDURE: deparseAppendStringInfoString(state, "PROCEDURE "); break; case OBJECT_ROUTINE: deparseAppendStringInfoString(state, "ROUTINE "); break; case OBJECT_RULE: deparseAppendStringInfoString(state, "RULE "); break; case OBJECT_TRANSFORM: deparseAppendStringInfoString(state, "TRANSFORM "); break; case OBJECT_TRIGGER: deparseAppendStringInfoString(state, "TRIGGER "); break; case OBJECT_OPCLASS: deparseAppendStringInfoString(state, "OPERATOR CLASS "); break; case OBJECT_OPFAMILY: deparseAppendStringInfoString(state, "OPERATOR FAMILY "); break; case OBJECT_LARGEOBJECT: deparseAppendStringInfoString(state, "LARGE OBJECT "); break; case OBJECT_CAST: deparseAppendStringInfoString(state, "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(state, 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: deparseAppendStringInfoString(state, quote_identifier(strVal(comment_stmt->object))); break; case OBJECT_TYPE: case OBJECT_DOMAIN: deparseTypeName(state, castNode(TypeName, comment_stmt->object)); break; case OBJECT_AGGREGATE: deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, comment_stmt->object)); break; case OBJECT_FUNCTION: case OBJECT_PROCEDURE: case OBJECT_ROUTINE: deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, comment_stmt->object)); break; case OBJECT_OPERATOR: deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, comment_stmt->object)); break; case OBJECT_TABCONSTRAINT: case OBJECT_POLICY: case OBJECT_RULE: case OBJECT_TRIGGER: l = castNode(List, comment_stmt->object); deparseAppendStringInfoString(state, quote_identifier(strVal(llast(l)))); deparseAppendStringInfoString(state, " ON "); deparseAnyNameSkipLast(state, l); break; case OBJECT_DOMCONSTRAINT: l = castNode(List, comment_stmt->object); deparseAppendStringInfoString(state, quote_identifier(strVal(llast(l)))); deparseAppendStringInfoString(state, " ON DOMAIN "); deparseTypeName(state, linitial(l)); break; case OBJECT_TRANSFORM: l = castNode(List, comment_stmt->object); deparseAppendStringInfoString(state, "FOR "); deparseTypeName(state, castNode(TypeName, linitial(l))); deparseAppendStringInfoString(state, " LANGUAGE "); deparseAppendStringInfoString(state, quote_identifier(strVal(lsecond(l)))); break; case OBJECT_OPCLASS: case OBJECT_OPFAMILY: l = castNode(List, comment_stmt->object); deparseAnyNameSkipFirst(state, l); deparseAppendStringInfoString(state, " USING "); deparseAppendStringInfoString(state, quote_identifier(strVal(linitial(l)))); break; case OBJECT_LARGEOBJECT: deparseValue(state, (union ValUnion *) comment_stmt->object, DEPARSE_NODE_CONTEXT_NONE); break; case OBJECT_CAST: l = castNode(List, comment_stmt->object); deparseAppendStringInfoChar(state, '('); deparseTypeName(state, castNode(TypeName, linitial(l))); deparseAppendStringInfoString(state, " AS "); deparseTypeName(state, castNode(TypeName, lsecond(l))); deparseAppendStringInfoChar(state, ')'); break; default: // No other cases are supported in the parser Assert(false); break; } deparseAppendStringInfoString(state, " IS "); if (comment_stmt->comment != NULL) deparseStringLiteral(state, comment_stmt->comment); else deparseAppendStringInfoString(state, "NULL"); } // "stats_param" in gram.y static void deparseStatsElem(DeparseState *state, StatsElem *stats_elem) { // only one of stats_elem->name or stats_elem->expr can be non-null if (stats_elem->name) deparseAppendStringInfoString(state, stats_elem->name); else if (stats_elem->expr) { deparseAppendStringInfoChar(state, '('); deparseExpr(state, stats_elem->expr, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ')'); } } static void deparseCreateStatsStmt(DeparseState *state, CreateStatsStmt *create_stats_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "CREATE STATISTICS "); if (create_stats_stmt->if_not_exists) deparseAppendStringInfoString(state, "IF NOT EXISTS "); deparseAnyName(state, create_stats_stmt->defnames); deparseAppendStringInfoChar(state, ' '); if (list_length(create_stats_stmt->stat_types) > 0) { deparseAppendStringInfoChar(state, '('); deparseNameList(state, create_stats_stmt->stat_types); deparseAppendStringInfoString(state, ") "); } deparseAppendStringInfoString(state, "ON "); foreach (lc, create_stats_stmt->exprs) { deparseStatsElem(state, lfirst(lc)); if (lnext(create_stats_stmt->exprs, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, " FROM "); deparseFromList(state, create_stats_stmt->relations); } static void deparseAlterCollationStmt(DeparseState *state, AlterCollationStmt *alter_collation_stmt) { deparseAppendStringInfoString(state, "ALTER COLLATION "); deparseAnyName(state, alter_collation_stmt->collname); deparseAppendStringInfoString(state, " REFRESH VERSION"); } static void deparseAlterDatabaseStmt(DeparseState *state, AlterDatabaseStmt *alter_database_stmt) { deparseAppendStringInfoString(state, "ALTER DATABASE "); deparseColId(state, alter_database_stmt->dbname); deparseAppendStringInfoChar(state, ' '); deparseCreatedbOptList(state, alter_database_stmt->options); removeTrailingSpace(state); } static void deparseAlterDatabaseSetStmt(DeparseState *state, AlterDatabaseSetStmt *alter_database_set_stmt) { deparseAppendStringInfoString(state, "ALTER DATABASE "); deparseColId(state, alter_database_set_stmt->dbname); deparseAppendStringInfoChar(state, ' '); deparseVariableSetStmt(state, alter_database_set_stmt->setstmt); } static void deparseAlterStatsStmt(DeparseState *state, AlterStatsStmt *alter_stats_stmt) { deparseAppendStringInfoString(state, "ALTER STATISTICS "); if (alter_stats_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseAnyName(state, alter_stats_stmt->defnames); deparseAppendStringInfoChar(state, ' '); if (alter_stats_stmt->stxstattarget) deparseAppendStringInfo(state, "SET STATISTICS %d", castNode(Integer, alter_stats_stmt->stxstattarget)->ival); else deparseAppendStringInfo(state, "SET STATISTICS DEFAULT"); } static void deparseAlterTSDictionaryStmt(DeparseState *state, AlterTSDictionaryStmt *alter_ts_dictionary_stmt) { deparseAppendStringInfoString(state, "ALTER TEXT SEARCH DICTIONARY "); deparseAnyName(state, alter_ts_dictionary_stmt->dictname); deparseAppendStringInfoChar(state, ' '); deparseDefinition(state, alter_ts_dictionary_stmt->options); } static void deparseAlterTSConfigurationStmt(DeparseState *state, AlterTSConfigurationStmt *alter_ts_configuration_stmt) { ListCell *lc = NULL; deparseAppendStringInfoString(state, "ALTER TEXT SEARCH CONFIGURATION "); deparseAnyName(state, alter_ts_configuration_stmt->cfgname); deparseAppendStringInfoChar(state, ' '); switch (alter_ts_configuration_stmt->kind) { case ALTER_TSCONFIG_ADD_MAPPING: deparseAppendStringInfoString(state, "ADD MAPPING FOR "); deparseNameList(state, alter_ts_configuration_stmt->tokentype); deparseAppendStringInfoString(state, " WITH "); deparseAnyNameList(state, alter_ts_configuration_stmt->dicts); break; case ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN: deparseAppendStringInfoString(state, "ALTER MAPPING FOR "); deparseNameList(state, alter_ts_configuration_stmt->tokentype); deparseAppendStringInfoString(state, " WITH "); deparseAnyNameList(state, alter_ts_configuration_stmt->dicts); break; case ALTER_TSCONFIG_REPLACE_DICT: deparseAppendStringInfoString(state, "ALTER MAPPING REPLACE "); deparseAnyName(state, linitial(alter_ts_configuration_stmt->dicts)); deparseAppendStringInfoString(state, " WITH "); deparseAnyName(state, lsecond(alter_ts_configuration_stmt->dicts)); break; case ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN: deparseAppendStringInfoString(state, "ALTER MAPPING FOR "); deparseNameList(state, alter_ts_configuration_stmt->tokentype); deparseAppendStringInfoString(state, " REPLACE "); deparseAnyName(state, linitial(alter_ts_configuration_stmt->dicts)); deparseAppendStringInfoString(state, " WITH "); deparseAnyName(state, lsecond(alter_ts_configuration_stmt->dicts)); break; case ALTER_TSCONFIG_DROP_MAPPING: deparseAppendStringInfoString(state, "DROP MAPPING "); if (alter_ts_configuration_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseAppendStringInfoString(state, "FOR "); deparseNameList(state, alter_ts_configuration_stmt->tokentype); break; } } static void deparseVariableShowStmt(DeparseState *state, VariableShowStmt *variable_show_stmt) { deparseAppendStringInfoString(state, "SHOW "); if (strcmp(variable_show_stmt->name, "timezone") == 0) deparseAppendStringInfoString(state, "TIME ZONE"); else if (strcmp(variable_show_stmt->name, "transaction_isolation") == 0) deparseAppendStringInfoString(state, "TRANSACTION ISOLATION LEVEL"); else if (strcmp(variable_show_stmt->name, "session_authorization") == 0) deparseAppendStringInfoString(state, "SESSION AUTHORIZATION"); else if (strcmp(variable_show_stmt->name, "all") == 0) deparseAppendStringInfoString(state, "ALL"); else deparseAppendStringInfoString(state, quote_identifier(variable_show_stmt->name)); } // "tablesample_clause" in gram.y static void deparseRangeTableSample(DeparseState *state, RangeTableSample *range_table_sample) { deparseRangeVar(state, castNode(RangeVar, range_table_sample->relation), DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoString(state, " TABLESAMPLE "); deparseFuncName(state, range_table_sample->method); deparseAppendStringInfoChar(state, '('); deparseExprList(state, range_table_sample->args); deparseAppendStringInfoString(state, ") "); if (range_table_sample->repeatable != NULL) { deparseAppendStringInfoString(state, "REPEATABLE ("); deparseExpr(state, range_table_sample->repeatable, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); } removeTrailingSpace(state); } static void deparseCreateSubscriptionStmt(DeparseState *state, CreateSubscriptionStmt *create_subscription_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "CREATE SUBSCRIPTION "); deparseAppendStringInfoString(state, quote_identifier(create_subscription_stmt->subname)); deparseAppendStringInfoString(state, " CONNECTION "); if (create_subscription_stmt->conninfo != NULL) deparseStringLiteral(state, create_subscription_stmt->conninfo); else deparseAppendStringInfoString(state, "''"); deparseAppendStringInfoString(state, " PUBLICATION "); foreach(lc, create_subscription_stmt->publication) { deparseColLabel(state, strVal(lfirst(lc))); if (lnext(create_subscription_stmt->publication, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ' '); deparseOptDefinition(state, create_subscription_stmt->options); removeTrailingSpace(state); } static void deparseAlterSubscriptionStmt(DeparseState *state, AlterSubscriptionStmt *alter_subscription_stmt) { ListCell *lc; deparseAppendStringInfoString(state, "ALTER SUBSCRIPTION "); deparseAppendStringInfoString(state, quote_identifier(alter_subscription_stmt->subname)); deparseAppendStringInfoChar(state, ' '); switch (alter_subscription_stmt->kind) { case ALTER_SUBSCRIPTION_OPTIONS: deparseAppendStringInfoString(state, "SET "); deparseDefinition(state, alter_subscription_stmt->options); break; case ALTER_SUBSCRIPTION_SKIP: deparseAppendStringInfoString(state, "SKIP "); deparseDefinition(state, alter_subscription_stmt->options); break; case ALTER_SUBSCRIPTION_CONNECTION: deparseAppendStringInfoString(state, "CONNECTION "); deparseStringLiteral(state, alter_subscription_stmt->conninfo); deparseAppendStringInfoChar(state, ' '); break; case ALTER_SUBSCRIPTION_REFRESH: deparseAppendStringInfoString(state, "REFRESH PUBLICATION "); deparseOptDefinition(state, alter_subscription_stmt->options); break; case ALTER_SUBSCRIPTION_ADD_PUBLICATION: deparseAppendStringInfoString(state, "ADD PUBLICATION "); foreach(lc, alter_subscription_stmt->publication) { deparseColLabel(state, strVal(lfirst(lc))); if (lnext(alter_subscription_stmt->publication, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ' '); deparseOptDefinition(state, alter_subscription_stmt->options); break; case ALTER_SUBSCRIPTION_DROP_PUBLICATION: deparseAppendStringInfoString(state, "DROP PUBLICATION "); foreach(lc, alter_subscription_stmt->publication) { deparseColLabel(state, strVal(lfirst(lc))); if (lnext(alter_subscription_stmt->publication, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ' '); deparseOptDefinition(state, alter_subscription_stmt->options); break; case ALTER_SUBSCRIPTION_SET_PUBLICATION: deparseAppendStringInfoString(state, "SET PUBLICATION "); foreach(lc, alter_subscription_stmt->publication) { deparseColLabel(state, strVal(lfirst(lc))); if (lnext(alter_subscription_stmt->publication, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ' '); deparseOptDefinition(state, 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)) { deparseAppendStringInfoString(state, " ENABLE "); } else { deparseAppendStringInfoString(state, " DISABLE "); } break; } removeTrailingSpace(state); } static void deparseDropSubscriptionStmt(DeparseState *state, DropSubscriptionStmt *drop_subscription_stmt) { deparseAppendStringInfoString(state, "DROP SUBSCRIPTION "); if (drop_subscription_stmt->missing_ok) deparseAppendStringInfoString(state, "IF EXISTS "); deparseAppendStringInfoString(state, drop_subscription_stmt->subname); } static void deparseCallStmt(DeparseState *state, CallStmt *call_stmt) { deparseAppendStringInfoString(state, "CALL "); deparseFuncCall(state, call_stmt->funccall, DEPARSE_NODE_CONTEXT_NONE); } static void deparseAlterOwnerStmt(DeparseState *state, AlterOwnerStmt *alter_owner_stmt) { List *l = NULL; deparseAppendStringInfoString(state, "ALTER "); switch (alter_owner_stmt->objectType) { case OBJECT_AGGREGATE: deparseAppendStringInfoString(state, "AGGREGATE "); deparseAggregateWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); break; case OBJECT_COLLATION: deparseAppendStringInfoString(state, "COLLATION "); deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_CONVERSION: deparseAppendStringInfoString(state, "CONVERSION "); deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_DATABASE: deparseAppendStringInfoString(state, "DATABASE "); deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_DOMAIN: deparseAppendStringInfoString(state, "DOMAIN "); deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_FUNCTION: deparseAppendStringInfoString(state, "FUNCTION "); deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); break; case OBJECT_LANGUAGE: deparseAppendStringInfoString(state, "LANGUAGE "); deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_LARGEOBJECT: deparseAppendStringInfoString(state, "LARGE OBJECT "); deparseNumericOnly(state, (union ValUnion *) alter_owner_stmt->object); break; case OBJECT_OPERATOR: deparseAppendStringInfoString(state, "OPERATOR "); deparseOperatorWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); break; case OBJECT_OPCLASS: l = castNode(List, alter_owner_stmt->object); deparseAppendStringInfoString(state, "OPERATOR CLASS "); deparseAnyNameSkipFirst(state, l); deparseAppendStringInfoString(state, " USING "); deparseColId(state, strVal(linitial(l))); break; case OBJECT_OPFAMILY: l = castNode(List, alter_owner_stmt->object); deparseAppendStringInfoString(state, "OPERATOR FAMILY "); deparseAnyNameSkipFirst(state, l); deparseAppendStringInfoString(state, " USING "); deparseColId(state, strVal(linitial(l))); break; case OBJECT_PROCEDURE: deparseAppendStringInfoString(state, "PROCEDURE "); deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); break; case OBJECT_ROUTINE: deparseAppendStringInfoString(state, "ROUTINE "); deparseFunctionWithArgtypes(state, castNode(ObjectWithArgs, alter_owner_stmt->object)); break; case OBJECT_SCHEMA: deparseAppendStringInfoString(state, "SCHEMA "); deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_TYPE: deparseAppendStringInfoString(state, "TYPE "); deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_TABLESPACE: deparseAppendStringInfoString(state, "TABLESPACE "); deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_STATISTIC_EXT: deparseAppendStringInfoString(state, "STATISTICS "); deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_TSDICTIONARY: deparseAppendStringInfoString(state, "TEXT SEARCH DICTIONARY "); deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_TSCONFIGURATION: deparseAppendStringInfoString(state, "TEXT SEARCH CONFIGURATION "); deparseAnyName(state, castNode(List, alter_owner_stmt->object)); break; case OBJECT_FDW: deparseAppendStringInfoString(state, "FOREIGN DATA WRAPPER "); deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_FOREIGN_SERVER: deparseAppendStringInfoString(state, "SERVER "); deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_EVENT_TRIGGER: deparseAppendStringInfoString(state, "EVENT TRIGGER "); deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_PUBLICATION: deparseAppendStringInfoString(state, "PUBLICATION "); deparseColId(state, strVal(alter_owner_stmt->object)); break; case OBJECT_SUBSCRIPTION: deparseAppendStringInfoString(state, "SUBSCRIPTION "); deparseColId(state, strVal(alter_owner_stmt->object)); break; default: Assert(false); } deparseAppendStringInfoString(state, " OWNER TO "); deparseRoleSpec(state, alter_owner_stmt->newowner); } // "operator_def_list" in gram.y static void deparseOperatorDefList(DeparseState *state, List *defs) { ListCell *lc = NULL; foreach (lc, defs) { DefElem *def_elem = castNode(DefElem, lfirst(lc)); deparseAppendStringInfoString(state, quote_identifier(def_elem->defname)); deparseAppendStringInfoString(state, " = "); if (def_elem->arg != NULL) deparseDefArg(state, def_elem->arg, true); else deparseAppendStringInfoString(state, "NONE"); if (lnext(defs, lc)) deparseAppendStringInfoString(state, ", "); } } static void deparseAlterOperatorStmt(DeparseState *state, AlterOperatorStmt *alter_operator_stmt) { deparseAppendStringInfoString(state, "ALTER OPERATOR "); deparseOperatorWithArgtypes(state, alter_operator_stmt->opername); deparseAppendStringInfoString(state, " SET ("); deparseOperatorDefList(state, alter_operator_stmt->options); deparseAppendStringInfoChar(state, ')'); } static void deparseAlterTypeStmt(DeparseState *state, AlterTypeStmt *alter_type_stmt) { deparseAppendStringInfoString(state, "ALTER TYPE "); deparseAnyName(state, alter_type_stmt->typeName); deparseAppendStringInfoString(state, " SET ("); deparseOperatorDefList(state, alter_type_stmt->options); deparseAppendStringInfoChar(state, ')'); } static void deparseDropOwnedStmt(DeparseState *state, DropOwnedStmt *drop_owned_stmt) { deparseAppendStringInfoString(state, "DROP OWNED BY "); deparseRoleList(state, drop_owned_stmt->roles); deparseAppendStringInfoChar(state, ' '); deparseOptDropBehavior(state, drop_owned_stmt->behavior); removeTrailingSpace(state); } static void deparseReassignOwnedStmt(DeparseState *state, ReassignOwnedStmt *reassigned_owned_stmt) { deparseAppendStringInfoString(state, "REASSIGN OWNED BY "); deparseRoleList(state, reassigned_owned_stmt->roles); deparseAppendStringInfoChar(state, ' '); deparseAppendStringInfoString(state, "TO "); deparseRoleSpec(state, reassigned_owned_stmt->newrole); } static void deparseClosePortalStmt(DeparseState *state, ClosePortalStmt *close_portal_stmt) { deparseAppendStringInfoString(state, "CLOSE "); if (close_portal_stmt->portalname != NULL) { deparseAppendStringInfoString(state, quote_identifier(close_portal_stmt->portalname)); } else { deparseAppendStringInfoString(state, "ALL"); } } // "CreateTrigStmt" in gram.y static void deparseCreateTrigStmt(DeparseState *state, CreateTrigStmt *create_trig_stmt) { ListCell *lc; bool skip_events_or = true; deparseAppendStringInfoString(state, "CREATE "); if (create_trig_stmt->replace) deparseAppendStringInfoString(state, "OR REPLACE "); if (create_trig_stmt->isconstraint) deparseAppendStringInfoString(state, "CONSTRAINT "); deparseAppendStringInfoString(state, "TRIGGER "); deparseAppendStringInfoString(state, quote_identifier(create_trig_stmt->trigname)); deparseAppendStringInfoChar(state, ' '); switch (create_trig_stmt->timing) { case TRIGGER_TYPE_BEFORE: deparseAppendStringInfoString(state, "BEFORE "); break; case TRIGGER_TYPE_AFTER: deparseAppendStringInfoString(state, "AFTER "); break; case TRIGGER_TYPE_INSTEAD: deparseAppendStringInfoString(state, "INSTEAD OF "); break; default: Assert(false); } if (TRIGGER_FOR_INSERT(create_trig_stmt->events)) { deparseAppendStringInfoString(state, "INSERT "); skip_events_or = false; } if (TRIGGER_FOR_DELETE(create_trig_stmt->events)) { if (!skip_events_or) deparseAppendStringInfoString(state, "OR "); deparseAppendStringInfoString(state, "DELETE "); skip_events_or = false; } if (TRIGGER_FOR_UPDATE(create_trig_stmt->events)) { if (!skip_events_or) deparseAppendStringInfoString(state, "OR "); deparseAppendStringInfoString(state, "UPDATE "); if (list_length(create_trig_stmt->columns) > 0) { deparseAppendStringInfoString(state, "OF "); deparseColumnList(state, create_trig_stmt->columns); deparseAppendStringInfoChar(state, ' '); } skip_events_or = false; } if (TRIGGER_FOR_TRUNCATE(create_trig_stmt->events)) { if (!skip_events_or) deparseAppendStringInfoString(state, "OR "); deparseAppendStringInfoString(state, "TRUNCATE "); } deparseAppendStringInfoString(state, "ON "); deparseRangeVar(state, create_trig_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); if (create_trig_stmt->transitionRels != NULL) { deparseAppendStringInfoString(state, "REFERENCING "); foreach(lc, create_trig_stmt->transitionRels) { deparseTriggerTransition(state, castNode(TriggerTransition, lfirst(lc))); deparseAppendStringInfoChar(state, ' '); } } if (create_trig_stmt->constrrel != NULL) { deparseAppendStringInfoString(state, "FROM "); deparseRangeVar(state, create_trig_stmt->constrrel, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); } if (create_trig_stmt->deferrable) deparseAppendStringInfoString(state, "DEFERRABLE "); if (create_trig_stmt->initdeferred) deparseAppendStringInfoString(state, "INITIALLY DEFERRED "); if (create_trig_stmt->row) deparseAppendStringInfoString(state, "FOR EACH ROW "); if (create_trig_stmt->whenClause) { deparseAppendStringInfoString(state, "WHEN ("); deparseExpr(state, create_trig_stmt->whenClause, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); } deparseAppendStringInfoString(state, "EXECUTE FUNCTION "); deparseFuncName(state, create_trig_stmt->funcname); deparseAppendStringInfoChar(state, '('); foreach(lc, create_trig_stmt->args) { deparseStringLiteral(state, strVal(lfirst(lc))); if (lnext(create_trig_stmt->args, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); } static void deparseTriggerTransition(DeparseState *state, TriggerTransition *trigger_transition) { if (trigger_transition->isNew) deparseAppendStringInfoString(state, "NEW "); else deparseAppendStringInfoString(state, "OLD "); if (trigger_transition->isTable) deparseAppendStringInfoString(state, "TABLE "); else deparseAppendStringInfoString(state, "ROW "); deparseAppendStringInfoString(state, quote_identifier(trigger_transition->name)); } static void deparseXmlExpr(DeparseState *state, XmlExpr* xml_expr, DeparseNodeContext context) { switch (xml_expr->op) { case IS_XMLCONCAT: /* XMLCONCAT(args) */ deparseAppendStringInfoString(state, "xmlconcat("); deparseExprList(state, xml_expr->args); deparseAppendStringInfoChar(state, ')'); break; case IS_XMLELEMENT: /* XMLELEMENT(name, xml_attributes, args) */ deparseAppendStringInfoString(state, "xmlelement(name "); deparseAppendStringInfoString(state, quote_identifier(xml_expr->name)); if (xml_expr->named_args != NULL) { deparseAppendStringInfoString(state, ", xmlattributes("); deparseXmlAttributeList(state, xml_expr->named_args); deparseAppendStringInfoString(state, ")"); } if (xml_expr->args != NULL) { deparseAppendStringInfoString(state, ", "); deparseExprList(state, xml_expr->args); } deparseAppendStringInfoString(state, ")"); break; case IS_XMLFOREST: /* XMLFOREST(xml_attributes) */ deparseAppendStringInfoString(state, "xmlforest("); deparseXmlAttributeList(state, xml_expr->named_args); deparseAppendStringInfoChar(state, ')'); break; case IS_XMLPARSE: /* XMLPARSE(text, is_doc, preserve_ws) */ Assert(list_length(xml_expr->args) == 2); deparseAppendStringInfoString(state, "xmlparse("); switch (xml_expr->xmloption) { case XMLOPTION_DOCUMENT: deparseAppendStringInfoString(state, "document "); break; case XMLOPTION_CONTENT: deparseAppendStringInfoString(state, "content "); break; default: Assert(false); } deparseExpr(state, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ')'); break; case IS_XMLPI: /* XMLPI(name [, args]) */ deparseAppendStringInfoString(state, "xmlpi(name "); deparseAppendStringInfoString(state, quote_identifier(xml_expr->name)); if (xml_expr->args != NULL) { deparseAppendStringInfoString(state, ", "); deparseExpr(state, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); } deparseAppendStringInfoChar(state, ')'); break; case IS_XMLROOT: /* XMLROOT(xml, version, standalone) */ deparseAppendStringInfoString(state, "xmlroot("); deparseExpr(state, linitial(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ", version "); if (castNode(A_Const, lsecond(xml_expr->args))->isnull) deparseAppendStringInfoString(state, "no value"); else deparseExpr(state, lsecond(xml_expr->args), DEPARSE_NODE_CONTEXT_A_EXPR); if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_YES) deparseAppendStringInfoString(state, ", standalone yes"); else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO) deparseAppendStringInfoString(state, ", standalone no"); else if (intVal(&castNode(A_Const, lthird(xml_expr->args))->val) == XML_STANDALONE_NO_VALUE) deparseAppendStringInfoString(state, ", standalone no value"); deparseAppendStringInfoChar(state, ')'); 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(state, linitial(xml_expr->args), context); deparseAppendStringInfoString(state, " IS DOCUMENT"); break; } } // "xmltable_column_el" in gram.y static void deparseRangeTableFuncCol(DeparseState *state, RangeTableFuncCol* range_table_func_col) { deparseAppendStringInfoString(state, quote_identifier(range_table_func_col->colname)); deparseAppendStringInfoChar(state, ' '); if (range_table_func_col->for_ordinality) { deparseAppendStringInfoString(state, "FOR ORDINALITY "); } else { deparseTypeName(state, range_table_func_col->typeName); deparseAppendStringInfoChar(state, ' '); if (range_table_func_col->colexpr) { deparseAppendStringInfoString(state, "PATH "); deparseExpr(state, range_table_func_col->colexpr, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); deparseAppendStringInfoChar(state, ' '); } if (range_table_func_col->coldefexpr) { deparseAppendStringInfoString(state, "DEFAULT "); deparseExpr(state, range_table_func_col->coldefexpr, DEPARSE_NODE_CONTEXT_NONE /* b_expr */); deparseAppendStringInfoChar(state, ' '); } if (range_table_func_col->is_not_null) deparseAppendStringInfoString(state, "NOT NULL "); } removeTrailingSpace(state); } // "table_ref" and "xmltable" in gram.y static void deparseRangeTableFunc(DeparseState *state, RangeTableFunc* range_table_func) { ListCell *lc; if (range_table_func->lateral) deparseAppendStringInfoString(state, "LATERAL "); deparseAppendStringInfoString(state, "xmltable("); if (range_table_func->namespaces) { deparseAppendStringInfoString(state, "xmlnamespaces("); deparseXmlNamespaceList(state, range_table_func->namespaces); deparseAppendStringInfoString(state, "), "); } deparseAppendStringInfoChar(state, '('); deparseExpr(state, range_table_func->rowexpr, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); deparseAppendStringInfoChar(state, ')'); deparseAppendStringInfoString(state, " PASSING "); deparseExpr(state, range_table_func->docexpr, DEPARSE_NODE_CONTEXT_NONE /* c_expr */); deparseAppendStringInfoString(state, " COLUMNS "); foreach(lc, range_table_func->columns) { deparseRangeTableFuncCol(state, castNode(RangeTableFuncCol, lfirst(lc))); if (lnext(range_table_func->columns, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoString(state, ") "); if (range_table_func->alias) { deparseAppendStringInfoString(state, "AS "); deparseAlias(state, range_table_func->alias); } removeTrailingSpace(state); } static void deparseXmlSerialize(DeparseState *state, XmlSerialize *xml_serialize) { deparseAppendStringInfoString(state, "xmlserialize("); switch (xml_serialize->xmloption) { case XMLOPTION_DOCUMENT: deparseAppendStringInfoString(state, "document "); break; case XMLOPTION_CONTENT: deparseAppendStringInfoString(state, "content "); break; default: Assert(false); } deparseExpr(state, xml_serialize->expr, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, " AS "); deparseTypeName(state, xml_serialize->typeName); if (xml_serialize->indent) { deparseAppendStringInfoString(state, " INDENT"); } deparseAppendStringInfoString(state, ")"); } static void deparseJsonFormat(DeparseState *state, JsonFormat *json_format) { if (json_format == NULL || json_format->format_type == JS_FORMAT_DEFAULT) return; deparseAppendStringInfoString(state, "FORMAT JSON "); switch (json_format->encoding) { case JS_ENC_UTF8: deparseAppendStringInfoString(state, "ENCODING utf8 "); break; case JS_ENC_UTF16: deparseAppendStringInfoString(state, "ENCODING utf16 "); break; case JS_ENC_UTF32: deparseAppendStringInfoString(state, "ENCODING utf32 "); break; case JS_ENC_DEFAULT: // no encoding specified break; } } static void deparseJsonIsPredicate(DeparseState *state, JsonIsPredicate *j) { deparseExpr(state, j->expr, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ' '); deparseJsonFormat(state, castNode(JsonFormat, j->format)); deparseAppendStringInfoString(state, "IS "); switch (j->item_type) { case JS_TYPE_ANY: deparseAppendStringInfoString(state, "JSON "); break; case JS_TYPE_ARRAY: deparseAppendStringInfoString(state, "JSON ARRAY "); break; case JS_TYPE_OBJECT: deparseAppendStringInfoString(state, "JSON OBJECT "); break; case JS_TYPE_SCALAR: deparseAppendStringInfoString(state, "JSON SCALAR "); break; } if (j->unique_keys) deparseAppendStringInfoString(state, "WITH UNIQUE "); removeTrailingSpace(state); } // "json_value_expr" in gram.y static void deparseJsonValueExpr(DeparseState *state, JsonValueExpr *json_value_expr) { deparseExpr(state, (Node *) json_value_expr->raw_expr, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoChar(state, ' '); deparseJsonFormat(state, json_value_expr->format); } // "json_value_expr_list" in gram.y static void deparseJsonValueExprList(DeparseState *state, List *exprs) { ListCell *lc; foreach(lc, exprs) { deparseJsonValueExpr(state, lfirst(lc)); removeTrailingSpace(state); if (lnext(exprs, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ' '); } // "json_name_and_value" in gram.y static void deparseJsonKeyValue(DeparseState *state, JsonKeyValue *json_key_value) { deparseExpr(state, (Node *) json_key_value->key, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ": "); deparseJsonValueExpr(state, json_key_value->value); } // "json_name_and_value_list" in gram.y static void deparseJsonKeyValueList(DeparseState *state, List *exprs) { ListCell *lc; foreach(lc, exprs) { deparseJsonKeyValue(state, lfirst(lc)); removeTrailingSpace(state); if (lnext(exprs, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ' '); } static void deparseJsonOutput(DeparseState *state, JsonOutput *json_output) { if (json_output == NULL) return; Assert(json_output->returning != NULL); deparseAppendStringInfoString(state, "RETURNING "); deparseTypeName(state, json_output->typeName); deparseAppendStringInfoChar(state, ' '); deparseJsonFormat(state, json_output->returning->format); } // "json_aggregate_func" and "func_expr" in gram.y static void deparseJsonObjectAgg(DeparseState *state, JsonObjectAgg *json_object_agg) { Assert(json_object_agg->constructor != NULL); deparseAppendStringInfoString(state, "JSON_OBJECTAGG("); deparseJsonKeyValue(state, json_object_agg->arg); if (json_object_agg->absent_on_null) deparseAppendStringInfoString(state, "ABSENT ON NULL "); if (json_object_agg->unique) deparseAppendStringInfoString(state, "WITH UNIQUE "); deparseJsonOutput(state, json_object_agg->constructor->output); removeTrailingSpace(state); deparseAppendStringInfoString(state, ") "); if (json_object_agg->constructor->agg_filter) { deparseAppendStringInfoString(state, "FILTER (WHERE "); deparseExpr(state, json_object_agg->constructor->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); } if (json_object_agg->constructor->over) { struct WindowDef *over = json_object_agg->constructor->over; deparseAppendStringInfoString(state, "OVER "); if (over->name) deparseAppendStringInfoString(state, over->name); else deparseWindowDef(state, over); } removeTrailingSpace(state); } // "json_aggregate_func" and "func_expr" in gram.y static void deparseJsonArrayAgg(DeparseState *state, JsonArrayAgg *json_array_agg) { Assert(json_array_agg->constructor != NULL); deparseAppendStringInfoString(state, "JSON_ARRAYAGG("); deparseJsonValueExpr(state, json_array_agg->arg); deparseOptSortClause(state, json_array_agg->constructor->agg_order, DEPARSE_NODE_CONTEXT_NONE); if (!json_array_agg->absent_on_null) deparseAppendStringInfoString(state, "NULL ON NULL "); deparseJsonOutput(state, json_array_agg->constructor->output); removeTrailingSpace(state); deparseAppendStringInfoString(state, ") "); if (json_array_agg->constructor->agg_filter) { deparseAppendStringInfoString(state, "FILTER (WHERE "); deparseExpr(state, json_array_agg->constructor->agg_filter, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ") "); } if (json_array_agg->constructor->over) { struct WindowDef *over = json_array_agg->constructor->over; deparseAppendStringInfoString(state, "OVER "); if (over->name) deparseAppendStringInfoString(state, over->name); else deparseWindowDef(state, over); } removeTrailingSpace(state); } static void deparseJsonObjectConstructor(DeparseState *state, JsonObjectConstructor *json_object_constructor) { deparseAppendStringInfoString(state, "JSON_OBJECT("); deparseJsonKeyValueList(state, json_object_constructor->exprs); if (json_object_constructor->absent_on_null) deparseAppendStringInfoString(state, "ABSENT ON NULL "); if (json_object_constructor->unique) deparseAppendStringInfoString(state, "WITH UNIQUE "); deparseJsonOutput(state, json_object_constructor->output); removeTrailingSpace(state); deparseAppendStringInfoChar(state, ')'); } static void deparseJsonArrayConstructor(DeparseState *state, JsonArrayConstructor *json_array_constructor) { deparseAppendStringInfoString(state, "JSON_ARRAY("); deparseJsonValueExprList(state, json_array_constructor->exprs); if (!json_array_constructor->absent_on_null) deparseAppendStringInfoString(state, "NULL ON NULL "); deparseJsonOutput(state, json_array_constructor->output); removeTrailingSpace(state); deparseAppendStringInfoChar(state, ')'); } static void deparseJsonArrayQueryConstructor(DeparseState *state, JsonArrayQueryConstructor *json_array_query_constructor) { deparseAppendStringInfoString(state, "JSON_ARRAY("); deparseSelectStmt(state, castNode(SelectStmt, json_array_query_constructor->query), DEPARSE_NODE_CONTEXT_NONE); deparseJsonFormat(state, json_array_query_constructor->format); deparseJsonOutput(state, json_array_query_constructor->output); removeTrailingSpace(state); deparseAppendStringInfoChar(state, ')'); } static void deparseJsonParseExpr(DeparseState *state, JsonParseExpr *json_parse_expr) { deparseAppendStringInfoString(state, "JSON("); deparseJsonValueExpr(state, json_parse_expr->expr); if (json_parse_expr->unique_keys) deparseAppendStringInfoString(state, " WITH UNIQUE KEYS"); deparseAppendStringInfoString(state, ")"); } static void deparseJsonScalarExpr(DeparseState *state, JsonScalarExpr *json_scalar_expr) { deparseAppendStringInfoString(state, "JSON_SCALAR("); deparseExpr(state, (Node*) json_scalar_expr->expr, DEPARSE_NODE_CONTEXT_A_EXPR); deparseAppendStringInfoString(state, ")"); } static void deparseJsonSerializeExpr(DeparseState *state, JsonSerializeExpr *json_serialize_expr) { deparseAppendStringInfoString(state, "JSON_SERIALIZE("); deparseJsonValueExpr(state, json_serialize_expr->expr); if (json_serialize_expr->output) deparseJsonOutput(state, json_serialize_expr->output); deparseAppendStringInfoString(state, ")"); } static void deparseJsonQuotesClauseOpt(DeparseState *state, JsonQuotes quotes) { switch (quotes) { case JS_QUOTES_UNSPEC: break; case JS_QUOTES_KEEP: deparseAppendStringInfoString(state, " KEEP QUOTES"); break; case JS_QUOTES_OMIT: deparseAppendStringInfoString(state, " OMIT QUOTES"); break; } } static void deparseJsonOnErrorClauseOpt(DeparseState *state, JsonBehavior *behavior) { if (!behavior) return; deparseAppendStringInfoChar(state, ' '); deparseJsonBehavior(state, behavior); deparseAppendStringInfoString(state, " ON ERROR"); } static void deparseJsonOnEmptyClauseOpt(DeparseState *state, JsonBehavior *behavior) { if (behavior) { deparseAppendStringInfoChar(state, ' '); deparseJsonBehavior(state, behavior); deparseAppendStringInfoString(state, " ON EMPTY"); } } static void deparseJsonFuncExpr(DeparseState *state, JsonFuncExpr *json_func_expr) { switch (json_func_expr->op) { case JSON_EXISTS_OP: deparseAppendStringInfoString(state, "JSON_EXISTS("); break; case JSON_QUERY_OP: deparseAppendStringInfoString(state, "JSON_QUERY("); break; case JSON_VALUE_OP: deparseAppendStringInfoString(state, "JSON_VALUE("); break; case JSON_TABLE_OP: deparseAppendStringInfoString(state, "JSON_TABLE("); break; } deparseJsonValueExpr(state, json_func_expr->context_item); deparseAppendStringInfoString(state, ", "); deparseExpr(state, json_func_expr->pathspec, DEPARSE_NODE_CONTEXT_A_EXPR); if (json_func_expr->passing) deparseAppendStringInfoString(state, " PASSING "); ListCell *lc = NULL; foreach (lc, json_func_expr->passing) { JsonArgument *json_argument = castNode(JsonArgument, lfirst(lc)); deparseJsonValueExpr(state, json_argument->val); deparseAppendStringInfoString(state, " AS "); deparseColLabel(state, json_argument->name); if (lnext(json_func_expr->passing, lc)) deparseAppendStringInfoString(state, ", "); } if (json_func_expr->output) { deparseAppendStringInfoChar(state, ' '); deparseJsonOutput(state, json_func_expr->output); } switch (json_func_expr->wrapper) { case JSW_UNSPEC: break; case JSW_NONE: deparseAppendStringInfoString(state, " WITHOUT WRAPPER"); break; case JSW_CONDITIONAL: deparseAppendStringInfoString(state, " WITH CONDITIONAL WRAPPER"); break; case JSW_UNCONDITIONAL: deparseAppendStringInfoString(state, " WITH UNCONDITIONAL WRAPPER"); break; } deparseJsonQuotesClauseOpt(state, json_func_expr->quotes); deparseJsonOnEmptyClauseOpt(state, json_func_expr->on_empty); deparseJsonOnErrorClauseOpt(state, json_func_expr->on_error); deparseAppendStringInfoChar(state, ')'); } static void deparseJsonTablePathSpec(DeparseState *state, JsonTablePathSpec *json_table_path_spec) { deparseStringLiteral(state, castNode(A_Const, json_table_path_spec->string)->val.sval.sval); if (json_table_path_spec->name) { deparseAppendStringInfoString(state, " AS "); deparseColLabel(state, json_table_path_spec->name); } } // "json_behavior" in gram.y static void deparseJsonBehavior(DeparseState *state, JsonBehavior *json_behavior) { switch (json_behavior->btype) { case JSON_BEHAVIOR_NULL: deparseAppendStringInfoString(state, "NULL"); break; case JSON_BEHAVIOR_ERROR: deparseAppendStringInfoString(state, "ERROR"); break; case JSON_BEHAVIOR_EMPTY: deparseAppendStringInfoString(state, "EMPTY"); break; case JSON_BEHAVIOR_TRUE: deparseAppendStringInfoString(state, "TRUE"); break; case JSON_BEHAVIOR_FALSE: deparseAppendStringInfoString(state, "FALSE"); break; case JSON_BEHAVIOR_EMPTY_ARRAY: deparseAppendStringInfoString(state, "EMPTY ARRAY"); break; case JSON_BEHAVIOR_EMPTY_OBJECT: deparseAppendStringInfoString(state, "EMPTY OBJECT"); break; case JSON_BEHAVIOR_DEFAULT: deparseAppendStringInfoString(state, "DEFAULT "); deparseExpr(state, (Node*) json_behavior->expr, DEPARSE_NODE_CONTEXT_A_EXPR); break; case JSON_BEHAVIOR_UNKNOWN: deparseAppendStringInfoString(state, "UNKNOWN"); break; } } static void deparseJsonTableColumn(DeparseState *state, JsonTableColumn *json_table_column) { if (json_table_column->coltype == JTC_NESTED) { deparseAppendStringInfoString(state, "NESTED PATH "); deparseJsonTablePathSpec(state, json_table_column->pathspec); deparseJsonTableColumns(state, json_table_column->columns); return; } deparseColLabel(state, json_table_column->name); deparseAppendStringInfoChar(state, ' '); switch (json_table_column->coltype) { case JTC_FOR_ORDINALITY: deparseAppendStringInfoString(state, " FOR ORDINALITY"); break; case JTC_EXISTS: case JTC_FORMATTED: case JTC_REGULAR: deparseTypeName(state, json_table_column->typeName); if (json_table_column->coltype == JTC_EXISTS) deparseAppendStringInfoString(state, " EXISTS "); else deparseAppendStringInfoChar(state, ' '); if (json_table_column->format) deparseJsonFormat(state, json_table_column->format); if (json_table_column->pathspec) { deparseAppendStringInfoString(state, "PATH "); deparseJsonTablePathSpec(state, json_table_column->pathspec); } break; case JTC_NESTED: Assert(false); } switch (json_table_column->wrapper) { case JSW_UNSPEC: break; case JSW_NONE: if (json_table_column->coltype == JTC_REGULAR || json_table_column->coltype == JTC_FORMATTED) deparseAppendStringInfoString(state, " WITHOUT WRAPPER"); break; case JSW_CONDITIONAL: deparseAppendStringInfoString(state, " WITH CONDITIONAL WRAPPER"); break; case JSW_UNCONDITIONAL: deparseAppendStringInfoString(state, " WITH UNCONDITIONAL WRAPPER"); break; } deparseJsonQuotesClauseOpt(state, json_table_column->quotes); deparseJsonOnEmptyClauseOpt(state, json_table_column->on_empty); deparseJsonOnErrorClauseOpt(state, json_table_column->on_error); } static void deparseJsonTableColumns(DeparseState *state, List *json_table_columns) { deparseAppendStringInfoString(state, " COLUMNS ("); ListCell *lc = NULL; foreach(lc, json_table_columns) { deparseJsonTableColumn(state, castNode(JsonTableColumn, lfirst(lc))); if (lnext(json_table_columns, lc)) deparseAppendStringInfoString(state, ", "); } deparseAppendStringInfoChar(state, ')'); } static void deparseJsonTable(DeparseState *state, JsonTable *json_table) { deparseAppendStringInfoString(state, "JSON_TABLE("); deparseJsonValueExpr(state, json_table->context_item); deparseAppendStringInfoString(state, ", "); deparseJsonTablePathSpec(state, json_table->pathspec); if (json_table->passing) deparseAppendStringInfoString(state, " PASSING "); ListCell *lc = NULL; foreach (lc, json_table->passing) { JsonArgument *json_argument = castNode(JsonArgument, lfirst(lc)); deparseJsonValueExpr(state, json_argument->val); deparseAppendStringInfoString(state, " AS "); deparseColLabel(state, json_argument->name); if (lnext(json_table->passing, lc)) deparseAppendStringInfoString(state, ", "); } deparseJsonTableColumns(state, json_table->columns); if (json_table->on_error) { deparseJsonBehavior(state, json_table->on_error); deparseAppendStringInfoString(state, " ON ERROR"); } deparseAppendStringInfoChar(state, ')'); if (json_table->alias) { deparseAppendStringInfoChar(state, ' '); deparseAlias(state, json_table->alias); } } static void deparseGroupingFunc(DeparseState *state, GroupingFunc *grouping_func) { deparseAppendStringInfoString(state, "GROUPING("); deparseExprList(state, grouping_func->args); deparseAppendStringInfoChar(state, ')'); } static void deparseClusterStmt(DeparseState *state, ClusterStmt *cluster_stmt) { deparseAppendStringInfoString(state, "CLUSTER "); deparseUtilityOptionList(state, cluster_stmt->params); if (cluster_stmt->relation != NULL) { deparseRangeVar(state, cluster_stmt->relation, DEPARSE_NODE_CONTEXT_NONE); deparseAppendStringInfoChar(state, ' '); } if (cluster_stmt->indexname != NULL) { deparseAppendStringInfoString(state, "USING "); deparseAppendStringInfoString(state, quote_identifier(cluster_stmt->indexname)); deparseAppendStringInfoChar(state, ' '); } removeTrailingSpace(state); } static void deparseValue(DeparseState *state, union ValUnion *value, DeparseNodeContext context) { if (!value) { deparseAppendStringInfoString(state, "NULL"); return; } switch (nodeTag(value)) { case T_Integer: case T_Float: deparseNumericOnly(state, value); break; case T_Boolean: deparseAppendStringInfoString(state, value->boolval.boolval ? "true" : "false"); break; case T_String: if (context == DEPARSE_NODE_CONTEXT_IDENTIFIER) { deparseAppendStringInfoString(state, quote_identifier(value->sval.sval)); } else if (context == DEPARSE_NODE_CONTEXT_CONSTANT) { deparseStringLiteral(state, value->sval.sval); } else { deparseAppendStringInfoString(state, value->sval.sval); } break; case T_BitString: if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'x') { deparseAppendStringInfoChar(state, 'x'); deparseStringLiteral(state, value->sval.sval + 1); } else if (strlen(value->sval.sval) >= 1 && value->sval.sval[0] == 'b') { deparseAppendStringInfoChar(state, 'b'); deparseStringLiteral(state, 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(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_SelectStmt: deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); break; case T_InsertStmt: deparseInsertStmt(state, castNode(InsertStmt, node)); break; case T_UpdateStmt: deparseUpdateStmt(state, castNode(UpdateStmt, node)); break; case T_DeleteStmt: deparseDeleteStmt(state, castNode(DeleteStmt, node)); break; case T_MergeStmt: deparseMergeStmt(state, castNode(MergeStmt, node)); break; default: Assert(false); } } // "RuleActionStmt" in gram.y static void deparseRuleActionStmt(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_SelectStmt: deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); break; case T_InsertStmt: deparseInsertStmt(state, castNode(InsertStmt, node)); break; case T_UpdateStmt: deparseUpdateStmt(state, castNode(UpdateStmt, node)); break; case T_DeleteStmt: deparseDeleteStmt(state, castNode(DeleteStmt, node)); break; case T_NotifyStmt: deparseNotifyStmt(state, castNode(NotifyStmt, node)); break; default: Assert(false); } } // "ExplainableStmt" in gram.y static void deparseExplainableStmt(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_SelectStmt: deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); break; case T_InsertStmt: deparseInsertStmt(state, castNode(InsertStmt, node)); break; case T_UpdateStmt: deparseUpdateStmt(state, castNode(UpdateStmt, node)); break; case T_DeleteStmt: deparseDeleteStmt(state, castNode(DeleteStmt, node)); break; case T_DeclareCursorStmt: deparseDeclareCursorStmt(state, castNode(DeclareCursorStmt, node)); break; case T_CreateTableAsStmt: deparseCreateTableAsStmt(state, castNode(CreateTableAsStmt, node)); break; case T_RefreshMatViewStmt: deparseRefreshMatViewStmt(state, castNode(RefreshMatViewStmt, node)); break; case T_ExecuteStmt: deparseExecuteStmt(state, castNode(ExecuteStmt, node)); break; case T_MergeStmt: deparseMergeStmt(state, castNode(MergeStmt, node)); break; default: Assert(false); } } // "schema_stmt" in gram.y static void deparseSchemaStmt(DeparseState *state, Node *node) { switch (nodeTag(node)) { case T_CreateStmt: deparseCreateStmt(state, castNode(CreateStmt, node), false); break; case T_IndexStmt: deparseIndexStmt(state, castNode(IndexStmt, node)); break; case T_CreateSeqStmt: deparseCreateSeqStmt(state, castNode(CreateSeqStmt, node)); break; case T_CreateTrigStmt: deparseCreateTrigStmt(state, castNode(CreateTrigStmt, node)); break; case T_GrantStmt: deparseGrantStmt(state, castNode(GrantStmt, node)); break; case T_ViewStmt: deparseViewStmt(state, castNode(ViewStmt, node)); break; default: Assert(false); } } // "stmt" in gram.y static void deparseStmt(DeparseState *state, Node *node) { DeparseStateNestingLevel *parent_level = NULL; // For statements that can be nested, push/pop is handled directly in the // respective deparse...Stmt methods bool skip_push_pop = IsA(node, SelectStmt) || IsA(node, InsertStmt) || IsA(node, UpdateStmt) || IsA(node, DeleteStmt) || IsA(node, MergeStmt); if (!skip_push_pop) parent_level = deparseStateIncreaseNestingLevel(state); // 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(state, castNode(AlterEventTrigStmt, node)); break; case T_AlterCollationStmt: deparseAlterCollationStmt(state, castNode(AlterCollationStmt, node)); break; case T_AlterDatabaseStmt: deparseAlterDatabaseStmt(state, castNode(AlterDatabaseStmt, node)); break; case T_AlterDatabaseSetStmt: deparseAlterDatabaseSetStmt(state, castNode(AlterDatabaseSetStmt, node)); break; case T_AlterDefaultPrivilegesStmt: deparseAlterDefaultPrivilegesStmt(state, castNode(AlterDefaultPrivilegesStmt, node)); break; case T_AlterDomainStmt: deparseAlterDomainStmt(state, castNode(AlterDomainStmt, node)); break; case T_AlterEnumStmt: deparseAlterEnumStmt(state, castNode(AlterEnumStmt, node)); break; case T_AlterExtensionStmt: deparseAlterExtensionStmt(state, castNode(AlterExtensionStmt, node)); break; case T_AlterExtensionContentsStmt: deparseAlterExtensionContentsStmt(state, castNode(AlterExtensionContentsStmt, node)); break; case T_AlterFdwStmt: deparseAlterFdwStmt(state, castNode(AlterFdwStmt, node)); break; case T_AlterForeignServerStmt: deparseAlterForeignServerStmt(state, castNode(AlterForeignServerStmt, node)); break; case T_AlterFunctionStmt: deparseAlterFunctionStmt(state, castNode(AlterFunctionStmt, node)); break; case T_AlterObjectDependsStmt: deparseAlterObjectDependsStmt(state, castNode(AlterObjectDependsStmt, node)); break; case T_AlterObjectSchemaStmt: deparseAlterObjectSchemaStmt(state, castNode(AlterObjectSchemaStmt, node)); break; case T_AlterOwnerStmt: deparseAlterOwnerStmt(state, castNode(AlterOwnerStmt, node)); break; case T_AlterOperatorStmt: deparseAlterOperatorStmt(state, castNode(AlterOperatorStmt, node)); break; case T_AlterTypeStmt: deparseAlterTypeStmt(state, castNode(AlterTypeStmt, node)); break; case T_AlterPolicyStmt: deparseAlterPolicyStmt(state, castNode(AlterPolicyStmt, node)); break; case T_AlterSeqStmt: deparseAlterSeqStmt(state, castNode(AlterSeqStmt, node)); break; case T_AlterSystemStmt: deparseAlterSystemStmt(state, castNode(AlterSystemStmt, node)); break; case T_AlterTableMoveAllStmt: deparseAlterTableMoveAllStmt(state, castNode(AlterTableMoveAllStmt, node)); break; case T_AlterTableStmt: deparseAlterTableStmt(state, castNode(AlterTableStmt, node)); break; case T_AlterTableSpaceOptionsStmt: // "AlterTblSpcStmt" in gram.y deparseAlterTableSpaceOptionsStmt(state, castNode(AlterTableSpaceOptionsStmt, node)); break; case T_AlterPublicationStmt: deparseAlterPublicationStmt(state, castNode(AlterPublicationStmt, node)); break; case T_AlterRoleSetStmt: deparseAlterRoleSetStmt(state, castNode(AlterRoleSetStmt, node)); break; case T_AlterRoleStmt: deparseAlterRoleStmt(state, castNode(AlterRoleStmt, node)); break; case T_AlterSubscriptionStmt: deparseAlterSubscriptionStmt(state, castNode(AlterSubscriptionStmt, node)); break; case T_AlterStatsStmt: deparseAlterStatsStmt(state, castNode(AlterStatsStmt, node)); break; case T_AlterTSConfigurationStmt: deparseAlterTSConfigurationStmt(state, castNode(AlterTSConfigurationStmt, node)); break; case T_AlterTSDictionaryStmt: deparseAlterTSDictionaryStmt(state, castNode(AlterTSDictionaryStmt, node)); break; case T_AlterUserMappingStmt: deparseAlterUserMappingStmt(state, castNode(AlterUserMappingStmt, node)); break; case T_CallStmt: deparseCallStmt(state, castNode(CallStmt, node)); break; case T_CheckPointStmt: deparseCheckPointStmt(state, castNode(CheckPointStmt, node)); break; case T_ClosePortalStmt: deparseClosePortalStmt(state, castNode(ClosePortalStmt, node)); break; case T_ClusterStmt: deparseClusterStmt(state, castNode(ClusterStmt, node)); break; case T_CommentStmt: deparseCommentStmt(state, castNode(CommentStmt, node)); break; case T_ConstraintsSetStmt: deparseConstraintsSetStmt(state, castNode(ConstraintsSetStmt, node)); break; case T_CopyStmt: deparseCopyStmt(state, castNode(CopyStmt, node)); break; case T_CreateAmStmt: deparseCreateAmStmt(state, castNode(CreateAmStmt, node)); break; case T_CreateTableAsStmt: // "CreateAsStmt" in gram.y deparseCreateTableAsStmt(state, castNode(CreateTableAsStmt, node)); break; case T_CreateCastStmt: deparseCreateCastStmt(state, castNode(CreateCastStmt, node)); break; case T_CreateConversionStmt: deparseCreateConversionStmt(state, castNode(CreateConversionStmt, node)); break; case T_CreateDomainStmt: deparseCreateDomainStmt(state, castNode(CreateDomainStmt, node)); break; case T_CreateExtensionStmt: deparseCreateExtensionStmt(state, castNode(CreateExtensionStmt, node)); break; case T_CreateFdwStmt: deparseCreateFdwStmt(state, castNode(CreateFdwStmt, node)); break; case T_CreateForeignServerStmt: deparseCreateForeignServerStmt(state, castNode(CreateForeignServerStmt, node)); break; case T_CreateForeignTableStmt: deparseCreateForeignTableStmt(state, castNode(CreateForeignTableStmt, node)); break; case T_CreateFunctionStmt: deparseCreateFunctionStmt(state, castNode(CreateFunctionStmt, node)); break; case T_CreateOpClassStmt: deparseCreateOpClassStmt(state, castNode(CreateOpClassStmt, node)); break; case T_CreateOpFamilyStmt: deparseCreateOpFamilyStmt(state, castNode(CreateOpFamilyStmt, node)); break; case T_CreatePublicationStmt: deparseCreatePublicationStmt(state, castNode(CreatePublicationStmt, node)); break; case T_AlterOpFamilyStmt: deparseAlterOpFamilyStmt(state, castNode(AlterOpFamilyStmt, node)); break; case T_CreatePolicyStmt: deparseCreatePolicyStmt(state, castNode(CreatePolicyStmt, node)); break; case T_CreatePLangStmt: deparseCreatePLangStmt(state, castNode(CreatePLangStmt, node)); break; case T_CreateSchemaStmt: deparseCreateSchemaStmt(state, castNode(CreateSchemaStmt, node)); break; case T_CreateSeqStmt: deparseCreateSeqStmt(state, castNode(CreateSeqStmt, node)); break; case T_CreateStmt: deparseCreateStmt(state, castNode(CreateStmt, node), false); break; case T_CreateSubscriptionStmt: deparseCreateSubscriptionStmt(state, castNode(CreateSubscriptionStmt, node)); break; case T_CreateStatsStmt: deparseCreateStatsStmt(state, castNode(CreateStatsStmt, node)); break; case T_CreateTableSpaceStmt: deparseCreateTableSpaceStmt(state, castNode(CreateTableSpaceStmt, node)); break; case T_CreateTransformStmt: deparseCreateTransformStmt(state, castNode(CreateTransformStmt, node)); break; case T_CreateTrigStmt: deparseCreateTrigStmt(state, castNode(CreateTrigStmt, node)); break; case T_CreateEventTrigStmt: deparseCreateEventTrigStmt(state, castNode(CreateEventTrigStmt, node)); break; case T_CreateRoleStmt: deparseCreateRoleStmt(state, castNode(CreateRoleStmt, node)); break; case T_CreateUserMappingStmt: deparseCreateUserMappingStmt(state, castNode(CreateUserMappingStmt, node)); break; case T_CreatedbStmt: deparseCreatedbStmt(state, castNode(CreatedbStmt, node)); break; case T_DeallocateStmt: deparseDeallocateStmt(state, castNode(DeallocateStmt, node)); break; case T_DeclareCursorStmt: deparseDeclareCursorStmt(state, castNode(DeclareCursorStmt, node)); break; case T_DefineStmt: deparseDefineStmt(state, castNode(DefineStmt, node)); break; case T_DeleteStmt: deparseDeleteStmt(state, castNode(DeleteStmt, node)); break; case T_DiscardStmt: deparseDiscardStmt(state, castNode(DiscardStmt, node)); break; case T_DoStmt: deparseDoStmt(state, castNode(DoStmt, node)); break; case T_DropOwnedStmt: deparseDropOwnedStmt(state, castNode(DropOwnedStmt, node)); break; case T_DropStmt: deparseDropStmt(state, castNode(DropStmt, node)); break; case T_DropSubscriptionStmt: deparseDropSubscriptionStmt(state, castNode(DropSubscriptionStmt, node)); break; case T_DropTableSpaceStmt: deparseDropTableSpaceStmt(state, castNode(DropTableSpaceStmt, node)); break; case T_DropRoleStmt: deparseDropRoleStmt(state, castNode(DropRoleStmt, node)); break; case T_DropUserMappingStmt: deparseDropUserMappingStmt(state, castNode(DropUserMappingStmt, node)); break; case T_DropdbStmt: deparseDropdbStmt(state, castNode(DropdbStmt, node)); break; case T_ExecuteStmt: deparseExecuteStmt(state, castNode(ExecuteStmt, node)); break; case T_ExplainStmt: deparseExplainStmt(state, castNode(ExplainStmt, node)); break; case T_FetchStmt: deparseFetchStmt(state, castNode(FetchStmt, node)); break; case T_GrantStmt: deparseGrantStmt(state, castNode(GrantStmt, node)); break; case T_GrantRoleStmt: deparseGrantRoleStmt(state, castNode(GrantRoleStmt, node)); break; case T_ImportForeignSchemaStmt: deparseImportForeignSchemaStmt(state, castNode(ImportForeignSchemaStmt, node)); break; case T_IndexStmt: deparseIndexStmt(state, castNode(IndexStmt, node)); break; case T_InsertStmt: deparseInsertStmt(state, castNode(InsertStmt, node)); break; case T_ListenStmt: deparseListenStmt(state, castNode(ListenStmt, node)); break; case T_RefreshMatViewStmt: deparseRefreshMatViewStmt(state, castNode(RefreshMatViewStmt, node)); break; case T_LoadStmt: deparseLoadStmt(state, castNode(LoadStmt, node)); break; case T_LockStmt: deparseLockStmt(state, castNode(LockStmt, node)); break; case T_MergeStmt: deparseMergeStmt(state, castNode(MergeStmt, node)); break; case T_NotifyStmt: deparseNotifyStmt(state, castNode(NotifyStmt, node)); break; case T_PrepareStmt: deparsePrepareStmt(state, castNode(PrepareStmt, node)); break; case T_ReassignOwnedStmt: deparseReassignOwnedStmt(state, castNode(ReassignOwnedStmt, node)); break; case T_ReindexStmt: deparseReindexStmt(state, castNode(ReindexStmt, node)); break; case T_RenameStmt: deparseRenameStmt(state, castNode(RenameStmt, node)); break; case T_RuleStmt: deparseRuleStmt(state, castNode(RuleStmt, node)); break; case T_SecLabelStmt: deparseSecLabelStmt(state, castNode(SecLabelStmt, node)); break; case T_SelectStmt: deparseSelectStmt(state, castNode(SelectStmt, node), DEPARSE_NODE_CONTEXT_NONE); break; case T_TransactionStmt: deparseTransactionStmt(state, castNode(TransactionStmt, node)); break; case T_TruncateStmt: deparseTruncateStmt(state, castNode(TruncateStmt, node)); break; case T_UnlistenStmt: deparseUnlistenStmt(state, castNode(UnlistenStmt, node)); break; case T_UpdateStmt: deparseUpdateStmt(state, castNode(UpdateStmt, node)); break; case T_VacuumStmt: deparseVacuumStmt(state, castNode(VacuumStmt, node)); break; case T_VariableSetStmt: deparseVariableSetStmt(state, castNode(VariableSetStmt, node)); break; case T_VariableShowStmt: deparseVariableShowStmt(state, castNode(VariableShowStmt, node)); break; case T_ViewStmt: deparseViewStmt(state, castNode(ViewStmt, node)); break; // These node types are created by DefineStmt grammar for CREATE TYPE in some cases case T_CompositeTypeStmt: deparseCompositeTypeStmt(state, castNode(CompositeTypeStmt, node)); break; case T_CreateEnumStmt: deparseCreateEnumStmt(state, castNode(CreateEnumStmt, node)); break; case T_CreateRangeStmt: deparseCreateRangeStmt(state, castNode(CreateRangeStmt, node)); break; default: elog(ERROR, "deparse: unsupported top-level node type: %u", nodeTag(node)); } if (!skip_push_pop) deparseStateDecreaseNestingLevel(state, parent_level); }