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.mysql.r18.ru
hf@genie.(none)
holyfoot@mysql.com
igor@hundin.mysql.fi
igor@linux.local
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 decimal2double(decimal_t *from, double *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 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
****************************************************************************/
/*
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,
uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
@ -2243,17 +2237,15 @@ Field_new_decimal::Field_new_decimal(char *ptr_arg,
struct st_table *table_arg,
uint8 dec_arg,bool zero_arg,
bool unsigned_arg)
:Field_num(ptr_arg,
(dec_arg == NOT_FIXED_DEC || len_arg > DECIMAL_MAX_LENGTH ?
DECIMAL_MAX_LENGTH : len_arg),
:Field_num(ptr_arg, len_arg,
null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg,
(dec_arg == NOT_FIXED_DEC ?
min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1) :
dec_arg),
zero_arg, unsigned_arg)
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,
const char *name,
struct st_table *t_arg,
uint8 dec_arg)
:Field_num((char*) 0,
(dec_arg == NOT_FIXED_DEC|| len_arg > DECIMAL_MAX_LENGTH ?
DECIMAL_MAX_LENGTH : len_arg),
uint8 dec_arg,
bool unsigned_arg)
:Field_num((char*) 0, len_arg,
maybe_null ? (uchar*) "": 0, 0,
NONE, name, t_arg,
(dec_arg == NOT_FIXED_DEC ?
min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1) :
dec_arg),
0, 0)
dec_arg,
0, 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);
}
@ -2295,7 +2287,7 @@ void Field_new_decimal::set_value_on_overflow(my_decimal *decimal_value,
bool sign)
{
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 (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)
{
my_decimal *dec= (my_decimal*)decimal_value;
int error= 0;
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 */
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"));
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
error= 1;
dec= &decimal_zero;
decimal_value= &decimal_zero;
}
DBUG_PRINT("info", ("saving with precision %d, scale: %d",
(int)field_length, (int)decimals()));
dbug_print_decimal("info", "value: %s", dec);
#ifndef DBUG_OFF
{
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 &
~E_DEC_OVERFLOW,
dec, ptr,
field_length,
decimals())))
if (warn_if_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
decimal_value, ptr, precision, dec)))
{
my_decimal buff;
DBUG_PRINT("info", ("overflow"));
set_value_on_overflow(&buff, dec->sign());
my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, field_length, decimals());
set_value_on_overflow(&buff, decimal_value->sign());
my_decimal2binary(E_DEC_FATAL_ERROR, &buff, ptr, precision, dec);
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);
}
@ -2387,7 +2385,11 @@ int Field_new_decimal::store(const char *from, uint length,
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);
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");
binary2my_decimal(E_DEC_FATAL_ERROR, ptr, decimal_value,
field_length,
decimals());
precision, dec);
DBUG_EXECUTE("info", print_decimal_buff(decimal_value, (byte *) ptr,
bin_size););
DBUG_RETURN(decimal_value);
@ -2489,12 +2490,9 @@ String *Field_new_decimal::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
my_decimal decimal_value;
int fixed_precision= (zerofill ?
(field_length + (decimals() ? 1 : 0)) :
0);
uint fixed_precision= zerofill ? precision : 0;
my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
fixed_precision, decimals(), '0',
val_buffer);
fixed_precision, dec, '0', val_buffer);
return val_buffer;
}
@ -2516,7 +2514,7 @@ void Field_new_decimal::sql_type(String &str) const
{
CHARSET_INFO *cs= str.charset();
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);
}

View File

@ -300,8 +300,6 @@ public:
int warn_if_overflow(int op_result);
/* maximum possible display length */
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 */
longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag,
int *err);
@ -438,7 +436,13 @@ public:
/* New decimal/numeric field which use fixed point arithmetic */
class Field_new_decimal :public Field_num {
public:
/* The maximum number of decimal digits can be stored */
uint precision;
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,
uchar null_bit_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);
Field_new_decimal(uint32 len_arg, bool maybe_null_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 ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; }
Item_result result_type () const { return DECIMAL_RESULT; }
@ -465,10 +470,7 @@ public:
void sort_string(char *buff, uint length);
bool zero_pack() const { return 0; }
void sql_type(String &str) const;
uint32 max_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); };
uint32 max_length() { return field_length; }
uint size_of() const { return sizeof(*this); }
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:
{
Field_new_decimal *f= (Field_new_decimal*)field;
uint precision= f->field_length;
uint precision= f->precision;
uint scale= f->decimals();
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->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)
{
print(str);
@ -943,10 +954,8 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
return 1;
}
if (collation->state & MY_CS_BINSORT)
{
return 0;
}
else if (dt.collation->state & MY_CS_BINSORT)
if (dt.collation->state & MY_CS_BINSORT)
{
set(dt);
return 0;
@ -1026,7 +1035,7 @@ void Item_field::set_field(Field *field_par)
field=result_field=field_par; // for easy coding with fields
maybe_null=field->maybe_null();
decimals= field->decimals();
max_length= field_par->representation_length();
max_length= field_par->field_length;
table_name= *field_par->table_name;
field_name= field_par->field_name;
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);
name= (char*) str_arg;
decimals= (uint8) decimal_value.frac;
max_length= my_decimal_max_length(&decimal_value);
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)
{
int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value);
decimals= (uint8) decimal_value.frac;
max_length= my_decimal_max_length(&decimal_value);
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);
decimals= (uint8) decimal_value.frac;
max_length= my_decimal_max_length(&decimal_value);
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;
max_length= length;
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);
decimals= (uint8) decimal_value.frac;
max_length= my_decimal_max_length(value_par);
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)
{
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;
max_length= my_decimal_max_length(&decimal_value);
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);
state= DECIMAL_VALUE;
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;
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);
state= DECIMAL_VALUE;
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;
}
default:
@ -3271,11 +3282,8 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
switch (field_type()) {
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:
return new Field_new_decimal((char*) 0, max_length - (decimals?1:0),
null_ptr, 0,
return new Field_new_decimal((char*) 0, max_length, null_ptr, 0,
Field::NONE, name, table, decimals, 0,
unsigned_flag);
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 */
if (Field::result_merge_type(fld_type) == INT_RESULT)
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)
{
int item_length= display_length(item);
int intp1= item_length - min(item->decimals, NOT_FIXED_DEC - 1);
int intp2= max_length - min(decimals, NOT_FIXED_DEC - 1);
/* can't be overflow because it work only for decimals (no strings) */
int dec_length= max(intp1, intp2) + decimals;
max_length= max(max_length, (uint) max(item_length, dec_length));
/*
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;
decimals= min(max(decimals, item->decimals), DECIMAL_MAX_SCALE);
int precision= min(max(prev_decimal_int_part, item->decimal_int_part())
+ decimals, DECIMAL_MAX_PRECISION);
unsigned_flag&= item->unsigned_flag;
max_length= my_decimal_precision_to_length(precision, decimals,
unsigned_flag);
}
else
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;
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",
(int) fld_type, max_length, (uint) decimals));
DBUG_RETURN(FALSE);

View File

@ -258,7 +258,7 @@ public:
Item *next;
uint32 max_length;
uint name_length; /* Length of name */
uint8 marker,decimals;
uint8 marker, decimals;
my_bool maybe_null; /* If item may be null */
my_bool null_value; /* if item is null */
my_bool unsigned_flag;
@ -442,6 +442,9 @@ public:
virtual cond_result eq_cmp_result() const { return COND_OK; }
inline uint float_length(uint decimals_par) const
{ 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
will not change until next fix_fields) and its value is known.
@ -953,7 +956,7 @@ public:
{ max_length=length; fixed= 1; }
#ifdef HAVE_LONG_LONG
Item_int(longlong i,uint length=21) :value(i)
{ max_length=length; fixed= 1;}
{ max_length=length; fixed= 1; }
#endif
Item_int(const char *str_arg,longlong i,uint length) :value(i)
{ max_length=length; name=(char*) str_arg; fixed= 1; }
@ -972,6 +975,7 @@ public:
void cleanup() {}
void print(String *str);
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;
};
@ -1001,6 +1005,7 @@ public:
int save_in_field(Field *field, bool no_conversions);
void print(String *str);
Item_num *neg ();
uint decimal_precision() const { return max_length; }
};
@ -1040,6 +1045,7 @@ public:
unsigned_flag= !decimal_value.sign();
return this;
}
uint decimal_precision() const { return decimal_value.precision(); }
bool eq(const Item *, bool binary_cmp) const;
};
@ -1802,6 +1808,9 @@ protected:
enum_field_types fld_type;
void get_full_info(Item *item);
/* It is used to count decimal precision in join_types */
int prev_decimal_int_part;
public:
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();
}
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
{
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
Item_func_if::val_real()
{
@ -1304,7 +1320,8 @@ Item_func_nullif::fix_length_and_dec()
{
max_length=args[0]->max_length;
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 &&
agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV))
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 */
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) {}
bool is_bool_func() { return 1; }
void fix_length_and_dec() { decimals=0; max_length=1; }
uint decimal_precision() const { return 1; }
};
class Item_cache;
@ -208,6 +209,7 @@ public:
bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); }
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; }
uint decimal_precision() const { return 1; }
friend class Arg_comparator;
};
@ -411,6 +413,7 @@ public:
void fix_length_and_dec();
void print(String *str);
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
uint decimal_precision() const { return 1; }
};
@ -445,6 +448,7 @@ public:
longlong val_int();
void fix_length_and_dec();
const char *func_name() const { return "interval"; }
uint decimal_precision() const { return 2; }
};
@ -485,6 +489,7 @@ public:
void fix_length_and_dec();
const char *func_name() const { return "ifnull"; }
Field *tmp_table_field(TABLE *table);
uint decimal_precision() const;
};
@ -507,6 +512,7 @@ public:
return Item_func::fix_fields(thd, tlist, ref);
}
void fix_length_and_dec();
uint decimal_precision() const;
const char *func_name() const { return "if"; }
table_map not_null_tables() const { return 0; }
};
@ -525,6 +531,7 @@ public:
my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return cached_result_type; }
void fix_length_and_dec();
uint decimal_precision() const { return args[0]->decimal_precision(); }
const char *func_name() const { return "nullif"; }
void print(String *str) { Item_func::print(str); }
table_map not_null_tables() const { return 0; }
@ -563,6 +570,7 @@ public:
String *val_str(String *);
my_decimal *val_decimal(my_decimal *);
void fix_length_and_dec();
uint decimal_precision() const;
table_map not_null_tables() const { return 0; }
enum Item_result result_type () const { return cached_result_type; }
const char *func_name() const { return "case"; }
@ -825,6 +833,7 @@ class Item_func_in :public Item_int_func
}
longlong val_int();
void fix_length_and_dec();
uint decimal_precision() const { return 1; }
void 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);
break;
case DECIMAL_RESULT:
res= new Field_new_decimal(max_length + (decimals?1:0), maybe_null,
name, t_arg, decimals);
res= new Field_new_decimal(my_decimal_precision_to_length(decimal_precision(),
decimals,
unsigned_flag),
maybe_null, name, t_arg, decimals, unsigned_flag);
break;
case ROW_RESULT:
default:
@ -590,19 +592,18 @@ void Item_func_numhybrid::fix_num_length_and_dec()
void Item_func::count_decimal_length()
{
uint32 length= 0;
int max_int_part= 0;
decimals= 0;
unsigned_flag= 1;
for (uint i=0 ; i < arg_count ; i++)
{
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;
length+= decimals;
if (length < max_length) // If previous operation gave overflow
max_length= UINT_MAX32;
else
max_length= length;
int precision= min(max_int_part + decimals, DECIMAL_MAX_PRECISION);
max_length= my_decimal_precision_to_length(precision, decimals,
unsigned_flag);
}
@ -616,8 +617,12 @@ void Item_func::count_decimal_length()
void Item_func::count_only_length()
{
max_length= 0;
unsigned_flag= 0;
for (uint i=0 ; i < arg_count ; i++)
{
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;
hybrid_type=INT_RESULT;
unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag;
result_precision();
}
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()
{
decimals= max(args[0]->decimals, args[1]->decimals);
max_length= (max(args[0]->max_length - args[0]->decimals,
args[1]->max_length - args[1]->decimals) +
decimals + 1);
int max_int_part= max(args[0]->decimal_precision() - args[0]->decimals,
args[1]->decimal_precision() - args[1]->decimals);
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()
{
decimals= args[0]->decimals + args[1]->decimals;
max_length= ((args[0]->max_length - args[0]->decimals) +
(args[1]->max_length - args[1]->decimals) +
decimals);
/* 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;
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))
return 0;
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_OK:
return decimal_value;
@ -1222,11 +1239,16 @@ my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
void Item_func_div::result_precision()
{
decimals= (args[0]->decimals + args[0]->decimals +
DECIMAL_DIV_SCALE_INCREASE);
max_length= ((args[0]->max_length - args[0]->decimals) +
(args[1]->max_length - args[1]->decimals) +
decimals);
uint precision=min(args[0]->decimal_precision() + prec_increment,
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;
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");
Item_num_op::fix_length_and_dec();
prec_increment= current_thd->variables.div_precincrement;
switch(hybrid_type) {
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);
max_length=args[0]->max_length - args[0]->decimals + decimals;
uint tmp=float_length(decimals);
@ -1383,7 +1406,6 @@ void Item_func_neg::fix_num_length_and_dec()
decimals= args[0]->decimals;
/* 1 add because sign can appear */
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;
DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT"));
}
unsigned_flag= 0;
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;
decimals= NOT_FIXED_DEC;
if (args[1]->const_item())
unsigned_flag= args[0]->unsigned_flag;
if (!args[1]->const_item())
{
int tmp=(int) args[1]->val_int();
if (tmp < 0)
decimals=0;
max_length= args[0]->max_length;
decimals= args[0]->decimals;
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
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);
int dec=(int) args[1]->val_int();
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 ||
my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate,
decimal_value) > 1)))
@ -1973,6 +2046,7 @@ double Item_func_units::val_real()
void Item_func_min_max::fix_length_and_dec()
{
int max_int_part=0;
decimals=0;
max_length=0;
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(decimals, args[i]->decimals);
set_if_bigger(max_int_part, args[i]->decimal_int_part());
if (!args[i]->maybe_null)
maybe_null=0;
cmp_type=item_cmp_type(cmp_type,args[i]->result_type());
}
if (cmp_type == STRING_RESULT)
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) {
case REAL_RESULT:
max_length= DBL_DIG + 8;
break;
case INT_RESULT:
max_length= MAX_BIGINT_WIDTH;
decimals=0;
break;
case STRING_RESULT:
max_length= MAX_BLOB_WIDTH;
break;
case DECIMAL_RESULT:
max_length= DECIMAL_MAX_LENGTH;
decimals= min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1);
max_length= DECIMAL_MAX_STR_LENGTH;
decimals= DECIMAL_MAX_SCALE;
break;
case ROW_RESULT: // Keep compiler happy
default:
@ -4773,7 +4853,7 @@ Item_func_sp::fix_length_and_dec()
if (result_field)
{
decimals= result_field->decimals();
max_length= result_field->representation_length();
max_length= result_field->field_length;
DBUG_VOID_RETURN;
}
@ -4785,29 +4865,12 @@ Item_func_sp::fix_length_and_dec()
}
else
{
if (!field)
field= sp_result_field();
field= sp_result_field();
decimals= field->decimals();
max_length= field->representation_length();
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;
max_length= field->field_length;
maybe_null= 1;
}
delete field;
DBUG_VOID_RETURN;
}

View File

@ -267,6 +267,8 @@ public:
void fix_length_and_dec()
{ max_length=args[0]->max_length; unsigned_flag=0; }
void print(String *str);
uint decimal_precision() const { return args[0]->decimal_precision(); }
};
@ -296,7 +298,7 @@ public:
longlong val_int();
my_decimal *val_decimal(my_decimal*);
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() {};
};
@ -346,6 +348,7 @@ public:
class Item_func_div :public Item_num_op
{
public:
uint prec_increment;
Item_func_div(Item *a,Item *b) :Item_num_op(a,b) {}
longlong int_op() { DBUG_ASSERT(0); return 0; }
double real_op();
@ -390,6 +393,7 @@ public:
const char *func_name() const { return "-"; }
void fix_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();
longlong int_op();
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);
return make_string_field(table);
case DECIMAL_RESULT:
return new Field_new_decimal(max_length - (decimals?1:0),
maybe_null, name, table, decimals);
return new Field_new_decimal(max_length, maybe_null, name, table,
decimals, unsigned_flag);
case ROW_RESULT:
default:
// This case should never be choosen
@ -372,13 +372,16 @@ void Item_sum_sum::fix_length_and_dec()
break;
case INT_RESULT:
case DECIMAL_RESULT:
{
/* SUM result can't be longer than length(arg) + length(MAX_ROWS) */
max_length= min(args[0]->max_length + DECIMAL_LONGLONG_DIGITS,
DECIMAL_MAX_LENGTH);
int precision= args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS;
max_length= my_decimal_precision_to_length(precision, decimals,
unsigned_flag);
curr_dec_buff= 0;
hybrid_type= DECIMAL_RESULT;
my_decimal_set_zero(dec_buffs);
break;
}
case ROW_RESULT:
default:
DBUG_ASSERT(0);
@ -725,11 +728,12 @@ void
Item_sum_avg_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
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();
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)
{
f_scale= args[0]->decimals;
max_length= DECIMAL_MAX_LENGTH + (f_scale ? 1 : 0);
f_precision= DECIMAL_MAX_LENGTH;
int precision= args[0]->decimal_precision() + prec_increment;
decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
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);
}
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);
}
if (hybrid_type == DECIMAL_RESULT)
return new Field_new_decimal(f_precision,
maybe_null, name, table, f_scale);
return new Field_new_decimal(max_length, maybe_null, name, table,
decimals, unsigned_flag);
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);
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;
}
@ -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_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)
{
@ -929,20 +939,21 @@ void Item_sum_variance::fix_length_and_dec()
{
DBUG_ENTER("Item_sum_variance::fix_length_and_dec");
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()) {
case REAL_RESULT:
case STRING_RESULT:
decimals= min(args[0]->decimals + 4, NOT_FIXED_DEC);
hybrid_type= REAL_RESULT;
sum= 0.0;
break;
case INT_RESULT:
case DECIMAL_RESULT:
/*
SUM result can't be longer than length(arg)*2 +
digits_after_the_point_to_add
*/
max_length= args[0]->max_length*2 + 4;
{
int precision= args[0]->decimal_precision()*2 + prec_increment;
decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
max_length= my_decimal_precision_to_length(precision, decimals,
unsigned_flag);
cur_dec= 0;
hybrid_type= DECIMAL_RESULT;
my_decimal_set_zero(dec_sum);
@ -954,12 +965,15 @@ void Item_sum_variance::fix_length_and_dec()
column_value * column_value
*/
f_scale0= args[0]->decimals;
f_precision0= DECIMAL_MAX_LENGTH / 2;
f_scale1= min(f_scale0 * 2, NOT_FIXED_DEC - 1);
f_precision1= DECIMAL_MAX_LENGTH;
f_precision0= min(args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS,
DECIMAL_MAX_PRECISION);
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_size1= my_decimal_get_binary_size(f_precision1, f_scale1);
break;
}
case ROW_RESULT:
default:
DBUG_ASSERT(0);
@ -997,8 +1011,8 @@ Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
0, name, table, &my_charset_bin);
}
if (hybrid_type == DECIMAL_RESULT)
return new Field_new_decimal(DECIMAL_MAX_LENGTH,
maybe_null, name, table, f_scale1 + 4);
return new Field_new_decimal(max_length, maybe_null, name, table,
decimals, unsigned_flag);
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);
my_decimal_mul(E_DEC_FATAL_ERROR, &sum_sqr_buf,
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_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;
}
@ -1929,10 +1945,12 @@ Item_avg_field::Item_avg_field(Item_result res_type, Item_sum_avg *item)
{
name=item->name;
decimals=item->decimals;
max_length=item->max_length;
max_length= item->max_length;
unsigned_flag= item->unsigned_flag;
field=item->result_field;
maybe_null=1;
hybrid_type= res_type;
prec_increment= item->prec_increment;
if (hybrid_type == DECIMAL_RESULT)
{
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()
{
// 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,
field->ptr, &dec_field, f_precision, f_scale);
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;
}
@ -2054,9 +2072,11 @@ Item_variance_field::Item_variance_field(Item_sum_variance *item)
name=item->name;
decimals=item->decimals;
max_length=item->max_length;
unsigned_flag= item->unsigned_flag;
field=item->result_field;
maybe_null=1;
sample= item->sample;
prec_increment= item->prec_increment;
if ((hybrid_type= item->hybrid_type) == DECIMAL_RESULT)
{
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,
&dec_sqr, f_precision1, f_scale1);
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_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;
}

View File

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

View File

@ -81,7 +81,7 @@ int decimal_operation_results(int result)
*/
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)
{
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))
return check_result(mask, E_DEC_OOM);
result= decimal2string((decimal_t*) d, (char*) str->ptr(),
&length, fixed_prec, fixed_dec,
&length, (int)fixed_prec, fixed_dec,
filler);
str->length(length);
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;
my_decimal rounded;
my_decimal2decimal(d, &rounded);
decimal_optimize_fraction(&rounded);
rounded.frac= decimal_actual_fraction(&rounded);
if (scale < rounded.frac)
{
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];
String str(buff, sizeof(buff), &my_charset_bin);
int length= DECIMAL_MAX_STR_LENGTH;
if (!val)
str.set("NULL", 4, &my_charset_bin);
else
my_decimal2string(0, val, 0, 0, 0, &str);
DBUG_PRINT(tag, (format, (char*) str.ptr()));
return "NULL";
(void)decimal2string((decimal_t*) val, buff, &length, 0,0,0);
return buff;
}
#endif
#endif /*DBUG_OFF*/
#endif /*MYSQL_CLIENT*/

View File

@ -35,27 +35,27 @@ C_MODE_END
#define DECIMAL_LONG_DIGITS 10
#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) */
#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 in one our big digit decreased on 1 (because we always put decimal
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
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
*/
#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)
@ -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
It contains internally all necessary space needed by the instance so
@ -99,15 +105,16 @@ public:
bool sign() const { return decimal_t::sign; }
void sign(bool s) { decimal_t::sign= s; }
uint precision() const { return intg + frac; }
};
#ifndef DBUG_OFF
void print_decimal(const my_decimal *dec);
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
#define dbug_print_decimal(A,B,C)
#define dbug_decimal_as_string(A) NULL
#endif
#ifndef MYSQL_CLIENT
@ -126,6 +133,18 @@ inline int check_result(uint mask, int 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
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
int my_decimal2string(uint mask, const my_decimal *d, int fixed_prec,
int fixed_dec, char filler, String *str);
int my_decimal2string(uint mask, const my_decimal *d, uint fixed_prec,
uint fixed_dec, char filler, String *str);
#endif
inline
@ -326,7 +345,8 @@ int my_decimal_cmp(const my_decimal *a, const my_decimal *b)
inline
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);
}

View File

@ -4219,7 +4219,8 @@ enum options_mysqld
OPT_PRELOAD_BUFFER_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_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_TRANS_RETRIES, OPT_READONLY, OPT_DEBUGGING,
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,
GET_ULONG, REQUIRED_ARG, 256*1024L, IO_SIZE*2+MALLOC_OVERHEAD,
~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,
"Alias for read_buffer_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_thd_ulong sys_read_rnd_buff_size("read_rnd_buffer_size",
&SV::read_rnd_buff_size);
sys_var_thd_ulong sys_div_precincrement("div_precision_increment",
&SV::div_precincrement);
#ifdef HAVE_REPLICATION
sys_var_bool_ptr sys_relay_log_purge("relay_log_purge",
&relay_log_purge);
@ -570,6 +572,7 @@ sys_var *sys_variables[]=
&sys_connect_timeout,
&sys_date_format,
&sys_datetime_format,
&sys_div_precincrement,
&sys_default_week_format,
&sys_delay_key_write,
&sys_delayed_insert_limit,
@ -758,6 +761,7 @@ struct show_var_st init_vars[]= {
{"datadir", mysql_real_data_home, SHOW_CHAR},
{sys_date_format.name, (char*) &sys_date_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_delay_key_write.name, (char*) &sys_delay_key_write, 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();
else
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;
}
case STRING_RESULT:

View File

@ -523,6 +523,7 @@ struct system_variables
ulong query_cache_type;
ulong read_buff_size;
ulong read_rnd_buff_size;
ulong div_precincrement;
ulong sortbuff_size;
ulong table_type;
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=
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=
my_decimal_precision_to_length(new_field->length, new_field->decimals,
type_modifier & UNSIGNED_FLAG);
break;
}
my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
DBUG_RETURN(NULL);
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);
break;
case DECIMAL_RESULT:
new_field= new Field_new_decimal(item->max_length - (item->decimals?1:0),
maybe_null,
item->name, table, item->decimals);
new_field= new Field_new_decimal(item->max_length, maybe_null, item->name,
table, item->decimals, item->unsigned_flag);
break;
case ROW_RESULT:
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);
if (field->has_charset())
{
table->field[8]->store((longlong) field->representation_length()/
table->field[8]->store((longlong) field->field_length/
field->charset()->mbmaxlen);
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();
}
@ -2373,7 +2373,8 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
uint dec =field->decimals();
switch (field->type()) {
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[11]->store((longlong) field->decimals());
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
decimal_optimize_fraction()
decimal_actual_fraction()
from number for processing
*/
void decimal_optimize_fraction(decimal_t *from)
int decimal_actual_fraction(decimal_t *from)
{
int frac= from->frac, i;
dec1 *buf0= from->buf + ROUND_UP(from->intg) + ROUND_UP(frac) - 1;
if (frac == 0)
return;
return 0;
i= ((frac - 1) % DIG_PER_DEC1 + 1);
while (frac > 0 && *buf0 == 0)
@ -302,7 +302,7 @@ void decimal_optimize_fraction(decimal_t *from)
*buf0 % powers10[i++] == 0;
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,
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 */
int fixed_intg= (fixed_precision ?
(fixed_precision -
(from->sign ? 1 : 0) -
(fixed_decimals ? 1 : 0) -
fixed_decimals) :
0);
(fixed_precision - fixed_decimals) : 0);
int error=E_DEC_OK;
char *s=to;
dec1 *buf, *buf0=from->buf, tmp;
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 */
buf0= remove_leading_zeroes(from, &intg);
@ -2609,7 +2601,7 @@ void test_fr(const char *s1, const char *orig)
printf("%-40s => ", s);
end= strend(s1);
string2decimal(s1, &a, &end);
decimal_optimize_fraction(&a);
a.frac= decimal_actual_fraction(&a);
print_decimal(&a, orig, 0, 0);
printf("\n");
}
@ -2947,7 +2939,7 @@ int main()
test_sh("123456789.987654321", 0, "123456789.987654321", 0);
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.12345678000000000", "1.12345678");
test_fr("1.1234567000000000", "1.1234567");