mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-28 17:15:19 +03:00 
			
		
		
		
	Evaluate "NULL IN (SELECT ...)" in a special way: Disable pushed-down 
conditions and their "consequences": 
 = Do full table scans instead of unique_[index_subquery] lookups.
 = Change appropriate "ref_or_null" accesses to full table scans in
   subquery's joins.
Also cache value of NULL IN (SELECT ...) if the SELECT is not correlated 
wrt any upper select.
mysql-test/r/subselect.result:
  BUG#8804: wrong results for NULL IN (SELECT ...): 
   - Updated test results
sql/item.h:
  BUG#8804: wrong results for NULL IN (SELECT ...): 
   - Added comments
sql/item_cmpfunc.cc:
  BUG#8804: wrong results for NULL IN (SELECT ...): 
  Made Item_in_optimizer to:
  - cache the value of "NULL IN (uncorrelated select)"
  - Turn off pushed-down predicates when evaluating "NULL IN (SELECT ...)"
sql/item_cmpfunc.h:
  BUG#8804: wrong results for NULL IN (SELECT ...): 
  - Made Item_in_optimizer cache the value of "NULL IN (uncorrelated select)"
  - Added comments
sql/item_subselect.cc:
  BUG#8804: wrong results for NULL IN (SELECT ...):
  - When needed, wrap the predicates we push into subquery into an 
    Item_func_trig_cond so we're able to turn them off when evaluating 
    NULL IN (SELECT ...).
  - Added code to evaluate NULL IN (SELECT ...) in a special way:
    = In [unique_]index_subquery, do full table scan to see if there 
      are any rows.
    = For other subqueries, change ref[_or_null] to ALL if the
      ref[_or_null] was created from pushed-down predicate.
sql/item_subselect.h:
  BUG#8804: wrong results for NULL IN (SELECT ...):
  - Added Item_subselect::is_correlated
  - Added comments
sql/records.cc:
  BUG#8804: wrong results for NULL IN (SELECT ...):
  - Make rr_sequential() non-static
sql/sql_lex.cc:
  BUG#8804: wrong results for NULL IN (SELECT ...):
  - Added st_select_lex::is_correlated and Item_subselect::is_correlated.
sql/sql_lex.h:
  BUG#8804: wrong results for NULL IN (SELECT ...):
  - Added st_select_lex::is_correlated
sql/sql_select.cc:
  BUG#8804: wrong results for NULL IN (SELECT ...):
  - Added KEY_FIELD::outer_ref to keep track of which ref accesses are 
    created from predicates that were pushed down into the subquery.
sql/sql_select.h:
  BUG#8804: wrong results for NULL IN (SELECT ...):
  - Added KEYUSE::outer_ref
mysql-test/r/subselect3.result:
  New BitKeeper file ``mysql-test/r/subselect3.result''
mysql-test/t/subselect3.test:
  New BitKeeper file ``mysql-test/t/subselect3.test''
		
	
		
			
				
	
	
		
			138 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| --disable_warnings
 | |
| drop table if exists t0, t1, t2, t3, t4;
 | |
| --enable_warnings
 | |
| 
 | |
| #
 | |
| # 1. Subquery with GROUP/HAVING
 | |
| #
 | |
| create table t1 (oref int, grp int, ie int) ;
 | |
| insert into t1 (oref, grp, ie) values
 | |
|  (1, 1, 1),
 | |
|  (1, 1, 1),
 | |
|  (1, 2, NULL),
 | |
| 
 | |
|  (2, 1, 3),
 | |
| 
 | |
|  (3, 1, 4),
 | |
|  (3, 2, NULL);
 | |
| 
 | |
| #  Ok, for  
 | |
| #   select max(ie) from t1 where oref=PARAM group by grp
 | |
| # we'll have:
 | |
| #  1  ->  (1, NULL)    matching + NULL
 | |
| #  2  ->  (3)          non-matching
 | |
| #  3  ->  (3, NULL)    non-matching + NULL
 | |
| #  4  ->  ()           nothing.
 | |
| 
 | |
| create table t2 (oref int, a int);
 | |
| insert into t2 values 
 | |
|   (1, 1),
 | |
|   (2, 2),
 | |
|   (3, 3),
 | |
|   (4, NULL),
 | |
|   (2, NULL);
 | |
| 
 | |
| # true, false, null, false, null
 | |
| select a, oref, a in (select max(ie) 
 | |
|   from t1 where oref=t2.oref group by grp) from t2;
 | |
| 
 | |
| # This must have a trigcond
 | |
| explain extended
 | |
| select a, oref, a in (select max(ie) 
 | |
|   from t1 where oref=t2.oref group by grp) from t2;
 | |
| 
 | |
| # This must not have a trigcond:
 | |
| explain extended
 | |
| select a, oref from t2 
 | |
| where a in (select max(ie) from t1 where oref=t2.oref group by grp);
 | |
| 
 | |
| 
 | |
| # Non-correlated subquery, 2 NULL evaluations
 | |
| create table t3 (a int);
 | |
| insert into t3 values (NULL), (NULL);
 | |
| flush status;
 | |
| select a in (select max(ie) from t1 where oref=4 group by grp) from t3;
 | |
| show status like 'Handler_read_rnd_next';
 | |
| select ' ^ This must show 11' Z;
 | |
| 
 | |
| # This must show trigcond:
 | |
| explain extended select a in (select max(ie) from t1 where oref=4 group by grp) from t3;
 | |
| 
 | |
| drop table t1, t2, t3;
 | |
| 
 | |
| # 
 | |
| #  2. Subquery handled with 'index_subquery':
 | |
| # 
 | |
| create table t1 (a int, oref int, key(a));
 | |
| insert into t1 values 
 | |
|   (1, 1),
 | |
|   (1, NULL),
 | |
|   (2, 3),
 | |
|   (2, NULL),
 | |
|   (3, NULL);
 | |
| 
 | |
| create table t2 (a int, oref int);
 | |
| insert into t2 values (1, 1), (2,2), (NULL, 3), (NULL, 4);
 | |
| 
 | |
| select oref, a, a in (select a from t1 where oref=t2.oref) Z from t2;
 | |
| 
 | |
| # The next explain shows "using index" but that is just incorrect display
 | |
| # (there is a bug filed about this).
 | |
| explain extended 
 | |
| select oref, a, a in (select a from t1 where oref=t2.oref) Z from t2;
 | |
| 
 | |
| flush status;
 | |
| select oref, a from t2 where a in (select a from t1 where oref=t2.oref);
 | |
| # This will only show access to t2:
 | |
| show status like '%Handler_read_rnd_next';
 | |
| 
 | |
| # Check that repeated NULL-scans are not cached (subq. is not correlated):
 | |
| delete from t2;
 | |
| insert into t2 values (NULL, 0),(NULL, 0), (NULL, 0), (NULL, 0);
 | |
| 
 | |
| flush status;
 | |
| select oref, a, a in (select a from t1 where oref=t2.oref) Z from t2;
 | |
| show status like '%Handler_read%';
 | |
| select 'No key lookups, seq reads: 29= 5 reads from t2 + 4 * 6 reads from t1.' Z;
 | |
| 
 | |
| drop table t1, t2;
 | |
| 
 | |
| #
 | |
| # 3. Subquery handled with 'unique_index_subquery':
 | |
| #
 | |
| create table t1 (a int, b int, primary key (a));
 | |
| insert into t1 values (1,1), (3,1),(100,1);
 | |
| 
 | |
| create table t2 (a int, b int);
 | |
| insert into t2 values (1,1),(2,1),(NULL,1),(NULL,0);
 | |
| 
 | |
| select a,b, a in (select a from t1 where t1.b = t2.b) Z from t2 ;
 | |
| 
 | |
| drop table t1, t2;
 | |
| 
 | |
| #
 | |
| # 4. Subquery that is a join, with ref access
 | |
| #
 | |
| create table t1 (a int, b int, key(a));
 | |
| insert into t1 values 
 | |
|   (0,0),(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9);
 | |
| 
 | |
| create table t2 like t1;
 | |
| insert into t2 select * from t1;
 | |
| update t2 set b=1;
 | |
| 
 | |
| create table t3 (a int, oref int);
 | |
| insert into t3 values (1, 1), (NULL,1), (NULL,0);
 | |
| select a, oref, 
 | |
|        t3.a in (select t1.a from t1, t2 where t1.b=t2.a and t2.b=t3.oref) Z 
 | |
| from t3;
 | |
| 
 | |
| # This must have trigcond in WHERE and HAVING:
 | |
| explain extended
 | |
| select a, oref, 
 | |
|        t3.a in (select t1.a from t1, t2 where t1.b=t2.a and t2.b=t3.oref) Z 
 | |
| from t3;
 | |
| 
 | |
| drop table t1, t2, t3;
 | |
| 
 |