summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <ramil/ram@mysql.com/ramil.myoffice.izhnet.ru>2007-01-31 14:31:11 +0400
committerunknown <ramil/ram@mysql.com/ramil.myoffice.izhnet.ru>2007-01-31 14:31:11 +0400
commit1bcc167053a88b46f9c8dafbad0bb2e584acf289 (patch)
treeb4e0d9edcc581bb4acc1f697ed311c5e52245be0 /sql
parent29617cad4182c5e95255db90767f83249d1e94e5 (diff)
parentabf7eb0627d1a652beaa2380dbb94c6ad0ae0a2a (diff)
downloadmariadb-git-1bcc167053a88b46f9c8dafbad0bb2e584acf289.tar.gz
Merge rkalimullin@bk-internal.mysql.com:/home/bk/mysql-5.0-maint
into mysql.com:/home/ram/work/b19690/b19690.5.0 sql/item_cmpfunc.cc: Auto merged sql/mysql_priv.h: Auto merged sql/mysqld.cc: Auto merged
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc2
-rw-r--r--sql/field.h15
-rw-r--r--sql/init.cc6
-rw-r--r--sql/item_cmpfunc.cc49
-rw-r--r--sql/item_cmpfunc.h3
-rw-r--r--sql/item_sum.cc7
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/mysqld.cc1
-rw-r--r--sql/sql_select.cc4
9 files changed, 80 insertions, 8 deletions
diff --git a/sql/field.cc b/sql/field.cc
index efe608b7bdd..74a5e742c06 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -4064,7 +4064,7 @@ int Field_double::store(double nr)
else
{
double max_value;
- if (dec >= NOT_FIXED_DEC)
+ if (not_fixed)
{
max_value= DBL_MAX;
}
diff --git a/sql/field.h b/sql/field.h
index 565342637ba..26092c12372 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -725,6 +725,7 @@ public:
class Field_double :public Field_real {
public:
+ my_bool not_fixed;
Field_double(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
@@ -732,12 +733,20 @@ public:
uint8 dec_arg,bool zero_arg,bool unsigned_arg)
:Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg,
- dec_arg, zero_arg, unsigned_arg)
+ dec_arg, zero_arg, unsigned_arg),
+ not_fixed(dec_arg >= NOT_FIXED_DEC)
{}
Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
struct st_table *table_arg, uint8 dec_arg)
- :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
- NONE, field_name_arg, table_arg, dec_arg, 0, 0)
+ :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0,
+ NONE, field_name_arg, table_arg, dec_arg, 0, 0),
+ not_fixed(dec_arg >= NOT_FIXED_DEC)
+ {}
+ Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg, uint8 dec_arg, my_bool not_fixed_srg)
+ :Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0,
+ NONE, field_name_arg, table_arg, dec_arg, 0, 0),
+ not_fixed(not_fixed_srg)
{}
enum_field_types type() const { return FIELD_TYPE_DOUBLE;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }
diff --git a/sql/init.cc b/sql/init.cc
index 25856a1e1b4..ad55a2a8b24 100644
--- a/sql/init.cc
+++ b/sql/init.cc
@@ -44,5 +44,11 @@ void unireg_init(ulong options)
{ /* It's used by filesort... */
log_10[i]= nr ; nr*= 10.0;
}
+ /* Make a tab of powers of 0.1 */
+ for (i= 0, nr= 0.1; i < array_elements(log_01); i++)
+ {
+ log_01[i]= nr;
+ nr*= 0.1;
+ }
DBUG_VOID_RETURN;
}
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index f4b99e19864..f64b53bfa12 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -423,8 +423,19 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
break;
}
case DECIMAL_RESULT:
+ break;
case REAL_RESULT:
+ {
+ if ((*a)->decimals < NOT_FIXED_DEC && (*b)->decimals < NOT_FIXED_DEC)
+ {
+ precision= 5 * log_01[max((*a)->decimals, (*b)->decimals)];
+ if (func == &Arg_comparator::compare_real)
+ func= &Arg_comparator::compare_real_fixed;
+ else if (func == &Arg_comparator::compare_e_real)
+ func= &Arg_comparator::compare_e_real_fixed;
+ }
break;
+ }
default:
DBUG_ASSERT(0);
}
@@ -563,6 +574,44 @@ int Arg_comparator::compare_e_decimal()
return test(my_decimal_cmp(val1, val2) == 0);
}
+
+int Arg_comparator::compare_real_fixed()
+{
+ /*
+ Fix yet another manifestation of Bug#2338. 'Volatile' will instruct
+ gcc to flush double values out of 80-bit Intel FPU registers before
+ performing the comparison.
+ */
+ volatile double val1, val2;
+ val1= (*a)->val_real();
+ if (!(*a)->null_value)
+ {
+ val2= (*b)->val_real();
+ if (!(*b)->null_value)
+ {
+ owner->null_value= 0;
+ if (val1 == val2 || fabs(val1 - val2) < precision)
+ return 0;
+ if (val1 < val2)
+ return -1;
+ return 1;
+ }
+ }
+ owner->null_value= 1;
+ return -1;
+}
+
+
+int Arg_comparator::compare_e_real_fixed()
+{
+ double val1= (*a)->val_real();
+ double val2= (*b)->val_real();
+ if ((*a)->null_value || (*b)->null_value)
+ return test((*a)->null_value && (*b)->null_value);
+ return test(val1 == val2 || fabs(val1 - val2) < precision);
+}
+
+
int Arg_comparator::compare_int_signed()
{
longlong val1= (*a)->val_int();
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 7bdc90adcee..1b27aac0871 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -34,6 +34,7 @@ class Arg_comparator: public Sql_alloc
arg_cmp_func func;
Item_bool_func2 *owner;
Arg_comparator *comparators; // used only for compare_row()
+ double precision;
public:
DTCollation cmp_collation;
@@ -80,6 +81,8 @@ public:
int compare_e_int(); // compare args[0] & args[1]
int compare_e_int_diff_signedness();
int compare_e_row(); // compare args[0] & args[1]
+ int compare_real_fixed();
+ int compare_e_real_fixed();
static arg_cmp_func comparator_matrix [5][2];
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 8bfac058936..28a9a1f4dbf 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -398,7 +398,8 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table,
{
switch (result_type()) {
case REAL_RESULT:
- return new Field_double(max_length,maybe_null,name,table,decimals);
+ return new Field_double(max_length, maybe_null, name, table, decimals,
+ TRUE);
case INT_RESULT:
return new Field_longlong(max_length,maybe_null,name,table,unsigned_flag);
case STRING_RESULT:
@@ -1123,7 +1124,7 @@ Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table,
if (hybrid_type == DECIMAL_RESULT)
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);
+ return new Field_double(max_length, maybe_null, name, table, decimals, TRUE);
}
@@ -1317,7 +1318,7 @@ Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
*/
return new Field_string(sizeof(double)*2 + sizeof(longlong), 0, name, table, &my_charset_bin);
}
- return new Field_double(max_length, maybe_null,name,table,decimals);
+ return new Field_double(max_length, maybe_null, name, table, decimals, TRUE);
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 8295f247835..4c0554719ed 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -1218,6 +1218,7 @@ extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file;
extern char log_error_file[FN_REFLEN], *opt_tc_log_file;
extern double log_10[32];
+extern double log_01[32];
extern ulonglong log_10_int[20];
extern ulonglong keybuff_size;
extern ulonglong thd_startup_options;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index d481bc928f8..8a1c1797736 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -432,6 +432,7 @@ ulong expire_logs_days = 0;
ulong rpl_recovery_rank=0;
double log_10[32]; /* 10 potences */
+double log_01[32];
time_t start_time;
char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], system_time_zone[30];
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index d62032c2b44..395c70e711a 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -8598,6 +8598,8 @@ Field* create_tmp_field_from_field(THD *thd, Field* org_field,
if (org_field->type() == MYSQL_TYPE_VAR_STRING ||
org_field->type() == MYSQL_TYPE_VARCHAR)
table->s->db_create_options|= HA_OPTION_PACK_RECORD;
+ else if (org_field->type() == FIELD_TYPE_DOUBLE)
+ ((Field_double *) new_field)->not_fixed= TRUE;
}
return new_field;
}
@@ -8638,7 +8640,7 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
switch (item->result_type()) {
case REAL_RESULT:
new_field=new Field_double(item->max_length, maybe_null,
- item->name, table, item->decimals);
+ item->name, table, item->decimals, TRUE);
break;
case INT_RESULT:
/* Select an integer type with the minimal fit precision */