mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
sp_head now has its own mem_root (WL#961).
Also fixed some difficult memory leaks that became apparent in this task. sql/sp.cc: sp_head now has its own mem_root. sql/sp_head.cc: sp_head now has its own mem_root. Also fixed some difficult memory leaks. sql/sp_head.h: sp_head now has its own mem_root. sql/sql_lex.h: Fixed some memory leaks in sp_head. Need to keep track on used lex:es. sql/sql_parse.cc: sp_head now has its own mem_root. Fixed SP memory leaks. sql/sql_prepare.cc: Fixed SP memory leaks. sql/sql_yacc.yy: sp_head now has its own mem_root.
This commit is contained in:
@ -151,7 +151,8 @@ db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
|
||||
{
|
||||
if (oldlex != thd->lex)
|
||||
thd->lex->sphead->restore_lex(thd);
|
||||
thd->lex->sphead->destroy();
|
||||
delete thd->lex->sphead;
|
||||
thd->lex= NULL;
|
||||
}
|
||||
ret= SP_PARSE_ERROR;
|
||||
}
|
||||
@ -444,7 +445,7 @@ sp_clear_function_cache(THD *thd)
|
||||
sp_head *sp;
|
||||
|
||||
while ((sp= li++))
|
||||
sp->destroy();
|
||||
delete sp;
|
||||
thd->spfuns.empty();
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ eval_func_item(THD *thd, Item *it, enum enum_field_types type)
|
||||
String *s= it->val_str(&tmp);
|
||||
|
||||
DBUG_PRINT("info",("default result: %*s",s->length(),s->c_ptr_quick()));
|
||||
it= new Item_string(sql_strmake(s->c_ptr_quick(), s->length()),
|
||||
it= new Item_string(thd->strmake(s->c_ptr_quick(), s->length()),
|
||||
s->length(), it->charset());
|
||||
break;
|
||||
}
|
||||
@ -91,6 +91,34 @@ eval_func_item(THD *thd, Item *it, enum enum_field_types type)
|
||||
DBUG_RETURN(it);
|
||||
}
|
||||
|
||||
void *
|
||||
sp_head::operator new(size_t size)
|
||||
{
|
||||
DBUG_ENTER("sp_head::operator new");
|
||||
MEM_ROOT own_root;
|
||||
sp_head *sp;
|
||||
|
||||
bzero((char *)&own_root, sizeof(own_root));
|
||||
init_alloc_root(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
|
||||
sp= (sp_head *)alloc_root(&own_root, size);
|
||||
sp->m_mem_root= own_root;
|
||||
|
||||
DBUG_RETURN(sp);
|
||||
}
|
||||
|
||||
void
|
||||
sp_head::operator delete(void *ptr, size_t size)
|
||||
{
|
||||
DBUG_ENTER("sp_head::operator delete");
|
||||
MEM_ROOT own_root;
|
||||
sp_head *sp= (sp_head *)ptr;
|
||||
|
||||
memcpy(&own_root, (const void *)&sp->m_mem_root, sizeof(MEM_ROOT));
|
||||
free_root(&own_root, MYF(0));
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
sp_head::sp_head(LEX_STRING *name, LEX *lex, LEX_STRING *comment, char suid)
|
||||
: Sql_alloc(), m_simple_case(FALSE), m_multi_query(FALSE)
|
||||
{
|
||||
@ -102,6 +130,7 @@ sp_head::sp_head(LEX_STRING *name, LEX *lex, LEX_STRING *comment, char suid)
|
||||
m_name.str= name->str;
|
||||
m_defstr.length= lex->end_of_query - lex->buf;
|
||||
m_defstr.str= lex->thd->strmake(dstr, m_defstr.length);
|
||||
m_free_list= NULL;
|
||||
|
||||
m_comment.length= 0;
|
||||
m_comment.str= 0;
|
||||
@ -115,6 +144,7 @@ sp_head::sp_head(LEX_STRING *name, LEX *lex, LEX_STRING *comment, char suid)
|
||||
m_pcont= lex->spcont;
|
||||
my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
|
||||
m_backpatch.empty();
|
||||
m_lex.empty();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -142,13 +172,31 @@ sp_head::create(THD *thd)
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
sp_head::~sp_head()
|
||||
{
|
||||
destroy();
|
||||
if (m_thd)
|
||||
restore_thd_mem_root(m_thd);
|
||||
}
|
||||
|
||||
void
|
||||
sp_head::destroy()
|
||||
{
|
||||
DBUG_ENTER("sp_head::destroy");
|
||||
DBUG_PRINT("info", ("name: %s", m_name.str));
|
||||
sp_instr *i;
|
||||
LEX *lex;
|
||||
|
||||
for (uint ip = 0 ; (i = get_instr(ip)) ; ip++)
|
||||
delete i;
|
||||
delete_dynamic(&m_instr);
|
||||
m_pcont->destroy();
|
||||
free_items(m_free_list);
|
||||
while ((lex= (LEX *)m_lex.pop()))
|
||||
{
|
||||
if (lex != &m_thd->main_lex) // We got interrupted and have lex'es left
|
||||
delete lex;
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -367,20 +415,22 @@ sp_head::reset_lex(THD *thd)
|
||||
{
|
||||
DBUG_ENTER("sp_head::reset_lex");
|
||||
LEX *sublex;
|
||||
LEX *oldlex= thd->lex;
|
||||
|
||||
m_lex= thd->lex;
|
||||
(void)m_lex.push_front(oldlex);
|
||||
thd->lex= sublex= new st_lex;
|
||||
sublex->yylineno= m_lex->yylineno;
|
||||
sublex->yylineno= oldlex->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, oldlex->buf, oldlex->end_of_query - oldlex->ptr);
|
||||
/* We must reset ptr and end_of_query again */
|
||||
sublex->ptr= m_lex->ptr;
|
||||
sublex->end_of_query= m_lex->end_of_query;
|
||||
sublex->tok_start= m_lex->tok_start;
|
||||
sublex->ptr= oldlex->ptr;
|
||||
sublex->end_of_query= oldlex->end_of_query;
|
||||
sublex->tok_start= oldlex->tok_start;
|
||||
/* And keep the SP stuff too */
|
||||
sublex->sphead= m_lex->sphead;
|
||||
sublex->spcont= m_lex->spcont;
|
||||
sublex->sphead= oldlex->sphead;
|
||||
sublex->spcont= oldlex->spcont;
|
||||
mysql_init_query(thd, true); // Only init lex
|
||||
sublex->sp_lex_in_use= FALSE;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -390,14 +440,18 @@ sp_head::restore_lex(THD *thd)
|
||||
{
|
||||
DBUG_ENTER("sp_head::restore_lex");
|
||||
LEX *sublex= thd->lex;
|
||||
LEX *oldlex= (LEX *)m_lex.pop();
|
||||
|
||||
if (! oldlex)
|
||||
return; // Nothing to restore
|
||||
|
||||
// Update some state in the old one first
|
||||
m_lex->ptr= sublex->ptr;
|
||||
m_lex->next_state= sublex->next_state;
|
||||
oldlex->ptr= sublex->ptr;
|
||||
oldlex->next_state= sublex->next_state;
|
||||
|
||||
// Collect some data from the sub statement lex.
|
||||
sp_merge_funs(m_lex, sublex);
|
||||
#if 0
|
||||
sp_merge_funs(oldlex, sublex);
|
||||
#ifdef NOT_USED_NOW
|
||||
// QQ We're not using this at the moment.
|
||||
if (sublex.sql_command == SQLCOM_CALL)
|
||||
{
|
||||
@ -438,8 +492,9 @@ sp_head::restore_lex(THD *thd)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
thd->lex= m_lex;
|
||||
if (! sublex->sp_lex_in_use)
|
||||
delete sublex;
|
||||
thd->lex= oldlex;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -478,6 +533,12 @@ sp_head::backpatch(sp_label_t *lab)
|
||||
//
|
||||
// sp_instr_stmt
|
||||
//
|
||||
sp_instr_stmt::~sp_instr_stmt()
|
||||
{
|
||||
if (m_lex)
|
||||
delete m_lex;
|
||||
}
|
||||
|
||||
int
|
||||
sp_instr_stmt::execute(THD *thd, uint *nextp)
|
||||
{
|
||||
|
@ -54,11 +54,19 @@ public:
|
||||
List<char *> m_tables; // Used tables.
|
||||
#endif
|
||||
|
||||
static void *
|
||||
operator new(size_t size);
|
||||
|
||||
static void
|
||||
operator delete(void *ptr, size_t size);
|
||||
|
||||
sp_head(LEX_STRING *name, LEX *lex, LEX_STRING *comment, char suid);
|
||||
|
||||
int
|
||||
create(THD *thd);
|
||||
|
||||
virtual ~sp_head();
|
||||
|
||||
// Free memory
|
||||
void
|
||||
destroy();
|
||||
@ -87,6 +95,7 @@ public:
|
||||
|
||||
// Restores lex in 'thd' from our copy, but keeps some status from the
|
||||
// one in 'thd', like ptr, tables, fields, etc.
|
||||
// If 'delete_lex' is true, we delete the current lex.
|
||||
void
|
||||
restore_lex(THD *thd);
|
||||
|
||||
@ -124,8 +133,31 @@ public:
|
||||
m_suid= suid;
|
||||
}
|
||||
|
||||
inline void reset_thd_mem_root(THD *thd)
|
||||
{
|
||||
m_thd_root= thd->mem_root;
|
||||
thd->mem_root= m_mem_root;
|
||||
m_free_list= thd->free_list; // Keep the old list
|
||||
thd->free_list= NULL; // Start a new one
|
||||
m_thd= thd;
|
||||
}
|
||||
|
||||
inline void restore_thd_mem_root(THD *thd)
|
||||
{
|
||||
Item *flist= m_free_list; // The old list
|
||||
m_free_list= thd->free_list; // Get the new one
|
||||
thd->free_list= flist; // Restore the old one
|
||||
m_mem_root= thd->mem_root;
|
||||
thd->mem_root= m_thd_root;
|
||||
m_thd= NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
MEM_ROOT m_mem_root; // My own mem_root
|
||||
MEM_ROOT m_thd_root; // Temp. store for thd's mem_root
|
||||
Item *m_free_list; // Where the items go
|
||||
THD *m_thd; // Set if we have reset mem_root
|
||||
LEX_STRING m_name;
|
||||
LEX_STRING m_defstr;
|
||||
LEX_STRING m_comment;
|
||||
@ -136,7 +168,7 @@ private:
|
||||
bool m_suid;
|
||||
|
||||
sp_pcontext *m_pcont; // Parse context
|
||||
LEX *m_lex; // Temp. store for the other lex
|
||||
List<LEX> m_lex; // Temp. store for the other lex
|
||||
DYNAMIC_ARRAY m_instr; // The "instructions"
|
||||
typedef struct
|
||||
{
|
||||
@ -211,11 +243,10 @@ class sp_instr_stmt : public sp_instr
|
||||
public:
|
||||
|
||||
sp_instr_stmt(uint ip)
|
||||
: sp_instr(ip)
|
||||
: sp_instr(ip), m_lex(NULL)
|
||||
{}
|
||||
|
||||
virtual ~sp_instr_stmt()
|
||||
{}
|
||||
virtual ~sp_instr_stmt();
|
||||
|
||||
virtual int execute(THD *thd, uint *nextp);
|
||||
|
||||
|
@ -495,6 +495,7 @@ typedef struct st_lex
|
||||
char *help_arg;
|
||||
SQL_LIST *gorder_list;
|
||||
sp_head *sphead;
|
||||
bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */
|
||||
sp_pcontext *spcont;
|
||||
List<char> spfuns; /* Called functions */
|
||||
|
||||
|
@ -2829,7 +2829,7 @@ mysql_execute_command(THD *thd)
|
||||
sp_head *sph= sp_find_function(thd, &lex->udf.name);
|
||||
if (sph)
|
||||
{
|
||||
sph->destroy(); // QQ Free memory. Remove this when caching!!!
|
||||
delete sph; // QQ Free memory. Remove this when caching!!!
|
||||
net_printf(thd, ER_UDF_EXISTS, lex->udf.name.str);
|
||||
goto error;
|
||||
}
|
||||
@ -3029,18 +3029,22 @@ mysql_execute_command(THD *thd)
|
||||
#endif
|
||||
res= lex->sphead->create(thd);
|
||||
|
||||
lex->sphead->destroy(); // QQ Free memory. Remove this when caching!!!
|
||||
|
||||
switch (res)
|
||||
{
|
||||
case SP_OK:
|
||||
send_ok(thd);
|
||||
delete lex->sphead; // QQ Free memory. Remove this when caching!!!
|
||||
lex->sphead= NULL;
|
||||
break;
|
||||
case SP_WRITE_ROW_FAILED:
|
||||
net_printf(thd, ER_SP_ALREADY_EXISTS, SP_TYPE_STRING(lex), name);
|
||||
delete lex->sphead; // QQ Free memory. Remove this when caching!!!
|
||||
lex->sphead= NULL;
|
||||
goto error;
|
||||
default:
|
||||
net_printf(thd, ER_SP_STORE_FAILED, SP_TYPE_STRING(lex), name);
|
||||
delete lex->sphead; // QQ Free memory. Remove this when caching!!!
|
||||
lex->sphead= NULL;
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
@ -3064,7 +3068,7 @@ mysql_execute_command(THD *thd)
|
||||
if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
|
||||
(res= open_and_lock_tables(thd, tables))))
|
||||
{
|
||||
sp->destroy(); // QQ Free memory. Remove this when caching!!!
|
||||
delete sp; // Free memory. Remove this when caching!!!
|
||||
break;
|
||||
}
|
||||
fix_tables_pointers(lex->all_selects_list);
|
||||
@ -3083,7 +3087,7 @@ mysql_execute_command(THD *thd)
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
thd->net.no_send_ok= nsok;
|
||||
#endif
|
||||
sp->destroy(); // QQ Free memory. Remove this when caching!!!
|
||||
delete sp; // QQ Free memory. Remove this when caching!!!
|
||||
goto error;
|
||||
}
|
||||
smrx= thd->server_status & SERVER_MORE_RESULTS_EXISTS;
|
||||
@ -3101,7 +3105,7 @@ mysql_execute_command(THD *thd)
|
||||
thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
|
||||
}
|
||||
|
||||
sp->destroy(); // QQ Free memory. Remove this when caching!!!
|
||||
delete sp; // QQ Free memory. Remove this when caching!!!
|
||||
|
||||
if (res == 0)
|
||||
send_ok(thd);
|
||||
@ -3128,7 +3132,7 @@ mysql_execute_command(THD *thd)
|
||||
{
|
||||
/* QQ This is an no-op right now, since we haven't
|
||||
put the characteristics in yet. */
|
||||
sp->destroy(); // QQ Free memory. Remove this when caching!!!
|
||||
delete sp; // QQ Free memory. Remove this when caching!!!
|
||||
send_ok(thd);
|
||||
}
|
||||
break;
|
||||
@ -3588,7 +3592,12 @@ mysql_parse(THD *thd, char *inBuf, uint length)
|
||||
{
|
||||
send_error(thd, 0, NullS);
|
||||
if (thd->lex->sphead)
|
||||
thd->lex->sphead->destroy();
|
||||
{
|
||||
if (lex != thd->lex)
|
||||
thd->lex->sphead->restore_lex(thd);
|
||||
delete thd->lex->sphead;
|
||||
thd->lex->sphead= NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3606,11 +3615,14 @@ mysql_parse(THD *thd, char *inBuf, uint length)
|
||||
#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
|
||||
query_cache_abort(&thd->net);
|
||||
if (thd->lex->sphead)
|
||||
thd->lex->sphead->destroy();
|
||||
{
|
||||
if (lex != thd->lex)
|
||||
thd->lex->sphead->restore_lex(thd);
|
||||
delete thd->lex->sphead;
|
||||
thd->lex->sphead= NULL;
|
||||
}
|
||||
#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);
|
||||
|
@ -762,8 +762,16 @@ 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)
|
||||
else
|
||||
{
|
||||
if (thd->lex->sphead)
|
||||
{
|
||||
if (lex != thd->lex)
|
||||
thd->lex->sphead->restore_lex(thd);
|
||||
delete thd->lex->sphead;
|
||||
thd->lex->sphead= NULL;
|
||||
}
|
||||
}
|
||||
lex_end(lex);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
@ -948,6 +948,7 @@ create:
|
||||
lex->sphead->m_old_cmq=
|
||||
YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
|
||||
YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
|
||||
lex->sphead->reset_thd_mem_root(YYTHD);
|
||||
}
|
||||
'(' sp_pdparam_list ')'
|
||||
{
|
||||
@ -961,6 +962,7 @@ create:
|
||||
/* Restore flag if it was cleared above */
|
||||
if (lex->sphead->m_old_cmq)
|
||||
YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
|
||||
lex->sphead->restore_thd_mem_root(YYTHD);
|
||||
}
|
||||
;
|
||||
|
||||
@ -997,6 +999,7 @@ create_function_tail:
|
||||
lex->sphead->m_old_cmq=
|
||||
YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
|
||||
YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
|
||||
lex->sphead->reset_thd_mem_root(YYTHD);
|
||||
}
|
||||
sp_fdparam_list ')'
|
||||
{
|
||||
@ -1014,6 +1017,7 @@ create_function_tail:
|
||||
/* Restore flag if it was cleared above */
|
||||
if (lex->sphead->m_old_cmq)
|
||||
YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
|
||||
lex->sphead->restore_thd_mem_root(YYTHD);
|
||||
}
|
||||
;
|
||||
|
||||
@ -1194,6 +1198,7 @@ sp_proc_stmt:
|
||||
|
||||
i->set_lex(lex);
|
||||
lex->sphead->add_instr(i);
|
||||
lex->sp_lex_in_use= TRUE;
|
||||
}
|
||||
}
|
||||
lex->sphead->restore_lex(YYTHD);
|
||||
|
Reference in New Issue
Block a user