From 56cf48a6fd42467279cb926d8d08733892f1b1f0 Mon Sep 17 00:00:00 2001 From: yelingzhi Date: Mon, 24 Mar 2025 09:39:16 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Djson=5Fexists=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E9=83=A8=E5=88=86=E7=BB=93=E6=9E=9C=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/utils/adt/jsonfuncs.cpp | 60 +++++++++++++--------- src/test/regress/expected/jsonpath.out | 21 ++++++++ src/test/regress/sql/jsonpath.sql | 12 +++++ 3 files changed, 69 insertions(+), 24 deletions(-) diff --git a/src/common/backend/utils/adt/jsonfuncs.cpp b/src/common/backend/utils/adt/jsonfuncs.cpp index 12dec56529..41d15ec892 100644 --- a/src/common/backend/utils/adt/jsonfuncs.cpp +++ b/src/common/backend/utils/adt/jsonfuncs.cpp @@ -3543,6 +3543,40 @@ static List* GetObjectValues(text* json) return resultList; } +static void JsonPathIgnoreTailingZero(JsonPathItem* path) +{ + JsonPathItem* prevstep = path; + JsonPathItem* step = path; + JsonPathItem* tail = nullptr; + while (step->next) { + prevstep = step; + step = step->next; + if (step->type != JPI_ARRAY) { + tail = nullptr; + continue; + } + JsonPathArrayStep* as = (JsonPathArrayStep*)step; + if (as->indexes != NIL) { + ListCell* idxCell = nullptr; + foreach (idxCell, as->indexes) { + int index = lfirst_int(idxCell); + if (index == 0) { + break; + } + } + /* Loop reaches the end, no zero in the list. */ + if (idxCell == nullptr) { + tail = nullptr; + continue; + } + } + tail = tail == nullptr? prevstep : tail; + } + if (tail != nullptr) { + tail->next = nullptr; + } +} + static void JPWalkArrayStep(JsonPathItem* path, text* json, void (*pwalker)(text*, void*), void* context) { @@ -3630,35 +3664,12 @@ static void JPWalkObjectStep(JsonPathItem* path, text* json, } } -static bool JsonElemntType(text* json) -{ - char* jsonType = text_to_cstring(DatumGetTextP(DirectFunctionCall1(json_typeof, PointerGetDatum(json)))); - return ((strcmp(jsonType, "object") != 0) && (strcmp(jsonType, "array") != 0)); -} - static void JsonPathWalker(JsonPathItem* path, text* json, void (*pwalker)(text*, void*), void* context) { if (path == NULL) { pwalker(json, context); return; - } else if (json == NULL || !IsJsonText(json) || JsonElemntType(json)) { - /* allow redundant tailing [0] in syntax relaxation */ - JsonPathRelaxState relax = ((JsonPathContext*)context)->relax; - if (relax == JSON_PATH_NO_RELAX || path->type != JPI_ARRAY) { - return; - } - ListCell* idxCell = NULL; - foreach (idxCell, ((JsonPathArrayStep*)path)->indexes) { - int index = lfirst_int(idxCell); - if (index == 0) { - if (path->next != NULL) { - JsonPathWalker(path->next, json, pwalker, context); - } else { - pwalker(json, context); - } - return; - } - } + } else if (json == NULL || !IsJsonText(json)) { return; } @@ -3736,6 +3747,7 @@ Datum json_path_exists(PG_FUNCTION_ARGS) context.cxt.topJson = json; context.cxt.relax = JSON_PATH_ALLOW_RELAX; context.result = false; + JsonPathIgnoreTailingZero(path); JsonPathWalker(path, json, (void (*)(text*, void*))JsonPathExistsPathWalker, (void*)(&context)); } diff --git a/src/test/regress/expected/jsonpath.out b/src/test/regress/expected/jsonpath.out index 6bdd69a5d4..bf276fe31b 100644 --- a/src/test/regress/expected/jsonpath.out +++ b/src/test/regress/expected/jsonpath.out @@ -586,6 +586,27 @@ NOTICE: result=t (1 row) +drop table if exists t_JsonExists_Case0006; +NOTICE: table "t_jsonexists_case0006" does not exist, skipping +CREATE TABLE t_JsonExists_Case0006(po_document VARCHAR2 (2000)); +INSERT INTO t_JsonExists_Case0006 + VALUES ('[{"first":"John"}, {"middle":"Mark"}, {"last":"Smith"}]'); +INSERT INTO t_JsonExists_Case0006 + VALUES ('{ + "name":[{"first":"John"}, {"middle":"Mark"}, {"last":"Smith"}], + "age":[{"John":"20"}, {"Mark":"35"}, {"Smith":"29"}] +}'); +SELECT po.po_document FROM t_JsonExists_Case0006 po WHERE json_exists(po.po_document,'$[0][0]'); + po_document +------------------------------------------------------------------- + [{"first":"John"}, {"middle":"Mark"}, {"last":"Smith"}] + { + + "name":[{"first":"John"}, {"middle":"Mark"}, {"last":"Smith"}],+ + "age":[{"John":"20"}, {"Mark":"35"}, {"Smith":"29"}] + + } +(2 rows) + +drop table t_JsonExists_Case0006; DROP SCHEMA test_jsonpath CASCADE; NOTICE: drop cascades to 3 other objects DETAIL: drop cascades to table t diff --git a/src/test/regress/sql/jsonpath.sql b/src/test/regress/sql/jsonpath.sql index a0078b1e9d..9e425f9585 100644 --- a/src/test/regress/sql/jsonpath.sql +++ b/src/test/regress/sql/jsonpath.sql @@ -178,4 +178,16 @@ end; call p_JsonTextcontains_Case0011('{"family" : {"id":12, "ages":[25,23], "address" : {"street" : "300 Oak Street", "apt" : 10}}}', '$.family','25,38'); +drop table if exists t_JsonExists_Case0006; +CREATE TABLE t_JsonExists_Case0006(po_document VARCHAR2 (2000)); +INSERT INTO t_JsonExists_Case0006 + VALUES ('[{"first":"John"}, {"middle":"Mark"}, {"last":"Smith"}]'); +INSERT INTO t_JsonExists_Case0006 + VALUES ('{ + "name":[{"first":"John"}, {"middle":"Mark"}, {"last":"Smith"}], + "age":[{"John":"20"}, {"Mark":"35"}, {"Smith":"29"}] +}'); +SELECT po.po_document FROM t_JsonExists_Case0006 po WHERE json_exists(po.po_document,'$[0][0]'); +drop table t_JsonExists_Case0006; + DROP SCHEMA test_jsonpath CASCADE; \ No newline at end of file -- Gitee