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

JSON_VALID returns 1 for byte strings that are not JSON, which widens what a JSON-typed column accepts

    XMLWordPrintable

Details

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

    Description

      JSON_VALID indicates whether a value is a valid JSON document. Several
      byte strings that no JSON grammar admits are reported valid, and the
      lexer is inconsistent with itself as well as with the standard.

      SELECT JSON_VALID('1.') AS v, JSON_TYPE('1.') AS t, JSON_DEPTH('1.') AS d;
      v  t       d
      1  DOUBLE  1

      No warning. RFC 8259 and ECMA-404 both require at least one digit after
      the decimal point. Yet the neighbouring malformed numbers are rejected:

      SELECT JSON_VALID('.1') AS leading_point, JSON_VALID('1e') AS bare_exponent;
      leading_point  bare_exponent
      0              0

      So `1.` is accepted while `.1` and `1e` are refused, which no reading of
      the grammar produces.

      How to repeat

      SELECT JSON_VALID('1.')   AS trailing_point;   -- 1
      SELECT JSON_VALID('1.e5') AS point_then_exp;   -- 1
      SELECT JSON_VALID('.1')   AS leading_point;    -- 0
      SELECT JSON_VALID('1e')   AS bare_exponent;    -- 0
      SELECT JSON_VALID('+1')   AS leading_plus;     -- 0
       
      -- an escape the standard does not define
      -- 1, STRING
      SELECT JSON_VALID('"a\q"') AS bad_escape, JSON_TYPE('"a\q"') AS t;

      The standard permits only the escapes `" \ / b f n r t u`.

      Why it matters

      JSON_VALID() is the CHECK constraint of a JSON-typed column, so
      whatever it admits, a JSON column stores:

      CREATE TABLE t1 (j JSON);
      INSERT INTO t1 VALUES ('1.');
      SELECT j, JSON_TYPE(j), JSON_VALID(j) FROM t1;
      j     JSON_TYPE(j)  JSON_VALID(j)
      1.    DOUBLE        1
      DROP TABLE t1;

      The insert succeeds and the row reads back as a document, so the column
      type is not the guarantee it appears to be.

      Root cause

      The number and string lexers accept forms the grammar does not define.
      This is a deliberate-looking leniency in places and an oversight in
      others; either way the two halves disagree with each other.

      Contract, `scripts/fill_help_tables.sql:467`: *"Indicates whether the
      given value is a valid JSON document or not. Returns 1 if valid, 0 if
      not, and NULL if the argument is NULL."*

      Affected versions

      JSON_VALID was added in 10.2.3. JSON-typed columns, whose CHECK
      constraint is JSON_VALID(), arrived in 10.4.3, from which point the
      leniency reaches stored data.

      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. Pinned as the lenient behaviour rather than the
      contract - func_json_invalid.result:126-128 records JSON_VALID('1.')
      = 1. A fix would have to move that recorded line.

      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.