diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index 005f41f7063..0798a034c3e 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -120,6 +120,9 @@ ASIN(0.8+0.2) SELECT ASIN(1.2-0.2); ASIN(1.2-0.2) 1.5707963267949 +select format(4.55, 1), format(4.551, 1); +format(4.55, 1) format(4.551, 1) +4.6 4.6 explain extended select degrees(pi()),radians(360); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index 33b672e42b5..0eac72782a8 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -54,6 +54,11 @@ SELECT ASIN(1.2-0.2); #select floor(log(8)/log(2)); #select floor(log(16)/log(2)); +# +# Bug #9060 (format returns incorrect result) +# +select format(4.55, 1), format(4.551, 1); + explain extended select degrees(pi()),radians(360); # diff --git a/sql/item_func.cc b/sql/item_func.cc index 89f9111101a..db2aa735b0e 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1880,22 +1880,16 @@ void Item_func_round::fix_length_and_dec() } } -double Item_func_round::real_op() +double my_double_round(double value, int dec, bool truncate) { - double value= args[0]->val_real(); - int dec=(int) args[1]->val_int(); - if (dec > 0) - decimals= dec; // to get correct output - uint abs_dec=abs(dec); double tmp; + uint abs_dec= abs(dec); /* tmp2 is here to avoid return the value with 80 bit precision This will fix that the test round(0.1,1) = round(0.1,1) is true */ volatile double tmp2; - if ((null_value=args[0]->null_value || args[1]->null_value)) - return 0.0; tmp=(abs_dec < array_elements(log_10) ? log_10[abs_dec] : pow(10.0,(double) abs_dec)); @@ -1912,6 +1906,18 @@ double Item_func_round::real_op() } +double Item_func_round::real_op() +{ + double value= args[0]->val_real(); + int dec= (int) args[1]->val_int(); + + if (!(null_value= args[0]->null_value || args[1]->null_value)) + return my_double_round(value, dec, truncate); + + return 0.0; +} + + longlong Item_func_round::int_op() { longlong value= args[0]->val_int(); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 52449f6d91c..857140dba8f 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1673,6 +1673,7 @@ String *Item_func_format::val_str(String *str) int diff; if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ + nr= my_double_round(nr, decimals, FALSE); dec= decimals ? decimals+1 : 0; /* Here default_charset() is right as this is not an automatic conversion */ str->set(nr,decimals, default_charset()); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index d46ee655165..645e835d9ca 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1251,6 +1251,7 @@ ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder, ha_rows max_rows, ha_rows *examined_rows); void filesort_free_buffers(TABLE *table); void change_double_for_sort(double nr,byte *to); +double my_double_round(double value, int dec, bool truncate); int get_quick_record(SQL_SELECT *select); int calc_weekday(long daynr,bool sunday_first_day_of_week); uint calc_week(TIME *l_time, uint week_behaviour, uint *year); diff --git a/sql/spatial.cc b/sql/spatial.cc index 427648850e4..176f1f2fbfe 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -98,6 +98,12 @@ static Geometry::Class_info geometrycollection_class("GEOMETRYCOLLECTION",Geometry::wkb_geometrycollection, create_geometrycollection); +static void get_point(double *x, double *y, const char *data) +{ + float8get(*x, data); + float8get(*y, data + SIZEOF_STORED_DOUBLE); +} + /***************************** Geometry *******************************/ Geometry::Class_info *Geometry::find_class(const char *name, uint32 len) @@ -268,14 +274,13 @@ const char *Geometry::append_points(String *txt, uint32 n_points, { while (n_points--) { - double d; + double x,y; data+= offset; - float8get(d, data); - txt->qs_append(d); - txt->qs_append(' '); - float8get(d, data + SIZEOF_STORED_DOUBLE); + get_point(&x, &y, data); data+= SIZEOF_STORED_DOUBLE * 2; - txt->qs_append(d); + txt->qs_append(x); + txt->qs_append(' '); + txt->qs_append(y); txt->qs_append(','); } return data; @@ -428,8 +433,7 @@ bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const while (n_points--) { double x, y; - float8get(x, data); - float8get(y, data + SIZEOF_STORED_DOUBLE); + get_point(&x, &y, data); data+= SIZEOF_STORED_DOUBLE * 2; txt->qs_append(x); txt->qs_append(' '); @@ -462,15 +466,13 @@ int Gis_line_string::length(double *len) const if (n_points < 1 || no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points)) return 1; - float8get(prev_x, data); - float8get(prev_y, data + SIZEOF_STORED_DOUBLE); + get_point(&prev_x, &prev_y, data); data+= SIZEOF_STORED_DOUBLE*2; while (--n_points) { double x, y; - float8get(x, data); - float8get(y, data + SIZEOF_STORED_DOUBLE); + get_point(&x, &y, data); data+= SIZEOF_STORED_DOUBLE * 2; *len+= sqrt(pow(prev_x-x,2)+pow(prev_y-y,2)); prev_x= x; @@ -499,13 +501,11 @@ int Gis_line_string::is_closed(int *closed) const return 1; /* Get first point */ - float8get(x1, data); - float8get(y1, data + SIZEOF_STORED_DOUBLE); + get_point(&x1, &y1, data); /* get last point */ data+= SIZEOF_STORED_DOUBLE*2 + (n_points-2)*POINT_DATA_SIZE; - float8get(x2, data); - float8get(y2, data + SIZEOF_STORED_DOUBLE); + get_point(&x2, &y2, data); *closed= (x1==x2) && (y1==y2); return 0; @@ -683,15 +683,13 @@ int Gis_polygon::area(double *ar, const char **end_of_data) const n_points= uint4korr(data); if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) return 1; - float8get(prev_x, data+4); - float8get(prev_y, data+(4+SIZEOF_STORED_DOUBLE)); + get_point(&prev_x, &prev_y, data+4); data+= (4+SIZEOF_STORED_DOUBLE*2); while (--n_points) // One point is already read { double x, y; - float8get(x, data); - float8get(y, data + SIZEOF_STORED_DOUBLE); + get_point(&x, &y, data); data+= (SIZEOF_STORED_DOUBLE*2); /* QQ: Is the following prev_x+x right ? */ lr_area+= (prev_x + x)* (prev_y - y); @@ -781,7 +779,8 @@ int Gis_polygon::interior_ring_n(uint32 num, String *result) const int Gis_polygon::centroid_xy(double *x, double *y) const { uint32 n_linear_rings; - double res_area, res_cx, res_cy; + double res_area; + double res_cx, res_cy; const char *data= m_data; bool first_loop= 1; LINT_INIT(res_area); @@ -807,15 +806,13 @@ int Gis_polygon::centroid_xy(double *x, double *y) const data+= 4; if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) return 1; - float8get(prev_x, data); - float8get(prev_y, data+SIZEOF_STORED_DOUBLE); + get_point(&prev_x, &prev_y, data); data+= (SIZEOF_STORED_DOUBLE*2); while (--n_points) // One point is already read { double x, y; - float8get(x, data); - float8get(y, data + SIZEOF_STORED_DOUBLE); + get_point(&x, &y, data); data+= (SIZEOF_STORED_DOUBLE*2); /* QQ: Is the following prev_x+x right ? */ cur_area+= (prev_x + x) * (prev_y - y);