Adopt SP stuff to the new lex pointer.
mysql-test/r/sp.result: New test (of more call levels). mysql-test/t/sp.test: New test (of more call levels). sql/mysql_priv.h: SPs wants to init lex only. sql/sp.cc: Restore lex pointer (and fixed memory leak). sql/sp_head.cc: lex is now a pointer, so reset things the right way. sql/sp_head.h: lex is now a pointer. sql/sql_lex.h: SPs wants to init lex only. sql/sql_parse.cc: SPs wants to init lex only. sql/sql_prepare.cc: Restore lex pointer.
This commit is contained in:
parent
78c162ee22
commit
8ea9613e7e
@ -95,6 +95,23 @@ delete from t1;
|
||||
drop procedure zip;
|
||||
drop procedure zap;
|
||||
drop procedure bar;
|
||||
create procedure c1(x int)
|
||||
call c2("c", x);
|
||||
create procedure c2(s char(16), x int)
|
||||
call c3(x, s);
|
||||
create procedure c3(x int, s char(16))
|
||||
call c4("level", x, s);
|
||||
create procedure c4(l char(8), x int, s char(16))
|
||||
insert into t1 values (concat(l,s), x);
|
||||
call c1(42);
|
||||
select * from t1;
|
||||
id data
|
||||
levelc 42
|
||||
delete from t1;
|
||||
drop procedure c1;
|
||||
drop procedure c2;
|
||||
drop procedure c3;
|
||||
drop procedure c4;
|
||||
create procedure iotest(x1 char(16), x2 char(16), y int)
|
||||
begin
|
||||
call inc2(x2, y);
|
||||
|
@ -126,6 +126,24 @@ drop procedure zap|
|
||||
drop procedure bar|
|
||||
|
||||
|
||||
# "Deep" calls...
|
||||
create procedure c1(x int)
|
||||
call c2("c", x)|
|
||||
create procedure c2(s char(16), x int)
|
||||
call c3(x, s)|
|
||||
create procedure c3(x int, s char(16))
|
||||
call c4("level", x, s)|
|
||||
create procedure c4(l char(8), x int, s char(16))
|
||||
insert into t1 values (concat(l,s), x)|
|
||||
|
||||
call c1(42)|
|
||||
select * from t1|
|
||||
delete from t1|
|
||||
drop procedure c1|
|
||||
drop procedure c2|
|
||||
drop procedure c3|
|
||||
drop procedure c4|
|
||||
|
||||
# INOUT test
|
||||
create procedure iotest(x1 char(16), x2 char(16), y int)
|
||||
begin
|
||||
|
@ -353,7 +353,7 @@ bool is_update_query(enum enum_sql_command command);
|
||||
void free_items(Item *item);
|
||||
bool alloc_query(THD *thd, char *packet, ulong packet_length);
|
||||
void mysql_init_select(LEX *lex);
|
||||
void mysql_init_query(THD *thd);
|
||||
void mysql_init_query(THD *thd, bool lexonly=0);
|
||||
bool mysql_new_select(LEX *lex, bool move_down);
|
||||
void create_select_for_variable(const char *var_name);
|
||||
void mysql_init_multi_delete(LEX *lex);
|
||||
|
31
sql/sp.cc
31
sql/sp.cc
@ -88,7 +88,6 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
|
||||
DBUG_ENTER("db_find_routine");
|
||||
DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name));
|
||||
extern int yyparse(void *thd);
|
||||
LEX *tmplex;
|
||||
TABLE *table;
|
||||
const char *defstr;
|
||||
int ret;
|
||||
@ -146,15 +145,29 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
|
||||
table= NULL;
|
||||
}
|
||||
|
||||
tmplex= lex_start(thd, (uchar*)defstr, strlen(defstr));
|
||||
if (yyparse(thd) || thd->is_fatal_error || tmplex->sphead == NULL)
|
||||
ret= SP_PARSE_ERROR;
|
||||
else
|
||||
{
|
||||
*sphp= tmplex->sphead;
|
||||
(*sphp)->sp_set_info((char *) creator, (uint) strlen(creator),
|
||||
created, modified, suid,
|
||||
ptr, length);
|
||||
LEX *oldlex= thd->lex;
|
||||
enum enum_sql_command oldcmd= thd->lex->sql_command;
|
||||
|
||||
lex_start(thd, (uchar*)defstr, strlen(defstr));
|
||||
if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL)
|
||||
{
|
||||
if (thd->lex->sphead)
|
||||
{
|
||||
if (oldlex != thd->lex)
|
||||
thd->lex->sphead->restore_lex(thd);
|
||||
thd->lex->sphead->destroy();
|
||||
}
|
||||
ret= SP_PARSE_ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
*sphp= thd->lex->sphead;
|
||||
(*sphp)->sp_set_info((char *) creator, (uint) strlen(creator),
|
||||
created, modified, suid,
|
||||
ptr, length);
|
||||
}
|
||||
thd->lex->sql_command= oldcmd;
|
||||
}
|
||||
|
||||
done:
|
||||
|
@ -365,54 +365,44 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
||||
void
|
||||
sp_head::reset_lex(THD *thd)
|
||||
{
|
||||
memcpy(&m_lex, thd->lex, sizeof(LEX)); // Save old one
|
||||
DBUG_ENTER("sp_head::reset_lex");
|
||||
LEX *sublex;
|
||||
|
||||
m_lex= thd->lex;
|
||||
thd->lex= sublex= new st_lex;
|
||||
sublex->yylineno= m_lex->yylineno;
|
||||
/* Reset most stuff. The length arguments doesn't matter here. */
|
||||
lex_start(thd, m_lex.buf, m_lex.end_of_query - m_lex.ptr);
|
||||
lex_start(thd, m_lex->buf, m_lex->end_of_query - m_lex->ptr);
|
||||
/* We must reset ptr and end_of_query again */
|
||||
thd->lex->ptr= m_lex.ptr;
|
||||
thd->lex->end_of_query= m_lex.end_of_query;
|
||||
sublex->ptr= m_lex->ptr;
|
||||
sublex->end_of_query= m_lex->end_of_query;
|
||||
/* And keep the SP stuff too */
|
||||
thd->lex->sphead = m_lex.sphead;
|
||||
thd->lex->spcont = m_lex.spcont;
|
||||
/* Clear all lists. (QQ Why isn't this reset by lex_start()?).
|
||||
We may be overdoing this, but we know for sure that value_list must
|
||||
be cleared at least. */
|
||||
thd->lex->col_list.empty();
|
||||
thd->lex->ref_list.empty();
|
||||
thd->lex->drop_list.empty();
|
||||
thd->lex->alter_list.empty();
|
||||
thd->lex->interval_list.empty();
|
||||
thd->lex->users_list.empty();
|
||||
thd->lex->columns.empty();
|
||||
thd->lex->key_list.empty();
|
||||
thd->lex->create_list.empty();
|
||||
thd->lex->insert_list= NULL;
|
||||
thd->lex->field_list.empty();
|
||||
thd->lex->value_list.empty();
|
||||
thd->lex->many_values.empty();
|
||||
thd->lex->var_list.empty();
|
||||
thd->lex->param_list.empty();
|
||||
thd->lex->proc_list.empty();
|
||||
thd->lex->auxilliary_table_list.empty();
|
||||
sublex->sphead= m_lex->sphead;
|
||||
sublex->spcont= m_lex->spcont;
|
||||
mysql_init_query(thd, true); // Only init lex
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
// Restore lex during parsing, after we have parsed a sub statement.
|
||||
void
|
||||
sp_head::restore_lex(THD *thd)
|
||||
{
|
||||
DBUG_ENTER("sp_head::restore_lex");
|
||||
LEX *sublex= thd->lex;
|
||||
|
||||
// Update some state in the old one first
|
||||
m_lex.ptr= thd->lex->ptr;
|
||||
m_lex.next_state= thd->lex->next_state;
|
||||
m_lex->ptr= sublex->ptr;
|
||||
m_lex->next_state= sublex->next_state;
|
||||
|
||||
// Collect some data from the sub statement lex.
|
||||
sp_merge_funs(&m_lex, thd->lex);
|
||||
sp_merge_funs(m_lex, sublex);
|
||||
#if 0
|
||||
// QQ We're not using this at the moment.
|
||||
if (thd->lex.sql_command == SQLCOM_CALL)
|
||||
if (sublex.sql_command == SQLCOM_CALL)
|
||||
{
|
||||
// It would be slightly faster to keep the list sorted, but we need
|
||||
// an "insert before" method to do that.
|
||||
char *proc= thd->lex.udf.name.str;
|
||||
char *proc= sublex.udf.name.str;
|
||||
|
||||
List_iterator_fast<char *> li(m_calls);
|
||||
char **it;
|
||||
@ -428,7 +418,7 @@ sp_head::restore_lex(THD *thd)
|
||||
// QQ ...or just open tables in thd->open_tables?
|
||||
// This is not entirerly clear at the moment, but for now, we collect
|
||||
// tables here.
|
||||
for (SELECT_LEX *sl= thd->lex.all_selects_list ;
|
||||
for (SELECT_LEX *sl= sublex.all_selects_list ;
|
||||
sl ;
|
||||
sl= sl->next_select())
|
||||
{
|
||||
@ -448,7 +438,8 @@ sp_head::restore_lex(THD *thd)
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy(thd->lex, &m_lex, sizeof(LEX)); // Restore lex
|
||||
thd->lex= m_lex;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
void
|
||||
@ -490,14 +481,14 @@ int
|
||||
sp_instr_stmt::execute(THD *thd, uint *nextp)
|
||||
{
|
||||
DBUG_ENTER("sp_instr_stmt::execute");
|
||||
DBUG_PRINT("info", ("command: %d", m_lex.sql_command));
|
||||
LEX olex; // The other lex
|
||||
DBUG_PRINT("info", ("command: %d", m_lex->sql_command));
|
||||
LEX *olex; // The other lex
|
||||
int res;
|
||||
|
||||
memcpy(&olex, thd->lex, sizeof(LEX)); // Save the other lex
|
||||
|
||||
memcpy(thd->lex, &m_lex, sizeof(LEX)); // Use my own lex
|
||||
thd->lex->thd = thd;
|
||||
olex= thd->lex; // Save the other lex
|
||||
thd->lex= m_lex; // Use my own lex
|
||||
thd->lex->thd = thd; // QQ Not reentrant!
|
||||
thd->lex->unit.thd= thd; // QQ Not reentrant
|
||||
|
||||
res= mysql_execute_command(thd);
|
||||
if (thd->lock || thd->open_tables || thd->derived_tables)
|
||||
@ -506,7 +497,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
|
||||
close_thread_tables(thd); /* Free tables */
|
||||
}
|
||||
|
||||
memcpy(thd->lex, &olex, sizeof(LEX)); // Restore the other lex
|
||||
thd->lex= olex; // Restore the other lex
|
||||
|
||||
*nextp = m_ip+1;
|
||||
DBUG_RETURN(res);
|
||||
|
@ -136,7 +136,7 @@ private:
|
||||
bool m_suid;
|
||||
|
||||
sp_pcontext *m_pcont; // Parse context
|
||||
LEX m_lex; // Temp. store for the other lex
|
||||
LEX *m_lex; // Temp. store for the other lex
|
||||
DYNAMIC_ARRAY m_instr; // The "instructions"
|
||||
typedef struct
|
||||
{
|
||||
@ -222,18 +222,18 @@ public:
|
||||
inline void
|
||||
set_lex(LEX *lex)
|
||||
{
|
||||
memcpy(&m_lex, lex, sizeof(LEX));
|
||||
m_lex= lex;
|
||||
}
|
||||
|
||||
inline LEX *
|
||||
get_lex()
|
||||
{
|
||||
return &m_lex;
|
||||
return m_lex;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
LEX m_lex; // My own lex
|
||||
LEX *m_lex; // My own lex
|
||||
|
||||
}; // class sp_instr_stmt : public sp_instr
|
||||
|
||||
|
@ -320,7 +320,7 @@ public:
|
||||
int exec();
|
||||
int cleanup();
|
||||
|
||||
friend void mysql_init_query(THD *thd);
|
||||
friend void mysql_init_query(THD *thd, bool lexonly);
|
||||
friend int subselect_union_engine::exec();
|
||||
private:
|
||||
bool create_total_list_n_last_return(THD *thd, st_lex *lex,
|
||||
@ -408,7 +408,7 @@ public:
|
||||
order_list.next= (byte**) &order_list.first;
|
||||
}
|
||||
|
||||
friend void mysql_init_query(THD *thd);
|
||||
friend void mysql_init_query(THD *thd, bool lexonly);
|
||||
st_select_lex(struct st_lex *lex);
|
||||
st_select_lex() {}
|
||||
void make_empty_select(st_select_lex *last_select)
|
||||
|
@ -3433,7 +3433,7 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize)
|
||||
****************************************************************************/
|
||||
|
||||
void
|
||||
mysql_init_query(THD *thd)
|
||||
mysql_init_query(THD *thd, bool lexonly)
|
||||
{
|
||||
DBUG_ENTER("mysql_init_query");
|
||||
LEX *lex=thd->lex;
|
||||
@ -3457,17 +3457,20 @@ mysql_init_query(THD *thd)
|
||||
lex->lock_option= TL_READ;
|
||||
lex->found_colon= 0;
|
||||
lex->safe_to_cache_query= 1;
|
||||
thd->select_number= lex->select_lex.select_number= 1;
|
||||
thd->free_list= 0;
|
||||
thd->total_warn_count=0; // Warnings for this query
|
||||
thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
|
||||
thd->sent_row_count= thd->examined_row_count= 0;
|
||||
thd->is_fatal_error= thd->rand_used= 0;
|
||||
thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
|
||||
thd->tmp_table_used= 0;
|
||||
if (opt_bin_log)
|
||||
reset_dynamic(&thd->user_var_events);
|
||||
thd->clear_error();
|
||||
if (! lexonly)
|
||||
{
|
||||
thd->select_number= lex->select_lex.select_number= 1;
|
||||
thd->free_list= 0;
|
||||
thd->total_warn_count=0; // Warnings for this query
|
||||
thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
|
||||
thd->sent_row_count= thd->examined_row_count= 0;
|
||||
thd->is_fatal_error= thd->rand_used= 0;
|
||||
thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
|
||||
thd->tmp_table_used= 0;
|
||||
if (opt_bin_log)
|
||||
reset_dynamic(&thd->user_var_events);
|
||||
thd->clear_error();
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -3582,7 +3585,11 @@ mysql_parse(THD *thd, char *inBuf, uint length)
|
||||
else
|
||||
{
|
||||
if (thd->net.report_error)
|
||||
{
|
||||
send_error(thd, 0, NullS);
|
||||
if (thd->lex->sphead)
|
||||
thd->lex->sphead->destroy();
|
||||
}
|
||||
else
|
||||
{
|
||||
mysql_execute_command(thd);
|
||||
@ -3598,8 +3605,12 @@ mysql_parse(THD *thd, char *inBuf, uint length)
|
||||
thd->is_fatal_error));
|
||||
#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
|
||||
query_cache_abort(&thd->net);
|
||||
if (thd->lex->sphead)
|
||||
thd->lex->sphead->destroy();
|
||||
#endif
|
||||
}
|
||||
if (thd->lex->sphead && lex != thd->lex)
|
||||
thd->lex->sphead->restore_lex(thd);
|
||||
thd->proc_info="freeing items";
|
||||
free_items(thd->free_list); /* Free strings used by items */
|
||||
lex_end(lex);
|
||||
|
@ -71,6 +71,7 @@ Long data handling:
|
||||
#include "sql_acl.h"
|
||||
#include "sql_select.h" // for JOIN
|
||||
#include <m_ctype.h> // for isspace()
|
||||
#include "sp_head.h"
|
||||
|
||||
#define IS_PARAM_NULL(pos, param_no) pos[param_no/8] & (1 << param_no & 7)
|
||||
|
||||
@ -761,6 +762,8 @@ static bool parse_prepare_query(PREP_STMT *stmt,
|
||||
thd->lex->param_count= 0;
|
||||
if (!yyparse((void *)thd) && !thd->is_fatal_error)
|
||||
error= send_prepare_results(stmt);
|
||||
if (thd->lex->sphead && lex != thd->lex)
|
||||
thd->lex->sphead->restore_lex(thd);
|
||||
lex_end(lex);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user