mirror of
https://github.com/MariaDB/server.git
synced 2026-04-20 07:15:33 +02:00
Fixed bug when accessing wrong decimal value in dynamic string (Fixed lp:781233)
Store decimal 0.0 in zero bytes in dynamic strings. mysqltest: Don't ignore error from mysql_stmt_fetch; This could cause rows to be missing from log when running with --ps-protocol Fixed wrong result length for CAST(... as TIME) client/mysqltest.cc: Don't ignore error from mysql_stmt_fetch; This could cause rows to be missing from log when running with --ps-protocol libmysql/libmysql.c: The max length for a TIME column is 17, not 15. mysql-test/r/dyncol.result: More tests mysql-test/t/dyncol.test: More tests mysys/ma_dyncol.c: Check content of decimal value on read and store to not get assert in decimal_bin_size(). Store decimal 0.0 in zero bytes in dynamic strings. This also solves a problem where decimal 0 had different internal representations. sql-common/my_time.c: Fixed DBUG_PRINT sql/item_timefunc.h: Fixed wrong result length for CAST(... as TIME). This was the cause of failures in buildbot when doing cast(... as time); sql/protocol.cc: More DBUG_PRINT
This commit is contained in:
parent
3a537679cb
commit
4c81cef75d
8 changed files with 124 additions and 19 deletions
|
|
@ -6673,6 +6673,7 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
|
|||
my_bool *is_null;
|
||||
ulong *length;
|
||||
uint i;
|
||||
int error;
|
||||
|
||||
/* Allocate array with bind structs, lengths and NULL flags */
|
||||
my_bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND),
|
||||
|
|
@ -6700,7 +6701,7 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
|
|||
die("mysql_stmt_bind_result failed: %d: %s",
|
||||
mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
|
||||
|
||||
while (mysql_stmt_fetch(stmt) == 0)
|
||||
while ((error=mysql_stmt_fetch(stmt)) == 0)
|
||||
{
|
||||
for (i= 0; i < num_fields; i++)
|
||||
append_field(ds, i, &fields[i], (char*)my_bind[i].buffer,
|
||||
|
|
@ -6709,8 +6710,11 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt,
|
|||
dynstr_append_mem(ds, "\n", 1);
|
||||
}
|
||||
|
||||
if (error != MYSQL_NO_DATA)
|
||||
die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: error: %d",
|
||||
error);
|
||||
if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
|
||||
die("fetch didn't end with MYSQL_NO_DATA from statement: %d %s",
|
||||
die("mysql_fetch didn't end with MYSQL_NO_DATA from statement: %d %s",
|
||||
mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
|
||||
|
||||
for (i= 0; i < num_fields; i++)
|
||||
|
|
|
|||
|
|
@ -4381,7 +4381,7 @@ static my_bool setup_one_fetch_function(MYSQL_BIND *param, MYSQL_FIELD *field)
|
|||
field->max_length= MAX_DOUBLE_STRING_REP_LENGTH;
|
||||
break;
|
||||
case MYSQL_TYPE_TIME:
|
||||
field->max_length= 15; /* 19:23:48.123456 */
|
||||
field->max_length= 17; /* -819:23:48.123456 */
|
||||
param->skip_result= skip_result_with_length;
|
||||
break;
|
||||
case MYSQL_TYPE_DATE:
|
||||
|
|
|
|||
|
|
@ -165,6 +165,12 @@ Note 1003 select hex(column_create(1,'afaf' AS char charset utf8 ,2,1212 AS unsi
|
|||
6, "2011-04-05" AS date,
|
||||
7, "- 0:45:49.000001" AS time,
|
||||
8, "2011-04-05 0:45:49.000001" AS datetime))`
|
||||
select hex(column_create(1, 0.0 AS decimal));
|
||||
hex(column_create(1, 0.0 AS decimal))
|
||||
000100010004
|
||||
select hex(column_create(1, 1.0 AS decimal));
|
||||
hex(column_create(1, 1.0 AS decimal))
|
||||
00010001000401018100
|
||||
#
|
||||
# column get uint
|
||||
#
|
||||
|
|
@ -575,6 +581,9 @@ column_get(column_create(1, "1223.5555" AS decimal(10,5)), 1 as decimal(3,2))
|
|||
9.99
|
||||
Warnings:
|
||||
Error 1264 Out of range value for column 'column_get(column_create(1, "1223.5555" AS decimal(10,5)), 1 as decimal(3,2))' at row 1
|
||||
select column_get(column_create(1, 0.0 AS decimal,2, 0.0 as decimal), 1 as decimal);
|
||||
column_get(column_create(1, 0.0 AS decimal,2, 0.0 as decimal), 1 as decimal)
|
||||
0
|
||||
#
|
||||
# column get datetime
|
||||
#
|
||||
|
|
@ -1234,3 +1243,23 @@ DROP TABLE t1;
|
|||
set @a=0x0102000200030004000F0D086B74697A6A7176746F6B687563726A746E7A746A666163726C6F7A6B62636B6B756B666779666977617369796F67756C726D62677A72756E63626D78636D7077706A6F736C6D636464696770786B6371637A6A6A6463737A6A676879716462637178646C666E6B6C726A637677696E7271746C616D646368687A6C707869786D666F666261797470616A63797673737A796D74747475666B717573687A79696E7276706F796A6E767361796A6F6D646F6378677A667074746363736A796D67746C786F697873686464616265616A7A6F7168707A6B776B6376737A6B72666C6F666C69636163686F6B666D627166786A71616F;
|
||||
select column_add(@a, 3, "a");
|
||||
ERROR HY000: Encountered illegal format of dynamic column string
|
||||
#
|
||||
# LP#781233 mysqld: decimal.c:1459: decimal_bin_size:
|
||||
# Assertion `scale >= 0 && precision > 0 && scale <= precision' ...
|
||||
#
|
||||
set @a=0x00020008000009000C2C010080;
|
||||
select COLUMN_GET(@a, 9 AS DECIMAL);
|
||||
COLUMN_GET(@a, 9 AS DECIMAL)
|
||||
0
|
||||
select hex(COLUMN_CREATE(0, COLUMN_GET(@a, 9 AS DECIMAL)));
|
||||
hex(COLUMN_CREATE(0, COLUMN_GET(@a, 9 AS DECIMAL)))
|
||||
000100000004
|
||||
select hex(COLUMN_CREATE(0, COLUMN_GET(@a, 9 AS DECIMAL(19,0))));
|
||||
hex(COLUMN_CREATE(0, COLUMN_GET(@a, 9 AS DECIMAL(19,0))))
|
||||
000100000004
|
||||
select hex(COLUMN_CREATE(0, COLUMN_GET(COLUMN_CREATE(0, 0.0 as decimal), 0 as decimal)));
|
||||
hex(COLUMN_CREATE(0, COLUMN_GET(COLUMN_CREATE(0, 0.0 as decimal), 0 as decimal)))
|
||||
000100000004
|
||||
select hex(COLUMN_CREATE(0, 0.0 as decimal));
|
||||
hex(COLUMN_CREATE(0, 0.0 as decimal))
|
||||
000100000004
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@ select hex(COLUMN_CREATE(1, "afaf" AS char character set utf8,
|
|||
6, "2011-04-05" AS date,
|
||||
7, "- 0:45:49.000001" AS time,
|
||||
8, "2011-04-05 0:45:49.000001" AS datetime));
|
||||
|
||||
select hex(column_create(1, 0.0 AS decimal));
|
||||
select hex(column_create(1, 1.0 AS decimal));
|
||||
|
||||
--echo #
|
||||
--echo # column get uint
|
||||
|
|
@ -204,6 +205,7 @@ select column_get(column_create(1, "1223.5555" as double), 1 as decimal(5,2));
|
|||
select column_get(column_create(1, "-1223.5555" as double), 1 as decimal(5,2));
|
||||
select column_get(column_create(1, "1223.5555" AS double), 1 as decimal(3,2));
|
||||
select column_get(column_create(1, "1223.5555" AS decimal(10,5)), 1 as decimal(3,2));
|
||||
select column_get(column_create(1, 0.0 AS decimal,2, 0.0 as decimal), 1 as decimal);
|
||||
|
||||
--echo #
|
||||
--echo # column get datetime
|
||||
|
|
@ -506,3 +508,16 @@ DROP TABLE t1;
|
|||
set @a=0x0102000200030004000F0D086B74697A6A7176746F6B687563726A746E7A746A666163726C6F7A6B62636B6B756B666779666977617369796F67756C726D62677A72756E63626D78636D7077706A6F736C6D636464696770786B6371637A6A6A6463737A6A676879716462637178646C666E6B6C726A637677696E7271746C616D646368687A6C707869786D666F666261797470616A63797673737A796D74747475666B717573687A79696E7276706F796A6E767361796A6F6D646F6378677A667074746363736A796D67746C786F697873686464616265616A7A6F7168707A6B776B6376737A6B72666C6F666C69636163686F6B666D627166786A71616F;
|
||||
--error ER_DYN_COL_WRONG_FORMAT
|
||||
select column_add(@a, 3, "a");
|
||||
|
||||
--echo #
|
||||
--echo # LP#781233 mysqld: decimal.c:1459: decimal_bin_size:
|
||||
--echo # Assertion `scale >= 0 && precision > 0 && scale <= precision' ...
|
||||
--echo #
|
||||
|
||||
set @a=0x00020008000009000C2C010080;
|
||||
select COLUMN_GET(@a, 9 AS DECIMAL);
|
||||
select hex(COLUMN_CREATE(0, COLUMN_GET(@a, 9 AS DECIMAL)));
|
||||
select hex(COLUMN_CREATE(0, COLUMN_GET(@a, 9 AS DECIMAL(19,0))));
|
||||
|
||||
select hex(COLUMN_CREATE(0, COLUMN_GET(COLUMN_CREATE(0, 0.0 as decimal), 0 as decimal)));
|
||||
select hex(COLUMN_CREATE(0, 0.0 as decimal));
|
||||
|
|
|
|||
|
|
@ -312,7 +312,9 @@ dynamic_column_sint_read(DYNAMIC_COLUMN_VALUE *store_it_here,
|
|||
|
||||
@param value The value for which we are calculating length
|
||||
|
||||
@return number of bytes
|
||||
@return
|
||||
Error: (size_t) ~0
|
||||
ok number of bytes
|
||||
*/
|
||||
|
||||
static size_t
|
||||
|
|
@ -331,11 +333,32 @@ dynamic_column_value_len(DYNAMIC_COLUMN_VALUE *value)
|
|||
return (dynamic_column_var_uint_bytes(value->charset->number) +
|
||||
value->string_value.length);
|
||||
case DYN_COL_DECIMAL:
|
||||
{
|
||||
int precision= value->decimal_value.intg + value->decimal_value.frac;
|
||||
int scale= value->decimal_value.frac;
|
||||
|
||||
if (precision == 0 || decimal_is_zero(&value->decimal_value))
|
||||
{
|
||||
/* This is here to simplify dynamic_column_decimal_store() */
|
||||
value->decimal_value.intg= value->decimal_value.frac= 0;
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
Check if legal decimal; This is needed to not get an assert in
|
||||
decimal_bin_size(). However this should be impossible as all
|
||||
decimals entered here should be valid and we have the special check
|
||||
above to handle the unlikely but possible case that decimal_value.intg
|
||||
and decimal.frac is 0.
|
||||
*/
|
||||
if (scale < 0 || precision <= 0)
|
||||
{
|
||||
DBUG_ASSERT(0); /* Impossible */
|
||||
return (size_t) ~0;
|
||||
}
|
||||
return (dynamic_column_var_uint_bytes(value->decimal_value.intg) +
|
||||
dynamic_column_var_uint_bytes(value->decimal_value.frac) +
|
||||
decimal_bin_size(value->decimal_value.intg +
|
||||
value->decimal_value.frac,
|
||||
value->decimal_value.frac));
|
||||
decimal_bin_size(precision, scale));
|
||||
}
|
||||
case DYN_COL_DATETIME:
|
||||
/* date+time in bits: 14 + 4 + 5 + 10 + 6 + 6 + 20 + 1 66bits ~= 9 bytes */
|
||||
return 9;
|
||||
|
|
@ -455,7 +478,14 @@ static enum enum_dyncol_func_result
|
|||
dynamic_column_decimal_store(DYNAMIC_COLUMN *str,
|
||||
decimal_t *value)
|
||||
{
|
||||
uint bin_size= decimal_bin_size(value->intg + value->frac, value->frac);
|
||||
uint bin_size;
|
||||
int precision= value->intg + value->frac;
|
||||
|
||||
/* Store decimal zero as empty string */
|
||||
if (precision == 0)
|
||||
return ER_DYNCOL_OK;
|
||||
|
||||
bin_size= decimal_bin_size(precision, value->frac);
|
||||
if (dynstr_realloc(str, bin_size + 20))
|
||||
return ER_DYNCOL_RESOURCE;
|
||||
|
||||
|
|
@ -464,8 +494,7 @@ dynamic_column_decimal_store(DYNAMIC_COLUMN *str,
|
|||
(void) dynamic_column_var_uint_store(str, value->frac);
|
||||
|
||||
decimal2bin(value, (uchar *) str->str + str->length,
|
||||
value->intg + value->frac,
|
||||
value->frac);
|
||||
precision, value->frac);
|
||||
str->length+= bin_size;
|
||||
return ER_DYNCOL_OK;
|
||||
}
|
||||
|
|
@ -502,20 +531,29 @@ dynamic_column_decimal_read(DYNAMIC_COLUMN_VALUE *store_it_here,
|
|||
uchar *data, size_t length)
|
||||
{
|
||||
size_t intg_len, frac_len;
|
||||
int intg, frac;
|
||||
int intg, frac, precision, scale;
|
||||
|
||||
dynamic_column_prepare_decimal(store_it_here);
|
||||
/* Decimals 0.0 is stored as a zero length string */
|
||||
if (length == 0)
|
||||
return ER_DYNCOL_OK; /* value contains zero */
|
||||
|
||||
intg= (int)dynamic_column_var_uint_get(data, length, &intg_len);
|
||||
data+= intg_len;
|
||||
frac= (int)dynamic_column_var_uint_get(data, length - intg_len, &frac_len);
|
||||
data+= frac_len;
|
||||
|
||||
/* Check the size of data is correct */
|
||||
if (decimal_bin_size(intg + frac, frac) !=
|
||||
precision= intg + frac;
|
||||
scale= frac;
|
||||
if (scale < 0 || precision <= 0 || scale > precision ||
|
||||
(length - intg_len - frac_len) >
|
||||
(size_t) (DECIMAL_BUFF_LENGTH*sizeof(decimal_digit_t)) ||
|
||||
decimal_bin_size(intg + frac, frac) !=
|
||||
(int) (length - intg_len - frac_len))
|
||||
return ER_DYNCOL_FORMAT;
|
||||
|
||||
if (bin2decimal(data, &store_it_here->decimal_value, intg + frac, frac) !=
|
||||
if (bin2decimal(data, &store_it_here->decimal_value, precision, scale) !=
|
||||
E_DEC_OK)
|
||||
return ER_DYNCOL_FORMAT;
|
||||
return ER_DYNCOL_OK;
|
||||
|
|
@ -1113,8 +1151,11 @@ dynamic_column_create_many_internal(DYNAMIC_COLUMN *str,
|
|||
{
|
||||
if (values[i].type != DYN_COL_NULL)
|
||||
{
|
||||
size_t tmp;
|
||||
not_null_column_count++;
|
||||
data_size+= dynamic_column_value_len(values + i);
|
||||
data_size+= (tmp=dynamic_column_value_len(values + i));
|
||||
if (tmp == (size_t) ~0)
|
||||
return ER_DYNCOL_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1822,7 +1863,12 @@ dynamic_column_update_many(DYNAMIC_COLUMN *str,
|
|||
|
||||
plan[i].act= PLAN_REPLACE;
|
||||
/* get data delta in bytes */
|
||||
plan[i].length= dynamic_column_value_len(plan[i].val);
|
||||
if ((plan[i].length= dynamic_column_value_len(plan[i].val)) ==
|
||||
(size_t) ~0)
|
||||
{
|
||||
rc= ER_DYNCOL_DATA;
|
||||
goto end;
|
||||
}
|
||||
data_delta+= plan[i].length - entry_data_size;
|
||||
}
|
||||
}
|
||||
|
|
@ -1841,7 +1887,12 @@ dynamic_column_update_many(DYNAMIC_COLUMN *str,
|
|||
plan[i].act= PLAN_ADD;
|
||||
header_delta++; /* One more row in header */
|
||||
/* get data delta in bytes */
|
||||
plan[i].length= dynamic_column_value_len(plan[i].val);
|
||||
if ((plan[i].length= dynamic_column_value_len(plan[i].val)) ==
|
||||
(size_t) ~0)
|
||||
{
|
||||
rc= ER_DYNCOL_DATA;
|
||||
goto end;
|
||||
}
|
||||
data_delta+= plan[i].length;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
|
|||
my_bool found_delimitier= 0, found_space= 0;
|
||||
uint frac_pos, frac_len;
|
||||
DBUG_ENTER("str_to_datetime");
|
||||
DBUG_PRINT("ENTER",("str: %.*s",length,str));
|
||||
DBUG_PRINT("enter",("str: %.*s",length,str));
|
||||
|
||||
LINT_INIT(field_length);
|
||||
|
||||
|
|
|
|||
|
|
@ -946,6 +946,12 @@ public:
|
|||
{
|
||||
return tmp_table_field_from_field_type(table, 0);
|
||||
}
|
||||
void fix_length_and_dec()
|
||||
{
|
||||
collation.set(&my_charset_bin);
|
||||
max_length= 17;
|
||||
maybe_null= 1;
|
||||
}
|
||||
bool result_as_longlong() { return TRUE; }
|
||||
longlong val_int();
|
||||
double val_real() { return val_real_from_decimal(); }
|
||||
|
|
|
|||
|
|
@ -617,7 +617,7 @@ bool Protocol::send_fields(List<Item> *list, uint flags)
|
|||
Protocol_text prot(thd);
|
||||
String *local_packet= prot.storage_packet();
|
||||
CHARSET_INFO *thd_charset= thd->variables.character_set_results;
|
||||
DBUG_ENTER("send_fields");
|
||||
DBUG_ENTER("Protocol::send_fields");
|
||||
|
||||
if (flags & SEND_NUM_ROWS)
|
||||
{ // Packet with number of elements
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue