mirror of
https://github.com/MariaDB/server.git
synced 2025-07-24 19:42:23 +03:00
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>
This commit is contained in:
committed by
Vicențiu Ciorbaru
parent
b213f57dc3
commit
c12d1ed48e
231
sql/item.cc
231
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
|
||||
|
28
sql/item.h
28
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
|
||||
{
|
||||
|
221
sql/item_func.cc
221
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);
|
||||
}
|
||||
|
||||
|
||||
@ -6305,75 +6276,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.
|
||||
@ -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())
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user