Skip to content

Commit ed9e79b

Browse files
author
Nikita Glukhov
committed
Add JSON() constructor
1 parent be596bc commit ed9e79b

File tree

19 files changed

+463
-27
lines changed

19 files changed

+463
-27
lines changed

doc/src/sgml/func.sgml

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16906,6 +16906,11 @@ $ ? (@ like_regex "^\\d+$")
1690616906
</para>
1690716907

1690816908
<itemizedlist>
16909+
<listitem>
16910+
<para>
16911+
<xref linkend="functions-jsonparse"/>
16912+
</para>
16913+
</listitem>
1690916914
<listitem>
1691016915
<para>
1691116916
<link linkend="functions-jsonscalar"><literal>JSON_SCALAR</literal></link>
@@ -16933,6 +16938,132 @@ $ ? (@ like_regex "^\\d+$")
1693316938
</listitem>
1693416939
</itemizedlist>
1693516940

16941+
<refentry id="functions-jsonparse">
16942+
<refnamediv>
16943+
<refname>JSON</refname>
16944+
<refpurpose>create a JSON from a text</refpurpose>
16945+
</refnamediv>
16946+
16947+
<refsynopsisdiv>
16948+
<synopsis>
16949+
JSON (
16950+
<replaceable class="parameter">expression</replaceable> [ FORMAT JSON [ ENCODING UTF8 ] ]
16951+
[ { WITH | WITHOUT } UNIQUE [ KEYS ] ]
16952+
[ RETURNING <replaceable class="parameter">json_data_type</replaceable> ]
16953+
)
16954+
</synopsis>
16955+
</refsynopsisdiv>
16956+
16957+
<refsect1>
16958+
<title>Description</title>
16959+
16960+
<para>
16961+
<function>JSON</function> function generates a <acronym>JSON</acronym>
16962+
from a text data.
16963+
</para>
16964+
</refsect1>
16965+
16966+
<refsect1>
16967+
<title>Parameters</title>
16968+
<variablelist>
16969+
<varlistentry>
16970+
<term>
16971+
<literal><replaceable class="parameter">expression</replaceable> [ FORMAT JSON [ ENCODING UTF8 ] ]</literal>
16972+
</term>
16973+
<listitem>
16974+
<para>
16975+
String expression that provides the <acronym>JSON</acronym> text data.
16976+
Accepted any character strings (<type>text</type>, <type>char</type>, etc.)
16977+
or binary strings (<type>bytea</type>) in UTF8 encoding.
16978+
For null input, <acronym>SQL</acronym> null value is returned.
16979+
</para>
16980+
<para>
16981+
The optional <literal>FORMAT</literal> clause is provided to conform
16982+
to the SQL/JSON standard.
16983+
</para>
16984+
</listitem>
16985+
</varlistentry>
16986+
<varlistentry>
16987+
<term>
16988+
<literal>[ { WITH | WITHOUT } UNIQUE [ KEYS ] ]</literal>
16989+
</term>
16990+
<listitem>
16991+
<para>
16992+
Defines whether duplicate keys are allowed:
16993+
</para>
16994+
<variablelist>
16995+
<varlistentry>
16996+
<term><literal>WITHOUT</literal></term>
16997+
<listitem>
16998+
<para>
16999+
Default. The constructed
17000+
<acronym>JSON</acronym> object can contain duplicate keys.
17001+
</para>
17002+
</listitem>
17003+
</varlistentry>
17004+
<varlistentry>
17005+
<term><literal>WITH</literal></term>
17006+
<listitem>
17007+
<para>
17008+
Duplicate keys are not allowed.
17009+
If the input data contains duplicate keys, an error is returned.
17010+
</para>
17011+
</listitem>
17012+
</varlistentry>
17013+
</variablelist>
17014+
<para>
17015+
Optionally, you can add the <literal>KEYS</literal> keyword for
17016+
semantic clarity.
17017+
</para>
17018+
</listitem>
17019+
</varlistentry>
17020+
<varlistentry>
17021+
<term>
17022+
<literal>RETURNING <replaceable class="parameter">json_data_type</replaceable></literal>
17023+
</term>
17024+
<listitem>
17025+
<para>
17026+
The output clause that specifies the type (<type>json</type> or
17027+
<type>jsonb</type>) of the generated <acronym>JSON</acronym>.
17028+
</para>
17029+
</listitem>
17030+
</varlistentry>
17031+
</variablelist>
17032+
</refsect1>
17033+
17034+
<refsect1>
17035+
<title>Notes</title>
17036+
<para>
17037+
Alternatively, you can construct <acronym>JSON</acronym> values simply
17038+
using <productname>PostgreSQL</productname>-specific casts to
17039+
<type>json</type> and <type>jsonb</type> types.
17040+
</para>
17041+
</refsect1>
17042+
<refsect1>
17043+
<title>Examples</title>
17044+
<para>
17045+
Construct a JSON the provided strings:
17046+
</para>
17047+
<screen>
17048+
SELECT JSON('{ "a" : 123, "b": [ true, "foo" ], "a" : "bar" }');
17049+
json
17050+
--------------------------------------------------
17051+
{ "a" : 123, "b": [ true, "foo" ], "a" : "bar" }
17052+
(1 row)
17053+
17054+
17055+
SELECT JSON('{"a": 123, "b": [true, "foo"], "a": "bar"}' RETURNING jsonb);
17056+
json
17057+
----------------------------------
17058+
{"a": "bar", "b": [true, "foo"]}
17059+
(1 row)
17060+
17061+
SELECT JSON('{"a": 123, "b": [true, "foo"], "a": "bar"}' WITH UNIQUE KEYS);
17062+
ERROR: duplicate JSON object key value
17063+
</screen>
17064+
</refsect1>
17065+
</refentry>
17066+
1693617067
<sect4 id="functions-jsonscalar">
1693717068
<title><literal>JSON_SCALAR</literal></title>
1693817069
<indexterm><primary>json_scalar</primary></indexterm>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ INTERVAL
156156
INTO
157157
IS
158158
JOIN
159+
JSON
159160
JSON_ARRAY
160161
JSON_ARRAYAGG
161162
JSON_EXISTS

src/backend/executor/execExpr.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2142,7 +2142,8 @@ ExecInitExprRec(Expr *node, ExprState *state,
21422142
{
21432143
ExecInitExprRec(ctor->func, state, resv, resnull);
21442144
}
2145-
else if (ctor->type == JSCTOR_JSON_SERIALIZE)
2145+
else if ((ctor->type == JSCTOR_JSON_PARSE && !ctor->unique) ||
2146+
ctor->type == JSCTOR_JSON_SERIALIZE)
21462147
{
21472148
/* Use the value of the first argument as a result */
21482149
ExecInitExprRec(linitial(args), state, resv, resnull);

src/backend/executor/execExprInterp.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,27 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
15991599
res = to_json_worker(value, category, outfuncid);
16001600
}
16011601
}
1602+
else if (ctor->type == JSCTOR_JSON_PARSE)
1603+
{
1604+
if (op->d.json_ctor.arg_nulls[0])
1605+
{
1606+
res = (Datum) 0;
1607+
isnull = true;
1608+
}
1609+
else
1610+
{
1611+
Datum value = op->d.json_ctor.arg_values[0];
1612+
text *js = DatumGetTextP(value);
1613+
1614+
if (is_jsonb)
1615+
res = jsonb_from_text(js, true);
1616+
else
1617+
{
1618+
(void) json_validate(js, true, true);
1619+
res = value;
1620+
}
1621+
}
1622+
}
16021623
else
16031624
{
16041625
res = (Datum) 0;
@@ -3954,7 +3975,7 @@ ExecEvalJsonIsPredicate(ExprState *state, ExprEvalStep *op)
39543975
* JSON text validation.
39553976
*/
39563977
if (res && (pred->unique_keys || exprtype == TEXTOID))
3957-
res = json_validate(json, pred->unique_keys);
3978+
res = json_validate(json, pred->unique_keys, false);
39583979
}
39593980
else if (exprtype == JSONBOID)
39603981
{

src/backend/parser/gram.y

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
534534
%type <list> copy_options
535535

536536
%type <typnam> Typename SimpleTypename ConstTypename
537-
GenericType Numeric opt_float
537+
GenericType Numeric opt_float JsonType
538538
Character ConstCharacter
539539
CharacterWithLength CharacterWithoutLength
540540
ConstDatetime ConstInterval
@@ -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_parse_expr
616617
json_scalar_expr
617618
json_serialize_expr
618619
json_api_common_syntax
@@ -12594,6 +12595,7 @@ SimpleTypename:
1259412595
$$->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
1259512596
makeIntConst($3, @3));
1259612597
}
12598+
| JsonType { $$ = $1; }
1259712599
;
1259812600

1259912601
/* We have a separate ConstTypename to allow defaulting fixed-length
@@ -12612,6 +12614,7 @@ ConstTypename:
1261212614
| ConstBit { $$ = $1; }
1261312615
| ConstCharacter { $$ = $1; }
1261412616
| ConstDatetime { $$ = $1; }
12617+
| JsonType { $$ = $1; }
1261512618
;
1261612619

1261712620
/*
@@ -12980,6 +12983,13 @@ interval_second:
1298012983
}
1298112984
;
1298212985

12986+
JsonType:
12987+
JSON
12988+
{
12989+
$$ = SystemTypeName("json");
12990+
$$->location = @1;
12991+
}
12992+
;
1298312993

1298412994
/*****************************************************************************
1298512995
*
@@ -14793,10 +14803,22 @@ json_func_expr:
1479314803
| json_value_func_expr
1479414804
| json_query_expr
1479514805
| json_exists_predicate
14806+
| json_parse_expr
1479614807
| json_scalar_expr
1479714808
| json_serialize_expr
1479814809
;
1479914810

14811+
json_parse_expr:
14812+
JSON '(' json_value_expr json_key_uniqueness_constraint_opt ')'
14813+
{
14814+
JsonParseExpr *n = makeNode(JsonParseExpr);
14815+
n->expr = (JsonValueExpr *) $3;
14816+
n->unique_keys = $4;
14817+
n->location = @1;
14818+
$$ = (Node *) n;
14819+
}
14820+
;
14821+
1480014822
json_scalar_expr:
1480114823
JSON_SCALAR '(' a_expr ')'
1480214824
{
@@ -15810,7 +15832,6 @@ unreserved_keyword:
1581015832
| INSTEAD
1581115833
| INVOKER
1581215834
| ISOLATION
15813-
| JSON
1581415835
| KEEP
1581515836
| KEY
1581615837
| KEYS
@@ -16025,6 +16046,7 @@ col_name_keyword:
1602516046
| INT_P
1602616047
| INTEGER
1602716048
| INTERVAL
16049+
| JSON
1602816050
| JSON_ARRAY
1602916051
| JSON_ARRAYAGG
1603016052
| JSON_EXISTS

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