From 1bbb72929d80977b0f3d977a3e4f98d9786f78db Mon Sep 17 00:00:00 2001
From: Amit Langote <amitlan@postgresql.org>
Date: Thu, 20 Jun 2024 17:49:56 +0900
Subject: [PATCH v1] SQL/JSON: Only allow arguments of jsonb type

Currently, functions JSON_QUERY(), JSON_VALUE(), JSON_EXISTS(),
and JSON_TABLE() allow users to specify arguments of character
string types or bytea which are implicitly cast to jsonb.  Any
errors that may occur from such coercion are always thrown, which
Markus Winand pointed out do not get ON ERROR treatment.

So, instead require the users to cast the argument to jsonb to make
it clear that transparent JSON parsing is not supported.

Reported-by: Markus Winand
Discussion: https://postgr.es/m/F7DD1442-265C-4220-A603-CB0DEB77E91D%40winand.at
---
 doc/src/sgml/func.sgml                        |  8 +++
 src/backend/catalog/sql_features.txt          |  4 +-
 src/backend/parser/parse_expr.c               | 16 +++---
 .../regress/expected/sqljson_jsontable.out    | 30 ++++++----
 .../regress/expected/sqljson_queryfuncs.out   | 57 ++++++++++---------
 src/test/regress/sql/sqljson_jsontable.sql    | 17 +++---
 src/test/regress/sql/sqljson_queryfuncs.sql   | 27 ++++-----
 7 files changed, 90 insertions(+), 69 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 4ebf4b3ed8..c1479b11f2 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -18671,6 +18671,14 @@ $.* ? (@ like_regex "^\\d+$")
    <replaceable>path_expression</replaceable> can contain.
   </para>
 
+  <note>
+   <para>
+    SQL/JSON paths can only be applied to the <type>jsonb</type> type, so it
+    might be necessary to cast the <replaceable>context_item</replaceable>
+    argument of these functions to <type>jsonb</type>.
+   </para>
+  </note>
+
   <table id="functions-sqljson-querying">
    <title>SQL/JSON Query Functions</title>
    <tgroup cols="1">
diff --git a/src/backend/catalog/sql_features.txt b/src/backend/catalog/sql_features.txt
index c002f37202..cc9bf67a46 100644
--- a/src/backend/catalog/sql_features.txt
+++ b/src/backend/catalog/sql_features.txt
@@ -547,14 +547,14 @@ T811	Basic SQL/JSON constructor functions			YES
 T812	SQL/JSON: JSON_OBJECTAGG			YES	
 T813	SQL/JSON: JSON_ARRAYAGG with ORDER BY			YES	
 T814	Colon in JSON_OBJECT or JSON_OBJECTAGG			YES	
-T821	Basic SQL/JSON query operators			YES	
+T821	Basic SQL/JSON query operators			YES	only jsonb arguments supported
 T822	SQL/JSON: IS JSON WITH UNIQUE KEYS predicate			YES	
 T823	SQL/JSON: PASSING clause			YES	
 T824	JSON_TABLE: specific PLAN clause			NO	
 T825	SQL/JSON: ON EMPTY and ON ERROR clauses			YES	
 T826	General value expression in ON ERROR or ON EMPTY clauses			YES	
 T827	JSON_TABLE: sibling NESTED COLUMNS clauses			YES	
-T828	JSON_QUERY			YES	
+T828	JSON_QUERY			YES	only jsonb arguments supported
 T829	JSON_QUERY: array wrapper options			YES	
 T830	Enforcing unique keys in SQL/JSON constructor functions			YES	
 T831	SQL/JSON path language: strict mode			YES	
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index a82621fa67..67e3730e5f 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -4265,29 +4265,23 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
 	JsonExpr   *jsexpr;
 	Node	   *path_spec;
 	const char *func_name = NULL;
-	JsonFormatType default_format;
 
 	switch (func->op)
 	{
 		case JSON_EXISTS_OP:
 			func_name = "JSON_EXISTS";
-			default_format = JS_FORMAT_DEFAULT;
 			break;
 		case JSON_QUERY_OP:
 			func_name = "JSON_QUERY";
-			default_format = JS_FORMAT_JSONB;
 			break;
 		case JSON_VALUE_OP:
 			func_name = "JSON_VALUE";
-			default_format = JS_FORMAT_DEFAULT;
 			break;
 		case JSON_TABLE_OP:
 			func_name = "JSON_TABLE";
-			default_format = JS_FORMAT_JSONB;
 			break;
 		default:
 			elog(ERROR, "invalid JsonFuncExpr op %d", (int) func->op);
-			default_format = JS_FORMAT_DEFAULT; /* keep compiler quiet */
 			break;
 	}
 
@@ -4330,9 +4324,15 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
 	 */
 	jsexpr->formatted_expr = transformJsonValueExpr(pstate, func_name,
 													func->context_item,
-													default_format,
-													JSONBOID,
+													JS_FORMAT_DEFAULT,
+													InvalidOid,
 													false);
+	if (exprType(jsexpr->formatted_expr) != JSONBOID)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("%s() only accepts arguments of jsonb type", func_name),
+				 errhint("Try casting the argument to jsonb"),
+				parser_errposition(pstate, func->location)));
 	jsexpr->format = func->context_item->format;
 
 	path_spec = transformExprRecurse(pstate, func->pathspec);
diff --git a/src/test/regress/expected/sqljson_jsontable.out b/src/test/regress/expected/sqljson_jsontable.out
index 3b70ed9548..c3fc5c0ba9 100644
--- a/src/test/regress/expected/sqljson_jsontable.out
+++ b/src/test/regress/expected/sqljson_jsontable.out
@@ -1,26 +1,26 @@
 -- JSON_TABLE
 -- Should fail (JSON_TABLE can be used only in FROM clause)
-SELECT JSON_TABLE('[]', '$');
+SELECT JSON_TABLE(jsonb '[]', '$');
 ERROR:  syntax error at or near "("
-LINE 1: SELECT JSON_TABLE('[]', '$');
+LINE 1: SELECT JSON_TABLE(jsonb '[]', '$');
                          ^
 -- Only allow EMPTY and ERROR for ON ERROR
-SELECT * FROM JSON_TABLE('[]', 'strict $.a' COLUMNS (js2 int PATH '$') DEFAULT 1 ON ERROR);
+SELECT * FROM JSON_TABLE(jsonb '[]', 'strict $.a' COLUMNS (js2 int PATH '$') DEFAULT 1 ON ERROR);
 ERROR:  invalid ON ERROR behavior
-LINE 1: ...BLE('[]', 'strict $.a' COLUMNS (js2 int PATH '$') DEFAULT 1 ...
+LINE 1: ...onb '[]', 'strict $.a' COLUMNS (js2 int PATH '$') DEFAULT 1 ...
                                                              ^
 DETAIL:  Only EMPTY or ERROR is allowed in the top-level ON ERROR clause.
-SELECT * FROM JSON_TABLE('[]', 'strict $.a' COLUMNS (js2 int PATH '$') NULL ON ERROR);
+SELECT * FROM JSON_TABLE(jsonb '[]', 'strict $.a' COLUMNS (js2 int PATH '$') NULL ON ERROR);
 ERROR:  invalid ON ERROR behavior
-LINE 1: ...BLE('[]', 'strict $.a' COLUMNS (js2 int PATH '$') NULL ON ER...
+LINE 1: ...onb '[]', 'strict $.a' COLUMNS (js2 int PATH '$') NULL ON ER...
                                                              ^
 DETAIL:  Only EMPTY or ERROR is allowed in the top-level ON ERROR clause.
-SELECT * FROM JSON_TABLE('[]', 'strict $.a' COLUMNS (js2 int PATH '$') EMPTY ON ERROR);
+SELECT * FROM JSON_TABLE(jsonb '[]', 'strict $.a' COLUMNS (js2 int PATH '$') EMPTY ON ERROR);
  js2 
 -----
 (0 rows)
 
-SELECT * FROM JSON_TABLE('[]', 'strict $.a' COLUMNS (js2 int PATH '$') ERROR ON ERROR);
+SELECT * FROM JSON_TABLE(jsonb '[]', 'strict $.a' COLUMNS (js2 int PATH '$') ERROR ON ERROR);
 ERROR:  jsonpath member accessor can only be applied to an object
 -- Column and path names must be distinct
 SELECT * FROM JSON_TABLE(jsonb'"1.23"', '$.a' as js2 COLUMNS (js2 int path '$'));
@@ -28,10 +28,10 @@ ERROR:  duplicate JSON_TABLE column or path name: js2
 LINE 1: ...M JSON_TABLE(jsonb'"1.23"', '$.a' as js2 COLUMNS (js2 int pa...
                                                              ^
 -- Should fail (no columns)
-SELECT * FROM JSON_TABLE(NULL, '$' COLUMNS ());
+SELECT * FROM JSON_TABLE(NULL::jsonb, '$' COLUMNS ());
 ERROR:  syntax error at or near ")"
-LINE 1: SELECT * FROM JSON_TABLE(NULL, '$' COLUMNS ());
-                                                    ^
+LINE 1: SELECT * FROM JSON_TABLE(NULL::jsonb, '$' COLUMNS ());
+                                                           ^
 SELECT * FROM JSON_TABLE (NULL::jsonb, '$' COLUMNS (v1 timestamp)) AS f (v1, v2);
 ERROR:  JSON_TABLE function has 1 columns available but 2 columns specified
 --duplicated column name
@@ -670,7 +670,7 @@ ERROR:  only string constants are supported in JSON_TABLE path specification
 LINE 1: SELECT * FROM JSON_TABLE(jsonb '{"a": 123}', '$' || '.' || '...
                                                      ^
 -- JsonPathQuery() error message mentioning column name
-SELECT * FROM JSON_TABLE('{"a": [{"b": "1"}, {"b": "2"}]}', '$' COLUMNS (b json path '$.a[*].b' ERROR ON ERROR));
+SELECT * FROM JSON_TABLE(jsonb '{"a": [{"b": "1"}, {"b": "2"}]}', '$' COLUMNS (b json path '$.a[*].b' ERROR ON ERROR));
 ERROR:  JSON path expression for column "b" should return single item without wrapper
 HINT:  Use WITH WRAPPER clause to wrap SQL/JSON items into array.
 -- JSON_TABLE: nested paths
@@ -1067,3 +1067,9 @@ CREATE OR REPLACE VIEW public.jsonb_table_view7 AS
         ) sub
 DROP VIEW jsonb_table_view7;
 DROP TABLE s;
+-- Only jsonb arguments are supported currently
+SELECT * FROM JSON_TABLE('[]', '$' COLUMNS(a int));
+ERROR:  JSON_TABLE() only accepts arguments of jsonb type
+LINE 1: SELECT * FROM JSON_TABLE('[]', '$' COLUMNS(a int));
+                      ^
+HINT:  Try casting the argument to jsonb
diff --git a/src/test/regress/expected/sqljson_queryfuncs.out b/src/test/regress/expected/sqljson_queryfuncs.out
index 6ca5674cef..df02aa08ef 100644
--- a/src/test/regress/expected/sqljson_queryfuncs.out
+++ b/src/test/regress/expected/sqljson_queryfuncs.out
@@ -532,9 +532,9 @@ SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +
 (1 row)
 
 -- Test that numeric JSON values are coerced uniformly
-select json_value('{"a": 1.234}', '$.a' returning int error on error);
+select json_value(jsonb '{"a": 1.234}', '$.a' returning int error on error);
 ERROR:  invalid input syntax for type integer: "1.234"
-select json_value('{"a": "1.234"}', '$.a' returning int error on error);
+select json_value(jsonb '{"a": "1.234"}', '$.a' returning int error on error);
 ERROR:  invalid input syntax for type integer: "1.234"
 -- JSON_QUERY
 SELECT JSON_VALUE(NULL::jsonb, '$');
@@ -1258,36 +1258,36 @@ SELECT JSON_VALUE(jsonb '{"d1": "foo"}', '$.a2' RETURNING queryfuncs_test_domain
 -- Check the cases where a coercion-related expression is masking an
 -- unsupported expressions
 -- CoerceViaIO
-SELECT JSON_QUERY('"a"', '$.a'  RETURNING int DEFAULT (SELECT '"1"')::jsonb ON ERROR);
+SELECT JSON_QUERY(jsonb '"a"', '$.a'  RETURNING int DEFAULT (SELECT '"1"')::jsonb ON ERROR);
 ERROR:  can only specify a constant, non-aggregate function, or operator expression for DEFAULT
-LINE 1: ...CT JSON_QUERY('"a"', '$.a'  RETURNING int DEFAULT (SELECT '"...
+LINE 1: ...N_QUERY(jsonb '"a"', '$.a'  RETURNING int DEFAULT (SELECT '"...
                                                              ^
 -- CoerceToDomain
-SELECT JSON_QUERY('"a"', '$.a' RETURNING queryfuncs_test_domain DEFAULT (select '"1"')::queryfuncs_test_domain ON ERROR);
+SELECT JSON_QUERY(jsonb '"a"', '$.a' RETURNING queryfuncs_test_domain DEFAULT (select '"1"')::queryfuncs_test_domain ON ERROR);
 ERROR:  can only specify a constant, non-aggregate function, or operator expression for DEFAULT
 LINE 1: ...', '$.a' RETURNING queryfuncs_test_domain DEFAULT (select '"...
                                                              ^
 -- RelabelType
-SELECT JSON_QUERY('"a"', '$.a'  RETURNING int DEFAULT (SELECT 1)::oid::int ON ERROR);
+SELECT JSON_QUERY(jsonb '"a"', '$.a'  RETURNING int DEFAULT (SELECT 1)::oid::int ON ERROR);
 ERROR:  can only specify a constant, non-aggregate function, or operator expression for DEFAULT
-LINE 1: ...CT JSON_QUERY('"a"', '$.a'  RETURNING int DEFAULT (SELECT 1)...
+LINE 1: ...N_QUERY(jsonb '"a"', '$.a'  RETURNING int DEFAULT (SELECT 1)...
                                                              ^
 -- ArrayCoerceExpr
-SELECT JSON_QUERY('"a"', '$.a'  RETURNING int[] DEFAULT (SELECT '{1}')::oid[]::int[] ON ERROR);
+SELECT JSON_QUERY(jsonb '"a"', '$.a'  RETURNING int[] DEFAULT (SELECT '{1}')::oid[]::int[] ON ERROR);
 ERROR:  can only specify a constant, non-aggregate function, or operator expression for DEFAULT
-LINE 1: ... JSON_QUERY('"a"', '$.a'  RETURNING int[] DEFAULT (SELECT '{...
+LINE 1: ...QUERY(jsonb '"a"', '$.a'  RETURNING int[] DEFAULT (SELECT '{...
                                                              ^
 -- CollateExpr
-SELECT JSON_QUERY('"a"', '$.a'  RETURNING int[] DEFAULT (SELECT '{1}')::text COLLATE "C" ON ERROR);
+SELECT JSON_QUERY(jsonb '"a"', '$.a'  RETURNING int[] DEFAULT (SELECT '{1}')::text COLLATE "C" ON ERROR);
 ERROR:  can only specify a constant, non-aggregate function, or operator expression for DEFAULT
-LINE 1: ... JSON_QUERY('"a"', '$.a'  RETURNING int[] DEFAULT (SELECT '{...
+LINE 1: ...QUERY(jsonb '"a"', '$.a'  RETURNING int[] DEFAULT (SELECT '{...
                                                              ^
 -- ConvertRowtypeExpr
 CREATE TABLE someparent (a int);
 CREATE TABLE somechild () INHERITS (someparent);
-SELECT JSON_QUERY('"a"', '$.a'  RETURNING someparent DEFAULT (SELECT '(1)')::somechild::someparent ON ERROR);
+SELECT JSON_QUERY(jsonb '"a"', '$.a'  RETURNING someparent DEFAULT (SELECT '(1)')::somechild::someparent ON ERROR);
 ERROR:  can only specify a constant, non-aggregate function, or operator expression for DEFAULT
-LINE 1: ..._QUERY('"a"', '$.a'  RETURNING someparent DEFAULT (SELECT '(...
+LINE 1: ...(jsonb '"a"', '$.a'  RETURNING someparent DEFAULT (SELECT '(...
                                                              ^
 DROP DOMAIN queryfuncs_test_domain;
 DROP TABLE someparent, somechild;
@@ -1325,22 +1325,9 @@ SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a' WITH WRAPPER);
 -- Should fail (invalid path)
 SELECT JSON_QUERY(jsonb '{"a": 123}', 'error' || ' ' || 'error');
 ERROR:  syntax error at or near " " of jsonpath input
--- Non-jsonb inputs automatically coerced to jsonb
-SELECT JSON_EXISTS(json '{"a": 123}', '$' || '.' || 'a');
- json_exists 
--------------
- t
-(1 row)
-
-SELECT JSON_QUERY(NULL FORMAT JSON, '$');
- json_query 
-------------
- 
-(1 row)
-
 -- Test non-const jsonpath
 CREATE TEMP TABLE jsonpaths (path) AS SELECT '$';
-SELECT json_value('"aaa"', path RETURNING json) FROM jsonpaths;
+SELECT json_value(jsonb '"aaa"', path RETURNING json) FROM jsonpaths;
  json_value 
 ------------
  "aaa"
@@ -1357,3 +1344,19 @@ SELECT JSON_QUERY(jsonb 'null', '$xyz' PASSING 1 AS xyz);
  1
 (1 row)
 
+-- Only jsonb arguments are supported currently
+SELECT JSON_EXISTS(NULL, '$');
+ERROR:  JSON_EXISTS() only accepts arguments of jsonb type
+LINE 1: SELECT JSON_EXISTS(NULL, '$');
+               ^
+HINT:  Try casting the argument to jsonb
+SELECT JSON_QUERY('1', '$');
+ERROR:  JSON_QUERY() only accepts arguments of jsonb type
+LINE 1: SELECT JSON_QUERY('1', '$');
+               ^
+HINT:  Try casting the argument to jsonb
+SELECT JSON_VALUE('aaa', '$');
+ERROR:  JSON_VALUE() only accepts arguments of jsonb type
+LINE 1: SELECT JSON_VALUE('aaa', '$');
+               ^
+HINT:  Try casting the argument to jsonb
diff --git a/src/test/regress/sql/sqljson_jsontable.sql b/src/test/regress/sql/sqljson_jsontable.sql
index a1f924146e..c956f90c5e 100644
--- a/src/test/regress/sql/sqljson_jsontable.sql
+++ b/src/test/regress/sql/sqljson_jsontable.sql
@@ -1,19 +1,19 @@
 -- JSON_TABLE
 
 -- Should fail (JSON_TABLE can be used only in FROM clause)
-SELECT JSON_TABLE('[]', '$');
+SELECT JSON_TABLE(jsonb '[]', '$');
 
 -- Only allow EMPTY and ERROR for ON ERROR
-SELECT * FROM JSON_TABLE('[]', 'strict $.a' COLUMNS (js2 int PATH '$') DEFAULT 1 ON ERROR);
-SELECT * FROM JSON_TABLE('[]', 'strict $.a' COLUMNS (js2 int PATH '$') NULL ON ERROR);
-SELECT * FROM JSON_TABLE('[]', 'strict $.a' COLUMNS (js2 int PATH '$') EMPTY ON ERROR);
-SELECT * FROM JSON_TABLE('[]', 'strict $.a' COLUMNS (js2 int PATH '$') ERROR ON ERROR);
+SELECT * FROM JSON_TABLE(jsonb '[]', 'strict $.a' COLUMNS (js2 int PATH '$') DEFAULT 1 ON ERROR);
+SELECT * FROM JSON_TABLE(jsonb '[]', 'strict $.a' COLUMNS (js2 int PATH '$') NULL ON ERROR);
+SELECT * FROM JSON_TABLE(jsonb '[]', 'strict $.a' COLUMNS (js2 int PATH '$') EMPTY ON ERROR);
+SELECT * FROM JSON_TABLE(jsonb '[]', 'strict $.a' COLUMNS (js2 int PATH '$') ERROR ON ERROR);
 
 -- Column and path names must be distinct
 SELECT * FROM JSON_TABLE(jsonb'"1.23"', '$.a' as js2 COLUMNS (js2 int path '$'));
 
 -- Should fail (no columns)
-SELECT * FROM JSON_TABLE(NULL, '$' COLUMNS ());
+SELECT * FROM JSON_TABLE(NULL::jsonb, '$' COLUMNS ());
 
 SELECT * FROM JSON_TABLE (NULL::jsonb, '$' COLUMNS (v1 timestamp)) AS f (v1, v2);
 
@@ -307,7 +307,7 @@ FROM JSON_TABLE(
 SELECT * FROM JSON_TABLE(jsonb '{"a": 123}', '$' || '.' || 'a' COLUMNS (foo int));
 
 -- JsonPathQuery() error message mentioning column name
-SELECT * FROM JSON_TABLE('{"a": [{"b": "1"}, {"b": "2"}]}', '$' COLUMNS (b json path '$.a[*].b' ERROR ON ERROR));
+SELECT * FROM JSON_TABLE(jsonb '{"a": [{"b": "1"}, {"b": "2"}]}', '$' COLUMNS (b json path '$.a[*].b' ERROR ON ERROR));
 
 -- JSON_TABLE: nested paths
 
@@ -518,3 +518,6 @@ SELECT sub.* FROM s,
 \sv jsonb_table_view7
 DROP VIEW jsonb_table_view7;
 DROP TABLE s;
+
+-- Only jsonb arguments are supported currently
+SELECT * FROM JSON_TABLE('[]', '$' COLUMNS(a int));
diff --git a/src/test/regress/sql/sqljson_queryfuncs.sql b/src/test/regress/sql/sqljson_queryfuncs.sql
index 919ab7e651..fdd6903f7f 100644
--- a/src/test/regress/sql/sqljson_queryfuncs.sql
+++ b/src/test/regress/sql/sqljson_queryfuncs.sql
@@ -138,8 +138,8 @@ SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +
 SELECT JSON_VALUE(jsonb 'null', '$ts' PASSING timestamptz '2018-02-21 12:34:56 +10' AS ts RETURNING jsonb);
 
 -- Test that numeric JSON values are coerced uniformly
-select json_value('{"a": 1.234}', '$.a' returning int error on error);
-select json_value('{"a": "1.234"}', '$.a' returning int error on error);
+select json_value(jsonb '{"a": 1.234}', '$.a' returning int error on error);
+select json_value(jsonb '{"a": "1.234"}', '$.a' returning int error on error);
 
 -- JSON_QUERY
 
@@ -423,19 +423,19 @@ SELECT JSON_VALUE(jsonb '{"d1": "foo"}', '$.a2' RETURNING queryfuncs_test_domain
 -- unsupported expressions
 
 -- CoerceViaIO
-SELECT JSON_QUERY('"a"', '$.a'  RETURNING int DEFAULT (SELECT '"1"')::jsonb ON ERROR);
+SELECT JSON_QUERY(jsonb '"a"', '$.a'  RETURNING int DEFAULT (SELECT '"1"')::jsonb ON ERROR);
 -- CoerceToDomain
-SELECT JSON_QUERY('"a"', '$.a' RETURNING queryfuncs_test_domain DEFAULT (select '"1"')::queryfuncs_test_domain ON ERROR);
+SELECT JSON_QUERY(jsonb '"a"', '$.a' RETURNING queryfuncs_test_domain DEFAULT (select '"1"')::queryfuncs_test_domain ON ERROR);
 -- RelabelType
-SELECT JSON_QUERY('"a"', '$.a'  RETURNING int DEFAULT (SELECT 1)::oid::int ON ERROR);
+SELECT JSON_QUERY(jsonb '"a"', '$.a'  RETURNING int DEFAULT (SELECT 1)::oid::int ON ERROR);
 -- ArrayCoerceExpr
-SELECT JSON_QUERY('"a"', '$.a'  RETURNING int[] DEFAULT (SELECT '{1}')::oid[]::int[] ON ERROR);
+SELECT JSON_QUERY(jsonb '"a"', '$.a'  RETURNING int[] DEFAULT (SELECT '{1}')::oid[]::int[] ON ERROR);
 -- CollateExpr
-SELECT JSON_QUERY('"a"', '$.a'  RETURNING int[] DEFAULT (SELECT '{1}')::text COLLATE "C" ON ERROR);
+SELECT JSON_QUERY(jsonb '"a"', '$.a'  RETURNING int[] DEFAULT (SELECT '{1}')::text COLLATE "C" ON ERROR);
 -- ConvertRowtypeExpr
 CREATE TABLE someparent (a int);
 CREATE TABLE somechild () INHERITS (someparent);
-SELECT JSON_QUERY('"a"', '$.a'  RETURNING someparent DEFAULT (SELECT '(1)')::somechild::someparent ON ERROR);
+SELECT JSON_QUERY(jsonb '"a"', '$.a'  RETURNING someparent DEFAULT (SELECT '(1)')::somechild::someparent ON ERROR);
 
 DROP DOMAIN queryfuncs_test_domain;
 DROP TABLE someparent, somechild;
@@ -449,15 +449,16 @@ SELECT JSON_QUERY(jsonb '{"a": 123}', '$' || '.' || 'a' WITH WRAPPER);
 -- Should fail (invalid path)
 SELECT JSON_QUERY(jsonb '{"a": 123}', 'error' || ' ' || 'error');
 
--- Non-jsonb inputs automatically coerced to jsonb
-SELECT JSON_EXISTS(json '{"a": 123}', '$' || '.' || 'a');
-SELECT JSON_QUERY(NULL FORMAT JSON, '$');
-
 -- Test non-const jsonpath
 CREATE TEMP TABLE jsonpaths (path) AS SELECT '$';
-SELECT json_value('"aaa"', path RETURNING json) FROM jsonpaths;
+SELECT json_value(jsonb '"aaa"', path RETURNING json) FROM jsonpaths;
 
 -- Test PASSING argument parsing
 SELECT JSON_QUERY(jsonb 'null', '$xyz' PASSING 1 AS xy);
 SELECT JSON_QUERY(jsonb 'null', '$xy' PASSING 1 AS xyz);
 SELECT JSON_QUERY(jsonb 'null', '$xyz' PASSING 1 AS xyz);
+
+-- Only jsonb arguments are supported currently
+SELECT JSON_EXISTS(NULL, '$');
+SELECT JSON_QUERY('1', '$');
+SELECT JSON_VALUE('aaa', '$');
-- 
2.43.0

