1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Fix for bug#58490, 'Incorrect result in multi level OUTER JOIN

in combination with IS NULL'
      
As this bug is a duplicate of bug#49322, it also includes test cases
covering this bugreport
      
Qualifying an OUTER JOIN with the condition 'WHERE <column> IS NULL',
where <column> is declared as 'NOT NULL' causes the
'not_exists_optimize' to be enabled by the optimizer.
      
In evaluate_join_record() the 'not_exists_optimize' caused
'NESTED_LOOP_NO_MORE_ROWS' to be returned immediately
when a matching row was found.
      
However, as the 'not_exists_optimize' is derived from
'JOIN_TAB::select_cond', the usual rules for condition guards
also applies for 'not_exist_optimize'. It is therefore incorrect
to check 'not_exists_optimize' without ensuring that all guards
protecting it is 'open'.
      
This fix uses the fact that 'not_exists_optimize' is derived from
a 'is_null' predicate term in 'tab->select_cond'. Furthermore,
'is_null' will evaluate to 'false' for any 'non-null' rows
once all guards protecting the is_null is open.
      
We can use this knowledge as an implicit guard check for the
'not_exists_optimize' by moving 'if (...not_exists_optimize)'
inside the handling of 'select_cond==false'. It will then
not take effect before its guards are open.
      
We also add an assert which requires that a
'not_exists_optimize' always comes together with
a select_cond. (containing 'is_null').
This commit is contained in:
Ole John Aske
2011-02-01 15:19:34 +01:00
parent 4b8888f6f0
commit ed74edada2
3 changed files with 291 additions and 2 deletions

View File

@ -11767,17 +11767,40 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
first_unmatched->found= 1;
for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++)
{
if (tab->table->reginfo.not_exists_optimize)
return NESTED_LOOP_NO_MORE_ROWS;
/* Check all predicates that has just been activated. */
/*
Actually all predicates non-guarded by first_unmatched->found
will be re-evaluated again. It could be fixed, but, probably,
it's not worth doing now.
*/
/*
not_exists_optimize has been created from a
select_cond containing 'is_null'. This 'is_null'
predicate is still present on any 'tab' with
'not_exists_optimize'. Furthermore, the usual rules
for condition guards also applies for
'not_exists_optimize' -> When 'is_null==false' we
know all cond. guards are open and we can apply
the 'not_exists_optimize'.
*/
DBUG_ASSERT(!(tab->table->reginfo.not_exists_optimize &&
!tab->select_cond));
if (tab->select_cond && !tab->select_cond->val_int())
{
/* The condition attached to table tab is false */
if (tab->table->reginfo.not_exists_optimize)
{
/*
When not_exists_optimize is set: No need to further
explore more rows of 'tab' for this partial result.
Any found 'tab' matches are known to evaluate to 'false'.
Returning .._NO_MORE_ROWS will skip rem. 'tab' rows.
*/
return NESTED_LOOP_NO_MORE_ROWS;
}
if (tab == join_tab)
found= 0;
else