Commit 6de14a23 authored by unknown's avatar unknown
Browse files

A lot of fixes to Precision math

Mostly about precision/decimals of the results of the operations


include/decimal.h:
  decimal interface changed a little
sql/field.cc:
  a lot of precision/decimals related changes to the Field_new_decimal
sql/field.h:
  Field_new_decimal interface changed
sql/ha_ndbcluster.cc:
  f->precision should be used here
sql/item.cc:
  precision/decimals counting related changes
sql/item.h:
  precision/decimals counting related changes
sql/item_cmpfunc.cc:
  precision/decimals counting related changes
sql/item_cmpfunc.h:
  precision/decimals counting related changes
sql/item_func.cc:
  precision/decimals counting related changes
sql/item_func.h:
  precision/decimals counting related changes
sql/item_sum.cc:
  precision/decimals counting related changes
sql/item_sum.h:
  precision/decimals counting related changes
sql/my_decimal.cc:
  precision/decimals counting related changes
sql/my_decimal.h:
  precision/decimals counting related changes
sql/mysqld.cc:
  precision/decimals counting related changes
sql/set_var.cc:
  precision/decimals counting related changes
sql/sp_head.cc:
  dbug_decimal_print was replaced with dbug_decimal_as_string
sql/sql_class.h:
  div_precincrement variable added
sql/sql_parse.cc:
  precision/decimals counting related changes
sql/sql_select.cc:
  precision/decimals counting related changes
sql/sql_show.cc:
  Field::representation_length was removed
strings/decimal.c:
  decimal_actual_fraction was introduced
BitKeeper/etc/logging_ok:
  Logging to logging@openlogging.org accepted
parent c0f35576
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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);

+45 −47
Original line number Diff line number Diff line
@@ -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);
}

+9 −7
Original line number Diff line number Diff line
@@ -300,8 +300,6 @@ class Field
  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 @@ class Field_decimal :public Field_real {
/* 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 @@ class Field_new_decimal :public Field_num {
                    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 @@ class Field_new_decimal :public Field_num {
  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; }
};
+1 −1
Original line number Diff line number Diff line
@@ -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)
      {
Loading