v4-0001-make-simplified-accessor-works-with-domain-ove.no-cfbot
application/octet-stream
Filename: v4-0001-make-simplified-accessor-works-with-domain-ove.no-cfbot
Type: application/octet-stream
Part: 0
From 72897ab85bfd890ff5fe13ca7a9e5d2f0168f8fa Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Fri, 4 Oct 2024 13:24:06 +0800
Subject: [PATCH v4 1/1] make simplified accessor works with domain over
JSON/JSONB
---
src/backend/parser/parse_func.c | 49 +++++++++++++++++++++++------
src/include/parser/parse_type.h | 1 -
src/test/regress/expected/jsonb.out | 43 +++++++++++++++++++++++++
src/test/regress/sql/jsonb.sql | 14 +++++++++
4 files changed, 97 insertions(+), 10 deletions(-)
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index a13c001dd4..9b990d58a1 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -51,13 +51,35 @@ static Oid FuncNameAsType(List *funcname);
static Node *ParseComplexProjection(ParseState *pstate, const char *funcname,
Node *first_arg, int location);
static Node *ParseJsonSimplifiedAccessorObjectField(ParseState *pstate, const char *funcname,
- Node *first_arg, int location);
+ Node *first_arg, int location, bool is_json);
static Oid LookupFuncNameInternal(ObjectType objtype, List *funcname,
int nargs, const Oid *argtypes,
bool include_out_arguments, bool missing_ok,
FuncLookupError *lookupError);
+static void is_json_or_jsonb(Oid typeid, bool *is_json, bool *is_jsonb);
+
+static void
+is_json_or_jsonb(Oid typeid, bool *is_json, bool *is_jsonb)
+{
+ Oid base_type = InvalidOid;
+
+ if(typeid == JSONOID || typeid == JSONBOID)
+ {
+ if(typeid == JSONOID)
+ *is_json = true;
+ if (typeid == JSONBOID)
+ *is_jsonb = true;
+ return;
+ }
+
+ base_type = getBaseType(typeid);
+ if(base_type == JSONOID)
+ *is_json = true;
+ if (base_type == JSONBOID)
+ *is_jsonb = true;
+}
/*
* Parse a function call
*
@@ -104,6 +126,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
bool func_variadic = (fn ? fn->func_variadic : false);
CoercionForm funcformat = (fn ? fn->funcformat : COERCE_EXPLICIT_CALL);
bool could_be_projection;
+ bool is_json = false;
+ bool is_jsonb = false;
Oid rettype;
Oid funcid;
ListCell *l;
@@ -217,6 +241,13 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
Assert(first_arg != NULL);
}
+ if (nargs == 1 && !proc_call &&
+ agg_order == NIL && agg_filter == NULL &&
+ !agg_star && !agg_distinct && over == NULL &&
+ !func_variadic && argnames == NIL &&
+ list_length(funcname) == 1)
+ is_json_or_jsonb(actual_arg_types[0], &is_json, &is_jsonb);
+
/*
* Decide whether it's legitimate to consider the construct to be a column
* projection. For that, there has to be a single argument of complex
@@ -231,18 +262,18 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
list_length(funcname) == 1 &&
(actual_arg_types[0] == RECORDOID ||
ISCOMPLEX(actual_arg_types[0]) ||
- ISJSON(actual_arg_types[0])));
+ is_json || is_jsonb ));
/*
* If it's column syntax, check for column projection case first.
*/
if (could_be_projection && is_column)
{
- if (ISJSON(actual_arg_types[0]))
+ if (is_json || is_jsonb)
retval = ParseJsonSimplifiedAccessorObjectField(pstate,
strVal(linitial(funcname)),
first_arg,
- location);
+ location, is_json);
else
retval = ParseComplexProjection(pstate,
strVal(linitial(funcname)),
@@ -252,8 +283,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
return retval;
/*
- * If ParseComplexProjection doesn't recognize it as a projection,
- * just press on.
+ * If ParseJsonSimplifiedAccessorObjectField, ParseComplexProjection
+ * doesn't recognize it as a projection, just press on.
*/
}
@@ -1958,7 +1989,7 @@ ParseJsonSimplifiedAccessorArrayElement(ParseState *pstate, A_Indices *subscript
*/
Node *
ParseJsonSimplifiedAccessorObjectField(ParseState *pstate, const char *funcname,
- Node *first_arg, int location)
+ Node *first_arg, int location, bool is_json)
{
OpExpr *result;
Node *rexpr;
@@ -1973,14 +2004,14 @@ ParseJsonSimplifiedAccessorObjectField(ParseState *pstate, const char *funcname,
false);
result = makeNode(OpExpr);
- if (exprType(first_arg) == JSONOID)
+ if (is_json)
{
result->opno = OID_JSON_OBJECT_FIELD_OP;
result->opresulttype = JSONOID;
}
else
{
- Assert(exprType(first_arg) == JSONBOID);
+ Assert(getBaseType(exprType(first_arg)) == JSONBOID);
result->opno = OID_JSONB_OBJECT_FIELD_OP;
result->opresulttype = JSONBOID;
}
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
index 9c8b3bfb2f..b62e7a6ce9 100644
--- a/src/include/parser/parse_type.h
+++ b/src/include/parser/parse_type.h
@@ -57,6 +57,5 @@ extern bool parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
/* true if typeid is composite, or domain over composite, but not RECORD */
#define ISCOMPLEX(typeid) (typeOrDomainTypeRelid(typeid) != InvalidOid)
-#define ISJSON(typeid) (typeid == JSONOID || typeid == JSONBOID)
#endif /* PARSE_TYPE_H */
diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out
index 954efe67b6..3dd89f28fe 100644
--- a/src/test/regress/expected/jsonb.out
+++ b/src/test/regress/expected/jsonb.out
@@ -5801,3 +5801,46 @@ select (test_jsonb_dot.test_jsonb).d[0].x[1] from test_jsonb_dot;
(3 rows)
+create domain json_d as jsonb;
+create type test as (a int, b json_d);
+create table t1(a test);
+insert into t1 select $$(1,"{""a"": 3, ""key1"": {""c"": ""42""}, ""key2"": [11, 12]}") $$;
+insert into t1 select $$ (1,"{""a"": 3, ""key1"": {""c"": ""42""}, ""key2"": [11, 12, {""x"": [31, 42]}]}") $$;
+select (t1.a).b.key1.c from t1;
+ c
+------
+ "42"
+ "42"
+(2 rows)
+
+select (t1.a).b.key2 from t1;
+ key2
+---------------------------
+ [11, 12]
+ [11, 12, {"x": [31, 42]}]
+(2 rows)
+
+select (t1.a).b.key2[0] from t1;
+ key2
+------
+ 11
+ 11
+(2 rows)
+
+select (t1.a).b.key2[0::text] from t1;
+ key2
+------
+ 11
+ 11
+(2 rows)
+
+select (t1.a).b.key2[2].x[1] from t1;
+ x
+----
+
+ 42
+(2 rows)
+
+drop table t1 cascade;
+drop type test cascade;
+drop domain json_d cascade;
diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql
index f095dc2bbe..19fb3dd230 100644
--- a/src/test/regress/sql/jsonb.sql
+++ b/src/test/regress/sql/jsonb.sql
@@ -1581,3 +1581,17 @@ select (test_jsonb_dot.test_jsonb).d[0:] from test_jsonb_dot;
select (test_jsonb_dot.test_jsonb).d[0::int] from test_jsonb_dot;
select (test_jsonb_dot.test_jsonb).d[0::float] from test_jsonb_dot;
select (test_jsonb_dot.test_jsonb).d[0].x[1] from test_jsonb_dot;
+
+create domain json_d as jsonb;
+create type test as (a int, b json_d);
+create table t1(a test);
+insert into t1 select $$(1,"{""a"": 3, ""key1"": {""c"": ""42""}, ""key2"": [11, 12]}") $$;
+insert into t1 select $$ (1,"{""a"": 3, ""key1"": {""c"": ""42""}, ""key2"": [11, 12, {""x"": [31, 42]}]}") $$;
+select (t1.a).b.key1.c from t1;
+select (t1.a).b.key2 from t1;
+select (t1.a).b.key2[0] from t1;
+select (t1.a).b.key2[0::text] from t1;
+select (t1.a).b.key2[2].x[1] from t1;
+drop table t1 cascade;
+drop type test cascade;
+drop domain json_d cascade;
\ No newline at end of file
--
2.34.1