Commit 568c6e85 authored by konstantin@mysql.com's avatar konstantin@mysql.com

Fix for bug#4912 "mysqld crashs in case a statement is executed

 a second time". The bug was caused by incompatibility of
negations elimination algorithm and PS: during first statement 
execute a subtree with negation was replaced with equivalent 
subtree without NOTs.
The problem was that although this transformation was permanent, 
items of the new subtree were created in execute-local memory.
The patch adds means to check if it is the first execute of a
prepared statement, and if this is the case, to allocate items
in memory of the prepared statement.
The implementation:
- backports Item_arena from 5.0
- adds Item_arena::is_stmt_prepare(), 
  Item_arena::is_first_stmt_execute().
- deletes THD::allocate_temporary_pool_for_ps_preparing(),
  THD::free_temporary_pool_for_ps_preparing(); they
  were redundant.
and adds a few invariants:
- thd->free_list never contains junk (= freed items)
- thd->current_arena is never null. If there is no
  prepared statement, it points at the thd. 
The rest of the patch contains mainly mechanical changes and
cleanups.
parent b9dbef8e
......@@ -219,3 +219,10 @@ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length I
t1 MyISAM 9 Dynamic 0 0 0 4294967295 1024 0 NULL # # # latin1_swedish_ci NULL
deallocate prepare stmt1 ;
drop table t1;
create table t1(a varchar(2), b varchar(3));
prepare stmt1 from "select a, b from t1 where (not (a='aa' and b < 'zzz'))";
execute stmt1;
a b
execute stmt1;
a b
deallocate prepare stmt1;
......@@ -206,3 +206,15 @@ execute stmt1;
show table status from test like 't1%' ;
deallocate prepare stmt1 ;
drop table t1;
#
# Bug#4912 "mysqld crashs in case a statement is executed a second time":
# negation elimination should and prepared statemens
#
create table t1(a varchar(2), b varchar(3));
prepare stmt1 from "select a, b from t1 where (not (a='aa' and b < 'zzz'))";
execute stmt1;
execute stmt1;
deallocate prepare stmt1;
......@@ -589,10 +589,8 @@ bool Item_in_optimizer::fix_left(THD *thd,
/*
If it is preparation PS only then we do not know values of parameters =>
cant't get there values and do not need that values.
TODO: during merge with 5.0 it should be changed on !thd->only_prepare()
*/
if (!thd->current_statement)
if (! thd->current_arena->is_stmt_prepare())
cache->store(args[0]);
if (cache->cols() == 1)
{
......
......@@ -125,7 +125,6 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param));
stmt= thd->current_statement;
char const *save_where= thd->where;
int res;
......@@ -306,7 +305,10 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
return RES_OK;
SELECT_LEX *select_lex= join->select_lex;
Statement backup;
/* Juggle with current arena only if we're in prepared statement prepare */
Item_arena *arena= join->thd->current_arena;
Item_arena backup;
if (!select_lex->master_unit()->first_select()->next_select() &&
!select_lex->table_list.elements &&
......@@ -341,8 +343,8 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
if (join->conds || join->having)
{
Item *cond;
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->set_n_backup_item_arena(arena, &backup);
if (!join->having)
cond= join->conds;
......@@ -355,15 +357,15 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
new Item_null())))
goto err;
}
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
return RES_REDUCE;
}
return RES_OK;
err:
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
return RES_ERROR;
}
......@@ -640,11 +642,11 @@ Item_in_subselect::single_value_transformer(JOIN *join,
}
SELECT_LEX *select_lex= join->select_lex;
Statement backup;
Item_arena *arena= join->thd->current_arena, backup;
thd->where= "scalar IN/ALL/ANY subquery";
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->set_n_backup_item_arena(arena, &backup);
if (select_lex->item_list.elements > 1)
{
......@@ -857,21 +859,21 @@ Item_in_subselect::single_value_transformer(JOIN *join,
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SELECT_REDUCED, warn_buff);
}
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_REDUCE);
}
}
}
ok:
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_OK);
err:
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_ERROR);
}
......@@ -885,12 +887,12 @@ Item_in_subselect::row_value_transformer(JOIN *join)
{
DBUG_RETURN(RES_OK);
}
Statement backup;
Item_arena *arena= join->thd->current_arena, backup;
Item *item= 0;
thd->where= "row IN/ALL/ANY subquery";
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->set_n_backup_item_arena(arena, &backup);
SELECT_LEX *select_lex= join->select_lex;
......@@ -974,13 +976,13 @@ Item_in_subselect::row_value_transformer(JOIN *join)
if (join->conds->fix_fields(thd, join->tables_list, 0))
goto err;
}
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_OK);
err:
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(RES_ERROR);
}
......
......@@ -36,8 +36,6 @@ class Item_subselect :public Item_result_field
protected:
/* thread handler, will be assigned in fix_fields only */
THD *thd;
/* prepared statement, or 0 */
Statement *stmt;
/* substitution instead of subselect in case of optimization */
Item *substitution;
/* unit of subquery */
......
......@@ -64,28 +64,28 @@ Item_sum::Item_sum(THD *thd, Item_sum *item):
/*
Save copy of arguments if we are prepare prepared statement
Save copy of arguments if we prepare prepared statement
(arguments can be rewritten in get_tmp_table_item())
SYNOPSIS
Item_sum::save_args_for_prepared_statements()
Item_sum::save_args_for_prepared_statement()
thd - thread handler
RETURN
0 - OK
1 - Error
*/
bool Item_sum::save_args_for_prepared_statements(THD *thd)
bool Item_sum::save_args_for_prepared_statement(THD *thd)
{
if (thd->current_statement)
return save_args(thd->current_statement);
if (thd->current_arena->is_stmt_prepare())
return save_args(thd->current_arena);
return 0;
}
bool Item_sum::save_args(Statement* stmt)
bool Item_sum::save_args(Item_arena* arena)
{
if (!(args_copy= (Item**) stmt->alloc(sizeof(Item*)*arg_count)))
if (!(args_copy= (Item**) arena->alloc(sizeof(Item*)*arg_count)))
return 1;
memcpy(args_copy, args, sizeof(Item*)*arg_count);
return 0;
......@@ -214,7 +214,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
if (save_args_for_prepared_statements(thd))
if (save_args_for_prepared_statement(thd))
return 1;
if (!thd->allow_sum_func)
......@@ -248,7 +248,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
if (save_args_for_prepared_statements(thd))
if (save_args_for_prepared_statement(thd))
return 1;
Item *item= args[0];
......@@ -1947,7 +1947,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
if (save_args_for_prepared_statements(thd))
if (save_args_for_prepared_statement(thd))
return 1;
uint i; /* for loop variable */
......
......@@ -92,8 +92,8 @@ class Item_sum :public Item_result_field
virtual bool setup(THD *thd) {return 0;}
virtual void make_unique() {}
Item *get_tmp_table_item(THD *thd);
bool save_args_for_prepared_statements(THD *);
bool save_args(Statement* stmt);
bool save_args_for_prepared_statement(THD *);
bool save_args(Item_arena *arena);
bool walk (Item_processor processor, byte *argument);
};
......
......@@ -295,7 +295,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout);
struct st_table;
class THD;
class Statement;
class Item_arena;
/* Struct to handle simple linked lists */
......
......@@ -2188,14 +2188,15 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
{
if (!wild_num)
return 0;
Statement *stmt= thd->current_statement, backup;
Item_arena *arena= thd->current_arena, backup;
/*
If we are in preparing prepared statement phase then we have change
temporary mem_root to statement mem root to save changes of SELECT list
*/
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->set_n_backup_item_arena(arena, &backup);
reg2 Item *item;
List_iterator<Item> it(fields);
while ( wild_num && (item= it++))
......@@ -2219,8 +2220,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
else if (insert_fields(thd,tables,((Item_field*) item)->db_name,
((Item_field*) item)->table_name, &it))
{
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
return (-1);
}
if (sum_func_list)
......@@ -2235,8 +2236,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
wild_num--;
}
}
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
return 0;
}
......@@ -2449,7 +2450,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
table_map not_null_tables= 0;
Statement *stmt= thd->current_statement, backup;
Item_arena *arena= thd->current_arena, backup;
DBUG_ENTER("setup_conds");
thd->set_query_id=1;
......@@ -2488,12 +2489,12 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
!(specialflag & SPECIAL_NO_NEW_FUNC)))
{
table->outer_join= 0;
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->set_n_backup_item_arena(arena, &backup);
*conds= and_conds(*conds, table->on_expr);
table->on_expr=0;
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
if ((*conds) && !(*conds)->fixed &&
(*conds)->fix_fields(thd, tables, conds))
DBUG_RETURN(1);
......@@ -2501,8 +2502,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
}
if (table->natural_join)
{
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->set_n_backup_item_arena(arena, &backup);
/* Make a join of all fields with have the same name */
TABLE *t1= table->table;
TABLE *t2= table->natural_join->table;
......@@ -2543,8 +2544,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
*conds= and_conds(*conds, cond_and);
// fix_fields() should be made with temporary memory pool
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
if (*conds && !(*conds)->fixed)
{
if ((*conds)->fix_fields(thd, tables, conds))
......@@ -2555,8 +2556,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
table->on_expr= and_conds(table->on_expr, cond_and);
// fix_fields() should be made with temporary memory pool
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
if (table->on_expr && !table->on_expr->fixed)
{
if (table->on_expr->fix_fields(thd, tables, &table->on_expr))
......@@ -2567,7 +2568,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
}
}
if (stmt)
if (arena->is_stmt_prepare())
{
/*
We are in prepared statement preparation code => we should store
......@@ -2580,8 +2581,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
DBUG_RETURN(test(thd->net.report_error));
err:
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(1);
}
......
......@@ -155,7 +155,7 @@ bool foreign_key_prefix(Key *a, Key *b)
** Thread specific functions
****************************************************************************/
THD::THD():user_time(0), current_statement(0), is_fatal_error(0),
THD::THD():user_time(0), current_arena(this), is_fatal_error(0),
last_insert_id_used(0),
insert_id_used(0), rand_used(0), time_zone_used(0),
in_lock_tables(0), global_read_lock(0), bootstrap(0)
......@@ -1301,23 +1301,59 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
}
Item_arena::Item_arena(THD* thd)
:free_list(0),
state(INITIALIZED)
{
init_sql_alloc(&mem_root,
thd->variables.query_alloc_block_size,
thd->variables.query_prealloc_size);
}
/* This constructor is called when Item_arena is a subobject of THD */
Item_arena::Item_arena()
:free_list(0),
state(CONVENTIONAL_EXECUTION)
{
clear_alloc_root(&mem_root);
}
Item_arena::Item_arena(bool init_mem_root)
:free_list(0),
state(INITIALIZED)
{
if (init_mem_root)
clear_alloc_root(&mem_root);
}
Item_arena::Type Item_arena::type() const
{
DBUG_ASSERT("Item_arena::type()" == "abstract");
return STATEMENT;
}
Item_arena::~Item_arena()
{}
/*
Statement functions
*/
Statement::Statement(THD *thd)
:id(++thd->statement_id_counter),
:Item_arena(thd),
id(++thd->statement_id_counter),
set_query_id(1),
allow_sum_func(0),
lex(&main_lex),
query(0),
query_length(0),
free_list(0)
query_length(0)
{
name.str= NULL;
init_sql_alloc(&mem_root,
thd->variables.query_alloc_block_size,
thd->variables.query_prealloc_size);
}
/*
......@@ -1332,14 +1368,12 @@ Statement::Statement()
allow_sum_func(0), /* initialized later */
lex(&main_lex),
query(0), /* these two are set */
query_length(0), /* in alloc_query() */
free_list(0)
query_length(0) /* in alloc_query() */
{
bzero((char *) &mem_root, sizeof(mem_root));
}
Statement::Type Statement::type() const
Item_arena::Type Statement::type() const
{
return STATEMENT;
}
......@@ -1356,14 +1390,29 @@ void Statement::set_statement(Statement *stmt)
}
void Statement::set_n_backup_item_arena(Statement *set, Statement *backup)
void
Statement::set_n_backup_statement(Statement *stmt, Statement *backup)
{
backup->set_statement(this);
set_statement(stmt);
}
void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
{
stmt->set_statement(this);
set_statement(backup);
}
void Item_arena::set_n_backup_item_arena(Item_arena *set, Item_arena *backup)
{
backup->set_item_arena(this);
set_item_arena(set);
}
void Statement::restore_backup_item_arena(Statement *set, Statement *backup)
void Item_arena::restore_backup_item_arena(Item_arena *set, Item_arena *backup)
{
set->set_item_arena(this);
set_item_arena(backup);
......@@ -1371,10 +1420,11 @@ void Statement::restore_backup_item_arena(Statement *set, Statement *backup)
init_alloc_root(&backup->mem_root, 0, 0);
}
void Statement::set_item_arena(Statement *set)
void Item_arena::set_item_arena(Item_arena *set)
{
mem_root= set->mem_root;
free_list= set->free_list;
state= set->state;
}
Statement::~Statement()
......
......@@ -418,6 +418,61 @@ struct system_variables
void free_tmp_table(THD *thd, TABLE *entry);
class Item_arena
{
public:
/*
List of items created in the parser for this query. Every item puts
itself to the list on creation (see Item::Item() for details))
*/
Item *free_list;
MEM_ROOT mem_root;
static const int INITIALIZED= 0, PREPARED= 1, EXECUTED= 3,
CONVENTIONAL_EXECUTION= 2, ERROR= -1;
int state;
/* We build without RTTI, so dynamic_cast can't be used. */
enum Type
{
STATEMENT, PREPARED_STATEMENT, STORED_PROCEDURE
};
Item_arena(THD *thd);
Item_arena();
Item_arena(bool init_mem_root);
virtual Type type() const;
virtual ~Item_arena();
inline bool is_stmt_prepare() const { return state < PREPARED; }
inline bool is_first_stmt_execute() const { return state == PREPARED; }
inline gptr alloc(unsigned int size) { return alloc_root(&mem_root,size); }
inline gptr calloc(unsigned int size)
{
gptr ptr;
if ((ptr=alloc_root(&mem_root,size)))
bzero((char*) ptr,size);
return ptr;
}
inline char *strdup(const char *str)
{ return strdup_root(&mem_root,str); }
inline char *strmake(const char *str, uint size)
{ return strmake_root(&mem_root,str,size); }
inline char *memdup(const char *str, uint size)
{ return memdup_root(&mem_root,str,size); }
inline char *memdup_w_gap(const char *str, uint size, uint gap)
{
gptr ptr;
if ((ptr=alloc_root(&mem_root,size+gap)))
memcpy(ptr,str,size);
return ptr;
}
void set_n_backup_item_arena(Item_arena *set, Item_arena *backup);
void restore_backup_item_arena(Item_arena *set, Item_arena *backup);
void set_item_arena(Item_arena *set);
};
/*
State of a single command executed against this connection.
One connection can contain a lot of simultaneously running statements,
......@@ -432,7 +487,7 @@ void free_tmp_table(THD *thd, TABLE *entry);
be used explicitly.
*/
class Statement
class Statement: public Item_arena
{
Statement(const Statement &rhs); /* not implemented: */
Statement &operator=(const Statement &rhs); /* non-copyable */
......@@ -474,20 +529,8 @@ class Statement
*/
char *query;
uint32 query_length; // current query length
/*
List of items created in the parser for this query. Every item puts
itself to the list on creation (see Item::Item() for details))
*/
Item *free_list;
MEM_ROOT mem_root;
public:
/* We build without RTTI, so dynamic_cast can't be used. */
enum Type
{
STATEMENT,
PREPARED_STATEMENT
};
/*
This constructor is called when statement is a subobject of THD:
......@@ -500,34 +543,10 @@ class Statement
/* Assign execution context (note: not all members) of given stmt to self */
void set_statement(Statement *stmt);
void set_n_backup_statement(Statement *stmt, Statement *backup);
void restore_backup_statement(Statement *stmt, Statement *backup);
/* return class type */
virtual Type type() const;
inline gptr alloc(unsigned int size) { return alloc_root(&mem_root,size); }
inline gptr calloc(unsigned int size)
{
gptr ptr;
if ((ptr=alloc_root(&mem_root,size)))
bzero((char*) ptr,size);
return ptr;
}
inline char *strdup(const char *str)
{ return strdup_root(&mem_root,str); }
inline char *strmake(const char *str, uint size)
{ return strmake_root(&mem_root,str,size); }
inline char *memdup(const char *str, uint size)
{ return memdup_root(&mem_root,str,size); }
inline char *memdup_w_gap(const char *str, uint size, uint gap)
{
gptr ptr;
if ((ptr=alloc_root(&mem_root,size+gap)))
memcpy(ptr,str,size);
return ptr;
}
void set_n_backup_item_arena(Statement *set, Statement *backup);
void restore_backup_item_arena(Statement *set, Statement *backup);
void set_item_arena(Statement *set);
};
......@@ -760,9 +779,9 @@ class THD :public ilink,
Vio* active_vio;
#endif
/*
Current prepared Statement if there one, or 0
Current prepared Item_arena if there one, or 0
*/
Statement *current_statement;
Item_arena *current_arena;
/*
next_insert_id is set on SET INSERT_ID= #. This is used as the next
generated auto_increment value in handler.cc
......@@ -983,33 +1002,6 @@ class THD :public ilink,
}
inline CHARSET_INFO *charset() { return variables.character_set_client; }
void update_charset();
inline void allocate_temporary_memory_pool_for_ps_preparing()
{
DBUG_ASSERT(current_statement!=0);
/*
We do not want to have in PS memory all that junk,
which will be created by preparation => substitute memory
from original thread pool.
We know that PS memory pool is now copied to THD, we move it back
to allow some code use it.
*/
current_statement->set_item_arena(this);
init_sql_alloc(&mem_root,
variables.query_alloc_block_size,
variables.query_prealloc_size);
free_list= 0;
}
inline void free_temporary_memory_pool_for_ps_preparing()
{
DBUG_ASSERT(current_statement!=0);
cleanup_items(current_statement->free_list);
free_items(free_list);
close_thread_tables(this); // to close derived tables
free_root(&mem_root, MYF(0));
set_item_arena(current_statement);
}
};
/* Flags for the THD::system_thread (bitmap) variable */
......
......@@ -151,7 +151,7 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
if it is preparation PS only then we do not need real data and we
can skip execution (and parameters is not defined, too)
*/
if (!thd->current_statement)
if (! thd->current_arena->is_stmt_prepare())
{
if (is_union)
{
......
......@@ -1527,9 +1527,9 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
We have to create array in prepared statement memory if it is
prepared statement
*/
Statement *stmt= thd->current_statement ? thd->current_statement : thd;
Item_arena *arena= thd->current_arena;
return (ref_pointer_array=
(Item **)stmt->alloc(sizeof(Item*) *
(Item **)arena->alloc(sizeof(Item*) *
(item_list.elements +
select_n_having_items +
order_group_num)* 5)) == 0;
......
......@@ -1543,6 +1543,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
mysqld_list_fields(thd,&table_list,fields);
free_items(thd->free_list);
thd->free_list= 0;
break;
}
#endif
......@@ -4047,6 +4048,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
}
thd->proc_info="freeing items";
free_items(thd->free_list); /* Free strings used by items */
thd->free_list= 0;
lex_end(lex);
}
DBUG_VOID_RETURN;
......@@ -4073,6 +4075,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
error= 1; /* Ignore question */
free_items(thd->free_list); /* Free strings used by items */
thd->free_list= 0;
lex_end(lex);
return error;
......
This diff is collapsed.
......@@ -4377,25 +4377,39 @@ COND *eliminate_not_funcs(THD *thd, COND *cond)
static COND *
optimize_cond(THD *thd, COND *conds, Item::cond_result *cond_value)
{
SELECT_LEX *select= thd->lex->current_select;
DBUG_ENTER("optimize_cond");
if (!conds)
if (conds)
{
*cond_value= Item::COND_TRUE;
DBUG_RETURN(conds);
DBUG_EXECUTE("where", print_where(conds, "original"););
/* Eliminate NOT operators; in case of PS/SP do it once */
if (thd->current_arena->is_first_stmt_execute())
{
Item_arena *arena= thd->current_arena, backup;
thd->set_n_backup_item_arena(arena, &backup);
conds= eliminate_not_funcs(thd, conds);
select->prep_where= conds->copy_andor_structure(thd);
thd->restore_backup_item_arena(arena, &backup);
}
DBUG_EXECUTE("where",print_where(conds,"original"););
/* eliminate NOT operators */
else
conds= eliminate_not_funcs(thd, conds);
DBUG_EXECUTE("where", print_where(conds, "after negation elimination"););
/* change field = field to field = const for each found field = const */
propagate_cond_constants((I_List<COND_CMP> *) 0,conds,conds);
propagate_cond_constants((I_List<COND_CMP> *) 0, conds, conds);
/*
Remove all instances of item == item
Remove all and-levels where CONST item != CONST item
*/
DBUG_EXECUTE("where",print_where(conds,"after const change"););
conds= remove_eq_conds(thd, conds, cond_value) ;
DBUG_EXECUTE("info",print_where(conds,"after remove"););
DBUG_EXECUTE("where", print_where(conds, "after const change"););
conds= remove_eq_conds(thd, conds, cond_value);
DBUG_EXECUTE("info", print_where(conds, "after remove"););
}
else
{
*cond_value= Item::COND_TRUE;
select->prep_where= 0;
}
DBUG_RETURN(conds);
}
......
......@@ -287,24 +287,23 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
thd_arg->lex->current_select= lex_select_save;
if (!item_list.elements)
{
Statement *stmt= thd->current_statement;
Statement backup;
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
Item_arena *arena= thd->current_arena, backup;
if (arena->is_stmt_prepare())
thd->set_n_backup_item_arena(arena, &backup);
Field **field;
for (field= table->field; *field; field++)
{
Item_field *item= new Item_field(*field);
if (!item || item_list.push_back(item))
{
if (stmt)
thd->restore_backup_item_arena(stmt, &backup);
if (arena->is_stmt_prepare())
thd->restore_backup_item_arena(arena, &backup);
DBUG_RETURN(-1);
}
}
if (stmt)
if (arena->is_stmt_prepare())
{
thd->restore_backup_item_arena(stmt, &backup);
thd->restore_backup_item_arena(arena, &backup);
/* prepare fake select to initialize it correctly */
ulong options_tmp= init_prepare_fake_select_lex(thd);
......
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