summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <Kristofer.Pettersson@naruto.>2007-03-16 14:25:11 +0100
committerunknown <Kristofer.Pettersson@naruto.>2007-03-16 14:25:11 +0100
commitffc605aad563c7634ea6b5ac8cb480793fcb9258 (patch)
tree6d91ece01a3a323d340611812b3bd65c0422e0b7 /sql
parentc039eed82cb21d75965fd9b2e936396e0282e0cb (diff)
downloadmariadb-git-ffc605aad563c7634ea6b5ac8cb480793fcb9258.tar.gz
Bug#20777 Function w BIGINT UNSIGNED shows diff. behaviour with and without --ps-protocol
- Stored procedures returning unsinged values returns signed values if text protocol is used. The reason is that the stored proceedure item Item_func_sp wasn't initializing the member variables properly based on the information contained in the associated result field. - The patch is to upon field-item association, ::fix_fields, initialize the member variables in appropriate order. - Field type of an Item_func_sp was hard coded to MYSQL_TYPE_VARCHAR. This is changed to return the type of the actual result field. - Member function name sp_result_field was refactored to the more appropriate init_result_field. - Member function name find_and_check_access was refactored to sp_check_access. mysql-test/r/sp.result: - Added test mysql-test/t/sp.test: - Added test sql/item_func.cc: Bug#20777 Function w BIGINT UNSIGNED shows diff. behaviour with and without --ps-protocol - Stored procedures returning unsinged values returns signed values if text protocol is used. The reason is that the stored proceedure item Item_func_sp wasn't initializing the member variables properly based on the information contained in the associated result field. - The patch is to upon field-item association, ::fix_fields, initialize the member variables in appropriate order. - Field type of an Item_func_sp was hard coded to MYSQL_TYPE_VARCHAR. This is changed to to return the type of the actual result field. - Member function name sp_result_field was refactored to the more appropriate init_result_field. - Member function name find_and_check_access was refactored to sp_check_access. sql/item_func.h: Bug#20777 Function w BIGINT UNSIGNED shows diff. behaviour with and without --ps-protocol - Stored procedures returning unsinged values returns signed values if text protocol is used. The reason is that the stored proceedure item Item_func_sp wasn't initializing the member variables properly based on the information contained in the associated result field. - The patch is to upon field-item association, ::fix_fields, initialize the member variables in appropriate order. - Field type of an Item_func_sp was hard coded to MYSQL_TYPE_VARCHAR. This is changed to to return the type of the actual result field. - Member function name sp_result_field was refactored to the more appropriate init_result_field. - Member function name find_and_check_access was refactored to sp_check_access.
Diffstat (limited to 'sql')
-rw-r--r--sql/item_func.cc317
-rw-r--r--sql/item_func.h31
2 files changed, 171 insertions, 177 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 32cc90b96d6..a27b7b6bcc2 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -4979,8 +4979,7 @@ longlong Item_func_row_count::val_int()
Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, sp_name *name)
- :Item_func(), context(context_arg), m_name(name), m_sp(NULL),
- result_field(NULL)
+ :Item_func(), context(context_arg), m_name(name), m_sp(NULL), sp_result_field(NULL)
{
maybe_null= 1;
m_name->init_qname(current_thd);
@@ -4990,21 +4989,21 @@ Item_func_sp::Item_func_sp(Name_resolution_context *context_arg, sp_name *name)
Item_func_sp::Item_func_sp(Name_resolution_context *context_arg,
sp_name *name, List<Item> &list)
- :Item_func(list), context(context_arg), m_name(name), m_sp(NULL),
- result_field(NULL)
+ :Item_func(list), context(context_arg), m_name(name), m_sp(NULL),sp_result_field(NULL)
{
maybe_null= 1;
m_name->init_qname(current_thd);
dummy_table= (TABLE*) sql_calloc(sizeof(TABLE));
}
+
void
Item_func_sp::cleanup()
{
- if (result_field)
+ if (sp_result_field)
{
- delete result_field;
- result_field= NULL;
+ delete sp_result_field;
+ sp_result_field= NULL;
}
m_sp= NULL;
dummy_table->s= NULL;
@@ -5033,82 +5032,117 @@ Item_func_sp::func_name() const
}
-Field *
-Item_func_sp::sp_result_field(void) const
+
+/**
+ @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)
{
- Field *field;
- DBUG_ENTER("Item_func_sp::sp_result_field");
- DBUG_PRINT("info", ("sp: %s, flags: %x, level: %lu",
- (m_sp ? "YES" : "NO"),
- (m_sp ? m_sp->m_flags : (uint)0),
- (m_sp ? m_sp->m_recursion_level : (ulong)0)));
+ DBUG_ENTER("Item_func_sp::init_result_field");
+
+ char *empty_name= (char *) "";
+ TABLE_SHARE *share;
+
+ DBUG_ASSERT(m_sp == NULL);
+ DBUG_ASSERT(sp_result_field == NULL);
+ DBUG_ASSERT(dummy_table->s == NULL);
- if (!m_sp)
+ if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
+ &thd->sp_func_cache, TRUE)))
{
- THD *thd= current_thd;
- if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
- &thd->sp_func_cache, TRUE)))
- {
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
- DBUG_RETURN(0);
- }
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
+ 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.
+ */
+ dummy_table->s= share= &dummy_table->share_not_to_be_used;
+ dummy_table->alias = empty_name;
+ dummy_table->maybe_null = maybe_null;
+ dummy_table->in_use= thd;
+ dummy_table->copy_blobs= TRUE;
+ share->table_cache_key = empty_name;
+ share->table_name = empty_name;
+
+ if (!(sp_result_field= m_sp->create_result_field(max_length, name, dummy_table)))
+ {
+ DBUG_RETURN(TRUE);
}
- if (!dummy_table->s)
+
+ if (sp_result_field->pack_length() > sizeof(result_buf))
{
- char *empty_name= (char *) "";
- TABLE_SHARE *share;
- dummy_table->s= share= &dummy_table->share_not_to_be_used;
- dummy_table->alias = empty_name;
- dummy_table->maybe_null = maybe_null;
- dummy_table->in_use= current_thd;
- dummy_table->copy_blobs= TRUE;
- share->table_cache_key = empty_name;
- share->table_name = empty_name;
+ sp_result_field->move_field(sql_alloc(sp_result_field->pack_length()));
+ } else {
+ sp_result_field->move_field(result_buf);
}
- if (!(field= m_sp->create_result_field(max_length, name, dummy_table)))
- my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
+
+ sp_result_field->null_ptr= (uchar *) &null_value;
+ sp_result_field->null_bit= 1;
+
- DBUG_RETURN(field);
+ DBUG_RETURN(FALSE);
}
+/**
+ @brief Initialize local members with values from the Field interface.
-/*
- Execute function & store value in field
+ @note called from Item::fix_fields.
+*/
+void Item_func_sp::fix_length_and_dec()
+{
+ DBUG_ENTER("Item_func_sp::fix_length_and_dec");
- RETURN
- 0 value <> NULL
- 1 value = NULL or error
+ DBUG_ASSERT(sp_result_field);
+ decimals= sp_result_field->decimals();
+ max_length= sp_result_field->field_length;
+ collation.set(sp_result_field->charset());
+ maybe_null= 1;
+ unsigned_flag= test(sp_result_field->flags & UNSIGNED_FLAG);
+
+ DBUG_VOID_RETURN;
+}
+
+/**
+ @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(Field **flp)
+Item_func_sp::execute()
{
THD *thd= current_thd;
- Field *f;
-
+
/*
Get field in virtual tmp table to store result. Create the field if
invoked first time.
*/
-
- if (!(f= *flp))
- {
- if (!(*flp= f= sp_result_field()))
- {
- /* Error set by sp_result_field() */
- null_value= 1;
- return TRUE;
- }
- f->move_field((f->pack_length() > sizeof(result_buf)) ?
- sql_alloc(f->pack_length()) : result_buf);
- f->null_ptr= (uchar *)&null_value;
- f->null_bit= 1;
- }
/* Execute function and store the return value in the field. */
- if (execute_impl(thd, f))
+ if (execute_impl(thd))
{
null_value= 1;
context->process_error(thd);
@@ -5117,14 +5151,24 @@ Item_func_sp::execute(Field **flp)
/* Check that the field (the value) is not NULL. */
- null_value= f->is_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, Field *return_value_fld)
+Item_func_sp::execute_impl(THD *thd)
{
bool err_status= TRUE;
Sub_statement_state statement_state;
@@ -5141,7 +5185,7 @@ Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
thd->security_ctx= context->security_ctx;
}
#endif
- if (find_and_check_access(thd))
+ if (sp_check_access(thd))
goto error;
/*
@@ -5150,7 +5194,7 @@ Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
function call into binlog.
*/
thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION);
- err_status= m_sp->execute_function(thd, args, arg_count, return_value_fld);
+ err_status= m_sp->execute_function(thd, args, arg_count, sp_result_field);
thd->restore_sub_statement_state(&statement_state);
error:
@@ -5165,15 +5209,9 @@ error:
void
Item_func_sp::make_field(Send_field *tmp_field)
{
- Field *field;
DBUG_ENTER("Item_func_sp::make_field");
- if ((field= sp_result_field()))
- {
- field->make_field(tmp_field);
- delete field;
- DBUG_VOID_RETURN;
- }
- init_make_field(tmp_field, MYSQL_TYPE_VARCHAR);
+ DBUG_ASSERT(sp_result_field);
+ sp_result_field->make_field(tmp_field);
DBUG_VOID_RETURN;
}
@@ -5181,67 +5219,20 @@ Item_func_sp::make_field(Send_field *tmp_field)
enum enum_field_types
Item_func_sp::field_type() const
{
- Field *field;
DBUG_ENTER("Item_func_sp::field_type");
-
- if (result_field)
- DBUG_RETURN(result_field->type());
- if ((field= sp_result_field()))
- {
- enum_field_types result= field->type();
- delete field;
- DBUG_RETURN(result);
- }
- DBUG_RETURN(MYSQL_TYPE_VARCHAR);
+ DBUG_ASSERT(sp_result_field);
+ DBUG_RETURN(sp_result_field->type());
}
-
Item_result
Item_func_sp::result_type() const
{
- Field *field;
DBUG_ENTER("Item_func_sp::result_type");
DBUG_PRINT("info", ("m_sp = %p", m_sp));
-
- if (result_field)
- DBUG_RETURN(result_field->result_type());
- if ((field= sp_result_field()))
- {
- Item_result result= field->result_type();
- delete field;
- DBUG_RETURN(result);
- }
- DBUG_RETURN(STRING_RESULT);
+ DBUG_ASSERT(sp_result_field);
+ DBUG_RETURN(sp_result_field->result_type());
}
-void
-Item_func_sp::fix_length_and_dec()
-{
- Field *field;
- DBUG_ENTER("Item_func_sp::fix_length_and_dec");
-
- if (result_field)
- {
- decimals= result_field->decimals();
- max_length= result_field->field_length;
- collation.set(result_field->charset());
- DBUG_VOID_RETURN;
- }
-
- if (!(field= sp_result_field()))
- {
- context->process_error(current_thd);
- DBUG_VOID_RETURN;
- }
- decimals= field->decimals();
- max_length= field->field_length;
- collation.set(field->charset());
- maybe_null= 1;
- delete field;
- DBUG_VOID_RETURN;
-}
-
-
longlong Item_func_found_rows::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -5252,57 +5243,39 @@ longlong Item_func_found_rows::val_int()
Field *
Item_func_sp::tmp_table_field(TABLE *t_arg)
{
- Field *field= 0;
DBUG_ENTER("Item_func_sp::tmp_table_field");
- if (m_sp)
- field= m_sp->create_result_field(max_length, (const char*) name, t_arg);
-
- if (!field)
- field= Item_func::tmp_table_field(t_arg);
-
- if (!field)
- my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
-
- DBUG_RETURN(field);
+ DBUG_ASSERT(sp_result_field);
+ DBUG_RETURN(sp_result_field);
}
-/*
- Find the function and check access rights to the function
-
- SYNOPSIS
- find_and_check_access()
- thd thread handler
-
- RETURN
- FALSE Access granted
- TRUE Requested access can't be granted or function doesn't exists
-
- NOTES
- Checks if requested access to function can be granted to user.
+/**
+ @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::find_and_check_access(THD *thd)
+Item_func_sp::sp_check_access(THD *thd)
{
- if (! m_sp && ! (m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
- &thd->sp_func_cache, TRUE)))
- {
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
- return TRUE;
- }
-
+ DBUG_ENTER("Item_func_sp::sp_check_access");
+ DBUG_ASSERT(m_sp);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_routine_access(thd, EXECUTE_ACL,
m_sp->m_db.str, m_sp->m_name.str, 0, FALSE))
- return TRUE;
+ DBUG_RETURN(TRUE);
#endif
- return FALSE;
+ DBUG_RETURN(FALSE);
}
@@ -5310,9 +5283,25 @@ bool
Item_func_sp::fix_fields(THD *thd, Item **ref)
{
bool res;
+ DBUG_ENTER("Item_func_sp::fix_fields");
DBUG_ASSERT(fixed == 0);
+
+ /*
+ We must call init_result_field before Item_func::fix_fields()
+ 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);
+
+ if (res)
+ DBUG_RETURN(res);
+
res= Item_func::fix_fields(thd, ref);
- if (!res && thd->lex->view_prepare_mode)
+
+ if (res)
+ DBUG_RETURN(res);
+
+ if (thd->lex->view_prepare_mode)
{
/*
Here we check privileges of the stored routine only during view
@@ -5324,15 +5313,17 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
good idea especially if the view has SQL SECURITY DEFINER and
the used stored procedure has SQL SECURITY DEFINER.
*/
- res= find_and_check_access(thd);
+ res= sp_check_access(thd);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /*
+ Try to set and restore the security context to see whether it's valid
+ */
Security_context *save_secutiry_ctx;
- if (!res && !(res= set_routine_security_ctx(thd, m_sp, false,
- &save_secutiry_ctx)))
- {
+ res= set_routine_security_ctx(thd, m_sp, false, &save_secutiry_ctx);
+ if (!res)
sp_restore_security_context(thd, save_secutiry_ctx);
- }
+
#endif /* ! NO_EMBEDDED_ACCESS_CHECKS */
}
- return res;
+ DBUG_RETURN(res);
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 68591f9c6f5..6a619327590 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1405,12 +1405,15 @@ private:
sp_name *m_name;
mutable sp_head *m_sp;
TABLE *dummy_table;
- Field *result_field;
char result_buf[64];
+ /*
+ The result field of the concrete stored function.
+ */
+ Field *sp_result_field;
- bool execute(Field **flp);
- bool execute_impl(THD *thd, Field *return_value_fld);
- Field *sp_result_field(void) const;
+ bool execute();
+ bool execute_impl(THD *thd);
+ bool init_result_field(THD *thd);
public:
@@ -1436,23 +1439,23 @@ public:
longlong val_int()
{
- if (execute(&result_field))
+ if (execute())
return (longlong) 0;
- return result_field->val_int();
+ return sp_result_field->val_int();
}
double val_real()
{
- if (execute(&result_field))
+ if (execute())
return 0.0;
- return result_field->val_real();
+ return sp_result_field->val_real();
}
my_decimal *val_decimal(my_decimal *dec_buf)
{
- if (execute(&result_field))
+ if (execute())
return NULL;
- return result_field->val_decimal(dec_buf);
+ return sp_result_field->val_decimal(dec_buf);
}
String *val_str(String *str)
@@ -1461,7 +1464,7 @@ public:
char buff[20];
buf.set(buff, 20, str->charset());
buf.length(0);
- if (execute(&result_field))
+ if (execute())
return NULL;
/*
result_field will set buf pointing to internal buffer
@@ -1469,7 +1472,7 @@ public:
when SP is executed. In order to prevent occasional
corruption of returned value, we make here a copy.
*/
- result_field->val_str(&buf);
+ sp_result_field->val_str(&buf);
str->copy(buf);
return str;
}
@@ -1477,11 +1480,11 @@ public:
virtual bool change_context_processor(byte *cntx)
{ context= (Name_resolution_context *)cntx; return FALSE; }
- void fix_length_and_dec();
- bool find_and_check_access(THD * thd);
+ bool sp_check_access(THD * thd);
virtual enum Functype functype() const { return FUNC_SP; }
bool fix_fields(THD *thd, Item **ref);
+ void fix_length_and_dec(void);
bool is_expensive() { return 1; }
};