Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)