mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
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.
This commit is contained in:
parent
c039eed82c
commit
ffc605aad5
4 changed files with 319 additions and 185 deletions
|
@ -5741,4 +5741,92 @@ END|
|
|||
CALL bug24117()|
|
||||
DROP PROCEDURE bug24117|
|
||||
DROP TABLE t3|
|
||||
drop function if exists bug20777|
|
||||
drop table if exists examplebug20777|
|
||||
create function bug20777(f1 bigint unsigned) returns bigint unsigned
|
||||
begin
|
||||
set f1 = (f1 - 10); set f1 = (f1 + 10);
|
||||
return f1;
|
||||
end|
|
||||
select bug20777(9223372036854775803) as '9223372036854775803 2**63-5';
|
||||
9223372036854775803 2**63-5
|
||||
9223372036854775803
|
||||
select bug20777(9223372036854775804) as '9223372036854775804 2**63-4';
|
||||
9223372036854775804 2**63-4
|
||||
9223372036854775804
|
||||
select bug20777(9223372036854775805) as '9223372036854775805 2**63-3';
|
||||
9223372036854775805 2**63-3
|
||||
9223372036854775805
|
||||
select bug20777(9223372036854775806) as '9223372036854775806 2**63-2';
|
||||
9223372036854775806 2**63-2
|
||||
9223372036854775806
|
||||
select bug20777(9223372036854775807) as '9223372036854775807 2**63-1';
|
||||
9223372036854775807 2**63-1
|
||||
9223372036854775807
|
||||
select bug20777(9223372036854775808) as '9223372036854775808 2**63+0';
|
||||
9223372036854775808 2**63+0
|
||||
9223372036854775808
|
||||
select bug20777(9223372036854775809) as '9223372036854775809 2**63+1';
|
||||
9223372036854775809 2**63+1
|
||||
9223372036854775809
|
||||
select bug20777(9223372036854775810) as '9223372036854775810 2**63+2';
|
||||
9223372036854775810 2**63+2
|
||||
9223372036854775810
|
||||
select bug20777(-9223372036854775808) as 'lower bounds signed bigint';
|
||||
lower bounds signed bigint
|
||||
0
|
||||
select bug20777(9223372036854775807) as 'upper bounds signed bigint';
|
||||
upper bounds signed bigint
|
||||
9223372036854775807
|
||||
select bug20777(0) as 'lower bounds unsigned bigint';
|
||||
lower bounds unsigned bigint
|
||||
0
|
||||
select bug20777(18446744073709551615) as 'upper bounds unsigned bigint';
|
||||
upper bounds unsigned bigint
|
||||
18446744073709551615
|
||||
select bug20777(18446744073709551616) as 'upper bounds unsigned bigint + 1';
|
||||
upper bounds unsigned bigint + 1
|
||||
18446744073709551615
|
||||
select bug20777(-1) as 'lower bounds unsigned bigint - 1';
|
||||
lower bounds unsigned bigint - 1
|
||||
0
|
||||
select bug20777(1.84e+19) as 'submitter value, 1.84e19';
|
||||
submitter value, 1.84e19
|
||||
9223372036854775808
|
||||
create table examplebug20777 as select
|
||||
0 as 'i',
|
||||
bug20777(9223372036854775806) as '2**63-2',
|
||||
bug20777(9223372036854775807) as '2**63-1',
|
||||
bug20777(9223372036854775808) as '2**63',
|
||||
bug20777(9223372036854775809) as '2**63+1',
|
||||
bug20777(18446744073709551614) as '2**64-2',
|
||||
bug20777(18446744073709551615) as '2**64-1',
|
||||
bug20777(18446744073709551616) as '2**64',
|
||||
bug20777(0) as '0',
|
||||
bug20777(-1) as '-1';
|
||||
insert into examplebug20777 values (1, 9223372036854775806, 9223372036854775807, 223372036854775808, 9223372036854775809, 18446744073709551614, 18446744073709551615, 8446744073709551616, 0, -1);
|
||||
show create table examplebug20777;
|
||||
Table Create Table
|
||||
examplebug20777 CREATE TABLE `examplebug20777` (
|
||||
`i` int(1) NOT NULL default '0',
|
||||
`2**63-2` bigint(20) unsigned default NULL,
|
||||
`2**63-1` bigint(20) unsigned default NULL,
|
||||
`2**63` bigint(20) unsigned default NULL,
|
||||
`2**63+1` bigint(20) unsigned default NULL,
|
||||
`2**64-2` bigint(20) unsigned default NULL,
|
||||
`2**64-1` bigint(20) unsigned default NULL,
|
||||
`2**64` bigint(20) unsigned default NULL,
|
||||
`0` bigint(20) unsigned default NULL,
|
||||
`-1` bigint(20) unsigned default NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
select * from examplebug20777 order by i;
|
||||
i 2**63-2 2**63-1 2**63 2**63+1 2**64-2 2**64-1 2**64 0 -1
|
||||
0 9223372036854775806 9223372036854775807 9223372036854775808 9223372036854775809 18446744073709551614 18446744073709551615 18446744073709551615 0 0
|
||||
1 9223372036854775806 9223372036854775807 223372036854775808 9223372036854775809 18446744073709551614 18446744073709551615 8446744073709551616 0 0
|
||||
drop table examplebug20777;
|
||||
select bug20777(18446744073709551613)+1;
|
||||
bug20777(18446744073709551613)+1
|
||||
18446744073709551614
|
||||
drop function bug20777;
|
||||
End of 5.0 tests.
|
||||
drop table t1,t2;
|
||||
|
|
|
@ -6715,9 +6715,56 @@ DROP PROCEDURE bug24117|
|
|||
DROP TABLE t3|
|
||||
|
||||
#
|
||||
# NOTE: The delimiter is `|`, and not `;`. It is changed to `;`
|
||||
# at the end of the file!
|
||||
# Bug#20777: Function w BIGINT UNSIGNED shows diff. behaviour --ps-protocol
|
||||
#
|
||||
--disable_warnings
|
||||
drop function if exists bug20777|
|
||||
drop table if exists examplebug20777|
|
||||
--enabled_warnings
|
||||
create function bug20777(f1 bigint unsigned) returns bigint unsigned
|
||||
begin
|
||||
set f1 = (f1 - 10); set f1 = (f1 + 10);
|
||||
return f1;
|
||||
end|
|
||||
delimiter ;|
|
||||
select bug20777(9223372036854775803) as '9223372036854775803 2**63-5';
|
||||
select bug20777(9223372036854775804) as '9223372036854775804 2**63-4';
|
||||
select bug20777(9223372036854775805) as '9223372036854775805 2**63-3';
|
||||
select bug20777(9223372036854775806) as '9223372036854775806 2**63-2';
|
||||
select bug20777(9223372036854775807) as '9223372036854775807 2**63-1';
|
||||
select bug20777(9223372036854775808) as '9223372036854775808 2**63+0';
|
||||
select bug20777(9223372036854775809) as '9223372036854775809 2**63+1';
|
||||
select bug20777(9223372036854775810) as '9223372036854775810 2**63+2';
|
||||
select bug20777(-9223372036854775808) as 'lower bounds signed bigint';
|
||||
select bug20777(9223372036854775807) as 'upper bounds signed bigint';
|
||||
select bug20777(0) as 'lower bounds unsigned bigint';
|
||||
select bug20777(18446744073709551615) as 'upper bounds unsigned bigint';
|
||||
select bug20777(18446744073709551616) as 'upper bounds unsigned bigint + 1';
|
||||
select bug20777(-1) as 'lower bounds unsigned bigint - 1';
|
||||
select bug20777(1.84e+19) as 'submitter value, 1.84e19';
|
||||
|
||||
create table examplebug20777 as select
|
||||
0 as 'i',
|
||||
bug20777(9223372036854775806) as '2**63-2',
|
||||
bug20777(9223372036854775807) as '2**63-1',
|
||||
bug20777(9223372036854775808) as '2**63',
|
||||
bug20777(9223372036854775809) as '2**63+1',
|
||||
bug20777(18446744073709551614) as '2**64-2',
|
||||
bug20777(18446744073709551615) as '2**64-1',
|
||||
bug20777(18446744073709551616) as '2**64',
|
||||
bug20777(0) as '0',
|
||||
bug20777(-1) as '-1';
|
||||
insert into examplebug20777 values (1, 9223372036854775806, 9223372036854775807, 223372036854775808, 9223372036854775809, 18446744073709551614, 18446744073709551615, 8446744073709551616, 0, -1);
|
||||
show create table examplebug20777;
|
||||
select * from examplebug20777 order by i;
|
||||
|
||||
drop table examplebug20777;
|
||||
select bug20777(18446744073709551613)+1;
|
||||
drop function bug20777;
|
||||
delimiter |;
|
||||
|
||||
###
|
||||
--echo End of 5.0 tests.
|
||||
|
||||
#
|
||||
# BUG#NNNN: New bug synopsis
|
||||
|
@ -6726,8 +6773,13 @@ DROP TABLE t3|
|
|||
#drop procedure if exists bugNNNN|
|
||||
#--enable_warnings
|
||||
#create procedure bugNNNN...
|
||||
|
||||
#
|
||||
# Add bugs above this line. Use existing tables t1 and t2 when
|
||||
# practical, or create table t3, t4 etc temporarily (and drop them).
|
||||
# practical, or create table t3,t4 etc temporarily (and drop them).
|
||||
# NOTE: The delimiter is `|`, and not `;`. It is changed to `;`
|
||||
# at the end of the file!
|
||||
#
|
||||
|
||||
delimiter ;|
|
||||
drop table t1,t2;
|
||||
|
||||
|
|
325
sql/item_func.cc
325
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;
|
||||
|
||||
if (!m_sp)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (!dummy_table->s)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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));
|
||||
DBUG_ASSERT(m_sp == NULL);
|
||||
DBUG_ASSERT(sp_result_field == NULL);
|
||||
DBUG_ASSERT(dummy_table->s == NULL);
|
||||
|
||||
DBUG_RETURN(field);
|
||||
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);
|
||||
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 (sp_result_field->pack_length() > sizeof(result_buf))
|
||||
{
|
||||
sp_result_field->move_field(sql_alloc(sp_result_field->pack_length()));
|
||||
} 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 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);
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue