Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c1010e2

Browse files
author
Nikita Glukhov
committed
Add JSON_SCALAR()
1 parent d58ca1c commit c1010e2

File tree

21 files changed

+432
-60
lines changed

21 files changed

+432
-60
lines changed

doc/src/sgml/func.sgml

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16901,11 +16901,16 @@ $ ? (@ like_regex "^\\d+$")
1690116901
<para>
1690216902
<productname>PostgreSQL</productname> provides several functions
1690316903
that generate JSON data. Taking values of SQL types as input, these
16904-
functions construct JSON objects or JSON arrays represented as
16905-
SQL character or binary strings.
16904+
functions construct JSON objects, JSON arrays or JSON scalars represented
16905+
as <type>json</type> or <type>jsonb</type> types, SQL character or binary strings.
1690616906
</para>
1690716907

1690816908
<itemizedlist>
16909+
<listitem>
16910+
<para>
16911+
<xref linkend="functions-jsonscalar"/>
16912+
</para>
16913+
</listitem>
1690916914
<listitem>
1691016915
<para>
1691116916
<link linkend="functions-jsonobject"><literal>JSON_OBJECT</literal></link>
@@ -16928,6 +16933,102 @@ $ ? (@ like_regex "^\\d+$")
1692816933
</listitem>
1692916934
</itemizedlist>
1693016935

16936+
<refentry id="functions-jsonscalar">
16937+
<refnamediv>
16938+
<refname>JSON_SCALAR</refname>
16939+
<refpurpose>create a JSON scalar</refpurpose>
16940+
</refnamediv>
16941+
16942+
<refsynopsisdiv>
16943+
<synopsis>
16944+
JSON_SCALAR (
16945+
<replaceable class="parameter">expression</replaceable>
16946+
[ RETURNING <replaceable class="parameter">json_data_type</replaceable> ]
16947+
)
16948+
</synopsis>
16949+
</refsynopsisdiv>
16950+
16951+
<refsect1>
16952+
<title>Description</title>
16953+
16954+
<para>
16955+
<function>JSON_SCALAR</function> function generates a scalar
16956+
<acronym>JSON</acronym> from a <acronym>SQL</acronym> data.
16957+
</para>
16958+
</refsect1>
16959+
16960+
<refsect1>
16961+
<title>Parameters</title>
16962+
<variablelist>
16963+
<varlistentry>
16964+
<term>
16965+
<literal><replaceable class="parameter">expression</replaceable></literal>
16966+
</term>
16967+
<listitem>
16968+
<para>
16969+
Expression that provides the data for constructing a
16970+
<acronym>JSON</acronym>.
16971+
For null input, <acronym>SQL</acronym> null
16972+
(not a <acronym>JSON</acronym> null) value is returned.
16973+
For any scalar other than a number, a Boolean, the text representation
16974+
will be used, with escaping as necessary to make it a valid
16975+
<acronym>JSON</acronym> string value.
16976+
For details, see
16977+
<function>to_json()</function>/<function>to_jsonb()</function>
16978+
in <xref linkend="functions-json-creation-table"/>.
16979+
</para>
16980+
</listitem>
16981+
</varlistentry>
16982+
<varlistentry>
16983+
<term>
16984+
<literal>RETURNING <replaceable class="parameter">json_data_type</replaceable></literal>
16985+
</term>
16986+
<listitem>
16987+
<para>
16988+
The output clause that specifies the type (<type>json</type> or
16989+
<type>jsonb</type>) of the generated <acronym>JSON</acronym> scalar.
16990+
</para>
16991+
</listitem>
16992+
</varlistentry>
16993+
</variablelist>
16994+
</refsect1>
16995+
16996+
<refsect1>
16997+
<title>Notes</title>
16998+
<para>
16999+
Alternatively, you can construct <acronym>JSON</acronym> objects by
17000+
using <productname>PostgreSQL</productname>-specific
17001+
<function>to_json()</function>/<function>to_jsonb()</function> functions.
17002+
See <xref linkend="functions-json-creation-table"/> for details.
17003+
</para>
17004+
</refsect1>
17005+
<refsect1>
17006+
<title>Examples</title>
17007+
<para>
17008+
Construct a JSON from the provided values various types:
17009+
</para>
17010+
<screen>
17011+
SELECT JSON_SCALAR(123.45);
17012+
json_scalar
17013+
-------------
17014+
123.45
17015+
(1 row)
17016+
17017+
SELECT JSON_SCALAR('123');
17018+
json_scalar
17019+
-------------
17020+
"123"
17021+
(1 row)
17022+
17023+
SELECT JSON_SCALAR(true);
17024+
json_scalar
17025+
-------------
17026+
true
17027+
(1 row)
17028+
</screen>
17029+
</refsect1>
17030+
</refentry>
17031+
1693117032
<sect4 id="functions-jsonobject">
1693217033
<title><literal>JSON_OBJECT</literal></title>
1693317034
<indexterm><primary>json_object</primary></indexterm>

doc/src/sgml/keywords/sql2016-02-reserved.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ JSON_EXISTS
162162
JSON_OBJECT
163163
JSON_OBJECTAGG
164164
JSON_QUERY
165+
JSON_SCALAR
165166
JSON_TABLE
166167
JSON_TABLE_PRIMITIVE
167168
JSON_VALUE

src/backend/executor/execExpr.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
#include "utils/array.h"
4747
#include "utils/builtins.h"
4848
#include "utils/datum.h"
49+
#include "utils/json.h"
50+
#include "utils/jsonb.h"
4951
#include "utils/jsonpath.h"
5052
#include "utils/lsyscache.h"
5153
#include "utils/typcache.h"
@@ -2172,6 +2174,43 @@ ExecInitExprRec(Expr *node, ExprState *state,
21722174
argno++;
21732175
}
21742176

2177+
/* prepare type cache for datum_to_json[b]() */
2178+
if (ctor->type == JSCTOR_JSON_SCALAR)
2179+
{
2180+
bool is_jsonb =
2181+
ctor->returning->format->format == JS_FORMAT_JSONB;
2182+
2183+
scratch.d.json_ctor.arg_type_cache =
2184+
palloc(sizeof(*scratch.d.json_ctor.arg_type_cache) * nargs);
2185+
2186+
for (int i = 0; i < nargs; i++)
2187+
{
2188+
int category;
2189+
Oid outfuncid;
2190+
Oid typid = scratch.d.json_ctor.arg_types[i];
2191+
2192+
if (is_jsonb)
2193+
{
2194+
JsonbTypeCategory jbcat;
2195+
2196+
jsonb_categorize_type(typid, &jbcat, &outfuncid);
2197+
2198+
category = (int) jbcat;
2199+
}
2200+
else
2201+
{
2202+
JsonTypeCategory jscat;
2203+
2204+
json_categorize_type(typid, &jscat, &outfuncid);
2205+
2206+
category = (int) jscat;
2207+
}
2208+
2209+
scratch.d.json_ctor.arg_type_cache[i].outfuncid = outfuncid;
2210+
scratch.d.json_ctor.arg_type_cache[i].category = category;
2211+
}
2212+
}
2213+
21752214
ExprEvalPushStep(state, &scratch);
21762215
}
21772216

src/backend/executor/execExprInterp.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,6 +1580,25 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
15801580
op->d.json_constructor.arg_types,
15811581
op->d.json_constructor.constructor->absent_on_null,
15821582
op->d.json_constructor.constructor->unique);
1583+
else if (ctor->type == JSCTOR_JSON_SCALAR)
1584+
{
1585+
if (op->d.json_ctor.arg_nulls[0])
1586+
{
1587+
res = (Datum) 0;
1588+
isnull = true;
1589+
}
1590+
else
1591+
{
1592+
Datum value = op->d.json_constructor.arg_values[0];
1593+
int category = op->d.json_constructor.arg_type_cache[0].category;
1594+
Oid outfuncid = op->d.json_constructor.arg_type_cache[0].outfuncid;
1595+
1596+
if (is_jsonb)
1597+
res = to_jsonb_worker(value, category, outfuncid);
1598+
else
1599+
res = to_json_worker(value, category, outfuncid);
1600+
}
1601+
}
15831602
else
15841603
{
15851604
res = (Datum) 0;

src/backend/nodes/copyfuncs.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,6 +2294,20 @@ _copyJsonValueExpr(const JsonValueExpr *from)
22942294
return newnode;
22952295
}
22962296

2297+
/*
2298+
* _copyJsonScalarExpr
2299+
*/
2300+
static JsonScalarExpr *
2301+
_copyJsonScalarExpr(const JsonScalarExpr *from)
2302+
{
2303+
JsonScalarExpr *newnode = makeNode(JsonScalarExpr);
2304+
2305+
COPY_NODE_FIELD(expr);
2306+
COPY_LOCATION_FIELD(location);
2307+
2308+
return newnode;
2309+
}
2310+
22972311
/*
22982312
* _copyJsonConstructorExpr
22992313
*/
@@ -5492,6 +5506,9 @@ copyObjectImpl(const void *from)
54925506
case T_JsonValueExpr:
54935507
retval = _copyJsonValueExpr(from);
54945508
break;
5509+
case T_JsonScalarExpr:
5510+
retval = _copyJsonScalarExpr(from);
5511+
break;
54955512
case T_JsonKeyValue:
54965513
retval = _copyJsonKeyValue(from);
54975514
break;

src/backend/nodes/equalfuncs.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,15 @@ _equalJsonValueExpr(const JsonValueExpr *a, const JsonValueExpr *b)
848848
return true;
849849
}
850850

851+
static bool
852+
_equalJsonScalarExpr(const JsonScalarExpr *a, const JsonScalarExpr *b)
853+
{
854+
COMPARE_NODE_FIELD(expr);
855+
COMPARE_LOCATION_FIELD(location);
856+
857+
return true;
858+
}
859+
851860
static bool
852861
_equalJsonConstructorExpr(const JsonConstructorExpr *a, const JsonConstructorExpr *b)
853862
{
@@ -3436,6 +3445,9 @@ equal(const void *a, const void *b)
34363445
case T_JsonValueExpr:
34373446
retval = _equalJsonValueExpr(a, b);
34383447
break;
3448+
case T_JsonScalarExpr:
3449+
retval = _equalJsonScalarExpr(a, b);
3450+
break;
34393451
case T_JsonConstructorExpr:
34403452
retval = _equalJsonConstructorExpr(a, b);
34413453
break;

src/backend/parser/gram.y

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
613613
json_value_func_expr
614614
json_query_expr
615615
json_exists_predicate
616+
json_scalar_expr
616617
json_api_common_syntax
617618
json_context_item
618619
json_argument
@@ -733,7 +734,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
733734
INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION
734735

735736
JOIN JSON JSON_ARRAY JSON_ARRAYAGG JSON_EXISTS JSON_OBJECT JSON_OBJECTAGG
736-
JSON_QUERY JSON_VALUE
737+
JSON_QUERY JSON_SCALAR JSON_VALUE
737738

738739
KEY KEYS KEEP
739740

@@ -14791,6 +14792,17 @@ json_func_expr:
1479114792
| json_value_func_expr
1479214793
| json_query_expr
1479314794
| json_exists_predicate
14795+
| json_scalar_expr
14796+
;
14797+
14798+
json_scalar_expr:
14799+
JSON_SCALAR '(' a_expr ')'
14800+
{
14801+
JsonScalarExpr *n = makeNode(JsonScalarExpr);
14802+
n->expr = (Expr *) $3;
14803+
n->location = @1;
14804+
$$ = (Node *) n;
14805+
}
1479414806
;
1479514807

1479614808

@@ -16007,6 +16019,7 @@ col_name_keyword:
1600716019
| JSON_OBJECT
1600816020
| JSON_OBJECTAGG
1600916021
| JSON_QUERY
16022+
| JSON_SCALAR
1601016023
| JSON_VALUE
1601116024
| LEAST
1601216025
| NATIONAL

src/backend/parser/parse_expr.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ static Node *transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg);
134134
static Node *transformJsonIsPredicate(ParseState *pstate, JsonIsPredicate *p);
135135
static Node *transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *p);
136136
static Node *transformJsonValueExpr(ParseState *pstate, JsonValueExpr *jve);
137+
static Node *transformJsonScalarExpr(ParseState *pstate, JsonScalarExpr *expr);
137138
static Node *make_row_comparison_op(ParseState *pstate, List *opname,
138139
List *largs, List *rargs, int location);
139140
static Node *make_row_distinct_op(ParseState *pstate, List *opname,
@@ -414,6 +415,10 @@ transformExprRecurse(ParseState *pstate, Node *expr)
414415
result = transformJsonValueExpr(pstate, (JsonValueExpr *) expr);
415416
break;
416417

418+
case T_JsonScalarExpr:
419+
result = transformJsonScalarExpr(pstate, (JsonScalarExpr *) expr);
420+
break;
421+
417422
default:
418423
/* should not reach here */
419424
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
@@ -4886,3 +4891,23 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
48864891

48874892
return (Node *) jsexpr;
48884893
}
4894+
4895+
/*
4896+
* Transform a JSON_SCALAR() expression.
4897+
*/
4898+
static Node *
4899+
transformJsonScalarExpr(ParseState *pstate, JsonScalarExpr *jsexpr)
4900+
{
4901+
JsonReturning *returning = makeNode(JsonReturning);
4902+
Node *arg = transformExprRecurse(pstate, (Node *) jsexpr->expr);
4903+
4904+
returning->format = makeJsonFormat(JS_FORMAT_JSON, JS_ENC_DEFAULT, -1);
4905+
returning->typid = JSONOID;
4906+
returning->typmod = -1;
4907+
4908+
if (exprType(arg) == UNKNOWNOID)
4909+
arg = coerce_to_specific_type(pstate, arg, TEXTOID, "JSON_SCALAR");
4910+
4911+
return makeJsonCtorExpr(pstate, JSCTOR_JSON_SCALAR, list_make1(arg), NULL,
4912+
returning, false, false, jsexpr->location);
4913+
}

src/backend/parser/parse_target.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1931,6 +1931,9 @@ FigureColnameInternal(Node *node, char **name)
19311931
case T_XmlSerialize:
19321932
*name = "xmlserialize";
19331933
return 2;
1934+
case T_JsonScalarExpr:
1935+
*name = "json_scalar";
1936+
return 2;
19341937
case T_JsonObjectConstructor:
19351938
*name = "json_object";
19361939
return 2;

0 commit comments

Comments
 (0)