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

Fix for BUG#15229.

The cause of this bug was a design flaw due to which the list of natural
join columns was incorrectly computed and stored for nested joins that
are not natural joins, but are operands (possibly indirect) of nested joins.

The patch corrects the flaw in a such a way, that the result columns of a
table reference are materialized only if it is a leaf table (that is, only
if it is a view, stored table, or natural/using join).


mysql-test/r/join.result:
  Added test for BUG#15229 and uncommented failing test cases of
  BUG#15357 (now fixed by this patch).
mysql-test/t/join.test:
  Added test for BUG#15229 and uncommented failing test cases of
  BUG#15357 (now fixed by this patch).
sql/sql_base.cc:
  - Do not materialize the result columns of regular nested joins
    (that are not natural/using joins).
  - Moved most of the code that creates/adds new natural join column
    references to the method 'get_or_create_column_ref', and simplified
    'mark_common_columns'.
  - Replaced a call to 'get_or_create_column_ref' with 'get_natural_column_ref'
    where it is for sure all columns are alredy created.
sql/table.cc:
  - Modified the method 'get_or_create_column_ref' so that it adds itself
    the newly created natural join columns to the respective table reference.
sql/table.h:
  - Modified the method 'get_or_create_column_ref' so that it adds itself
    the newly created natural join columns to the respective table reference.
This commit is contained in:
unknown
2006-03-02 11:50:15 +02:00
parent f095abaa47
commit de1e87bbcd
5 changed files with 166 additions and 56 deletions

View File

@ -3608,8 +3608,18 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
Natural_join_column *nj_col_1, *nj_col_2;
const char *field_name_1;
Query_arena *arena, backup;
bool add_columns= TRUE;
bool result= TRUE;
bool first_outer_loop= TRUE;
/*
Leaf table references to which new natural join columns are added
if the leaves are != NULL.
*/
TABLE_LIST *leaf_1= (table_ref_1->nested_join &&
!table_ref_1->is_natural_join) ?
NULL : table_ref_1;
TABLE_LIST *leaf_2= (table_ref_2->nested_join &&
!table_ref_2->is_natural_join) ?
NULL : table_ref_2;
DBUG_ENTER("mark_common_columns");
DBUG_PRINT("info", ("operand_1: %s operand_2: %s",
@ -3618,35 +3628,13 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
*found_using_fields= 0;
arena= thd->activate_stmt_arena_if_needed(&backup);
/*
TABLE_LIST::join_columns could be allocated by the previous call to
store_natural_using_join_columns() for the lower level of nested tables.
*/
if (!table_ref_1->join_columns)
{
if (!(table_ref_1->join_columns= new List<Natural_join_column>))
goto err;
table_ref_1->is_join_columns_complete= FALSE;
}
if (!table_ref_2->join_columns)
{
if (!(table_ref_2->join_columns= new List<Natural_join_column>))
goto err;
table_ref_2->is_join_columns_complete= FALSE;
}
for (it_1.set(table_ref_1); !it_1.end_of_fields(); it_1.next())
{
bool is_created_1;
bool found= FALSE;
if (!(nj_col_1= it_1.get_or_create_column_ref(&is_created_1)))
if (!(nj_col_1= it_1.get_or_create_column_ref(leaf_1)))
goto err;
field_name_1= nj_col_1->name();
/* If nj_col_1 was just created add it to the list of join columns. */
if (is_created_1)
table_ref_1->join_columns->push_back(nj_col_1);
/*
Find a field with the same name in table_ref_2.
@ -3657,17 +3645,12 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
nj_col_2= NULL;
for (it_2.set(table_ref_2); !it_2.end_of_fields(); it_2.next())
{
bool is_created_2;
Natural_join_column *cur_nj_col_2;
const char *cur_field_name_2;
if (!(cur_nj_col_2= it_2.get_or_create_column_ref(&is_created_2)))
if (!(cur_nj_col_2= it_2.get_or_create_column_ref(leaf_2)))
goto err;
cur_field_name_2= cur_nj_col_2->name();
/* If nj_col_1 was just created add it to the list of join columns. */
if (add_columns && is_created_2)
table_ref_2->join_columns->push_back(cur_nj_col_2);
/*
Compare the two columns and check for duplicate common fields.
A common field is duplicate either if it was already found in
@ -3686,9 +3669,15 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
found= TRUE;
}
}
/* Force it_2.set() to use table_ref_2->join_columns. */
table_ref_2->is_join_columns_complete= TRUE;
add_columns= FALSE;
if (first_outer_loop && leaf_2)
{
/*
Make sure that the next inner loop "knows" that all columns
are materialized already.
*/
leaf_2->is_join_columns_complete= TRUE;
first_outer_loop= FALSE;
}
if (!found)
continue; // No matching field
@ -3772,7 +3761,8 @@ mark_common_columns(THD *thd, TABLE_LIST *table_ref_1, TABLE_LIST *table_ref_2,
++(*found_using_fields);
}
}
table_ref_1->is_join_columns_complete= TRUE;
if (leaf_1)
leaf_1->is_join_columns_complete= TRUE;
/*
Everything is OK.
@ -4625,16 +4615,15 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
if (tables->is_natural_join)
{
bool is_created;
TABLE *field_table;
/*
In this case we are sure that the column ref will not be created
because it was already created and stored with the natural join.
*/
Natural_join_column *nj_col;
if (!(nj_col= field_iterator.get_or_create_column_ref(&is_created)))
if (!(nj_col= field_iterator.get_natural_column_ref()))
DBUG_RETURN(TRUE);
DBUG_ASSERT(nj_col->table_field && !is_created);
DBUG_ASSERT(nj_col->table_field);
field_table= nj_col->table_ref->table;
if (field_table)
{