From ca49e5e96fcab75c8e19a42d701b16ac96ee9d43 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Tue, 29 Jun 2021 00:07:04 +0800 Subject: [PATCH v4] Add a pg_get_query_def() wrapper around get_query_def(). This function can be useful for external modules, for instance if they want to display a statement after the rewrite stage. In order to emit valid SQL, make sure that any subquery RTE comes with an alias. This is always the case for user facing queries, as the parser will refuse a subquery without an alias, but that may not be the case for a Query after rewriting for instance. Catversion is bumped. Author: Julien Rouhaud Reviewed-by: Pavel Stehule Discussion: https://postgr.es/m/20210627041138.zklczwmu3ms4ufnk@nol --- src/backend/utils/adt/ruleutils.c | 49 ++++++++++++++++++++++++------- src/include/utils/ruleutils.h | 2 ++ 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 7f4f3f7369..c9a1dde65f 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -90,6 +90,8 @@ #define PRETTYFLAG_INDENT 0x0002 #define PRETTYFLAG_SCHEMA 0x0004 +#define GET_PRETTY_FLAGS(pretty) ((pretty) ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT) + /* Default line length for pretty-print wrapping: 0 means wrap always */ #define WRAP_COLUMN_DEFAULT 0 @@ -526,7 +528,7 @@ pg_get_ruledef_ext(PG_FUNCTION_ARGS) int prettyFlags; char *res; - prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; + prettyFlags = GET_PRETTY_FLAGS(pretty); res = pg_get_ruledef_worker(ruleoid, prettyFlags); @@ -647,7 +649,7 @@ pg_get_viewdef_ext(PG_FUNCTION_ARGS) int prettyFlags; char *res; - prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; + prettyFlags = GET_PRETTY_FLAGS(pretty); res = pg_get_viewdef_worker(viewoid, prettyFlags, WRAP_COLUMN_DEFAULT); @@ -667,7 +669,7 @@ pg_get_viewdef_wrap(PG_FUNCTION_ARGS) char *res; /* calling this implies we want pretty printing */ - prettyFlags = PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA; + prettyFlags = GET_PRETTY_FLAGS(true); res = pg_get_viewdef_worker(viewoid, prettyFlags, wrap); @@ -713,7 +715,7 @@ pg_get_viewdef_name_ext(PG_FUNCTION_ARGS) Oid viewoid; char *res; - prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; + prettyFlags = GET_PRETTY_FLAGS(pretty); /* Look up view name. Can't lock it - we might not have privileges. */ viewrel = makeRangeVarFromNameList(textToQualifiedNameList(viewname)); @@ -1056,7 +1058,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty) context.windowClause = NIL; context.windowTList = NIL; context.varprefix = true; - context.prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; + context.prettyFlags = GET_PRETTY_FLAGS(pretty); context.wrapColumn = WRAP_COLUMN_DEFAULT; context.indentLevel = PRETTYINDENT_STD; context.special_exprkind = EXPR_KIND_NONE; @@ -1146,7 +1148,7 @@ pg_get_indexdef_ext(PG_FUNCTION_ARGS) int prettyFlags; char *res; - prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; + prettyFlags = GET_PRETTY_FLAGS(pretty); res = pg_get_indexdef_worker(indexrelid, colno, NULL, colno != 0, false, @@ -1179,7 +1181,7 @@ pg_get_indexdef_columns(Oid indexrelid, bool pretty) { int prettyFlags; - prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; + prettyFlags = GET_PRETTY_FLAGS(pretty); return pg_get_indexdef_worker(indexrelid, 0, NULL, true, true, @@ -1187,6 +1189,23 @@ pg_get_indexdef_columns(Oid indexrelid, bool pretty) prettyFlags, false); } +/* Public wraper around get_query_def */ +char * +pg_get_querydef(Query *query, bool pretty, int wrapColumn, int startIndent) +{ + StringInfoData buf; + int prettyFlags; + + prettyFlags = GET_PRETTY_FLAGS(pretty); + + initStringInfo(&buf); + + get_query_def(query, &buf, NIL, NULL, prettyFlags, wrapColumn, + startIndent); + + return buf.data; +} + /* * Internal workhorse to decompile an index definition. * @@ -1842,7 +1861,7 @@ pg_get_partkeydef_columns(Oid relid, bool pretty) { int prettyFlags; - prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; + prettyFlags = GET_PRETTY_FLAGS(pretty); return pg_get_partkeydef_worker(relid, prettyFlags, true, false); } @@ -2089,7 +2108,7 @@ pg_get_constraintdef_ext(PG_FUNCTION_ARGS) int prettyFlags; char *res; - prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; + prettyFlags = GET_PRETTY_FLAGS(pretty); res = pg_get_constraintdef_worker(constraintId, false, prettyFlags, true); @@ -2619,7 +2638,7 @@ pg_get_expr_ext(PG_FUNCTION_ARGS) int prettyFlags; char *relname; - prettyFlags = pretty ? (PRETTYFLAG_PAREN | PRETTYFLAG_INDENT | PRETTYFLAG_SCHEMA) : PRETTYFLAG_INDENT; + prettyFlags = GET_PRETTY_FLAGS(pretty); if (OidIsValid(relid)) { @@ -11002,6 +11021,16 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context) if (strcmp(refname, rte->ctename) != 0) printalias = true; } + else if (rte->rtekind == RTE_SUBQUERY) + { + /* + * For a subquery RTE, always print alias. A user-specified query + * should only be valid if an alias is provided, but our view + * expansion doesn't generate aliases, so a rewritten query might + * not be valid SQL. + */ + printalias = true; + } if (printalias) appendStringInfo(buf, " %s", quote_identifier(refname)); diff --git a/src/include/utils/ruleutils.h b/src/include/utils/ruleutils.h index e8090c96d7..b3767a0497 100644 --- a/src/include/utils/ruleutils.h +++ b/src/include/utils/ruleutils.h @@ -23,6 +23,8 @@ struct PlannedStmt; extern char *pg_get_indexdef_string(Oid indexrelid); extern char *pg_get_indexdef_columns(Oid indexrelid, bool pretty); +extern char *pg_get_querydef(Query *query, bool pretty, int wrapColumn, + int startIndent); extern char *pg_get_partkeydef_columns(Oid relid, bool pretty); extern char *pg_get_partconstrdef_string(Oid partitionId, char *aliasname); -- 2.33.1