Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-40703

JSON_EXISTS returns 1 for the root path of an empty or malformed document, without reading it

    XMLWordPrintable

Details

    • Bug
    • Status: Open (View Workflow)
    • Major
    • Resolution: Unresolved
    • 10.11, 11.4, 11.8, 12.3, 13.0
    • None
    • JSON

    Description

      JSON_EXISTS is documented to determine whether a document has an element
      at a path. Asked for the root path, it answers 1 whatever the argument
      is - including bytes that are not a document at all, and including the
      empty string.

      SELECT JSON_EXISTS('', '$') AS v;
      v
      1

      No warning is raised. Every sibling function refuses the same bytes in
      the same statement:

      SELECT JSON_EXISTS('', '$')            AS ex,
             JSON_CONTAINS('', '1')          AS co,
             JSON_CONTAINS_PATH('','one','$') AS cp,
             JSON_VALID('')                  AS va,
             JSON_LENGTH('')                 AS le;
      ex  co    cp    va  le
      1   NULL  NULL  0   NULL
      Warnings:
      Warning  4037  Unexpected end of JSON text in argument 1
                    to function 'json_contains'
      Warning  4037  Unexpected end of JSON text in argument 1
                    to function 'json_contains_path'
      Note     4037  Unexpected end of JSON text in argument 1
                    to function 'json_valid'
      Warning  4037  Unexpected end of JSON text in argument 1
                    to function 'json_length'

      How to repeat

      SELECT JSON_EXISTS('', '$')        AS empty_string;
      SELECT JSON_EXISTS('   ', '$')     AS spaces;
      SELECT JSON_EXISTS('rubbish', '$') AS not_json;
      SELECT JSON_EXISTS('{', '$')       AS truncated;
      -- all four answer 1, silently
       
      -- and the same documents with any other path answer NULL and say why
      SELECT JSON_EXISTS('', '$.a')  AS with_a_step;
      SELECT JSON_EXISTS('', '$[0]') AS with_a_subscript;
      -- NULL + Warning 4037

      So the answer 1 for the root path is given without the document having
      been read at all.

      Root cause

      The root path needs no search, so the function answers before the
      argument is scanned. Any other path drives a scan, which is why the
      same document is diagnosed there and not here.

      The contract is *"Determines whether json_doc has an element pointed to
      by path json_path. Returns 1 if the element exists, 0 if not, or NULL
      if any of the inputs were NULL"* (`scripts/fill_help_tables.sql:440`).
      Of the three documented answers, 1 is the only one that cannot be right
      for a document that does not exist.

      Why it matters

      JSON_EXISTS(col, '$') is the natural way to ask whether a column holds
      anything at all, and written that way it cannot fail: a column of
      rubbish and a column of documents give the same answer, and nothing
      downstream can tell them apart.

      Affected versions

      JSON_EXISTS was added in 10.2.3 and the early return for the root
      path has been there throughout.

      Verified on 10.11 only (10.11.19-MariaDB-debug, commit 1dab253482d).
      Other branches were not tested.

      Note

      Found while auditing the JSON functions against their documented
      contracts. No test in mysql-test/ calls JSON_EXISTS on an
      empty or malformed document.

      Attachments

        Issue Links

          Activity

            People

              Unassigned Unassigned
              arcivanov Arcadiy Ivanov
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

                Created:
                Updated:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.