BitKeeper/etc/logging_ok:
  auto-union
sql/item.cc:
  Auto merged
sql/item_func.cc:
  Auto merged
sql/mysqld.cc:
  Auto merged
sql/set_var.cc:
  Auto merged
sql/sql_parse.cc:
  Auto merged
sql/item.h:
  SCCS merged
This commit is contained in:
unknown 2005-05-05 20:10:50 +05:00
commit 54d57ffd2f
23 changed files with 417 additions and 241 deletions

View File

@ -82,6 +82,7 @@ hf@bisonxp.(none)
hf@deer.(none) hf@deer.(none)
hf@deer.mysql.r18.ru hf@deer.mysql.r18.ru
hf@genie.(none) hf@genie.(none)
holyfoot@mysql.com
igor@hundin.mysql.fi igor@hundin.mysql.fi
igor@linux.local igor@linux.local
igor@rurik.mysql.com igor@rurik.mysql.com

View File

@ -39,7 +39,7 @@ int decimal2longlong(decimal_t *from, longlong *to);
int longlong2decimal(longlong from, decimal_t *to); int longlong2decimal(longlong from, decimal_t *to);
int decimal2double(decimal_t *from, double *to); int decimal2double(decimal_t *from, double *to);
int double2decimal(double from, decimal_t *to); int double2decimal(double from, decimal_t *to);
void decimal_optimize_fraction(decimal_t *from); int decimal_actual_fraction(decimal_t *from);
int decimal2bin(decimal_t *from, char *to, int precision, int scale); int decimal2bin(decimal_t *from, char *to, int precision, int scale);
int bin2decimal(char *from, decimal_t *to, int precision, int scale); int bin2decimal(char *from, decimal_t *to, int precision, int scale);

View File

@ -2229,12 +2229,6 @@ void Field_decimal::sql_type(String &res) const
** Field_new_decimal ** Field_new_decimal
****************************************************************************/ ****************************************************************************/
/*
Constructors of new decimal field. In case of using NOT_FIXED_DEC it try
to use maximally allowed length (DECIMAL_MAX_LENGTH) and number of digits
after decimal point maximally close to half of this range
(min(DECIMAL_MAX_LENGTH/2, NOT_FIXED_DEC-1))
*/
Field_new_decimal::Field_new_decimal(char *ptr_arg, Field_new_decimal::Field_new_decimal(char *ptr_arg,
uint32 len_arg, uchar *null_ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, uchar null_bit_arg,
@ -2243,17 +2237,15 @@ Field_new_decimal::Field_new_decimal(char *ptr_arg,
struct st_table *table_arg, struct st_table *table_arg,
uint8 dec_arg,bool zero_arg, uint8 dec_arg,bool zero_arg,
bool unsigned_arg) bool unsigned_arg)
:Field_num(ptr_arg, :Field_num(ptr_arg, len_arg,
(dec_arg == NOT_FIXED_DEC || len_arg > DECIMAL_MAX_LENGTH ?
DECIMAL_MAX_LENGTH : len_arg),
null_ptr_arg, null_bit_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg, unireg_check_arg, field_name_arg, table_arg,
(dec_arg == NOT_FIXED_DEC ? dec_arg, zero_arg, unsigned_arg)
min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1) :
dec_arg),
zero_arg, unsigned_arg)
{ {
bin_size= my_decimal_get_binary_size(field_length, dec); precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) &&
(dec <= DECIMAL_MAX_SCALE));
bin_size= my_decimal_get_binary_size(precision, dec);
} }
@ -2261,18 +2253,18 @@ Field_new_decimal::Field_new_decimal(uint32 len_arg,
bool maybe_null, bool maybe_null,
const char *name, const char *name,
struct st_table *t_arg, struct st_table *t_arg,
uint8 dec_arg) uint8 dec_arg,
:Field_num((char*) 0, bool unsigned_arg)
(dec_arg == NOT_FIXED_DEC|| len_arg > DECIMAL_MAX_LENGTH ? :Field_num((char*) 0, len_arg,
DECIMAL_MAX_LENGTH : len_arg),
maybe_null ? (uchar*) "": 0, 0, maybe_null ? (uchar*) "": 0, 0,
NONE, name, t_arg, NONE, name, t_arg,
(dec_arg == NOT_FIXED_DEC ? dec_arg,
min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1) : 0, unsigned_arg)
dec_arg),
0, 0)
{ {
bin_size= my_decimal_get_binary_size(field_length, dec); precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg);
DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) &&
(dec <= DECIMAL_MAX_SCALE));
bin_size= my_decimal_get_binary_size(precision, dec);
} }
@ -2295,7 +2287,7 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
bool sign) bool sign)
{ {
DBUG_ENTER("Field_new_decimal::set_value_on_overflow"); DBUG_ENTER("Field_new_decimal::set_value_on_overflow");
max_my_decimal(decimal_value, field_length, decimals()); max_my_decimal(decimal_value, precision, decimals());
if (sign) if (sign)
{ {
if (unsigned_flag) if (unsigned_flag)
@ -2326,10 +2318,14 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
bool Field_new_decimal::store_value(const my_decimal *decimal_value) bool Field_new_decimal::store_value(const my_decimal *decimal_value)
{ {
my_decimal *dec= (my_decimal*)decimal_value;
int error= 0; int error= 0;
DBUG_ENTER("Field_new_decimal::store_value"); DBUG_ENTER("Field_new_decimal::store_value");
dbug_print_decimal("enter", "value: %s", dec); #ifndef DBUG_OFF
{
char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
DBUG_PRINT("enter", ("value: %s", dbug_decimal_as_string(dbug_buff, decimal_value)));
}
#endif
/* check that we do not try to write negative value in unsigned field */ /* check that we do not try to write negative value in unsigned field */
if (unsigned_flag && decimal_value->sign()) if (unsigned_flag && decimal_value->sign())
@ -2337,25 +2333,27 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
DBUG_PRINT("info", ("unsigned overflow")); DBUG_PRINT("info", ("unsigned overflow"));
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1; error= 1;
dec= &decimal_zero; decimal_value= &decimal_zero;
} }
DBUG_PRINT("info", ("saving with precision %d, scale: %d", #ifndef DBUG_OFF
(int)field_length, (int)decimals())); {
dbug_print_decimal("info", "value: %s", dec); char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
DBUG_PRINT("info", ("saving with precision %d, scale: %d, value %s",
(int)precision, (int)dec,
dbug_decimal_as_string(dbug_buff, decimal_value)));
}
#endif
if (warn_if_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & if (warn_if_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
~E_DEC_OVERFLOW, decimal_value, ptr, precision, dec)))
dec, ptr,
field_length,
decimals())))
{ {
my_decimal buff; my_decimal buff;
DBUG_PRINT("info", ("overflow")); DBUG_PRINT("info", ("overflow"));
set_value_on_overflow(&buff, dec->sign()); set_value_on_overflow(&buff, decimal_value->sign());
my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, field_length, decimals()); my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec);
error= 1; error= 1;
} }
DBUG_EXECUTE("info", print_decimal_buff(dec, (byte *) ptr, bin_size);); DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr, bin_size););
DBUG_RETURN(error); DBUG_RETURN(error);
} }
@ -2387,7 +2385,11 @@ int Field_new_decimal::store(const char *from, uint length,
break; break;
} }
dbug_print_decimal("enter", "value: %s", &decimal_value); #ifndef DBUG_OFF
char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
DBUG_PRINT("enter", ("value: %s",
dbug_decimal_as_string(dbug_buff, &decimal_value)));
#endif
store_value(&decimal_value); store_value(&decimal_value);
DBUG_RETURN(err); DBUG_RETURN(err);
} }
@ -2477,8 +2479,7 @@ my_decimal* Field_new_decimal::val_decimal(my_decimal *decimal_value)
{ {
DBUG_ENTER("Field_new_decimal::val_decimal"); DBUG_ENTER("Field_new_decimal::val_decimal");
binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value, binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value,
field_length, precision, dec);
decimals());
DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr, DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr,
bin_size);); bin_size););
DBUG_RETURN(decimal_value); DBUG_RETURN(decimal_value);
@ -2489,12 +2490,9 @@ String *Field_new_decimal::val_str(String *val_buffer,
String *val_ptr __attribute__((unused))) String *val_ptr __attribute__((unused)))
{ {
my_decimal decimal_value; my_decimal decimal_value;
int fixed_precision= (zerofill ? uint fixed_precision= zerofill ? precision : 0;
(field_length + (decimals() ? 1 : 0)) :
0);
my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
fixed_precision, decimals(), '0', fixed_precision, dec, '0', val_buffer);
val_buffer);
return val_buffer; return val_buffer;
} }
@ -2516,7 +2514,7 @@ void Field_new_decimal::sql_type(String &str) const
{ {
CHARSET_INFO *cs= str.charset(); CHARSET_INFO *cs= str.charset();
str.length(cs->cset->snprintf(cs, (char*) str.ptr(), str.alloced_length(), str.length(cs->cset->snprintf(cs, (char*) str.ptr(), str.alloced_length(),
"decimal(%d,%d)", field_length, (int)dec)); "decimal(%d,%d)", precision, (int)dec));
add_zerofill_and_unsigned(str); add_zerofill_and_unsigned(str);
} }

View File

@ -300,8 +300,6 @@ public:
int warn_if_overflow(int op_result); int warn_if_overflow(int op_result);
/* maximum possible display length */ /* maximum possible display length */
virtual uint32 max_length()= 0; virtual uint32 max_length()= 0;
/* length of field value symbolic representation (in bytes) */
virtual uint32 representation_length() { return field_length; }
/* convert decimal to longlong with overflow check */ /* convert decimal to longlong with overflow check */
longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag, longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag,
int *err); int *err);
@ -438,7 +436,13 @@ public:
/* New decimal/numeric field which use fixed point arithmetic */ /* New decimal/numeric field which use fixed point arithmetic */
class Field_new_decimal :public Field_num { class Field_new_decimal :public Field_num {
public: public:
/* The maximum number of decimal digits can be stored */
uint precision;
uint bin_size; uint bin_size;
/* Constructors take max_length of the field as a parameter - not the */
/* precision as the number of decimal digits allowed */
/* So for example we need to count length from precision handling */
/* CREATE TABLE ( DECIMAL(x,y)) */
Field_new_decimal(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, Field_new_decimal(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg, enum utype unireg_check_arg, const char *field_name_arg,
@ -446,7 +450,8 @@ public:
uint8 dec_arg, bool zero_arg, bool unsigned_arg); uint8 dec_arg, bool zero_arg, bool unsigned_arg);
Field_new_decimal(uint32 len_arg, bool maybe_null_arg, Field_new_decimal(uint32 len_arg, bool maybe_null_arg,
const char *field_name_arg, const char *field_name_arg,
struct st_table *table_arg, uint8 dec_arg); struct st_table *table_arg, uint8 dec_arg,
bool unsigned_arg);
enum_field_types type() const { return FIELD_TYPE_NEWDECIMAL;} enum_field_types type() const { return FIELD_TYPE_NEWDECIMAL;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
Item_result result_type () const { return DECIMAL_RESULT; } Item_result result_type () const { return DECIMAL_RESULT; }
@ -465,10 +470,7 @@ public:
void sort_string(char *buff, uint length); void sort_string(char *buff, uint length);
bool zero_pack() const { return 0; } bool zero_pack() const { return 0; }
void sql_type(String &str) const; void sql_type(String &str) const;
uint32 max_length() uint32 max_length() { return field_length; }
{ return field_length + 1 + (dec ? 1 : 0) + (field_length == dec ? 1 : 0); }
uint32 representation_length()
{ return field_length + 1 + (dec ? 1 : 0) + (field_length == dec ? 1 : 0); };
uint size_of() const { return sizeof(*this); } uint size_of() const { return sizeof(*this); }
uint32 pack_length() const { return (uint32) bin_size; } uint32 pack_length() const { return (uint32) bin_size; }
}; };

View File

@ -3621,7 +3621,7 @@ static int create_ndb_column(NDBCOL &col,
case MYSQL_TYPE_NEWDECIMAL: case MYSQL_TYPE_NEWDECIMAL:
{ {
Field_new_decimal *f= (Field_new_decimal*)field; Field_new_decimal *f= (Field_new_decimal*)field;
uint precision= f->field_length; uint precision= f->precision;
uint scale= f->decimals(); uint scale= f->decimals();
if (field->flags & UNSIGNED_FLAG) if (field->flags & UNSIGNED_FLAG)
{ {

View File

@ -80,7 +80,7 @@ Hybrid_type_traits_decimal::fix_length_and_dec(Item *item, Item *arg) const
{ {
item->decimals= arg->decimals; item->decimals= arg->decimals;
item->max_length= min(arg->max_length + DECIMAL_LONGLONG_DIGITS, item->max_length= min(arg->max_length + DECIMAL_LONGLONG_DIGITS,
DECIMAL_MAX_LENGTH); DECIMAL_MAX_STR_LENGTH);
} }
@ -348,6 +348,17 @@ Item::Item(THD *thd, Item *item):
} }
uint Item::decimal_precision() const
{
Item_result restype= result_type();
if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT))
return min(my_decimal_length_to_precision(max_length, decimals, unsigned_flag),
DECIMAL_MAX_PRECISION);
return min(max_length, DECIMAL_MAX_PRECISION);
}
void Item::print_item_w_name(String *str) void Item::print_item_w_name(String *str)
{ {
print(str); print(str);
@ -943,10 +954,8 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
return 1; return 1;
} }
if (collation->state & MY_CS_BINSORT) if (collation->state & MY_CS_BINSORT)
{
return 0; return 0;
} if (dt.collation->state & MY_CS_BINSORT)
else if (dt.collation->state & MY_CS_BINSORT)
{ {
set(dt); set(dt);
return 0; return 0;
@ -1026,7 +1035,7 @@ void Item_field::set_field(Field *field_par)
field=result_field=field_par; // for easy coding with fields field=result_field=field_par; // for easy coding with fields
maybe_null=field->maybe_null(); maybe_null=field->maybe_null();
decimals= field->decimals(); decimals= field->decimals();
max_length= field_par->representation_length(); max_length= field_par->field_length;
table_name= *field_par->table_name; table_name= *field_par->table_name;
field_name= field_par->field_name; field_name= field_par->field_name;
db_name= field_par->table->s->db; db_name= field_par->table->s->db;
@ -1371,18 +1380,18 @@ Item_decimal::Item_decimal(const char *str_arg, uint length,
str2my_decimal(E_DEC_FATAL_ERROR, str_arg, length, charset, &decimal_value); str2my_decimal(E_DEC_FATAL_ERROR, str_arg, length, charset, &decimal_value);
name= (char*) str_arg; name= (char*) str_arg;
decimals= (uint8) decimal_value.frac; decimals= (uint8) decimal_value.frac;
max_length= my_decimal_max_length(&decimal_value);
fixed= 1; fixed= 1;
unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
decimals, unsigned_flag);
} }
Item_decimal::Item_decimal(longlong val, bool unsig) Item_decimal::Item_decimal(longlong val, bool unsig)
{ {
int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value); int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value);
decimals= (uint8) decimal_value.frac; decimals= (uint8) decimal_value.frac;
max_length= my_decimal_max_length(&decimal_value);
fixed= 1; fixed= 1;
unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
decimals, unsigned_flag);
} }
@ -1390,9 +1399,9 @@ Item_decimal::Item_decimal(double val, int precision, int scale)
{ {
double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value); double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value);
decimals= (uint8) decimal_value.frac; decimals= (uint8) decimal_value.frac;
max_length= my_decimal_max_length(&decimal_value);
fixed= 1; fixed= 1;
unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
decimals, unsigned_flag);
} }
@ -1404,7 +1413,6 @@ Item_decimal::Item_decimal(const char *str, const my_decimal *val_arg,
decimals= (uint8) decimal_par; decimals= (uint8) decimal_par;
max_length= length; max_length= length;
fixed= 1; fixed= 1;
unsigned_flag= !decimal_value.sign();
} }
@ -1412,19 +1420,20 @@ Item_decimal::Item_decimal(my_decimal *value_par)
{ {
my_decimal2decimal(value_par, &decimal_value); my_decimal2decimal(value_par, &decimal_value);
decimals= (uint8) decimal_value.frac; decimals= (uint8) decimal_value.frac;
max_length= my_decimal_max_length(value_par);
fixed= 1; fixed= 1;
unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
decimals, !decimal_value.sign());
} }
Item_decimal::Item_decimal(const char *bin, int precision, int scale) Item_decimal::Item_decimal(const char *bin, int precision, int scale)
{ {
binary2my_decimal(E_DEC_FATAL_ERROR, bin, &decimal_value, precision, scale); binary2my_decimal(E_DEC_FATAL_ERROR, bin,
&decimal_value, precision, scale);
decimals= (uint8) decimal_value.frac; decimals= (uint8) decimal_value.frac;
max_length= my_decimal_max_length(&decimal_value);
fixed= 1; fixed= 1;
unsigned_flag= !decimal_value.sign(); max_length= my_decimal_precision_to_length(precision, decimals,
!decimal_value.sign());
} }
@ -1702,7 +1711,8 @@ void Item_param::set_decimal(const char *str, ulong length)
str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value, &end); str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value, &end);
state= DECIMAL_VALUE; state= DECIMAL_VALUE;
decimals= decimal_value.frac; decimals= decimal_value.frac;
max_length= decimal_value.intg + decimals + 2; max_length= my_decimal_precision_to_length(decimal_value.precision(),
decimals, unsigned_flag);
maybe_null= 0; maybe_null= 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@ -1853,7 +1863,8 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
my_decimal2decimal(ent_value, &decimal_value); my_decimal2decimal(ent_value, &decimal_value);
state= DECIMAL_VALUE; state= DECIMAL_VALUE;
decimals= ent_value->frac; decimals= ent_value->frac;
max_length= ent_value->intg + decimals + 2; max_length= my_decimal_precision_to_length(ent_value->precision(),
decimals, unsigned_flag);
break; break;
} }
default: default:
@ -3271,11 +3282,8 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
switch (field_type()) { switch (field_type()) {
case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_DECIMAL:
return new Field_decimal((char*) 0, max_length, null_ptr, 0, Field::NONE,
name, table, decimals, 0, unsigned_flag);
case MYSQL_TYPE_NEWDECIMAL: case MYSQL_TYPE_NEWDECIMAL:
return new Field_new_decimal((char*) 0, max_length - (decimals?1:0), return new Field_new_decimal((char*) 0, max_length, null_ptr, 0,
null_ptr, 0,
Field::NONE, name, table, decimals, 0, Field::NONE, name, table, decimals, 0,
unsigned_flag); unsigned_flag);
case MYSQL_TYPE_TINY: case MYSQL_TYPE_TINY:
@ -5031,6 +5039,7 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item)
/* fix variable decimals which always is NOT_FIXED_DEC */ /* fix variable decimals which always is NOT_FIXED_DEC */
if (Field::result_merge_type(fld_type) == INT_RESULT) if (Field::result_merge_type(fld_type) == INT_RESULT)
decimals= 0; decimals= 0;
prev_decimal_int_part= item->decimal_int_part();
} }
@ -5153,18 +5162,12 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
} }
if (Field::result_merge_type(fld_type) == DECIMAL_RESULT) if (Field::result_merge_type(fld_type) == DECIMAL_RESULT)
{ {
int item_length= display_length(item); decimals= min(max(decimals, item->decimals), DECIMAL_MAX_SCALE);
int intp1= item_length - min(item->decimals, NOT_FIXED_DEC - 1); int precision= min(max(prev_decimal_int_part, item->decimal_int_part())
int intp2= max_length - min(decimals, NOT_FIXED_DEC - 1); + decimals, DECIMAL_MAX_PRECISION);
/* can't be overflow because it work only for decimals (no strings) */ unsigned_flag&= item->unsigned_flag;
int dec_length= max(intp1, intp2) + decimals; max_length= my_decimal_precision_to_length(precision, decimals,
max_length= max(max_length, (uint) max(item_length, dec_length)); unsigned_flag);
/*
we can't allow decimals to be NOT_FIXED_DEC, to prevent creation
decimal with max precision (see Field_new_decimal constcuctor)
*/
if (decimals >= NOT_FIXED_DEC)
decimals= NOT_FIXED_DEC - 1;
} }
else else
max_length= max(max_length, display_length(item)); max_length= max(max_length, display_length(item));
@ -5185,6 +5188,9 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
} }
maybe_null|= item->maybe_null; maybe_null|= item->maybe_null;
get_full_info(item); get_full_info(item);
/* Remember decimal integer part to be used in DECIMAL_RESULT handleng */
prev_decimal_int_part= decimal_int_part();
DBUG_PRINT("info", ("become type: %d len: %u dec: %u", DBUG_PRINT("info", ("become type: %d len: %u dec: %u",
(int) fld_type, max_length, (uint) decimals)); (int) fld_type, max_length, (uint) decimals));
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);

View File

@ -258,7 +258,7 @@ public:
Item *next; Item *next;
uint32 max_length; uint32 max_length;
uint name_length; /* Length of name */ uint name_length; /* Length of name */
uint8 marker,decimals; uint8 marker, decimals;
my_bool maybe_null; /* If item may be null */ my_bool maybe_null; /* If item may be null */
my_bool null_value; /* if item is null */ my_bool null_value; /* if item is null */
my_bool unsigned_flag; my_bool unsigned_flag;
@ -442,6 +442,9 @@ public:
virtual cond_result eq_cmp_result() const { return COND_OK; } virtual cond_result eq_cmp_result() const { return COND_OK; }
inline uint float_length(uint decimals_par) const inline uint float_length(uint decimals_par) const
{ return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} { return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;}
virtual uint decimal_precision() const;
inline int decimal_int_part() const
{ return my_decimal_int_part(decimal_precision(), decimals); }
/* /*
Returns true if this is constant (during query execution, i.e. its value Returns true if this is constant (during query execution, i.e. its value
will not change until next fix_fields) and its value is known. will not change until next fix_fields) and its value is known.
@ -953,7 +956,7 @@ public:
{ max_length=length; fixed= 1; } { max_length=length; fixed= 1; }
#ifdef HAVE_LONG_LONG #ifdef HAVE_LONG_LONG
Item_int(longlong i,uint length=21) :value(i) Item_int(longlong i,uint length=21) :value(i)
{ max_length=length; fixed= 1;} { max_length=length; fixed= 1; }
#endif #endif
Item_int(const char *str_arg,longlong i,uint length) :value(i) Item_int(const char *str_arg,longlong i,uint length) :value(i)
{ max_length=length; name=(char*) str_arg; fixed= 1; } { max_length=length; name=(char*) str_arg; fixed= 1; }
@ -972,6 +975,7 @@ public:
void cleanup() {} void cleanup() {}
void print(String *str); void print(String *str);
Item_num *neg() { value= -value; return this; } Item_num *neg() { value= -value; return this; }
uint decimal_precision() const { return (uint)(max_length - test(value < 0)); }
bool eq(const Item *, bool binary_cmp) const; bool eq(const Item *, bool binary_cmp) const;
}; };
@ -1001,6 +1005,7 @@ public:
int save_in_field(Field *field, bool no_conversions); int save_in_field(Field *field, bool no_conversions);
void print(String *str); void print(String *str);
Item_num *neg (); Item_num *neg ();
uint decimal_precision() const { return max_length; }
}; };
@ -1040,6 +1045,7 @@ public:
unsigned_flag= !decimal_value.sign(); unsigned_flag= !decimal_value.sign();
return this; return this;
} }
uint decimal_precision() const { return decimal_value.precision(); }
bool eq(const Item *, bool binary_cmp) const; bool eq(const Item *, bool binary_cmp) const;
}; };
@ -1802,6 +1808,9 @@ protected:
enum_field_types fld_type; enum_field_types fld_type;
void get_full_info(Item *item); void get_full_info(Item *item);
/* It is used to count decimal precision in join_types */
int prev_decimal_int_part;
public: public:
Item_type_holder(THD*, Item*); Item_type_holder(THD*, Item*);

View File

@ -1134,6 +1134,14 @@ Item_func_ifnull::fix_length_and_dec()
cached_field_type= Item_func::field_type(); cached_field_type= Item_func::field_type();
} }
uint Item_func_ifnull::decimal_precision() const
{
int max_int_part=max(args[0]->decimal_int_part(),args[1]->decimal_int_part());
return min(max_int_part + decimals, DECIMAL_MAX_PRECISION);
}
enum_field_types Item_func_ifnull::field_type() const enum_field_types Item_func_ifnull::field_type() const
{ {
return cached_field_type; return cached_field_type;
@ -1251,6 +1259,14 @@ Item_func_if::fix_length_and_dec()
} }
uint Item_func_if::decimal_precision() const
{
int precision=(max(args[1]->decimal_int_part(),args[2]->decimal_int_part())+
decimals);
return min(precision, DECIMAL_MAX_PRECISION);
}
double double
Item_func_if::val_real() Item_func_if::val_real()
{ {
@ -1304,7 +1320,8 @@ Item_func_nullif::fix_length_and_dec()
{ {
max_length=args[0]->max_length; max_length=args[0]->max_length;
decimals=args[0]->decimals; decimals=args[0]->decimals;
agg_result_type(&cached_result_type, args, 2); unsigned_flag= args[0]->unsigned_flag;
cached_result_type= args[0]->result_type();
if (cached_result_type == STRING_RESULT && if (cached_result_type == STRING_RESULT &&
agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV)) agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV))
return; return;
@ -1616,6 +1633,18 @@ void Item_func_case::fix_length_and_dec()
} }
uint Item_func_case::decimal_precision() const
{
int max_int_part=0;
for (uint i=0 ; i < ncases ; i+=2)
set_if_bigger(max_int_part, args[i+1]->decimal_int_part());
if (else_expr_num != -1)
set_if_bigger(max_int_part, args[else_expr_num]->decimal_int_part());
return min(max_int_part + decimals, DECIMAL_MAX_PRECISION);
}
/* TODO: Fix this so that it prints the whole CASE expression */ /* TODO: Fix this so that it prints the whole CASE expression */
void Item_func_case::print(String *str) void Item_func_case::print(String *str)

View File

@ -95,6 +95,7 @@ public:
Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {} Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {}
bool is_bool_func() { return 1; } bool is_bool_func() { return 1; }
void fix_length_and_dec() { decimals=0; max_length=1; } void fix_length_and_dec() { decimals=0; max_length=1; }
uint decimal_precision() const { return 1; }
}; };
class Item_cache; class Item_cache;
@ -208,6 +209,7 @@ public:
bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); } bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); }
bool is_bool_func() { return 1; } bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; } CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; }
uint decimal_precision() const { return 1; }
friend class Arg_comparator; friend class Arg_comparator;
}; };
@ -411,6 +413,7 @@ public:
void fix_length_and_dec(); void fix_length_and_dec();
void print(String *str); void print(String *str);
CHARSET_INFO *compare_collation() { return cmp_collation.collation; } CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
uint decimal_precision() const { return 1; }
}; };
@ -445,6 +448,7 @@ public:
longlong val_int(); longlong val_int();
void fix_length_and_dec(); void fix_length_and_dec();
const char *func_name() const { return "interval"; } const char *func_name() const { return "interval"; }
uint decimal_precision() const { return 2; }
}; };
@ -485,6 +489,7 @@ public:
void fix_length_and_dec(); void fix_length_and_dec();
const char *func_name() const { return "ifnull"; } const char *func_name() const { return "ifnull"; }
Field *tmp_table_field(TABLE *table); Field *tmp_table_field(TABLE *table);
uint decimal_precision() const;
}; };
@ -507,6 +512,7 @@ public:
return Item_func::fix_fields(thd, tlist, ref); return Item_func::fix_fields(thd, tlist, ref);
} }
void fix_length_and_dec(); void fix_length_and_dec();
uint decimal_precision() const;
const char *func_name() const { return "if"; } const char *func_name() const { return "if"; }
table_map not_null_tables() const { return 0; } table_map not_null_tables() const { return 0; }
}; };
@ -525,6 +531,7 @@ public:
my_decimal *val_decimal(my_decimal *); my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return cached_result_type; } enum Item_result result_type () const { return cached_result_type; }
void fix_length_and_dec(); void fix_length_and_dec();
uint decimal_precision() const { return args[0]->decimal_precision(); }
const char *func_name() const { return "nullif"; } const char *func_name() const { return "nullif"; }
void print(String *str) { Item_func::print(str); } void print(String *str) { Item_func::print(str); }
table_map not_null_tables() const { return 0; } table_map not_null_tables() const { return 0; }
@ -563,6 +570,7 @@ public:
String *val_str(String *); String *val_str(String *);
my_decimal *val_decimal(my_decimal *); my_decimal *val_decimal(my_decimal *);
void fix_length_and_dec(); void fix_length_and_dec();
uint decimal_precision() const;
table_map not_null_tables() const { return 0; } table_map not_null_tables() const { return 0; }
enum Item_result result_type () const { return cached_result_type; } enum Item_result result_type () const { return cached_result_type; }
const char *func_name() const { return "case"; } const char *func_name() const { return "case"; }
@ -825,6 +833,7 @@ class Item_func_in :public Item_int_func
} }
longlong val_int(); longlong val_int();
void fix_length_and_dec(); void fix_length_and_dec();
uint decimal_precision() const { return 1; }
void cleanup() void cleanup()
{ {
DBUG_ENTER("Item_func_in::cleanup"); DBUG_ENTER("Item_func_in::cleanup");

View File

@ -534,8 +534,10 @@ Field *Item_func::tmp_table_field(TABLE *t_arg)
res= make_string_field(t_arg); res= make_string_field(t_arg);
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
res= new Field_new_decimal(max_length + (decimals?1:0), maybe_null, res= new Field_new_decimal(my_decimal_precision_to_length(decimal_precision(),
name, t_arg, decimals); decimals,
unsigned_flag),
maybe_null, name, t_arg, decimals, unsigned_flag);
break; break;
case ROW_RESULT: case ROW_RESULT:
default: default:
@ -590,19 +592,18 @@ void Item_func_numhybrid::fix_num_length_and_dec()
void Item_func::count_decimal_length() void Item_func::count_decimal_length()
{ {
uint32 length= 0; int max_int_part= 0;
decimals= 0; decimals= 0;
unsigned_flag= 1;
for (uint i=0 ; i < arg_count ; i++) for (uint i=0 ; i < arg_count ; i++)
{ {
set_if_bigger(decimals, args[i]->decimals); set_if_bigger(decimals, args[i]->decimals);
set_if_bigger(length, (args[i]->max_length - args[i]->decimals)); set_if_bigger(max_int_part, args[i]->decimal_int_part());
set_if_smaller(unsigned_flag, args[i]->unsigned_flag);
} }
max_length= length; int precision= min(max_int_part + decimals, DECIMAL_MAX_PRECISION);
length+= decimals; max_length= my_decimal_precision_to_length(precision, decimals,
if (length < max_length) // If previous operation gave overflow unsigned_flag);
max_length= UINT_MAX32;
else
max_length= length;
} }
@ -616,8 +617,12 @@ void Item_func::count_decimal_length()
void Item_func::count_only_length() void Item_func::count_only_length()
{ {
max_length= 0; max_length= 0;
unsigned_flag= 0;
for (uint i=0 ; i < arg_count ; i++) for (uint i=0 ; i < arg_count ; i++)
{
set_if_bigger(max_length, args[i]->max_length); set_if_bigger(max_length, args[i]->max_length);
set_if_bigger(unsigned_flag, args[i]->unsigned_flag);
}
} }
@ -719,7 +724,6 @@ void Item_num_op::find_num_type(void)
{ {
decimals= 0; decimals= 0;
hybrid_type=INT_RESULT; hybrid_type=INT_RESULT;
unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag;
result_precision(); result_precision();
} }
DBUG_PRINT("info", ("Type: %s", DBUG_PRINT("info", ("Type: %s",
@ -1075,9 +1079,17 @@ my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value)
void Item_func_additive_op::result_precision() void Item_func_additive_op::result_precision()
{ {
decimals= max(args[0]->decimals, args[1]->decimals); decimals= max(args[0]->decimals, args[1]->decimals);
max_length= (max(args[0]->max_length - args[0]->decimals, int max_int_part= max(args[0]->decimal_precision() - args[0]->decimals,
args[1]->max_length - args[1]->decimals) + args[1]->decimal_precision() - args[1]->decimals);
decimals + 1); int precision= min(max_int_part + 1 + decimals, DECIMAL_MAX_PRECISION);
/* Integer operations keep unsigned_flag if one of arguments is unsigned */
if (result_type() == INT_RESULT)
unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag;
else
unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
max_length= my_decimal_precision_to_length(precision, decimals,
unsigned_flag);
} }
@ -1172,10 +1184,15 @@ my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value)
void Item_func_mul::result_precision() void Item_func_mul::result_precision()
{ {
decimals= args[0]->decimals + args[1]->decimals; /* Integer operations keep unsigned_flag if one of arguments is unsigned */
max_length= ((args[0]->max_length - args[0]->decimals) + if (result_type() == INT_RESULT)
(args[1]->max_length - args[1]->decimals) + unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag;
decimals); else
unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
decimals= min(args[0]->decimals + args[1]->decimals, DECIMAL_MAX_SCALE);
int precision= min(args[0]->decimal_precision() + args[1]->decimal_precision(),
DECIMAL_MAX_PRECISION);
max_length= my_decimal_precision_to_length(precision, decimals,unsigned_flag);
} }
@ -1207,7 +1224,7 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
if ((null_value= args[1]->null_value)) if ((null_value= args[1]->null_value))
return 0; return 0;
switch (my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value, switch (my_decimal_div(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value,
val1, val2, DECIMAL_DIV_SCALE_INCREASE)) { val1, val2, prec_increment)) {
case E_DEC_TRUNCATED: case E_DEC_TRUNCATED:
case E_DEC_OK: case E_DEC_OK:
return decimal_value; return decimal_value;
@ -1222,11 +1239,16 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
void Item_func_div::result_precision() void Item_func_div::result_precision()
{ {
decimals= (args[0]->decimals + args[0]->decimals + uint precision=min(args[0]->decimal_precision() + prec_increment,
DECIMAL_DIV_SCALE_INCREASE); DECIMAL_MAX_PRECISION);
max_length= ((args[0]->max_length - args[0]->decimals) + /* Integer operations keep unsigned_flag if one of arguments is unsigned */
(args[1]->max_length - args[1]->decimals) + if (result_type() == INT_RESULT)
decimals); unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag;
else
unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
max_length= my_decimal_precision_to_length(precision, decimals,
unsigned_flag);
} }
@ -1234,10 +1256,11 @@ void Item_func_div::fix_length_and_dec()
{ {
DBUG_ENTER("Item_func_div::fix_length_and_dec"); DBUG_ENTER("Item_func_div::fix_length_and_dec");
Item_num_op::fix_length_and_dec(); Item_num_op::fix_length_and_dec();
prec_increment= current_thd->variables.div_precincrement;
switch(hybrid_type) { switch(hybrid_type) {
case REAL_RESULT: case REAL_RESULT:
{ {
decimals=max(args[0]->decimals,args[1]->decimals)+2; decimals=max(args[0]->decimals,args[1]->decimals)+prec_increment;
set_if_smaller(decimals, NOT_FIXED_DEC); set_if_smaller(decimals, NOT_FIXED_DEC);
max_length=args[0]->max_length - args[0]->decimals + decimals; max_length=args[0]->max_length - args[0]->decimals + decimals;
uint tmp=float_length(decimals); uint tmp=float_length(decimals);
@ -1383,7 +1406,6 @@ void Item_func_neg::fix_num_length_and_dec()
decimals= args[0]->decimals; decimals= args[0]->decimals;
/* 1 add because sign can appear */ /* 1 add because sign can appear */
max_length= args[0]->max_length + 1; max_length= args[0]->max_length + 1;
unsigned_flag= 0;
} }
@ -1409,6 +1431,7 @@ void Item_func_neg::fix_length_and_dec()
hybrid_type= DECIMAL_RESULT; hybrid_type= DECIMAL_RESULT;
DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT")); DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT"));
} }
unsigned_flag= 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@ -1793,17 +1816,65 @@ my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value)
} }
void Item_func_round::fix_num_length_and_dec() void Item_func_round::fix_length_and_dec()
{ {
max_length= args[0]->max_length; unsigned_flag= args[0]->unsigned_flag;
decimals= NOT_FIXED_DEC; if (!args[1]->const_item())
if (args[1]->const_item())
{ {
int tmp=(int) args[1]->val_int(); max_length= args[0]->max_length;
if (tmp < 0) decimals= args[0]->decimals;
decimals=0; hybrid_type= REAL_RESULT;
return;
}
int decimals_to_set= max(args[1]->val_int(), 0);
if (args[0]->decimals == NOT_FIXED_DEC)
{
max_length= args[0]->max_length;
decimals= min(decimals_to_set, NOT_FIXED_DEC);
hybrid_type= REAL_RESULT;
return;
}
switch (args[0]->result_type())
{
case REAL_RESULT:
case STRING_RESULT:
hybrid_type= REAL_RESULT;
decimals= min(decimals_to_set, NOT_FIXED_DEC);
max_length= float_length(decimals);
break;
case INT_RESULT:
if (truncate || (args[0]->decimal_precision() < DECIMAL_LONGLONG_DIGITS))
{
/* Here we can keep INT_RESULT */
hybrid_type= INT_RESULT;
int length_can_increase= !truncate && (args[1]->val_int() < 0);
max_length= args[0]->max_length + length_can_increase;
decimals= 0;
break;
}
case DECIMAL_RESULT:
{
hybrid_type= DECIMAL_RESULT;
int decimals_delta= args[0]->decimals - decimals_to_set;
int precision= args[0]->decimal_precision();
if (decimals_delta > 0)
{
int length_increase= truncate ? 0:1;
precision-= decimals_delta - length_increase;
decimals= decimals_to_set;
}
else else
decimals=min(tmp, NOT_FIXED_DEC); /* Decimals to set is bigger that the original scale */
/* we keep original decimals value */
decimals= args[0]->decimals;
max_length= my_decimal_precision_to_length(precision, decimals,
unsigned_flag);
break;
}
default:
DBUG_ASSERT(0); /* This result type isn't handled */
} }
} }
@ -1881,7 +1952,9 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value)
my_decimal val, *value= args[0]->val_decimal(&val); my_decimal val, *value= args[0]->val_decimal(&val);
int dec=(int) args[1]->val_int(); int dec=(int) args[1]->val_int();
if (dec > 0) if (dec > 0)
decimals= dec; // to get correct output {
decimals= min(dec, DECIMAL_MAX_SCALE); // to get correct output
}
if ((null_value= (args[0]->null_value || args[1]->null_value || if ((null_value= (args[0]->null_value || args[1]->null_value ||
my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate, my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate,
decimal_value) > 1))) decimal_value) > 1)))
@ -1973,6 +2046,7 @@ double Item_func_units::val_real()
void Item_func_min_max::fix_length_and_dec() void Item_func_min_max::fix_length_and_dec()
{ {
int max_int_part=0;
decimals=0; decimals=0;
max_length=0; max_length=0;
maybe_null=1; maybe_null=1;
@ -1982,12 +2056,16 @@ void Item_func_min_max::fix_length_and_dec()
{ {
set_if_bigger(max_length, args[i]->max_length); set_if_bigger(max_length, args[i]->max_length);
set_if_bigger(decimals, args[i]->decimals); set_if_bigger(decimals, args[i]->decimals);
set_if_bigger(max_int_part, args[i]->decimal_int_part());
if (!args[i]->maybe_null) if (!args[i]->maybe_null)
maybe_null=0; maybe_null=0;
cmp_type=item_cmp_type(cmp_type,args[i]->result_type()); cmp_type=item_cmp_type(cmp_type,args[i]->result_type());
} }
if (cmp_type == STRING_RESULT) if (cmp_type == STRING_RESULT)
agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV); agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV);
else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT))
max_length= my_decimal_precision_to_length(max_int_part+decimals, decimals,
unsigned_flag);
} }
@ -3914,15 +3992,17 @@ void Item_func_get_user_var::fix_length_and_dec()
switch (var_entry->type) { switch (var_entry->type) {
case REAL_RESULT: case REAL_RESULT:
max_length= DBL_DIG + 8; max_length= DBL_DIG + 8;
break;
case INT_RESULT: case INT_RESULT:
max_length= MAX_BIGINT_WIDTH; max_length= MAX_BIGINT_WIDTH;
decimals=0;
break; break;
case STRING_RESULT: case STRING_RESULT:
max_length= MAX_BLOB_WIDTH; max_length= MAX_BLOB_WIDTH;
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
max_length= DECIMAL_MAX_LENGTH; max_length= DECIMAL_MAX_STR_LENGTH;
decimals= min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1); decimals= DECIMAL_MAX_SCALE;
break; break;
case ROW_RESULT: // Keep compiler happy case ROW_RESULT: // Keep compiler happy
default: default:
@ -4773,7 +4853,7 @@ Item_func_sp::fix_length_and_dec()
if (result_field) if (result_field)
{ {
decimals= result_field->decimals(); decimals= result_field->decimals();
max_length= result_field->representation_length(); max_length= result_field->field_length;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
@ -4785,29 +4865,12 @@ Item_func_sp::fix_length_and_dec()
} }
else else
{ {
if (!field) field= sp_result_field();
field= sp_result_field();
decimals= field->decimals(); decimals= field->decimals();
max_length= field->representation_length(); max_length= field->field_length;
maybe_null= 1;
switch (field->result_type()) {
case STRING_RESULT:
maybe_null= 1;
case REAL_RESULT:
case INT_RESULT:
case DECIMAL_RESULT:
break;
case ROW_RESULT:
default:
// This case should never be chosen
DBUG_ASSERT(0);
break;
}
if (field != result_field)
delete field;
} }
delete field;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }

View File

@ -267,6 +267,8 @@ public:
void fix_length_and_dec() void fix_length_and_dec()
{ max_length=args[0]->max_length; unsigned_flag=0; } { max_length=args[0]->max_length; unsigned_flag=0; }
void print(String *str); void print(String *str);
uint decimal_precision() const { return args[0]->decimal_precision(); }
}; };
@ -296,7 +298,7 @@ public:
longlong val_int(); longlong val_int();
my_decimal *val_decimal(my_decimal*); my_decimal *val_decimal(my_decimal*);
enum Item_result result_type () const { return DECIMAL_RESULT; } enum Item_result result_type () const { return DECIMAL_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_DECIMAL; } enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
void fix_length_and_dec() {}; void fix_length_and_dec() {};
}; };
@ -346,6 +348,7 @@ public:
class Item_func_div :public Item_num_op class Item_func_div :public Item_num_op
{ {
public: public:
uint prec_increment;
Item_func_div(Item *a,Item *b) :Item_num_op(a,b) {} Item_func_div(Item *a,Item *b) :Item_num_op(a,b) {}
longlong int_op() { DBUG_ASSERT(0); return 0; } longlong int_op() { DBUG_ASSERT(0); return 0; }
double real_op(); double real_op();
@ -390,6 +393,7 @@ public:
const char *func_name() const { return "-"; } const char *func_name() const { return "-"; }
void fix_length_and_dec(); void fix_length_and_dec();
void fix_num_length_and_dec(); void fix_num_length_and_dec();
uint decimal_precision() const { return args[0]->decimal_precision(); }
}; };
@ -593,7 +597,7 @@ public:
double real_op(); double real_op();
longlong int_op(); longlong int_op();
my_decimal *decimal_op(my_decimal *); my_decimal *decimal_op(my_decimal *);
void fix_num_length_and_dec(); void fix_length_and_dec();
}; };

View File

@ -156,8 +156,8 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table,
collation.collation); collation.collation);
return make_string_field(table); return make_string_field(table);
case DECIMAL_RESULT: case DECIMAL_RESULT:
return new Field_new_decimal(max_length - (decimals?1:0), return new Field_new_decimal(max_length, maybe_null, name, table,
maybe_null, name, table, decimals); decimals, unsigned_flag);
case ROW_RESULT: case ROW_RESULT:
default: default:
// This case should never be choosen // This case should never be choosen
@ -372,13 +372,16 @@ void Item_sum_sum::fix_length_and_dec()
break; break;
case INT_RESULT: case INT_RESULT:
case DECIMAL_RESULT: case DECIMAL_RESULT:
{
/* SUM result can't be longer than length(arg) + length(MAX_ROWS) */ /* SUM result can't be longer than length(arg) + length(MAX_ROWS) */
max_length= min(args[0]->max_length + DECIMAL_LONGLONG_DIGITS, int precision= args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS;
DECIMAL_MAX_LENGTH); max_length= my_decimal_precision_to_length(precision, decimals,
unsigned_flag);
curr_dec_buff= 0; curr_dec_buff= 0;
hybrid_type= DECIMAL_RESULT; hybrid_type= DECIMAL_RESULT;
my_decimal_set_zero(dec_buffs); my_decimal_set_zero(dec_buffs);
break; break;
}
case ROW_RESULT: case ROW_RESULT:
default: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);
@ -725,11 +728,12 @@ void
Item_sum_avg_distinct::fix_length_and_dec() Item_sum_avg_distinct::fix_length_and_dec()
{ {
Item_sum_distinct::fix_length_and_dec(); Item_sum_distinct::fix_length_and_dec();
prec_increment= current_thd->variables.div_precincrement;
/* /*
AVG() will divide val by count. We need to reserve digits AVG() will divide val by count. We need to reserve digits
after decimal point as the result can be fractional. after decimal point as the result can be fractional.
*/ */
decimals= min(decimals + 4, NOT_FIXED_DEC); decimals= min(decimals + prec_increment, NOT_FIXED_DEC);
} }
@ -790,14 +794,19 @@ void Item_sum_avg::fix_length_and_dec()
{ {
Item_sum_sum::fix_length_and_dec(); Item_sum_sum::fix_length_and_dec();
maybe_null=null_value=1; maybe_null=null_value=1;
decimals= min(args[0]->decimals + 4, NOT_FIXED_DEC); prec_increment= current_thd->variables.div_precincrement;
if (hybrid_type == DECIMAL_RESULT) if (hybrid_type == DECIMAL_RESULT)
{ {
f_scale= args[0]->decimals; int precision= args[0]->decimal_precision() + prec_increment;
max_length= DECIMAL_MAX_LENGTH + (f_scale ? 1 : 0); decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
f_precision= DECIMAL_MAX_LENGTH; max_length= my_decimal_precision_to_length(precision, decimals,
unsigned_flag);
f_precision= min(precision+DECIMAL_LONGLONG_DIGITS, DECIMAL_MAX_PRECISION);
f_scale= args[0]->decimals;
dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale); dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale);
} }
else
decimals= min(args[0]->decimals + prec_increment, NOT_FIXED_DEC);
} }
@ -822,8 +831,8 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table,
0, name, table, &my_charset_bin); 0, name, table, &my_charset_bin);
} }
if (hybrid_type == DECIMAL_RESULT) if (hybrid_type == DECIMAL_RESULT)
return new Field_new_decimal(f_precision, return new Field_new_decimal(max_length, maybe_null, name, table,
maybe_null, name, table, f_scale); decimals, unsigned_flag);
return new Field_double(max_length, maybe_null, name, table, decimals); return new Field_double(max_length, maybe_null, name, table, decimals);
} }
@ -868,7 +877,7 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
} }
sum_dec= Item_sum_sum::val_decimal(&sum); sum_dec= Item_sum_sum::val_decimal(&sum);
int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt); int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt);
my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, 4); my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, prec_increment);
return val; return val;
} }
@ -905,7 +914,8 @@ Item *Item_sum_std::copy_or_same(THD* thd)
Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item): Item_sum_variance::Item_sum_variance(THD *thd, Item_sum_variance *item):
Item_sum_num(thd, item), hybrid_type(item->hybrid_type), Item_sum_num(thd, item), hybrid_type(item->hybrid_type),
cur_dec(item->cur_dec), count(item->count), sample(item->sample) cur_dec(item->cur_dec), count(item->count), sample(item->sample),
prec_increment(item->prec_increment)
{ {
if (hybrid_type == DECIMAL_RESULT) if (hybrid_type == DECIMAL_RESULT)
{ {
@ -929,20 +939,21 @@ void Item_sum_variance::fix_length_and_dec()
{ {
DBUG_ENTER("Item_sum_variance::fix_length_and_dec"); DBUG_ENTER("Item_sum_variance::fix_length_and_dec");
maybe_null= null_value= 1; maybe_null= null_value= 1;
decimals= min(args[0]->decimals + 4, NOT_FIXED_DEC); prec_increment= current_thd->variables.div_precincrement;
switch (args[0]->result_type()) { switch (args[0]->result_type()) {
case REAL_RESULT: case REAL_RESULT:
case STRING_RESULT: case STRING_RESULT:
decimals= min(args[0]->decimals + 4, NOT_FIXED_DEC);
hybrid_type= REAL_RESULT; hybrid_type= REAL_RESULT;
sum= 0.0; sum= 0.0;
break; break;
case INT_RESULT: case INT_RESULT:
case DECIMAL_RESULT: case DECIMAL_RESULT:
/* {
SUM result can't be longer than length(arg)*2 + int precision= args[0]->decimal_precision()*2 + prec_increment;
digits_after_the_point_to_add decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
*/ max_length= my_decimal_precision_to_length(precision, decimals,
max_length= args[0]->max_length*2 + 4; unsigned_flag);
cur_dec= 0; cur_dec= 0;
hybrid_type= DECIMAL_RESULT; hybrid_type= DECIMAL_RESULT;
my_decimal_set_zero(dec_sum); my_decimal_set_zero(dec_sum);
@ -954,12 +965,15 @@ void Item_sum_variance::fix_length_and_dec()
column_value * column_value column_value * column_value
*/ */
f_scale0= args[0]->decimals; f_scale0= args[0]->decimals;
f_precision0= DECIMAL_MAX_LENGTH / 2; f_precision0= min(args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS,
f_scale1= min(f_scale0 * 2, NOT_FIXED_DEC - 1); DECIMAL_MAX_PRECISION);
f_precision1= DECIMAL_MAX_LENGTH; f_scale1= min(args[0]->decimals * 2, DECIMAL_MAX_SCALE);
f_precision1= min(args[0]->decimal_precision()*2 + DECIMAL_LONGLONG_DIGITS,
DECIMAL_MAX_PRECISION);
dec_bin_size0= my_decimal_get_binary_size(f_precision0, f_scale0); dec_bin_size0= my_decimal_get_binary_size(f_precision0, f_scale0);
dec_bin_size1= my_decimal_get_binary_size(f_precision1, f_scale1); dec_bin_size1= my_decimal_get_binary_size(f_precision1, f_scale1);
break; break;
}
case ROW_RESULT: case ROW_RESULT:
default: default:
DBUG_ASSERT(0); DBUG_ASSERT(0);
@ -997,8 +1011,8 @@ Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
0, name, table, &my_charset_bin); 0, name, table, &my_charset_bin);
} }
if (hybrid_type == DECIMAL_RESULT) if (hybrid_type == DECIMAL_RESULT)
return new Field_new_decimal(DECIMAL_MAX_LENGTH, return new Field_new_decimal(max_length, maybe_null, name, table,
maybe_null, name, table, f_scale1 + 4); decimals, unsigned_flag);
return new Field_double(max_length, maybe_null,name,table,decimals); return new Field_double(max_length, maybe_null,name,table,decimals);
} }
@ -1083,9 +1097,11 @@ my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf)
int2my_decimal(E_DEC_FATAL_ERROR, count-sample, 0, &count1_buf); int2my_decimal(E_DEC_FATAL_ERROR, count-sample, 0, &count1_buf);
my_decimal_mul(E_DEC_FATAL_ERROR, &sum_sqr_buf, my_decimal_mul(E_DEC_FATAL_ERROR, &sum_sqr_buf,
dec_sum+cur_dec, dec_sum+cur_dec); dec_sum+cur_dec, dec_sum+cur_dec);
my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &sum_sqr_buf, &count_buf, 2); my_decimal_div(E_DEC_FATAL_ERROR, dec_buf,
&sum_sqr_buf, &count_buf, prec_increment);
my_decimal_sub(E_DEC_FATAL_ERROR, &sum_sqr_buf, dec_sqr+cur_dec, dec_buf); my_decimal_sub(E_DEC_FATAL_ERROR, &sum_sqr_buf, dec_sqr+cur_dec, dec_buf);
my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &sum_sqr_buf, &count1_buf, 2); my_decimal_div(E_DEC_FATAL_ERROR, dec_buf,
&sum_sqr_buf, &count1_buf, prec_increment);
return dec_buf; return dec_buf;
} }
@ -1929,10 +1945,12 @@ Item_avg_field::Item_avg_field(Item_result res_type, Item_sum_avg *item)
{ {
name=item->name; name=item->name;
decimals=item->decimals; decimals=item->decimals;
max_length=item->max_length; max_length= item->max_length;
unsigned_flag= item->unsigned_flag;
field=item->result_field; field=item->result_field;
maybe_null=1; maybe_null=1;
hybrid_type= res_type; hybrid_type= res_type;
prec_increment= item->prec_increment;
if (hybrid_type == DECIMAL_RESULT) if (hybrid_type == DECIMAL_RESULT)
{ {
f_scale= item->f_scale; f_scale= item->f_scale;
@ -1941,7 +1959,6 @@ Item_avg_field::Item_avg_field(Item_result res_type, Item_sum_avg *item)
} }
} }
double Item_avg_field::val_real() double Item_avg_field::val_real()
{ {
// fix_fields() never calls for this Item // fix_fields() never calls for this Item
@ -1982,7 +1999,8 @@ my_decimal *Item_avg_field::val_decimal(my_decimal *dec_buf)
binary2my_decimal(E_DEC_FATAL_ERROR, binary2my_decimal(E_DEC_FATAL_ERROR,
field->ptr, &dec_field, f_precision, f_scale); field->ptr, &dec_field, f_precision, f_scale);
int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count); int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count);
my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &dec_field, &dec_count, 4); my_decimal_div(E_DEC_FATAL_ERROR, dec_buf,
&dec_field, &dec_count, prec_increment);
return dec_buf; return dec_buf;
} }
@ -2054,9 +2072,11 @@ Item_variance_field::Item_variance_field(Item_sum_variance *item)
name=item->name; name=item->name;
decimals=item->decimals; decimals=item->decimals;
max_length=item->max_length; max_length=item->max_length;
unsigned_flag= item->unsigned_flag;
field=item->result_field; field=item->result_field;
maybe_null=1; maybe_null=1;
sample= item->sample; sample= item->sample;
prec_increment= item->prec_increment;
if ((hybrid_type= item->hybrid_type) == DECIMAL_RESULT) if ((hybrid_type= item->hybrid_type) == DECIMAL_RESULT)
{ {
f_scale0= item->f_scale0; f_scale0= item->f_scale0;
@ -2116,9 +2136,10 @@ my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf)
binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr+dec_bin_size0, binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr+dec_bin_size0,
&dec_sqr, f_precision1, f_scale1); &dec_sqr, f_precision1, f_scale1);
my_decimal_mul(E_DEC_FATAL_ERROR, &tmp, &dec_sum, &dec_sum); my_decimal_mul(E_DEC_FATAL_ERROR, &tmp, &dec_sum, &dec_sum);
my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &tmp, &dec_count, 2); my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &tmp, &dec_count, prec_increment);
my_decimal_sub(E_DEC_FATAL_ERROR, &dec_sum, &dec_sqr, dec_buf); my_decimal_sub(E_DEC_FATAL_ERROR, &dec_sum, &dec_sqr, dec_buf);
my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &dec_sum, &dec1_count, 2); my_decimal_div(E_DEC_FATAL_ERROR, dec_buf,
&dec_sum, &dec1_count, prec_increment);
return dec_buf; return dec_buf;
} }

View File

@ -237,6 +237,7 @@ private:
Item_sum_avg_distinct(THD *thd, Item_sum_avg_distinct *original) Item_sum_avg_distinct(THD *thd, Item_sum_avg_distinct *original)
:Item_sum_distinct(thd, original) {} :Item_sum_distinct(thd, original) {}
public: public:
uint prec_increment;
Item_sum_avg_distinct(Item *item_arg) : Item_sum_distinct(item_arg) {} Item_sum_avg_distinct(Item *item_arg) : Item_sum_distinct(item_arg) {}
void fix_length_and_dec(); void fix_length_and_dec();
@ -343,8 +344,8 @@ class Item_avg_field :public Item_result_field
public: public:
Field *field; Field *field;
Item_result hybrid_type; Item_result hybrid_type;
uint f_precision, f_scale; uint f_precision, f_scale, dec_bin_size;
uint dec_bin_size; uint prec_increment;
Item_avg_field(Item_result res_type, Item_sum_avg *item); Item_avg_field(Item_result res_type, Item_sum_avg *item);
enum Type type() const { return FIELD_AVG_ITEM; } enum Type type() const { return FIELD_AVG_ITEM; }
double val_real(); double val_real();
@ -366,12 +367,14 @@ class Item_sum_avg :public Item_sum_sum
{ {
public: public:
ulonglong count; ulonglong count;
uint f_precision, f_scale; uint prec_increment;
uint dec_bin_size; uint f_precision, f_scale, dec_bin_size;
Item_sum_avg(Item *item_par) :Item_sum_sum(item_par), count(0) {} Item_sum_avg(Item *item_par) :Item_sum_sum(item_par), count(0) {}
Item_sum_avg(THD *thd, Item_sum_avg *item) Item_sum_avg(THD *thd, Item_sum_avg *item)
:Item_sum_sum(thd, item), count(item->count) {} :Item_sum_sum(thd, item), count(item->count),
prec_increment(item->prec_increment) {}
void fix_length_and_dec(); void fix_length_and_dec();
enum Sumfunctype sum_func () const {return AVG_FUNC;} enum Sumfunctype sum_func () const {return AVG_FUNC;}
void clear(); void clear();
@ -402,6 +405,7 @@ public:
uint f_precision1, f_scale1; uint f_precision1, f_scale1;
uint dec_bin_size0, dec_bin_size1; uint dec_bin_size0, dec_bin_size1;
uint sample; uint sample;
uint prec_increment;
Item_variance_field(Item_sum_variance *item); Item_variance_field(Item_sum_variance *item);
enum Type type() const {return FIELD_VARIANCE_ITEM; } enum Type type() const {return FIELD_VARIANCE_ITEM; }
double val_real(); double val_real();
@ -446,6 +450,7 @@ public:
uint f_precision1, f_scale1; uint f_precision1, f_scale1;
uint dec_bin_size0, dec_bin_size1; uint dec_bin_size0, dec_bin_size1;
uint sample; uint sample;
uint prec_increment;
Item_sum_variance(Item *item_par, uint sample_arg) :Item_sum_num(item_par), Item_sum_variance(Item *item_par, uint sample_arg) :Item_sum_num(item_par),
hybrid_type(REAL_RESULT), cur_dec(0), count(0), sample(sample_arg) hybrid_type(REAL_RESULT), cur_dec(0), count(0), sample(sample_arg)

View File

@ -81,7 +81,7 @@ int decimal_operation_results(int result)
*/ */
int my_decimal2string(uint mask, const my_decimal *d, int my_decimal2string(uint mask, const my_decimal *d,
int fixed_prec, int fixed_dec, uint fixed_prec, uint fixed_dec,
char filler, String *str) char filler, String *str)
{ {
int length= (fixed_prec ? (fixed_prec + 1) : my_decimal_string_length(d)); int length= (fixed_prec ? (fixed_prec + 1) : my_decimal_string_length(d));
@ -89,7 +89,7 @@ int my_decimal2string(uint mask, const my_decimal *d,
if (str->alloc(length)) if (str->alloc(length))
return check_result(mask, E_DEC_OOM); return check_result(mask, E_DEC_OOM);
result= decimal2string((decimal_t*) d, (char*) str->ptr(), result= decimal2string((decimal_t*) d, (char*) str->ptr(),
&length, fixed_prec, fixed_dec, &length, (int)fixed_prec, fixed_dec,
filler); filler);
str->length(length); str->length(length);
return check_result(mask, result); return check_result(mask, result);
@ -123,7 +123,7 @@ int my_decimal2binary(uint mask, const my_decimal *d, char *bin, int prec,
int err1= E_DEC_OK, err2; int err1= E_DEC_OK, err2;
my_decimal rounded; my_decimal rounded;
my_decimal2decimal(d, &rounded); my_decimal2decimal(d, &rounded);
decimal_optimize_fraction(&rounded); rounded.frac= decimal_actual_fraction(&rounded);
if (scale < rounded.frac) if (scale < rounded.frac)
{ {
err1= E_DEC_TRUNCATED; err1= E_DEC_TRUNCATED;
@ -220,18 +220,16 @@ print_decimal_buff(const my_decimal *dec, const byte* ptr, int length)
} }
void dbug_print_decimal(const char *tag, const char *format, my_decimal *val) const char *dbug_decimal_as_string(char *buff, const my_decimal *val)
{ {
char buff[DECIMAL_MAX_STR_LENGTH]; int length= DECIMAL_MAX_STR_LENGTH;
String str(buff, sizeof(buff), &my_charset_bin);
if (!val) if (!val)
str.set("NULL", 4, &my_charset_bin); return "NULL";
else (void)decimal2string((decimal_t*) val, buff, &length, 0,0,0);
my_decimal2string(0, val, 0, 0, 0, &str); return buff;
DBUG_PRINT(tag, (format, (char*) str.ptr()));
} }
#endif #endif /*DBUG_OFF*/
#endif /*MYSQL_CLIENT*/ #endif /*MYSQL_CLIENT*/

View File

@ -35,27 +35,27 @@ C_MODE_END
#define DECIMAL_LONG_DIGITS 10 #define DECIMAL_LONG_DIGITS 10
#define DECIMAL_LONG3_DIGITS 8 #define DECIMAL_LONG3_DIGITS 8
/* number of digits on which we increase scale of devision result */
#define DECIMAL_DIV_SCALE_INCREASE 5
/* maximum length of buffer in our big digits (uint32) */ /* maximum length of buffer in our big digits (uint32) */
#define DECIMAL_BUFF_LENGTH 8 #define DECIMAL_BUFF_LENGTH 9
/* /*
maximum guaranteed length of number in decimal digits (number of our maximum guaranteed precision of number in decimal digits (number of our
digits * number of decimal digits in one our big digit - number of decimal digits * number of decimal digits in one our big digit - number of decimal
digits in one our big digit decreased on 1 (because we always put decimal digits in one our big digit decreased on 1 (because we always put decimal
point on the border of our big digits)) point on the border of our big digits))
*/ */
#define DECIMAL_MAX_LENGTH ((8 * 9) - 8) #define DECIMAL_MAX_PRECISION ((DECIMAL_BUFF_LENGTH * 9) - 8*2)
#define DECIMAL_MAX_SCALE 30
#define DECIMAL_NOT_SPECIFIED 31
/* /*
maximum length of string representation (number of maximum decimal maximum length of string representation (number of maximum decimal
digits + 1 position for sign + 1 position for decimal point) digits + 1 position for sign + 1 position for decimal point)
*/ */
#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_LENGTH + 2) #define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_PRECISION + 2)
/* /*
maximum size of packet length maximum size of packet length
*/ */
#define DECIMAL_MAX_FIELD_SIZE DECIMAL_MAX_LENGTH #define DECIMAL_MAX_FIELD_SIZE DECIMAL_MAX_PRECISION
inline uint my_decimal_size(uint precision, uint scale) inline uint my_decimal_size(uint precision, uint scale)
@ -68,6 +68,12 @@ inline uint my_decimal_size(uint precision, uint scale)
} }
inline int my_decimal_int_part(uint precision, uint decimals)
{
return precision - ((decimals == DECIMAL_NOT_SPECIFIED) ? 0 : decimals);
}
/* /*
my_decimal class limits 'decimal_t' type to what we need in MySQL my_decimal class limits 'decimal_t' type to what we need in MySQL
It contains internally all necessary space needed by the instance so It contains internally all necessary space needed by the instance so
@ -99,15 +105,16 @@ public:
bool sign() const { return decimal_t::sign; } bool sign() const { return decimal_t::sign; }
void sign(bool s) { decimal_t::sign= s; } void sign(bool s) { decimal_t::sign= s; }
uint precision() const { return intg + frac; }
}; };
#ifndef DBUG_OFF #ifndef DBUG_OFF
void print_decimal(const my_decimal *dec); void print_decimal(const my_decimal *dec);
void print_decimal_buff(const my_decimal *dec, const byte* ptr, int length); void print_decimal_buff(const my_decimal *dec, const byte* ptr, int length);
void dbug_print_decimal(const char *tag, const char *format, my_decimal *val); const char *dbug_decimal_as_string(char *buff, const my_decimal *val);
#else #else
#define dbug_print_decimal(A,B,C) #define dbug_decimal_as_string(A) NULL
#endif #endif
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
@ -126,6 +133,18 @@ inline int check_result(uint mask, int result)
return result; return result;
} }
inline uint my_decimal_length_to_precision(uint length, uint scale,
bool unsigned_flag)
{
return (uint) (length - (scale>0 ? 1:0) - (unsigned_flag ? 0:1));
}
inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
bool unsigned_flag)
{
set_if_smaller(precision, DECIMAL_MAX_PRECISION);
return (uint32)(precision + (scale>0 ? 1:0) + (unsigned_flag ? 0:1));
}
inline inline
int my_decimal_string_length(const my_decimal *d) int my_decimal_string_length(const my_decimal *d)
@ -209,8 +228,8 @@ int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to)
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
int my_decimal2string(uint mask, const my_decimal *d, int fixed_prec, int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec,
int fixed_dec, char filler, String *str); uint fixed_dec, char filler, String *str);
#endif #endif
inline inline
@ -326,7 +345,8 @@ int my_decimal_cmp(const my_decimal *a, const my_decimal *b)
inline inline
void max_my_decimal(my_decimal *to, int precision, int frac) void max_my_decimal(my_decimal *to, int precision, int frac)
{ {
DBUG_ASSERT(precision <= DECIMAL_MAX_LENGTH); DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION)&&
(frac <= DECIMAL_MAX_SCALE));
max_decimal(precision, frac, (decimal_t*) to); max_decimal(precision, frac, (decimal_t*) to);
} }

View File

@ -4219,7 +4219,8 @@ enum options_mysqld
OPT_PRELOAD_BUFFER_SIZE, OPT_PRELOAD_BUFFER_SIZE,
OPT_QUERY_CACHE_LIMIT, OPT_QUERY_CACHE_MIN_RES_UNIT, OPT_QUERY_CACHE_SIZE, OPT_QUERY_CACHE_LIMIT, OPT_QUERY_CACHE_MIN_RES_UNIT, OPT_QUERY_CACHE_SIZE,
OPT_QUERY_CACHE_TYPE, OPT_QUERY_CACHE_WLOCK_INVALIDATE, OPT_RECORD_BUFFER, OPT_QUERY_CACHE_TYPE, OPT_QUERY_CACHE_WLOCK_INVALIDATE, OPT_RECORD_BUFFER,
OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT, OPT_RELAY_LOG_PURGE, OPT_RECORD_RND_BUFFER, OPT_DIV_PRECINCREMENT, OPT_RELAY_LOG_SPACE_LIMIT,
OPT_RELAY_LOG_PURGE,
OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME, OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME,
OPT_SLAVE_TRANS_RETRIES, OPT_READONLY, OPT_DEBUGGING, OPT_SLAVE_TRANS_RETRIES, OPT_READONLY, OPT_DEBUGGING,
OPT_SORT_BUFFER, OPT_TABLE_CACHE, OPT_SORT_BUFFER, OPT_TABLE_CACHE,
@ -5451,6 +5452,11 @@ The minimum value for this variable is 4096.",
(gptr*) &max_system_variables.read_rnd_buff_size, 0, (gptr*) &max_system_variables.read_rnd_buff_size, 0,
GET_ULONG, REQUIRED_ARG, 256*1024L, IO_SIZE*2+MALLOC_OVERHEAD, GET_ULONG, REQUIRED_ARG, 256*1024L, IO_SIZE*2+MALLOC_OVERHEAD,
~0L, MALLOC_OVERHEAD, IO_SIZE, 0}, ~0L, MALLOC_OVERHEAD, IO_SIZE, 0},
{"div_precision_increment", OPT_DIV_PRECINCREMENT,
"Precision of the result of '/' operator will be increased on that value.",
(gptr*) &global_system_variables.div_precincrement,
(gptr*) &max_system_variables.div_precincrement, 0, GET_ULONG,
REQUIRED_ARG, 4, 0, DECIMAL_MAX_SCALE, 0, 0, 0},
{"record_buffer", OPT_RECORD_BUFFER, {"record_buffer", OPT_RECORD_BUFFER,
"Alias for read_buffer_size", "Alias for read_buffer_size",
(gptr*) &global_system_variables.read_buff_size, (gptr*) &global_system_variables.read_buff_size,

View File

@ -298,6 +298,8 @@ sys_var_thd_ulong sys_read_buff_size("read_buffer_size",
sys_var_bool_ptr sys_readonly("read_only", &opt_readonly); sys_var_bool_ptr sys_readonly("read_only", &opt_readonly);
sys_var_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size", sys_var_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size",
&SV::read_rnd_buff_size); &SV::read_rnd_buff_size);
sys_var_thd_ulong sys_div_precincrement("div_precision_increment",
&SV::div_precincrement);
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
sys_var_bool_ptr sys_relay_log_purge("relay_log_purge", sys_var_bool_ptr sys_relay_log_purge("relay_log_purge",
&relay_log_purge); &relay_log_purge);
@ -570,6 +572,7 @@ sys_var *sys_variables[]=
&sys_connect_timeout, &sys_connect_timeout,
&sys_date_format, &sys_date_format,
&sys_datetime_format, &sys_datetime_format,
&sys_div_precincrement,
&sys_default_week_format, &sys_default_week_format,
&sys_delay_key_write, &sys_delay_key_write,
&sys_delayed_insert_limit, &sys_delayed_insert_limit,
@ -758,6 +761,7 @@ struct show_var_st init_vars[]= {
{"datadir", mysql_real_data_home, SHOW_CHAR}, {"datadir", mysql_real_data_home, SHOW_CHAR},
{sys_date_format.name, (char*) &sys_date_format, SHOW_SYS}, {sys_date_format.name, (char*) &sys_date_format, SHOW_SYS},
{sys_datetime_format.name, (char*) &sys_datetime_format, SHOW_SYS}, {sys_datetime_format.name, (char*) &sys_datetime_format, SHOW_SYS},
{sys_div_precincrement.name,(char*) &sys_div_precincrement,SHOW_SYS},
{sys_default_week_format.name, (char*) &sys_default_week_format, SHOW_SYS}, {sys_default_week_format.name, (char*) &sys_default_week_format, SHOW_SYS},
{sys_delay_key_write.name, (char*) &sys_delay_key_write, SHOW_SYS}, {sys_delay_key_write.name, (char*) &sys_delay_key_write, SHOW_SYS},
{sys_delayed_insert_limit.name, (char*) &sys_delayed_insert_limit,SHOW_SYS}, {sys_delayed_insert_limit.name, (char*) &sys_delayed_insert_limit,SHOW_SYS},

View File

@ -164,7 +164,10 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
it= new Item_null(); it= new Item_null();
else else
it= new Item_decimal(val); it= new Item_decimal(val);
dbug_print_decimal("info", "DECIMAL_RESULT: %s", val); #ifndef DBUG_OFF
char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
DBUG_PRINT("info", ("DECIMAL_RESULT: %s", dbug_decimal_as_string(dbug_buff, val)));
#endif
break; break;
} }
case STRING_RESULT: case STRING_RESULT:

View File

@ -523,6 +523,7 @@ struct system_variables
ulong query_cache_type; ulong query_cache_type;
ulong read_buff_size; ulong read_buff_size;
ulong read_rnd_buff_size; ulong read_rnd_buff_size;
ulong div_precincrement;
ulong sortbuff_size; ulong sortbuff_size;
ulong table_type; ulong table_type;
ulong tmp_table_size; ulong tmp_table_size;

View File

@ -5471,9 +5471,14 @@ new_create_field(THD *thd, char *field_name, enum_field_types type,
} }
new_field->pack_length= new_field->pack_length=
my_decimal_get_binary_size(new_field->length, new_field->decimals); my_decimal_get_binary_size(new_field->length, new_field->decimals);
if (new_field->length <= DECIMAL_MAX_LENGTH && if (new_field->length <= DECIMAL_MAX_PRECISION &&
new_field->length >= new_field->decimals) new_field->length >= new_field->decimals)
{
new_field->length=
my_decimal_precision_to_length(new_field->length, new_field->decimals,
type_modifier & UNSIGNED_FLAG);
break; break;
}
my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name); my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
DBUG_RETURN(NULL); DBUG_RETURN(NULL);
case MYSQL_TYPE_VARCHAR: case MYSQL_TYPE_VARCHAR:

View File

@ -7781,9 +7781,8 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
new_field= item->make_string_field(table); new_field= item->make_string_field(table);
break; break;
case DECIMAL_RESULT: case DECIMAL_RESULT:
new_field= new Field_new_decimal(item->max_length - (item->decimals?1:0), new_field= new Field_new_decimal(item->max_length, maybe_null, item->name,
maybe_null, table, item->decimals, item->unsigned_flag);
item->name, table, item->decimals);
break; break;
case ROW_RESULT: case ROW_RESULT:
default: default:

View File

@ -2362,10 +2362,10 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
strlen((const char*) pos), cs); strlen((const char*) pos), cs);
if (field->has_charset()) if (field->has_charset())
{ {
table->field[8]->store((longlong) field->representation_length()/ table->field[8]->store((longlong) field->field_length/
field->charset()->mbmaxlen); field->charset()->mbmaxlen);
table->field[8]->set_notnull(); table->field[8]->set_notnull();
table->field[9]->store((longlong) field->representation_length()); table->field[9]->store((longlong) field->field_length);
table->field[9]->set_notnull(); table->field[9]->set_notnull();
} }
@ -2373,7 +2373,8 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
uint dec =field->decimals(); uint dec =field->decimals();
switch (field->type()) { switch (field->type()) {
case FIELD_TYPE_NEWDECIMAL: case FIELD_TYPE_NEWDECIMAL:
table->field[10]->store((longlong) field->field_length); table->field[10]->store((longlong)
((Field_new_decimal*)field)->precision);
table->field[10]->set_notnull(); table->field[10]->set_notnull();
table->field[11]->store((longlong) field->decimals()); table->field[11]->store((longlong) field->decimals());
table->field[11]->set_notnull(); table->field[11]->set_notnull();

View File

@ -274,20 +274,20 @@ static dec1 *remove_leading_zeroes(decimal_t *from, int *intg_result)
/* /*
Remove ending 0 digits from fraction part Count actual length of fraction part (without ending zeroes)
SYNOPSIS SYNOPSIS
decimal_optimize_fraction() decimal_actual_fraction()
from number for processing from number for processing
*/ */
void decimal_optimize_fraction(decimal_t *from) int decimal_actual_fraction(decimal_t *from)
{ {
int frac= from->frac, i; int frac= from->frac, i;
dec1 *buf0= from->buf + ROUND_UP(from->intg) + ROUND_UP(frac) - 1; dec1 *buf0= from->buf + ROUND_UP(from->intg) + ROUND_UP(frac) - 1;
if (frac == 0) if (frac == 0)
return; return 0;
i= ((frac - 1) % DIG_PER_DEC1 + 1); i= ((frac - 1) % DIG_PER_DEC1 + 1);
while (frac > 0 && *buf0 == 0) while (frac > 0 && *buf0 == 0)
@ -302,7 +302,7 @@ void decimal_optimize_fraction(decimal_t *from)
*buf0 % powers10[i++] == 0; *buf0 % powers10[i++] == 0;
frac--); frac--);
} }
from->frac= frac; return frac;
} }
@ -332,23 +332,15 @@ int decimal2string(decimal_t *from, char *to, int *to_len,
int fixed_precision, int fixed_decimals, int fixed_precision, int fixed_decimals,
char filler) char filler)
{ {
int len, intg, frac=from->frac, i, intg_len, frac_len, fill; int len, intg, frac= from->frac, i, intg_len, frac_len, fill;
/* number digits before decimal point */ /* number digits before decimal point */
int fixed_intg= (fixed_precision ? int fixed_intg= (fixed_precision ?
(fixed_precision - (fixed_precision - fixed_decimals) : 0);
(from->sign ? 1 : 0) -
(fixed_decimals ? 1 : 0) -
fixed_decimals) :
0);
int error=E_DEC_OK; int error=E_DEC_OK;
char *s=to; char *s=to;
dec1 *buf, *buf0=from->buf, tmp; dec1 *buf, *buf0=from->buf, tmp;
DBUG_ASSERT(*to_len >= 2+from->sign); DBUG_ASSERT(*to_len >= 2+from->sign);
DBUG_ASSERT(fixed_precision == 0 ||
(fixed_precision < *to_len &&
fixed_precision > ((from->sign ? 1 : 0) +
(fixed_decimals ? 1 : 0))));
/* removing leading zeroes */ /* removing leading zeroes */
buf0= remove_leading_zeroes(from, &intg); buf0= remove_leading_zeroes(from, &intg);
@ -2609,7 +2601,7 @@ void test_fr(const char *s1, const char *orig)
printf("%-40s => ", s); printf("%-40s => ", s);
end= strend(s1); end= strend(s1);
string2decimal(s1, &a, &end); string2decimal(s1, &a, &end);
decimal_optimize_fraction(&a); a.frac= decimal_actual_fraction(&a);
print_decimal(&a, orig, 0, 0); print_decimal(&a, orig, 0, 0);
printf("\n"); printf("\n");
} }
@ -2947,7 +2939,7 @@ int main()
test_sh("123456789.987654321", 0, "123456789.987654321", 0); test_sh("123456789.987654321", 0, "123456789.987654321", 0);
a.len= sizeof(buf1)/sizeof(dec1); a.len= sizeof(buf1)/sizeof(dec1);
printf("==== decimal_optimize_fraction ====\n"); printf("==== decimal_actual_fraction ====\n");
test_fr("1.123456789000000000", "1.123456789"); test_fr("1.123456789000000000", "1.123456789");
test_fr("1.12345678000000000", "1.12345678"); test_fr("1.12345678000000000", "1.12345678");
test_fr("1.1234567000000000", "1.1234567"); test_fr("1.1234567000000000", "1.1234567");