Bug in jsonb_path_exists (maybe _match) one-element scalar/variable jsonpath handling

Поиск
Список
Период
Сортировка
От David G. Johnston
Тема Bug in jsonb_path_exists (maybe _match) one-element scalar/variable jsonpath handling
Дата
Msg-id CAKFQuwbeytffJkVnEqDyLZ=rQsznoTh1OgDoOF3VmOMkxcTMjA@mail.gmail.com
обсуждение исходный текст
Ответы Re: Bug in jsonb_path_exists (maybe _match) one-element scalar/variable jsonpath handling
Re: Bug in jsonb_path_exists (maybe _match) one-element scalar/variable jsonpath handling
Список pgsql-bugs
Hey,

There is supposedly a recently submitted (i.e., in moderation) bug report from a Slack member on this as well, but I decided I didn't want to wait for it to post.


The following query produces an incorrect result.  It should error (or at worse produce "false"), but it instead produces "true" (this applies to @? too)

select jsonb_path_exists('{"foo": true}'::jsonb, '$bar', '{}', false);

The corresponding:

select jsonb_path_match('{"foo": true}'::jsonb, '$bar', '{}', false);

produces the expected <ERROR:  could not find jsonpath variable "bar">

The responsible code seems to be (just did some code skimming here):

src/backend/utils/adt/jsonpath_exec.c@executeItemOptUnwrapTarget

        case jpiVariable:
            {
                JsonbValue  vbuf;
                JsonbValue *v;
                bool        hasNext = jspGetNext(jsp, &elem);

                if (!hasNext && !found)
                {
                    res = jperOk;   /* skip evaluation */
                    break;
                }

                v = hasNext ? &vbuf : palloc(sizeof(*v));

                baseObject = cxt->baseObject;
                getJsonPathItem(cxt, jsp, v);

                res = executeNextItem(cxt, jsp, &elem,
                                      v, found, hasNext);
                cxt->baseObject = baseObject;
            }
            break;

Specifically, since exists doesn't care about values, just presence, found is false, and since the variable is the only thing present, hasNext is also false.  Thus we simply return jperOK without ever checking to see what the variable actually is. This results in the exists code producing a true result.

Looking at this more, it isn't just the variable case that ends up producing the wrong answer.  Going by the principle that any function call of jsonb_path_exists that returns true should produce said match when executing jsonb_path_match, this is also broken for the rest (probably) of the matched types in the case group.  And indeed, if the variable "bar" is defined the error in the match case just changes to "single boolean result is expected".

select jsonb_path_exists('{"foo": true}'::jsonb, '"bar"', '{}', false); -- true (bar in double quotes)
select jsonb_path_match('{"foo": true}'::jsonb, '"bar"', '{}', false); -- ERROR:  single boolean result is expected
select jsonb_path_match('{"foo": true}'::jsonb, '$bar', '{"bar":"foo"}', false); -- same error as above, as expected

I expect the missing variable specification to produce jperError and the rest of the block to produce jperNotFound.  The "single boolean result expected" error seems incorrect though I'm not sure where that is coming from.  But I'm also not considering, or am even aware of, what the standard we are guided by here says should actually happen.

David J.

В списке pgsql-bugs по дате отправления:

Предыдущее
От: PG Bug reporting form
Дата:
Сообщение: BUG #17694: In JSONPath expressions, characters between leading $ and dot appear to be ignored
Следующее
От: PG Bug reporting form
Дата:
Сообщение: BUG #17695: Failed Assert in logical replication snapbuild.