1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +03:00

SQL/JSON constructors

This patch introduces the SQL/JSON standard constructors for JSON:

JSON()
JSON_ARRAY()
JSON_ARRAYAGG()
JSON_OBJECT()
JSON_OBJECTAGG()

For the most part these functions provide facilities that mimic
existing json/jsonb functions. However, they also offer some useful
additional functionality. In addition to text input, the JSON() function
accepts bytea input, which it will decode and constuct a json value from.
The other functions provide useful options for handling duplicate keys
and null values.

This series of patches will be followed by a consolidated documentation
patch.

Nikita Glukhov

Reviewers have included (in no particular order) Andres Freund, Alexander
Korotkov, Pavel Stehule, Andrew Alsup, Erik Rijkers, Zihong Yu,
Himanshu Upadhyaya, Daniel Gustafsson, Justin Pryzby.

Discussion: https://postgr.es/m/cd0bb935-0158-78a7-08b5-904886deac4b@postgrespro.ru
This commit is contained in:
Andrew Dunstan
2022-03-03 13:02:10 -05:00
parent f79b803dcc
commit f4fb45d15c
37 changed files with 3615 additions and 130 deletions

View File

@@ -2344,6 +2344,152 @@ _copyJsonValueExpr(const JsonValueExpr *from)
return newnode;
}
/*
* _copyJsonConstructorExpr
*/
static JsonConstructorExpr *
_copyJsonConstructorExpr(const JsonConstructorExpr *from)
{
JsonConstructorExpr *newnode = makeNode(JsonConstructorExpr);
COPY_SCALAR_FIELD(type);
COPY_NODE_FIELD(args);
COPY_NODE_FIELD(func);
COPY_NODE_FIELD(coercion);
COPY_NODE_FIELD(returning);
COPY_SCALAR_FIELD(absent_on_null);
COPY_SCALAR_FIELD(unique);
COPY_LOCATION_FIELD(location);
return newnode;
}
/*
* _copyJsonKeyValue
*/
static JsonKeyValue *
_copyJsonKeyValue(const JsonKeyValue *from)
{
JsonKeyValue *newnode = makeNode(JsonKeyValue);
COPY_NODE_FIELD(key);
COPY_NODE_FIELD(value);
return newnode;
}
/*
* _copyJsonObjectConstructor
*/
static JsonObjectConstructor *
_copyJsonObjectConstructor(const JsonObjectConstructor *from)
{
JsonObjectConstructor *newnode = makeNode(JsonObjectConstructor);
COPY_NODE_FIELD(exprs);
COPY_NODE_FIELD(output);
COPY_SCALAR_FIELD(absent_on_null);
COPY_SCALAR_FIELD(unique);
COPY_LOCATION_FIELD(location);
return newnode;
}
/*
* _copyJsonAggConstructor
*/
static JsonAggConstructor *
_copyJsonAggConstructor(const JsonAggConstructor *from)
{
JsonAggConstructor *newnode = makeNode(JsonAggConstructor);
COPY_NODE_FIELD(output);
COPY_NODE_FIELD(agg_filter);
COPY_NODE_FIELD(agg_order);
COPY_NODE_FIELD(over);
COPY_LOCATION_FIELD(location);
return newnode;
}
/*
* _copyJsonObjectAgg
*/
static JsonObjectAgg *
_copyJsonObjectAgg(const JsonObjectAgg *from)
{
JsonObjectAgg *newnode = makeNode(JsonObjectAgg);
COPY_NODE_FIELD(constructor);
COPY_NODE_FIELD(arg);
COPY_SCALAR_FIELD(absent_on_null);
COPY_SCALAR_FIELD(unique);
return newnode;
}
/*
* _copyJsonOutput
*/
static JsonOutput *
_copyJsonOutput(const JsonOutput *from)
{
JsonOutput *newnode = makeNode(JsonOutput);
COPY_NODE_FIELD(typeName);
COPY_NODE_FIELD(returning);
return newnode;
}
/*
* _copyJsonArrayConstructor
*/
static JsonArrayConstructor *
_copyJsonArrayConstructor(const JsonArrayConstructor *from)
{
JsonArrayConstructor *newnode = makeNode(JsonArrayConstructor);
COPY_NODE_FIELD(exprs);
COPY_NODE_FIELD(output);
COPY_SCALAR_FIELD(absent_on_null);
COPY_LOCATION_FIELD(location);
return newnode;
}
/*
* _copyJsonArrayAgg
*/
static JsonArrayAgg *
_copyJsonArrayAgg(const JsonArrayAgg *from)
{
JsonArrayAgg *newnode = makeNode(JsonArrayAgg);
COPY_NODE_FIELD(constructor);
COPY_NODE_FIELD(arg);
COPY_SCALAR_FIELD(absent_on_null);
return newnode;
}
/*
* _copyJsonArrayQueryConstructor
*/
static JsonArrayQueryConstructor *
_copyJsonArrayQueryConstructor(const JsonArrayQueryConstructor *from)
{
JsonArrayQueryConstructor *newnode = makeNode(JsonArrayQueryConstructor);
COPY_NODE_FIELD(query);
COPY_NODE_FIELD(output);
COPY_NODE_FIELD(format);
COPY_SCALAR_FIELD(absent_on_null);
COPY_LOCATION_FIELD(location);
return newnode;
}
/* ****************************************************************
* pathnodes.h copy functions
*
@@ -5406,6 +5552,33 @@ copyObjectImpl(const void *from)
case T_JsonValueExpr:
retval = _copyJsonValueExpr(from);
break;
case T_JsonKeyValue:
retval = _copyJsonKeyValue(from);
break;
case T_JsonConstructorExpr:
retval = _copyJsonConstructorExpr(from);
break;
case T_JsonObjectConstructor:
retval = _copyJsonObjectConstructor(from);
break;
case T_JsonAggConstructor:
retval = _copyJsonAggConstructor(from);
break;
case T_JsonObjectAgg:
retval = _copyJsonObjectAgg(from);
break;
case T_JsonOutput:
retval = _copyJsonOutput(from);
break;
case T_JsonArrayConstructor:
retval = _copyJsonArrayConstructor(from);
break;
case T_JsonArrayQueryConstructor:
retval = _copyJsonArrayQueryConstructor(from);
break;
case T_JsonArrayAgg:
retval = _copyJsonArrayAgg(from);
break;
/*
* RELATION NODES

View File

@@ -871,6 +871,111 @@ _equalJsonValueExpr(const JsonValueExpr *a, const JsonValueExpr *b)
return true;
}
static bool
_equalJsonConstructorExpr(const JsonConstructorExpr *a, const JsonConstructorExpr *b)
{
COMPARE_SCALAR_FIELD(type);
COMPARE_NODE_FIELD(args);
COMPARE_NODE_FIELD(func);
COMPARE_NODE_FIELD(coercion);
COMPARE_NODE_FIELD(returning);
COMPARE_SCALAR_FIELD(absent_on_null);
COMPARE_SCALAR_FIELD(unique);
COMPARE_LOCATION_FIELD(location);
return true;
}
static bool
_equalJsonKeyValue(const JsonKeyValue *a, const JsonKeyValue *b)
{
COMPARE_NODE_FIELD(key);
COMPARE_NODE_FIELD(value);
return true;
}
static bool
_equalJsonObjectConstructor(const JsonObjectConstructor *a,
const JsonObjectConstructor *b)
{
COMPARE_NODE_FIELD(exprs);
COMPARE_NODE_FIELD(output);
COMPARE_SCALAR_FIELD(absent_on_null);
COMPARE_SCALAR_FIELD(unique);
COMPARE_LOCATION_FIELD(location);
return true;
}
static bool
_equalJsonAggConstructor(const JsonAggConstructor *a,
const JsonAggConstructor *b)
{
COMPARE_NODE_FIELD(output);
COMPARE_NODE_FIELD(agg_filter);
COMPARE_NODE_FIELD(agg_order);
COMPARE_NODE_FIELD(over);
COMPARE_LOCATION_FIELD(location);
return true;
}
static bool
_equalJsonObjectAgg(const JsonObjectAgg *a, const JsonObjectAgg *b)
{
COMPARE_NODE_FIELD(constructor);
COMPARE_NODE_FIELD(arg);
COMPARE_SCALAR_FIELD(absent_on_null);
COMPARE_SCALAR_FIELD(unique);
return true;
}
static bool
_equalJsonOutput(const JsonOutput *a, const JsonOutput *b)
{
COMPARE_NODE_FIELD(typeName);
COMPARE_NODE_FIELD(returning);
return true;
}
static bool
_equalJsonArrayConstructor(const JsonArrayConstructor *a,
const JsonArrayConstructor *b)
{
COMPARE_NODE_FIELD(exprs);
COMPARE_NODE_FIELD(output);
COMPARE_SCALAR_FIELD(absent_on_null);
COMPARE_LOCATION_FIELD(location);
return true;
}
static bool
_equalJsonArrayAgg(const JsonArrayAgg *a, const JsonArrayAgg *b)
{
COMPARE_NODE_FIELD(constructor);
COMPARE_NODE_FIELD(arg);
COMPARE_SCALAR_FIELD(absent_on_null);
return true;
}
static bool
_equalJsonArrayQueryConstructor(const JsonArrayQueryConstructor *a,
const JsonArrayQueryConstructor *b)
{
COMPARE_NODE_FIELD(query);
COMPARE_NODE_FIELD(output);
COMPARE_NODE_FIELD(format);
COMPARE_SCALAR_FIELD(absent_on_null);
COMPARE_LOCATION_FIELD(location);
return true;
}
/*
* Stuff from pathnodes.h
*/
@@ -3398,6 +3503,9 @@ equal(const void *a, const void *b)
case T_JsonValueExpr:
retval = _equalJsonValueExpr(a, b);
break;
case T_JsonConstructorExpr:
retval = _equalJsonConstructorExpr(a, b);
break;
/*
* RELATION NODES
@@ -3978,6 +4086,30 @@ equal(const void *a, const void *b)
case T_PublicationTable:
retval = _equalPublicationTable(a, b);
break;
case T_JsonKeyValue:
retval = _equalJsonKeyValue(a, b);
break;
case T_JsonObjectConstructor:
retval = _equalJsonObjectConstructor(a, b);
break;
case T_JsonAggConstructor:
retval = _equalJsonAggConstructor(a, b);
break;
case T_JsonObjectAgg:
retval = _equalJsonObjectAgg(a, b);
break;
case T_JsonOutput:
retval = _equalJsonOutput(a, b);
break;
case T_JsonArrayConstructor:
retval = _equalJsonArrayConstructor(a, b);
break;
case T_JsonArrayQueryConstructor:
retval = _equalJsonArrayQueryConstructor(a, b);
break;
case T_JsonArrayAgg:
retval = _equalJsonArrayAgg(a, b);
break;
default:
elog(ERROR, "unrecognized node type: %d",

View File

@@ -872,3 +872,18 @@ makeJsonEncoding(char *name)
return JS_ENC_DEFAULT;
}
/*
* makeJsonKeyValue -
* creates a JsonKeyValue node
*/
Node *
makeJsonKeyValue(Node *key, Node *value)
{
JsonKeyValue *n = makeNode(JsonKeyValue);
n->key = (Expr *) key;
n->value = castNode(JsonValueExpr, value);
return (Node *) n;
}

View File

@@ -257,6 +257,9 @@ exprType(const Node *expr)
type = exprType((Node *) (jve->formatted_expr ? jve->formatted_expr : jve->raw_expr));
}
break;
case T_JsonConstructorExpr:
type = ((const JsonConstructorExpr *) expr)->returning->typid;
break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
type = InvalidOid; /* keep compiler quiet */
@@ -491,6 +494,8 @@ exprTypmod(const Node *expr)
return exprTypmod((Node *) ((const PlaceHolderVar *) expr)->phexpr);
case T_JsonValueExpr:
return exprTypmod((Node *) ((const JsonValueExpr *) expr)->formatted_expr);
case T_JsonConstructorExpr:
return -1; /* ((const JsonConstructorExpr *) expr)->returning->typmod; */
default:
break;
}
@@ -970,6 +975,16 @@ exprCollation(const Node *expr)
case T_JsonValueExpr:
coll = exprCollation((Node *) ((const JsonValueExpr *) expr)->formatted_expr);
break;
case T_JsonConstructorExpr:
{
const JsonConstructorExpr *ctor = (const JsonConstructorExpr *) expr;
if (ctor->coercion)
coll = exprCollation((Node *) ctor->coercion);
else
coll = InvalidOid;
}
break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
coll = InvalidOid; /* keep compiler quiet */
@@ -1186,6 +1201,16 @@ exprSetCollation(Node *expr, Oid collation)
exprSetCollation((Node *) ((JsonValueExpr *) expr)->formatted_expr,
collation);
break;
case T_JsonConstructorExpr:
{
JsonConstructorExpr *ctor = (JsonConstructorExpr *) expr;
if (ctor->coercion)
exprSetCollation((Node *) ctor->coercion, collation);
else
Assert(!OidIsValid(collation)); /* result is always a json[b] type */
}
break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
break;
@@ -1635,6 +1660,9 @@ exprLocation(const Node *expr)
case T_JsonValueExpr:
loc = exprLocation((Node *) ((const JsonValueExpr *) expr)->raw_expr);
break;
case T_JsonConstructorExpr:
loc = ((const JsonConstructorExpr *) expr)->location;
break;
default:
/* for any other node type it's just unknown... */
loc = -1;
@@ -2379,6 +2407,18 @@ expression_tree_walker(Node *node,
return true;
}
break;
case T_JsonConstructorExpr:
{
JsonConstructorExpr *ctor = (JsonConstructorExpr *) node;
if (walker(ctor->args, context))
return true;
if (walker(ctor->func, context))
return true;
if (walker(ctor->coercion, context))
return true;
}
break;
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(node));
@@ -3361,6 +3401,19 @@ expression_tree_mutator(Node *node,
MUTATE(newnode->formatted_expr, jve->formatted_expr, Expr *);
MUTATE(newnode->format, jve->format, JsonFormat *);
return (Node *) newnode;
}
case T_JsonConstructorExpr:
{
JsonConstructorExpr *jve = (JsonConstructorExpr *) node;
JsonConstructorExpr *newnode;
FLATCOPY(newnode, jve, JsonConstructorExpr);
MUTATE(newnode->args, jve->args, List *);
MUTATE(newnode->func, jve->func, Expr *);
MUTATE(newnode->coercion, jve->coercion, Expr *);
MUTATE(newnode->returning, jve->returning, JsonReturning *);
return (Node *) newnode;
}
default:
@@ -3637,6 +3690,7 @@ raw_expression_tree_walker(Node *node,
case T_ParamRef:
case T_A_Const:
case T_A_Star:
case T_JsonFormat:
/* primitive node types with no subnodes */
break;
case T_Alias:
@@ -4085,6 +4139,104 @@ raw_expression_tree_walker(Node *node,
return true;
}
break;
case T_JsonConstructorExpr:
{
JsonConstructorExpr *ctor = (JsonConstructorExpr *) node;
if (walker(ctor->args, context))
return true;
if (walker(ctor->func, context))
return true;
if (walker(ctor->coercion, context))
return true;
if (walker(ctor->returning, context))
return true;
}
break;
case T_JsonOutput:
{
JsonOutput *out = (JsonOutput *) node;
if (walker(out->typeName, context))
return true;
if (walker(out->returning, context))
return true;
}
break;
case T_JsonKeyValue:
{
JsonKeyValue *jkv = (JsonKeyValue *) node;
if (walker(jkv->key, context))
return true;
if (walker(jkv->value, context))
return true;
}
break;
case T_JsonObjectConstructor:
{
JsonObjectConstructor *joc = (JsonObjectConstructor *) node;
if (walker(joc->output, context))
return true;
if (walker(joc->exprs, context))
return true;
}
break;
case T_JsonArrayConstructor:
{
JsonArrayConstructor *jac = (JsonArrayConstructor *) node;
if (walker(jac->output, context))
return true;
if (walker(jac->exprs, context))
return true;
}
break;
case T_JsonAggConstructor:
{
JsonAggConstructor *ctor = (JsonAggConstructor *) node;
if (walker(ctor->output, context))
return true;
if (walker(ctor->agg_order, context))
return true;
if (walker(ctor->agg_filter, context))
return true;
if (walker(ctor->over, context))
return true;
}
break;
case T_JsonObjectAgg:
{
JsonObjectAgg *joa = (JsonObjectAgg *) node;
if (walker(joa->constructor, context))
return true;
if (walker(joa->arg, context))
return true;
}
break;
case T_JsonArrayAgg:
{
JsonArrayAgg *jaa = (JsonArrayAgg *) node;
if (walker(jaa->constructor, context))
return true;
if (walker(jaa->arg, context))
return true;
}
break;
case T_JsonArrayQueryConstructor:
{
JsonArrayQueryConstructor *jaqc = (JsonArrayQueryConstructor *) node;
if (walker(jaqc->output, context))
return true;
if (walker(jaqc->query, context))
return true;
}
break;
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(node));

View File

@@ -1781,6 +1781,21 @@ _outJsonValueExpr(StringInfo str, const JsonValueExpr *node)
WRITE_NODE_FIELD(format);
}
static void
_outJsonConstructorExpr(StringInfo str, const JsonConstructorExpr *node)
{
WRITE_NODE_TYPE("JSONCTOREXPR");
WRITE_NODE_FIELD(args);
WRITE_NODE_FIELD(func);
WRITE_NODE_FIELD(coercion);
WRITE_INT_FIELD(type);
WRITE_NODE_FIELD(returning);
WRITE_BOOL_FIELD(unique);
WRITE_BOOL_FIELD(absent_on_null);
WRITE_LOCATION_FIELD(location);
}
/*****************************************************************************
*
* Stuff from pathnodes.h.
@@ -4576,6 +4591,9 @@ outNode(StringInfo str, const void *obj)
case T_JsonValueExpr:
_outJsonValueExpr(str, obj);
break;
case T_JsonConstructorExpr:
_outJsonConstructorExpr(str, obj);
break;
default:

View File

@@ -1434,6 +1434,26 @@ _readJsonValueExpr(void)
READ_DONE();
}
/*
* _readJsonConstructorExpr
*/
static JsonConstructorExpr *
_readJsonConstructorExpr(void)
{
READ_LOCALS(JsonConstructorExpr);
READ_NODE_FIELD(args);
READ_NODE_FIELD(func);
READ_NODE_FIELD(coercion);
READ_INT_FIELD(type);
READ_NODE_FIELD(returning);
READ_BOOL_FIELD(unique);
READ_BOOL_FIELD(absent_on_null);
READ_LOCATION_FIELD(location);
READ_DONE();
}
/*
* Stuff from pathnodes.h.
*
@@ -3025,6 +3045,8 @@ parseNodeString(void)
return_value = _readJsonReturning();
else if (MATCH("JSONVALUEEXPR", 13))
return_value = _readJsonValueExpr();
else if (MATCH("JSONCTOREXPR", 12))
return_value = _readJsonConstructorExpr();
else
{
elog(ERROR, "badly formatted node string \"%.32s\"...", token);