From: Amit Langote Date: Wed, 19 Jun 2024 06:22:06 +0000 (+0900) Subject: SQL/JSON: Correct jsonpath variable name matching X-Git-Tag: REL_17_BETA2~27 X-Git-Url: http://git.postgresql.org/gitweb/?a=commitdiff_plain;h=0f271e8e8d9c8db0ea86c0d12b3221009b81d8bf;p=postgresql.git SQL/JSON: Correct jsonpath variable name matching Previously, GetJsonPathVar() allowed a jsonpath expression to reference any prefix of a PASSING variable's name. For example, the following query would incorrectly work: SELECT JSON_QUERY(context_item, jsonpath '$xy' PASSING val AS xyz); The fix ensures that the length of the variable name mentioned in a jsonpath expression matches exactly with the name of the PASSING variable before comparing the strings using strncmp(). Reported-by: Alvaro Herrera (off-list) Discussion: https://postgr.es/m/CA+HiwqFGkLWMvELBH6E4SQ45qUHthgcRH6gCJL20OsYDRtFx_w@mail.gmail.com --- diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index b9ebc827a74..2bf86d06ef5 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -4278,6 +4278,7 @@ ExecInitJsonExpr(JsonExpr *jsexpr, ExprState *state, JsonPathVariable *var = palloc(sizeof(*var)); var->name = argname->sval; + var->namelen = strlen(var->name); var->typid = exprType((Node *) argexpr); var->typmod = exprTypmod((Node *) argexpr); diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c index c30d059a762..d79c9298227 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -2994,7 +2994,8 @@ GetJsonPathVar(void *cxt, char *varName, int varNameLen, { JsonPathVariable *curvar = lfirst(lc); - if (!strncmp(curvar->name, varName, varNameLen)) + if (curvar->namelen == varNameLen && + strncmp(curvar->name, varName, varNameLen) == 0) { var = curvar; break; @@ -4118,6 +4119,7 @@ JsonTableInitOpaque(TableFuncScanState *state, int natts) JsonPathVariable *var = palloc(sizeof(*var)); var->name = pstrdup(name->sval); + var->namelen = strlen(var->name); var->typid = exprType((Node *) state->expr); var->typmod = exprTypmod((Node *) state->expr); diff --git a/src/include/utils/jsonpath.h b/src/include/utils/jsonpath.h index 9d2b8533d54..ee35698d083 100644 --- a/src/include/utils/jsonpath.h +++ b/src/include/utils/jsonpath.h @@ -287,6 +287,7 @@ extern bool jspConvertRegexFlags(uint32 xflags, int *result, typedef struct JsonPathVariable { char *name; + int namelen; /* strlen(name) as cache for GetJsonPathVar() */ Oid typid; int32 typmod; Datum value; diff --git a/src/test/regress/expected/sqljson_queryfuncs.out b/src/test/regress/expected/sqljson_queryfuncs.out index 21e0fc64170..98117b346d4 100644 --- a/src/test/regress/expected/sqljson_queryfuncs.out +++ b/src/test/regress/expected/sqljson_queryfuncs.out @@ -1334,3 +1334,14 @@ SELECT json_value('"aaa"', path RETURNING json) FROM jsonpaths; "aaa" (1 row) +-- Test PASSING argument parsing +SELECT JSON_QUERY(jsonb 'null', '$xyz' PASSING 1 AS xy); +ERROR: could not find jsonpath variable "xyz" +SELECT JSON_QUERY(jsonb 'null', '$xy' PASSING 1 AS xyz); +ERROR: could not find jsonpath variable "xy" +SELECT JSON_QUERY(jsonb 'null', '$xyz' PASSING 1 AS xyz); + json_query +------------ + 1 +(1 row) + diff --git a/src/test/regress/sql/sqljson_queryfuncs.sql b/src/test/regress/sql/sqljson_queryfuncs.sql index c46489e2dd7..d9dbb1ceaac 100644 --- a/src/test/regress/sql/sqljson_queryfuncs.sql +++ b/src/test/regress/sql/sqljson_queryfuncs.sql @@ -454,3 +454,8 @@ 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; + +-- 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);