Adds JSON table functions in ruleutils_15.c

Relevant PG commit:
4e34747c88a03ede6e9d731727815e37273d4bc9
boolean_node
naisila 2022-07-25 16:33:47 +03:00
parent c71d940093
commit abb198b757
1 changed files with 223 additions and 5 deletions

View File

@ -462,6 +462,8 @@ static char *generate_function_name(Oid funcid, int nargs,
ParseExprKind special_exprkind);
static void get_json_path_spec(Node *path_spec, deparse_context *context,
bool showimplicit);
static void get_json_table_columns(TableFunc *tf, JsonTableParent *node,
deparse_context *context, bool showimplicit);
#define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
@ -5239,7 +5241,8 @@ get_json_behavior(JsonBehavior *behavior, deparse_context *context,
/*
* get_json_expr_options
*
* Parse back common options for JSON_QUERY, JSON_VALUE, JSON_EXISTS.
* Parse back common options for JSON_QUERY, JSON_VALUE, JSON_EXISTS and
* JSON_TABLE columns.
*/
static void
get_json_expr_options(JsonExpr *jsexpr, deparse_context *context,
@ -6507,6 +6510,9 @@ get_rule_expr(Node *node, deparse_context *context,
case JSON_EXISTS_OP:
appendStringInfoString(buf, "JSON_EXISTS(");
break;
default:
elog(ERROR, "unexpected JsonExpr type: %d", jexpr->op);
break;
}
get_rule_expr(jexpr->formatted_expr, context, showimplicit);
@ -7830,16 +7836,14 @@ get_sublink_expr(SubLink *sublink, deparse_context *context)
/* ----------
* get_tablefunc - Parse back a table function
* get_xmltable - Parse back a XMLTABLE function
* ----------
*/
static void
get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
{
StringInfo buf = context->buf;
/* XMLTABLE is the only existing implementation. */
appendStringInfoString(buf, "XMLTABLE(");
if (tf->ns_uris != NIL)
@ -7930,6 +7934,220 @@ get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
appendStringInfoChar(buf, ')');
}
/*
* get_json_nested_columns - Parse back nested JSON_TABLE columns
*/
static void
get_json_table_nested_columns(TableFunc *tf, Node *node,
deparse_context *context, bool showimplicit,
bool needcomma)
{
if (IsA(node, JsonTableSibling))
{
JsonTableSibling *n = (JsonTableSibling *) node;
get_json_table_nested_columns(tf, n->larg, context, showimplicit,
needcomma);
get_json_table_nested_columns(tf, n->rarg, context, showimplicit, true);
}
else
{
JsonTableParent *n = castNode(JsonTableParent, node);
if (needcomma)
appendStringInfoChar(context->buf, ',');
appendStringInfoChar(context->buf, ' ');
appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
get_const_expr(n->path, context, -1);
get_json_table_columns(tf, n, context, showimplicit);
}
}
/*
* get_json_table_columns - Parse back JSON_TABLE columns
*/
static void
get_json_table_columns(TableFunc *tf, JsonTableParent *node,
deparse_context *context, bool showimplicit)
{
StringInfo buf = context->buf;
JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
ListCell *lc_colname;
ListCell *lc_coltype;
ListCell *lc_coltypmod;
ListCell *lc_colvarexpr;
int colnum = 0;
appendStringInfoChar(buf, ' ');
appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
if (PRETTY_INDENT(context))
context->indentLevel += PRETTYINDENT_VAR;
forfour(lc_colname, tf->colnames,
lc_coltype, tf->coltypes,
lc_coltypmod, tf->coltypmods,
lc_colvarexpr, tf->colvalexprs)
{
char *colname = strVal(lfirst(lc_colname));
JsonExpr *colexpr;
Oid typid;
int32 typmod;
bool ordinality;
JsonBehaviorType default_behavior;
typid = lfirst_oid(lc_coltype);
typmod = lfirst_int(lc_coltypmod);
colexpr = castNode(JsonExpr, lfirst(lc_colvarexpr));
if (colnum < node->colMin)
{
colnum++;
continue;
}
if (colnum > node->colMax)
break;
if (colnum > node->colMin)
appendStringInfoString(buf, ", ");
colnum++;
ordinality = !colexpr;
appendContextKeyword(context, "", 0, 0, 0);
appendStringInfo(buf, "%s %s", quote_identifier(colname),
ordinality ? "FOR ORDINALITY" :
format_type_with_typemod(typid, typmod));
if (ordinality)
continue;
if (colexpr->op == JSON_EXISTS_OP)
{
appendStringInfoString(buf, " EXISTS");
default_behavior = JSON_BEHAVIOR_FALSE;
}
else
{
if (colexpr->op == JSON_QUERY_OP)
{
char typcategory;
bool typispreferred;
get_type_category_preferred(typid, &typcategory, &typispreferred);
if (typcategory == TYPCATEGORY_STRING)
appendStringInfoString(buf,
colexpr->format->format_type == JS_FORMAT_JSONB ?
" FORMAT JSONB" : " FORMAT JSON");
}
default_behavior = JSON_BEHAVIOR_NULL;
}
if (jexpr->on_error->btype == JSON_BEHAVIOR_ERROR)
default_behavior = JSON_BEHAVIOR_ERROR;
appendStringInfoString(buf, " PATH ");
get_json_path_spec(colexpr->path_spec, context, showimplicit);
get_json_expr_options(colexpr, context, default_behavior);
}
if (node->child)
get_json_table_nested_columns(tf, node->child, context, showimplicit,
node->colMax >= node->colMin);
if (PRETTY_INDENT(context))
context->indentLevel -= PRETTYINDENT_VAR;
appendContextKeyword(context, ")", 0, 0, 0);
}
/* ----------
* get_json_table - Parse back a JSON_TABLE function
* ----------
*/
static void
get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
{
StringInfo buf = context->buf;
JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
JsonTableParent *root = castNode(JsonTableParent, tf->plan);
appendStringInfoString(buf, "JSON_TABLE(");
if (PRETTY_INDENT(context))
context->indentLevel += PRETTYINDENT_VAR;
appendContextKeyword(context, "", 0, 0, 0);
get_rule_expr(jexpr->formatted_expr, context, showimplicit);
appendStringInfoString(buf, ", ");
get_const_expr(root->path, context, -1);
if (jexpr->passing_values)
{
ListCell *lc1, *lc2;
bool needcomma = false;
appendStringInfoChar(buf, ' ');
appendContextKeyword(context, "PASSING ", 0, 0, 0);
if (PRETTY_INDENT(context))
context->indentLevel += PRETTYINDENT_VAR;
forboth(lc1, jexpr->passing_names,
lc2, jexpr->passing_values)
{
if (needcomma)
appendStringInfoString(buf, ", ");
needcomma = true;
appendContextKeyword(context, "", 0, 0, 0);
get_rule_expr((Node *) lfirst(lc2), context, false);
appendStringInfo(buf, " AS %s",
quote_identifier((lfirst_node(String, lc1))->sval)
);
}
if (PRETTY_INDENT(context))
context->indentLevel -= PRETTYINDENT_VAR;
}
get_json_table_columns(tf, root, context, showimplicit);
if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY)
get_json_behavior(jexpr->on_error, context, "ERROR");
if (PRETTY_INDENT(context))
context->indentLevel -= PRETTYINDENT_VAR;
appendContextKeyword(context, ")", 0, 0, 0);
}
/* ----------
* get_tablefunc - Parse back a table function
* ----------
*/
static void
get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
{
/* XMLTABLE and JSON_TABLE are the only existing implementations. */
if (tf->functype == TFT_XMLTABLE)
get_xmltable(tf, context, showimplicit);
else if (tf->functype == TFT_JSON_TABLE)
get_json_table(tf, context, showimplicit);
}
/* ----------
* get_from_clause - Parse back a FROM clause
*