Commit 3c814f22 authored by igor@olga.mysql.com's avatar igor@olga.mysql.com
Browse files

Fixed bug #25219: crash for a query that contains an EXIST subquery with

UNION over correlated and uncorrelated SELECTS.
In such subqueries each uncorrelated SELECT should be considered as
uncacheable. Otherwise join_free is called for it and in many cases
it causes some problems.
parent 0d665bd5
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -3605,3 +3605,36 @@ FROM t1) t;
COUNT(*)
3000
DROP TABLE t1,t2;
CREATE TABLE t1 (id char(4) PRIMARY KEY, c int);
CREATE TABLE t2 (c int);
INSERT INTO t1 VALUES ('aa', 1);
INSERT INTO t2 VALUES (1);
SELECT * FROM t1 
WHERE EXISTS (SELECT c FROM t2 WHERE c=1
UNION 
SELECT c from t2 WHERE c=t1.c);
id	c
aa	1
INSERT INTO t1 VALUES ('bb', 2), ('cc', 3), ('dd',1);
SELECT * FROM t1 
WHERE EXISTS (SELECT c FROM t2 WHERE c=1
UNION 
SELECT c from t2 WHERE c=t1.c);
id	c
aa	1
bb	2
cc	3
dd	1
INSERT INTO t2 VALUES (2);
CREATE TABLE t3 (c int);
INSERT INTO t3 VALUES (1);
SELECT * FROM t1 
WHERE EXISTS (SELECT t2.c FROM t2 JOIN t3 ON t2.c=t3.c WHERE t2.c=1
UNION 
SELECT c from t2 WHERE c=t1.c);
id	c
aa	1
bb	2
cc	3
dd	1
DROP TABLE t1,t2,t3;
+34 −0
Original line number Diff line number Diff line
@@ -2508,3 +2508,37 @@ SELECT SQL_NO_CACHE COUNT(*)
          FROM t1) t;

DROP TABLE t1,t2;

#
# Bug #25219: EXIST subquery with UNION over a mix of
#             correlated and uncorrelated selects
#             

CREATE TABLE t1 (id char(4) PRIMARY KEY, c int);
CREATE TABLE t2 (c int);

INSERT INTO t1 VALUES ('aa', 1);
INSERT INTO t2 VALUES (1);

SELECT * FROM t1 
  WHERE EXISTS (SELECT c FROM t2 WHERE c=1
                UNION 
                SELECT c from t2 WHERE c=t1.c);

INSERT INTO t1 VALUES ('bb', 2), ('cc', 3), ('dd',1);

SELECT * FROM t1 
  WHERE EXISTS (SELECT c FROM t2 WHERE c=1
                UNION 
                SELECT c from t2 WHERE c=t1.c);

INSERT INTO t2 VALUES (2);
CREATE TABLE t3 (c int);
INSERT INTO t3 VALUES (1);

SELECT * FROM t1 
  WHERE EXISTS (SELECT t2.c FROM t2 JOIN t3 ON t2.c=t3.c WHERE t2.c=1
                UNION 
                SELECT c from t2 WHERE c=t1.c);

DROP TABLE t1,t2,t3;
+4 −1
Original line number Diff line number Diff line
@@ -410,7 +410,10 @@ MY_LOCALE *my_locale_by_name(const char *name);
#define UNCACHEABLE_EXPLAIN     8
/* Don't evaluate subqueries in prepare even if they're not correlated */
#define UNCACHEABLE_PREPARE    16
/* Used to chack GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */
/* For uncorrelated SELECT in an UNION with some correlated SELECTs */
#define UNCACHEABLE_UNITED     32

/* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */
#define UNDEF_POS (-1)
#ifdef EXTRA_DEBUG
/*
+10 −2
Original line number Diff line number Diff line
@@ -1371,9 +1371,17 @@ void st_select_lex::mark_as_dependent(SELECT_LEX *last)
    if (!(s->uncacheable & UNCACHEABLE_DEPENDENT))
    {
      // Select is dependent of outer select
      s->uncacheable|= UNCACHEABLE_DEPENDENT;
      s->uncacheable= (s->uncacheable & ~UNCACHEABLE_UNITED) |
                       UNCACHEABLE_DEPENDENT;
      SELECT_LEX_UNIT *munit= s->master_unit();
      munit->uncacheable|= UNCACHEABLE_DEPENDENT;
      munit->uncacheable= (munit->uncacheable & ~UNCACHEABLE_UNITED) |
                       UNCACHEABLE_DEPENDENT;
      for (SELECT_LEX *sl= munit->first_select(); sl ; sl= sl->next_select())
      {
        if (sl != s &&
            !(sl->uncacheable & (UNCACHEABLE_DEPENDENT | UNCACHEABLE_UNITED)))
          sl->uncacheable|= UNCACHEABLE_UNITED;
      }
    }
  is_correlated= TRUE;
  this->master_unit()->item->is_correlated= TRUE;