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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy