Commit abb5e74d authored by Konstantin Osipov's avatar Konstantin Osipov

Backport of:

----------------------------------------------------------
revno: 2630.13.6
committer: Konstantin Osipov <konstantin@mysql.com>
branch nick: mysql-6.0-3288
timestamp: Fri 2008-07-11 20:22:44 +0400
message:
  WL#3288, step 1: ensure that the SQL layer always closes an open
  cursor (rnd or index read) before closing a handler.


sql/handler.h:
  Assert that the read is closed in handler destructor.
sql/sql_select.cc:
  Remove JOIN::table which was a piece of redundancy. The problem was
  that JOIN::cleanup() works only if JOIN::table is not null,
  but JOIN::cleanup also assigns JOIN::table to NULL. This assignment
  is apparently there for safety, from the times when we had no support for correlated
  subqueries. Indeed, in case of a evaluation of a correlated subquery more than once it led
  to JOIN::cleanup doing nothing, and leaving the rnd or index read open.
      
  In do_select(), make sure we call JOIN::join_free() even in case of an
  error.
sql/sql_select.h:
  Remove JOIN::table, JOIN::all_tables has the same functionality.
parent 3138ee3b
...@@ -1152,7 +1152,7 @@ public: ...@@ -1152,7 +1152,7 @@ public:
virtual ~handler(void) virtual ~handler(void)
{ {
DBUG_ASSERT(locked == FALSE); DBUG_ASSERT(locked == FALSE);
/* TODO: DBUG_ASSERT(inited == NONE); */ DBUG_ASSERT(inited == NONE);
} }
virtual handler *clone(MEM_ROOT *mem_root); virtual handler *clone(MEM_ROOT *mem_root);
/** This is called after create to allow us to set up cached variables */ /** This is called after create to allow us to set up cached variables */
......
...@@ -1958,15 +1958,19 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) ...@@ -1958,15 +1958,19 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
} }
} }
/* /*
Okay, got values for all arguments. Close tables that might be used by Okay, got values for all arguments. Close tables that might be used by
arguments evaluation. If arguments evaluation required prelocking mode, arguments evaluation. If arguments evaluation required prelocking mode,
we'll leave it here. we'll leave it here.
*/ */
if (!thd->in_sub_stmt) if (!thd->in_sub_stmt)
{ {
thd->lex->unit.cleanup(); thd->lex->unit.cleanup();
close_thread_tables(thd);
thd_proc_info(thd, "closing tables");
close_thread_tables(thd);
thd_proc_info(thd, 0);
thd->rollback_item_tree_changes(); thd->rollback_item_tree_changes();
} }
......
...@@ -991,13 +991,13 @@ JOIN::optimize() ...@@ -991,13 +991,13 @@ JOIN::optimize()
} }
if (const_tables && !thd->locked_tables && if (const_tables && !thd->locked_tables &&
!(select_options & SELECT_NO_UNLOCK)) !(select_options & SELECT_NO_UNLOCK))
mysql_unlock_some_tables(thd, table, const_tables); mysql_unlock_some_tables(thd, all_tables, const_tables);
if (!conds && outer_join) if (!conds && outer_join)
{ {
/* Handle the case where we have an OUTER JOIN without a WHERE */ /* Handle the case where we have an OUTER JOIN without a WHERE */
conds=new Item_int((longlong) 1,1); // Always true conds=new Item_int((longlong) 1,1); // Always true
} }
select= make_select(*table, const_table_map, select= make_select(*all_tables, const_table_map,
const_table_map, conds, 1, &error); const_table_map, conds, 1, &error);
if (error) if (error)
{ /* purecov: inspected */ { /* purecov: inspected */
...@@ -2905,7 +2905,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds, ...@@ -2905,7 +2905,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, COND *conds,
join->join_tab=stat; join->join_tab=stat;
join->map2table=stat_ref; join->map2table=stat_ref;
join->table= join->all_tables=table_vector; join->all_tables= table_vector;
join->const_tables=const_count; join->const_tables=const_count;
join->found_const_table_map=found_const_table_map; join->found_const_table_map=found_const_table_map;
...@@ -5595,7 +5595,7 @@ get_best_combination(JOIN *join) ...@@ -5595,7 +5595,7 @@ get_best_combination(JOIN *join)
{ {
TABLE *form; TABLE *form;
*j= *join->best_positions[tablenr].table; *j= *join->best_positions[tablenr].table;
form=join->table[tablenr]=j->table; form=join->all_tables[tablenr]=j->table;
used_tables|= form->map; used_tables|= form->map;
form->reginfo.join_tab=j; form->reginfo.join_tab=j;
if (!*j->on_expr_ref) if (!*j->on_expr_ref)
...@@ -5867,7 +5867,7 @@ JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table) ...@@ -5867,7 +5867,7 @@ JOIN::make_simple_join(JOIN *parent, TABLE *tmp_table)
DBUG_RETURN(TRUE); /* purecov: inspected */ DBUG_RETURN(TRUE); /* purecov: inspected */
join_tab= parent->join_tab_reexec; join_tab= parent->join_tab_reexec;
table= &parent->table_reexec[0]; parent->table_reexec[0]= tmp_table; parent->table_reexec[0]= tmp_table;
tables= 1; tables= 1;
const_tables= 0; const_tables= 0;
const_table_map= 0; const_table_map= 0;
...@@ -6899,24 +6899,23 @@ void JOIN::cleanup(bool full) ...@@ -6899,24 +6899,23 @@ void JOIN::cleanup(bool full)
{ {
DBUG_ENTER("JOIN::cleanup"); DBUG_ENTER("JOIN::cleanup");
if (table) if (all_tables)
{ {
JOIN_TAB *tab,*end; JOIN_TAB *tab,*end;
/* /*
Only a sorted table may be cached. This sorted table is always the Only a sorted table may be cached. This sorted table is always the
first non const table in join->table first non const table in join->all_tables
*/ */
if (tables > const_tables) // Test for not-const tables if (tables > const_tables) // Test for not-const tables
{ {
free_io_cache(table[const_tables]); free_io_cache(all_tables[const_tables]);
filesort_free_buffers(table[const_tables],full); filesort_free_buffers(all_tables[const_tables],full);
} }
if (full) if (full)
{ {
for (tab= join_tab, end= tab+tables; tab != end; tab++) for (tab= join_tab, end= tab+tables; tab != end; tab++)
tab->cleanup(); tab->cleanup();
table= 0;
} }
else else
{ {
...@@ -7245,7 +7244,7 @@ static void clear_tables(JOIN *join) ...@@ -7245,7 +7244,7 @@ static void clear_tables(JOIN *join)
are not re-calculated. are not re-calculated.
*/ */
for (uint i=join->const_tables ; i < join->tables ; i++) for (uint i=join->const_tables ; i < join->tables ; i++)
mark_as_null_row(join->table[i]); // All fields are NULL mark_as_null_row(join->all_tables[i]); // All fields are NULL
} }
/***************************************************************************** /*****************************************************************************
...@@ -10995,26 +10994,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) ...@@ -10995,26 +10994,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
if (error == NESTED_LOOP_NO_MORE_ROWS) if (error == NESTED_LOOP_NO_MORE_ROWS)
error= NESTED_LOOP_OK; error= NESTED_LOOP_OK;
if (error == NESTED_LOOP_OK)
{
/*
Sic: this branch works even if rc != 0, e.g. when
send_data above returns an error.
*/
if (!table) // If sending data to client
{
/*
The following will unlock all cursors if the command wasn't an
update command
*/
join->join_free(); // Unlock all cursors
if (join->result->send_eof())
rc= 1; // Don't send error
}
DBUG_PRINT("info",("%ld records output", (long) join->send_records));
}
else
rc= -1;
if (table) if (table)
{ {
int tmp, new_errno= 0; int tmp, new_errno= 0;
...@@ -11031,6 +11011,29 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) ...@@ -11031,6 +11011,29 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
if (new_errno) if (new_errno)
table->file->print_error(new_errno,MYF(0)); table->file->print_error(new_errno,MYF(0));
} }
else
{
/*
The following will unlock all cursors if the command wasn't an
update command
*/
join->join_free(); // Unlock all cursors
}
if (error == NESTED_LOOP_OK)
{
/*
Sic: this branch works even if rc != 0, e.g. when
send_data above returns an error.
*/
if (!table) // If sending data to client
{
if (join->result->send_eof())
rc= 1; // Don't send error
}
DBUG_PRINT("info",("%ld records output", (long) join->send_records));
}
else
rc= -1;
#ifndef DBUG_OFF #ifndef DBUG_OFF
if (rc) if (rc)
{ {
......
...@@ -280,7 +280,7 @@ public: ...@@ -280,7 +280,7 @@ public:
JOIN_TAB *join_tab,**best_ref; JOIN_TAB *join_tab,**best_ref;
JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs
JOIN_TAB *join_tab_save; ///< saved join_tab for subquery reexecution JOIN_TAB *join_tab_save; ///< saved join_tab for subquery reexecution
TABLE **table,**all_tables,*sort_by_table; TABLE **all_tables,*sort_by_table;
uint tables,const_tables; uint tables,const_tables;
uint send_group_parts; uint send_group_parts;
bool sort_and_group,first_record,full_join,group, no_field_update; bool sort_and_group,first_record,full_join,group, no_field_update;
...@@ -427,7 +427,7 @@ public: ...@@ -427,7 +427,7 @@ public:
select_result *result_arg) select_result *result_arg)
{ {
join_tab= join_tab_save= 0; join_tab= join_tab_save= 0;
table= 0; all_tables= 0;
tables= 0; tables= 0;
const_tables= 0; const_tables= 0;
join_list= 0; join_list= 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment