mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 10:14:19 +01:00
Merge: manual resolve
This commit is contained in:
commit
522a27069f
10 changed files with 158 additions and 72 deletions
|
@ -226,3 +226,18 @@ a b
|
|||
execute stmt1;
|
||||
a b
|
||||
deallocate prepare stmt1;
|
||||
drop table t1;
|
||||
prepare stmt1 from "select 1 into @var";
|
||||
execute stmt1;
|
||||
execute stmt1;
|
||||
prepare stmt1 from "create table t1 select 1 as i";
|
||||
execute stmt1;
|
||||
drop table t1;
|
||||
execute stmt1;
|
||||
prepare stmt1 from "insert into t1 select i from t1";
|
||||
execute stmt1;
|
||||
execute stmt1;
|
||||
prepare stmt1 from "select * from t1 into outfile 'f1.txt'";
|
||||
execute stmt1;
|
||||
deallocate prepare stmt1;
|
||||
drop table t1;
|
||||
|
|
|
@ -209,7 +209,7 @@ drop table t1;
|
|||
|
||||
#
|
||||
# Bug#4912 "mysqld crashs in case a statement is executed a second time":
|
||||
# negation elimination should and prepared statemens
|
||||
# negation elimination should work once and not break prepared statements
|
||||
#
|
||||
|
||||
create table t1(a varchar(2), b varchar(3));
|
||||
|
@ -217,4 +217,26 @@ prepare stmt1 from "select a, b from t1 where (not (a='aa' and b < 'zzz'))";
|
|||
execute stmt1;
|
||||
execute stmt1;
|
||||
deallocate prepare stmt1;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Bug#5034 "prepared "select 1 into @arg15", second execute crashes
|
||||
# server".
|
||||
# Check that descendands of select_result can be reused in prepared
|
||||
# statements or are correctly created and deleted on each execute
|
||||
#
|
||||
|
||||
prepare stmt1 from "select 1 into @var";
|
||||
execute stmt1;
|
||||
execute stmt1;
|
||||
prepare stmt1 from "create table t1 select 1 as i";
|
||||
execute stmt1;
|
||||
drop table t1;
|
||||
execute stmt1;
|
||||
prepare stmt1 from "insert into t1 select i from t1";
|
||||
execute stmt1;
|
||||
execute stmt1;
|
||||
prepare stmt1 from "select * from t1 into outfile 'f1.txt'";
|
||||
execute stmt1;
|
||||
deallocate prepare stmt1;
|
||||
drop table t1;
|
||||
|
|
|
@ -708,6 +708,12 @@ void select_result::send_error(uint errcode,const char *err)
|
|||
::send_error(thd, errcode, err);
|
||||
}
|
||||
|
||||
|
||||
void select_result::cleanup()
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
static String default_line_term("\n",default_charset_info);
|
||||
static String default_escaped("\\",default_charset_info);
|
||||
static String default_field_term("\t",default_charset_info);
|
||||
|
@ -813,6 +819,32 @@ void select_to_file::send_error(uint errcode,const char *err)
|
|||
}
|
||||
|
||||
|
||||
bool select_to_file::send_eof()
|
||||
{
|
||||
int error= test(end_io_cache(&cache));
|
||||
if (my_close(file,MYF(MY_WME)))
|
||||
error= 1;
|
||||
if (!error)
|
||||
::send_ok(thd,row_count);
|
||||
file= -1;
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
void select_to_file::cleanup()
|
||||
{
|
||||
/* In case of error send_eof() may be not called: close the file here. */
|
||||
if (file >= 0)
|
||||
{
|
||||
(void) end_io_cache(&cache);
|
||||
(void) my_close(file,MYF(0));
|
||||
file= -1;
|
||||
}
|
||||
path[0]= '\0';
|
||||
row_count= 0;
|
||||
}
|
||||
|
||||
|
||||
select_to_file::~select_to_file()
|
||||
{
|
||||
if (file >= 0)
|
||||
|
@ -1063,18 +1095,6 @@ err:
|
|||
}
|
||||
|
||||
|
||||
bool select_export::send_eof()
|
||||
{
|
||||
int error=test(end_io_cache(&cache));
|
||||
if (my_close(file,MYF(MY_WME)))
|
||||
error=1;
|
||||
if (!error)
|
||||
::send_ok(thd,row_count);
|
||||
file= -1;
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** Dump of select to a binary file
|
||||
***************************************************************************/
|
||||
|
@ -1128,18 +1148,6 @@ err:
|
|||
}
|
||||
|
||||
|
||||
bool select_dump::send_eof()
|
||||
{
|
||||
int error=test(end_io_cache(&cache));
|
||||
if (my_close(file,MYF(MY_WME)))
|
||||
error=1;
|
||||
if (!error)
|
||||
::send_ok(thd,row_count);
|
||||
file= -1;
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
select_subselect::select_subselect(Item_subselect *item_arg)
|
||||
{
|
||||
item= item_arg;
|
||||
|
@ -1306,6 +1314,13 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
|
|||
}
|
||||
|
||||
|
||||
void select_dumpvar::cleanup()
|
||||
{
|
||||
vars.empty();
|
||||
row_count=0;
|
||||
}
|
||||
|
||||
|
||||
Item_arena::Item_arena(THD* thd)
|
||||
:free_list(0),
|
||||
state((int)INITIALIZED)
|
||||
|
@ -1410,6 +1425,21 @@ void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
|
|||
}
|
||||
|
||||
|
||||
void Statement::end_statement()
|
||||
{
|
||||
/* Cleanup SQL processing state to resuse this statement in next query. */
|
||||
lex_end(lex);
|
||||
delete lex->result;
|
||||
lex->result= 0;
|
||||
free_items(free_list);
|
||||
free_list= 0;
|
||||
/*
|
||||
Don't free mem_root, as mem_root is freed in the end of dispatch_command
|
||||
(once for any command).
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
void Item_arena::set_n_backup_item_arena(Item_arena *set, Item_arena *backup)
|
||||
{
|
||||
backup->set_item_arena(this);
|
||||
|
|
|
@ -551,6 +551,12 @@ public:
|
|||
void restore_backup_statement(Statement *stmt, Statement *backup);
|
||||
/* return class type */
|
||||
virtual Type type() const;
|
||||
|
||||
/*
|
||||
Cleanup statement parse state (parse tree, lex) after execution of
|
||||
a non-prepared SQL statement.
|
||||
*/
|
||||
void end_statement();
|
||||
};
|
||||
|
||||
|
||||
|
@ -1033,10 +1039,13 @@ public:
|
|||
~Disable_binlog();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Used to hold information about file and file structure in exchainge
|
||||
via non-DB file (...INTO OUTFILE..., ...LOAD DATA...)
|
||||
XXX: We never call destructor for objects of this class.
|
||||
*/
|
||||
|
||||
class sql_exchange :public Sql_alloc
|
||||
{
|
||||
public:
|
||||
|
@ -1046,7 +1055,6 @@ public:
|
|||
bool dumpfile;
|
||||
ulong skip_lines;
|
||||
sql_exchange(char *name,bool dumpfile_flag);
|
||||
~sql_exchange() {}
|
||||
};
|
||||
|
||||
#include "log_event.h"
|
||||
|
@ -1077,6 +1085,11 @@ public:
|
|||
virtual void send_error(uint errcode,const char *err);
|
||||
virtual bool send_eof()=0;
|
||||
virtual void abort() {}
|
||||
/*
|
||||
Cleanup instance of this class for next execution of a prepared
|
||||
statement/stored procedure.
|
||||
*/
|
||||
virtual void cleanup();
|
||||
};
|
||||
|
||||
|
||||
|
@ -1103,6 +1116,8 @@ public:
|
|||
~select_to_file();
|
||||
bool send_fields(List<Item> &list, uint flag) { return 0; }
|
||||
void send_error(uint errcode,const char *err);
|
||||
bool send_eof();
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
|
||||
|
@ -1115,7 +1130,6 @@ public:
|
|||
~select_export();
|
||||
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
|
||||
bool send_data(List<Item> &items);
|
||||
bool send_eof();
|
||||
};
|
||||
|
||||
|
||||
|
@ -1124,7 +1138,6 @@ public:
|
|||
select_dump(sql_exchange *ex) :select_to_file(ex) {}
|
||||
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
|
||||
bool send_data(List<Item> &items);
|
||||
bool send_eof();
|
||||
};
|
||||
|
||||
|
||||
|
@ -1149,6 +1162,8 @@ class select_insert :public select_result {
|
|||
bool send_data(List<Item> &items);
|
||||
void send_error(uint errcode,const char *err);
|
||||
bool send_eof();
|
||||
/* not implemented: select_insert is never re-used in prepared statements */
|
||||
void cleanup();
|
||||
};
|
||||
|
||||
|
||||
|
@ -1449,4 +1464,5 @@ public:
|
|||
bool send_fields(List<Item> &list, uint flag) {return 0;}
|
||||
bool send_data(List<Item> &items);
|
||||
bool send_eof();
|
||||
void cleanup();
|
||||
};
|
||||
|
|
|
@ -1465,6 +1465,13 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
|||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
void select_insert::cleanup()
|
||||
{
|
||||
/* select_insert/select_create are never re-used in prepared statement */
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
|
||||
select_insert::~select_insert()
|
||||
{
|
||||
if (table)
|
||||
|
|
|
@ -1653,6 +1653,11 @@ void st_select_lex::print_limit(THD *thd, String *str)
|
|||
}
|
||||
|
||||
|
||||
st_lex::st_lex()
|
||||
:result(0)
|
||||
{}
|
||||
|
||||
|
||||
/*
|
||||
Unlink first table from global table list and first table from outer select
|
||||
list (lex->select_lex)
|
||||
|
|
|
@ -633,7 +633,7 @@ typedef struct st_lex
|
|||
list of those tables after they are opened.
|
||||
*/
|
||||
TABLE_LIST *time_zone_tables_used;
|
||||
st_lex() {}
|
||||
st_lex();
|
||||
inline void uncacheable(uint8 cause)
|
||||
{
|
||||
safe_to_cache_query= 0;
|
||||
|
|
|
@ -1967,8 +1967,6 @@ mysql_execute_command(THD *thd)
|
|||
else
|
||||
thd->send_explain_fields(result);
|
||||
res= mysql_explain_union(thd, &thd->lex->unit, result);
|
||||
MYSQL_LOCK *save_lock= thd->lock;
|
||||
thd->lock= (MYSQL_LOCK *)0;
|
||||
if (lex->describe & DESCRIBE_EXTENDED)
|
||||
{
|
||||
char buff[1024];
|
||||
|
@ -1980,20 +1978,19 @@ mysql_execute_command(THD *thd)
|
|||
ER_YES, str.ptr());
|
||||
}
|
||||
result->send_eof();
|
||||
thd->lock= save_lock;
|
||||
delete result;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!result)
|
||||
if (!result && !(result= new select_send()))
|
||||
{
|
||||
if (!(result=new select_send()))
|
||||
{
|
||||
res= -1;
|
||||
break;
|
||||
}
|
||||
res= -1;
|
||||
break;
|
||||
}
|
||||
query_cache_store_query(thd, tables);
|
||||
res=handle_select(thd, lex, result);
|
||||
res= handle_select(thd, lex, result);
|
||||
if (result != lex->result)
|
||||
delete result;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -2708,23 +2705,24 @@ unsent_create_error:
|
|||
}
|
||||
|
||||
|
||||
if (!(res=open_and_lock_tables(thd, tables)))
|
||||
if (!(res= open_and_lock_tables(thd, tables)) &&
|
||||
(result= new select_insert(tables->table, &lex->field_list,
|
||||
lex->duplicates)))
|
||||
{
|
||||
if ((result=new select_insert(tables->table,&lex->field_list,
|
||||
lex->duplicates)))
|
||||
/* Skip first table, which is the table we are inserting in */
|
||||
lex->select_lex.table_list.first= (byte*) first_local_table->next;
|
||||
/*
|
||||
insert/replace from SELECT give its SELECT_LEX for SELECT,
|
||||
and item_list belong to SELECT
|
||||
*/
|
||||
lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
|
||||
res=handle_select(thd,lex,result);
|
||||
/* revert changes for SP */
|
||||
lex->select_lex.table_list.first= (byte*) first_local_table;
|
||||
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
|
||||
/* Skip first table, which is the table we are inserting in */
|
||||
lex->select_lex.table_list.first= (byte*) first_local_table->next;
|
||||
/*
|
||||
insert/replace from SELECT give its SELECT_LEX for SELECT,
|
||||
and item_list belong to SELECT
|
||||
*/
|
||||
lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
|
||||
res= handle_select(thd, lex, result);
|
||||
/* revert changes for SP */
|
||||
lex->select_lex.table_list.first= (byte*) first_local_table;
|
||||
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
|
||||
delete result;
|
||||
if (thd->net.report_error)
|
||||
res= -1;
|
||||
res= -1;
|
||||
}
|
||||
else
|
||||
res= -1;
|
||||
|
@ -3904,8 +3902,8 @@ mysql_init_select(LEX *lex)
|
|||
select_lex->select_limit= HA_POS_ERROR;
|
||||
if (select_lex == &lex->select_lex)
|
||||
{
|
||||
DBUG_ASSERT(lex->result == 0);
|
||||
lex->exchange= 0;
|
||||
lex->result= 0;
|
||||
lex->proc_list.first= 0;
|
||||
}
|
||||
}
|
||||
|
@ -4047,9 +4045,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
|
|||
query_cache_abort(&thd->net);
|
||||
}
|
||||
thd->proc_info="freeing items";
|
||||
free_items(thd->free_list); /* Free strings used by items */
|
||||
thd->free_list= 0;
|
||||
lex_end(lex);
|
||||
thd->end_statement();
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
@ -4074,10 +4070,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
|
|||
if (!yyparse((void*) thd) && ! thd->is_fatal_error &&
|
||||
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);
|
||||
|
||||
thd->end_statement();
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1630,7 +1630,8 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
|
|||
static void reset_stmt_for_execute(Prepared_statement *stmt)
|
||||
{
|
||||
THD *thd= stmt->thd;
|
||||
SELECT_LEX *sl= stmt->lex->all_selects_list;
|
||||
LEX *lex= stmt->lex;
|
||||
SELECT_LEX *sl= lex->all_selects_list;
|
||||
|
||||
for (; sl; sl= sl->next_select_in_list())
|
||||
{
|
||||
|
@ -1678,7 +1679,9 @@ static void reset_stmt_for_execute(Prepared_statement *stmt)
|
|||
unit->reinit_exec_mechanism();
|
||||
}
|
||||
}
|
||||
stmt->lex->current_select= &stmt->lex->select_lex;
|
||||
lex->current_select= &lex->select_lex;
|
||||
if (lex->result)
|
||||
lex->result->cleanup();
|
||||
}
|
||||
|
||||
|
||||
|
@ -2053,6 +2056,7 @@ void Prepared_statement::setup_set_params()
|
|||
Prepared_statement::~Prepared_statement()
|
||||
{
|
||||
free_items(free_list);
|
||||
delete lex->result;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -199,16 +199,10 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
|
|||
res= 1;
|
||||
if (res)
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
result->send_error(0, NullS);
|
||||
result->abort();
|
||||
}
|
||||
else
|
||||
send_error(thd, 0, NullS);
|
||||
result->send_error(0, NullS);
|
||||
result->abort();
|
||||
res= 1; // Error sent to client
|
||||
}
|
||||
delete result;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue