summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVarun Gupta <varunraiko1803@gmail.com>2017-11-23 10:38:04 +0200
committerVicențiu Ciorbaru <vicentiu@mariadb.org>2017-12-04 13:22:29 +0200
commitc12d1ed48ee0708b85fbdbe149d15f6fea2c1e31 (patch)
treeedc7283e665d576945f85267e70c45ae22fd27cb
parentb213f57dc3f9da93ce444805f7581d982bde9f75 (diff)
downloadmariadb-git-c12d1ed48ee0708b85fbdbe149d15f6fea2c1e31.tar.gz
Refactor parts of Item_func_sp into Item_sp
In preparation for implementing custom aggregate functions, refactor the common code between regular stored functions and aggregate stored functions. This includes: * initialising SP result field * executing a SP * access checks In addition, refactor sp_head::execute_function to take two extra parameters, a function rcontext and a Query_arena. These two paremeters were initially initialised and destroyed within sp_head::execute_function, but for aggregate stored functions we will require control over their lifetime. The owner of these objects now becomes Item_sp. Signed-off-by: Vicențiu Ciorbaru <vicentiu@mariadb.org>
-rw-r--r--sql/item.cc231
-rw-r--r--sql/item.h28
-rw-r--r--sql/item_func.cc221
-rw-r--r--sql/item_func.h19
-rw-r--r--sql/sp_head.cc53
-rw-r--r--sql/sp_head.h3
6 files changed, 296 insertions, 259 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 3ed43de5739..250f6707d4e 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -2730,6 +2730,237 @@ Item* Item_func_or_sum::build_clone(THD *thd)
return copy;
}
+Item_sp::Item_sp(THD *thd, Name_resolution_context *context_arg,
+ sp_name *name_arg) :
+ context(context_arg), m_name(name_arg), m_sp(NULL), func_ctx(NULL),
+ sp_result_field(NULL)
+{
+ dummy_table= (TABLE*) thd->calloc(sizeof(TABLE) + sizeof(TABLE_SHARE));
+ dummy_table->s= (TABLE_SHARE*) (dummy_table + 1);
+ memset(&sp_mem_root, 0, sizeof(sp_mem_root));
+}
+
+const char *
+Item_sp::func_name(THD *thd) const
+{
+ /* Calculate length to avoid reallocation of string for sure */
+ uint len= (((m_name->m_explicit_name ? m_name->m_db.length : 0) +
+ m_name->m_name.length)*2 + //characters*quoting
+ 2 + // ` and `
+ (m_name->m_explicit_name ?
+ 3 : 0) + // '`', '`' and '.' for the db
+ 1 + // end of string
+ ALIGN_SIZE(1)); // to avoid String reallocation
+ String qname((char *)alloc_root(thd->mem_root, len), len,
+ system_charset_info);
+
+ qname.length(0);
+ if (m_name->m_explicit_name)
+ {
+ append_identifier(thd, &qname, m_name->m_db.str, m_name->m_db.length);
+ qname.append('.');
+ }
+ append_identifier(thd, &qname, m_name->m_name.str, m_name->m_name.length);
+ return qname.c_ptr_safe();
+}
+
+void
+Item_sp::cleanup()
+{
+ delete sp_result_field;
+ sp_result_field= NULL;
+ m_sp= NULL;
+ delete func_ctx;
+ func_ctx= NULL;
+ free_root(&sp_mem_root, MYF(0));
+ dummy_table->alias.free();
+}
+
+/**
+ @brief Checks if requested access to function can be granted to user.
+ If function isn't found yet, it searches function first.
+ If function can't be found or user don't have requested access
+ error is raised.
+
+ @param thd thread handler
+
+ @return Indication if the access was granted or not.
+ @retval FALSE Access is granted.
+ @retval TRUE Requested access can't be granted or function doesn't exists.
+
+*/
+bool
+Item_sp::sp_check_access(THD *thd)
+{
+ DBUG_ENTER("Item_sp::sp_check_access");
+ DBUG_ASSERT(m_sp);
+ DBUG_RETURN(m_sp->check_execute_access(thd));
+}
+
+/**
+ @brief Execute function & store value in field.
+
+ @return Function returns error status.
+ @retval FALSE on success.
+ @retval TRUE if an error occurred.
+*/
+bool Item_sp::execute(THD *thd, bool *null_value, Item **args, uint arg_count)
+{
+ if (execute_impl(thd, args, arg_count))
+ {
+ *null_value= 1;
+ context->process_error(thd);
+ if (thd->killed)
+ thd->send_kill_message();
+ return true;
+ }
+
+ /* Check that the field (the value) is not NULL. */
+
+ *null_value= sp_result_field->is_null();
+ return (*null_value);
+}
+
+/**
+ @brief Execute function and store the return value in the field.
+
+ @note This function was intended to be the concrete implementation of
+ the interface function execute. This was never realized.
+
+ @return The error state.
+ @retval FALSE on success
+ @retval TRUE if an error occurred.
+*/
+bool
+Item_sp::execute_impl(THD *thd, Item **args, uint arg_count)
+{
+ Sub_statement_state statement_state;
+ Security_context *save_security_ctx= thd->security_ctx;
+ enum enum_sp_data_access access=
+ (m_sp->daccess() == SP_DEFAULT_ACCESS) ?
+ SP_DEFAULT_ACCESS_MAPPING : m_sp->daccess();
+
+ DBUG_ENTER("Item_sp::execute_impl");
+
+ if (context->security_ctx)
+ {
+ /* Set view definer security context */
+ thd->security_ctx= context->security_ctx;
+ }
+
+ if (sp_check_access(thd))
+ {
+ thd->security_ctx= save_security_ctx;
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ Throw an error if a non-deterministic function is called while
+ statement-based replication (SBR) is active.
+ */
+
+ if (!m_sp->detistic() && !trust_function_creators &&
+ (access == SP_CONTAINS_SQL || access == SP_MODIFIES_SQL_DATA) &&
+ (mysql_bin_log.is_open() &&
+ thd->variables.binlog_format == BINLOG_FORMAT_STMT))
+ {
+ my_error(ER_BINLOG_UNSAFE_ROUTINE, MYF(0));
+ thd->security_ctx= save_security_ctx;
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ Disable the binlogging if this is not a SELECT statement. If this is a
+ SELECT, leave binlogging on, so execute_function() code writes the
+ function call into binlog.
+ */
+ thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION);
+
+ init_sql_alloc(&sp_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
+ Query_arena call_arena(&sp_mem_root, Query_arena::STMT_INITIALIZED_FOR_SP);
+
+ bool err_status= m_sp->execute_function(thd, args, arg_count,
+ sp_result_field, &func_ctx,
+ &call_arena);
+ /* Free Items allocated during function execution. */
+ delete func_ctx;
+ func_ctx= NULL;
+ call_arena.free_items();
+ free_root(&sp_mem_root, MYF(0));
+ memset(&sp_mem_root, 0, sizeof(sp_mem_root));
+
+ thd->restore_sub_statement_state(&statement_state);
+
+ thd->security_ctx= save_security_ctx;
+ DBUG_RETURN(err_status);
+}
+
+
+/**
+ @brief Initialize the result field by creating a temporary dummy table
+ and assign it to a newly created field object. Meta data used to
+ create the field is fetched from the sp_head belonging to the stored
+ proceedure found in the stored procedure functon cache.
+
+ @note This function should be called from fix_fields to init the result
+ field. It is some what related to Item_field.
+
+ @see Item_field
+
+ @param thd A pointer to the session and thread context.
+
+ @return Function return error status.
+ @retval TRUE is returned on an error
+ @retval FALSE is returned on success.
+*/
+
+bool
+Item_sp::init_result_field(THD *thd, sp_head *sp, uint max_length,
+ uint maybe_null, bool *null_value, LEX_CSTRING *name)
+{
+ DBUG_ENTER("Item_sp::init_result_field");
+
+ DBUG_ASSERT(m_sp == NULL);
+ DBUG_ASSERT(sp_result_field == NULL);
+
+ if (!(m_sp= sp))
+ {
+ my_missing_function_error (m_name->m_name, ErrConvDQName(m_name).ptr());
+ context->process_error(thd);
+ DBUG_RETURN(TRUE);
+ }
+
+ /*
+ A Field needs to be attached to a Table.
+ Below we "create" a dummy table by initializing
+ the needed pointers.
+ */
+ dummy_table->alias.set("", 0, table_alias_charset);
+ dummy_table->in_use= thd;
+ dummy_table->copy_blobs= TRUE;
+ dummy_table->s->table_cache_key= empty_clex_str;
+ dummy_table->s->table_name= empty_clex_str;
+ dummy_table->maybe_null= maybe_null;
+
+ if (!(sp_result_field= m_sp->create_result_field(max_length, name,
+ dummy_table)))
+ DBUG_RETURN(TRUE);
+
+ if (sp_result_field->pack_length() > sizeof(result_buf))
+ {
+ void *tmp;
+ if (!(tmp= thd->alloc(sp_result_field->pack_length())))
+ DBUG_RETURN(TRUE);
+ sp_result_field->move_field((uchar*) tmp);
+ }
+ else
+ sp_result_field->move_field(result_buf);
+
+ sp_result_field->null_ptr= (uchar *) null_value;
+ sp_result_field->null_bit= 1;
+
+ DBUG_RETURN(FALSE);
+}
/**
@brief
diff --git a/sql/item.h b/sql/item.h
index d21fc86ea48..574680bc86d 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -4471,6 +4471,34 @@ public:
Item* build_clone(THD *thd);
};
+class sp_head;
+class sp_name;
+struct st_sp_security_context;
+
+class Item_sp
+{
+public:
+ Name_resolution_context *context;
+ sp_name *m_name;
+ sp_head *m_sp;
+ TABLE *dummy_table;
+ uchar result_buf[64];
+ sp_rcontext *func_ctx;
+ MEM_ROOT sp_mem_root;
+
+ /*
+ The result field of the stored function.
+ */
+ Field *sp_result_field;
+ Item_sp(THD *thd, Name_resolution_context *context_arg, sp_name *name_arg);
+ const char *func_name(THD *thd) const;
+ void cleanup();
+ bool sp_check_access(THD *thd);
+ bool execute(THD *thd, bool *null_value, Item **args, uint arg_count);
+ bool execute_impl(THD *thd, Item **args, uint arg_count);
+ bool init_result_field(THD *thd, sp_head *sp, uint max_length,
+ uint maybe_null, bool *null_value, LEX_CSTRING *name);
+};
class Item_ref :public Item_ident
{
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 67269e4dd0e..d851b508daf 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -6238,35 +6238,24 @@ longlong Item_func_row_count::val_int()
Item_func_sp::Item_func_sp(THD *thd, Name_resolution_context *context_arg,
sp_name *name):
- Item_func(thd), context(context_arg), m_name(name), m_sp(NULL), sp_result_field(NULL)
+ Item_func(thd), Item_sp(thd, context_arg, name)
{
maybe_null= 1;
- dummy_table= (TABLE*) thd->calloc(sizeof(TABLE)+ sizeof(TABLE_SHARE));
- dummy_table->s= (TABLE_SHARE*) (dummy_table+1);
}
Item_func_sp::Item_func_sp(THD *thd, Name_resolution_context *context_arg,
sp_name *name_arg, List<Item> &list):
- Item_func(thd, list), context(context_arg), m_name(name_arg), m_sp(NULL),
- sp_result_field(NULL)
+ Item_func(thd, list), Item_sp(thd, context_arg, name_arg)
{
maybe_null= 1;
- dummy_table= (TABLE*) thd->calloc(sizeof(TABLE)+ sizeof(TABLE_SHARE));
- dummy_table->s= (TABLE_SHARE*) (dummy_table+1);
}
void
Item_func_sp::cleanup()
{
- if (sp_result_field)
- {
- delete sp_result_field;
- sp_result_field= NULL;
- }
- m_sp= NULL;
- dummy_table->alias.free();
+ Item_sp::cleanup();
Item_func::cleanup();
}
@@ -6274,25 +6263,7 @@ const char *
Item_func_sp::func_name() const
{
THD *thd= current_thd;
- /* Calculate length to avoid reallocation of string for sure */
- uint len= (((m_name->m_explicit_name ? m_name->m_db.length : 0) +
- m_name->m_name.length)*2 + //characters*quoting
- 2 + // ` and `
- (m_name->m_explicit_name ?
- 3 : 0) + // '`', '`' and '.' for the db
- 1 + // end of string
- ALIGN_SIZE(1)); // to avoid String reallocation
- String qname((char *)alloc_root(thd->mem_root, len), len,
- system_charset_info);
-
- qname.length(0);
- if (m_name->m_explicit_name)
- {
- append_identifier(thd, &qname, m_name->m_db.str, m_name->m_db.length);
- qname.append('.');
- }
- append_identifier(thd, &qname, m_name->m_name.str, m_name->m_name.length);
- return qname.c_ptr_safe();
+ return Item_sp::func_name(thd);
}
@@ -6306,75 +6277,6 @@ void my_missing_function_error(const LEX_CSTRING &token, const char *func_name)
/**
- @brief Initialize the result field by creating a temporary dummy table
- and assign it to a newly created field object. Meta data used to
- create the field is fetched from the sp_head belonging to the stored
- proceedure found in the stored procedure functon cache.
-
- @note This function should be called from fix_fields to init the result
- field. It is some what related to Item_field.
-
- @see Item_field
-
- @param thd A pointer to the session and thread context.
-
- @return Function return error status.
- @retval TRUE is returned on an error
- @retval FALSE is returned on success.
-*/
-
-bool
-Item_func_sp::init_result_field(THD *thd, sp_head *sp)
-{
- TABLE_SHARE *share;
- DBUG_ENTER("Item_func_sp::init_result_field");
-
- DBUG_ASSERT(m_sp == NULL);
- DBUG_ASSERT(sp_result_field == NULL);
-
- if (!(m_sp= sp))
- {
- my_missing_function_error (m_name->m_name, ErrConvDQName(m_name).ptr());
- context->process_error(thd);
- DBUG_RETURN(TRUE);
- }
-
- /*
- A Field need to be attached to a Table.
- Below we "create" a dummy table by initializing
- the needed pointers.
- */
-
- share= dummy_table->s;
- dummy_table->alias.set("", 0, table_alias_charset);
- dummy_table->maybe_null = maybe_null;
- dummy_table->in_use= thd;
- dummy_table->copy_blobs= TRUE;
- share->table_cache_key= empty_clex_str;
- share->table_name= empty_clex_str;
-
- if (!(sp_result_field= m_sp->create_result_field(max_length, &name, dummy_table)))
- {
- DBUG_RETURN(TRUE);
- }
-
- if (sp_result_field->pack_length() > sizeof(result_buf))
- {
- void *tmp;
- if (!(tmp= thd->alloc(sp_result_field->pack_length())))
- DBUG_RETURN(TRUE);
- sp_result_field->move_field((uchar*) tmp);
- }
- else
- sp_result_field->move_field(result_buf);
-
- sp_result_field->null_ptr= (uchar *) &null_value;
- sp_result_field->null_bit= 1;
- DBUG_RETURN(FALSE);
-}
-
-
-/**
@note
Deterministic stored procedures are considered inexpensive.
Consequently such procedures may be evaluated during optimization,
@@ -6408,95 +6310,11 @@ void Item_func_sp::fix_length_and_dec()
}
-/**
- @brief Execute function & store value in field.
-
- @return Function returns error status.
- @retval FALSE on success.
- @retval TRUE if an error occurred.
-*/
-
bool
Item_func_sp::execute()
{
- THD *thd= current_thd;
-
/* Execute function and store the return value in the field. */
-
- if (execute_impl(thd))
- {
- null_value= 1;
- context->process_error(thd);
- if (thd->killed)
- thd->send_kill_message();
- return TRUE;
- }
-
- /* Check that the field (the value) is not NULL. */
-
- null_value= sp_result_field->is_null();
-
- return null_value;
-}
-
-
-/**
- @brief Execute function and store the return value in the field.
-
- @note This function was intended to be the concrete implementation of
- the interface function execute. This was never realized.
-
- @return The error state.
- @retval FALSE on success
- @retval TRUE if an error occurred.
-*/
-bool
-Item_func_sp::execute_impl(THD *thd)
-{
- bool err_status= TRUE;
- Sub_statement_state statement_state;
- Security_context *save_security_ctx= thd->security_ctx;
- enum enum_sp_data_access access=
- (m_sp->daccess() == SP_DEFAULT_ACCESS) ?
- SP_DEFAULT_ACCESS_MAPPING : m_sp->daccess();
-
- DBUG_ENTER("Item_func_sp::execute_impl");
-
- if (context->security_ctx)
- {
- /* Set view definer security context */
- thd->security_ctx= context->security_ctx;
- }
- if (sp_check_access(thd))
- goto error;
-
- /*
- Throw an error if a non-deterministic function is called while
- statement-based replication (SBR) is active.
- */
-
- if (!m_sp->detistic() && !trust_function_creators &&
- (access == SP_CONTAINS_SQL || access == SP_MODIFIES_SQL_DATA) &&
- (mysql_bin_log.is_open() &&
- thd->variables.binlog_format == BINLOG_FORMAT_STMT))
- {
- my_error(ER_BINLOG_UNSAFE_ROUTINE, MYF(0));
- goto error;
- }
-
- /*
- Disable the binlogging if this is not a SELECT statement. If this is a
- SELECT, leave binlogging on, so execute_function() code writes the
- function call into binlog.
- */
- thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION);
- err_status= m_sp->execute_function(thd, args, arg_count, sp_result_field);
- thd->restore_sub_statement_state(&statement_state);
-
-error:
- thd->security_ctx= save_security_ctx;
-
- DBUG_RETURN(err_status);
+ return Item_sp::execute(current_thd, &null_value, args, arg_count);
}
@@ -6561,29 +6379,6 @@ longlong Item_func_sqlcode::val_int()
}
-/**
- @brief Checks if requested access to function can be granted to user.
- If function isn't found yet, it searches function first.
- If function can't be found or user don't have requested access
- error is raised.
-
- @param thd thread handler
-
- @return Indication if the access was granted or not.
- @retval FALSE Access is granted.
- @retval TRUE Requested access can't be granted or function doesn't exists.
-
-*/
-
-bool
-Item_func_sp::sp_check_access(THD *thd)
-{
- DBUG_ENTER("Item_func_sp::sp_check_access");
- DBUG_ASSERT(m_sp);
- DBUG_RETURN(m_sp->check_execute_access(thd));
-}
-
-
bool
Item_func_sp::fix_fields(THD *thd, Item **ref)
{
@@ -6625,15 +6420,15 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
to make m_sp and result_field members available to fix_length_and_dec(),
which is called from Item_func::fix_fields().
*/
- res= init_result_field(thd, sp);
+ res= init_result_field(thd, sp, max_length, maybe_null, &null_value, &name);
if (res)
- DBUG_RETURN(res);
+ DBUG_RETURN(TRUE);
res= Item_func::fix_fields(thd, ref);
if (res)
- DBUG_RETURN(res);
+ DBUG_RETURN(TRUE);
if (thd->lex->is_view_context_analysis())
{
diff --git a/sql/item_func.h b/sql/item_func.h
index ed6f800fd17..07c6b5bb8d3 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -2732,26 +2732,12 @@ public:
*
*/
-class sp_head;
-class sp_name;
-struct st_sp_security_context;
-
-class Item_func_sp :public Item_func
+class Item_func_sp :public Item_func,
+ public Item_sp
{
private:
- Name_resolution_context *context;
- sp_name *m_name;
- mutable sp_head *m_sp;
- TABLE *dummy_table;
- uchar result_buf[64];
- /*
- The result field of the concrete stored function.
- */
- Field *sp_result_field;
bool execute();
- bool execute_impl(THD *thd);
- bool init_result_field(THD *thd, sp_head *sp);
protected:
bool is_expensive_processor(void *arg)
@@ -2843,7 +2829,6 @@ public:
virtual bool change_context_processor(void *cntx)
{ context= (Name_resolution_context *)cntx; return FALSE; }
- bool sp_check_access(THD * thd);
virtual enum Functype functype() const { return FUNC_SP; }
bool fix_fields(THD *thd, Item **ref);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 829e4cc6414..62e198efb9e 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1675,18 +1675,16 @@ err_with_cleanup:
bool
sp_head::execute_function(THD *thd, Item **argp, uint argcount,
- Field *return_value_fld)
+ Field *return_value_fld, sp_rcontext **func_ctx,
+ Query_arena *call_arena)
{
ulonglong UNINIT_VAR(binlog_save_options);
bool need_binlog_call= FALSE;
uint arg_no;
sp_rcontext *octx = thd->spcont;
- sp_rcontext *nctx = NULL;
char buf[STRING_BUFFER_USUAL_SIZE];
String binlog_buf(buf, sizeof(buf), &my_charset_bin);
bool err_status= FALSE;
- MEM_ROOT call_mem_root;
- Query_arena call_arena(&call_mem_root, Query_arena::STMT_INITIALIZED_FOR_SP);
Query_arena backup_arena;
DBUG_ENTER("sp_head::execute_function");
DBUG_PRINT("info", ("function %s", m_name.str));
@@ -1719,23 +1717,25 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
TODO: we should create sp_rcontext once per command and reuse
it on subsequent executions of a function/trigger.
*/
- init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
- thd->set_n_backup_active_arena(&call_arena, &backup_arena);
-
- if (!(nctx= rcontext_create(thd, return_value_fld, argp, argcount)))
+ if (!(*func_ctx))
{
- thd->restore_active_arena(&call_arena, &backup_arena);
- err_status= TRUE;
- goto err_with_cleanup;
- }
+ thd->set_n_backup_active_arena(call_arena, &backup_arena);
- /*
- We have to switch temporarily back to callers arena/memroot.
- Function arguments belong to the caller and so the may reference
- memory which they will allocate during calculation long after
- this function call will be finished (e.g. in Item::cleanup()).
- */
- thd->restore_active_arena(&call_arena, &backup_arena);
+ if (!(*func_ctx= rcontext_create(thd, return_value_fld, argp, argcount)))
+ {
+ thd->restore_active_arena(call_arena, &backup_arena);
+ err_status= TRUE;
+ goto err_with_cleanup;
+ }
+
+ /*
+ We have to switch temporarily back to callers arena/memroot.
+ Function arguments belong to the caller and so the may reference
+ memory which they will allocate during calculation long after
+ this function call will be finished (e.g. in Item::cleanup()).
+ */
+ thd->restore_active_arena(call_arena, &backup_arena);
+ }
/* Pass arguments. */
for (arg_no= 0; arg_no < argcount; arg_no++)
@@ -1743,7 +1743,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
/* Arguments must be fixed in Item_func_sp::fix_fields */
DBUG_ASSERT(argp[arg_no]->fixed);
- if ((err_status= nctx->set_variable(thd, arg_no, &(argp[arg_no]))))
+ if ((err_status= (*func_ctx)->set_variable(thd, arg_no, &(argp[arg_no]))))
goto err_with_cleanup;
}
@@ -1775,7 +1775,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
if (arg_no)
binlog_buf.append(',');
- Item *item= nctx->get_item(arg_no);
+ Item *item= (*func_ctx)->get_item(arg_no);
str_value= item->type_handler()->print_item_value(thd, item,
&str_value_holder);
if (str_value)
@@ -1785,7 +1785,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
}
binlog_buf.append(')');
}
- thd->spcont= nctx;
+ thd->spcont= *func_ctx;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *save_security_ctx;
@@ -1826,11 +1826,11 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
sp_rcontext and allocate all these objects (and sp_rcontext
itself) on it directly rather than juggle with arenas.
*/
- thd->set_n_backup_active_arena(&call_arena, &backup_arena);
+ thd->set_n_backup_active_arena(call_arena, &backup_arena);
err_status= execute(thd, TRUE);
- thd->restore_active_arena(&call_arena, &backup_arena);
+ thd->restore_active_arena(call_arena, &backup_arena);
if (need_binlog_call)
{
@@ -1860,7 +1860,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
{
/* We need result only in function but not in trigger */
- if (!nctx->is_return_value_set())
+ if (!(*func_ctx)->is_return_value_set())
{
my_error(ER_SP_NORETURNEND, MYF(0), m_name.str);
err_status= TRUE;
@@ -1872,9 +1872,6 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
#endif
err_with_cleanup:
- delete nctx;
- call_arena.free_items();
- free_root(&call_mem_root, MYF(0));
thd->spcont= octx;
/*
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 8d836732a10..1a994bdf70d 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -343,7 +343,8 @@ public:
GRANT_INFO *grant_info);
bool
- execute_function(THD *thd, Item **args, uint argcount, Field *return_fld);
+ execute_function(THD *thd, Item **args, uint argcount, Field *return_fld,
+ sp_rcontext **nctx, Query_arena *call_arena);
bool
execute_procedure(THD *thd, List<Item> *args);