From cf79473d1ae6cd17834603fce4cdaf67c9b5d398 Mon Sep 17 00:00:00 2001 From: Andrew Dunstan Date: Tue, 18 Jan 2022 14:57:54 -0500 Subject: [PATCH 6/6] GUC sql_json --- doc/src/sgml/config.sgml | 19 +++ src/backend/parser/gram.y | 11 +- src/backend/parser/parse_expr.c | 48 ++++-- src/backend/utils/adt/format_type.c | 7 +- src/backend/utils/adt/jsonb.c | 2 + src/backend/utils/adt/ruleutils.c | 6 +- src/backend/utils/misc/guc.c | 19 +++ src/backend/utils/misc/postgresql.conf.sample | 1 + src/include/nodes/parsenodes.h | 2 + src/include/utils/jsonb.h | 14 ++ src/test/regress/expected/jsonb.out | 130 ++++++++++++++++ src/test/regress/expected/sqljson.out | 141 ++++++++++++++++++ src/test/regress/sql/jsonb.sql | 38 +++++ src/test/regress/sql/sqljson.sql | 32 ++++ 14 files changed, 454 insertions(+), 16 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 4cd9818acf..4fda095cdb 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -9735,6 +9735,25 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' + + sql_json (enum) + json + jsonb + + sql_json configuration parameter + + + + + Valid values are json and jsonb. + Specifies what PostgreSQL type is used + as an implementation of SQL type JSON. + When sql_json is set to jsonb, + PostgreSQL type json can be + accessed using explicit qualification pg_catalog.json. + + + diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index de40ba5caf..00f90eeb5b 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -62,6 +62,7 @@ #include "storage/lmgr.h" #include "utils/date.h" #include "utils/datetime.h" +#include "utils/jsonb.h" #include "utils/numeric.h" #include "utils/xml.h" @@ -13488,10 +13489,11 @@ interval_second: } ; +/* Mapping of PG jsonb types to SQL/JSON JSON type */ JsonType: JSON { - $$ = SystemTypeName("json"); + $$ = SystemTypeName(SQLJSON_TYPE_NAME()); $$->location = @1; } ; @@ -15366,21 +15368,24 @@ json_func_expr: ; json_parse_expr: - JSON '(' json_value_expr json_key_uniqueness_constraint_opt ')' + JSON '(' json_value_expr json_key_uniqueness_constraint_opt + json_returning_clause_opt ')' { JsonParseExpr *n = makeNode(JsonParseExpr); n->expr = (JsonValueExpr *) $3; n->unique_keys = $4; + n->output = (JsonOutput *) $5; n->location = @1; $$ = (Node *) n; } ; json_scalar_expr: - JSON_SCALAR '(' a_expr ')' + JSON_SCALAR '(' a_expr json_returning_clause_opt ')' { JsonScalarExpr *n = makeNode(JsonScalarExpr); n->expr = (Expr *) $3; + n->output = (JsonOutput *) $4; n->location = @1; $$ = (Node *) n; } diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index c5fc4584a5..8ba09dd1c1 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -37,6 +37,7 @@ #include "utils/builtins.h" #include "utils/date.h" #include "utils/fmgroids.h" +#include "utils/jsonb.h" #include "utils/lsyscache.h" #include "utils/timestamp.h" #include "utils/xml.h" @@ -4448,19 +4449,49 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func) return (Node *) jsexpr; } +static JsonReturning * +transformJsonConstructorRet(ParseState *pstate, JsonOutput *output, const char *fname) +{ + JsonReturning *returning; + + if (output) + { + returning = transformJsonOutput(pstate, output, false); + + Assert(OidIsValid(returning->typid)); + + if (returning->typid != JSONOID && returning->typid != JSONBOID) + ereport(ERROR, + (errcode(ERRCODE_DATATYPE_MISMATCH), + errmsg("cannot use RETURNING type %s in %s", + format_type_be(returning->typid), fname), + parser_errposition(pstate, output->typeName->location))); + } + else + { + Oid targettype = SQLJSON_TYPE_OID(); + JsonFormatType format = + SQLJSON_TYPE_IS_JSONB() ? JS_FORMAT_JSONB : JS_FORMAT_JSON; + + returning = makeNode(JsonReturning); + returning->format = makeJsonFormat(format, JS_ENC_DEFAULT, -1); + returning->typid = targettype; + returning->typmod = -1; + } + + return returning; +} + /* * Transform a JSON() expression. */ static Node * transformJsonParseExpr(ParseState *pstate, JsonParseExpr *jsexpr) { - JsonReturning *returning = makeNode(JsonReturning); + JsonReturning *returning = transformJsonConstructorRet(pstate, jsexpr->output, + "JSON()"); Node *arg; - returning->format = makeJsonFormat(JS_FORMAT_JSON, JS_ENC_DEFAULT, -1); - returning->typid = JSONOID; - returning->typmod = -1; - if (jsexpr->unique_keys) { /* @@ -4500,12 +4531,9 @@ transformJsonParseExpr(ParseState *pstate, JsonParseExpr *jsexpr) static Node * transformJsonScalarExpr(ParseState *pstate, JsonScalarExpr *jsexpr) { - JsonReturning *returning = makeNode(JsonReturning); Node *arg = transformExprRecurse(pstate, (Node *) jsexpr->expr); - - returning->format = makeJsonFormat(JS_FORMAT_JSON, JS_ENC_DEFAULT, -1); - returning->typid = JSONOID; - returning->typmod = -1; + JsonReturning *returning = transformJsonConstructorRet(pstate, jsexpr->output, + "JSON_SCALAR()"); if (exprType(arg) == UNKNOWNOID) arg = coerce_to_specific_type(pstate, arg, TEXTOID, "JSON_SCALAR"); diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c index 060fd7e183..fe1627dedc 100644 --- a/src/backend/utils/adt/format_type.c +++ b/src/backend/utils/adt/format_type.c @@ -23,6 +23,7 @@ #include "mb/pg_wchar.h" #include "utils/builtins.h" #include "utils/fmgroids.h" +#include "utils/jsonb.h" #include "utils/lsyscache.h" #include "utils/numeric.h" #include "utils/syscache.h" @@ -296,7 +297,11 @@ format_type_extended(Oid type_oid, int32 typemod, bits16 flags) break; case JSONOID: - buf = pstrdup("json"); + buf = pstrdup(SQLJSON_TYPE_IS_JSONB() ? "pg_catalog.json" : "json"); + break; + + case JSONBOID: + buf = pstrdup(SQLJSON_TYPE_IS_JSONB() ? "json" : "jsonb"); break; } diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c index 2043f2e74a..9089b3b22e 100644 --- a/src/backend/utils/adt/jsonb.c +++ b/src/backend/utils/adt/jsonb.c @@ -69,6 +69,8 @@ static JsonbParseState *clone_parse_state(JsonbParseState *state); static char *JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len, bool indent); static void add_indent(StringInfo out, bool indent, int level); +int sql_json_type; /* GUC for mapping jsonb to SQL/JSON JSON */ + /* * jsonb type input function */ diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index bbdadfb1d7..45e2b8ab62 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -63,6 +63,7 @@ #include "utils/fmgroids.h" #include "utils/guc.h" #include "utils/hsearch.h" +#include "utils/jsonb.h" #include "utils/lsyscache.h" #include "utils/partcache.h" #include "utils/rel.h" @@ -10043,8 +10044,9 @@ get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf) if (ctor->unique) appendStringInfoString(buf, " WITH UNIQUE KEYS"); - if (ctor->type != JSCTOR_JSON_PARSE && - ctor->type != JSCTOR_JSON_SCALAR) + if (!((ctor->type == JSCTOR_JSON_PARSE || + ctor->type == JSCTOR_JSON_SCALAR) && + ctor->returning->typid == SQLJSON_TYPE_OID())) get_json_returning(ctor->returning, buf, true); } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 4c94f09c64..1e36b5b4ac 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -97,6 +97,7 @@ #include "utils/bytea.h" #include "utils/float.h" #include "utils/guc_tables.h" +#include "utils/jsonb.h" #include "utils/memutils.h" #include "utils/pg_locale.h" #include "utils/pg_lsn.h" @@ -558,6 +559,12 @@ static const struct config_enum_entry wal_compression_options[] = { {NULL, 0, false} }; +const struct config_enum_entry sql_json_type_info[] = { + {"json", SQLJSON_TYPE_JSON, false}, + {"jsonb", SQLJSON_TYPE_JSONB, false}, + {NULL, 0, false} +}; + /* * Options for enum values stored in other modules */ @@ -5025,6 +5032,18 @@ static struct config_enum ConfigureNamesEnum[] = NULL, NULL, NULL }, + { + {"sql_json", PGC_USERSET, COMPAT_OPTIONS_CLIENT, + gettext_noop("Sets what PostgreSQL type to use as an implementaion of SQL JSON type."), + gettext_noop("When turned on, jsonb type is mapped to SQL JSON type, " + "json type is mapped to JSON TEXT type.") + }, + &sql_json_type, + SQLJSON_TYPE_JSON, + sql_json_type_info, + NULL, NULL, NULL + }, + /* End-of-list marker */ { {NULL, 0, 0, NULL, NULL}, NULL, 0, NULL, NULL, NULL, NULL diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 817d5f5324..72b54a4da9 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -768,6 +768,7 @@ # - Other Platforms and Clients - #transform_null_equals = off +#sql_json = json # jsonb #------------------------------------------------------------------------------ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 6ec1662315..27ec40dd7f 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1643,6 +1643,7 @@ typedef struct JsonParseExpr { NodeTag type; JsonValueExpr *expr; /* string expression */ + JsonOutput *output; /* RETURNING clause, if specified */ bool unique_keys; /* WITH UNIQUE KEYS? */ int location; /* token location, or -1 if unknown */ } JsonParseExpr; @@ -1655,6 +1656,7 @@ typedef struct JsonScalarExpr { NodeTag type; Expr *expr; /* scalar expression */ + JsonOutput *output; /* RETURNING clause, if specified */ int location; /* token location, or -1 if unknown */ } JsonScalarExpr; diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h index bae466b523..7534c2e7d1 100644 --- a/src/include/utils/jsonb.h +++ b/src/include/utils/jsonb.h @@ -393,6 +393,20 @@ typedef enum /* type categories for datum_to_jsonb */ JSONBTYPE_OTHER /* all else */ } JsonbTypeCategory; +/* values for the sql+json_type GUC. */ +typedef enum SqlJsonType +{ + SQLJSON_TYPE_JSON = 0, + SQLJSON_TYPE_JSONB = 1 +} SqlJsonType; + +#define SQLJSON_TYPE_IS_JSONB() (sql_json_type == SQLJSON_TYPE_JSONB) +#define SQLJSON_TYPE_OID() (SQLJSON_TYPE_IS_JSONB() ? JSONBOID : JSONOID) +#define SQLJSON_TYPE_NAME() (SQLJSON_TYPE_IS_JSONB() ? "jsonb" : "json") + +/* GUC */ +extern int sql_json_type; + /* Support functions */ extern uint32 getJsonbOffset(const JsonbContainer *jc, int index); extern uint32 getJsonbLength(const JsonbContainer *jc, int index); diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out index a9cd145aec..905b50e850 100644 --- a/src/test/regress/expected/jsonb.out +++ b/src/test/regress/expected/jsonb.out @@ -5509,3 +5509,133 @@ select '12345.0000000000000000000000000000000000000000000005'::jsonb::int8; 12345 (1 row) +-- test mapping of jsonb to SQL/JSON JSON type +select json(' { "aa": 1, "b" : 2 }'); + json +----------------------- + { "aa": 1, "b" : 2 } +(1 row) + +select json ' { "aa": 1, "b" : 2 }'; + json +----------------------- + { "aa": 1, "b" : 2 } +(1 row) + +select pg_catalog.json ' { "aa": 1, "b" : 2 }'; + json +----------------------- + { "aa": 1, "b" : 2 } +(1 row) + +create table test_json_as_json (js json, jb jsonb); +\d test_json_as_json + Table "public.test_json_as_json" + Column | Type | Collation | Nullable | Default +--------+-------+-----------+----------+--------- + js | json | | | + jb | jsonb | | | + +set sql_json = jsonb; +select json(' { "aa": 1, "b" : 2 }'); + json +------------------- + {"b": 2, "aa": 1} +(1 row) + +select json ' { "aa": 1, "b" : 2 }'; + jsonb +------------------- + {"b": 2, "aa": 1} +(1 row) + +select pg_catalog.json ' { "aa": 1, "b" : 2 }'; + json +----------------------- + { "aa": 1, "b" : 2 } +(1 row) + +\d test_json_as_json + Table "public.test_json_as_json" + Column | Type | Collation | Nullable | Default +--------+-----------------+-----------+----------+--------- + js | pg_catalog.json | | | + jb | json | | | + +create table test_json_as_jsonb (js json, jb jsonb, jt pg_catalog.json); +\d test_json_as_jsonb + Table "public.test_json_as_jsonb" + Column | Type | Collation | Nullable | Default +--------+-----------------+-----------+----------+--------- + js | json | | | + jb | json | | | + jt | pg_catalog.json | | | + +insert into test_json_as_jsonb values ('{ "a" : 1 }', '{ "a" : 1 }', '{ "a" : 1 }'); +select * from test_json_as_jsonb; + js | jb | jt +----------+----------+------------- + {"a": 1} | {"a": 1} | { "a" : 1 } +(1 row) + +select jsonb_object_field(js, 'a') from test_json_as_jsonb; + jsonb_object_field +-------------------- + 1 +(1 row) + +select jsonb_object_field(jb, 'a') from test_json_as_jsonb; + jsonb_object_field +-------------------- + 1 +(1 row) + +select jsonb_object_field(jt, 'a') from test_json_as_jsonb; +ERROR: function jsonb_object_field(pg_catalog.json, unknown) does not exist +LINE 1: select jsonb_object_field(jt, 'a') from test_json_as_jsonb; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +select json_object_field(jt, 'a') from test_json_as_jsonb; + json_object_field +------------------- + 1 +(1 row) + +set sql_json = json; +\d test_json_as_jsonb + Table "public.test_json_as_jsonb" + Column | Type | Collation | Nullable | Default +--------+-------+-----------+----------+--------- + js | jsonb | | | + jb | jsonb | | | + jt | json | | | + +select * from test_json_as_jsonb; + js | jb | jt +----------+----------+------------- + {"a": 1} | {"a": 1} | { "a" : 1 } +(1 row) + +select jsonb_object_field(js, 'a') from test_json_as_jsonb; + jsonb_object_field +-------------------- + 1 +(1 row) + +select jsonb_object_field(jb, 'a') from test_json_as_jsonb; + jsonb_object_field +-------------------- + 1 +(1 row) + +select jsonb_object_field(jt, 'a') from test_json_as_jsonb; +ERROR: function jsonb_object_field(json, unknown) does not exist +LINE 1: select jsonb_object_field(jt, 'a') from test_json_as_jsonb; + ^ +HINT: No function matches the given name and argument types. You might need to add explicit type casts. +select json_object_field(jt, 'a') from test_json_as_jsonb; + json_object_field +------------------- + 1 +(1 row) + diff --git a/src/test/regress/expected/sqljson.out b/src/test/regress/expected/sqljson.out index 11f5eb2d2c..51bd216120 100644 --- a/src/test/regress/expected/sqljson.out +++ b/src/test/regress/expected/sqljson.out @@ -113,6 +113,103 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' WITHOUT UNIQUE KEYS); Output: JSON('123'::json) (2 rows) +SELECT JSON('123' RETURNING text); +ERROR: cannot use RETURNING type text in JSON() +LINE 1: SELECT JSON('123' RETURNING text); + ^ +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'); + QUERY PLAN +----------------------------- + Result + Output: JSON('123'::json) +(2 rows) + +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING json); + QUERY PLAN +----------------------------- + Result + Output: JSON('123'::json) +(2 rows) + +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING jsonb); + QUERY PLAN +---------------------------------------------- + Result + Output: JSON('123'::jsonb RETURNING jsonb) +(2 rows) + +SELECT pg_typeof(JSON('123')); + pg_typeof +----------- + json +(1 row) + +SELECT pg_typeof(JSON('123' RETURNING json)); + pg_typeof +----------- + json +(1 row) + +SELECT pg_typeof(JSON('123' RETURNING jsonb)); + pg_typeof +----------- + jsonb +(1 row) + +SET sql_json = jsonb; +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'); + QUERY PLAN +----------------------------- + Result + Output: JSON('123'::json) +(2 rows) + +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING json); + QUERY PLAN +----------------------------- + Result + Output: JSON('123'::json) +(2 rows) + +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING jsonb); + QUERY PLAN +----------------------------- + Result + Output: JSON('123'::json) +(2 rows) + +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING pg_catalog.json); + QUERY PLAN +------------------------------------------------------------------ + Result + Output: JSON('123'::pg_catalog.json RETURNING pg_catalog.json) +(2 rows) + +SELECT pg_typeof(JSON('123')); + pg_typeof +----------- + json +(1 row) + +SELECT pg_typeof(JSON('123' RETURNING json)); + pg_typeof +----------- + json +(1 row) + +SELECT pg_typeof(JSON('123' RETURNING jsonb)); + pg_typeof +----------- + json +(1 row) + +SELECT pg_typeof(JSON('123' RETURNING pg_catalog.json)); + pg_typeof +----------------- + pg_catalog.json +(1 row) + +SET sql_json = json; -- JSON_SCALAR() SELECT JSON_SCALAR(); ERROR: syntax error at or near ")" @@ -204,6 +301,50 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR('123'); Output: JSON_SCALAR('123'::text) (2 rows) +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING json); + QUERY PLAN +---------------------------- + Result + Output: JSON_SCALAR(123) +(2 rows) + +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING jsonb); + QUERY PLAN +-------------------------------------------- + Result + Output: JSON_SCALAR(123 RETURNING jsonb) +(2 rows) + +SET sql_json = jsonb; +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123); + QUERY PLAN +---------------------------- + Result + Output: JSON_SCALAR(123) +(2 rows) + +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING json); + QUERY PLAN +---------------------------- + Result + Output: JSON_SCALAR(123) +(2 rows) + +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING jsonb); + QUERY PLAN +---------------------------- + Result + Output: JSON_SCALAR(123) +(2 rows) + +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING pg_catalog.json); + QUERY PLAN +------------------------------------------------------ + Result + Output: JSON_SCALAR(123 RETURNING pg_catalog.json) +(2 rows) + +SET sql_json = json; -- JSON_SERIALIZE() SELECT JSON_SERIALIZE(); ERROR: syntax error at or near ")" diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql index 5016f29c15..4af2a0cb11 100644 --- a/src/test/regress/sql/jsonb.sql +++ b/src/test/regress/sql/jsonb.sql @@ -1482,3 +1482,41 @@ select '12345.0000000000000000000000000000000000000000000005'::jsonb::float8; select '12345.0000000000000000000000000000000000000000000005'::jsonb::int2; select '12345.0000000000000000000000000000000000000000000005'::jsonb::int4; select '12345.0000000000000000000000000000000000000000000005'::jsonb::int8; + +-- test mapping of jsonb to SQL/JSON JSON type +select json(' { "aa": 1, "b" : 2 }'); +select json ' { "aa": 1, "b" : 2 }'; +select pg_catalog.json ' { "aa": 1, "b" : 2 }'; + +create table test_json_as_json (js json, jb jsonb); +\d test_json_as_json + +set sql_json = jsonb; + +select json(' { "aa": 1, "b" : 2 }'); +select json ' { "aa": 1, "b" : 2 }'; +select pg_catalog.json ' { "aa": 1, "b" : 2 }'; + +\d test_json_as_json + +create table test_json_as_jsonb (js json, jb jsonb, jt pg_catalog.json); +\d test_json_as_jsonb + +insert into test_json_as_jsonb values ('{ "a" : 1 }', '{ "a" : 1 }', '{ "a" : 1 }'); + +select * from test_json_as_jsonb; + +select jsonb_object_field(js, 'a') from test_json_as_jsonb; +select jsonb_object_field(jb, 'a') from test_json_as_jsonb; +select jsonb_object_field(jt, 'a') from test_json_as_jsonb; +select json_object_field(jt, 'a') from test_json_as_jsonb; + +set sql_json = json; +\d test_json_as_jsonb + +select * from test_json_as_jsonb; + +select jsonb_object_field(js, 'a') from test_json_as_jsonb; +select jsonb_object_field(jb, 'a') from test_json_as_jsonb; +select jsonb_object_field(jt, 'a') from test_json_as_jsonb; +select json_object_field(jt, 'a') from test_json_as_jsonb; diff --git a/src/test/regress/sql/sqljson.sql b/src/test/regress/sql/sqljson.sql index 98bd93c110..4ff6076763 100644 --- a/src/test/regress/sql/sqljson.sql +++ b/src/test/regress/sql/sqljson.sql @@ -23,6 +23,27 @@ EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'::bytea FORMAT JSON ENCODING UTF8) EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' WITH UNIQUE KEYS); EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' WITHOUT UNIQUE KEYS); +SELECT JSON('123' RETURNING text); + +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'); +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING json); +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING jsonb); +SELECT pg_typeof(JSON('123')); +SELECT pg_typeof(JSON('123' RETURNING json)); +SELECT pg_typeof(JSON('123' RETURNING jsonb)); + +SET sql_json = jsonb; + +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123'); +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING json); +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING jsonb); +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON('123' RETURNING pg_catalog.json); +SELECT pg_typeof(JSON('123')); +SELECT pg_typeof(JSON('123' RETURNING json)); +SELECT pg_typeof(JSON('123' RETURNING jsonb)); +SELECT pg_typeof(JSON('123' RETURNING pg_catalog.json)); + +SET sql_json = json; -- JSON_SCALAR() SELECT JSON_SCALAR(); @@ -41,6 +62,17 @@ SELECT JSON_SCALAR('{}'::jsonb); EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123); EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR('123'); +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING json); +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING jsonb); + +SET sql_json = jsonb; + +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123); +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING json); +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING jsonb); +EXPLAIN (VERBOSE, COSTS OFF) SELECT JSON_SCALAR(123 RETURNING pg_catalog.json); + +SET sql_json = json; -- JSON_SERIALIZE() SELECT JSON_SERIALIZE(); -- 2.31.1