aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/ruleutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r--src/backend/utils/adt/ruleutils.c275
1 files changed, 260 insertions, 15 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 4a98b82f07c..5f953338f3d 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -457,9 +457,15 @@ static void get_func_expr(FuncExpr *expr, deparse_context *context,
bool showimplicit);
static void get_agg_expr(Aggref *aggref, deparse_context *context,
Aggref *original_aggref);
+static void get_agg_expr_helper(Aggref *aggref, deparse_context *context,
+ Aggref *original_aggref, const char *funcname,
+ const char *options, bool is_json_objectagg);
static void get_agg_combine_expr(Node *node, deparse_context *context,
void *callback_arg);
static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
+static void get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
+ const char *funcname, const char *options,
+ bool is_json_objectagg);
static bool get_func_sql_syntax(FuncExpr *expr, deparse_context *context);
static void get_coercion_expr(Node *arg, deparse_context *context,
Oid resulttype, int32 resulttypmod,
@@ -467,6 +473,15 @@ static void get_coercion_expr(Node *arg, deparse_context *context,
static void get_const_expr(Const *constval, deparse_context *context,
int showtype);
static void get_const_collation(Const *constval, deparse_context *context);
+static void get_json_format(JsonFormat *format, StringInfo buf);
+static void get_json_constructor(JsonConstructorExpr *ctor,
+ deparse_context *context, bool showimplicit);
+static void get_json_constructor_options(JsonConstructorExpr *ctor,
+ StringInfo buf);
+static void get_json_agg_constructor(JsonConstructorExpr *ctor,
+ deparse_context *context,
+ const char *funcname,
+ bool is_json_objectagg);
static void simple_quote_literal(StringInfo buf, const char *val);
static void get_sublink_expr(SubLink *sublink, deparse_context *context);
static void get_tablefunc(TableFunc *tf, deparse_context *context,
@@ -6280,7 +6295,8 @@ get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno,
bool need_paren = (PRETTY_PAREN(context)
|| IsA(expr, FuncExpr)
|| IsA(expr, Aggref)
- || IsA(expr, WindowFunc));
+ || IsA(expr, WindowFunc)
+ || IsA(expr, JsonConstructorExpr));
if (need_paren)
appendStringInfoChar(context->buf, '(');
@@ -8117,6 +8133,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_GroupingFunc:
case T_WindowFunc:
case T_FuncExpr:
+ case T_JsonConstructorExpr:
/* function-like: name(..) or name[..] */
return true;
@@ -8292,6 +8309,11 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
return false;
}
+ case T_JsonValueExpr:
+ /* maybe simple, check args */
+ return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
+ node, prettyFlags);
+
default:
break;
}
@@ -9495,6 +9517,19 @@ get_rule_expr(Node *node, deparse_context *context,
}
break;
+ case T_JsonValueExpr:
+ {
+ JsonValueExpr *jve = (JsonValueExpr *) node;
+
+ get_rule_expr((Node *) jve->raw_expr, context, false);
+ get_json_format(jve->format, context->buf);
+ }
+ break;
+
+ case T_JsonConstructorExpr:
+ get_json_constructor((JsonConstructorExpr *) node, context, false);
+ break;
+
case T_List:
{
char *sep;
@@ -9769,10 +9804,23 @@ static void
get_agg_expr(Aggref *aggref, deparse_context *context,
Aggref *original_aggref)
{
+ get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
+ false);
+}
+
+/*
+ * get_agg_expr_helper - subroutine for get_agg_expr and
+ * get_json_agg_constructor
+ */
+static void
+get_agg_expr_helper(Aggref *aggref, deparse_context *context,
+ Aggref *original_aggref, const char *funcname,
+ const char *options, bool is_json_objectagg)
+{
StringInfo buf = context->buf;
Oid argtypes[FUNC_MAX_ARGS];
int nargs;
- bool use_variadic;
+ bool use_variadic = false;
/*
* For a combining aggregate, we look up and deparse the corresponding
@@ -9802,13 +9850,14 @@ get_agg_expr(Aggref *aggref, deparse_context *context,
/* Extract the argument types as seen by the parser */
nargs = get_aggregate_argtypes(aggref, argtypes);
+ if (!funcname)
+ funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
+ argtypes, aggref->aggvariadic,
+ &use_variadic,
+ context->special_exprkind);
+
/* Print the aggregate name, schema-qualified if needed */
- appendStringInfo(buf, "%s(%s",
- generate_function_name(aggref->aggfnoid, nargs,
- NIL, argtypes,
- aggref->aggvariadic,
- &use_variadic,
- context->special_exprkind),
+ appendStringInfo(buf, "%s(%s", funcname,
(aggref->aggdistinct != NIL) ? "DISTINCT " : "");
if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
@@ -9844,7 +9893,21 @@ get_agg_expr(Aggref *aggref, deparse_context *context,
if (tle->resjunk)
continue;
if (i++ > 0)
- appendStringInfoString(buf, ", ");
+ {
+ if (is_json_objectagg)
+ {
+ /*
+ * the ABSENT ON NULL and WITH UNIQUE args are printed
+ * separately, so ignore them here
+ */
+ if (i > 2)
+ break;
+
+ appendStringInfoString(buf, " : ");
+ }
+ else
+ appendStringInfoString(buf, ", ");
+ }
if (use_variadic && i == nargs)
appendStringInfoString(buf, "VARIADIC ");
get_rule_expr(arg, context, true);
@@ -9858,6 +9921,9 @@ get_agg_expr(Aggref *aggref, deparse_context *context,
}
}
+ if (options)
+ appendStringInfoString(buf, options);
+
if (aggref->aggfilter != NULL)
{
appendStringInfoString(buf, ") FILTER (WHERE ");
@@ -9891,6 +9957,19 @@ get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
static void
get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
{
+ get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
+}
+
+
+/*
+ * get_windowfunc_expr_helper - subroutine for get_windowfunc_expr and
+ * get_json_agg_constructor
+ */
+static void
+get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
+ const char *funcname, const char *options,
+ bool is_json_objectagg)
+{
StringInfo buf = context->buf;
Oid argtypes[FUNC_MAX_ARGS];
int nargs;
@@ -9913,16 +9992,30 @@ get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
nargs++;
}
- appendStringInfo(buf, "%s(",
- generate_function_name(wfunc->winfnoid, nargs,
- argnames, argtypes,
- false, NULL,
- context->special_exprkind));
+ if (!funcname)
+ funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
+ argtypes, false, NULL,
+ context->special_exprkind);
+
+ appendStringInfo(buf, "%s(", funcname);
+
/* winstar can be set only in zero-argument aggregates */
if (wfunc->winstar)
appendStringInfoChar(buf, '*');
else
- get_rule_expr((Node *) wfunc->args, context, true);
+ {
+ if (is_json_objectagg)
+ {
+ get_rule_expr((Node *) linitial(wfunc->args), context, false);
+ appendStringInfoString(buf, " : ");
+ get_rule_expr((Node *) lsecond(wfunc->args), context, false);
+ }
+ else
+ get_rule_expr((Node *) wfunc->args, context, true);
+ }
+
+ if (options)
+ appendStringInfoString(buf, options);
if (wfunc->aggfilter != NULL)
{
@@ -10484,6 +10577,158 @@ get_const_collation(Const *constval, deparse_context *context)
}
/*
+ * get_json_format - Parse back a JsonFormat node
+ */
+static void
+get_json_format(JsonFormat *format, StringInfo buf)
+{
+ if (format->format_type == JS_FORMAT_DEFAULT)
+ return;
+
+ appendStringInfoString(buf,
+ format->format_type == JS_FORMAT_JSONB ?
+ " FORMAT JSONB" : " FORMAT JSON");
+
+ if (format->encoding != JS_ENC_DEFAULT)
+ {
+ const char *encoding;
+
+ encoding =
+ format->encoding == JS_ENC_UTF16 ? "UTF16" :
+ format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
+
+ appendStringInfo(buf, " ENCODING %s", encoding);
+ }
+}
+
+/*
+ * get_json_returning - Parse back a JsonReturning structure
+ */
+static void
+get_json_returning(JsonReturning *returning, StringInfo buf,
+ bool json_format_by_default)
+{
+ if (!OidIsValid(returning->typid))
+ return;
+
+ appendStringInfo(buf, " RETURNING %s",
+ format_type_with_typemod(returning->typid,
+ returning->typmod));
+
+ if (!json_format_by_default ||
+ returning->format->format_type !=
+ (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
+ get_json_format(returning->format, buf);
+}
+
+/*
+ * get_json_constructor - Parse back a JsonConstructorExpr node
+ */
+static void
+get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context,
+ bool showimplicit)
+{
+ StringInfo buf = context->buf;
+ const char *funcname;
+ bool is_json_object;
+ int curridx;
+ ListCell *lc;
+
+ if (ctor->type == JSCTOR_JSON_OBJECTAGG)
+ {
+ get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
+ return;
+ }
+ else if (ctor->type == JSCTOR_JSON_ARRAYAGG)
+ {
+ get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
+ return;
+ }
+
+ switch (ctor->type)
+ {
+ case JSCTOR_JSON_OBJECT:
+ funcname = "JSON_OBJECT";
+ break;
+ case JSCTOR_JSON_ARRAY:
+ funcname = "JSON_ARRAY";
+ break;
+ default:
+ elog(ERROR, "invalid JsonConstructorExprType %d", ctor->type);
+ }
+
+ appendStringInfo(buf, "%s(", funcname);
+
+ is_json_object = ctor->type == JSCTOR_JSON_OBJECT;
+ foreach(lc, ctor->args)
+ {
+ curridx = foreach_current_index(lc);
+ if (curridx > 0)
+ {
+ const char *sep;
+
+ sep = (is_json_object && (curridx % 2) != 0) ? " : " : ", ";
+ appendStringInfoString(buf, sep);
+ }
+
+ get_rule_expr((Node *) lfirst(lc), context, true);
+ }
+
+ get_json_constructor_options(ctor, buf);
+ appendStringInfo(buf, ")");
+}
+
+/*
+ * Append options, if any, to the JSON constructor being deparsed
+ */
+static void
+get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
+{
+ if (ctor->absent_on_null)
+ {
+ if (ctor->type == JSCTOR_JSON_OBJECT ||
+ ctor->type == JSCTOR_JSON_OBJECTAGG)
+ appendStringInfoString(buf, " ABSENT ON NULL");
+ }
+ else
+ {
+ if (ctor->type == JSCTOR_JSON_ARRAY ||
+ ctor->type == JSCTOR_JSON_ARRAYAGG)
+ appendStringInfoString(buf, " NULL ON NULL");
+ }
+
+ if (ctor->unique)
+ appendStringInfoString(buf, " WITH UNIQUE KEYS");
+
+ get_json_returning(ctor->returning, buf, true);
+}
+
+/*
+ * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node
+ */
+static void
+get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context,
+ const char *funcname, bool is_json_objectagg)
+{
+ StringInfoData options;
+
+ initStringInfo(&options);
+ get_json_constructor_options(ctor, &options);
+
+ if (IsA(ctor->func, Aggref))
+ get_agg_expr_helper((Aggref *) ctor->func, context,
+ (Aggref *) ctor->func,
+ funcname, options.data, is_json_objectagg);
+ else if (IsA(ctor->func, WindowFunc))
+ get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
+ funcname, options.data,
+ is_json_objectagg);
+ else
+ elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
+ nodeTag(ctor->func));
+}
+
+/*
* simple_quote_literal - Format a string as a SQL literal, append to buf
*/
static void