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

MAKE_SET() on inner table of LEFT JOIN wrongly rejects NULL-complemented rows

    XMLWordPrintable

Details

    • Bug
    • Status: Closed (View Workflow)
    • Major
    • Resolution: Duplicate
    • 12.3.2
    • N/A
    • Optimizer
    • None
    • Not for Release Notes

    Description

      Summary

      Wrong result: MAKE_SET() on inner table of LEFT JOIN wrongly rejects NULL-complemented rows


      Description

      MAKE_SET(1, NULL) returns a non-NULL empty string (MAKE_SET(1, NULL) IS NOT NULL is true).
      A WHERE predicate MAKE_SET(1, inner_col) IS NOT NULL (or other predicates that are true for that empty string) must not null-reject outer-join NULL-complemented rows.

      On MariaDB 12.3.2, placing that predicate in WHERE drops the NULL-extended LEFT JOIN row, while evaluating the same predicate in the SELECT list (or filtering it in an outer subquery) keeps the row. This is incorrect outer→inner join simplification when not_null_tables() is wrong for a function that does not return SQL NULL on NULL input.

      How to repeat

      CREATE TABLE t1 (a INT, b INT);
      INSERT INTO t1 VALUES (1,1),(2,3);
       
      -- Semantics
      SELECT MAKE_SET(1, NULL) IS NOT NULL;  -- 1
       
      -- SELECT-list: NULL-extended row satisfies the predicate
      SELECT t1.a, t2.b, MAKE_SET(1, t2.b) IS NOT NULL AS p
      FROM t1 LEFT JOIN t1 t2 ON t1.a = t2.b;
      -- 1 | 1    | 1
      -- 2 | NULL | 1
       
      -- WHERE: same predicate wrongly drops the NULL-extended row
      SELECT COUNT(*) AS c_where
      FROM t1 LEFT JOIN t1 t2 ON t1.a = t2.b
      WHERE MAKE_SET(1, t2.b) IS NOT NULL;
      -- Actual: 1
      -- Expected: 2
       
      -- Equivalent filter outside the join (oracle)
      SELECT COUNT(*) AS c_subq FROM (
        SELECT t1.a, MAKE_SET(1, t2.b) IS NOT NULL AS p
        FROM t1 LEFT JOIN t1 t2 ON t1.a = t2.b
      ) s WHERE p;
      -- Actual: 2
      -- Expected: 2
       
      DROP TABLE t1;
      

      Alternate form:

      CREATE TABLE t1 (c1 INT);
      INSERT INTO t1 VALUES (1);
       
      SELECT ref_1.c1,
             (MAKE_SET(1, BIN(ref_1.c1), BIN(ref_1.c1)) NOT LIKE '%_6') AS w_1
      FROM t1 AS ref_1 RIGHT JOIN t1 AS ref_2 ON FALSE;
      -- Returns 1 row: (NULL, 1)
       
      SELECT ref_1.c1,
             (MAKE_SET(1, BIN(ref_1.c1), BIN(ref_1.c1)) NOT LIKE '%_6') AS w_1
      FROM t1 AS ref_1 RIGHT JOIN t1 AS ref_2 ON FALSE
      WHERE (MAKE_SET(1, BIN(ref_1.c1), BIN(ref_1.c1)) NOT LIKE '%_6');
      -- Actual: empty set
      -- Expected: 1 row (NULL, 1)
       
      DROP TABLE t1;
      

      Observed on: 12.3.2-MariaDB

      Actual result

      • LEFT JOIN + WHERE MAKE_SET(1, t2.b) IS NOT NULLCOUNT = 1
      • RIGHT JOIN ON FALSE + same-style WHERE → empty set

      Expected result

      • LEFT JOIN form → COUNT = 2
      • RIGHT JOIN ON FALSE form → 1 row (NULL, 1), matching the query without WHERE

      Environment

      • MariaDB 12.3.2
      • InnoDB, default sql_mode

      Attachments

        Issue Links

          Activity

            People

              Unassigned Unassigned
              mu mu
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Git Integration

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