summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am4
-rw-r--r--sql/field.cc586
-rw-r--r--sql/field.h192
-rw-r--r--sql/field_conv.cc8
-rw-r--r--sql/filesort.cc22
-rw-r--r--sql/ha_innodb.cc2
-rw-r--r--sql/ha_myisam.cc2
-rw-r--r--sql/item.cc827
-rw-r--r--sql/item.h410
-rw-r--r--sql/item_buff.cc37
-rw-r--r--sql/item_cmpfunc.cc444
-rw-r--r--sql/item_cmpfunc.h123
-rw-r--r--sql/item_create.cc7
-rw-r--r--sql/item_create.h3
-rw-r--r--sql/item_func.cc1161
-rw-r--r--sql/item_func.h294
-rw-r--r--sql/item_row.cc3
-rw-r--r--sql/item_row.h5
-rw-r--r--sql/item_strfunc.cc7
-rw-r--r--sql/item_strfunc.h3
-rw-r--r--sql/item_subselect.cc123
-rw-r--r--sql/item_subselect.h8
-rw-r--r--sql/item_sum.cc1178
-rw-r--r--sql/item_sum.h166
-rw-r--r--sql/item_timefunc.h4
-rw-r--r--sql/item_uniq.cc6
-rw-r--r--sql/item_uniq.h1
-rw-r--r--sql/log_event.cc53
-rw-r--r--sql/my_decimal.cc212
-rw-r--r--sql/my_decimal.h332
-rw-r--r--sql/mysql_priv.h4
-rw-r--r--sql/mysqld.cc7
-rw-r--r--sql/procedure.cc28
-rw-r--r--sql/procedure.h3
-rw-r--r--sql/protocol.cc40
-rw-r--r--sql/protocol.h3
-rw-r--r--sql/set_var.cc14
-rw-r--r--sql/sp_head.cc82
-rw-r--r--sql/sp_rcontext.cc10
-rw-r--r--sql/sql_analyse.cc173
-rw-r--r--sql/sql_analyse.h31
-rw-r--r--sql/sql_base.cc12
-rw-r--r--sql/sql_class.cc25
-rw-r--r--sql/sql_class.h10
-rw-r--r--sql/sql_handler.cc6
-rw-r--r--sql/sql_lex.cc14
-rw-r--r--sql/sql_parse.cc27
-rw-r--r--sql/sql_prepare.cc13
-rw-r--r--sql/sql_select.cc72
-rw-r--r--sql/sql_show.cc16
-rw-r--r--sql/sql_table.cc8
-rw-r--r--sql/sql_trigger.cc3
-rw-r--r--sql/sql_udf.h1
-rw-r--r--sql/sql_update.cc4
-rw-r--r--sql/sql_yacc.yy67
55 files changed, 5906 insertions, 990 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 3c520ac971c..498fb93abf3 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -58,7 +58,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
log_event.h sql_repl.h slave.h \
stacktrace.h sql_sort.h sql_cache.h set_var.h \
spatial.h gstream.h client_settings.h tzfile.h \
- tztime.h \
+ tztime.h my_decimal.h\
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
parse_file.h sql_view.h sql_trigger.h \
examples/ha_example.h examples/ha_archive.h \
@@ -95,7 +95,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
stacktrace.c repl_failsafe.h repl_failsafe.cc \
sql_olap.cc sql_view.cc \
gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \
- tztime.cc my_time.c \
+ tztime.cc my_time.c my_decimal.cc\
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
sp_cache.cc parse_file.cc sql_trigger.cc \
examples/ha_example.cc examples/ha_archive.cc \
diff --git a/sql/field.cc b/sql/field.cc
index f95eaaba5df..ad66fec2fc2 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -52,6 +52,25 @@ const char field_separator=',';
Static help functions
*****************************************************************************/
+/*
+ Numeric fields base class constructor
+*/
+Field_num::Field_num(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
+ const char *field_name_arg,
+ struct st_table *table_arg,
+ uint8 dec_arg, bool zero_arg, bool unsigned_arg)
+ :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg),
+ dec(dec_arg),zerofill(zero_arg),unsigned_flag(unsigned_arg)
+{
+ if (zerofill)
+ flags|=ZEROFILL_FLAG;
+ if (unsigned_flag)
+ flags|=UNSIGNED_FLAG;
+}
+
+
void Field_num::prepend_zeros(String *value)
{
int diff;
@@ -82,7 +101,7 @@ void Field_num::prepend_zeros(String *value)
Make this multi-byte-character safe
RETURN
- 0 ok
+ 0 OK
1 error. A warning is pushed if field_name != 0
*/
@@ -104,7 +123,7 @@ bool Field::check_int(const char *str, int length, const char *int_end,
}
end= str+length;
if ((str= int_end) == end)
- return 0; // ok; All digits was used
+ return 0; // OK; All digits was used
/* Allow end .0000 */
if (*str == '.')
@@ -125,6 +144,32 @@ bool Field::check_int(const char *str, int length, const char *int_end,
}
+/*
+ Process decimal library return codes and issue warnings for overflow and
+ truncation.
+
+ SYNOPSIS
+ Field::check_overflow()
+ op_result decimal library return code (E_DEC_* see include/decimal.h)
+
+ RETURN
+ 1 there was overflow
+ 0 no error or some other errors except overflow
+*/
+
+int Field::check_overflow(int op_result)
+{
+ if (op_result == E_DEC_OVERFLOW)
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ return 1;
+ }
+ else if (op_result == E_DEC_TRUNCATED)
+ set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1);
+ /* we return 1 only in case of EFL */
+ return 0;
+}
+
#ifdef NOT_USED
static bool test_if_real(const char *str,int length, CHARSET_INFO *cs)
{
@@ -191,6 +236,10 @@ static Field::field_cast_enum field_cast_decimal[]=
{Field::FIELD_CAST_DECIMAL,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
+static Field::field_cast_enum field_cast_new_decimal[]=
+{Field::FIELD_CAST_NEWDECIMAL,
+ Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
+ Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_tiny[]=
{Field::FIELD_CAST_TINY,
Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG,
@@ -283,6 +332,9 @@ static Field::field_cast_enum field_cast_varstring[]=
static Field::field_cast_enum field_cast_blob[]=
{Field::FIELD_CAST_BLOB,
Field::FIELD_CAST_STOP};
+static Field::field_cast_enum field_cast_bit[]=
+{Field::FIELD_CAST_BIT,
+ Field::FIELD_CAST_STOP};
/*
Geometrical, enum and set fields can be casted only to expressions
*/
@@ -302,7 +354,8 @@ static Field::field_cast_enum *field_cast_array[]=
field_cast_timestamp, field_cast_year, field_cast_date, field_cast_newdate,
field_cast_time, field_cast_datetime,
field_cast_string, field_cast_varstring, field_cast_blob,
- field_cast_geom, field_cast_enum, field_cast_set
+ field_cast_geom, field_cast_enum, field_cast_set, field_cast_bit,
+ field_cast_new_decimal
};
@@ -398,6 +451,14 @@ bool Field::send_binary(Protocol *protocol)
}
+my_decimal *Field::val_decimal(my_decimal *decimal)
+{
+ /* This never have to be called */
+ DBUG_ASSERT(0);
+ return 0;
+}
+
+
void Field_num::add_zerofill_and_unsigned(String &res) const
{
if (unsigned_flag)
@@ -406,6 +467,7 @@ void Field_num::add_zerofill_and_unsigned(String &res) const
res.append(" zerofill");
}
+
void Field::make_field(Send_field *field)
{
field->db_name= orig_table->s->table_cache_key;
@@ -420,12 +482,155 @@ void Field::make_field(Send_field *field)
}
+/*
+ Conversion from decimal to longlong with checking overflow and
+ setting correct value (min/max) in case of overflow
+
+ SYNOPSIS
+ Field::convert_decimal2longlong()
+ val value which have to be converted
+ unsigned_flag type of integer in which we convert val
+ err variable to pass error code
+
+ RETURN
+ value converted from val
+*/
+longlong Field::convert_decimal2longlong(const my_decimal *val,
+ bool unsigned_flag, int *err)
+{
+ longlong i;
+ if (unsigned_flag)
+ {
+ if (val->sign())
+ {
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ i= 0;
+ *err= 1;
+ }
+ else if (check_overflow(my_decimal2int(E_DEC_ERROR &
+ ~E_DEC_OVERFLOW & ~E_DEC_TRUNCATED,
+ val, TRUE, &i)))
+ {
+ i= ~(longlong) 0;
+ *err= 1;
+ }
+ }
+ else if (check_overflow(my_decimal2int(E_DEC_ERROR &
+ ~E_DEC_OVERFLOW & ~E_DEC_TRUNCATED,
+ val, FALSE, &i)))
+ {
+ i= (val->sign() ? LONGLONG_MIN : LONGLONG_MAX);
+ *err= 1;
+ }
+ return i;
+}
+
+
+/*
+ Storing decimal in integer fields.
+
+ SYNOPSIS
+ Field_num::store_decimal()
+ val value for storing
+
+ NOTE
+ This method is used by all integer fields, real/decimal redefine it
+
+ RETURN
+ 0 OK
+ != 0 error
+*/
+
+int Field_num::store_decimal(const my_decimal *val)
+{
+ int err= 0;
+ longlong i= convert_decimal2longlong(val, unsigned_flag, &err);
+ return test(err | store(i));
+}
+
+
+/*
+ Return decimal value of integer field
+
+ SYNOPSIS
+ Field_num::val_decimal()
+ decimal_value buffer for storing decimal value
+
+ NOTE
+ This method is used by all integer fields, real/decimal redefine it
+ All longlong values fit in our decimal buffer which cal store 8*9=72
+ digits of integer number
+
+ RETURN
+ pointer to decimal buffer with value of field
+*/
+
+my_decimal* Field_num::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(result_type() == INT_RESULT);
+ longlong nr= val_int();
+ if (!is_null())
+ int2my_decimal(E_DEC_FATAL_ERROR, nr, unsigned_flag, decimal_value);
+ return decimal_value;
+}
+
+
+Field_str::Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
+ const char *field_name_arg,
+ struct st_table *table_arg,CHARSET_INFO *charset)
+ :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg)
+{
+ field_charset=charset;
+ if (charset->state & MY_CS_BINSORT)
+ flags|=BINARY_FLAG;
+}
+
+
void Field_num::make_field(Send_field *field)
{
Field::make_field(field);
field->decimals= dec;
}
+/*
+ Decimal representation of Field_str
+
+ SYNOPSIS
+ Field_str::store_decimal()
+ d value for storing
+
+ NOTE
+ Field_str is the base class for fields like Field_date, and some
+ similar. Some dates use fraction and also string value should be
+ converted to floating point value according our rules, so we use double
+ to store value of decimal in string
+
+ RETURN
+ 0 OK
+ != 0 error
+*/
+
+int Field_str::store_decimal(const my_decimal *d)
+{
+ double val;
+ /* TODO: use decimal2string? */
+ int err= check_overflow(my_decimal2double(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW, d, &val));
+ return err | store(val);
+}
+
+
+my_decimal *Field_str::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(result_type() == INT_RESULT);
+ longlong nr= val_int();
+ if (is_null())
+ int2my_decimal(E_DEC_FATAL_ERROR, nr, 0, decimal_value);
+ return decimal_value;
+}
+
uint Field::fill_cache_field(CACHE_FIELD *copy)
{
@@ -697,7 +902,7 @@ void Field_decimal::overflow(bool negative)
int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmp(buff,sizeof(buff), &my_charset_bin);
/* Convert character set if the old one is multi byte */
@@ -838,7 +1043,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
/*
We only have to generate warnings if count_cuted_fields is set.
This is to avoid extra checks of the number when they are not needed.
- Even if this flag is not set, it's ok to increment warnings, if
+ Even if this flag is not set, it's OK to increment warnings, if
it makes the code easer to read.
*/
@@ -1255,6 +1460,275 @@ 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,
+ enum utype unireg_check_arg,
+ const char *field_name_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),
+ 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)
+{
+ bin_size= my_decimal_get_binary_size(field_length, dec);
+}
+
+
+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),
+ 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)
+{
+ bin_size= my_decimal_get_binary_size(field_length, dec);
+}
+
+
+void Field_new_decimal::reset(void)
+{
+ store_value(&decimal_zero);
+}
+
+
+/*
+ Generate max/min decimal value in case of overflow.
+
+ SYNOPSIS
+ Field_new_decimal::set_value_on_overflow();
+ decimal_value buffer for value
+ sign sign of value which caused overflow
+*/
+
+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());
+ if (sign)
+ {
+ if (unsigned_flag)
+ my_decimal_set_zero(decimal_value);
+ else
+ decimal_value->sign(TRUE);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Store decimal value in the binary buffer
+
+ SYNOPSIS
+ store_value(const my_decimal *decimal_value)
+ decimal_value my_decimal
+
+ DESCRIPTION
+ checks if decimal_value fits into field size.
+ if it does, stores the decimal in the buffer using binary format.
+ Otherwise sets maximal number that can be stored in the field.
+*/
+
+bool Field_new_decimal::store_value(const my_decimal *decimal_value)
+{
+ DBUG_ENTER("Field_new_decimal::store_value");
+ my_decimal *dec= (my_decimal*)decimal_value;
+ DBUG_EXECUTE("enter", print_decimal(dec););
+
+ /* check that we do not try to write negative value in unsigned field */
+ if (unsigned_flag && decimal_value->sign())
+ {
+ DBUG_PRINT("info", ("unsigned overflow"));
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ dec= &decimal_zero;
+ }
+ DBUG_PRINT("info", ("saving with precision %d, scale: %d",
+ (int)field_length, (int)decimals()));
+ DBUG_EXECUTE("info", print_decimal(dec););
+
+ if (check_overflow(my_decimal2binary(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
+ dec, ptr,
+ field_length,
+ decimals())))
+ {
+ 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());
+ DBUG_EXECUTE("info", print_decimal_buff(&buff, ptr, bin_size););
+ DBUG_RETURN(1);
+ }
+ DBUG_EXECUTE("info", print_decimal_buff(dec, ptr, bin_size););
+ DBUG_RETURN(0);
+}
+
+
+int Field_new_decimal::store(const char *from, uint length,
+ CHARSET_INFO *charset)
+{
+ DBUG_ENTER("Field_new_decimal::store(char*)");
+ int err;
+ my_decimal decimal_value;
+ switch ((err= str2my_decimal(E_DEC_FATAL_ERROR &
+ ~(E_DEC_OVERFLOW | E_DEC_BAD_NUM),
+ from, length, charset, &decimal_value)))
+ {
+ case E_DEC_TRUNCATED:
+ set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1);
+ break;
+ case E_DEC_OVERFLOW:
+ set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
+ set_value_on_overflow(&decimal_value, decimal_value.sign());
+ break;
+ case E_DEC_BAD_NUM:
+ push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
+ ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
+ "decimal", from, field_name,
+ (ulong) table->in_use->row_count);
+ my_decimal_set_zero(&decimal_value);
+ break;
+ }
+
+ DBUG_EXECUTE("info", print_decimal(&decimal_value););
+ store_value(&decimal_value);
+ DBUG_RETURN(err);
+}
+
+
+int Field_new_decimal::store(double nr)
+{
+ my_decimal decimal_value;
+ int err= double2my_decimal(E_DEC_FATAL_ERROR &
+ ~E_DEC_OVERFLOW, nr,
+ &decimal_value);
+ /*
+ TODO: fix following when double2my_decimal when double2decimal
+ will return E_DEC_TRUNCATED always correctly
+ */
+ if (!err)
+ {
+ double nr2;
+ my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &nr2);
+ if (nr2 != nr)
+ err= E_DEC_TRUNCATED;
+ }
+ if (check_overflow(err))
+ set_value_on_overflow(&decimal_value, decimal_value.sign());
+ store_value(&decimal_value);
+ return err;
+}
+
+
+int Field_new_decimal::store(longlong nr)
+{
+ my_decimal decimal_value;
+ int err;
+ if ((err= check_overflow(int2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW,
+ nr, unsigned_flag, &decimal_value))))
+ set_value_on_overflow(&decimal_value, decimal_value.sign());
+ store_value(&decimal_value);
+ return err;
+}
+
+
+int Field_new_decimal::store_decimal(const my_decimal *decimal_value)
+{
+ return store_value(decimal_value);
+}
+
+
+double Field_new_decimal::val_real(void)
+{
+ double dbl;
+ my_decimal decimal_value;
+ my_decimal2double(E_DEC_FATAL_ERROR, val_decimal(&decimal_value), &dbl);
+ return dbl;
+}
+
+
+longlong Field_new_decimal::val_int(void)
+{
+ longlong i;
+ my_decimal decimal_value;
+ my_decimal2int(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
+ unsigned_flag, &i);
+ return i;
+}
+
+
+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());
+ DBUG_EXECUTE("info", print_decimal_buff(decimal_value, ptr, bin_size););
+ DBUG_RETURN(decimal_value);
+}
+
+
+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);
+ my_decimal2string(E_DEC_FATAL_ERROR, val_decimal(&decimal_value),
+ fixed_precision, decimals(), '0',
+ val_buffer);
+ return val_buffer;
+}
+
+
+int Field_new_decimal::cmp(const char *a,const char*b)
+{
+ return memcmp(a, b, bin_size);
+}
+
+
+void Field_new_decimal::sort_string(char *buff,
+ uint length __attribute__((unused)))
+{
+ memcpy(buff, ptr, bin_size);
+}
+
+
+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));
+ add_zerofill_and_unsigned(str);
+}
+
+/****************************************************************************
** tiny int
****************************************************************************/
@@ -2554,7 +3028,6 @@ int Field_float::store(longlong nr)
return store((double)nr);
}
-
double Field_float::val_real(void)
{
float j;
@@ -2835,6 +3308,12 @@ int Field_double::store(longlong nr)
return store((double)nr);
}
+int Field_real::store_decimal(const my_decimal *dm)
+{
+ double dbl;
+ my_decimal2double(E_DEC_FATAL_ERROR, dm, &dbl);
+ return store(dbl);
+}
double Field_double::val_real(void)
{
@@ -2865,6 +3344,13 @@ longlong Field_double::val_int(void)
}
+my_decimal *Field_real::val_decimal(my_decimal *decimal_value)
+{
+ double2my_decimal(E_DEC_FATAL_ERROR, val_real(), decimal_value);
+ return decimal_value;
+}
+
+
String *Field_double::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
@@ -3032,7 +3518,7 @@ void Field_double::sql_type(String &res) const
TIMESTAMP_OLD_FIELD - old timestamp, if there was not any fields with
auto-set-on-update (or now() as default) in this table before, then this
field has NOW() as default and is updated when row changes, else it is
- field which has 0 as default value and is not automaitcally updated.
+ field which has 0 as default value and is not automatically updated.
TIMESTAMP_DN_FIELD - field with NOW() as default but not set on update
automatically (TIMESTAMP DEFAULT NOW())
TIMESTAMP_UN_FIELD - field which is set on update automatically but has not
@@ -3094,7 +3580,7 @@ timestamp_auto_set_type Field_timestamp::get_auto_set_type() const
return TIMESTAMP_AUTO_SET_ON_UPDATE;
case TIMESTAMP_OLD_FIELD:
/*
- Altough we can have several such columns in legacy tables this
+ Although we can have several such columns in legacy tables this
function should be called only for first of them (i.e. the one
having auto-set property).
*/
@@ -3598,7 +4084,7 @@ String *Field_time::val_str(String *val_buffer,
/*
- Normally we would not consider 'time' as a vaild date, but we allow
+ Normally we would not consider 'time' as a valid date, but we allow
get_date() here to be able to do things like
DATE_FORMAT(time, "%l.%i %p")
*/
@@ -4319,7 +4805,7 @@ String *Field_datetime::val_str(String *val_buffer,
longlongget(tmp,ptr);
/*
- Avoid problem with slow longlong aritmetic and sprintf
+ Avoid problem with slow longlong arithmetic and sprintf
*/
part1=(long) (tmp/LL(1000000));
@@ -4437,14 +4923,14 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
{
int error= 0;
uint32 not_used;
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
uint copy_length;
/* See the comment for Field_long::store(long long) */
DBUG_ASSERT(table->in_use == current_thd);
- /* Convert character set if nesessary */
+ /* Convert character set if necessary */
if (String::needs_conversion(length, cs, field_charset, &not_used))
{
uint conv_errors;
@@ -4542,6 +5028,16 @@ int Field_string::store(longlong nr)
return Field_string::store(buff,(uint)l,cs);
}
+int Field_longstr::store_decimal(const my_decimal *d)
+{
+ uint buf_size= my_decimal_string_length(d);
+ char *buff= (char *)my_alloca(buf_size);
+ String str(buff, buf_size, &my_charset_bin);
+ my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str);
+ int result= store(str.ptr(), str.length(), str.charset());
+ my_afree(buff);
+ return result;
+}
double Field_string::val_real(void)
{
@@ -4561,6 +5057,14 @@ longlong Field_string::val_int(void)
}
+my_decimal *Field_longstr::val_decimal(my_decimal *decimal_value)
+{
+ str2my_decimal(E_DEC_FATAL_ERROR, ptr, field_length, charset(),
+ decimal_value);
+ return decimal_value;
+}
+
+
String *Field_string::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
@@ -4792,11 +5296,11 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
{
int error= 0;
uint32 not_used, copy_length;
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
enum MYSQL_ERROR::enum_warning_level level= MYSQL_ERROR::WARN_LEVEL_WARN;
- /* Convert character set if nesessary */
+ /* Convert character set if necessary */
if (String::needs_conversion(length, cs, field_charset, &not_used))
{
uint conv_errors;
@@ -4872,7 +5376,6 @@ longlong Field_varstring::val_int(void)
&end_not_used, &not_used);
}
-
String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
@@ -5273,7 +5776,7 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint blob_pack_length,
CHARSET_INFO *cs)
- :Field_str(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L,
+ :Field_longstr(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L,
null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
table_arg, cs),
packlength(blob_pack_length)
@@ -5396,12 +5899,12 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
else
{
bool was_conversion;
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
uint copy_length;
uint32 not_used;
- /* Convert character set if nesessary */
+ /* Convert character set if necessary */
if ((was_conversion= String::needs_conversion(length, cs, field_charset,
&not_used)))
{
@@ -5415,7 +5918,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
copy_length= max_data_length();
/*
- copy_length is ok as last argument to well_formed_len as this is never
+ copy_length is OK as last argument to well_formed_len as this is never
used to limit the length of the data. The cut of long data is done with
the 'min()' call below.
*/
@@ -5457,7 +5960,6 @@ int Field_blob::store(longlong nr)
return Field_blob::store(value.ptr(), (uint) value.length(), cs);
}
-
double Field_blob::val_real(void)
{
int not_used;
@@ -5485,7 +5987,6 @@ longlong Field_blob::val_int(void)
return my_strntoll(charset(),blob,length,10,NULL,&not_used);
}
-
String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
@@ -5998,10 +6499,10 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
{
int err= 0;
uint32 not_used;
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
- /* Convert character set if nesessary */
+ /* Convert character set if necessary */
if (String::needs_conversion(length, cs, field_charset, &not_used))
{
uint dummy_errors;
@@ -6182,10 +6683,10 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
char *not_used;
uint not_used2;
uint32 not_used_offset;
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmpstr(buff,sizeof(buff), &my_charset_bin);
- /* Convert character set if nesessary */
+ /* Convert character set if necessary */
if (String::needs_conversion(length, cs, field_charset, &not_used_offset))
{
uint dummy_errors;
@@ -6444,6 +6945,14 @@ int Field_bit::store(longlong nr)
}
+int Field_bit::store_decimal(const my_decimal *val)
+{
+ int err= 0;
+ longlong i= convert_decimal2longlong(val, 1, &err);
+ return test(err | store(i));
+}
+
+
double Field_bit::val_real(void)
{
return (double) Field_bit::val_int();
@@ -6487,6 +6996,13 @@ String *Field_bit::val_str(String *val_buffer,
}
+my_decimal *Field_bit::val_decimal(my_decimal *deciaml_value)
+{
+ int2my_decimal(E_DEC_FATAL_ERROR, val_int(), 1, deciaml_value);
+ return deciaml_value;
+}
+
+
int Field_bit::key_cmp(const byte *str, uint length)
{
if (bit_len)
@@ -6593,6 +7109,9 @@ void create_field::create_length_to_internal_length(void)
/* We need one extra byte to store the bits we save among the null bits */
key_length= pack_length+ test(length & 7);
break;
+ case MYSQL_TYPE_NEWDECIMAL:
+ key_length= pack_length= my_decimal_get_binary_size(length, decimals);
+ break;
default:
key_length= pack_length= calc_pack_length(sql_type, length);
break;
@@ -6646,7 +7165,8 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
case FIELD_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr;
case FIELD_TYPE_GEOMETRY: return 4+portable_sizeof_char_ptr;
case FIELD_TYPE_SET:
- case FIELD_TYPE_ENUM: abort(); return 0; // This shouldn't happen
+ case FIELD_TYPE_ENUM:
+ case FIELD_TYPE_NEWDECIMAL: abort(); return 0; // This shouldn't happen
case FIELD_TYPE_BIT: return length / 8;
default: return 0;
}
@@ -6767,6 +7287,12 @@ Field *make_field(char *ptr, uint32 field_length,
f_decimals(pack_flag),
f_is_zerofill(pack_flag) != 0,
f_is_dec(pack_flag) == 0);
+ case FIELD_TYPE_NEWDECIMAL:
+ return new Field_new_decimal(ptr,field_length,null_pos,null_bit,
+ unireg_check, field_name, table,
+ f_decimals(pack_flag),
+ f_is_zerofill(pack_flag) != 0,
+ f_is_dec(pack_flag) == 0);
case FIELD_TYPE_FLOAT:
return new Field_float(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
@@ -6959,7 +7485,7 @@ create_field::create_field(Field *old_field,Field *orig_field)
/*
Produce warning or note about data saved into field
- SYNOPSYS
+ SYNOPSIS
set_warning()
level - level of message (Note/Warning/Error)
code - error code of message to be produced
@@ -6991,7 +7517,7 @@ Field::set_warning(const uint level, const uint code, int cuted_increment)
/*
Produce warning or note about datetime string data saved into field
- SYNOPSYS
+ SYNOPSIS
set_datime_warning()
level - level of message (Note/Warning/Error)
code - error code of message to be produced
@@ -7020,7 +7546,7 @@ Field::set_datetime_warning(const uint level, const uint code,
/*
Produce warning or note about integer datetime value saved into field
- SYNOPSYS
+ SYNOPSIS
set_warning()
level - level of message (Note/Warning/Error)
code - error code of message to be produced
@@ -7052,7 +7578,7 @@ Field::set_datetime_warning(const uint level, const uint code,
/*
Produce warning or note about double datetime data saved into field
- SYNOPSYS
+ SYNOPSIS
set_warning()
level - level of message (Note/Warning/Error)
code - error code of message to be produced
diff --git a/sql/field.h b/sql/field.h
index 756fa713707..d0b43e77e5a 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -80,7 +80,8 @@ public:
FIELD_CAST_TIMESTAMP, FIELD_CAST_YEAR, FIELD_CAST_DATE, FIELD_CAST_NEWDATE,
FIELD_CAST_TIME, FIELD_CAST_DATETIME,
FIELD_CAST_STRING, FIELD_CAST_VARSTRING, FIELD_CAST_BLOB,
- FIELD_CAST_GEOM, FIELD_CAST_ENUM, FIELD_CAST_SET, FIELD_CAST_BIT
+ FIELD_CAST_GEOM, FIELD_CAST_ENUM, FIELD_CAST_SET, FIELD_CAST_BIT,
+ FIELD_CAST_NEWDECIMAL
};
utype unireg_check;
@@ -96,9 +97,11 @@ public:
virtual int store(const char *to,uint length,CHARSET_INFO *cs)=0;
virtual int store(double nr)=0;
virtual int store(longlong nr)=0;
+ virtual int store_decimal(const my_decimal *d)=0;
virtual int store_time(TIME *ltime, timestamp_type t_type);
virtual double val_real(void)=0;
virtual longlong val_int(void)=0;
+ virtual my_decimal *val_decimal(my_decimal *);
inline String *val_str(String *str) { return val_str(str, str); }
/*
val_str(buf1, buf2) gets two buffers and should use them as follows:
@@ -287,10 +290,16 @@ public:
int cuted_increment);
void set_datetime_warning(const uint level, const uint code,
double nr, timestamp_type ts_type);
+ int check_overflow(int op_result);
virtual field_cast_enum field_cast_type()= 0;
bool field_cast_compatible(field_cast_enum type);
/* 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);
friend bool reopen_table(THD *,struct st_table *,bool);
friend int cre_myisam(my_string name, register TABLE *form, uint options,
ulonglong auto_increment_value);
@@ -317,16 +326,7 @@ public:
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
struct st_table *table_arg,
- uint8 dec_arg,bool zero_arg,bool unsigned_arg)
- :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg),
- dec(dec_arg),zerofill(zero_arg),unsigned_flag(unsigned_arg)
- {
- if (zerofill)
- flags|=ZEROFILL_FLAG;
- if (unsigned_flag)
- flags|=UNSIGNED_FLAG;
- }
+ uint8 dec_arg, bool zero_arg, bool unsigned_arg);
Item_result result_type () const { return REAL_RESULT; }
void prepend_zeros(String *value);
void add_zerofill_and_unsigned(String &res) const;
@@ -335,6 +335,8 @@ public:
uint decimals() const { return (uint) dec; }
uint size_of() const { return sizeof(*this); }
bool eq_def(Field *field);
+ int store_decimal(const my_decimal *);
+ my_decimal *val_decimal(my_decimal *);
};
@@ -345,18 +347,12 @@ public:
Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
- struct st_table *table_arg,CHARSET_INFO *charset)
- :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg)
- {
- field_charset=charset;
- if (charset->state & MY_CS_BINSORT)
- flags|=BINARY_FLAG;
- }
+ struct st_table *table_arg, CHARSET_INFO *charset);
Item_result result_type () const { return STRING_RESULT; }
uint decimals() const { return NOT_FIXED_DEC; }
int store(double nr);
int store(longlong nr)=0;
+ int store_decimal(const my_decimal *);
int store(const char *to,uint length,CHARSET_INFO *cs)=0;
uint size_of() const { return sizeof(*this); }
CHARSET_INFO *charset(void) const { return field_charset; }
@@ -364,19 +360,54 @@ public:
bool binary() const { return field_charset == &my_charset_bin; }
uint32 max_length() { return field_length; }
friend class create_field;
+ my_decimal *val_decimal(my_decimal *);
+};
+
+/* base class for Item_string, Item_valstring, Item_blob */
+class Field_longstr :public Field_str
+{
+public:
+ Field_longstr(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
+ const char *field_name_arg,
+ struct st_table *table_arg,CHARSET_INFO *charset)
+ :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
+ field_name_arg, table_arg, charset)
+ {}
+
+ my_decimal *val_decimal(my_decimal *);
+ int store_decimal(const my_decimal *d);
+};
+
+/* base class for float and double and decimal (old one) */
+class Field_real :public Field_num {
+public:
+
+ Field_real(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
+ uchar null_bit_arg, utype unireg_check_arg,
+ const char *field_name_arg,
+ struct st_table *table_arg,
+ uint8 dec_arg, bool zero_arg, bool unsigned_arg)
+ :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
+ field_name_arg, table_arg, dec_arg, zero_arg, unsigned_arg)
+ {}
+
+
+ int store_decimal(const my_decimal *);
+ my_decimal *val_decimal(my_decimal *);
};
-class Field_decimal :public Field_num {
+class Field_decimal :public Field_real {
public:
Field_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,
struct st_table *table_arg,
uint8 dec_arg,bool zero_arg,bool unsigned_arg)
- :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg,
- dec_arg, zero_arg,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)
{}
enum_field_types type() const { return FIELD_TYPE_DECIMAL;}
enum ha_base_keytype key_type() const
@@ -398,6 +429,46 @@ public:
};
+/* New decimal/numeric field which use fixed point arithmetic */
+class Field_new_decimal :public Field_num {
+public:
+ uint bin_size;
+ 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,
+ struct st_table *table_arg,
+ 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);
+ 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; }
+ void reset(void);
+ bool store_value(const my_decimal *decimal_value);
+ void set_value_on_overflow(my_decimal *decimal_value, bool sign);
+ int store(const char *to, uint length, CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
+ int store_decimal(const my_decimal *);
+ double val_real(void);
+ longlong val_int(void);
+ my_decimal *val_decimal(my_decimal *);
+ String *val_str(String*, String *);
+ int cmp(const char *, const char*);
+ 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); };
+ field_cast_enum field_cast_type() { return FIELD_CAST_NEWDECIMAL; }
+ uint size_of() const { return sizeof(*this); }
+ uint32 pack_length() const { return (uint32) bin_size; }
+};
+
+
class Field_tiny :public Field_num {
public:
Field_tiny(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
@@ -576,21 +647,22 @@ public:
};
#endif
-class Field_float :public Field_num {
+
+class Field_float :public Field_real {
public:
Field_float(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,
- uint8 dec_arg,bool zero_arg,bool unsigned_arg)
- :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg,
- dec_arg, zero_arg,unsigned_arg)
+ 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)
{}
Field_float(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
struct st_table *table_arg, uint8 dec_arg)
- :Field_num((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)
{}
enum_field_types type() const { return FIELD_TYPE_FLOAT;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; }
@@ -611,21 +683,21 @@ public:
};
-class Field_double :public Field_num {
+class Field_double :public Field_real {
public:
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,
struct st_table *table_arg,
uint8 dec_arg,bool zero_arg,bool unsigned_arg)
- :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg,
- dec_arg, zero_arg,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)
{}
Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
struct st_table *table_arg, uint8 dec_arg)
- :Field_num((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)
{}
enum_field_types type() const { return FIELD_TYPE_DOUBLE;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }
@@ -646,7 +718,7 @@ public:
};
-/* Everything saved in this will disapper. It will always return NULL */
+/* Everything saved in this will disappear. It will always return NULL */
class Field_null :public Field_str {
static uchar null[1];
@@ -662,9 +734,11 @@ public:
{ null[0]=1; return 0; }
int store(double nr) { null[0]=1; return 0; }
int store(longlong nr) { null[0]=1; return 0; }
+ int store_decimal(const my_decimal *d) { null[0]=1; return 0; }
void reset(void) {}
double val_real(void) { return 0.0;}
longlong val_int(void) { return 0;}
+ my_decimal *val_decimal(my_decimal *) { return 0; }
String *val_str(String *value,String *value2)
{ value2->length(0); return value2;}
int cmp(const char *a, const char *b) { return 0;}
@@ -892,18 +966,18 @@ public:
};
-class Field_string :public Field_str {
+class Field_string :public Field_longstr {
public:
Field_string(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg, CHARSET_INFO *cs)
- :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg,cs) {};
+ :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg, cs) {};
Field_string(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
- struct st_table *table_arg, CHARSET_INFO *cs)
- :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg, cs) {};
+ struct st_table *table_arg, CHARSET_INFO *cs)
+ :Field_longstr((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
+ NONE, field_name_arg, table_arg, cs) {};
enum_field_types type() const
{
@@ -942,7 +1016,7 @@ public:
};
-class Field_varstring :public Field_str {
+class Field_varstring :public Field_longstr {
public:
/* Store number of bytes used to store length (1 or 2) */
uint32 length_bytes;
@@ -952,19 +1026,19 @@ public:
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg, CHARSET_INFO *cs)
- :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg, cs),
- length_bytes(length_bytes_arg)
+ :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
+ unireg_check_arg, field_name_arg, table_arg, cs),
+ length_bytes(length_bytes_arg)
{
if (table)
table->s->varchar_fields++;
}
Field_varstring(uint32 len_arg,bool maybe_null_arg,
- const char *field_name_arg,
- struct st_table *table_arg, CHARSET_INFO *cs)
- :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg, cs),
- length_bytes(len_arg < 256 ? 1 :2)
+ const char *field_name_arg,
+ struct st_table *table_arg, CHARSET_INFO *cs)
+ :Field_longstr((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
+ NONE, field_name_arg, table_arg, cs),
+ length_bytes(len_arg < 256 ? 1 :2)
{
if (table)
table->s->varchar_fields++;
@@ -1012,7 +1086,7 @@ public:
};
-class Field_blob :public Field_str {
+class Field_blob :public Field_longstr {
protected:
uint packlength;
String value; // For temporaries
@@ -1023,8 +1097,8 @@ public:
CHARSET_INFO *cs);
Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
struct st_table *table_arg, CHARSET_INFO *cs)
- :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg, cs),
+ :Field_longstr((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0,
+ NONE, field_name_arg, table_arg, cs),
packlength(4)
{
flags|= BLOB_FLAG;
@@ -1103,9 +1177,7 @@ public:
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
field_cast_enum field_cast_type() { return FIELD_CAST_BLOB; }
- uint32 max_length();
-};
-
+ uint32 max_length();};
#ifdef HAVE_SPATIAL
class Field_geom :public Field_blob {
@@ -1130,7 +1202,7 @@ public:
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr) { return 1; }
int store(longlong nr) { return 1; }
-
+ int store_decimal(const my_decimal *) { return 1; }
void get_key_image(char *buff,uint length,imagetype type);
field_cast_enum field_cast_type() { return FIELD_CAST_GEOM; }
};
@@ -1224,9 +1296,11 @@ public:
int store(const char *to, uint length, CHARSET_INFO *charset);
int store(double nr);
int store(longlong nr);
+ int store_decimal(const my_decimal *);
double val_real(void);
longlong val_int(void);
String *val_str(String*, String *);
+ my_decimal *val_decimal(my_decimal *);
int cmp(const char *a, const char *b)
{ return cmp_binary(a, b); }
int key_cmp(const byte *a, const byte *b)
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 002f059f70b..57161a7063e 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -586,6 +586,9 @@ void field_conv(Field *to,Field *from)
!(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) &&
to->real_type() != FIELD_TYPE_ENUM &&
to->real_type() != FIELD_TYPE_SET &&
+ (to->real_type() != FIELD_TYPE_NEWDECIMAL ||
+ (to->field_length == from->field_length &&
+ (((Field_num*)to)->dec == ((Field_num*)from)->dec))) &&
from->charset() == to->charset() &&
to->table->s->db_low_byte_first == from->table->s->db_low_byte_first)
{ // Identical fields
@@ -623,6 +626,11 @@ void field_conv(Field *to,Field *from)
}
else if (from->result_type() == REAL_RESULT)
to->store(from->val_real());
+ else if (from->result_type() == DECIMAL_RESULT)
+ {
+ my_decimal buff;
+ to->store_decimal(from->val_decimal(&buff));
+ }
else
to->store(from->val_int());
}
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 1665358dbf0..956ac2ef61b 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -703,6 +703,22 @@ static void make_sortkey(register SORTPARAM *param,
#endif
break;
}
+ case DECIMAL_RESULT:
+ {
+ my_decimal dec_buf, *dec_val= item->val_decimal(&dec_buf);
+ if ((maybe_null=item->null_value))
+ {
+ bzero((char*)to, sort_field->length+1);
+ to++;
+ break;
+ }
+ if ((maybe_null=item->maybe_null))
+ *to++=1;
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_val, (byte*)to,
+ item->max_length - (item->decimals ? 1:0),
+ item->decimals);
+ break;
+ }
case REAL_RESULT:
{
double value= item->val_real();
@@ -1212,6 +1228,12 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
sortorder->length=4;
#endif
break;
+ case DECIMAL_RESULT:
+ sortorder->length=
+ my_decimal_get_binary_size(sortorder->item->max_length -
+ (sortorder->item->decimals ? 1 : 0),
+ sortorder->item->decimals);
+ break;
case REAL_RESULT:
sortorder->length=sizeof(double);
break;
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index be493138fd0..052ee0643ee 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -2159,6 +2159,8 @@ get_innobase_type_from_mysql_type(
} else {
return(DATA_MYSQL);
}
+ case FIELD_TYPE_NEWDECIMAL:
+ return(DATA_BINARY);
case FIELD_TYPE_LONG:
case FIELD_TYPE_LONGLONG:
case FIELD_TYPE_TINY:
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 9631b78bca3..ad7e775aacf 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -727,7 +727,7 @@ int ha_myisam::assign_to_keycache(THD* thd, HA_CHECK_OPT *check_opt)
if ((error= mi_assign_to_key_cache(file, map, new_key_cache)))
{
- char buf[80];
+ char buf[STRING_BUFFER_USUAL_SIZE];
my_snprintf(buf, sizeof(buf),
"Failed to flush to index file (errno: %d)", error);
errmsg= buf;
diff --git a/sql/item.cc b/sql/item.cc
index 30e03916a74..17ded05766f 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -44,6 +44,34 @@ void item_init(void)
item_user_lock_init();
}
+
+/*
+TODO: make this functions class dependent
+*/
+bool Item::val_bool()
+{
+ switch(result_type())
+ {
+ case INT_RESULT:
+ return val_int();
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value;
+ my_decimal *val= val_decimal(&decimal_value);
+ if (val)
+ return !my_decimal_is_zero(val);
+ return 0;
+ }
+ case REAL_RESULT:
+ case STRING_RESULT:
+ return val_real() != 0.0;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+}
+
+
Item::Item():
name(0), orig_name(0), name_length(0), fixed(0),
collation(&my_charset_bin, DERIVATION_COERCIBLE)
@@ -72,7 +100,7 @@ Item::Item():
}
/*
- Constructor used by Item_field, Item_*_ref & agregate (sum) functions.
+ Constructor used by Item_field, Item_*_ref & aggregate (sum) functions.
Used for duplicating lists in processing queries with temporary
tables
*/
@@ -148,7 +176,7 @@ bool Item::cleanup_processor(byte *arg)
void Item::rename(char *new_name)
{
/*
- we can compare pointers to names here, bacause if name was not changed,
+ we can compare pointers to names here, because if name was not changed,
pointer will be same
*/
if (!orig_name && new_name != name)
@@ -411,6 +439,55 @@ int Item::save_in_field_no_warnings(Field *field, bool no_conversions)
}
+double Item_splocal::val_real()
+{
+ DBUG_ASSERT(fixed);
+ Item *it= this_item();
+ double ret= it->val_real();
+ Item::null_value= it->null_value;
+ return ret;
+}
+
+
+longlong Item_splocal::val_int()
+{
+ DBUG_ASSERT(fixed);
+ Item *it= this_item();
+ longlong ret= it->val_int();
+ Item::null_value= it->null_value;
+ return ret;
+}
+
+
+String *Item_splocal::val_str(String *sp)
+{
+ DBUG_ASSERT(fixed);
+ Item *it= this_item();
+ String *ret= it->val_str(sp);
+ Item::null_value= it->null_value;
+ return ret;
+}
+
+
+my_decimal *Item_splocal::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed);
+ Item *it= this_item();
+ my_decimal value, *val= it->val_decimal(&value);
+ Item::null_value= it->null_value;
+ return val;
+}
+
+
+bool Item_splocal::is_null()
+{
+ Item *it= this_item();
+ bool ret= it->is_null();
+ Item::null_value= it->null_value;
+ return ret;
+}
+
+
Item *
Item_splocal::this_item()
{
@@ -438,12 +515,38 @@ Item_splocal::type() const
}
+bool Item_splocal::fix_fields(THD *, struct st_table_list *, Item **)
+{
+ Item *it= this_item();
+ DBUG_ASSERT(it->fixed);
+ max_length= it->max_length;
+ decimals= it->decimals;
+ fixed= 1;
+ return FALSE;
+}
+
+
+void Item_splocal::cleanup()
+{
+ fixed= 0;
+}
+
+
+void Item_splocal::print(String *str)
+{
+ str->reserve(m_name.length+8);
+ str->append(m_name.str, m_name.length);
+ str->append('@');
+ str->qs_append(m_offset);
+}
+
+
/*
Aggregate two collations together taking
into account their coercibility (aka derivation):
- 0 == DERIVATION_EXPLICIT - an explicitely written COLLATE clause
+ 0 == DERIVATION_EXPLICIT - an explicitly written COLLATE clause
1 == DERIVATION_NONE - a mix of two different collations
2 == DERIVATION_IMPLICIT - a column
3 == DERIVATION_COERCIBLE - a string constant
@@ -482,7 +585,7 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
/*
We do allow to use binary strings (like BLOBS)
together with character strings.
- Binaries have more precedance than a character
+ Binaries have more precedence than a character
string of the same derivation.
*/
if (collation == &my_charset_bin)
@@ -634,8 +737,8 @@ void Item_field::set_field(Field *field_par)
{
field=result_field=field_par; // for easy coding with fields
maybe_null=field->maybe_null();
- max_length=field_par->field_length;
decimals= field->decimals();
+ max_length= field_par->representation_length();
table_name= *field_par->table_name;
field_name= field_par->field_name;
db_name= field_par->table->s->db;
@@ -743,6 +846,7 @@ String *Item_field::val_str(String *str)
return field->val_str(str,&str_value);
}
+
double Item_field::val_real()
{
DBUG_ASSERT(fixed == 1);
@@ -751,6 +855,7 @@ double Item_field::val_real()
return field->val_real();
}
+
longlong Item_field::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -760,6 +865,14 @@ longlong Item_field::val_int()
}
+my_decimal *Item_field::val_decimal(my_decimal *decimal_value)
+{
+ if ((null_value= field->is_null()))
+ return 0;
+ return field->val_decimal(decimal_value);
+}
+
+
String *Item_field::str_result(String *str)
{
if ((null_value=result_field->is_null()))
@@ -814,6 +927,40 @@ longlong Item_field::val_int_result()
}
+my_decimal *Item_field::val_decimal_result(my_decimal *decimal_value)
+{
+ if ((null_value= result_field->is_null()))
+ return 0;
+ return result_field->val_decimal(decimal_value);
+}
+
+
+bool Item_field::val_bool_result()
+{
+ if ((null_value= result_field->is_null()))
+ return FALSE;
+ switch (result_field->result_type())
+ {
+ case INT_RESULT:
+ return result_field->val_int();
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value;
+ my_decimal *val= result_field->val_decimal(&decimal_value);
+ if (val)
+ return !my_decimal_is_zero(val);
+ return 0;
+ }
+ case REAL_RESULT:
+ case STRING_RESULT:
+ return result_field->val_real() != 0.0;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+}
+
+
bool Item_field::eq(const Item *item, bool binary_cmp) const
{
if (item->type() != FIELD_ITEM)
@@ -872,10 +1019,17 @@ Item_int::Item_int(const char *str_arg, uint length)
value= my_strtoll10(str_arg, &end_ptr, &error);
max_length= (uint) (end_ptr - str_arg);
name= (char*) str_arg;
+ unsigned_flag= value > 0;
fixed= 1;
}
+my_decimal *Item_int::val_decimal(my_decimal *decimal_value)
+{
+ int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_value);
+ return decimal_value;
+}
+
String *Item_int::val_str(String *str)
{
// following assert is redundant, because fixed=1 assigned in constructor
@@ -916,7 +1070,98 @@ void Item_uint::print(String *str)
}
-String *Item_real::val_str(String *str)
+Item_decimal::Item_decimal(const char *str_arg, uint length,
+ CHARSET_INFO *charset)
+{
+ 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();
+}
+
+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();
+}
+
+
+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();
+}
+
+
+Item_decimal::Item_decimal(const char *str, const my_decimal *val_arg,
+ uint decimal_par, uint length)
+{
+ my_decimal2decimal(val_arg, &decimal_value);
+ name= (char*) str;
+ decimals= (uint8) decimal_par;
+ max_length= length;
+ fixed= 1;
+ unsigned_flag= !decimal_value.sign();
+}
+
+
+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();
+}
+
+
+Item_decimal::Item_decimal(const char *bin, int precision, int 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();
+}
+
+
+longlong Item_decimal::val_int()
+{
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &result);
+ return result;
+}
+
+double Item_decimal::val_real()
+{
+ double result;
+ my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result);
+ return result;
+}
+
+String *Item_decimal::val_str(String *result)
+{
+ result->set_charset(&my_charset_bin);
+ my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, result);
+ return result;
+}
+
+void Item_decimal::print(String *str)
+{
+ my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, &str_value);
+ str->append(str_value);
+}
+
+
+String *Item_float::val_str(String *str)
{
// following assert is redundant, because fixed=1 assigned in constructor
DBUG_ASSERT(fixed == 1);
@@ -925,6 +1170,15 @@ String *Item_real::val_str(String *str)
}
+my_decimal *Item_float::val_decimal(my_decimal *decimal_value)
+{
+ // following assert is redundant, because fixed=1 assigned in constructor
+ DBUG_ASSERT(fixed == 1);
+ double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value);
+ return (decimal_value);
+}
+
+
void Item_string::print(String *str)
{
str->append('_');
@@ -934,8 +1188,20 @@ void Item_string::print(String *str)
str->append('\'');
}
+
+my_decimal *Item_string::val_decimal(my_decimal *decimal_value)
+{
+ /* following assert is redundant, because fixed=1 assigned in constructor */
+ DBUG_ASSERT(fixed == 1);
+ string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value);
+ return (decimal_value);
+}
+
+
bool Item_null::eq(const Item *item, bool binary_cmp) const
{ return item->type() == type(); }
+
+
double Item_null::val_real()
{
// following assert is redundant, because fixed=1 assigned in constructor
@@ -959,6 +1225,11 @@ String *Item_null::val_str(String *str)
return 0;
}
+my_decimal *Item_null::val_decimal(my_decimal *decimal_value)
+{
+ return 0;
+}
+
Item *Item_null::safe_charset_converter(CHARSET_INFO *tocs)
{
@@ -1005,7 +1276,6 @@ void Item_param::set_null()
{
DBUG_ENTER("Item_param::set_null");
/* These are cleared after each execution by reset() method */
- max_length= 0;
null_value= 1;
/*
Because of NULL and string values we need to set max_length for each new
@@ -1042,6 +1312,32 @@ void Item_param::set_double(double d)
/*
+ Set decimal parameter value from string.
+
+ SYNOPSIS
+ set_decimal()
+ str - character string
+ length - string length
+
+ NOTE
+ as we use character strings to send decimal values in
+ binary protocol, we use str2my_decimal to convert it to
+ internal decimal value.
+*/
+void Item_param::set_decimal(const char *str, ulong length)
+{
+ DBUG_ENTER("Item_param::set_decimal");
+
+ str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value);
+ state= DECIMAL_VALUE;
+ decimals= decimal_value.frac;
+ max_length= decimal_value.intg + decimals + 2;
+ maybe_null= 0;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
Set parameter value from TIME value.
SYNOPSIS
@@ -1094,6 +1390,7 @@ bool Item_param::set_str(const char *str, ulong length)
&dummy_errors))
DBUG_RETURN(TRUE);
state= STRING_VALUE;
+ max_length= length;
maybe_null= 0;
/* max_length and decimals are set after charset conversion */
/* sic: str may be not null-terminated, don't add DBUG_PRINT here */
@@ -1133,7 +1430,7 @@ bool Item_param::set_longdata(const char *str, ulong length)
RETURN
0 OK
- 1 Out of memort
+ 1 Out of memory
*/
bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
@@ -1179,6 +1476,15 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
DBUG_RETURN(1);
break;
}
+ case DECIMAL_RESULT:
+ {
+ const my_decimal *ent_value= (const my_decimal *)entry->value;
+ my_decimal2decimal(ent_value, &decimal_value);
+ state= DECIMAL_VALUE;
+ decimals= ent_value->frac;
+ max_length= ent_value->intg + decimals + 2;
+ break;
+ }
default:
DBUG_ASSERT(0);
set_null();
@@ -1210,7 +1516,7 @@ void Item_param::reset()
str_value.length(0);
str_value_ptr.length(0);
/*
- We must prevent all charset conversions untill data has been written
+ We must prevent all charset conversions until data has been written
to the binary log.
*/
str_value.set_charset(&my_charset_bin);
@@ -1238,6 +1544,8 @@ int Item_param::save_in_field(Field *field, bool no_conversions)
return field->store(value.integer);
case REAL_VALUE:
return field->store(value.real);
+ case DECIMAL_VALUE:
+ return field->store_decimal(&decimal_value);
case TIME_VALUE:
field->store_time(&value.time, value.time.time_type);
return 0;
@@ -1288,6 +1596,12 @@ double Item_param::val_real()
return value.real;
case INT_VALUE:
return (double) value.integer;
+ case DECIMAL_VALUE:
+ {
+ double result;
+ my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &result);
+ return result;
+ }
case STRING_VALUE:
case LONG_DATA_VALUE:
{
@@ -1318,6 +1632,12 @@ longlong Item_param::val_int()
return (longlong) (value.real + (value.real > 0 ? 0.5 : -0.5));
case INT_VALUE:
return value.integer;
+ case DECIMAL_VALUE:
+ {
+ longlong i;
+ my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &i);
+ return i;
+ }
case STRING_VALUE:
case LONG_DATA_VALUE:
{
@@ -1336,6 +1656,36 @@ longlong Item_param::val_int()
}
+my_decimal *Item_param::val_decimal(my_decimal *dec)
+{
+ switch (state) {
+ case DECIMAL_VALUE:
+ return &decimal_value;
+ case REAL_VALUE:
+ double2my_decimal(E_DEC_FATAL_ERROR, value.real, dec);
+ return dec;
+ case INT_VALUE:
+ int2my_decimal(E_DEC_FATAL_ERROR, value.integer, unsigned_flag, dec);
+ return dec;
+ case STRING_VALUE:
+ case LONG_DATA_VALUE:
+ string2my_decimal(E_DEC_FATAL_ERROR, &str_value, dec);
+ return dec;
+ case TIME_VALUE:
+ {
+ longlong i= (longlong) TIME_to_ulonglong(&value.time);
+ int2my_decimal(E_DEC_FATAL_ERROR, i, 0, dec);
+ return dec;
+ }
+ case NULL_VALUE:
+ return 0;
+ default:
+ DBUG_ASSERT(0);
+ }
+ return 0;
+}
+
+
String *Item_param::val_str(String* str)
{
switch (state) {
@@ -1348,6 +1698,11 @@ String *Item_param::val_str(String* str)
case INT_VALUE:
str->set(value.integer, &my_charset_bin);
return str;
+ case DECIMAL_VALUE:
+ if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
+ 0, 0, 0, str) <= 1)
+ return str;
+ return NULL;
case TIME_VALUE:
{
if (str->reserve(MAX_DATE_STRING_REP_LENGTH))
@@ -1380,6 +1735,11 @@ const String *Item_param::query_val_str(String* str) const
case REAL_VALUE:
str->set(value.real, NOT_FIXED_DEC, &my_charset_bin);
break;
+ case DECIMAL_VALUE:
+ if (my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value,
+ 0, 0, 0, str) > 1)
+ return &my_null_string;
+ break;
case TIME_VALUE:
{
char *buf, *ptr;
@@ -1474,7 +1834,7 @@ void Item_param::print(String *str)
}
else
{
- char buffer[80];
+ char buffer[STRING_BUFFER_USUAL_SIZE];
String tmp(buffer, sizeof(buffer), &my_charset_bin);
const String *res;
res= query_val_str(&tmp);
@@ -1505,6 +1865,17 @@ String *Item_copy_string::val_str(String *str)
}
+my_decimal *Item_copy_string::val_decimal(my_decimal *decimal_value)
+{
+ // Item_copy_string is used without fix_fields call
+ if (null_value)
+ return 0;
+ string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value);
+ return (decimal_value);
+}
+
+
+
int Item_copy_string::save_in_field(Field *field, bool no_conversions)
{
if (null_value)
@@ -1548,6 +1919,24 @@ longlong Item_ref_null_helper::val_int()
}
+my_decimal *Item_ref_null_helper::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ my_decimal *val= (*ref)->val_decimal_result(decimal_value);
+ owner->was_null|= null_value= (*ref)->null_value;
+ return val;
+}
+
+
+bool Item_ref_null_helper::val_bool()
+{
+ DBUG_ASSERT(fixed == 1);
+ bool val= (*ref)->val_bool_result();
+ owner->was_null|= null_value= (*ref)->null_value;
+ return val;
+}
+
+
String* Item_ref_null_helper::val_str(String* s)
{
DBUG_ASSERT(fixed == 1);
@@ -1931,7 +2320,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE)
{
if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel)))
- return TRUE; /* Some error occured (e.g. ambigous names). */
+ return TRUE; /* Some error occurred (e.g. ambiguous names). */
if (ref != not_found_item)
{
DBUG_ASSERT(*ref && (*ref)->fixed);
@@ -1995,7 +2384,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
rf is Item_ref => never substitute other items (in this case)
during fix_fields() => we can use rf after fix_fields()
*/
- if (rf->fix_fields(thd, tables, reference) || rf->check_cols(1))
+ if (!rf->fixed &&
+ rf->fix_fields(thd, tables, reference) || rf->check_cols(1))
return TRUE;
mark_as_dependent(thd, last, current_sel, rf);
@@ -2016,7 +2406,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
rf is Item_ref => never substitute other items (in this case)
during fix_fields() => we can use rf after fix_fields()
*/
- return rf->fix_fields(thd, tables, reference) || rf->check_cols(1);
+ return (!rf->fixed &&
+ rf->fix_fields(thd, tables, reference) || rf->check_cols(1));
}
}
}
@@ -2089,7 +2480,7 @@ void Item_field::cleanup()
Item_ident::cleanup();
/*
Even if this object was created by direct link to field in setup_wild()
- it will be linked correctly next tyme by name of field and table alias.
+ it will be linked correctly next time by name of field and table alias.
I.e. we can drop 'field'.
*/
field= result_field= 0;
@@ -2263,9 +2654,17 @@ void Item_empty_string::make_field(Send_field *tmp_field)
enum_field_types Item::field_type() const
{
- return ((result_type() == STRING_RESULT) ? MYSQL_TYPE_VARCHAR :
- (result_type() == INT_RESULT) ? FIELD_TYPE_LONGLONG :
- FIELD_TYPE_DOUBLE);
+ switch (result_type())
+ {
+ case STRING_RESULT: return MYSQL_TYPE_VARCHAR;
+ case INT_RESULT: return FIELD_TYPE_LONGLONG;
+ case DECIMAL_RESULT: return FIELD_TYPE_NEWDECIMAL;
+ case REAL_RESULT: return FIELD_TYPE_DOUBLE;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ return FIELD_TYPE_VAR_STRING;
+ };
}
@@ -2318,6 +2717,11 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
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,
+ Field::NONE, name, table, decimals, 0,
+ unsigned_flag);
case MYSQL_TYPE_TINY:
return new Field_tiny((char*) 0, max_length, null_ptr, 0, Field::NONE,
name, table, 0, unsigned_flag);
@@ -2453,7 +2857,7 @@ int Item_null::save_in_field(Field *field, bool no_conversions)
field Field where we want to store NULL
RETURN VALUES
- 0 ok
+ 0 OK
1 Field doesn't support NULL values
*/
@@ -2492,6 +2896,15 @@ int Item::save_in_field(Field *field, bool no_conversions)
field->set_notnull();
error=field->store(nr);
}
+ else if (result_type() == DECIMAL_RESULT)
+ {
+ my_decimal decimal_value;
+ my_decimal *value= val_decimal(&decimal_value);
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ error=field->store_decimal(value);
+ }
else
{
longlong nr=val_int();
@@ -2533,9 +2946,18 @@ int Item_int::save_in_field(Field *field, bool no_conversions)
return field->store(nr);
}
+
+int Item_decimal::save_in_field(Field *field, bool no_conversions)
+{
+ field->set_notnull();
+ return field->store_decimal(&decimal_value);
+}
+
+
Item_num *Item_uint::neg()
{
- return new Item_real(name, - ((double) value), 0, max_length);
+ Item_decimal *item= new Item_decimal(value, 0);
+ return item->neg();
}
@@ -2544,7 +2966,7 @@ Item_num *Item_uint::neg()
value is not a true double value (overflow)
*/
-Item_real::Item_real(const char *str_arg, uint length)
+Item_float::Item_float(const char *str_arg, uint length)
{
int error;
char *end_not_used;
@@ -2566,7 +2988,7 @@ Item_real::Item_real(const char *str_arg, uint length)
}
-int Item_real::save_in_field(Field *field, bool no_conversions)
+int Item_float::save_in_field(Field *field, bool no_conversions)
{
double nr= val_real();
if (null_value)
@@ -2576,7 +2998,7 @@ int Item_real::save_in_field(Field *field, bool no_conversions)
}
-void Item_real::print(String *str)
+void Item_float::print(String *str)
{
if (presentation)
{
@@ -2639,6 +3061,16 @@ longlong Item_hex_string::val_int()
}
+my_decimal *Item_hex_string::val_decimal(my_decimal *decimal_value)
+{
+ // following assert is redundant, because fixed=1 assigned in constructor
+ DBUG_ASSERT(fixed == 1);
+ ulonglong value= (ulonglong)val_int();
+ int2my_decimal(E_DEC_FATAL_ERROR, value, TRUE, decimal_value);
+ return (decimal_value);
+}
+
+
int Item_hex_string::save_in_field(Field *field, bool no_conversions)
{
int error;
@@ -2728,6 +3160,7 @@ bool Item::send(Protocol *protocol, String *buffer)
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_NEWDECIMAL:
{
String *res;
if ((res=val_str(buffer)))
@@ -2818,6 +3251,20 @@ bool Item_field::send(Protocol *protocol, String *buffer)
}
+Item_ref::Item_ref(Item **item, const char *table_name_par,
+ const char *field_name_par)
+ :Item_ident(NullS, table_name_par, field_name_par), result_field(0),
+ ref(item)
+{
+ /*
+ This constructor used to create some internals references over fixed items
+ */
+ DBUG_ASSERT(ref);
+ if (*ref)
+ set_properties();
+}
+
+
/*
Resolve the name of a reference to a column reference.
@@ -2888,7 +3335,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
Item **group_by_ref= NULL;
if (!(ref= resolve_ref_in_select_and_group(thd, this, current_sel)))
- return TRUE; /* Some error occured (e.g. ambigous names). */
+ return TRUE; /* Some error occurred (e.g. ambiguous names). */
if (ref == not_found_item) /* This reference was not resolved. */
{
@@ -2918,7 +3365,7 @@ bool Item_ref::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference)
if (outer_sel->resolve_mode == SELECT_LEX::SELECT_MODE)
{
if (!(ref= resolve_ref_in_select_and_group(thd, this, outer_sel)))
- return TRUE; /* Some error occured (e.g. ambigous names). */
+ return TRUE; /* Some error occurred (e.g. ambiguous names). */
if (ref != not_found_item)
{
DBUG_ASSERT(*ref && (*ref)->fixed);
@@ -3145,6 +3592,106 @@ String *Item_ref::str_result(String* str)
}
+my_decimal *Item_ref::val_decimal_result(my_decimal *decimal_value)
+{
+ if (result_field)
+ {
+ if ((null_value= result_field->is_null()))
+ return 0;
+ return result_field->val_decimal(decimal_value);
+ }
+ return val_decimal(decimal_value);
+}
+
+
+bool Item_ref::val_bool_result()
+{
+ if (result_field)
+ {
+ if ((null_value= result_field->is_null()))
+ return 0;
+ switch (result_field->result_type())
+ {
+ case INT_RESULT:
+ return result_field->val_int();
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value;
+ my_decimal *val= result_field->val_decimal(&decimal_value);
+ if (val)
+ return !my_decimal_is_zero(val);
+ return 0;
+ }
+ case REAL_RESULT:
+ case STRING_RESULT:
+ return result_field->val_real() != 0.0;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+ return val_bool();
+}
+
+
+double Item_ref::val_real()
+{
+ DBUG_ASSERT(fixed);
+ double tmp=(*ref)->val_result();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+longlong Item_ref::val_int()
+{
+ DBUG_ASSERT(fixed);
+ longlong tmp=(*ref)->val_int_result();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+bool Item_ref::val_bool()
+{
+ DBUG_ASSERT(fixed);
+ bool tmp= (*ref)->val_bool_result();
+ null_value= (*ref)->null_value;
+ return tmp;
+}
+
+
+String *Item_ref::val_str(String* tmp)
+{
+ DBUG_ASSERT(fixed);
+ tmp=(*ref)->str_result(tmp);
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+bool Item_ref::is_null()
+{
+ DBUG_ASSERT(fixed);
+ (void) (*ref)->val_int_result();
+ return (*ref)->null_value;
+}
+
+
+bool Item_ref::get_date(TIME *ltime,uint fuzzydate)
+{
+ return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
+}
+
+
+my_decimal *Item_ref::val_decimal(my_decimal *decimal_value)
+{
+ my_decimal *val= (*ref)->val_decimal(decimal_value);
+ null_value= (*ref)->null_value;
+ return val;
+}
+
+
void Item_ref_null_helper::print(String *str)
{
str->append("<ref_null_helper>(", 18);
@@ -3156,6 +3703,59 @@ void Item_ref_null_helper::print(String *str)
}
+double Item_direct_ref::val_real()
+{
+ double tmp=(*ref)->val_real();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+longlong Item_direct_ref::val_int()
+{
+ longlong tmp=(*ref)->val_int();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+String *Item_direct_ref::val_str(String* tmp)
+{
+ tmp=(*ref)->val_str(tmp);
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+my_decimal *Item_direct_ref::val_decimal(my_decimal *decimal_value)
+{
+ my_decimal *tmp= (*ref)->val_decimal(decimal_value);
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+bool Item_direct_ref::val_bool()
+{
+ bool tmp= (*ref)->val_bool();
+ null_value=(*ref)->null_value;
+ return tmp;
+}
+
+
+bool Item_direct_ref::is_null()
+{
+ (void) (*ref)->val_int();
+ return (*ref)->null_value;
+}
+
+
+bool Item_direct_ref::get_date(TIME *ltime,uint fuzzydate)
+{
+ return (null_value=(*ref)->get_date(ltime,fuzzydate));
+}
+
+
void Item_null_helper::print(String *str)
{
str->append("<null_helper>(", 14);
@@ -3380,6 +3980,9 @@ Item_result item_cmp_type(Item_result a,Item_result b)
return INT_RESULT;
else if (a == ROW_RESULT || b == ROW_RESULT)
return ROW_RESULT;
+ if ((a == INT_RESULT || a == DECIMAL_RESULT) &&
+ (b == INT_RESULT || b == DECIMAL_RESULT))
+ return DECIMAL_RESULT;
return REAL_RESULT;
}
@@ -3394,7 +3997,9 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
item->result_type());
char *name=item->name; // Alloced by sql_alloc
- if (res_type == STRING_RESULT)
+ switch (res_type)
+ {
+ case STRING_RESULT:
{
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff),&my_charset_bin),*result;
@@ -3407,22 +4012,40 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
char *tmp_str= sql_strmake(result->ptr(), length);
new_item= new Item_string(name, tmp_str, length, result->charset());
}
+ break;
}
- else if (res_type == INT_RESULT)
+ case INT_RESULT:
{
longlong result=item->val_int();
uint length=item->max_length;
bool null_value=item->null_value;
new_item= (null_value ? (Item*) new Item_null(name) :
(Item*) new Item_int(name, result, length));
+ break;
}
- else
+ case REAL_RESULT:
{ // It must REAL_RESULT
double result= item->val_real();
uint length=item->max_length,decimals=item->decimals;
bool null_value=item->null_value;
new_item= (null_value ? (Item*) new Item_null(name) : (Item*)
- new Item_real(name, result, decimals, length));
+ new Item_float(name, result, decimals, length));
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value;
+ my_decimal *result= item->val_decimal(&decimal_value);
+ uint length= item->max_length, decimals= item->decimals;
+ bool null_value= item->null_value;
+ new_item= (null_value ?
+ (Item*) new Item_null(name) :
+ (Item*) new Item_decimal(name, result, length, decimals));
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
}
if (new_item)
thd->change_item_tree(ref, new_item);
@@ -3453,6 +4076,16 @@ bool field_is_equal_to_item(Field *field,Item *item)
}
if (res_type == INT_RESULT)
return 1; // Both where of type int
+ if (res_type == DECIMAL_RESULT)
+ {
+ my_decimal item_buf, *item_val,
+ field_buf, *field_val;
+ item_val= item->val_decimal(&item_buf);
+ if (item->null_value)
+ return 1; // This must be true
+ field_val= field->val_decimal(&field_buf);
+ return !my_decimal_cmp(item_val, field_val);
+ }
double result= item->val_real();
if (item->null_value)
return 1;
@@ -3467,6 +4100,8 @@ Item_cache* Item_cache::get_cache(Item_result type)
return new Item_cache_int();
case REAL_RESULT:
return new Item_cache_real();
+ case DECIMAL_RESULT:
+ return new Item_cache_decimal();
case STRING_RESULT:
return new Item_cache_str();
case ROW_RESULT:
@@ -3494,6 +4129,23 @@ void Item_cache_int::store(Item *item)
{
value= item->val_int_result();
null_value= item->null_value;
+ unsigned_flag= item->unsigned_flag;
+}
+
+
+String *Item_cache_int::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ str->set(value, default_charset());
+ return str;
+}
+
+
+my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val)
+{
+ DBUG_ASSERT(fixed == 1);
+ int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val);
+ return decimal_val;
}
@@ -3504,6 +4156,69 @@ void Item_cache_real::store(Item *item)
}
+longlong Item_cache_real::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ return (longlong) (value+(value > 0 ? 0.5 : -0.5));
+}
+
+
+String* Item_cache_real::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ str->set(value, decimals, default_charset());
+ return str;
+}
+
+
+my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val)
+{
+ DBUG_ASSERT(fixed == 1);
+ double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
+ return decimal_val;
+}
+
+
+void Item_cache_decimal::store(Item *item)
+{
+ my_decimal *val= item->val_decimal_result(&decimal_value);
+ if (val != &decimal_value)
+ my_decimal2decimal(val, &decimal_value);
+ null_value= item->null_value;
+}
+
+double Item_cache_decimal::val_real()
+{
+ DBUG_ASSERT(fixed);
+ double res;
+ my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res);
+ return res;
+}
+
+longlong Item_cache_decimal::val_int()
+{
+ DBUG_ASSERT(fixed);
+ longlong res;
+ my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res);
+ return res;
+}
+
+String* Item_cache_decimal::val_str(String *str)
+{
+ DBUG_ASSERT(fixed);
+ my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE,
+ &decimal_value);
+ my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, str);
+ return str;
+}
+
+my_decimal *Item_cache_decimal::val_decimal(my_decimal *val)
+{
+ DBUG_ASSERT(fixed);
+ return &decimal_value;
+}
+
+
void Item_cache_str::store(Item *item)
{
value_buff.set(buffer, sizeof(buffer), item->collation.collation);
@@ -3525,7 +4240,6 @@ void Item_cache_str::store(Item *item)
}
}
-
double Item_cache_str::val_real()
{
DBUG_ASSERT(fixed == 1);
@@ -3549,6 +4263,16 @@ longlong Item_cache_str::val_int()
return (longlong)0;
}
+my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (value)
+ string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val);
+ else
+ decimal_val= 0;
+ return decimal_val;
+}
+
bool Item_cache_row::allocate(uint num)
{
@@ -3701,18 +4425,18 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item, TABLE *table)
/*
- STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT
+ STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT DECIMAL_RESULT
ROW_RESULT should never appear in Item_type_holder::join_types,
but it is included in following table just to make table full
(there DBUG_ASSERT in function to catch ROW_RESULT)
*/
-static Item_result type_convertor[4][4]=
-{{STRING_RESULT, STRING_RESULT, STRING_RESULT, ROW_RESULT},
- {STRING_RESULT, REAL_RESULT, REAL_RESULT, ROW_RESULT},
- {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT},
- {ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT}};
-
+static Item_result type_convertor[5][5]=
+{{STRING_RESULT, STRING_RESULT, STRING_RESULT, ROW_RESULT, STRING_RESULT},
+ {STRING_RESULT, REAL_RESULT, REAL_RESULT, ROW_RESULT, REAL_RESULT},
+ {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT, DECIMAL_RESULT},
+ {ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT},
+ {STRING_RESULT, REAL_RESULT, DECIMAL_RESULT, ROW_RESULT, DECIMAL_RESULT}};
/*
Values of 'from' field can be stored in 'to' field.
@@ -3730,6 +4454,12 @@ static Item_result type_convertor[4][4]=
inline bool is_attr_compatible(Item *from, Item *to)
{
return ((to->max_length >= from->max_length) &&
+ ((to->result_type() != DECIMAL_RESULT &&
+ to->result_type() != REAL_RESULT &&
+ to->result_type() != INT_RESULT) ||
+ (to->decimals >= from->decimals) &&
+ ((to->max_length - to->decimals) >=
+ (from->max_length - from->decimals))) &&
(to->maybe_null || !from->maybe_null) &&
(to->result_type() != STRING_RESULT ||
from->result_type() != STRING_RESULT ||
@@ -3778,6 +4508,9 @@ bool Item_type_holder::join_types(THD *thd, Item *item, TABLE *table)
if (use_new_field ||
(new_result_type != item_type) || (new_length > max_length) ||
(!maybe_null && item->maybe_null) ||
+ ((new_result_type == REAL_RESULT || new_result_type == DECIMAL_RESULT) &&
+ (decimals < item->decimals ||
+ (max_length - decimals) < (new_length - item->decimals))) ||
(item_type == STRING_RESULT &&
collation.collation != item->collation.collation))
{
@@ -3805,8 +4538,20 @@ bool Item_type_holder::join_types(THD *thd, Item *item, TABLE *table)
return 1;
}
- max_length= max(max_length, new_length);
- decimals= max(decimals, item->decimals);
+ if (new_result_type == DECIMAL_RESULT)
+ {
+ int intp1= new_length - item->decimals;
+ int intp2= max_length - decimals;
+ max_length= max(intp1, intp2);
+ decimals= max(decimals, item->decimals);
+ /* can't be overflow because it work only for decimals (no strings) */
+ max_length+= decimals;
+ }
+ else
+ {
+ max_length= max(max_length, new_length);
+ decimals= max(decimals, item->decimals);
+ }
maybe_null|= item->maybe_null;
item_type= new_result_type;
}
@@ -3823,6 +4568,7 @@ uint32 Item_type_holder::real_length(Item *item)
switch (item->result_type())
{
case STRING_RESULT:
+ case DECIMAL_RESULT:
return item->max_length;
case REAL_RESULT:
return 53;
@@ -3848,6 +4594,11 @@ longlong Item_type_holder::val_int()
return 0;
}
+my_decimal *Item_type_holder::val_decimal(my_decimal *)
+{
+ DBUG_ASSERT(0); // should never be called
+ return 0;
+}
String *Item_type_holder::val_str(String*)
{
diff --git a/sql/item.h b/sql/item.h
index 8209c566025..ccbc00470e5 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -27,7 +27,7 @@ class Item_field;
/*
"Declared Type Collation"
- A combination of collation and its deriviation.
+ A combination of collation and its derivation.
*/
enum Derivation
@@ -45,7 +45,7 @@ enum Derivation
MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value
(i.e. constant).
MY_COLL_ALLOW_CONV - allow any kind of conversion
- (combintion of the above two)
+ (combination of the above two)
MY_COLL_DISALLOW_NONE - don't allow return DERIVATION_NONE
(e.g. when aggregating for comparison)
MY_COLL_CMP_CONV - combination of MY_COLL_ALLOW_CONV
@@ -130,7 +130,7 @@ public:
PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM,
FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM,
SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER,
- PARAM_ITEM, TRIGGER_FIELD_ITEM};
+ PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM};
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
@@ -156,11 +156,11 @@ public:
// alloc & destruct is done as start of select using sql_alloc
Item();
/*
- Constructor used by Item_field, Item_ref & agregate (sum) functions.
+ Constructor used by Item_field, Item_ref & aggregate (sum) functions.
Used for duplicating lists in processing queries with temporary
tables
Also it used for Item_cond_and/Item_cond_or for creating
- top AND/OR ctructure of WHERE clause to protect it of
+ top AND/OR structure of WHERE clause to protect it of
optimisation changes in prepared statements
*/
Item(THD *thd, Item *item);
@@ -193,40 +193,107 @@ public:
virtual enum_field_types field_type() const;
virtual enum Type type() const =0;
/* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */
+ /*
+ Return double precision floating point representation of item.
+
+ SYNOPSIS
+ val_real()
+
+ RETURN
+ In case of NULL value return 0.0 and set null_value flag to TRUE.
+ If value is not null null_value flag will be reset to FALSE.
+ */
virtual double val_real()=0;
+ /*
+ Return integer representation of item.
+
+ SYNOPSIS
+ val_int()
+
+ RETURN
+ In case of NULL value return 0 and set null_value flag to TRUE.
+ If value is not null null_value flag will be reset to FALSE.
+ */
virtual longlong val_int()=0;
/*
Return string representation of this item object.
- The argument to val_str() is an allocated buffer this or any
- nested Item object can use to store return value of this method.
- This buffer should only be used if the item itself doesn't have an
- own String buffer. In case when the item maintains it's own string
- buffer, it's preferrable to return it instead to minimize number of
- mallocs/memcpys.
- The caller of this method can modify returned string, but only in
- case when it was allocated on heap, (is_alloced() is true). This
- allows the caller to efficiently use a buffer allocated by a child
- without having to allocate a buffer of it's own. The buffer, given
- to val_str() as agrument, belongs to the caller and is later used
- by the caller at it's own choosing.
- A few implications from the above:
- - unless you return a string object which only points to your buffer
- but doesn't manages it you should be ready that it will be
- modified.
- - even for not allocated strings (is_alloced() == false) the caller
- can change charset (see Item_func_{typecast/binary}. XXX: is this
- a bug?
- - still you should try to minimize data copying and return internal
- object whenever possible.
+ SYNOPSIS
+ val_str()
+ str an allocated buffer this or any nested Item object can use to
+ store return value of this method.
+
+ NOTE
+ Buffer passed via argument should only be used if the item itself
+ doesn't have an own String buffer. In case when the item maintains
+ it's own string buffer, it's preferable to return it instead to
+ minimize number of mallocs/memcpys.
+ The caller of this method can modify returned string, but only in case
+ when it was allocated on heap, (is_alloced() is true). This allows
+ the caller to efficiently use a buffer allocated by a child without
+ having to allocate a buffer of it's own. The buffer, given to
+ val_str() as argument, belongs to the caller and is later used by the
+ caller at it's own choosing.
+ A few implications from the above:
+ - unless you return a string object which only points to your buffer
+ but doesn't manages it you should be ready that it will be
+ modified.
+ - even for not allocated strings (is_alloced() == false) the caller
+ can change charset (see Item_func_{typecast/binary}. XXX: is this
+ a bug?
+ - still you should try to minimize data copying and return internal
+ object whenever possible.
+
+ RETURN
+ In case of NULL value return 0 (NULL pointer) and set null_value flag
+ to TRUE.
+ If value is not null null_value flag will be reset to FALSE.
+ */
+ virtual String *val_str(String *str)=0;
+ /*
+ Return decimal representation of item with fixed point.
+
+ SYNOPSIS
+ val_decimal()
+ decimal_buffer buffer which can be used by Item for returning value
+ (but can be not)
+
+ NOTE
+ Returned value should not be changed if it is not the same which was
+ passed via argument.
+
+ RETURN
+ Return pointer on my_decimal (it can be other then passed via argument)
+ if value is not NULL (null_value flag will be reset to FALSE).
+ In case of NULL value it return 0 pointer and set null_value flag
+ to TRUE.
+ */
+ virtual my_decimal *val_decimal(my_decimal *decimal_buffer)= 0;
+ /*
+ Return boolean value of item.
+
+ RETURN
+ FALSE value is false or NULL
+ TRUE value is true (not equal to 0)
*/
- virtual String *val_str(String*)=0;
+ bool val_bool();
virtual Field *get_tmp_table_field() { return 0; }
virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
virtual const char *full_name() const { return name ? name : "???"; }
+
+ /*
+ *result* family of methods is analog of *val* family (see above) but
+ return value of result_field of item if it is present. If Item have not
+ result field, it return val(). This methods set null_value flag in same
+ way as *val* methods do it.
+ */
virtual double val_result() { return val_real(); }
virtual longlong val_int_result() { return val_int(); }
virtual String *str_result(String* tmp) { return val_str(tmp); }
+ virtual my_decimal *val_decimal_result(my_decimal *val)
+ { return val_decimal(val); }
+ virtual bool val_bool_result() { return val_bool(); }
+
/* bit map of tables used by item */
virtual table_map used_tables() const { return (table_map) 0L; }
/*
@@ -287,14 +354,14 @@ public:
virtual void top_level_item() {}
/*
set field of temporary table for Item which can be switched on temporary
- table during query processing (groupping and so on)
+ table during query processing (grouping and so on)
*/
virtual void set_result_field(Field *field) {}
virtual bool is_result_field() { return 0; }
virtual bool is_bool_func() { return 0; }
virtual void save_in_result_field(bool no_conversions) {}
/*
- set value of aggegate function in case of no rows for groupping were found
+ set value of aggregate function in case of no rows for grouping were found
*/
virtual void no_rows_in_result() {}
virtual Item *copy_or_same(THD *thd) { return this; }
@@ -368,6 +435,9 @@ public:
Item *this_item();
Item *this_const_item() const;
+ bool fix_fields(THD *, struct st_table_list *, Item **);
+ void cleanup();
+
inline uint get_offset()
{
return m_offset;
@@ -377,37 +447,12 @@ public:
// the item in the frame
enum Type type() const;
- inline double val_real()
- {
- Item *it= this_item();
- double ret= it->val_real();
- Item::null_value= it->null_value;
- return ret;
- }
-
- inline longlong val_int()
- {
- Item *it= this_item();
- longlong ret= it->val_int();
- Item::null_value= it->null_value;
- return ret;
- }
-
- inline String *val_str(String *sp)
- {
- Item *it= this_item();
- String *ret= it->val_str(sp);
- Item::null_value= it->null_value;
- return ret;
- }
-
- inline bool is_null()
- {
- Item *it= this_item();
- bool ret= it->is_null();
- Item::null_value= it->null_value;
- return ret;
- }
+ double val_real();
+ longlong val_int();
+ String *val_str(String *sp);
+ my_decimal *val_decimal(my_decimal *);
+ inline bool is_null();
+ void print(String *str);
inline void make_field(Send_field *field)
{
@@ -432,14 +477,6 @@ public:
return this_item()->save_in_field(field, no_conversions);
}
- void print(String *str)
- {
- str->reserve(m_name.length+8);
- str->append(m_name.str, m_name.length);
- str->append('@');
- str->qs_append(m_offset);
- }
-
inline bool send(Protocol *protocol, String *str)
{
return this_item()->send(protocol, str);
@@ -544,10 +581,13 @@ public:
bool eq(const Item *item, bool binary_cmp) const;
double val_real();
longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
String *val_str(String*);
double val_result();
longlong val_int_result();
String *str_result(String* tmp);
+ my_decimal *val_decimal_result(my_decimal *);
+ bool val_bool_result();
bool send(Protocol *protocol, String *str_arg);
void reset_field(Field *f);
bool fix_fields(THD *, struct st_table_list *, Item **);
@@ -600,12 +640,13 @@ public:
double val_real();
longlong val_int();
String *val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
int save_in_field(Field *field, bool no_conversions);
int save_safe_in_field(Field *field);
bool send(Protocol *protocol, String *str);
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_NULL; }
- // to prevent drop fixed flag (no need parent cleanup call)
+ /* to prevent drop fixed flag (no need parent cleanup call) */
void cleanup() {}
bool basic_const_item() const { return 1; }
Item *new_item() { return new Item_null(name); }
@@ -623,7 +664,8 @@ public:
enum enum_item_param_state
{
NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE,
- STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE
+ STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE,
+ DECIMAL_VALUE
} state;
/*
@@ -637,6 +679,7 @@ public:
Can not be declared inside the union as it's not a POD type.
*/
String str_value_ptr;
+ my_decimal decimal_value;
union
{
longlong integer;
@@ -688,6 +731,7 @@ public:
double val_real();
longlong val_int();
+ my_decimal *val_decimal(my_decimal*);
String *val_str(String*);
bool get_time(TIME *tm);
bool get_date(TIME *tm, uint fuzzydate);
@@ -696,6 +740,7 @@ public:
void set_null();
void set_int(longlong i, uint32 max_length_arg);
void set_double(double i);
+ void set_decimal(const char *str, ulong length);
bool set_str(const char *str, ulong length);
bool set_longdata(const char *str, ulong length);
void set_time(TIME *tm, timestamp_type type, uint32 max_length_arg);
@@ -746,6 +791,7 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
+ my_decimal *val_decimal(my_decimal *);
String *val_str(String*);
int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
@@ -784,14 +830,52 @@ public:
};
-class Item_real :public Item_num
+/* decimal (fixed point) constant */
+class Item_decimal :public Item_num
+{
+protected:
+ my_decimal decimal_value;
+public:
+ Item_decimal(const char *str_arg, uint length, CHARSET_INFO *charset);
+ Item_decimal(const char *str, const my_decimal *val_arg,
+ uint decimal_par, uint length);
+ Item_decimal(my_decimal *value_par);
+ Item_decimal(longlong val, bool unsig);
+ Item_decimal(double val, int precision, int scale);
+ Item_decimal(const char *bin, int precision, int scale);
+
+ enum Type type() const { return DECIMAL_ITEM; }
+ enum Item_result result_type () const { return DECIMAL_RESULT; }
+ enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
+ longlong val_int();
+ double val_real();
+ String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *val) { return &decimal_value; }
+ int save_in_field(Field *field, bool no_conversions);
+ bool basic_const_item() const { return 1; }
+ Item *new_item()
+ {
+ return new Item_decimal(name, &decimal_value, decimals, max_length);
+ }
+ // to prevent drop fixed flag (no need parent cleanup call)
+ void cleanup() {}
+ void print(String *str);
+ Item_num *neg()
+ {
+ my_decimal_neg(&decimal_value);
+ unsigned_flag= !decimal_value.sign();
+ return this;
+ }
+};
+
+class Item_float :public Item_num
{
char *presentation;
public:
double value;
// Item_real() :value(0) {}
- Item_real(const char *str_arg, uint length);
- Item_real(const char *str,double val_arg,uint decimal_par,uint length)
+ Item_float(const char *str_arg, uint length);
+ Item_float(const char *str,double val_arg,uint decimal_par,uint length)
:value(val_arg)
{
presentation= name=(char*) str;
@@ -799,7 +883,8 @@ public:
max_length=length;
fixed= 1;
}
- Item_real(double value_par) :presentation(0), value(value_par) { fixed= 1; }
+ Item_float(double value_par) :presentation(0), value(value_par) { fixed= 1; }
+
int save_in_field(Field *field, bool no_conversions);
enum Type type() const { return REAL_ITEM; }
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
@@ -810,37 +895,29 @@ public:
return (longlong) (value+(value > 0 ? 0.5 : -0.5));
}
String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *);
bool basic_const_item() const { return 1; }
// to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {}
- Item *new_item() { return new Item_real(name,value,decimals,max_length); }
+ Item *new_item()
+ { return new Item_float(name, value, decimals, max_length); }
Item_num *neg() { value= -value; return this; }
void print(String *str);
};
-class Item_static_real_func :public Item_real
+class Item_static_float_func :public Item_float
{
const char *func_name;
public:
- Item_static_real_func(const char *str, double val_arg, uint decimal_par,
+ Item_static_float_func(const char *str, double val_arg, uint decimal_par,
uint length)
- :Item_real(NullS, val_arg, decimal_par, length), func_name(str)
+ :Item_float(NullS, val_arg, decimal_par, length), func_name(str)
{}
void print(String *str) { str->append(func_name); }
};
-class Item_float :public Item_real
-{
-public:
- Item_float(const char *str,uint length) :Item_real(str,length)
- {
- decimals=NOT_FIXED_DEC;
- max_length=DBL_DIG+8;
- }
-};
-
class Item_string :public Item
{
public:
@@ -894,6 +971,7 @@ public:
DBUG_ASSERT(fixed == 1);
return (String*) &str_value;
}
+ my_decimal *val_decimal(my_decimal *);
int save_in_field(Field *field, bool no_conversions);
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
@@ -932,7 +1010,7 @@ class Item_datetime :public Item_string
{
public:
Item_datetime(const char *item_name): Item_string(item_name,"",0,
- &my_charset_bin)
+ &my_charset_bin)
{ max_length=19;}
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
};
@@ -971,6 +1049,7 @@ public:
longlong val_int();
bool basic_const_item() const { return 1; }
String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; }
+ my_decimal *val_decimal(my_decimal *);
int save_in_field(Field *field, bool no_conversions);
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
@@ -1033,54 +1112,25 @@ public:
TODO we probably fix a superset of problems like in BUG#6658. Check this
with Bar, and if we have a more broader set of problems like this.
*/
- Item_ref(Item **item, const char *table_name_par, const char *field_name_par)
- :Item_ident(NullS, table_name_par, field_name_par), result_field(0), ref(item)
- {
- DBUG_ASSERT(item);
- if (*item)
- set_properties();
- }
+ Item_ref(Item **item, const char *table_name_par, const char *field_name_par);
/* Constructor need to process subselect with temporary tables (see Item) */
Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {}
enum Type type() const { return REF_ITEM; }
bool eq(const Item *item, bool binary_cmp) const
{ return ref && (*ref)->eq(item, binary_cmp); }
- double val_real()
- {
- DBUG_ASSERT(fixed);
- double tmp=(*ref)->val_result();
- null_value=(*ref)->null_value;
- return tmp;
- }
- longlong val_int()
- {
- DBUG_ASSERT(fixed);
- longlong tmp=(*ref)->val_int_result();
- null_value=(*ref)->null_value;
- return tmp;
- }
- String *val_str(String* tmp)
- {
- DBUG_ASSERT(fixed);
- tmp=(*ref)->str_result(tmp);
- null_value=(*ref)->null_value;
- return tmp;
- }
- bool is_null()
- {
- DBUG_ASSERT(fixed);
- (void) (*ref)->val_int_result();
- return (*ref)->null_value;
- }
- bool get_date(TIME *ltime,uint fuzzydate)
- {
- DBUG_ASSERT(fixed);
- return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
- }
+ double val_real();
+ longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
+ bool val_bool();
+ String *val_str(String* tmp);
+ bool is_null();
+ bool get_date(TIME *ltime,uint fuzzydate);
double val_result();
longlong val_int_result();
String *str_result(String* tmp);
+ my_decimal *val_decimal_result(my_decimal *);
+ bool val_bool_result();
bool send(Protocol *prot, String *tmp);
void make_field(Send_field *field) { (*ref)->make_field(field); }
bool fix_fields(THD *, struct st_table_list *, Item **);
@@ -1121,33 +1171,13 @@ public:
/* Constructor need to process subselect with temporary tables (see Item) */
Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {}
- double val_real()
- {
- double tmp=(*ref)->val_real();
- null_value=(*ref)->null_value;
- return tmp;
- }
- longlong val_int()
- {
- longlong tmp=(*ref)->val_int();
- null_value=(*ref)->null_value;
- return tmp;
- }
- String *val_str(String* tmp)
- {
- tmp=(*ref)->val_str(tmp);
- null_value=(*ref)->null_value;
- return tmp;
- }
- bool is_null()
- {
- (void) (*ref)->val_int();
- return (*ref)->null_value;
- }
- bool get_date(TIME *ltime,uint fuzzydate)
- {
- return (null_value=(*ref)->get_date(ltime,fuzzydate));
- }
+ double val_real();
+ longlong val_int();
+ String *val_str(String* tmp);
+ my_decimal *val_decimal(my_decimal *);
+ bool val_bool();
+ bool is_null();
+ bool get_date(TIME *ltime,uint fuzzydate);
};
@@ -1164,6 +1194,8 @@ public:
double val_real();
longlong val_int();
String* val_str(String* s);
+ my_decimal *val_decimal(my_decimal *);
+ bool val_bool();
bool get_date(TIME *ltime, uint fuzzydate);
void print(String *str);
};
@@ -1174,7 +1206,8 @@ class Item_null_helper :public Item_ref_null_helper
public:
Item_null_helper(Item_in_subselect* master, Item *item,
const char *table_name_par, const char *field_name_par)
- :Item_ref_null_helper(master, &item, table_name_par, field_name_par),
+ :Item_ref_null_helper(master, (store= 0, &store), table_name_par,
+ field_name_par),
store(item)
{ ref= &store; }
void print(String *str);
@@ -1243,6 +1276,7 @@ public:
return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),10, (char**) 0,&err);
}
String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *);
void make_field(Send_field *field) { item->make_field(field); }
void copy();
int save_in_field(Field *field, bool no_conversions);
@@ -1291,6 +1325,15 @@ public:
};
+class Item_decimal_buff :public Item_buff
+{
+ Item *item;
+ my_decimal value;
+public:
+ Item_decimal_buff(Item *item_par);
+ bool cmp(void);
+};
+
class Item_field_buff :public Item_buff
{
char *buff;
@@ -1453,24 +1496,23 @@ public:
void print(String *str);
};
+
class Item_cache_int: public Item_cache
{
+protected:
longlong value;
public:
Item_cache_int(): Item_cache(), value(0) {}
-
+
void store(Item *item);
double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
- String* val_str(String *str)
- {
- DBUG_ASSERT(fixed == 1);
- str->set(value, default_charset());
- return str;
- }
+ String* val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
enum Item_result result_type() const { return INT_RESULT; }
};
+
class Item_cache_real: public Item_cache
{
double value;
@@ -1479,30 +1521,41 @@ public:
void store(Item *item);
double val_real() { DBUG_ASSERT(fixed == 1); return value; }
- longlong val_int()
- {
- DBUG_ASSERT(fixed == 1);
- return (longlong) (value+(value > 0 ? 0.5 : -0.5));
- }
- String* val_str(String *str)
- {
- str->set(value, decimals, default_charset());
- return str;
- }
+ longlong val_int();
+ String* val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
enum Item_result result_type() const { return REAL_RESULT; }
};
+
+class Item_cache_decimal: public Item_cache
+{
+protected:
+ my_decimal decimal_value;
+public:
+ Item_cache_decimal(): Item_cache() {}
+
+ void store(Item *item);
+ double val_real();
+ longlong val_int();
+ String* val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
+ enum Item_result result_type() const { return DECIMAL_RESULT; }
+};
+
+
class Item_cache_str: public Item_cache
{
- char buffer[80];
+ char buffer[STRING_BUFFER_USUAL_SIZE];
String *value, value_buff;
public:
Item_cache_str(): Item_cache(), value(0) { }
-
+
void store(Item *item);
double val_real();
longlong val_int();
String* val_str(String *) { DBUG_ASSERT(fixed == 1); return value; }
+ my_decimal *val_decimal(my_decimal *);
enum Item_result result_type() const { return STRING_RESULT; }
CHARSET_INFO *charset() const { return value->charset(); };
};
@@ -1547,6 +1600,12 @@ public:
illegal_method_call((const char*)"val_str");
return 0;
};
+ my_decimal *val_decimal(my_decimal *val)
+ {
+ illegal_method_call((const char*)"val_decimal");
+ return 0;
+ };
+
enum Item_result result_type() const { return ROW_RESULT; }
uint cols() { return item_count; }
@@ -1585,6 +1644,7 @@ public:
enum Type type() const { return TYPE_HOLDER; }
double val_real();
longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
String *val_str(String*);
bool join_types(THD *thd, Item *, TABLE *);
Field *example() { return field_example; }
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
index 66de26dba9a..7c77f7fa3bc 100644
--- a/sql/item_buff.cc
+++ b/sql/item_buff.cc
@@ -28,11 +28,21 @@ Item_buff *new_Item_buff(Item *item)
if (item->type() == Item::FIELD_ITEM &&
!(((Item_field *) item)->field->flags & BLOB_FLAG))
return new Item_field_buff((Item_field *) item);
- if (item->result_type() == STRING_RESULT)
+ switch (item->result_type())
+ {
+ case STRING_RESULT:
return new Item_str_buff((Item_field *) item);
- if (item->result_type() == INT_RESULT)
+ case INT_RESULT:
return new Item_int_buff((Item_field *) item);
- return new Item_real_buff(item);
+ case REAL_RESULT:
+ return new Item_real_buff(item);
+ case DECIMAL_RESULT:
+ return new Item_decimal_buff(item);
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ return 0;
+ }
}
Item_buff::~Item_buff() {}
@@ -107,6 +117,27 @@ bool Item_field_buff::cmp(void)
}
+Item_decimal_buff::Item_decimal_buff(Item *it)
+ :item(it)
+{
+ my_decimal_set_zero(&value);
+}
+
+
+bool Item_decimal_buff::cmp()
+{
+ my_decimal tmp;
+ my_decimal *ptmp= item->val_decimal(&tmp);
+ if (null_value != item->null_value || my_decimal_cmp(&value, ptmp) == 0)
+ {
+ null_value= item->null_value;
+ my_decimal2decimal(ptmp, &value);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
/*****************************************************************************
** Instansiate templates
*****************************************************************************/
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 1079e31e23a..71a4e4dda53 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -31,6 +31,8 @@ static Item_result item_store_type(Item_result a,Item_result b)
return STRING_RESULT;
else if (a == REAL_RESULT || b == REAL_RESULT)
return REAL_RESULT;
+ else if (a == DECIMAL_RESULT || b == DECIMAL_RESULT)
+ return DECIMAL_RESULT;
else
return INT_RESULT;
}
@@ -51,7 +53,8 @@ static void agg_cmp_type(Item_result *type, Item **items, uint nitems)
type[0]= item_cmp_type(type[0], items[i]->result_type());
}
-static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname)
+static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
+ const char *fname)
{
my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0),
c1.collation->name,c1.derivation_name(),
@@ -104,7 +107,7 @@ Item_bool_func2* Le_creator::create(Item *a, Item *b) const
longlong Item_func_not::val_int()
{
DBUG_ASSERT(fixed == 1);
- double value= args[0]->val_real();
+ bool value= args[0]->val_bool();
null_value=args[0]->null_value;
return ((!null_value && value == 0) ? 1 : 0);
}
@@ -116,11 +119,11 @@ longlong Item_func_not::val_int()
longlong Item_func_not_all::val_int()
{
DBUG_ASSERT(fixed == 1);
- double value= args[0]->val_real();
+ bool value= args[0]->val_bool();
/*
- return TRUE if there was records in underlaying select in max/min
- optimisation (ALL subquery)
+ return TRUE if there was records in underlying select in max/min
+ optimization (ALL subquery)
*/
if (empty_underlying_subquery())
return 1;
@@ -147,7 +150,7 @@ void Item_func_not_all::print(String *str)
/*
Special NOP (No OPeration) for ALL subquery it is like Item_func_not_all
- (return TRUE if underlaying sudquery do not return rows) but if subquery
+ (return TRUE if underlying subquery do not return rows) but if subquery
returns some rows it return same value as argument (TRUE/FALSE).
*/
@@ -157,8 +160,8 @@ longlong Item_func_nop_all::val_int()
longlong value= args[0]->val_int();
/*
- return FALSE if there was records in underlaying select in max/min
- optimisation (SAME/ANY subquery)
+ return FALSE if there was records in underlying select in max/min
+ optimization (SAME/ANY subquery)
*/
if (empty_underlying_subquery())
return 0;
@@ -270,7 +273,9 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
owner= item;
func= comparator_matrix[type]
[test(owner->functype() == Item_func::EQUAL_FUNC)];
- if (type == ROW_RESULT)
+ switch(type)
+ {
+ case ROW_RESULT:
{
uint n= (*a)->cols();
if (n != (*b)->cols())
@@ -290,8 +295,9 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
}
comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i));
}
+ break;
}
- else if (type == STRING_RESULT)
+ case STRING_RESULT:
{
/*
We must set cmp_charset here as we may be called from for an automatic
@@ -315,7 +321,7 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
func= &Arg_comparator::compare_e_binary_string;
/*
- As this is binary comparsion, mark all fields that they can't be
+ As this is binary compassion, mark all fields that they can't be
transformed. Otherwise we would get into trouble with comparisons
like:
WHERE col= 'j' AND col LIKE BINARY 'j'
@@ -325,14 +331,16 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
(*a)->transform(&Item::set_no_const_sub, (byte*) 0);
(*b)->transform(&Item::set_no_const_sub, (byte*) 0);
}
+ break;
}
- else if (type == INT_RESULT)
+ case INT_RESULT:
{
if (func == &Arg_comparator::compare_int_signed)
{
if ((*a)->unsigned_flag)
- func= ((*b)->unsigned_flag)? &Arg_comparator::compare_int_unsigned :
- &Arg_comparator::compare_int_unsigned_signed;
+ func= (((*b)->unsigned_flag)?
+ &Arg_comparator::compare_int_unsigned :
+ &Arg_comparator::compare_int_unsigned_signed);
else if ((*b)->unsigned_flag)
func= &Arg_comparator::compare_int_signed_unsigned;
}
@@ -341,6 +349,13 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
if ((*a)->unsigned_flag ^ (*b)->unsigned_flag)
func= &Arg_comparator::compare_e_int_diff_signedness;
}
+ break;
+ }
+ case DECIMAL_RESULT:
+ case REAL_RESULT:
+ break;
+ default:
+ DBUG_ASSERT(0);
}
return 0;
}
@@ -434,6 +449,24 @@ int Arg_comparator::compare_real()
return -1;
}
+int Arg_comparator::compare_decimal()
+{
+ my_decimal value1;
+ my_decimal *val1= (*a)->val_decimal(&value1);
+ if (!(*a)->null_value)
+ {
+ my_decimal value2;
+ my_decimal *val2= (*b)->val_decimal(&value2);
+ if (!(*b)->null_value)
+ {
+ owner->null_value= 0;
+ return my_decimal_cmp(val1, val2);
+ }
+ }
+ owner->null_value= 1;
+ return -1;
+}
+
int Arg_comparator::compare_e_real()
{
double val1= (*a)->val_real();
@@ -443,6 +476,16 @@ int Arg_comparator::compare_e_real()
return test(val1 == val2);
}
+int Arg_comparator::compare_e_decimal()
+{
+ my_decimal value1, value2;
+ my_decimal *val1= (*a)->val_decimal(&value1);
+ my_decimal *val2= (*b)->val_decimal(&value2);
+ if ((*a)->null_value || (*b)->null_value)
+ return test((*a)->null_value && (*b)->null_value);
+ return test(my_decimal_cmp(val1, val2) == 0);
+}
+
int Arg_comparator::compare_int_signed()
{
longlong val1= (*a)->val_int();
@@ -776,6 +819,8 @@ longlong Item_func_strcmp::val_int()
void Item_func_interval::fix_length_and_dec()
{
+ use_decimal_comparison= (row->el(0)->result_type() == DECIMAL_RESULT) ||
+ (row->el(0)->result_type() == INT_RESULT);
if (row->cols() > 8)
{
bool consts=1;
@@ -786,10 +831,41 @@ void Item_func_interval::fix_length_and_dec()
}
if (consts &&
- (intervals=(double*) sql_alloc(sizeof(double)*(row->cols()-1))))
+ (intervals=
+ (interval_range*) sql_alloc(sizeof(interval_range)*(row->cols()-1))))
{
- for (uint i=1 ; i < row->cols(); i++)
- intervals[i-1]= row->el(i)->val_real();
+ if (use_decimal_comparison)
+ {
+ for (uint i=1 ; i < row->cols(); i++)
+ {
+ Item *el= row->el(i);
+ interval_range *range= intervals + (i-1);
+ if ((el->result_type() == DECIMAL_RESULT) ||
+ (el->result_type() == INT_RESULT))
+ {
+ range->type= DECIMAL_RESULT;
+ range->dec.init();
+ my_decimal *dec= el->val_decimal(&range->dec);
+ if (dec != &range->dec)
+ {
+ range->dec= *dec;
+ range->dec.fix_buffer_pointer();
+ }
+ }
+ else
+ {
+ range->type= REAL_RESULT;
+ range->dbl= el->val_real();
+ }
+ }
+ }
+ else
+ {
+ for (uint i=1 ; i < row->cols(); i++)
+ {
+ intervals[i-1].dbl= row->el(i)->val_real();
+ }
+ }
}
}
maybe_null= 0;
@@ -812,6 +888,11 @@ longlong Item_func_interval::val_int()
{
DBUG_ASSERT(fixed == 1);
double value= row->el(0)->val_real();
+ my_decimal dec_buf, *dec= NULL;
+ if (use_decimal_comparison)
+ {
+ dec= row->el(0)->val_decimal(&dec_buf);
+ }
uint i;
if (row->el(0)->null_value)
@@ -824,18 +905,37 @@ longlong Item_func_interval::val_int()
while (start != end)
{
uint mid= (start + end + 1) / 2;
- if (intervals[mid] <= value)
+ interval_range *range= intervals + mid;
+ my_bool cmp_result;
+ if (dec && range->type == DECIMAL_RESULT)
+ cmp_result= my_decimal_cmp(&range->dec, dec) <= 0;
+ else
+ cmp_result= (range->dbl <= value);
+ if (cmp_result)
start= mid;
else
end= mid - 1;
}
- return (value < intervals[start]) ? 0 : start + 1;
+ interval_range *range= intervals+start;
+ return ((dec && range->type == DECIMAL_RESULT) ?
+ my_decimal_cmp(dec, &range->dec) < 0 :
+ value < range->dbl) ? 0 : start + 1;
}
for (i=1 ; i < row->cols() ; i++)
{
- if (row->el(i)->val_real() > value)
- return i-1;
+ Item *el= row->el(i);
+ if (use_decimal_comparison &&
+ ((el->result_type() == DECIMAL_RESULT) ||
+ (el->result_type() == INT_RESULT)))
+ {
+ my_decimal e_dec_buf, *e_dec= row->el(i)->val_decimal(&e_dec_buf);
+ if (my_decimal_cmp(e_dec, dec) > 0)
+ return i-1;
+ }
+ else
+ if (row->el(i)->val_real() > value)
+ return i-1;
}
return i-1;
}
@@ -847,7 +947,7 @@ void Item_func_between::fix_length_and_dec()
/*
As some compare functions are generated after sql_yacc,
- we have to check for out of memory conditons here
+ we have to check for out of memory conditions here
*/
if (!args[0] || !args[1] || !args[2])
return;
@@ -857,7 +957,7 @@ void Item_func_between::fix_length_and_dec()
return;
/*
- Make a special case of compare with date/time and longlong fields.
+ Make a special ease of compare with date/time and longlong fields.
They are compared as integers, so for const item this time-consuming
conversion can be done only once, not for every single comparison
*/
@@ -926,6 +1026,24 @@ longlong Item_func_between::val_int()
null_value= value >= a;
}
}
+ else if (cmp_type == DECIMAL_RESULT)
+ {
+ my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf),
+ a_buf, *a_dec, b_buf, *b_dec;
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+ a_dec= args[1]->val_decimal(&a_buf);
+ b_dec= args[2]->val_decimal(&b_buf);
+ if (!args[1]->null_value && !args[2]->null_value)
+ return (my_decimal_cmp(dec, a_dec)>=0) && (my_decimal_cmp(dec, b_dec)<=0);
+
+ if (args[1]->null_value && args[2]->null_value)
+ null_value=1;
+ else if (args[1]->null_value)
+ null_value= (my_decimal_cmp(dec, b_dec) <= 0);
+ else
+ null_value= (my_decimal_cmp(dec, a_dec) >= 0);
+ }
else
{
double value= args[0]->val_real(),a,b;
@@ -965,14 +1083,26 @@ void
Item_func_ifnull::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null;
- max_length=max(args[0]->max_length,args[1]->max_length);
- 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,
+ args[1]->max_length - args[1]->decimals) +
+ decimals);
agg_result_type(&cached_result_type, args, 2);
- if (cached_result_type == STRING_RESULT)
+ switch (cached_result_type)
+ {
+ case STRING_RESULT:
agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV);
- else if (cached_result_type != REAL_RESULT)
+ break;
+ case DECIMAL_RESULT:
+ case REAL_RESULT:
+ break;
+ case INT_RESULT:
decimals= 0;
-
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
cached_field_type= args[0]->field_type();
if (cached_field_type != args[1]->field_type())
cached_field_type= Item_func::field_type();
@@ -1020,6 +1150,24 @@ Item_func_ifnull::val_int()
return value;
}
+
+my_decimal *Item_func_ifnull::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ my_decimal *value= args[0]->val_decimal(decimal_value);
+ if (!args[0]->null_value)
+ {
+ null_value= 0;
+ return value;
+ }
+ value= args[1]->val_decimal(decimal_value);
+ if ((null_value= args[1]->null_value))
+ return 0;
+ return value;
+}
+
+
+
String *
Item_func_ifnull::val_str(String *str)
{
@@ -1043,8 +1191,10 @@ void
Item_func_if::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null || args[2]->maybe_null;
- max_length=max(args[1]->max_length,args[2]->max_length);
- decimals=max(args[1]->decimals,args[2]->decimals);
+ decimals= max(args[1]->decimals, args[2]->decimals);
+ max_length= (max(args[1]->max_length - args[1]->decimals,
+ args[2]->max_length - args[2]->decimals) +
+ decimals);
enum Item_result arg1_type=args[1]->result_type();
enum Item_result arg2_type=args[2]->result_type();
bool null1=args[1]->const_item() && args[1]->null_value;
@@ -1080,7 +1230,7 @@ double
Item_func_if::val_real()
{
DBUG_ASSERT(fixed == 1);
- Item *arg= args[0]->val_int() ? args[1] : args[2];
+ Item *arg= args[0]->val_bool() ? args[1] : args[2];
double value= arg->val_real();
null_value=arg->null_value;
return value;
@@ -1090,7 +1240,7 @@ longlong
Item_func_if::val_int()
{
DBUG_ASSERT(fixed == 1);
- Item *arg= args[0]->val_int() ? args[1] : args[2];
+ Item *arg= args[0]->val_bool() ? args[1] : args[2];
longlong value=arg->val_int();
null_value=arg->null_value;
return value;
@@ -1100,7 +1250,7 @@ String *
Item_func_if::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- Item *arg= args[0]->val_int() ? args[1] : args[2];
+ Item *arg= args[0]->val_bool() ? args[1] : args[2];
String *res=arg->val_str(str);
if (res)
res->set_charset(collation.collation);
@@ -1109,6 +1259,17 @@ Item_func_if::val_str(String *str)
}
+my_decimal *
+Item_func_if::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ Item *arg= args[0]->val_bool() ? args[1] : args[2];
+ my_decimal *value= arg->val_decimal(decimal_value);
+ null_value= arg->null_value;
+ return value;
+}
+
+
void
Item_func_nullif::fix_length_and_dec()
{
@@ -1125,6 +1286,7 @@ Item_func_nullif::fix_length_and_dec()
}
}
+
/*
nullif () returns NULL if arguments are equal, else it returns the
first argument.
@@ -1178,6 +1340,22 @@ Item_func_nullif::val_str(String *str)
}
+my_decimal *
+Item_func_nullif::val_decimal(my_decimal * decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ my_decimal *res;
+ if (!cmp.compare())
+ {
+ null_value=1;
+ return 0;
+ }
+ res= args[0]->val_decimal(decimal_value);
+ null_value= args[0]->null_value;
+ return res;
+}
+
+
bool
Item_func_nullif::is_null()
{
@@ -1193,14 +1371,16 @@ Item_func_nullif::is_null()
Item *Item_func_case::find_item(String *str)
{
- String *first_expr_str,*tmp;
+ String *first_expr_str, *tmp;
+ my_decimal *first_expr_dec, first_expr_dec_val;
longlong first_expr_int;
double first_expr_real;
-
+
/* These will be initialized later */
LINT_INIT(first_expr_str);
LINT_INIT(first_expr_int);
LINT_INIT(first_expr_real);
+ LINT_INIT(first_expr_dec);
if (first_expr_num != -1)
{
@@ -1221,9 +1401,14 @@ Item *Item_func_case::find_item(String *str)
if (args[first_expr_num]->null_value)
return else_expr_num != -1 ? args[else_expr_num] : 0;
break;
+ case DECIMAL_RESULT:
+ first_expr_dec= args[first_expr_num]->val_decimal(&first_expr_dec_val);
+ if (args[first_expr_num]->null_value)
+ return else_expr_num != -1 ? args[else_expr_num] : 0;
+ break;
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
break;
}
@@ -1235,7 +1420,7 @@ Item *Item_func_case::find_item(String *str)
if (first_expr_num == -1)
{
// No expression between CASE and the first WHEN
- if (args[i]->val_int())
+ if (args[i]->val_bool())
return args[i+1];
continue;
}
@@ -1253,9 +1438,16 @@ Item *Item_func_case::find_item(String *str)
if (args[i]->val_real() == first_expr_real && !args[i]->null_value)
return args[i+1];
break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal value;
+ if (my_decimal_cmp(args[i]->val_decimal(&value), first_expr_dec) == 0)
+ return args[i+1];
+ break;
+ }
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
break;
}
@@ -1320,6 +1512,27 @@ double Item_func_case::val_real()
return res;
}
+
+my_decimal *Item_func_case::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ char buff[MAX_FIELD_WIDTH];
+ String dummy_str(buff, sizeof(buff), default_charset());
+ Item *item= find_item(&dummy_str);
+ my_decimal *res;
+
+ if (!item)
+ {
+ null_value=1;
+ return 0;
+ }
+
+ res= item->val_decimal(decimal_value);
+ null_value= item->null_value;
+ return res;
+}
+
+
void Item_func_case::fix_length_and_dec()
{
Item **agg;
@@ -1358,7 +1571,7 @@ void Item_func_case::fix_length_and_dec()
agg_cmp_type(&cmp_type, agg, nagg);
if ((cmp_type == STRING_RESULT) &&
agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV))
- return;
+ return;
}
if (else_expr_num == -1 || args[else_expr_num]->maybe_null)
@@ -1453,20 +1666,45 @@ double Item_func_coalesce::val_real()
}
+my_decimal *Item_func_coalesce::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ null_value= 0;
+ for (uint i= 0; i < arg_count; i++)
+ {
+ my_decimal *res= args[i]->val_decimal(decimal_value);
+ if (!args[i]->null_value)
+ return res;
+ }
+ null_value=1;
+ return 0;
+}
+
+
void Item_func_coalesce::fix_length_and_dec()
{
- max_length= 0;
- decimals= 0;
agg_result_type(&cached_result_type, args, arg_count);
- for (uint i=0 ; i < arg_count ; i++)
+ switch (cached_result_type)
{
- set_if_bigger(max_length,args[i]->max_length);
- set_if_bigger(decimals,args[i]->decimals);
- }
- if (cached_result_type == STRING_RESULT)
+ case STRING_RESULT:
+ count_only_length();
+ decimals= NOT_FIXED_DEC;
agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV);
- else if (cached_result_type != REAL_RESULT)
+ break;
+ case DECIMAL_RESULT:
+ count_decimal_length();
+ break;
+ case REAL_RESULT:
+ count_real_length();
+ break;
+ case INT_RESULT:
+ count_only_length();
decimals= 0;
+ break;
+ case ROW_RESULT:
+ defaullt:
+ DBUG_ASSERT(0);
+ }
}
/****************************************************************************
@@ -1483,11 +1721,24 @@ static int cmp_double(void *cmp_arg, double *a,double *b)
return *a < *b ? -1 : *a == *b ? 0 : 1;
}
-static int cmp_row(void *cmp_arg, cmp_item_row* a, cmp_item_row* b)
+static int cmp_row(void *cmp_arg, cmp_item_row *a, cmp_item_row *b)
{
return a->compare(b);
}
+
+static int cmp_decimal(void *cmp_arg, my_decimal *a, my_decimal *b)
+{
+ /*
+ We need call of fixing buffer pointer, because fast sort just copy
+ decimal buffers in memory and pointers left pointing on old buffer place
+ */
+ a->fix_buffer_pointer();
+ b->fix_buffer_pointer();
+ return my_decimal_cmp(a, b);
+}
+
+
int in_vector::find(Item *item)
{
byte *result=get_value(item);
@@ -1612,17 +1863,47 @@ byte *in_double::get_value(Item *item)
return (byte*) &tmp;
}
-cmp_item* cmp_item::get_comparator(Item *item)
+
+in_decimal::in_decimal(uint elements)
+ :in_vector(elements, sizeof(my_decimal),(qsort2_cmp) cmp_decimal, 0)
+{}
+
+
+void in_decimal::set(uint pos, Item *item)
+{
+ /* as far as 'item' is constant, we can store reference on my_decimal */
+ my_decimal *dec= ((my_decimal *)base) + pos;
+ dec->len= DECIMAL_BUFF_LENGTH;
+ dec->fix_buffer_pointer();
+ my_decimal *res= item->val_decimal(dec);
+ if (res != dec)
+ my_decimal2decimal(res, dec);
+}
+
+
+byte *in_decimal::get_value(Item *item)
+{
+ my_decimal *result= item->val_decimal(&val);
+ if (item->null_value)
+ return 0;
+ return (byte *)result;
+}
+
+
+cmp_item* cmp_item::get_comparator(Item_result type,
+ CHARSET_INFO *cs)
{
- switch (item->result_type()) {
+ switch (type) {
case STRING_RESULT:
- return new cmp_item_sort_string(item->collation.collation);
+ return new cmp_item_sort_string(cs);
case INT_RESULT:
return new cmp_item_int;
case REAL_RESULT:
return new cmp_item_real;
case ROW_RESULT:
return new cmp_item_row;
+ case DECIMAL_RESULT:
+ return new cmp_item_decimal;
default:
DBUG_ASSERT(0);
break;
@@ -1681,7 +1962,9 @@ void cmp_item_row::store_value(Item *item)
for (uint i=0; i < n; i++)
{
if (!comparators[i])
- if (!(comparators[i]= cmp_item::get_comparator(item->el(i))))
+ if (!(comparators[i]=
+ cmp_item::get_comparator(item->el(i)->result_type(),
+ item->el(i)->collation.collation)))
break; // new failed
comparators[i]->store_value(item->el(i));
item->null_value|= item->el(i)->null_value;
@@ -1752,6 +2035,36 @@ int cmp_item_row::compare(cmp_item *c)
}
+void cmp_item_decimal::store_value(Item *item)
+{
+ my_decimal *val= item->val_decimal(&value);
+ if (val != &value)
+ my_decimal2decimal(val, &value);
+}
+
+
+int cmp_item_decimal::cmp(Item *arg)
+{
+ my_decimal tmp_buf, *tmp= arg->val_decimal(&tmp_buf);
+ if (arg->null_value)
+ return 1;
+ return my_decimal_cmp(&value, tmp);
+}
+
+
+int cmp_item_decimal::compare(cmp_item *c)
+{
+ cmp_item_decimal *cmp= (cmp_item_decimal *)c;
+ return my_decimal_cmp(&value, &cmp->value);
+}
+
+
+cmp_item* cmp_item_decimal::make_same()
+{
+ return new cmp_item_decimal();
+}
+
+
bool Item_func_in::nulls_in_row()
{
Item **arg,**arg_end;
@@ -1807,6 +2120,9 @@ void Item_func_in::fix_length_and_dec()
case ROW_RESULT:
array= new in_row(arg_count-1, args[0]);
break;
+ case DECIMAL_RESULT:
+ array= new in_decimal(arg_count - 1);
+ break;
default:
DBUG_ASSERT(0);
return;
@@ -1828,7 +2144,7 @@ void Item_func_in::fix_length_and_dec()
}
else
{
- in_item= cmp_item::get_comparator(args[0]);
+ in_item= cmp_item::get_comparator(cmp_type, cmp_collation.collation);
if (cmp_type == STRING_RESULT)
in_item->cmp_charset= cmp_collation.collation;
}
@@ -2003,7 +2319,7 @@ bool Item_cond::walk(Item_processor processor, byte *arg)
DESCRIPTION
The function recursively applies the transform method with the
- same transformer to each member item of the codition list.
+ same transformer to each member item of the condition list.
If the call of the method for a member item returns a new item
the old item is substituted for a new one.
After this the transform method is applied to the root node
@@ -2088,7 +2404,6 @@ void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array,
ref_pointer_array[el]= item;
Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name);
fields.push_front(item);
- ref_pointer_array[el]= item;
thd->change_item_tree(ref, new_item);
}
item->update_used_tables();
@@ -2157,7 +2472,7 @@ void Item_cond::neg_arguments(THD *thd)
/*
- Evalution of AND(expr, expr, expr ...)
+ Evaluation of AND(expr, expr, expr ...)
NOTES:
abort_if_null is set for AND expressions for which we don't care if the
@@ -2182,7 +2497,7 @@ longlong Item_cond_and::val_int()
null_value= 0;
while ((item=li++))
{
- if (item->val_int() == 0)
+ if (!item->val_bool())
{
if (abort_on_null || !(null_value= item->null_value))
return 0; // return FALSE
@@ -2200,7 +2515,7 @@ longlong Item_cond_or::val_int()
null_value=0;
while ((item=li++))
{
- if (item->val_int() != 0)
+ if (item->val_bool())
{
null_value=0;
return 1;
@@ -2439,7 +2754,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
DBUG_ASSERT(fixed == 0);
if ((!args[0]->fixed &&
args[0]->fix_fields(thd, tables, args)) || args[0]->check_cols(1) ||
- (!args[1]->fixed &&
+ (!args[1]->fixed &&
args[1]->fix_fields(thd,tables, args + 1)) || args[1]->check_cols(1))
return TRUE; /* purecov: inspected */
with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func;
@@ -2813,7 +3128,7 @@ longlong Item_cond_xor::val_int()
/*
Apply NOT transformation to the item and return a new one.
- SYNPOSIS
+ SYNOPSIS
neg_transformer()
thd thread handler
@@ -2991,10 +3306,10 @@ uint Item_equal::members()
SYNOPSIS
contains()
- field field whose occurence is to be checked
+ field field whose occurrence is to be checked
DESCRIPTION
- The function checks whether field is occured in the Item_equal object
+ The function checks whether field is occurred in the Item_equal object
RETURN VALUES
1 if nultiple equality contains a reference to field
@@ -3022,7 +3337,7 @@ bool Item_equal::contains(Field *field)
item multiple equality whose members are to be joined
DESCRIPTION
- The function actually merges two multiple equalitis.
+ The function actually merges two multiple equalities.
After this operation the Item_equal object additionally contains
the field items of another item of the type Item_equal.
If the optional constant items are not equal the cond_false flag is
@@ -3159,7 +3474,8 @@ longlong Item_equal::val_int()
void Item_equal::fix_length_and_dec()
{
Item *item= const_item ? const_item : get_first();
- eval_item= cmp_item::get_comparator(item);
+ eval_item= cmp_item::get_comparator(item->result_type(),
+ item->collation.collation);
if (item->result_type() == STRING_RESULT)
eval_item->cmp_charset= cmp_collation.collation;
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 181f1312d46..717bcbca7d5 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -67,6 +67,7 @@ public:
int compare_string(); // compare args[0] & args[1]
int compare_binary_string(); // compare args[0] & args[1]
int compare_real(); // compare args[0] & args[1]
+ int compare_decimal(); // compare args[0] & args[1]
int compare_int_signed(); // compare args[0] & args[1]
int compare_int_signed_unsigned();
int compare_int_unsigned_signed();
@@ -75,11 +76,12 @@ public:
int compare_e_string(); // compare args[0] & args[1]
int compare_e_binary_string(); // compare args[0] & args[1]
int compare_e_real(); // compare args[0] & args[1]
+ int compare_e_decimal(); // compare args[0] & args[1]
int compare_e_int(); // compare args[0] & args[1]
int compare_e_int_diff_signedness();
int compare_e_row(); // compare args[0] & args[1]
- static arg_cmp_func comparator_matrix [4][2];
+ static arg_cmp_func comparator_matrix [5][2];
friend class Item_func;
};
@@ -269,7 +271,7 @@ public:
class Item_func_not_all :public Item_func_not
{
- /* allow to check presence od values in max/min optimisation */
+ /* allow to check presence of values in max/min optimization */
Item_sum_hybrid *test_sum_item;
Item_maxmin_subselect *test_sub_item;
@@ -421,10 +423,18 @@ public:
};
+struct interval_range
+{
+ Item_result type;
+ double dbl;
+ my_decimal dec;
+};
+
class Item_func_interval :public Item_int_func
{
Item_row *row;
- double *intervals;
+ my_bool use_decimal_comparison;
+ interval_range *intervals;
public:
Item_func_interval(Item_row *a)
:Item_int_func(a),row(a),intervals(0)
@@ -437,24 +447,43 @@ public:
};
-class Item_func_ifnull :public Item_func
+class Item_func_coalesce :public Item_func
{
+protected:
enum Item_result cached_result_type;
+ Item_func_coalesce(Item *a, Item *b)
+ :Item_func(a, b), cached_result_type(INT_RESULT)
+ {}
+public:
+ Item_func_coalesce(List<Item> &list)
+ :Item_func(list),cached_result_type(INT_RESULT)
+ {}
+ double val_real();
+ longlong val_int();
+ String *val_str(String *);
+ my_decimal *val_decimal(my_decimal *);
+ void fix_length_and_dec();
+ enum Item_result result_type () const { return cached_result_type; }
+ const char *func_name() const { return "coalesce"; }
+ table_map not_null_tables() const { return 0; }
+};
+
+
+class Item_func_ifnull :public Item_func_coalesce
+{
+protected:
enum_field_types cached_field_type;
bool field_type_defined;
public:
- Item_func_ifnull(Item *a,Item *b)
- :Item_func(a,b), cached_result_type(INT_RESULT)
- {}
+ Item_func_ifnull(Item *a, Item *b) :Item_func_coalesce(a,b) {}
double val_real();
longlong val_int();
String *val_str(String *str);
- enum Item_result result_type () const { return cached_result_type; }
+ my_decimal *val_decimal(my_decimal *);
enum_field_types field_type() const;
void fix_length_and_dec();
const char *func_name() const { return "ifnull"; }
Field *tmp_table_field(TABLE *table);
- table_map not_null_tables() const { return 0; }
};
@@ -468,6 +497,7 @@ public:
double val_real();
longlong val_int();
String *val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return cached_result_type; }
bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref)
{
@@ -491,6 +521,7 @@ public:
double val_real();
longlong val_int();
String *val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
enum Item_result result_type () const { return cached_result_type; }
void fix_length_and_dec();
const char *func_name() const { return "nullif"; }
@@ -500,23 +531,6 @@ public:
};
-class Item_func_coalesce :public Item_func
-{
- enum Item_result cached_result_type;
-public:
- Item_func_coalesce(List<Item> &list)
- :Item_func(list),cached_result_type(INT_RESULT)
- {}
- double val_real();
- longlong val_int();
- String *val_str(String *);
- void fix_length_and_dec();
- enum Item_result result_type () const { return cached_result_type; }
- const char *func_name() const { return "coalesce"; }
- table_map not_null_tables() const { return 0; }
-};
-
-
class Item_func_case :public Item_func
{
int first_expr_num, else_expr_num;
@@ -529,7 +543,7 @@ public:
Item_func_case(List<Item> &list, Item *first_expr_arg, Item *else_expr_arg)
:Item_func(), first_expr_num(-1), else_expr_num(-1),
cached_result_type(INT_RESULT)
- {
+ {
ncases= list.elements;
if (first_expr_arg)
{
@@ -546,6 +560,7 @@ public:
double val_real();
longlong val_int();
String *val_str(String *);
+ my_decimal *val_decimal(my_decimal *);
void fix_length_and_dec();
table_map not_null_tables() const { return 0; }
enum Item_result result_type () const { return cached_result_type; }
@@ -586,7 +601,7 @@ public:
class in_string :public in_vector
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmp;
public:
in_string(uint elements,qsort2_cmp cmp_func, CHARSET_INFO *cs);
@@ -613,6 +628,16 @@ public:
byte *get_value(Item *item);
};
+class in_decimal :public in_vector
+{
+ my_decimal val;
+public:
+ in_decimal(uint elements);
+ void set(uint pos, Item *item);
+ byte *get_value(Item *item);
+};
+
+
/*
** Classes for easy comparing of non const items
*/
@@ -627,7 +652,7 @@ public:
virtual int cmp(Item *item)= 0;
// for optimized IN with row
virtual int compare(cmp_item *item)= 0;
- static cmp_item* get_comparator(Item *);
+ static cmp_item* get_comparator(Item_result type, CHARSET_INFO *cs);
virtual cmp_item *make_same()= 0;
virtual void store_value_by_template(cmp_item *tmpl, Item *item)
{
@@ -648,7 +673,7 @@ public:
class cmp_item_sort_string :public cmp_item_string
{
protected:
- char value_buff[80];
+ char value_buff[STRING_BUFFER_USUAL_SIZE];
String value;
public:
cmp_item_sort_string(CHARSET_INFO *cs):
@@ -660,7 +685,7 @@ public:
}
int cmp(Item *arg)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String tmp(buff, sizeof(buff), cmp_charset), *res;
if (!(res= arg->val_str(&tmp)))
return 1; /* Can't be right */
@@ -714,6 +739,18 @@ public:
cmp_item *make_same();
};
+
+class cmp_item_decimal :public cmp_item
+{
+ my_decimal value;
+public:
+ void store_value(Item *item);
+ int cmp(Item *arg);
+ int compare(cmp_item *c);
+ cmp_item *make_same();
+};
+
+
class cmp_item_row :public cmp_item
{
cmp_item **comparators;
@@ -996,26 +1033,26 @@ public:
/*
- The class Item_equal is used to represent conjuctions of equality
+ The class Item_equal is used to represent conjunctions of equality
predicates of the form field1 = field2, and field=const in where
conditions and on expressions.
All equality predicates of the form field1=field2 contained in a
- conjuction are substituted for a sequence of items of this class.
- An item of this class Item_equal(f1,f2,...fk) respresents a
+ conjunction are substituted for a sequence of items of this class.
+ An item of this class Item_equal(f1,f2,...fk) represents a
multiple equality f1=f2=...=fk.
- If a conjuction contains predicates f1=f2 and f2=f3, a new item of
+ If a conjunction contains predicates f1=f2 and f2=f3, a new item of
this class is created Item_equal(f1,f2,f3) representing the multiple
equality f1=f2=f3 that substitutes the above equality predicates in
- the conjuction.
- A conjuction of the predicates f2=f1 and f3=f1 and f3=f2 will be
+ the conjunction.
+ A conjunction of the predicates f2=f1 and f3=f1 and f3=f2 will be
substituted for the item representing the same multiple equality
f1=f2=f3.
- An item Item_equal(f1,f2) can appear instead of a conjuction of
+ An item Item_equal(f1,f2) can appear instead of a conjunction of
f2=f1 and f1=f2, or instead of just the predicate f1=f2.
- An item of the class Item_equal inherites equalities from outer
+ An item of the class Item_equal inherits equalities from outer
conjunctive levels.
Suppose we have a where condition of the following form:
@@ -1026,7 +1063,7 @@ public:
f1=f3 will be substituted for Item_equal(f1,f2,f3,f4,f5);
An object of the class Item_equal can contain an optional constant
- item c. Thenit represents a multiple equality of the form
+ item c. Then it represents a multiple equality of the form
c=f1=...=fk.
Objects of the class Item_equal are used for the following:
@@ -1044,7 +1081,7 @@ public:
3. An object Item_equal(t1.f1,...,tk.fk) is used to optimize the
selected execution plan for the query: if table ti is accessed
before the table tj then in any predicate P in the where condition
- the occurence of tj.fj is substituted for ti.fi. This can allow
+ the occurrence of tj.fj is substituted for ti.fi. This can allow
an evaluation of the predicate at an earlier step.
When feature 1 is supported they say that join transitive closure
@@ -1175,7 +1212,7 @@ public:
/*
- XOR is Item_cond, not an Item_int_func bevause we could like to
+ XOR is Item_cond, not an Item_int_func because we could like to
optimize (a XOR b) later on. It's low prio, though
*/
@@ -1192,7 +1229,7 @@ public:
};
-/* Some usefull inline functions */
+/* Some useful inline functions */
inline Item *and_conds(Item *a, Item *b)
{
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 9fb44658dd5..6bd5c0c9a52 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -289,7 +289,7 @@ Item *create_func_period_diff(Item* a, Item *b)
Item *create_func_pi(void)
{
- return new Item_static_real_func("pi()", M_PI, 6, 8);
+ return new Item_static_float_func("pi()", M_PI, 6, 8);
}
Item *create_func_pow(Item* a, Item *b)
@@ -454,7 +454,7 @@ Item *create_load_file(Item* a)
}
-Item *create_func_cast(Item *a, Cast_target cast_type, int len,
+Item *create_func_cast(Item *a, Cast_target cast_type, int len, int dec,
CHARSET_INFO *cs)
{
Item *res;
@@ -467,6 +467,9 @@ Item *create_func_cast(Item *a, Cast_target cast_type, int len,
case ITEM_CAST_DATE: res= new Item_date_typecast(a); break;
case ITEM_CAST_TIME: res= new Item_time_typecast(a); break;
case ITEM_CAST_DATETIME: res= new Item_datetime_typecast(a); break;
+ case ITEM_CAST_DECIMAL:
+ res= new Item_decimal_typecast(a, (len>0) ? len : 10, dec ? dec : 2);
+ break;
case ITEM_CAST_CHAR:
res= new Item_char_typecast(a, len, cs ? cs :
current_thd->variables.collation_connection);
diff --git a/sql/item_create.h b/sql/item_create.h
index 1be33fef257..0a9af144ec0 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -28,7 +28,8 @@ Item *create_func_bit_length(Item* a);
Item *create_func_coercibility(Item* a);
Item *create_func_ceiling(Item* a);
Item *create_func_char_length(Item* a);
-Item *create_func_cast(Item *a, Cast_target cast_type, int len, CHARSET_INFO *cs);
+Item *create_func_cast(Item *a, Cast_target cast_type, int len, int dec,
+ CHARSET_INFO *cs);
Item *create_func_connection_id(void);
Item *create_func_conv(Item* a, Item *b, Item *c);
Item *create_func_cos(Item* a);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index e1d81b2a37d..68654338cf6 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -194,6 +194,11 @@ bool Item_func::agg_arg_charsets(DTCollation &coll,
}
if ((*arg)->type() == FIELD_ITEM)
((Item_field *)(*arg))->no_const_subst= 1;
+ /*
+ We do not check conv->fixed, because Item_func_conv_charset which can
+ be return by safe_charset_converter can't be fixed at creation, also
+ it do not need tables (second argument) for name resolving
+ */
*arg= conv;
conv->fix_fields(thd, 0, arg);
}
@@ -414,7 +419,6 @@ void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array,
ref_pointer_array[el]= item;
Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name);
fields.push_front(item);
- ref_pointer_array[el]= item;
thd->change_item_tree(arg, new_item);
}
}
@@ -519,15 +523,26 @@ Field *Item_func::tmp_table_field(TABLE *t_arg)
case STRING_RESULT:
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);
+ break;
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
break;
}
return res;
}
+my_decimal *Item_func::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed);
+ int2my_decimal(E_DEC_FATAL_ERROR, val_int(), unsigned_flag, decimal_value);
+ return decimal_value;
+}
+
String *Item_real_func::val_str(String *str)
{
@@ -540,38 +555,97 @@ String *Item_real_func::val_str(String *str)
}
-String *Item_num_func::val_str(String *str)
+void Item_func::fix_num_length_and_dec()
{
- DBUG_ASSERT(fixed == 1);
- if (hybrid_type == INT_RESULT)
+ decimals= 0;
+ for (uint i=0 ; i < arg_count ; i++)
{
- longlong nr=val_int();
- if (null_value)
- return 0; /* purecov: inspected */
- if (!unsigned_flag)
- str->set(nr,&my_charset_bin);
- else
- str->set((ulonglong) nr,&my_charset_bin);
+ set_if_bigger(decimals, args[i]->decimals);
}
- else
+ max_length= float_length(decimals);
+}
+
+
+void Item_func_numhybrid::fix_num_length_and_dec()
+{}
+
+
+/*
+ Set max_length/decimals of function if function is fixed point and
+ result length/precision depends on argument ones
+
+ SYNOPSIS
+ Item_func::count_decimal_length()
+*/
+
+void Item_func::count_decimal_length()
+{
+ uint32 length= 0;
+ decimals= 0;
+ for (uint i=0 ; i < arg_count ; i++)
{
- double nr= val_real();
- if (null_value)
- return 0; /* purecov: inspected */
- str->set(nr,decimals,&my_charset_bin);
+ set_if_bigger(decimals, args[i]->decimals);
+ set_if_bigger(length, (args[i]->max_length - args[i]->decimals));
}
- return str;
+ max_length= length;
+ length+= decimals;
+ if (length < max_length) // If previous operation gave overflow
+ max_length= UINT_MAX32;
+ else
+ max_length= length;
}
-void Item_func::fix_num_length_and_dec()
+/*
+ Set max_length of if it is maximum length of its arguments
+
+ SYNOPSIS
+ Item_func::count_only_length()
+*/
+
+void Item_func::count_only_length()
{
- decimals=0;
+ max_length= 0;
+ for (uint i=0 ; i < arg_count ; i++)
+ set_if_bigger(max_length, args[i]->max_length);
+}
+
+
+/*
+ Set max_length/decimals of function if function is floating point and
+ result length/precision depends on argument ones
+
+ SYNOPSIS
+ Item_func::count_real_length()
+*/
+
+void Item_func::count_real_length()
+{
+ uint32 length= 0;
+ decimals= 0;
+ max_length= 0;
for (uint i=0 ; i < arg_count ; i++)
- set_if_bigger(decimals,args[i]->decimals);
- max_length=float_length(decimals);
+ {
+ if (decimals != NOT_FIXED_DEC)
+ {
+ set_if_bigger(decimals, args[i]->decimals);
+ set_if_bigger(length, (args[i]->max_length - args[i]->decimals));
+ }
+ set_if_bigger(max_length, args[i]->max_length);
+ }
+ if (decimals != NOT_FIXED_DEC)
+ {
+ max_length= length;
+ length+= decimals;
+ if (length < max_length) // If previous operation gave overflow
+ max_length= UINT_MAX32;
+ else
+ max_length= length;
+ }
}
+
+
void Item_func::signal_divide_by_null()
{
THD *thd= current_thd;
@@ -602,45 +676,221 @@ String *Item_int_func::val_str(String *str)
return str;
}
+
/*
- Change from REAL_RESULT (default) to INT_RESULT if both arguments are
- integers
+ Check arguments here to determine result's type for function with two
+ arguments.
+
+ SYNOPSIS
+ Item_num_op::find_num_type()
*/
void Item_num_op::find_num_type(void)
{
- if (args[0]->result_type() == INT_RESULT &&
- args[1]->result_type() == INT_RESULT)
+ DBUG_ENTER("Item_num_op::find_num_type");
+ DBUG_PRINT("info", ("name %s", func_name()));
+ DBUG_ASSERT(arg_count == 2);
+ Item_result r0= args[0]->result_type();
+ Item_result r1= args[1]->result_type();
+
+ if (r0 == REAL_RESULT || r1 == REAL_RESULT ||
+ r0 == STRING_RESULT || r1 ==STRING_RESULT)
+ {
+ count_real_length();
+ max_length= float_length(decimals);
+ hybrid_type= REAL_RESULT;
+ }
+ else if (r0 == DECIMAL_RESULT || r1 == DECIMAL_RESULT)
{
+ hybrid_type= DECIMAL_RESULT;
+ result_precision();
+ }
+ else if (r0 == INT_RESULT && r1 == INT_RESULT)
+ {
+ decimals= 0;
hybrid_type=INT_RESULT;
unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag;
+ result_precision();
}
+ DBUG_PRINT("info", ("Type: %s",
+ (hybrid_type == REAL_RESULT ? "REAL_RESULT" :
+ hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
+ hybrid_type == INT_RESULT ? "INT_RESULT" :
+ "--ILLEGAL!!!--")));
+ DBUG_VOID_RETURN;
}
-String *Item_num_op::val_str(String *str)
+
+/*
+ Set result type of function if it (type) is depends only on first argument
+
+ SYNOPSIS
+ Item_func_num1::find_num_type()
+*/
+void Item_func_num1::find_num_type()
+{
+ DBUG_ENTER("Item_func_num1::find_num_type");
+ DBUG_PRINT("info", ("name %s", func_name()));
+ switch(hybrid_type= args[0]->result_type())
+ {
+ case INT_RESULT:
+ unsigned_flag=args[0]->unsigned_flag;
+ hybrid_type= INT_RESULT;
+ break;
+ case STRING_RESULT:
+ case REAL_RESULT:
+ hybrid_type= REAL_RESULT;
+ max_length= float_length(decimals);
+ break;
+ case DECIMAL_RESULT:
+ hybrid_type= DECIMAL_RESULT;
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ DBUG_PRINT("info", ("Type: %s",
+ (hybrid_type == REAL_RESULT ? "REAL_RESULT" :
+ hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
+ hybrid_type == INT_RESULT ? "INT_RESULT" :
+ "--ILLEGAL!!!--")));
+ DBUG_VOID_RETURN;
+}
+
+
+void Item_func_num1::fix_num_length_and_dec()
+{
+ decimals= args[0]->decimals;
+ max_length= args[0]->max_length;
+}
+
+
+void Item_func_numhybrid::fix_length_and_dec()
+{
+ fix_num_length_and_dec();
+ find_num_type();
+}
+
+
+String *Item_func_numhybrid::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- if (hybrid_type == INT_RESULT)
+ switch (hybrid_type)
{
- longlong nr=val_int();
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value, *val;
+ if (!(val= decimal_op(&decimal_value)))
+ return 0;
+ my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val);
+ my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str);
+ break;
+ }
+ case INT_RESULT:
+ {
+ longlong nr= int_op();
if (null_value)
return 0; /* purecov: inspected */
if (!unsigned_flag)
str->set(nr,&my_charset_bin);
else
str->set((ulonglong) nr,&my_charset_bin);
+ break;
}
- else
+ case REAL_RESULT:
{
- double nr= val_real();
+ double nr=real_op();
if (null_value)
return 0; /* purecov: inspected */
str->set(nr,decimals,&my_charset_bin);
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
}
return str;
}
+double Item_func_numhybrid::val_real()
+{
+ DBUG_ASSERT(fixed == 1);
+ switch (hybrid_type)
+ {
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value, *val;
+ if (!(val= decimal_op(&decimal_value)))
+ return 0.0;
+ double result;
+ my_decimal2double(E_DEC_FATAL_ERROR, val, &result);
+ return result;
+ }
+ case INT_RESULT:
+ return (double)int_op();
+ case REAL_RESULT:
+ return real_op();
+ default:
+ DBUG_ASSERT(0);
+ }
+ return 0.0;
+}
+
+
+longlong Item_func_numhybrid::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ switch (hybrid_type)
+ {
+ case DECIMAL_RESULT:
+ {
+ my_decimal decimal_value, *val;
+ if (!(val= decimal_op(&decimal_value)))
+ return 0;
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &result);
+ return result;
+ }
+ case INT_RESULT:
+ return int_op();
+ case REAL_RESULT:
+ return (longlong)real_op();
+ default:
+ DBUG_ASSERT(0);
+ }
+ return 0;
+}
+
+
+my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value)
+{
+ my_decimal *val= decimal_value;
+ DBUG_ASSERT(fixed == 1);
+ switch (hybrid_type)
+ {
+ case DECIMAL_RESULT:
+ val= decimal_op(decimal_value);
+ break;
+ case INT_RESULT:
+ {
+ longlong result= int_op();
+ int2my_decimal(E_DEC_FATAL_ERROR, result, unsigned_flag, decimal_value);
+ break;
+ }
+ case REAL_RESULT:
+ {
+ double result= int_op();
+ double2my_decimal(E_DEC_FATAL_ERROR, result, decimal_value);
+ break;
+ }
+ case STRING_RESULT:
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ return val;
+}
+
+
void Item_func_signed::print(String *str)
{
str->append("cast(", 5);
@@ -659,26 +909,83 @@ void Item_func_unsigned::print(String *str)
}
-double Item_func_plus::val_real()
+String *Item_decimal_typecast::val_str(String *str)
+{
+ my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
+ my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, &tmp_buf);
+ my_decimal2string(E_DEC_FATAL_ERROR, &tmp_buf, 0, 0, 0, str);
+ return str;
+}
+
+
+double Item_decimal_typecast::val_real()
+{
+ my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
+ double res;
+ my_decimal2double(E_DEC_FATAL_ERROR, tmp, &res);
+ return res;
+}
+
+
+longlong Item_decimal_typecast::val_int()
+{
+ my_decimal tmp_buf, *tmp= val_decimal(&tmp_buf);
+ longlong res;
+ my_decimal2int(E_DEC_FATAL_ERROR, tmp, unsigned_flag, &res);
+ return res;
+}
+
+
+my_decimal *Item_decimal_typecast::val_decimal(my_decimal *dec)
+{
+ my_decimal tmp_buf, *tmp= args[0]->val_decimal(&tmp_buf);
+ my_decimal_round(E_DEC_FATAL_ERROR, tmp, decimals, FALSE, dec);
+ return dec;
+}
+
+
+double Item_func_plus::real_op()
{
- DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real() + args[1]->val_real();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
return value;
}
-longlong Item_func_plus::val_int()
+
+longlong Item_func_plus::int_op()
{
- DBUG_ASSERT(fixed == 1);
- if (hybrid_type == INT_RESULT)
- {
- longlong value=args[0]->val_int()+args[1]->val_int();
- if ((null_value=args[0]->null_value || args[1]->null_value))
- return 0;
- return value;
- }
- return (longlong) Item_func_plus::val_real();
+ longlong value=args[0]->val_int()+args[1]->val_int();
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0;
+ return value;
+}
+
+
+my_decimal *Item_func_plus::decimal_op(my_decimal *decimal_value)
+{
+ my_decimal value1, *val1= args[0]->val_decimal(&value1);
+ if ((null_value= args[0]->null_value))
+ return 0;
+ my_decimal value2, *val2= args[1]->val_decimal(&value2);
+ if ((null_value= args[1]->null_value) ||
+ my_decimal_add(E_DEC_FATAL_ERROR, decimal_value, val1, val2) > 1)
+ return 0;
+ return decimal_value;
+}
+
+/*
+ Set precision of results for additive operations (+ and -)
+
+ SYNOPSIS
+ Item_func_additive_op::result_precision()
+*/
+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);
}
@@ -696,53 +1003,80 @@ void Item_func_minus::fix_length_and_dec()
}
-double Item_func_minus::val_real()
+double Item_func_minus::real_op()
{
- DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real() - args[1]->val_real();
if ((null_value=args[0]->null_value || args[1]->null_value))
return 0.0;
return value;
}
-longlong Item_func_minus::val_int()
+
+longlong Item_func_minus::int_op()
{
- DBUG_ASSERT(fixed == 1);
- if (hybrid_type == INT_RESULT)
- {
- longlong value=args[0]->val_int() - args[1]->val_int();
- if ((null_value=args[0]->null_value || args[1]->null_value))
- return 0;
- return value;
- }
- return (longlong) Item_func_minus::val_real();
+ longlong value=args[0]->val_int() - args[1]->val_int();
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0;
+ return value;
}
-double Item_func_mul::val_real()
+my_decimal *Item_func_minus::decimal_op(my_decimal *decimal_value)
+{
+ my_decimal value1, *val1= args[0]->val_decimal(&value1);
+ if ((null_value= args[0]->null_value))
+ return 0;
+ my_decimal value2, *val2= args[1]->val_decimal(&value2);
+ if ((null_value= args[1]->null_value) ||
+ my_decimal_sub(E_DEC_FATAL_ERROR, decimal_value, val1, val2) > 1)
+ return 0;
+ return decimal_value;
+}
+
+
+double Item_func_mul::real_op()
{
DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real() * args[1]->val_real();
if ((null_value=args[0]->null_value || args[1]->null_value))
- return 0.0; /* purecov: inspected */
+ return 0.0;
return value;
}
-longlong Item_func_mul::val_int()
+
+longlong Item_func_mul::int_op()
{
DBUG_ASSERT(fixed == 1);
- if (hybrid_type == INT_RESULT)
- {
- longlong value=args[0]->val_int()*args[1]->val_int();
- if ((null_value=args[0]->null_value || args[1]->null_value))
- return 0; /* purecov: inspected */
- return value;
- }
- return (longlong) Item_func_mul::val_real();
+ longlong value=args[0]->val_int()*args[1]->val_int();
+ if ((null_value=args[0]->null_value || args[1]->null_value))
+ return 0;
+ return value;
+}
+
+
+my_decimal *Item_func_mul::decimal_op(my_decimal *decimal_value)
+{
+ my_decimal value1, *val1= args[0]->val_decimal(&value1);
+ if ((null_value= args[0]->null_value))
+ return 0;
+ my_decimal value2, *val2= args[1]->val_decimal(&value2);
+ if ((null_value= args[1]->null_value) ||
+ my_decimal_mul(E_DEC_FATAL_ERROR, decimal_value, val1, val2) > 1)
+ return 0;
+ return 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);
}
-double Item_func_div::val_real()
+double Item_func_div::real_op()
{
DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real();
@@ -758,34 +1092,66 @@ double Item_func_div::val_real()
}
-longlong Item_func_div::val_int()
+my_decimal *Item_func_div::decimal_op(my_decimal *decimal_value)
{
- DBUG_ASSERT(fixed == 1);
- if (hybrid_type == INT_RESULT)
+ my_decimal value1, *val1= args[0]->val_decimal(&value1);
+ if ((null_value= args[0]->null_value))
+ return 0;
+ my_decimal value2, *val2= args[1]->val_decimal(&value2);
+ 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))
{
- longlong value=args[0]->val_int();
- longlong val2=args[1]->val_int();
- if ((null_value= args[0]->null_value || args[1]->null_value))
- return 0;
- if (val2 == 0)
- {
- signal_divide_by_null();
- return 0;
- }
- return value/val2;
+ case E_DEC_TRUNCATED:
+ case E_DEC_OK:
+ return decimal_value;
+ case E_DEC_DIV_ZERO:
+ signal_divide_by_null();
+ default:
+ return 0;
}
- return (longlong) Item_func_div::val_real();
+}
+
+
+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);
}
void Item_func_div::fix_length_and_dec()
{
- decimals=max(args[0]->decimals,args[1]->decimals)+2;
- set_if_smaller(decimals, NOT_FIXED_DEC);
- max_length=args[0]->max_length - args[0]->decimals + decimals;
- uint tmp=float_length(decimals);
- set_if_smaller(max_length,tmp);
- maybe_null=1;
+ DBUG_ENTER("Item_func_div::fix_length_and_dec");
+ Item_num_op::fix_length_and_dec();
+ switch(hybrid_type)
+ {
+ case REAL_RESULT:
+ {
+ decimals=max(args[0]->decimals,args[1]->decimals)+2;
+ set_if_smaller(decimals, NOT_FIXED_DEC);
+ max_length=args[0]->max_length - args[0]->decimals + decimals;
+ uint tmp=float_length(decimals);
+ set_if_smaller(max_length,tmp);
+ break;
+ }
+ case INT_RESULT:
+ hybrid_type= DECIMAL_RESULT;
+ DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT"));
+ result_precision();
+ break;
+ case DECIMAL_RESULT:
+ result_precision();
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ maybe_null= 1; // devision by zero
+ DBUG_VOID_RETURN;
}
@@ -808,15 +1174,43 @@ longlong Item_func_int_div::val_int()
}
+String *Item_func_int_div::val_str(String*str)
+{
+ longlong nr= val_int();
+ if (null_value)
+ return 0; /* purecov: inspected */
+ if (!unsigned_flag)
+ str->set(nr,&my_charset_bin);
+ else
+ str->set((ulonglong) nr,&my_charset_bin);
+ return str;
+}
+
+
void Item_func_int_div::fix_length_and_dec()
{
- find_num_type();
max_length=args[0]->max_length - args[0]->decimals;
maybe_null=1;
+ unsigned_flag=args[0]->unsigned_flag | args[1]->unsigned_flag;
}
-double Item_func_mod::val_real()
+longlong Item_func_mod::int_op()
+{
+ DBUG_ASSERT(fixed == 1);
+ longlong value= args[0]->val_int();
+ longlong val2= args[1]->val_int();
+ if ((null_value= args[0]->null_value || args[1]->null_value))
+ return 0; /* purecov: inspected */
+ if (val2 == 0)
+ {
+ signal_divide_by_null();
+ return 0;
+ }
+ return value % val2;
+}
+
+double Item_func_mod::real_op()
{
DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real();
@@ -831,67 +1225,81 @@ double Item_func_mod::val_real()
return fmod(value,val2);
}
-longlong Item_func_mod::val_int()
+
+my_decimal *Item_func_mod::decimal_op(my_decimal *decimal_value)
{
- DBUG_ASSERT(fixed == 1);
- longlong value= args[0]->val_int();
- longlong val2= args[1]->val_int();
- if ((null_value= args[0]->null_value || args[1]->null_value))
- return 0; /* purecov: inspected */
- if (val2 == 0)
+ my_decimal value1, *val1= args[0]->val_decimal(&value1);
+ if ((null_value= args[0]->null_value))
+ return 0;
+ my_decimal value2, *val2= args[1]->val_decimal(&value2);
+ if ((null_value= args[1]->null_value))
+ return 0;
+ switch (my_decimal_mod(E_DEC_FATAL_ERROR & ~E_DEC_DIV_ZERO, decimal_value,
+ val1, val2))
{
+ case E_DEC_TRUNCATED:
+ case E_DEC_OK:
+ return decimal_value;
+ case E_DEC_DIV_ZERO:
signal_divide_by_null();
+ default:
return 0;
}
- return value % val2;
}
-void Item_func_mod::fix_length_and_dec()
+
+void Item_func_mod::result_precision()
{
- Item_num_op::fix_length_and_dec();
+ decimals= max(args[0]->decimals, args[1]->decimals);
+ max_length= max(args[0]->max_length, args[1]->max_length);
}
-double Item_func_neg::val_real()
+double Item_func_neg::real_op()
{
- DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real();
- null_value=args[0]->null_value;
+ null_value= args[0]->null_value;
return -value;
}
-longlong Item_func_neg::val_int()
+longlong Item_func_neg::int_op()
{
- DBUG_ASSERT(fixed == 1);
- longlong value=args[0]->val_int();
- null_value=args[0]->null_value;
+ longlong value= args[0]->val_int();
+ null_value= args[0]->null_value;
return -value;
}
-void Item_func_neg::fix_length_and_dec()
+my_decimal *Item_func_neg::decimal_op(my_decimal *decimal_value)
{
- enum Item_result arg_result= args[0]->result_type();
- enum Item::Type arg_type= args[0]->type();
- decimals=args[0]->decimals;
- max_length=args[0]->max_length;
- hybrid_type= REAL_RESULT;
-
- /*
- We need to account for added '-' in the following cases:
- A) argument is a real or integer positive constant - in this case
- argument's max_length is set to actual number of bytes occupied, and not
- maximum number of bytes real or integer may require. Note that all
- constants are non negative so we don't need to account for removed '-'.
- B) argument returns a string.
- */
- if (arg_result == STRING_RESULT ||
- (arg_type == REAL_ITEM && ((Item_real*)args[0])->value >= 0) ||
- (arg_type == INT_ITEM && ((Item_int*)args[0])->value > 0))
- max_length++;
+ my_decimal val, *value= args[0]->val_decimal(&val);
+ if (!(null_value= args[0]->null_value))
+ {
+ my_decimal2decimal(value, decimal_value);
+ my_decimal_neg(decimal_value);
+ }
+ return decimal_value;
+}
+
+
+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;
+}
- if (args[0]->result_type() == INT_RESULT)
+
+void Item_func_signproc::fix_length_and_dec()
+{
+ DBUG_ENTER("Item_func_signproc::fix_length_and_dec");
+ Item_func_num1::fix_length_and_dec();
+ if (hybrid_type == INT_RESULT &&
+ args[0]->type() == INT_ITEM &&
+ ((ulonglong) ((Item_uint*) args[0])->value >=
+ (ulonglong) LONGLONG_MIN))
{
/*
If this is in integer context keep the context as integer
@@ -903,42 +1311,47 @@ void Item_func_neg::fix_length_and_dec()
(This is needed because the lex parser doesn't anymore handle
signed integers)
*/
- if (args[0]->type() != INT_ITEM ||
- ((ulonglong) ((Item_uint*) args[0])->value <=
- (ulonglong) LONGLONG_MIN))
- hybrid_type= INT_RESULT;
+ hybrid_type= DECIMAL_RESULT;
+ DBUG_PRINT("info", ("Type changed: DECIMAL_RESULT"));
}
+ DBUG_VOID_RETURN;
}
-double Item_func_abs::val_real()
+double Item_func_abs::real_op()
{
- DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real();
- null_value=args[0]->null_value;
+ null_value= args[0]->null_value;
return fabs(value);
}
-longlong Item_func_abs::val_int()
+longlong Item_func_abs::int_op()
{
- DBUG_ASSERT(fixed == 1);
- longlong value=args[0]->val_int();
- null_value=args[0]->null_value;
+ longlong value= args[0]->val_int();
+ null_value= args[0]->null_value;
return value >= 0 ? value : -value;
}
-void Item_func_abs::fix_length_and_dec()
+my_decimal *Item_func_abs::decimal_op(my_decimal *decimal_value)
{
- decimals=args[0]->decimals;
- max_length=args[0]->max_length;
- hybrid_type= REAL_RESULT;
- if (args[0]->result_type() == INT_RESULT)
+ my_decimal val, *value= args[0]->val_decimal(&val);
+ if (!(null_value= args[0]->null_value))
{
- hybrid_type= INT_RESULT;
- unsigned_flag= 1;
+ my_decimal2decimal(value, decimal_value);
+ if (decimal_value->sign())
+ my_decimal_neg(decimal_value);
}
+ return decimal_value;
+}
+
+
+void Item_func_abs::fix_length_and_dec()
+{
+ Item_func_num1::fix_length_and_dec();
+ if (hybrid_type == INT_RESULT)
+ unsigned_flag= 1;
}
@@ -1139,42 +1552,148 @@ void Item_func_integer::fix_length_and_dec()
decimals=0;
}
-longlong Item_func_ceiling::val_int()
+void Item_func_int_val::fix_num_length_and_dec()
{
- DBUG_ASSERT(fixed == 1);
- double value= args[0]->val_real();
- null_value=args[0]->null_value;
+ max_length= args[0]->max_length - (args[0]->decimals ?
+ args[0]->decimals + 1 :
+ 0) + 2;
+ uint tmp= float_length(decimals);
+ set_if_smaller(max_length,tmp);
+ decimals= 0;
+}
+
+
+void Item_func_int_val::find_num_type()
+{
+ DBUG_ENTER("Item_func_int_val::find_num_type");
+ DBUG_PRINT("info", ("name %s", func_name()));
+ switch(hybrid_type= args[0]->result_type())
+ {
+ case STRING_RESULT:
+ case REAL_RESULT:
+ hybrid_type= REAL_RESULT;
+ max_length= float_length(decimals);
+ break;
+ case INT_RESULT:
+ case DECIMAL_RESULT:
+ /*
+ -2 because in most high position can't be used any digit for longlong
+ and one position for increasing value during operation
+ */
+ if ((args[0]->max_length - args[0]->decimals) >=
+ (DECIMAL_LONGLONG_DIGITS - 2))
+ {
+ hybrid_type= DECIMAL_RESULT;
+ }
+ else
+ {
+ unsigned_flag= args[0]->unsigned_flag;
+ hybrid_type= INT_RESULT;
+ }
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ DBUG_PRINT("info", ("Type: %s",
+ (hybrid_type == REAL_RESULT ? "REAL_RESULT" :
+ hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
+ hybrid_type == INT_RESULT ? "INT_RESULT" :
+ "--ILLEGAL!!!--")));
+
+ DBUG_VOID_RETURN;
+}
+
+
+longlong Item_func_ceiling::int_op()
+{
+ /*
+ the volatile's for BUG #3051 to calm optimizer down (because of gcc's
+ bug)
+ */
+ volatile double value= args[0]->val_real();
+ null_value= args[0]->null_value;
return (longlong) ceil(value);
}
-longlong Item_func_floor::val_int()
+
+double Item_func_ceiling::real_op()
{
- DBUG_ASSERT(fixed == 1);
- // the volatile's for BUG #3051 to calm optimizer down (because of gcc's bug)
+ /*
+ the volatile's for BUG #3051 to calm optimizer down (because of gcc's
+ bug)
+ */
volatile double value= args[0]->val_real();
- null_value=args[0]->null_value;
+ null_value= args[0]->null_value;
+ return ceil(value);
+}
+
+
+my_decimal *Item_func_ceiling::decimal_op(my_decimal *decimal_value)
+{
+ my_decimal val, *value= args[0]->val_decimal(&val);
+ if ((null_value= args[0]->null_value))
+ return 0;
+ if (my_decimal_ceiling(E_DEC_FATAL_ERROR, value, decimal_value) > 1)
+ return 0;
+ return decimal_value;
+}
+
+
+longlong Item_func_floor::int_op()
+{
+ /*
+ the volatile's for BUG #3051 to calm optimizer down (because of gcc's
+ bug)
+ */
+ volatile double value= args[0]->val_real();
+ null_value= args[0]->null_value;
return (longlong) floor(value);
}
-void Item_func_round::fix_length_and_dec()
+
+double Item_func_floor::real_op()
{
- max_length=args[0]->max_length;
- decimals=args[0]->decimals;
+ /*
+ the volatile's for BUG #3051 to calm optimizer down (because of gcc's
+ bug)
+ */
+ volatile double value= args[0]->val_real();
+ null_value= args[0]->null_value;
+ return floor(value);
+}
+
+
+my_decimal *Item_func_floor::decimal_op(my_decimal *decimal_value)
+{
+ my_decimal val, *value= args[0]->val_decimal(&val);
+ if ((null_value= args[0]->null_value))
+ return 0;
+ if (my_decimal_floor(E_DEC_FATAL_ERROR, value, decimal_value) > 1)
+ return 0;
+ return decimal_value;
+}
+
+
+void Item_func_round::fix_num_length_and_dec()
+{
+ max_length= args[0]->max_length;
+ decimals= NOT_FIXED_DEC;
if (args[1]->const_item())
{
int tmp=(int) args[1]->val_int();
if (tmp < 0)
decimals=0;
else
- decimals=min(tmp,NOT_FIXED_DEC);
+ decimals=min(tmp, NOT_FIXED_DEC);
}
}
-double Item_func_round::val_real()
+double Item_func_round::real_op()
{
- DBUG_ASSERT(fixed == 1);
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;
/*
@@ -1201,6 +1720,58 @@ double Item_func_round::val_real()
}
+longlong Item_func_round::int_op()
+{
+ longlong value= args[0]->val_int();
+ int dec=(int) args[1]->val_int();
+ decimals= 0;
+ uint abs_dec;
+ if ((null_value= args[0]->null_value || args[1]->null_value))
+ return 0;
+ if (dec >= 0)
+ return value; // integer have not digits after point
+
+ abs_dec= -dec;
+ double tmp;
+ /*
+ 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;
+
+ tmp= (abs_dec < array_elements(log_10) ?
+ log_10[abs_dec] : pow(10.0, (double) abs_dec));
+
+ if (truncate)
+ {
+ if (unsigned_flag)
+ tmp2= floor(((double)((ulonglong)value))/tmp)*tmp;
+ else if (value >= 0)
+ tmp2= floor(((double)value)/tmp)*tmp;
+ else
+ tmp2= ceil(((double)value)/tmp)*tmp;
+ }
+ else
+ tmp2= rint(((double)value)/tmp)*tmp;
+ return (longlong)tmp2;
+}
+
+
+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
+ if ((null_value= args[0]->null_value || args[1]->null_value))
+ return 0;
+ if (my_decimal_round(E_DEC_FATAL_ERROR, value, dec, truncate,
+ decimal_value) > 1)
+ return 0;
+ return decimal_value;
+}
+
+
bool Item_func_rand::fix_fields(THD *thd, struct st_table_list *tables,
Item **ref)
{
@@ -1291,10 +1862,8 @@ void Item_func_min_max::fix_length_and_dec()
for (uint i=0 ; i < arg_count ; i++)
{
- if (max_length < args[i]->max_length)
- max_length=args[i]->max_length;
- if (decimals < args[i]->decimals)
- decimals=args[i]->decimals;
+ set_if_bigger(max_length, args[i]->max_length);
+ set_if_bigger(decimals, args[i]->decimals);
if (!args[i]->maybe_null)
maybe_null=0;
cmp_type=item_cmp_type(cmp_type,args[i]->result_type());
@@ -1319,6 +1888,14 @@ String *Item_func_min_max::val_str(String *str)
str->set((ulonglong) nr,&my_charset_bin);
return str;
}
+ case DECIMAL_RESULT:
+ {
+ my_decimal dec_buf, *dec_val= val_decimal(&dec_buf);
+ if (null_value)
+ return 0;
+ my_decimal2string(E_DEC_FATAL_ERROR, dec_val, 0, 0, 0, str);
+ return str;
+ }
case REAL_RESULT:
{
double nr= val_real();
@@ -1357,7 +1934,7 @@ String *Item_func_min_max::val_str(String *str)
}
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
return 0;
}
@@ -1410,6 +1987,40 @@ longlong Item_func_min_max::val_int()
return value;
}
+
+my_decimal *Item_func_min_max::val_decimal(my_decimal *dec)
+{
+ DBUG_ASSERT(fixed == 1);
+ my_decimal tmp_buf, *tmp, *res= NULL;
+ null_value=1;
+ for (uint i=0; i < arg_count ; i++)
+ {
+ if (null_value)
+ {
+ res= args[i]->val_decimal(dec);
+ null_value= args[i]->null_value;
+ }
+ else
+ {
+ tmp= args[i]->val_decimal(&tmp_buf);
+ if (args[i]->null_value)
+ continue;
+ if ((my_decimal_cmp(tmp, res) * cmp_sign) < 0)
+ {
+ if (tmp == &tmp_buf)
+ {
+ my_decimal2decimal(tmp, dec);
+ res= dec;
+ }
+ else
+ res= tmp;
+ }
+ }
+ }
+ return res;
+}
+
+
longlong Item_func_length::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -1533,6 +2144,21 @@ longlong Item_func_field::val_int()
return (longlong) (i);
}
}
+ else if (cmp_type == DECIMAL_RESULT)
+ {
+ my_decimal dec_arg_buf, *dec_arg,
+ dec_buf, *dec= args[0]->val_decimal(&dec_buf);
+ if (args[0]->is_null())
+ return 0;
+ for (uint i=1; i < arg_count; i++)
+ {
+ dec_arg= args[i]->val_decimal(&dec_arg_buf);
+ if (args[i]->is_null())
+ continue;
+ if (!my_decimal_cmp(dec_arg, dec))
+ return (longlong) (i);
+ }
+ }
else
{
double val= args[0]->val_real();
@@ -1776,7 +2402,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
arg != arg_end ;
arg++,i++)
{
- if (!(*arg)->fixed &&
+ if (!(*arg)->fixed &&
(*arg)->fix_fields(thd, tables, arg))
DBUG_RETURN(1);
// we can't assign 'item' before, because fix_fields() can change arg
@@ -1792,7 +2418,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
Moreover, some arguments can represent a numeric input
which doesn't effect the result character set and collation.
There is no a general rule for UDF. Everything depends on
- the particular user definted function.
+ the particular user defined function.
*/
if (item->collation.collation->state & MY_CS_BINSORT)
func->collation.set(&my_charset_bin);
@@ -1803,7 +2429,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
const_item_cache&=item->const_item();
f_args.arg_type[i]=item->result_type();
}
- //TODO: why all folowing memory is not allocated with 1 call of sql_alloc?
+ //TODO: why all following memory is not allocated with 1 call of sql_alloc?
if (!(buffers=new String[arg_count]) ||
!(f_args.args= (char**) sql_alloc(arg_count * sizeof(char *))) ||
!(f_args.lengths= (ulong*) sql_alloc(arg_count * sizeof(long))) ||
@@ -1903,6 +2529,7 @@ bool udf_handler::get_arguments()
f_args.args[i]=0;
switch (f_args.arg_type[i]) {
case STRING_RESULT:
+ case DECIMAL_RESULT:
{
String *res=args[i]->val_str(&buffers[str_count++]);
if (!(args[i]->null_value))
@@ -1930,7 +2557,7 @@ bool udf_handler::get_arguments()
break;
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
break;
}
@@ -1975,6 +2602,31 @@ String *udf_handler::val_str(String *str,String *save_str)
}
+my_decimal *udf_handler::val_decimal(my_bool *null_value, my_decimal *dec_buf)
+{
+ char buf[DECIMAL_MAX_STR_LENGTH+1], *end;
+ ulong res_length= DECIMAL_MAX_STR_LENGTH;
+
+ if (get_arguments())
+ {
+ *null_value=1;
+ return 0;
+ }
+ char *(*func)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *)=
+ (char* (*)(UDF_INIT *, UDF_ARGS *, char *, ulong *, uchar *, uchar *))
+ u_d->func;
+
+ char *res= func(&initid, &f_args, buf, &res_length, &is_null, &error);
+ if (is_null || error)
+ {
+ *null_value= 1;
+ return 0;
+ }
+ buf[res_length]= 0;
+ str2my_decimal(E_DEC_FATAL_ERROR, buf, dec_buf, &end);
+ return dec_buf;
+}
+
double Item_func_udf_float::val_real()
{
@@ -2021,6 +2673,59 @@ String *Item_func_udf_int::val_str(String *str)
return str;
}
+
+longlong Item_func_udf_decimal::val_int()
+{
+ my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
+ if (null_value)
+ return 0;
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
+ return result;
+}
+
+
+double Item_func_udf_decimal::val_real()
+{
+ my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
+ if (null_value)
+ return 0.0;
+ double result;
+ my_decimal2double(E_DEC_FATAL_ERROR, dec, &result);
+ return result;
+}
+
+
+my_decimal *Item_func_udf_decimal::val_decimal(my_decimal *dec_buf)
+{
+ DBUG_ASSERT(fixed == 1);
+ DBUG_ENTER("Item_func_udf_decimal::val_decimal");
+ DBUG_PRINT("info",("result_type: %d arg_count: %d",
+ args[0]->result_type(), arg_count));
+
+ DBUG_RETURN(udf.val_decimal(&null_value, dec_buf));
+}
+
+
+String *Item_func_udf_decimal::val_str(String *str)
+{
+ my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
+ if (null_value)
+ return 0;
+ if (str->length() < DECIMAL_MAX_STR_LENGTH)
+ str->length(DECIMAL_MAX_STR_LENGTH);
+ my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf);
+ my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, '0', str);
+ return str;
+}
+
+
+void Item_func_udf_decimal::fix_length_and_dec()
+{
+ fix_num_length_and_dec();
+}
+
+
/* Default max_length is max argument length */
void Item_func_udf_str::fix_length_and_dec()
@@ -2417,7 +3122,7 @@ longlong Item_func_benchmark::val_int()
break;
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
return 0;
}
@@ -2583,6 +3288,8 @@ bool Item_func_set_user_var::update_hash(void *ptr, uint length,
entry->value[length]= 0; // Store end \0
}
memcpy(entry->value,ptr,length);
+ if (type == DECIMAL_RESULT)
+ ((my_decimal*)entry->value)->fix_buffer_pointer();
entry->length= length;
entry->type=type;
entry->collation.set(cs, dv);
@@ -2598,7 +3305,7 @@ bool Item_func_set_user_var::update_hash(void *ptr, uint length,
/* Get the value of a variable as a double */
-double user_var_entry::val(my_bool *null_value)
+double user_var_entry::val_real(my_bool *null_value)
{
if ((*null_value= (value == 0)))
return 0.0;
@@ -2608,6 +3315,12 @@ double user_var_entry::val(my_bool *null_value)
return *(double*) value;
case INT_RESULT:
return (double) *(longlong*) value;
+ case DECIMAL_RESULT:
+ {
+ double result;
+ my_decimal2double(E_DEC_FATAL_ERROR, (my_decimal *)value, &result);
+ return result;
+ }
case STRING_RESULT:
return my_atof(value); // This is null terminated
case ROW_RESULT:
@@ -2630,6 +3343,12 @@ longlong user_var_entry::val_int(my_bool *null_value)
return (longlong) *(double*) value;
case INT_RESULT:
return *(longlong*) value;
+ case DECIMAL_RESULT:
+ {
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *)value, 1, &result);
+ return result;
+ }
case STRING_RESULT:
{
int error;
@@ -2658,6 +3377,9 @@ String *user_var_entry::val_str(my_bool *null_value, String *str,
case INT_RESULT:
str->set(*(longlong*) value, &my_charset_bin);
break;
+ case DECIMAL_RESULT:
+ my_decimal2string(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, 0, 0, str);
+ break;
case STRING_RESULT:
if (str->copy(value, length, collation.collation))
str= 0; // EOM error
@@ -2668,16 +3390,43 @@ String *user_var_entry::val_str(my_bool *null_value, String *str,
return(str);
}
+/* Get the value of a variable as a decimal */
+
+my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val)
+{
+ if ((*null_value= (value == 0)))
+ return 0;
+
+ switch (type) {
+ case REAL_RESULT:
+ double2my_decimal(E_DEC_FATAL_ERROR, *(double*) value, val);
+ break;
+ case INT_RESULT:
+ int2my_decimal(E_DEC_FATAL_ERROR, *(longlong*) value, 0, val);
+ break;
+ case DECIMAL_RESULT:
+ val= (my_decimal *)value;
+ break;
+ case STRING_RESULT:
+ str2my_decimal(E_DEC_FATAL_ERROR, value, length, collation.collation, val);
+ break;
+ case ROW_RESULT:
+ DBUG_ASSERT(1); // Impossible
+ break;
+ }
+ return(val);
+}
+
/*
This functions is invoked on SET @variable or @variable:= expression.
- Evaluete (and check expression), store results.
+ Evaluate (and check expression), store results.
SYNOPSYS
Item_func_set_user_var::check()
NOTES
- For now it always return OK. All problem with value evalueting
- will be catched by thd->net.report_error check in sql_set_variables().
+ For now it always return OK. All problem with value evaluating
+ will be caught by thd->net.report_error check in sql_set_variables().
RETURN
FALSE OK.
@@ -2704,9 +3453,14 @@ Item_func_set_user_var::check()
save_result.vstr= args[0]->val_str(&value);
break;
}
+ case DECIMAL_RESULT:
+ {
+ save_result.vdec= args[0]->val_decimal(&decimal_buff);
+ break;
+ }
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
break;
}
@@ -2725,7 +3479,7 @@ Item_func_set_user_var::check()
the value method used by the user
RETURN
- 0 Ok
+ 0 OK
1 EOM Error
*/
@@ -2762,9 +3516,20 @@ Item_func_set_user_var::update()
args[0]->collation.derivation);
break;
}
+ case DECIMAL_RESULT:
+ {
+ if (!save_result.vdec) // Null value
+ res= update_hash((void*) 0, 0, DECIMAL_RESULT, &my_charset_bin,
+ DERIVATION_NONE);
+ else
+ res= update_hash((void*) save_result.vdec,
+ sizeof(my_decimal), DECIMAL_RESULT,
+ &my_charset_bin, DERIVATION_NONE);
+ break;
+ }
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
break;
}
@@ -2777,7 +3542,7 @@ double Item_func_set_user_var::val_real()
DBUG_ASSERT(fixed == 1);
check();
update(); // Store expression
- return entry->val(&null_value);
+ return entry->val_real(&null_value);
}
longlong Item_func_set_user_var::val_int()
@@ -2797,6 +3562,15 @@ String *Item_func_set_user_var::val_str(String *str)
}
+my_decimal *Item_func_set_user_var::val_decimal(my_decimal *val)
+{
+ DBUG_ASSERT(fixed == 1);
+ check();
+ update(); // Store expression
+ return entry->val_decimal(&null_value, val);
+}
+
+
void Item_func_set_user_var::print(String *str)
{
str->append("(@", 2);
@@ -2833,7 +3607,16 @@ double Item_func_get_user_var::val_real()
DBUG_ASSERT(fixed == 1);
if (!var_entry)
return 0.0; // No such variable
- return (var_entry->val(&null_value));
+ return (var_entry->val_real(&null_value));
+}
+
+
+my_decimal *Item_func_get_user_var::val_decimal(my_decimal *dec)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (!var_entry)
+ return 0;
+ return var_entry->val_decimal(&null_value, dec);
}
@@ -2864,7 +3647,7 @@ longlong Item_func_get_user_var::val_int()
RETURN
0 OK
- 1 Failed to put appropiate record into binary log
+ 1 Failed to put appropriate record into binary log
*/
@@ -2888,8 +3671,8 @@ int get_var_with_binlog(THD *thd, LEX_STRING &name,
that it gets into the binlog (if it didn't, the slave could be
influenced by a variable of the same name previously set by another
thread).
- We create it like if it had been explicitely set with SET before.
- The 'new' mimicks what sql_yacc.yy does when 'SET @a=10;'.
+ We create it like if it had been explicitly set with SET before.
+ The 'new' mimics what sql_yacc.yy does when 'SET @a=10;'.
sql_set_variables() is what is called from 'case SQLCOM_SET_OPTION'
in dispatch_command()). Instead of building a one-element list to pass to
sql_set_variables(), we could instead manually call check() and update();
@@ -2920,7 +3703,7 @@ int get_var_with_binlog(THD *thd, LEX_STRING &name,
uint size;
/*
First we need to store value of var_entry, when the next situation
- appers:
+ appears:
> set @a:=1;
> insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1);
We have to write to binlog value @a= 1;
@@ -2982,7 +3765,13 @@ void Item_func_get_user_var::fix_length_and_dec()
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);
+ break;
case ROW_RESULT: // Keep compiler happy
+ default:
+ DBUG_ASSERT(0);
break;
}
}
@@ -3539,7 +4328,7 @@ const char *
Item_func_sp::func_name() const
{
THD *thd= current_thd;
- /* Calculate length to avoud reallocation of string for sure */
+ /* Calculate length to avoid reallocation of string for sure */
uint len= ((m_name->m_db.length +
m_name->m_name.length)*2 + //characters*quoting
2 + // ` and `
@@ -3590,7 +4379,7 @@ Item_func_sp::execute(Item **itp)
#endif
/*
- We don't need to surpress senfing of ok packet here (by setting
+ We don't need to suppress sending of OK packet here (by setting
thd->net.no_send_ok to true), because we are not allowing statements
in functions now.
*/
@@ -3663,9 +4452,13 @@ Item_func_sp::fix_length_and_dec()
decimals= 0;
max_length= 21;
break;
+ case DECIMAL_RESULT:
+ // TODO: where to find real precision and scale?
+ decimals= min(DECIMAL_MAX_LENGTH / 2, NOT_FIXED_DEC - 1);
+ max_length= DECIMAL_MAX_LENGTH;
case ROW_RESULT:
default:
- // This case should never be choosen
+ // This case should never be chosen
DBUG_ASSERT(0);
break;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index a3618cca23e..20f70fce575 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -133,7 +133,10 @@ public:
void print(String *str);
void print_op(String *str);
void print_args(String *str, uint from);
- void fix_num_length_and_dec();
+ virtual void fix_num_length_and_dec();
+ void count_only_length();
+ void count_real_length();
+ void count_decimal_length();
inline bool get_arg0_date(TIME *ltime, uint fuzzy_date)
{
return (null_value=args[0]->get_date(ltime, fuzzy_date));
@@ -148,7 +151,9 @@ public:
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg);
Item *get_tmp_table_item(THD *thd);
-
+
+ my_decimal *val_decimal(my_decimal *);
+
bool agg_arg_collations(DTCollation &c, Item **items, uint nitems,
uint flags= 0);
bool agg_arg_collations_for_comparison(DTCollation &c,
@@ -172,49 +177,70 @@ public:
longlong val_int()
{ DBUG_ASSERT(fixed == 1); return (longlong) val_real(); }
enum Item_result result_type () const { return REAL_RESULT; }
- void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); }
+ void fix_length_and_dec()
+ { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); }
};
-class Item_num_func :public Item_func
+class Item_func_numhybrid: public Item_func
{
- protected:
+protected:
Item_result hybrid_type;
public:
- Item_num_func(Item *a) :Item_func(a),hybrid_type(REAL_RESULT) {}
- Item_num_func(Item *a,Item *b) :Item_func(a,b),hybrid_type(REAL_RESULT) {}
- String *val_str(String*str);
- longlong val_int()
- { DBUG_ASSERT(fixed == 1); return (longlong) val_real(); }
+ Item_func_numhybrid(Item *a) :Item_func(a),hybrid_type(REAL_RESULT)
+ {}
+ Item_func_numhybrid(Item *a,Item *b)
+ :Item_func(a,b),hybrid_type(REAL_RESULT)
+ {}
+
enum Item_result result_type () const { return hybrid_type; }
- void fix_length_and_dec() { fix_num_length_and_dec(); }
+ void fix_length_and_dec();
+ void fix_num_length_and_dec();
+ virtual void find_num_type()= 0; /* To be called from fix_length_and_dec */
+
+ double val_real();
+ longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
+ String *val_str(String*str);
+
+ virtual longlong int_op()= 0;
+ virtual double real_op()= 0;
+ virtual my_decimal *decimal_op(my_decimal *)= 0;
bool is_null() { (void) val_real(); return null_value; }
};
+/* function where type of result detected by first argument */
+class Item_func_num1: public Item_func_numhybrid
+{
+public:
+ Item_func_num1(Item *a) :Item_func_numhybrid(a) {}
+ Item_func_num1(Item *a, Item *b) :Item_func_numhybrid(a, b) {}
-class Item_num_op :public Item_func
+ void fix_num_length_and_dec();
+ void find_num_type();
+};
+
+
+/* Base class for operations like '+', '-', '*' */
+class Item_num_op :public Item_func_numhybrid
{
- protected:
- Item_result hybrid_type;
public:
- Item_num_op(Item *a,Item *b) :Item_func(a,b),hybrid_type(REAL_RESULT) {}
- String *val_str(String*str);
+ Item_num_op(Item *a,Item *b) :Item_func_numhybrid(a, b) {}
+ virtual void result_precision()= 0;
void print(String *str) { print_op(str); }
- enum Item_result result_type () const { return hybrid_type; }
- void fix_length_and_dec() { fix_num_length_and_dec(); find_num_type(); }
- void find_num_type(void);
- bool is_null() { (void) val_real(); return null_value; }
+ void find_num_type();
};
class Item_int_func :public Item_func
{
public:
- Item_int_func() :Item_func() { max_length=21; }
- Item_int_func(Item *a) :Item_func(a) { max_length=21; }
- Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length=21; }
- Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) { max_length=21; }
- Item_int_func(List<Item> &list) :Item_func(list) { max_length=21; }
+ Item_int_func() :Item_func() { max_length= 21; }
+ Item_int_func(Item *a) :Item_func(a) { max_length= 21; }
+ Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length= 21; }
+ Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c)
+ { max_length= 21; }
+ Item_int_func(List<Item> &list) :Item_func(list) { max_length= 21; }
Item_int_func(THD *thd, Item_int_func *item) :Item_func(thd, item) {}
double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
String *val_str(String*str);
@@ -257,22 +283,51 @@ public:
};
-class Item_func_plus :public Item_num_op
+class Item_decimal_typecast :public Item_func
{
+ my_decimal decimal_value;
public:
- Item_func_plus(Item *a,Item *b) :Item_num_op(a,b) {}
- const char *func_name() const { return "+"; }
+ Item_decimal_typecast(Item *a, int len, int dec) :Item_func(a)
+ {
+ max_length= len + 2;
+ decimals= dec;
+ }
+ String *val_str(String *str);
double val_real();
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; }
+ void fix_length_and_dec() {};
+};
+
+
+class Item_func_additive_op :public Item_num_op
+{
+public:
+ Item_func_additive_op(Item *a,Item *b) :Item_num_op(a,b) {}
+ void result_precision();
+};
+
+
+class Item_func_plus :public Item_func_additive_op
+{
+public:
+ Item_func_plus(Item *a,Item *b) :Item_func_additive_op(a,b) {}
+ const char *func_name() const { return "+"; }
+ longlong int_op();
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
};
-class Item_func_minus :public Item_num_op
+class Item_func_minus :public Item_func_additive_op
{
public:
- Item_func_minus(Item *a,Item *b) :Item_num_op(a,b) {}
+ Item_func_minus(Item *a,Item *b) :Item_func_additive_op(a,b) {}
const char *func_name() const { return "-"; }
- double val_real();
- longlong val_int();
+ longlong int_op();
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
void fix_length_and_dec();
};
@@ -282,8 +337,10 @@ class Item_func_mul :public Item_num_op
public:
Item_func_mul(Item *a,Item *b) :Item_num_op(a,b) {}
const char *func_name() const { return "*"; }
- double val_real();
- longlong val_int();
+ longlong int_op();
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
+ void result_precision();
};
@@ -291,22 +348,27 @@ class Item_func_div :public Item_num_op
{
public:
Item_func_div(Item *a,Item *b) :Item_num_op(a,b) {}
- double val_real();
- longlong val_int();
+ longlong int_op() { DBUG_ASSERT(0); }
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
const char *func_name() const { return "/"; }
void fix_length_and_dec();
+ void result_precision();
};
-class Item_func_int_div :public Item_num_op
+class Item_func_int_div :public Item_func
{
public:
- Item_func_int_div(Item *a,Item *b) :Item_num_op(a,b)
- { hybrid_type=INT_RESULT; }
+ Item_func_int_div(Item *a,Item *b) :Item_func(a,b)
+ {}
double val_real() { DBUG_ASSERT(fixed == 1); return (double) val_int(); }
longlong val_int();
+ String *val_str(String*str);
const char *func_name() const { return "DIV"; }
void fix_length_and_dec();
+ void print(String *str) { print_op(str); }
+ enum Item_result result_type () const { return INT_RESULT; }
};
@@ -314,37 +376,47 @@ class Item_func_mod :public Item_num_op
{
public:
Item_func_mod(Item *a,Item *b) :Item_num_op(a,b) {}
- double val_real();
- longlong val_int();
+ longlong int_op();
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
const char *func_name() const { return "%"; }
+ void result_precision();
+};
+
+
+class Item_func_signproc :public Item_func_num1
+{
+public:
+ Item_func_signproc(Item *a) :Item_func_num1(a) {}
+ Item_func_signproc(Item *a, Item *b) :Item_func_num1(a, b) {}
void fix_length_and_dec();
};
-class Item_func_neg :public Item_num_func
+class Item_func_neg :public Item_func_signproc
{
public:
- Item_func_neg(Item *a) :Item_num_func(a) {}
- double val_real();
- longlong val_int();
+ Item_func_neg(Item *a) :Item_func_signproc(a) {}
+ double real_op();
+ longlong int_op();
+ my_decimal *decimal_op(my_decimal *);
const char *func_name() const { return "-"; }
- void fix_length_and_dec();
+ void fix_num_length_and_dec();
};
-class Item_func_abs :public Item_num_func
+class Item_func_abs :public Item_func_num1
{
public:
- Item_func_abs(Item *a) :Item_num_func(a) {}
+ Item_func_abs(Item *a) :Item_func_num1(a) {}
+ double real_op();
+ longlong int_op();
+ my_decimal *decimal_op(my_decimal *);
const char *func_name() const { return "abs"; }
- double val_real();
- longlong val_int();
- enum Item_result result_type () const
- { return args[0]->result_type() == INT_RESULT ? INT_RESULT : REAL_RESULT; }
void fix_length_and_dec();
};
-// A class to handle logaritmic and trigometric functions
+// A class to handle logarithmic and trigonometric functions
class Item_dec_func :public Item_real_func
{
@@ -491,34 +563,49 @@ public:
};
-class Item_func_ceiling :public Item_func_integer
+class Item_func_int_val :public Item_func_num1
+{
+public:
+ Item_func_int_val(Item *a) :Item_func_num1(a) {}
+ void fix_num_length_and_dec();
+ void find_num_type();
+};
+
+
+class Item_func_ceiling :public Item_func_int_val
{
- Item_func_ceiling(); /* Never called */
public:
- Item_func_ceiling(Item *a) :Item_func_integer(a) {}
+ Item_func_ceiling(Item *a) :Item_func_int_val(a) {}
const char *func_name() const { return "ceiling"; }
- longlong val_int();
+ longlong int_op();
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
};
-class Item_func_floor :public Item_func_integer
+
+class Item_func_floor :public Item_func_int_val
{
public:
- Item_func_floor(Item *a) :Item_func_integer(a) {}
+ Item_func_floor(Item *a) :Item_func_int_val(a) {}
const char *func_name() const { return "floor"; }
- longlong val_int();
+ longlong int_op();
+ double real_op();
+ my_decimal *decimal_op(my_decimal *);
};
/* This handles round and truncate */
-class Item_func_round :public Item_real_func
+class Item_func_round :public Item_func_num1
{
bool truncate;
public:
- Item_func_round(Item *a,Item *b,bool trunc_arg)
- :Item_real_func(a,b),truncate(trunc_arg) {}
+ Item_func_round(Item *a, Item *b, bool trunc_arg)
+ :Item_func_num1(a,b), truncate(trunc_arg) {}
const char *func_name() const { return truncate ? "truncate" : "round"; }
- double val_real();
- void fix_length_and_dec();
+ double real_op();
+ longlong int_op();
+ my_decimal *decimal_op(my_decimal *);
+ void fix_num_length_and_dec();
};
@@ -554,7 +641,8 @@ class Item_func_units :public Item_real_func
:Item_real_func(a),name(name_arg),mul(mul_arg),add(add_arg) {}
double val_real();
const char *func_name() const { return name; }
- void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); }
+ void fix_length_and_dec()
+ { decimals= NOT_FIXED_DEC; max_length= float_length(decimals); }
};
@@ -569,6 +657,7 @@ public:
double val_real();
longlong val_int();
String *val_str(String *);
+ my_decimal *val_decimal(my_decimal *);
void fix_length_and_dec();
enum Item_result result_type () const { return cmp_type; }
table_map not_null_tables() const { return 0; }
@@ -755,7 +844,11 @@ public:
Item_func_last_insert_id(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "last_insert_id"; }
- void fix_length_and_dec() { if (arg_count) max_length= args[0]->max_length; }
+ void fix_length_and_dec()
+ {
+ if (arg_count)
+ max_length= args[0]->max_length;
+ }
};
class Item_func_benchmark :public Item_int_func
@@ -809,6 +902,14 @@ class Item_func_udf_float :public Item_udf_func
DBUG_ASSERT(fixed == 1);
return (longlong) Item_func_udf_float::val_real();
}
+ my_decimal *val_decimal(my_decimal *dec_buf)
+ {
+ double res=val_real();
+ if (null_value)
+ return NULL;
+ double2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf);
+ return dec_buf;
+ }
double val_real();
String *val_str(String *str);
void fix_length_and_dec() { fix_num_length_and_dec(); }
@@ -825,7 +926,22 @@ public:
double val_real() { return (double) Item_func_udf_int::val_int(); }
String *val_str(String *str);
enum Item_result result_type () const { return INT_RESULT; }
- void fix_length_and_dec() { decimals=0; max_length=21; }
+ void fix_length_and_dec() { decimals= 0; max_length= 21; }
+};
+
+
+class Item_func_udf_decimal :public Item_udf_func
+{
+public:
+ Item_func_udf_decimal(udf_func *udf_arg) :Item_udf_func(udf_arg) {}
+ Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list)
+ :Item_udf_func(udf_arg,list) {}
+ longlong val_int();
+ double val_real();
+ my_decimal *val_decimal(my_decimal *);
+ String *val_str(String *str);
+ enum Item_result result_type () const { return DECIMAL_RESULT; }
+ void fix_length_and_dec();
};
@@ -852,6 +968,14 @@ public:
return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10,
(char**) 0, &err_not_used) : (longlong) 0;
}
+ my_decimal *val_decimal(my_decimal *dec_buf)
+ {
+ String *res=val_str(&str_value);
+ if (!res)
+ return NULL;
+ string2my_decimal(E_DEC_FATAL_ERROR, res, dec_buf);
+ return dec_buf;
+ }
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec();
};
@@ -876,6 +1000,15 @@ public:
};
+class Item_func_udf_decimal :public Item_int_func
+{
+public:
+ Item_func_udf_decimal(udf_func *udf_arg) :Item_int_func() {}
+ Item_func_udf_decimal(udf_func *udf_arg, List<Item> &list) :Item_int_func(list) {}
+ my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; }
+};
+
+
class Item_func_udf_str :public Item_func
{
public:
@@ -934,7 +1067,7 @@ class Item_master_pos_wait :public Item_int_func
};
-/* Handling of user definiable variables */
+/* Handling of user definable variables */
class user_var_entry;
@@ -945,11 +1078,13 @@ class Item_func_set_user_var :public Item_func
user_var_entry *entry;
char buffer[MAX_FIELD_WIDTH];
String value;
+ my_decimal decimal_buff;
union
{
longlong vint;
double vreal;
String *vstr;
+ my_decimal *vdec;
} save_result;
String save_buff;
@@ -961,6 +1096,7 @@ public:
double val_real();
longlong val_int();
String *val_str(String *str);
+ my_decimal *val_decimal(my_decimal *);
bool update_hash(void *ptr, uint length, enum Item_result type,
CHARSET_INFO *cs, Derivation dv);
bool check();
@@ -986,6 +1122,7 @@ public:
LEX_STRING get_name() { return name; }
double val_real();
longlong val_int();
+ my_decimal *val_decimal(my_decimal*);
String *val_str(String* str);
void fix_length_and_dec();
void print(String *str);
@@ -1095,7 +1232,8 @@ public:
enum Cast_target
{
ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT,
- ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR
+ ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR,
+ ITEM_CAST_DECIMAL
};
@@ -1161,6 +1299,22 @@ public:
return d;
}
+ my_decimal *val_decimal(my_decimal *dec_buf)
+ {
+ Item *it;
+ my_decimal *result;
+
+ if (execute(&it))
+ {
+ null_value= 1;
+ return NULL;
+ }
+ result= it->val_decimal(dec_buf);
+ null_value= it->null_value;
+ return result;
+ }
+
+
String *val_str(String *str)
{
Item *it;
diff --git a/sql/item_row.cc b/sql/item_row.cc
index a5a430785d6..08c682afa85 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -100,10 +100,9 @@ void Item_row::split_sum_func(THD *thd, Item **ref_pointer_array,
(item->used_tables() && item->type() != REF_ITEM))
{
uint el= fields.elements;
- ref_pointer_array[el]=*arg;
+ ref_pointer_array[el]= *arg;
Item *new_item= new Item_ref(ref_pointer_array + el, 0, (*arg)->name);
fields.push_front(*arg);
- ref_pointer_array[el]= *arg;
thd->change_item_tree(arg, new_item);
}
}
diff --git a/sql/item_row.h b/sql/item_row.h
index 64bd5cbbb44..e6b23eebb49 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -56,6 +56,11 @@ public:
illegal_method_call((const char*)"val_str");
return 0;
};
+ my_decimal *val_decimal(my_decimal *)
+ {
+ illegal_method_call((const char*)"val_decimal");
+ return 0;
+ };
bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
table_map used_tables() const { return used_tables_cache; };
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index e3f1053dc73..55185a5f75b 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -49,6 +49,8 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
uint nr_of_decimals(const char *str)
{
+ if (strchr(str,'e') || strchr(str,'E'))
+ return NOT_FIXED_DEC;
if ((str=strchr(str,'.')))
{
const char *start= ++str;
@@ -1784,10 +1786,9 @@ void Item_func_make_set::split_sum_func(THD *thd, Item **ref_pointer_array,
(item->used_tables() && item->type() != REF_ITEM))
{
uint el= fields.elements;
- ref_pointer_array[el]=item;
+ ref_pointer_array[el]= item;
Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name);
fields.push_front(item);
- ref_pointer_array[el]= item;
thd->change_item_tree(&item, new_item);
}
Item_str_func::split_sum_func(thd, ref_pointer_array, fields);
@@ -1803,7 +1804,7 @@ void Item_func_make_set::fix_length_and_dec()
for (uint i=0 ; i < arg_count ; i++)
max_length+=args[i]->max_length;
-
+
used_tables_cache|= item->used_tables();
not_null_tables_cache&= item->not_null_tables();
const_item_cache&= item->const_item();
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 97c42c3abf6..dc50c9a4ccd 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -397,8 +397,7 @@ public:
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- return (!item->fixed &&
- item->fix_fields(thd, tlist, &item) ||
+ return ((!item->fixed && item->fix_fields(thd, tlist, &item)) ||
item->check_cols(1) ||
Item_func::fix_fields(thd, tlist, ref));
}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index b5cb01494fa..8d392232f02 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -143,7 +143,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
res= engine->prepare();
- // all transformetion is done (used by prepared statements)
+ // all transformation is done (used by prepared statements)
changed= 1;
if (!res)
@@ -246,7 +246,7 @@ void Item_subselect::update_used_tables()
{
if (!engine->uncacheable())
{
- // did all used tables become ststic?
+ // did all used tables become static?
if (!(used_tables_cache & ~engine->upper_select_const_tables()))
const_item_cache= 1;
}
@@ -292,7 +292,7 @@ Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param,
const_item_cache= parent->get_const_item_cache();
/*
- this subquery alwais creates during preparation, so we can assign
+ this subquery always creates during preparation, so we can assign
thd here
*/
thd= thd_param;
@@ -356,7 +356,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
!(select_lex->item_list.head()->type() == FIELD_ITEM ||
select_lex->item_list.head()->type() == REF_ITEM) &&
/*
- switch off this optimisation for prepare statement,
+ switch off this optimization for prepare statement,
because we do not rollback this changes
TODO: make rollback for it, or special name resolving mode in 5.0.
*/
@@ -374,7 +374,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
}
substitution= select_lex->item_list.head();
/*
- as far as we moved content to upper leven, field which depend of
+ as far as we moved content to upper level, field which depend of
'upper' select is not really dependent => we remove this dependence
*/
substitution->walk(&Item::remove_dependence_processor,
@@ -494,7 +494,7 @@ longlong Item_singlerow_subselect::val_int()
}
}
-String *Item_singlerow_subselect::val_str (String *str)
+String *Item_singlerow_subselect::val_str(String *str)
{
if (!exec() && !value->null_value)
{
@@ -509,10 +509,41 @@ String *Item_singlerow_subselect::val_str (String *str)
}
+my_decimal *Item_singlerow_subselect::val_decimal(my_decimal *decimal_value)
+{
+ if (!exec() && !value->null_value)
+ {
+ null_value= 0;
+ return value->val_decimal(decimal_value);
+ }
+ else
+ {
+ reset();
+ return 0;
+ }
+}
+
+
+bool Item_singlerow_subselect::val_bool()
+{
+ if (!exec() && !value->null_value)
+ {
+ null_value= 0;
+ return value->val_bool();
+ }
+ else
+ {
+ reset();
+ return 0;
+ }
+}
+
+
Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex):
Item_subselect()
{
DBUG_ENTER("Item_exists_subselect::Item_exists_subselect");
+ bool val_bool();
init(select_lex, new select_exists_subselect(this));
max_columns= UINT_MAX;
null_value= 0; //can't be NULL
@@ -622,6 +653,32 @@ String *Item_exists_subselect::val_str(String *str)
return str;
}
+
+my_decimal *Item_exists_subselect::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (exec())
+ {
+ reset();
+ return 0;
+ }
+ int2my_decimal(E_DEC_FATAL_ERROR, value, 0, decimal_value);
+ return decimal_value;
+}
+
+
+bool Item_exists_subselect::val_bool()
+{
+ DBUG_ASSERT(fixed == 1);
+ if (exec())
+ {
+ reset();
+ return 0;
+ }
+ return value;
+}
+
+
double Item_in_subselect::val_real()
{
DBUG_ASSERT(fixed == 1);
@@ -752,7 +809,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
/*
Item_sum_(max|min) can't substitute other item => we can use 0 as
- reference
+ reference, also Item_sum_(max|min) can't be fixed after creation, so
+ we do not check item->fixed
*/
if (item->fix_fields(thd, join->tables_list, 0))
goto err;
@@ -774,7 +832,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
// left expression belong to outer select
SELECT_LEX *current= thd->lex->current_select, *up;
thd->lex->current_select= up= current->return_after_parsing();
- if (!left_expr->fixed &&
+ if (!left_expr->fixed &&
left_expr->fix_fields(thd, up->get_table_list(), &left_expr))
{
thd->lex->current_select= current;
@@ -803,7 +861,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
thd->lex->current_select= current;
/*
- As far as Item_ref_in_optimizer do not substitude itself on fix_fields
+ As far as Item_ref_in_optimizer do not substitute itself on fix_fields
we can use same item for all selects.
*/
expr= new Item_direct_ref((Item**)optimizer->get_cache(),
@@ -840,6 +898,10 @@ Item_in_subselect::single_value_transformer(JOIN *join,
*/
select_lex->having= join->having= and_items(join->having, item);
select_lex->having_fix_field= 1;
+ /*
+ we do not check join->having->fixed, because Item_and (from and_items)
+ or comparison function (from func->create) can't be fixed after creation
+ */
tmp= join->having->fix_fields(thd, join->tables_list, 0);
select_lex->having_fix_field= 0;
if (tmp)
@@ -871,6 +933,11 @@ Item_in_subselect::single_value_transformer(JOIN *join,
new Item_cond_and(having, join->having) :
having);
select_lex->having_fix_field= 1;
+ /*
+ we do not check join->having->fixed, because Item_and (from
+ and_items) or comparison function (from func->create) can't be
+ fixed after creation
+ */
tmp= join->having->fix_fields(thd, join->tables_list, 0);
select_lex->having_fix_field= 0;
if (tmp)
@@ -887,6 +954,10 @@ Item_in_subselect::single_value_transformer(JOIN *join,
argument (reference) to fix_fields()
*/
select_lex->where= join->conds= and_items(join->conds, item);
+ /*
+ we do not check join->conds->fixed, because Item_and can't be fixed
+ after creation
+ */
if (join->conds->fix_fields(thd, join->tables_list, 0))
goto err;
}
@@ -908,6 +979,10 @@ Item_in_subselect::single_value_transformer(JOIN *join,
item= new Item_cond_or(new Item_func_isnull(left_expr), item);
select_lex->having= join->having= item;
select_lex->having_fix_field= 1;
+ /*
+ we do not check join->having->fixed, because comparison function
+ (from func->create) can't be fixed after creation
+ */
tmp= join->having->fix_fields(thd, join->tables_list, 0);
select_lex->having_fix_field= 0;
if (tmp)
@@ -982,7 +1057,7 @@ Item_in_subselect::row_value_transformer(JOIN *join)
goto err;
}
- // we will refer to apper level cache array => we have to save it in PS
+ // we will refer to upper level cache array => we have to save it in PS
optimizer->keep_top_level_cache();
thd->lex->current_select= current;
@@ -1000,9 +1075,9 @@ Item_in_subselect::row_value_transformer(JOIN *join)
check_cols(left_expr->el(i)->cols()))
goto err;
Item *func= new Item_ref_null_helper(this,
- select_lex->ref_pointer_array+i,
- (char *) "<no matter>",
- (char *) "<list ref>");
+ select_lex->ref_pointer_array+i,
+ (char *) "<no matter>",
+ (char *) "<list ref>");
func=
eq_creator.create(new Item_direct_ref((*optimizer->get_cache())->
addr(i),
@@ -1023,6 +1098,10 @@ Item_in_subselect::row_value_transformer(JOIN *join)
*/
select_lex->having= join->having= and_items(join->having, item);
select_lex->having_fix_field= 1;
+ /*
+ join->having can't be fixed after creation, so we do not check
+ join->having->fixed
+ */
if (join->having->fix_fields(thd, join->tables_list, 0))
{
select_lex->having_fix_field= 0;
@@ -1038,6 +1117,10 @@ Item_in_subselect::row_value_transformer(JOIN *join)
argument (reference) to fix_fields()
*/
select_lex->where= join->conds= and_items(join->conds, item);
+ /*
+ join->conds can't be fixed after creation, so we do not check
+ join->conds->fixed
+ */
if (join->conds->fix_fields(thd, join->tables_list, 0))
goto err;
}
@@ -1533,7 +1616,7 @@ void subselect_indexsubquery_engine::print(String *str)
str->append(" on ", 4);
str->append(key_info->name);
if (check_null)
- str->append(" chicking NULL", 14);
+ str->append(" checking NULL", 14);
if (cond)
{
str->append(" where ", 7);
@@ -1545,7 +1628,7 @@ void subselect_indexsubquery_engine::print(String *str)
/*
change select_result object of engine
- SINOPSYS
+ SYNOPSIS
subselect_single_select_engine::change_result()
si new subselect Item
res new select_result object
@@ -1567,7 +1650,7 @@ bool subselect_single_select_engine::change_result(Item_subselect *si,
/*
change select_result object of engine
- SINOPSYS
+ SYNOPSIS
subselect_single_select_engine::change_result()
si new subselect Item
res new select_result object
@@ -1590,7 +1673,7 @@ bool subselect_union_engine::change_result(Item_subselect *si,
/*
change select_result emulation, never should be called
- SINOPSYS
+ SYNOPSIS
subselect_single_select_engine::change_result()
si new subselect Item
res new select_result object
@@ -1611,7 +1694,7 @@ bool subselect_uniquesubquery_engine::change_result(Item_subselect *si,
/*
Report about presence of tables in subquery
- SINOPSYS
+ SYNOPSIS
subselect_single_select_engine::no_tables()
RETURN
@@ -1627,7 +1710,7 @@ bool subselect_single_select_engine::no_tables()
/*
Report about presence of tables in subquery
- SINOPSYS
+ SYNOPSIS
subselect_union_engine::no_tables()
RETURN
@@ -1648,7 +1731,7 @@ bool subselect_union_engine::no_tables()
/*
Report about presence of tables in subquery
- SINOPSYS
+ SYNOPSIS
subselect_uniquesubquery_engine::no_tables()
RETURN
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 53fe21a9bb6..4661fae81da 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -142,6 +142,8 @@ public:
double val_real();
longlong val_int ();
String *val_str (String *);
+ my_decimal *val_decimal(my_decimal *);
+ bool val_bool();
enum Item_result result_type() const;
void fix_length_and_dec();
@@ -155,7 +157,7 @@ public:
friend class select_singlerow_subselect;
};
-/* used in static ALL/ANY optimisation */
+/* used in static ALL/ANY optimization */
class select_max_min_finder_subselect;
class Item_maxmin_subselect :public Item_singlerow_subselect
{
@@ -193,6 +195,8 @@ public:
longlong val_int();
double val_real();
String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *);
+ bool val_bool();
void fix_length_and_dec();
void print(String *str);
@@ -294,7 +298,7 @@ public:
virtual int prepare()= 0;
virtual void fix_length_and_dec(Item_cache** row)= 0;
virtual int exec()= 0;
- virtual uint cols()= 0; /* return number of columnss in select */
+ virtual uint cols()= 0; /* return number of columns in select */
virtual uint8 uncacheable()= 0; /* query is uncacheable */
enum Item_result type() { return res_type; }
virtual void exclude()= 0;
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 29837c3afbd..2ecc1eb083c 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -124,6 +124,16 @@ Item *Item_sum::get_tmp_table_item(THD *thd)
return sum_item;
}
+
+my_decimal *Item_sum::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed);
+ DBUG_ASSERT(decimal_value);
+ int2my_decimal(E_DEC_FATAL_ERROR, val_int(), unsigned_flag, decimal_value);
+ return decimal_value;
+}
+
+
bool Item_sum::walk (Item_processor processor, byte *argument)
{
if (arg_count)
@@ -139,6 +149,32 @@ bool Item_sum::walk (Item_processor processor, byte *argument)
}
+Field *Item_sum::create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_length)
+{
+ switch (result_type()) {
+ case REAL_RESULT:
+ return new Field_double(max_length,maybe_null,name,table,decimals);
+ case INT_RESULT:
+ return new Field_longlong(max_length,maybe_null,name,table,unsigned_flag);
+ case STRING_RESULT:
+ if (max_length > 255 && convert_blob_length)
+ return new Field_varstring(convert_blob_length, maybe_null,
+ name, 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);
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
+ }
+}
+
+
String *
Item_sum_num::val_str(String *str)
{
@@ -151,6 +187,17 @@ Item_sum_num::val_str(String *str)
}
+my_decimal *Item_sum_num::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed == 1);
+ double nr= val_real();
+ if (null_value)
+ return 0;
+ double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value);
+ return (decimal_value);
+}
+
+
String *
Item_sum_int::val_str(String *str)
{
@@ -184,8 +231,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
return TRUE;
- if (decimals < args[i]->decimals)
- decimals=args[i]->decimals;
+ set_if_bigger(decimals, args[i]->decimals);
maybe_null |= args[i]->maybe_null;
}
result_field=0;
@@ -198,6 +244,29 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
+Item_sum_hybrid::Item_sum_hybrid(THD *thd, Item_sum_hybrid *item)
+ :Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type),
+ hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign),
+ used_table_cache(item->used_table_cache), was_values(item->was_values)
+{
+ switch (hybrid_type)
+ {
+ case INT_RESULT:
+ sum_int= item->sum_int;
+ break;
+ case DECIMAL_RESULT:
+ my_decimal2decimal(&item->sum_dec, &sum_dec);
+ break;
+ case REAL_RESULT:
+ sum= item->sum;
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ collation.set(item->collation);
+}
+
bool
Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
@@ -217,20 +286,29 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
item->fix_fields(thd, tables, args) ||
(item= args[0])->check_cols(1))
return TRUE;
+ decimals=item->decimals;
- hybrid_type= item->result_type();
- if (hybrid_type == INT_RESULT)
- {
- max_length=20;
- }
- else if (hybrid_type == REAL_RESULT)
- {
- max_length=float_length(decimals);
- }else
+ switch (hybrid_type= item->result_type())
{
- max_length=item->max_length;
- }
- decimals=item->decimals;
+ case INT_RESULT:
+ max_length= 20;
+ sum_int= 0;
+ break;
+ case DECIMAL_RESULT:
+ max_length= item->max_length;
+ my_decimal_set_zero(&sum_dec);
+ break;
+ case REAL_RESULT:
+ max_length= float_length(decimals);
+ sum= 0.0;
+ break;
+ case STRING_RESULT:
+ max_length= item->max_length;
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ };
/* MIN/MAX can return NULL for empty set indepedent of the used column */
maybe_null= 1;
unsigned_flag=item->unsigned_flag;
@@ -252,6 +330,19 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
** reset and add of sum_func
***********************************************************************/
+Item_sum_sum::Item_sum_sum(THD *thd, Item_sum_sum *item)
+ :Item_sum_num(thd, item), hybrid_type(item->hybrid_type),
+ curr_dec_buff(item->curr_dec_buff)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal2decimal(item->dec_buffs, dec_buffs);
+ my_decimal2decimal(item->dec_buffs + 1, dec_buffs + 1);
+ }
+ else
+ sum= item->sum;
+}
+
Item *Item_sum_sum::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_sum(thd, this);
@@ -260,30 +351,128 @@ Item *Item_sum_sum::copy_or_same(THD* thd)
void Item_sum_sum::clear()
{
- null_value=1; sum=0.0;
+ DBUG_ENTER("Item_sum_sum::clear");
+ null_value=1;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ curr_dec_buff= 0;
+ my_decimal_set_zero(dec_buffs);
+ }
+ else
+ sum= 0.0;
+ DBUG_VOID_RETURN;
+}
+
+
+void Item_sum_sum::fix_length_and_dec()
+{
+ DBUG_ENTER("Item_sum_sum::fix_length_and_dec");
+ maybe_null=null_value=1;
+ decimals= args[0]->decimals;
+ switch (args[0]->result_type())
+ {
+ case REAL_RESULT:
+ case STRING_RESULT:
+ hybrid_type= REAL_RESULT;
+ sum= 0.0;
+ 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);
+ curr_dec_buff= 0;
+ hybrid_type= DECIMAL_RESULT;
+ my_decimal_set_zero(dec_buffs);
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+ DBUG_PRINT("info", ("Type: %s (%d, %d)",
+ (hybrid_type == REAL_RESULT ? "REAL_RESULT" :
+ hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
+ hybrid_type == INT_RESULT ? "INT_RESULT" :
+ "--ILLEGAL!!!--"),
+ max_length,
+ (int)decimals));
+ DBUG_VOID_RETURN;
}
bool Item_sum_sum::add()
{
- sum+= args[0]->val_real();
- if (!args[0]->null_value)
- null_value= 0;
- return 0;
+ DBUG_ENTER("Item_sum_sum::add");
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1),
+ val, dec_buffs + curr_dec_buff);
+ curr_dec_buff^= 1;
+ null_value= 0;
+ }
+ }
+ else
+ {
+ sum+= args[0]->val_real();
+ if (!args[0]->null_value)
+ null_value= 0;
+ }
+ DBUG_RETURN(0);
+}
+
+
+longlong Item_sum_sum::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, unsigned_flag,
+ &result);
+ return result;
+ }
+ return Item_sum_num::val_int();
}
double Item_sum_sum::val_real()
{
DBUG_ASSERT(fixed == 1);
+ if (hybrid_type == DECIMAL_RESULT)
+ my_decimal2double(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, &sum);
return sum;
}
+String *Item_sum_sum::val_str(String*str)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ if (null_value)
+ return NULL;
+ my_decimal_round(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff, decimals,
+ FALSE, dec_buffs + curr_dec_buff);
+ my_decimal2string(E_DEC_FATAL_ERROR, dec_buffs + curr_dec_buff,
+ 0, 0, 0, str);
+ return str;
+ }
+ return Item_sum_num::val_str(str);
+}
+
+
+my_decimal *Item_sum_sum::val_decimal(my_decimal *val)
+{
+ DBUG_ASSERT(hybrid_type == DECIMAL_RESULT);
+ return(dec_buffs + curr_dec_buff);
+}
+
/* Item_sum_sum_distinct */
Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item)
- :Item_sum_num(item), sum(0.0), tree(0)
+ :Item_sum_sum(item), tree(0)
{
/*
quick_group is an optimizer hint, which means that GROUP BY can be
@@ -297,12 +486,24 @@ Item_sum_sum_distinct::Item_sum_sum_distinct(Item *item)
Item_sum_sum_distinct::Item_sum_sum_distinct(THD *thd,
Item_sum_sum_distinct *original)
- :Item_sum_num(thd, original), sum(0.0), tree(0)
+ :Item_sum_sum(thd, original), tree(0), dec_bin_buff(original->dec_bin_buff)
{
quick_group= 0;
}
+void Item_sum_sum_distinct::fix_length_and_dec()
+{
+ Item_sum_sum::fix_length_and_dec();
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ dec_bin_buff= (byte *)
+ sql_alloc(my_decimal_get_binary_size(args[0]->max_length,
+ args[0]->decimals));
+ }
+}
+
+
Item *
Item_sum_sum_distinct::copy_or_same(THD *thd)
{
@@ -320,10 +521,11 @@ C_MODE_END
bool Item_sum_sum_distinct::setup(THD *thd)
{
+ DBUG_ENTER("Item_sum_sum_distinct::setup");
SELECT_LEX *select_lex= thd->lex->current_select;
/* what does it mean??? */
if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
- return 1;
+ DBUG_RETURN(1);
DBUG_ASSERT(tree == 0); /* setup can not be called twice */
@@ -337,17 +539,25 @@ bool Item_sum_sum_distinct::setup(THD *thd)
TODO: if underlying item result fits in 4 bytes we can take advantage
of it and have tree of long/ulong. It gives 10% performance boost
*/
- static uint key_length= sizeof(double);
- tree= new Unique(simple_raw_key_cmp, &key_length, key_length,
+ uint *key_length_ptr= (uint *)thd->alloc(sizeof(uint));
+ *key_length_ptr= ((hybrid_type == DECIMAL_RESULT) ?
+ my_decimal_get_binary_size(args[0]->max_length,
+ args[0]->decimals) :
+ sizeof(double));
+ tree= new Unique(simple_raw_key_cmp, key_length_ptr, *key_length_ptr,
thd->variables.max_heap_table_size);
- return tree == 0;
+ DBUG_PRINT("info", ("tree 0x%lx, key length %d", (ulong)tree,
+ *key_length_ptr));
+ DBUG_RETURN(tree == 0);
}
void Item_sum_sum_distinct::clear()
{
+ DBUG_ENTER("Item_sum_sum_distinct::clear");
DBUG_ASSERT(tree); /* we always have a tree */
null_value= 1;
tree->reset();
+ DBUG_VOID_RETURN;
}
void Item_sum_sum_distinct::cleanup()
@@ -360,25 +570,71 @@ void Item_sum_sum_distinct::cleanup()
bool Item_sum_sum_distinct::add()
{
- /* args[0]->val_real() may reset args[0]->null_value */
- double val= args[0]->val_real();
- if (!args[0]->null_value)
+ DBUG_ENTER("Item_sum_sum_distinct::add");
+ if (hybrid_type == DECIMAL_RESULT)
{
- DBUG_ASSERT(tree);
- null_value= 0;
- if (val)
- return tree->unique_add(&val);
+ my_decimal value, *val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ DBUG_ASSERT(tree);
+ null_value= 0;
+ my_decimal2binary(E_DEC_FATAL_ERROR, val, dec_bin_buff,
+ args[0]->max_length, args[0]->decimals);
+ DBUG_RETURN(tree->unique_add(dec_bin_buff));
+ }
}
- return 0;
+ else
+ {
+ /* args[0]->val() may reset args[0]->null_value */
+ double val= args[0]->val_real();
+ if (!args[0]->null_value)
+ {
+ DBUG_ASSERT(tree);
+ null_value= 0;
+ DBUG_PRINT("info", ("real: %lg, tree 0x%lx", val, (ulong)tree));
+ if (val)
+ DBUG_RETURN(tree->unique_add(&val));
+ }
+ else
+ DBUG_PRINT("info", ("real: NULL"));
+ }
+ DBUG_RETURN(0);
+}
+
+
+void Item_sum_sum_distinct::add_real(double val)
+{
+ DBUG_ENTER("Item_sum_sum_distinct::add_real");
+ sum+= val;
+ DBUG_PRINT("info", ("sum %lg, val %lg", sum, val));
+ DBUG_VOID_RETURN;
+}
+
+
+void Item_sum_sum_distinct::add_decimal(byte *val)
+{
+ binary2my_decimal(E_DEC_FATAL_ERROR, val, &tmp_dec,
+ args[0]->max_length, args[0]->decimals);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs + (curr_dec_buff^1),
+ &tmp_dec, dec_buffs + curr_dec_buff);
+ curr_dec_buff^= 1;
}
C_MODE_START
-static int sum_sum_distinct(void *element, element_count num_of_dups,
- void *item_sum_sum_distinct)
+static int sum_sum_distinct_real(void *element, element_count num_of_dups,
+ void *item_sum_sum_distinct)
+{
+ ((Item_sum_sum_distinct *)
+ (item_sum_sum_distinct))->add_real(* (double *) element);
+ return 0;
+}
+
+static int sum_sum_distinct_decimal(void *element, element_count num_of_dups,
+ void *item_sum_sum_distinct)
{
((Item_sum_sum_distinct *)
- (item_sum_sum_distinct))->add(* (double *) element);
+ (item_sum_sum_distinct))->add_decimal((byte *)element);
return 0;
}
@@ -386,16 +642,86 @@ C_MODE_END
double Item_sum_sum_distinct::val_real()
{
+ DBUG_ENTER("Item_sum_sum_distinct::val");
/*
We don't have a tree only if 'setup()' hasn't been called;
this is the case of sql_select.cc:return_zero_rows.
*/
- sum= 0.0;
- if (tree)
- tree->walk(sum_sum_distinct, (void *) this);
- return sum;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ /* Item_sum_sum_distinct::val_decimal do not use argument */
+ my_decimal *val= val_decimal(0);
+ if (!null_value)
+ my_decimal2double(E_DEC_FATAL_ERROR, val, &sum);
+ }
+ else
+ {
+ sum= 0.0;
+ DBUG_PRINT("info", ("tree 0x%lx", (ulong)tree));
+ if (tree)
+ tree->walk(sum_sum_distinct_real, (void *) this);
+ }
+ DBUG_RETURN(sum);
}
+
+my_decimal *Item_sum_sum_distinct::val_decimal(my_decimal *fake)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal_set_zero(dec_buffs);
+ curr_dec_buff= 0;
+ if (tree)
+ tree->walk(sum_sum_distinct_decimal, (void *)this);
+ }
+ else
+ {
+ double real= val_real();
+ double2my_decimal(E_DEC_FATAL_ERROR, real, dec_buffs + curr_dec_buff);
+ }
+ return(dec_buffs + curr_dec_buff);
+}
+
+
+longlong Item_sum_sum_distinct::val_int()
+{
+ longlong i;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ /* Item_sum_sum_distinct::val_decimal do not use argument */
+ my_decimal *val= val_decimal(0);
+ if (!null_value)
+ my_decimal2int(E_DEC_FATAL_ERROR, val, unsigned_flag, &i);
+ }
+ else
+ i= (longlong) val_real();
+ return i;
+}
+
+
+String *Item_sum_sum_distinct::val_str(String *str)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ /* Item_sum_sum_distinct::val_decimal do not use argument */
+ my_decimal *val= val_decimal(0);
+ if (null_value)
+ return 0;
+ my_decimal_round(E_DEC_FATAL_ERROR, val, decimals, FALSE, val);
+ my_decimal2string(E_DEC_FATAL_ERROR, val, 0, 0, 0, str);
+ }
+ else
+ {
+ double nr= val_real();
+ if (null_value)
+ return 0;
+ str->set(nr, decimals, &my_charset_bin);
+ }
+ return str;
+}
+
+
/* end of Item_sum_sum_distinct */
Item *Item_sum_count::copy_or_same(THD* thd)
@@ -442,6 +768,20 @@ void Item_sum_count::cleanup()
/*
Avgerage
*/
+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);
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ f_scale= args[0]->decimals;
+ max_length= DECIMAL_MAX_LENGTH + (f_scale ? 1 : 0);
+ f_precision= DECIMAL_MAX_LENGTH;
+ dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale);
+ }
+}
+
Item *Item_sum_avg::copy_or_same(THD* thd)
{
@@ -449,21 +789,43 @@ Item *Item_sum_avg::copy_or_same(THD* thd)
}
+Field *Item_sum_avg::create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_len)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ if (group)
+ return new Field_string(dec_bin_size + sizeof(longlong),
+ 0, name, table, &my_charset_bin);
+ else
+ return new Field_new_decimal(f_precision,
+ maybe_null, name, table, f_scale);
+ }
+ else
+ {
+ if (group)
+ return new Field_string(sizeof(double)+sizeof(longlong),
+ 0, name,table,&my_charset_bin);
+ else
+ return new Field_double(max_length, maybe_null, name, table, decimals);
+ }
+}
+
+
void Item_sum_avg::clear()
{
- sum=0.0; count=0;
+ Item_sum_sum::clear();
+ count=0;
}
bool Item_sum_avg::add()
{
- double nr= args[0]->val_real();
+ if (Item_sum_sum::add())
+ return TRUE;
if (!args[0]->null_value)
- {
- sum+=nr;
count++;
- }
- return 0;
+ return FALSE;
}
double Item_sum_avg::val_real()
@@ -474,11 +836,46 @@ double Item_sum_avg::val_real()
null_value=1;
return 0.0;
}
- null_value=0;
- return sum/ulonglong2double(count);
+ return Item_sum_sum::val_real() / ulonglong2double(count);
}
+my_decimal *Item_sum_avg::val_decimal(my_decimal *val)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (!count)
+ {
+ null_value=1;
+ return NULL;
+ }
+ my_decimal sum, cnt;
+ const my_decimal *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);
+ return val;
+}
+
+
+String *Item_sum_avg::val_str(String *str)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *dec_val= val_decimal(&value);
+ if (null_value)
+ return NULL;
+ my_decimal_round(E_DEC_FATAL_ERROR, dec_val, decimals, FALSE, &value);
+ my_decimal2string(E_DEC_FATAL_ERROR, &value, 0, 0, 0, str);
+ return str;
+ }
+ double nr= val_real();
+ if (null_value)
+ return NULL;
+ str->set(nr, decimals, &my_charset_bin);
+ return str;
+}
+
+
+
/*
Standard deviation
*/
@@ -500,26 +897,140 @@ Item *Item_sum_std::copy_or_same(THD* thd)
Variance
*/
+
+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)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ memcpy(dec_sum, item->dec_sum, sizeof(item->dec_sum));
+ memcpy(dec_sqr, item->dec_sqr, sizeof(item->dec_sqr));
+ for (int i=0; i<2; i++)
+ {
+ dec_sum[i].fix_buffer_pointer();
+ dec_sqr[i].fix_buffer_pointer();
+ }
+ }
+ else
+ {
+ sum= item->sum;
+ sum_sqr= item->sum_sqr;
+ }
+}
+
+
+void Item_sum_variance::fix_length_and_dec()
+{
+ DBUG_ENTER("Item_sum_sum::fix_length_and_dec");
+ maybe_null=null_value=1;
+ decimals= args[0]->decimals + 4;
+ switch (args[0]->result_type())
+ {
+ case REAL_RESULT:
+ case STRING_RESULT:
+ 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;
+ cur_dec= 0;
+ hybrid_type= DECIMAL_RESULT;
+ my_decimal_set_zero(dec_sum);
+ my_decimal_set_zero(dec_sqr);
+ 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;
+ 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);
+ }
+ DBUG_PRINT("info", ("Type: %s (%d, %d)",
+ (hybrid_type == REAL_RESULT ? "REAL_RESULT" :
+ hybrid_type == DECIMAL_RESULT ? "DECIMAL_RESULT" :
+ hybrid_type == INT_RESULT ? "INT_RESULT" :
+ "--ILLEGAL!!!--"),
+ max_length,
+ (int)decimals));
+ DBUG_VOID_RETURN;
+}
+
+
Item *Item_sum_variance::copy_or_same(THD* thd)
{
return new (thd->mem_root) Item_sum_variance(thd, this);
}
+Field *Item_sum_variance::create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_len)
+{
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ if (group)
+ return new Field_string(dec_bin_size0+dec_bin_size1+sizeof(longlong),
+ 0, name,table,&my_charset_bin);
+ else
+ return new Field_new_decimal(DECIMAL_MAX_LENGTH,
+ maybe_null, name, table, f_scale1 + 4);
+ }
+ else
+ {
+ if (group)
+ return new Field_string(sizeof(double)*2+sizeof(longlong),
+ 0, name,table,&my_charset_bin);
+ else
+ return new Field_double(max_length, maybe_null,name,table,decimals);
+ }
+}
+
+
void Item_sum_variance::clear()
{
- sum=sum_sqr=0.0;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal_set_zero(dec_sum);
+ my_decimal_set_zero(dec_sqr);
+ cur_dec= 0;
+ }
+ else
+ sum=sum_sqr=0.0;
count=0;
}
bool Item_sum_variance::add()
{
- double nr= args[0]->val_real();
- if (!args[0]->null_value)
+ if (hybrid_type == DECIMAL_RESULT)
{
- sum+=nr;
- sum_sqr+=nr*nr;
- count++;
+ my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf);
+ my_decimal sqr_buf;
+ if (!args[0]->null_value)
+ {
+ count++;
+ int next_dec= cur_dec ^ 1;
+ my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr+next_dec,
+ dec_sqr+cur_dec, &sqr_buf);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_sum+next_dec,
+ dec_sum+cur_dec, dec);
+ cur_dec= next_dec;
+ }
+ }
+ else
+ {
+ double nr= args[0]->val_real();
+ if (!args[0]->null_value)
+ {
+ sum+=nr;
+ sum_sqr+=nr*nr;
+ count++;
+ }
}
return 0;
}
@@ -533,16 +1044,77 @@ double Item_sum_variance::val_real()
return 0.0;
}
null_value=0;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ double result;
+ my_decimal dec_buf, *dec= Item_sum_variance::val_decimal(&dec_buf);
+ my_decimal2double(E_DEC_FATAL_ERROR, dec, &result);
+ return result;
+ }
/* Avoid problems when the precision isn't good enough */
double tmp=ulonglong2double(count);
double tmp2=(sum_sqr - sum*sum/tmp)/tmp;
return tmp2 <= 0.0 ? 0.0 : tmp2;
}
+
+my_decimal *Item_sum_variance::val_decimal(my_decimal *dec_buf)
+{
+ DBUG_ASSERT(fixed ==1 );
+ if (hybrid_type == REAL_RESULT)
+ {
+ double result= Item_sum_variance::val_real();
+ if (null_value)
+ return 0;
+ double2my_decimal(E_DEC_FATAL_ERROR, result, dec_buf);
+ return dec_buf;
+ }
+ if (!count)
+ {
+ null_value= 1;
+ return 0;
+ }
+ null_value= 0;
+ my_decimal count_buf, sum_sqr_buf;
+ int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &count_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_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, &count_buf, 2);
+ return dec_buf;
+}
+
void Item_sum_variance::reset_field()
{
- double nr= args[0]->val_real();
char *res=result_field->ptr;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *arg_dec= args[0]->val_decimal(&value);
+ if (args[0]->null_value)
+ {
+ my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero,
+ res, f_precision0, f_scale0);
+ my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero,
+ res+dec_bin_size0, f_precision1, f_scale1);
+ res+= dec_bin_size0 + dec_bin_size1;
+ longlong tmp=0;
+ int8store(res,tmp);
+ }
+ else
+ {
+ my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec,
+ res, f_precision0, f_scale0);
+ my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum, arg_dec, arg_dec);
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_sum,
+ res+dec_bin_size0, f_precision1, f_scale1);
+ res+= dec_bin_size0 + dec_bin_size1;
+ longlong tmp=1;
+ int8store(res,tmp);
+ }
+ return;
+ }
+ double nr= args[0]->val_real();
if (args[0]->null_value)
bzero(res,sizeof(double)*2+sizeof(longlong));
@@ -558,10 +1130,33 @@ void Item_sum_variance::reset_field()
void Item_sum_variance::update_field()
{
- double nr,old_nr,old_sqr;
longlong field_count;
char *res=result_field->ptr;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *arg_val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ binary2my_decimal(E_DEC_FATAL_ERROR, res,
+ dec_sum+1, f_precision0, f_scale0);
+ binary2my_decimal(E_DEC_FATAL_ERROR, res+dec_bin_size0,
+ dec_sqr+1, f_precision1, f_scale1);
+ field_count= sint8korr(res + (dec_bin_size0 + dec_bin_size1));
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_sum, arg_val, dec_sum+1);
+ my_decimal_mul(E_DEC_FATAL_ERROR, dec_sum+1, arg_val, arg_val);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_sqr, dec_sqr+1, dec_sum+1);
+ field_count++;
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_sum,
+ res, f_precision0, f_scale0);
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_sqr,
+ res+dec_bin_size0, f_precision1, f_scale1);
+ res+= dec_bin_size0 + dec_bin_size1;
+ int8store(res, field_count);
+ }
+ return;
+ }
+ double nr,old_nr,old_sqr;
float8get(old_nr, res);
float8get(old_sqr, res+sizeof(double));
field_count=sint8korr(res+sizeof(double)*2);
@@ -582,9 +1177,20 @@ void Item_sum_variance::update_field()
void Item_sum_hybrid::clear()
{
- sum= 0.0;
- sum_int= 0;
- value.length(0);
+ switch (hybrid_type)
+ {
+ case INT_RESULT:
+ sum_int= 0;
+ break;
+ case DECIMAL_RESULT:
+ my_decimal_set_zero(&sum_dec);
+ break;
+ case REAL_RESULT:
+ sum= 0.0;
+ break;
+ default:
+ value.length(0);
+ }
null_value= 1;
}
@@ -606,6 +1212,9 @@ double Item_sum_hybrid::val_real()
if (unsigned_flag)
return ulonglong2double(sum_int);
return (double) sum_int;
+ case DECIMAL_RESULT:
+ my_decimal2double(E_DEC_FATAL_ERROR, &sum_dec, &sum);
+ return sum;
case REAL_RESULT:
return sum;
case ROW_RESULT:
@@ -622,9 +1231,47 @@ longlong Item_sum_hybrid::val_int()
DBUG_ASSERT(fixed == 1);
if (null_value)
return 0;
- if (hybrid_type == INT_RESULT)
+ switch (hybrid_type)
+ {
+ case INT_RESULT:
+ return sum_int;
+ case DECIMAL_RESULT:
+ {
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, &sum_dec, unsigned_flag, &result);
return sum_int;
- return (longlong) Item_sum_hybrid::val_real();
+ }
+ default:
+ return (longlong) Item_sum_hybrid::val_real();
+ }
+}
+
+
+my_decimal *Item_sum_hybrid::val_decimal(my_decimal *val)
+{
+ DBUG_ASSERT(fixed == 1);
+ if (null_value)
+ return 0;
+ switch (hybrid_type) {
+ case STRING_RESULT:
+ string2my_decimal(E_DEC_FATAL_ERROR, &value, val);
+ break;
+ case REAL_RESULT:
+ double2my_decimal(E_DEC_FATAL_ERROR, sum, val);
+ break;
+ case DECIMAL_RESULT:
+ val= &sum_dec;
+ break;
+ case INT_RESULT:
+ int2my_decimal(E_DEC_FATAL_ERROR, sum_int, unsigned_flag, val);
+ break;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
+ }
+ return val; // Keep compiler happy
}
@@ -640,6 +1287,9 @@ Item_sum_hybrid::val_str(String *str)
case REAL_RESULT:
str->set(sum,decimals, &my_charset_bin);
break;
+ case DECIMAL_RESULT:
+ my_decimal2string(E_DEC_FATAL_ERROR, &sum_dec, 0, 0, 0, str);
+ return str;
case INT_RESULT:
if (unsigned_flag)
str->set((ulonglong) sum_int, &my_charset_bin);
@@ -713,6 +1363,17 @@ bool Item_sum_min::add()
}
}
break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value &&
+ (null_value || (my_decimal_cmp(&sum_dec, val) > 0)))
+ {
+ my_decimal2decimal(val, &sum_dec);
+ null_value= 0;
+ }
+ }
+ break;
case REAL_RESULT:
{
double nr= args[0]->val_real();
@@ -766,6 +1427,17 @@ bool Item_sum_max::add()
}
}
break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value &&
+ (null_value || (my_decimal_cmp(val, &sum_dec) > 0)))
+ {
+ my_decimal2decimal(val, &sum_dec);
+ null_value= 0;
+ }
+ }
+ break;
case REAL_RESULT:
{
double nr= args[0]->val_real();
@@ -867,7 +1539,9 @@ void Item_sum_num::reset_field()
void Item_sum_hybrid::reset_field()
{
- if (hybrid_type == STRING_RESULT)
+ switch(hybrid_type)
+ {
+ case STRING_RESULT:
{
char buff[MAX_FIELD_WIDTH];
String tmp(buff,sizeof(buff),result_field->charset()),*res;
@@ -883,8 +1557,9 @@ void Item_sum_hybrid::reset_field()
result_field->set_notnull();
result_field->store(res->ptr(),res->length(),tmp.charset());
}
+ break;
}
- else if (hybrid_type == INT_RESULT)
+ case INT_RESULT:
{
longlong nr=args[0]->val_int();
@@ -899,8 +1574,9 @@ void Item_sum_hybrid::reset_field()
result_field->set_notnull();
}
result_field->store(nr);
+ break;
}
- else // REAL_RESULT
+ case REAL_RESULT:
{
double nr= args[0]->val_real();
@@ -915,14 +1591,46 @@ void Item_sum_hybrid::reset_field()
result_field->set_notnull();
}
result_field->store(nr);
+ break;
+ }
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *arg_dec= args[0]->val_decimal(&value);
+
+ if (maybe_null)
+ {
+ if (args[0]->null_value)
+ result_field->set_null();
+ else
+ result_field->set_notnull();
+ }
+ if (!args[0]->null_value)
+ result_field->store_decimal(arg_dec);
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
}
}
void Item_sum_sum::reset_field()
{
- double nr= args[0]->val_real(); // Nulls also return 0
- float8store(result_field->ptr,nr);
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *arg_val= args[0]->val_decimal(&value);
+ if (args[0]->null_value)
+ result_field->reset();
+ else
+ result_field->store_decimal(arg_val);
+ }
+ else
+ {
+ DBUG_ASSERT(hybrid_type == REAL_RESULT);
+ double nr= args[0]->val_real(); // Nulls also return 0
+ float8store(result_field->ptr, nr);
+ }
if (args[0]->null_value)
result_field->set_null();
else
@@ -949,17 +1657,40 @@ void Item_sum_count::reset_field()
void Item_sum_avg::reset_field()
{
- double nr= args[0]->val_real();
char *res=result_field->ptr;
-
- if (args[0]->null_value)
- bzero(res,sizeof(double)+sizeof(longlong));
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *arg_dec= args[0]->val_decimal(&value);
+ if (args[0]->null_value)
+ {
+ my_decimal2binary(E_DEC_FATAL_ERROR, &decimal_zero,
+ res, f_precision, f_scale);
+ res+= dec_bin_size;
+ longlong tmp=0;
+ int8store(res,tmp);
+ }
+ else
+ {
+ my_decimal2binary(E_DEC_FATAL_ERROR, arg_dec,
+ res, f_precision, f_scale);
+ res+= dec_bin_size;
+ longlong tmp=1;
+ int8store(res,tmp);
+ }
+ }
else
{
- float8store(res,nr);
- res+=sizeof(double);
- longlong tmp=1;
- int8store(res,tmp);
+ double nr= args[0]->val_real();
+
+ if (args[0]->null_value)
+ bzero(res,sizeof(double)+sizeof(longlong));
+ else
+ {
+ float8store(res,nr);
+ res+=sizeof(double);
+ longlong tmp=1;
+ int8store(res,tmp);
+ }
}
}
@@ -983,17 +1714,39 @@ void Item_sum_bit::update_field()
void Item_sum_sum::update_field()
{
- double old_nr,nr;
- char *res=result_field->ptr;
-
- float8get(old_nr,res);
- nr= args[0]->val_real();
- if (!args[0]->null_value)
+ if (hybrid_type == DECIMAL_RESULT)
{
- old_nr+=nr;
- result_field->set_notnull();
+ my_decimal value, *arg_val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ if (!result_field->is_null())
+ {
+ my_decimal field_value,
+ *field_val= result_field->val_decimal(&field_value);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, field_val);
+ result_field->store_decimal(dec_buffs);
+ }
+ else
+ {
+ result_field->store_decimal(arg_val);
+ result_field->set_notnull();
+ }
+ }
+ }
+ else
+ {
+ double old_nr,nr;
+ char *res=result_field->ptr;
+
+ float8get(old_nr,res);
+ nr= args[0]->val_real();
+ if (!args[0]->null_value)
+ {
+ old_nr+=nr;
+ result_field->set_notnull();
+ }
+ float8store(res,old_nr);
}
- float8store(res,old_nr);
}
@@ -1017,32 +1770,59 @@ void Item_sum_count::update_field()
void Item_sum_avg::update_field()
{
- double nr,old_nr;
longlong field_count;
char *res=result_field->ptr;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *arg_val= args[0]->val_decimal(&value);
+ if (!args[0]->null_value)
+ {
+ binary2my_decimal(E_DEC_FATAL_ERROR, res,
+ dec_buffs + 1, f_precision, f_scale);
+ field_count= sint8korr(res + dec_bin_size);
+ my_decimal_add(E_DEC_FATAL_ERROR, dec_buffs, arg_val, dec_buffs + 1);
+ field_count++;
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec_buffs,
+ res, f_precision, f_scale);
+ res+= dec_bin_size;
+ int8store(res, field_count);
+ }
+ }
+ else
+ {
+ double nr, old_nr;
- float8get(old_nr,res);
- field_count=sint8korr(res+sizeof(double));
+ float8get(old_nr, res);
+ field_count= sint8korr(res + sizeof(double));
- nr= args[0]->val_real();
- if (!args[0]->null_value)
- {
- old_nr+=nr;
- field_count++;
+ nr= args[0]->val_real();
+ if (!args[0]->null_value)
+ {
+ old_nr+= nr;
+ field_count++;
+ }
+ float8store(res,old_nr);
+ res+= sizeof(double);
+ int8store(res, field_count);
}
- float8store(res,old_nr);
- res+=sizeof(double);
- int8store(res,field_count);
}
void Item_sum_hybrid::update_field()
{
- if (hybrid_type == STRING_RESULT)
+ switch (hybrid_type)
+ {
+ case STRING_RESULT:
min_max_update_str_field();
- else if (hybrid_type == INT_RESULT)
+ break;
+ case INT_RESULT:
min_max_update_int_field();
- else
+ break;
+ case DECIMAL_RESULT:
+ min_max_update_decimal_field();
+ break;
+ default:
min_max_update_real_field();
+ }
}
@@ -1112,41 +1892,119 @@ Item_sum_hybrid::min_max_update_int_field()
}
-Item_avg_field::Item_avg_field(Item_sum_avg *item)
+void
+Item_sum_hybrid::min_max_update_decimal_field()
+{
+ /* TODO: optimize: do not get result_field in case of args[0] is NULL */
+ my_decimal old_val, nr_val;
+ const my_decimal *old_nr= result_field->val_decimal(&old_val);
+ const my_decimal *nr= args[0]->val_decimal(&nr_val);
+ if (!args[0]->null_value)
+ {
+ if (result_field->is_null(0))
+ old_nr=nr;
+ else
+ {
+ bool res= my_decimal_cmp(old_nr, nr) > 0;
+ /* (cmp_sign > 0 && res) || (!(cmp_sign > 0) && !res) */
+ if ((cmp_sign > 0) ^ (!res))
+ old_nr=nr;
+ }
+ result_field->set_notnull();
+ }
+ else if (result_field->is_null(0))
+ result_field->set_null();
+ result_field->store_decimal(old_nr);
+}
+
+
+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;
field=item->result_field;
maybe_null=1;
+ hybrid_type= res_type;
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ f_scale= item->f_scale;
+ f_precision= item->f_precision;
+ dec_bin_size= item->dec_bin_size;
+ }
}
double Item_avg_field::val_real()
{
// fix_fields() never calls for this Item
- double nr;
- longlong count;
- float8get(nr,field->ptr);
- char *res=(field->ptr+sizeof(double));
- count=sint8korr(res);
-
- if (!count)
+ if (hybrid_type == DECIMAL_RESULT)
{
- null_value=1;
- return 0.0;
+ my_decimal value, *dec_val= val_decimal(&value);
+ if (null_value)
+ return 0.0;
+ double d;
+ my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &d);
+ return d;
}
- null_value=0;
- return nr/(double) count;
+ else
+ {
+ double nr;
+ longlong count;
+ float8get(nr,field->ptr);
+ char *res=(field->ptr+sizeof(double));
+ count=sint8korr(res);
+
+ if (!count)
+ {
+ null_value=1;
+ return 0.0;
+ }
+ null_value=0;
+ return nr/(double) count;
+ }
+}
+
+longlong Item_avg_field::val_int()
+{
+ return (longlong)val_real();
+}
+
+
+my_decimal *Item_avg_field::val_decimal(my_decimal * val)
+{
+ // fix_fields() never calls for this Item
+ longlong count= sint8korr(field->ptr + dec_bin_size);
+ if ((null_value= !count))
+ return NULL;
+
+ my_decimal dec_count, dec_field;
+ 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, val, &dec_field, &dec_count, 4);
+ return val;
}
+
String *Item_avg_field::val_str(String *str)
{
// fix_fields() never calls for this Item
- double nr= Item_avg_field::val_real();
- if (null_value)
- return 0;
- str->set(nr,decimals, &my_charset_bin);
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal value, *dec_val= val_decimal(&value);
+ if (null_value)
+ return NULL;
+ my_decimal_round(E_DEC_FATAL_ERROR, dec_val, decimals, FALSE, &value);
+ my_decimal2string(E_DEC_FATAL_ERROR, &value, 0, 0, 0, str);
+ }
+ else
+ {
+ double nr= Item_avg_field::val_real();
+ if (null_value)
+ return 0;
+ str->set(nr, decimals, &my_charset_bin);
+ }
return str;
}
@@ -1169,11 +2027,29 @@ Item_variance_field::Item_variance_field(Item_sum_variance *item)
max_length=item->max_length;
field=item->result_field;
maybe_null=1;
+ if ((hybrid_type= item->hybrid_type) == DECIMAL_RESULT)
+ {
+ f_scale0= item->f_scale0;
+ f_precision0= item->f_precision0;
+ dec_bin_size0= item->dec_bin_size0;
+ f_scale1= item->f_scale1;
+ f_precision1= item->f_precision1;
+ dec_bin_size1= item->dec_bin_size1;
+ }
}
double Item_variance_field::val_real()
{
// fix_fields() never calls for this Item
+ if (hybrid_type == DECIMAL_RESULT)
+ {
+ my_decimal dec_buf, *dec_val= val_decimal(&dec_buf);
+ if (null_value)
+ return 0.0;
+ double d;
+ my_decimal2double(E_DEC_FATAL_ERROR, dec_val, &d);
+ return d;
+ }
double sum,sum_sqr;
longlong count;
float8get(sum,field->ptr);
@@ -1201,6 +2077,28 @@ String *Item_variance_field::val_str(String *str)
return str;
}
+
+my_decimal *Item_variance_field::val_decimal(my_decimal *dec_buf)
+{
+ // fix_fields() never calls for this Item
+ longlong count= sint8korr(field->ptr+dec_bin_size0+dec_bin_size1);
+ if ((null_value= !count))
+ return 0;
+
+ my_decimal dec_count, dec_sum, dec_sqr, tmp;
+ int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &dec_count);
+ binary2my_decimal(E_DEC_FATAL_ERROR, field->ptr,
+ &dec_sum, f_precision0, f_scale0);
+ 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_sub(E_DEC_FATAL_ERROR, &dec_sum, &dec_sqr, dec_buf);
+ my_decimal_div(E_DEC_FATAL_ERROR, dec_buf, &dec_sum, &dec_count, 2);
+ return dec_buf;
+}
+
+
/****************************************************************************
** COUNT(DISTINCT ...)
****************************************************************************/
@@ -1597,6 +2495,58 @@ Item *Item_sum_udf_int::copy_or_same(THD* thd)
}
+String *Item_sum_udf_decimal::val_str(String *str)
+{
+ my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
+ if (null_value)
+ return 0;
+ if (str->length() < DECIMAL_MAX_STR_LENGTH)
+ str->length(DECIMAL_MAX_STR_LENGTH);
+ my_decimal_round(E_DEC_FATAL_ERROR, dec, decimals, FALSE, &dec_buf);
+ my_decimal2string(E_DEC_FATAL_ERROR, &dec_buf, 0, 0, '0', str);
+ return str;
+}
+
+
+double Item_sum_udf_decimal::val_real()
+{
+ my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
+ if (null_value)
+ return 0.0;
+ double result;
+ my_decimal2double(E_DEC_FATAL_ERROR, dec, &result);
+ return result;
+}
+
+
+longlong Item_sum_udf_decimal::val_int()
+{
+ my_decimal dec_buf, *dec= udf.val_decimal(&null_value, &dec_buf);
+ if (null_value)
+ return 0;
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, dec, unsigned_flag, &result);
+ return result;
+}
+
+
+my_decimal *Item_sum_udf_decimal::val_decimal(my_decimal *dec_buf)
+{
+ DBUG_ASSERT(fixed == 1);
+ DBUG_ENTER("Item_func_udf_decimal::val_decimal");
+ DBUG_PRINT("info",("result_type: %d arg_count: %d",
+ args[0]->result_type(), arg_count));
+
+ DBUG_RETURN(udf.val_decimal(&null_value, dec_buf));
+}
+
+
+Item *Item_sum_udf_decimal::copy_or_same(THD* thd)
+{
+ return new (thd->mem_root) Item_sum_udf_decimal(thd, this);
+}
+
+
longlong Item_sum_udf_int::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -2037,7 +2987,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
for (i=0 ; i < arg_count ; i++)
{
- if ((!args[i]->fixed &&
+ if ((!args[i]->fixed &&
args[i]->fix_fields(thd, tables, args + i)) ||
args[i]->check_cols(1))
return TRUE;
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 7866a9ae913..d759f5607c3 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -78,6 +78,7 @@ public:
virtual void update_field()=0;
virtual bool keep_field_type(void) const { return 0; }
virtual void fix_length_and_dec() { maybe_null=1; null_value=1; }
+ my_decimal *val_decimal(my_decimal *);
virtual const char *func_name() const { return "?"; }
virtual Item *result_item(Field *field)
{ return new Item_field(field);}
@@ -92,6 +93,9 @@ public:
virtual bool setup(THD *thd) {return 0;}
virtual void make_unique() {}
Item *get_tmp_table_item(THD *thd);
+ virtual int scale() { return decimals; }
+ virtual Field *create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_length);
bool walk (Item_processor processor, byte *argument);
};
@@ -112,6 +116,7 @@ public:
return (longlong) val_real(); /* Real as default */
}
String *val_str(String*str);
+ my_decimal *val_decimal(my_decimal *);
void reset_field();
};
@@ -132,17 +137,24 @@ public:
class Item_sum_sum :public Item_sum_num
{
+protected:
+ Item_result hybrid_type;
double sum;
- void fix_length_and_dec() { maybe_null=null_value=1; }
+ my_decimal dec_buffs[2];
+ uint curr_dec_buff;
+ void fix_length_and_dec();
- public:
- Item_sum_sum(Item *item_par) :Item_sum_num(item_par),sum(0.0) {}
- Item_sum_sum(THD *thd, Item_sum_sum *item)
- :Item_sum_num(thd, item), sum(item->sum) {}
+public:
+ Item_sum_sum(Item *item_par) :Item_sum_num(item_par) {}
+ Item_sum_sum(THD *thd, Item_sum_sum *item);
enum Sumfunctype sum_func () const {return SUM_FUNC;}
void clear();
bool add();
double val_real();
+ longlong val_int();
+ String *val_str(String*str);
+ my_decimal *val_decimal(my_decimal *);
+ enum Item_result result_type () const { return hybrid_type; }
void reset_field();
void update_field();
void no_rows_in_result() {}
@@ -159,29 +171,35 @@ class Item_sum_sum :public Item_sum_num
class Unique;
-class Item_sum_sum_distinct :public Item_sum_num
+class Item_sum_sum_distinct :public Item_sum_sum
{
- double sum;
Unique *tree;
+ byte *dec_bin_buff;
+ my_decimal tmp_dec;
private:
Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item);
public:
Item_sum_sum_distinct(Item *item_par);
~Item_sum_sum_distinct() {}
-
+
bool setup(THD *thd);
void clear();
void cleanup();
bool add();
double val_real();
+ my_decimal *val_decimal(my_decimal *);
+ longlong val_int();
+ String *val_str(String *str);
- inline void add(double val) { sum+= val; }
+ void add_real(double val);
+ void add_decimal(byte *val);
enum Sumfunctype sum_func () const { return SUM_DISTINCT_FUNC; }
void reset_field() {} // not used
void update_field() {} // not used
const char *func_name() const { return "sum_distinct"; }
Item *copy_or_same(THD* thd);
virtual void no_rows_in_result() {}
+ void fix_length_and_dec();
};
@@ -304,44 +322,51 @@ class Item_avg_field :public Item_result_field
{
public:
Field *field;
- Item_avg_field(Item_sum_avg *item);
+ Item_result hybrid_type;
+ uint f_precision, f_scale;
+ uint dec_bin_size;
+ Item_avg_field(Item_result res_type, Item_sum_avg *item);
enum Type type() const { return FIELD_AVG_ITEM; }
double val_real();
- longlong val_int()
- { /* can't be fix_fields()ed */ return (longlong) val_real(); }
+ longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
bool is_null() { (void) val_int(); return null_value; }
String *val_str(String*);
- enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
+ enum_field_types field_type() const
+ {
+ return hybrid_type == DECIMAL_RESULT ?
+ MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE;
+ }
void fix_length_and_dec() {}
+ enum Item_result result_type () const { return hybrid_type; }
};
-class Item_sum_avg :public Item_sum_num
+class Item_sum_avg :public Item_sum_sum
{
- void fix_length_and_dec()
- {
- decimals=min(decimals+4, NOT_FIXED_DEC);
- maybe_null=1;
- }
-
- double sum;
+public:
ulonglong count;
+ uint f_precision, f_scale;
+ uint dec_bin_size;
- public:
- Item_sum_avg(Item *item_par) :Item_sum_num(item_par), sum(0.0), 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_num(thd, item), sum(item->sum), count(item->count) {}
+ :Item_sum_sum(thd, item), count(item->count) {}
+ void fix_length_and_dec();
enum Sumfunctype sum_func () const {return AVG_FUNC;}
void clear();
bool add();
double val_real();
+ my_decimal *val_decimal(my_decimal *);
+ String *val_str(String *str);
void reset_field();
void update_field();
Item *result_item(Field *field)
- { return new Item_avg_field(this); }
+ { return new Item_avg_field(hybrid_type, this); }
void no_rows_in_result() {}
const char *func_name() const { return "avg"; }
Item *copy_or_same(THD* thd);
+ Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
};
class Item_sum_variance;
@@ -350,15 +375,25 @@ class Item_variance_field :public Item_result_field
{
public:
Field *field;
+ Item_result hybrid_type;
+ uint f_precision0, f_scale0;
+ uint f_precision1, f_scale1;
+ uint dec_bin_size0, dec_bin_size1;
Item_variance_field(Item_sum_variance *item);
enum Type type() const {return FIELD_VARIANCE_ITEM; }
double val_real();
longlong val_int()
{ /* can't be fix_fields()ed */ return (longlong) val_real(); }
String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *);
bool is_null() { (void) val_int(); return null_value; }
- enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
+ enum_field_types field_type() const
+ {
+ return hybrid_type == DECIMAL_RESULT ?
+ MYSQL_TYPE_NEWDECIMAL : MYSQL_TYPE_DOUBLE;
+ }
void fix_length_and_dec() {}
+ enum Item_result result_type () const { return hybrid_type; }
};
@@ -376,23 +411,27 @@ public:
class Item_sum_variance : public Item_sum_num
{
+ void fix_length_and_dec();
+
+public:
+ Item_result hybrid_type;
double sum, sum_sqr;
+ my_decimal dec_sum[2], dec_sqr[2];
+ int cur_dec;
ulonglong count;
- void fix_length_and_dec()
- {
- decimals=min(decimals+4, NOT_FIXED_DEC);
- maybe_null=1;
- }
+ uint f_precision0, f_scale0;
+ uint f_precision1, f_scale1;
+ uint dec_bin_size0, dec_bin_size1;
- public:
- Item_sum_variance(Item *item_par) :Item_sum_num(item_par),count(0) {}
- Item_sum_variance(THD *thd, Item_sum_variance *item):
- Item_sum_num(thd, item), sum(item->sum), sum_sqr(item->sum_sqr),
- count(item->count) {}
+ Item_sum_variance(Item *item_par) :Item_sum_num(item_par), hybrid_type(REAL_RESULT),
+ cur_dec(0),count(0)
+ {}
+ Item_sum_variance(THD *thd, Item_sum_variance *item);
enum Sumfunctype sum_func () const { return VARIANCE_FUNC; }
void clear();
bool add();
double val_real();
+ my_decimal *val_decimal(my_decimal *);
void reset_field();
void update_field();
Item *result_item(Field *field)
@@ -400,6 +439,8 @@ class Item_sum_variance : public Item_sum_num
void no_rows_in_result() {}
const char *func_name() const { return "variance"; }
Item *copy_or_same(THD* thd);
+ Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
+ enum Item_result result_type () const { return hybrid_type; }
};
class Item_sum_std;
@@ -410,6 +451,7 @@ public:
Item_std_field(Item_sum_std *item);
enum Type type() const { return FIELD_STD_ITEM; }
double val_real();
+ enum Item_result result_type () const { return REAL_RESULT; }
};
/*
@@ -429,16 +471,18 @@ class Item_sum_std :public Item_sum_variance
{ return new Item_std_field(this); }
const char *func_name() const { return "std"; }
Item *copy_or_same(THD* thd);
+ enum Item_result result_type () const { return REAL_RESULT; }
};
// This class is a string or number function depending on num_func
class Item_sum_hybrid :public Item_sum
{
- protected:
+protected:
String value,tmp_value;
double sum;
longlong sum_int;
+ my_decimal sum_dec;
Item_result hybrid_type;
enum_field_types hybrid_field_type;
int cmp_sign;
@@ -449,15 +493,10 @@ class Item_sum_hybrid :public Item_sum
Item_sum_hybrid(Item *item_par,int sign)
:Item_sum(item_par), sum(0.0), sum_int(0),
hybrid_type(INT_RESULT), hybrid_field_type(FIELD_TYPE_LONGLONG),
- cmp_sign(sign), used_table_cache(~(table_map) 0), was_values(TRUE)
- { collation.set(&my_charset_bin); }
- Item_sum_hybrid(THD *thd, Item_sum_hybrid *item):
- Item_sum(thd, item), value(item->value),
- sum(item->sum), sum_int(item->sum_int), hybrid_type(item->hybrid_type),
- hybrid_field_type(item->hybrid_field_type),cmp_sign(item->cmp_sign),
- used_table_cache(item->used_table_cache),
+ cmp_sign(sign), used_table_cache(~(table_map) 0),
was_values(TRUE)
- { collation.set(item->collation); }
+ { collation.set(&my_charset_bin); }
+ Item_sum_hybrid(THD *thd, Item_sum_hybrid *item);
bool fix_fields(THD *, TABLE_LIST *, Item **);
table_map used_tables() const { return used_table_cache; }
bool const_item() const { return !used_table_cache; }
@@ -465,6 +504,7 @@ class Item_sum_hybrid :public Item_sum
void clear();
double val_real();
longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
void reset_field();
String *val_str(String *);
void make_const() { used_table_cache=0; }
@@ -475,6 +515,7 @@ class Item_sum_hybrid :public Item_sum
void min_max_update_str_field();
void min_max_update_real_field();
void min_max_update_int_field();
+ void min_max_update_decimal_field();
void cleanup();
bool any_value() { return was_values; }
void no_rows_in_result();
@@ -523,7 +564,7 @@ public:
void reset_field();
void update_field();
void fix_length_and_dec()
- { decimals=0; max_length=21; unsigned_flag=1; maybe_null=null_value=0; }
+ { decimals= 0; max_length=21; unsigned_flag= 1; maybe_null= null_value= 0; }
};
@@ -661,6 +702,23 @@ public:
Item *copy_or_same(THD* thd);
};
+class Item_sum_udf_decimal :public Item_udf_sum
+{
+public:
+ Item_sum_udf_decimal(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
+ Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list)
+ :Item_udf_sum(udf_arg,list) {}
+ Item_sum_udf_decimal(THD *thd, Item_sum_udf_decimal *item)
+ :Item_udf_sum(thd, item) {}
+ String *val_str(String *);
+ double val_real();
+ longlong val_int();
+ my_decimal *val_decimal(my_decimal *);
+ enum Item_result result_type () const { return DECIMAL_RESULT; }
+ void fix_length_and_dec() { fix_num_length_and_dec(); }
+ Item *copy_or_same(THD* thd);
+};
+
#else /* Dummy functions to get sql_yacc.cc compiled */
class Item_sum_udf_float :public Item_sum_num
@@ -694,6 +752,22 @@ public:
};
+class Item_sum_udf_decimal :public Item_sum_num
+{
+ public:
+ Item_sum_udf_decimal(udf_func *udf_arg) :Item_sum_num() {}
+ Item_sum_udf_decimal(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {}
+ Item_sum_udf_decimal(THD *thd, Item_sum_udf_float *item)
+ :Item_sum_num(thd, item) {}
+ enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
+ double val_real() { DBUG_ASSERT(fixed == 1); return 0.0; }
+ my_decimal *val_decimal(my_decimal *) { DBUG_ASSERT(fixed == 1); return 0; }
+ void clear() {}
+ bool add() { return 0; }
+ void update_field() {}
+};
+
+
class Item_sum_udf_str :public Item_sum_num
{
public:
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 917018463e5..ab511ae2883 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -315,7 +315,9 @@ public:
};
-/* This can't be a Item_str_func, because the val() functions are special */
+/*
+ This can't be a Item_str_func, because the val_real() functions are special
+*/
class Item_date :public Item_func
{
diff --git a/sql/item_uniq.cc b/sql/item_uniq.cc
index 88e0cbbc0e6..c1a19d71d04 100644
--- a/sql/item_uniq.cc
+++ b/sql/item_uniq.cc
@@ -20,3 +20,9 @@
#endif
#include "mysql_priv.h"
+
+Field *Item_sum_unique_users::create_tmp_field(bool group, TABLE *table,
+ uint convert_blob_length)
+{
+ return new Field_long(9,maybe_null,name,table,1);
+}
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index e74c09ca3c4..602474f7581 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.h
@@ -57,4 +57,5 @@ public:
return new Item_sum_unique_users(thd, this);
}
void print(String *str) { str->append("0.0", 3); }
+ Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
};
diff --git a/sql/log_event.cc b/sql/log_event.cc
index d09b2b3dc03..d2a0e8642f9 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -3099,6 +3099,16 @@ void User_var_log_event::pack_info(Protocol* protocol)
buf= my_malloc(val_offset + 22, MYF(MY_WME));
event_len= longlong10_to_str(uint8korr(val), buf + val_offset,-10)-buf;
break;
+ case DECIMAL_RESULT:
+ {
+ buf= my_malloc(val_offset + DECIMAL_MAX_STR_LENGTH, MYF(MY_WME));
+ String str(buf+val_offset, DECIMAL_MAX_STR_LENGTH, &my_charset_bin);
+ my_decimal dec;
+ binary2my_decimal(E_DEC_FATAL_ERROR, val+2, &dec, val[0], val[1]);
+ my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, 0, &str);
+ event_len= str.length() + val_offset;
+ break;
+ }
case STRING_RESULT:
/* 15 is for 'COLLATE' and other chars */
buf= my_malloc(event_len+val_len*2+1+2*MY_CS_NAME_SIZE+15, MYF(MY_WME));
@@ -3167,7 +3177,7 @@ bool User_var_log_event::write(IO_CACHE* file)
char buf[UV_NAME_LEN_SIZE];
char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE];
- char buf2[8], *pos= buf2;
+ char buf2[max(8, DECIMAL_MAX_FIELD_SIZE + 2)], *pos= buf2;
uint buf1_length;
ulong event_length;
@@ -3182,8 +3192,6 @@ bool User_var_log_event::write(IO_CACHE* file)
{
buf1[1]= type;
int4store(buf1 + 2, charset_number);
- int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len);
- buf1_length= 10;
switch (type) {
case REAL_RESULT:
@@ -3192,6 +3200,16 @@ bool User_var_log_event::write(IO_CACHE* file)
case INT_RESULT:
int8store(buf2, *(longlong*) val);
break;
+ case DECIMAL_RESULT:
+ {
+ my_decimal *dec= (my_decimal *)val;
+ dec->fix_buffer_pointer();
+ buf2[0]= (char)(dec->intg + dec->frac);
+ buf2[1]= (char)dec->frac;
+ decimal2bin((decimal*)val, buf2+2, buf2[0], buf2[1]);
+ val_len= decimal_bin_size(buf2[0], buf2[1]) + 2;
+ break;
+ }
case STRING_RESULT:
pos= val;
break;
@@ -3200,6 +3218,8 @@ bool User_var_log_event::write(IO_CACHE* file)
DBUG_ASSERT(1);
return 0;
}
+ int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len);
+ buf1_length= 10;
}
/* Length of the whole event */
@@ -3247,6 +3267,23 @@ void User_var_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* las
longlong10_to_str(uint8korr(val), int_buf, -10);
fprintf(file, ":=%s;\n", int_buf);
break;
+ case DECIMAL_RESULT:
+ {
+ char str_buf[200];
+ int str_len= sizeof(str_buf) - 1;
+ int precision= (int)val[0];
+ int scale= (int)val[1];
+ decimal_digit dec_buf[10];
+ decimal dec;
+ dec.len= 10;
+ dec.buf= dec_buf;
+
+ bin2decimal(val+2, &dec, precision, scale);
+ decimal2string(&dec, str_buf, &str_len, 0, 0, 0);
+ str_buf[str_len]= 0;
+ fprintf(file, "%s",str_buf);
+ break;
+ }
case STRING_RESULT:
{
/*
@@ -3323,7 +3360,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
switch (type) {
case REAL_RESULT:
float8get(real_val, val);
- it= new Item_real(real_val);
+ it= new Item_float(real_val);
val= (char*) &real_val; // Pointer to value in native format
val_len= 8;
break;
@@ -3333,6 +3370,14 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
val= (char*) &int_val; // Pointer to value in native format
val_len= 8;
break;
+ case DECIMAL_RESULT:
+ {
+ Item_decimal *dec= new Item_decimal(val+2, val[0], val[1]);
+ it= dec;
+ val= (char *)dec->val_decimal(NULL);
+ val_len= sizeof(my_decimal);
+ break;
+ }
case STRING_RESULT:
it= new Item_string(val, val_len, charset);
break;
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
new file mode 100644
index 00000000000..eafcd2eaaf3
--- /dev/null
+++ b/sql/my_decimal.cc
@@ -0,0 +1,212 @@
+/* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "mysql_priv.h"
+
+#ifndef MYSQL_CLIENT
+/*
+ report result of decimal operation
+
+ SYNOPSIS
+ decimal_operation_results()
+ result decimal library return code (E_DEC_* see include/decimal.h)
+
+ return
+ result
+*/
+int decimal_operation_results(int result)
+{
+ switch (result)
+ {
+ case E_DEC_OK:
+ break;
+//TODO: fix error messages
+ case E_DEC_TRUNCATED:
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_DATA_TRUNCATED, ER(WARN_DATA_TRUNCATED),
+ "", (long)-1);
+ break;
+ case E_DEC_OVERFLOW:
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_WARN_DATA_OUT_OF_RANGE,
+ ER(ER_WARN_DATA_OUT_OF_RANGE),
+ "", (long)-1);
+ break;
+ case E_DEC_DIV_ZERO:
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_DIVISION_BY_ZERO, ER(ER_DIVISION_BY_ZERO));
+ break;
+ case E_DEC_BAD_NUM:
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
+ ER(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
+ "decimal", "", "", (long)-1);
+ break;
+ case E_DEC_OOM:
+ my_error(ER_OUT_OF_RESOURCES, MYF(0));
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ return result;
+}
+
+
+/*
+ Converting decimal to string
+
+ SYNOPSIS
+ my_decimal2string()
+
+ return
+ E_DEC_OK
+ E_DEC_TRUNCATED
+ E_DEC_OVERFLOW
+ E_DEC_OOM
+*/
+
+int my_decimal2string(uint mask, const my_decimal *d,
+ int fixed_prec, int fixed_dec,
+ char filler, String *str)
+{
+ int length= (fixed_prec ? (fixed_prec + 1) : my_decimal_string_length(d));
+ int result;
+ if (str->alloc(length))
+ return check_result(mask, E_DEC_OOM);
+ char *sptr= (char *)str->ptr();
+ int res= decimal2string((decimal *)d, sptr,
+ &length, fixed_prec, fixed_dec,
+ filler);
+ result= check_result(mask, res);
+ str->length(length);
+ return result;
+}
+
+
+/*
+ Convert from decimal to binary representation
+
+ SYNOPSIS
+ my_decimal2binary()
+ mask error processing mask
+ d number for conversion
+ bin pointer to buffer where to write result
+ prec overall number of decimal digits
+ scale number of decimal digits after decimal point
+
+ NOTE
+ Before conversion we round number if it need but produce truncation
+ error in this case
+
+ RETURN
+ E_DEC_OK
+ E_DEC_TRUNCATED
+ E_DEC_OVERFLOW
+*/
+
+int my_decimal2binary(uint mask, const my_decimal *d, byte *bin, int prec,
+ int scale)
+{
+ int err1= E_DEC_OK, err2;
+ my_decimal rounded;
+ my_decimal2decimal(d, &rounded);
+ decimal_optimize_fraction(&rounded);
+ if (scale < rounded.frac)
+ {
+ err1= E_DEC_TRUNCATED;
+ /* decimal_round can return only E_DEC_TRUNCATED */
+ decimal_round(&rounded, &rounded, scale, HALF_UP);
+ }
+ err2= decimal2bin(&rounded, bin, prec, scale);
+ if (!err2)
+ err2= err1;
+ return check_result(mask, err2);
+}
+
+
+/*
+ Convert string for decimal when string can be in some multibyte charset
+
+ SYNOPSIS
+ str2my_decimal()
+ mask error processing mask
+ from string to process
+ length length of given string
+ charset charset of given string
+ decimal_value buffer for result storing
+
+ RESULT
+ E_DEC_OK
+ E_DEC_TRUNCATED
+ E_DEC_OVERFLOW
+ E_DEC_BAD_NUM
+ E_DEC_OOM
+*/
+int str2my_decimal(uint mask, const char *from, uint length,
+ CHARSET_INFO *charset, my_decimal *decimal_value)
+{
+ char *end;
+ int err;
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String tmp(buff, sizeof(buff), &my_charset_bin);
+ if (charset->mbminlen > 1)
+ {
+ uint dummy_errors;
+ tmp.copy(from, length, charset, &my_charset_latin1, &dummy_errors);
+ from= tmp.ptr();
+ length= tmp.length();
+ charset= &my_charset_bin;
+ }
+ my_decimal_set_zero(decimal_value);
+ err= string2decimal((char *)from, (decimal *)decimal_value, &end);
+ if (*end && !err)
+ err= E_DEC_TRUNCATED;
+ check_result(mask, err);
+ return err;
+}
+
+
+#ifndef DBUG_OFF
+/* routines for debugging print */
+
+/* print decimal */
+void
+print_decimal(const my_decimal *dec)
+{
+ fprintf(DBUG_FILE,
+ "\nDecimal: sign: %d intg: %d frac: %d \n\
+%09d,%09d,%09d,%09d,%09d,%09d,%09d,%09d\n",
+ dec->sign(), dec->intg, dec->frac,
+ dec->buf[0], dec->buf[1], dec->buf[2], dec->buf[3],
+ dec->buf[4], dec->buf[5], dec->buf[6], dec->buf[7]);
+}
+
+
+/* print decimal with its binary representation */
+void
+print_decimal_buff(const my_decimal *dec, const byte* ptr, int length)
+{
+ print_decimal(dec);
+ fprintf(DBUG_FILE, "Record: ");
+ for(int i= 0; i < length; i++)
+ {
+ fprintf(DBUG_FILE, "%02X ", (uint)((uchar *)ptr)[i]);
+ }
+ fprintf(DBUG_FILE, "\n");
+}
+#endif
+
+
+#endif /*MYSQL_CLIENT*/
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
new file mode 100644
index 00000000000..63d3fb7e2e5
--- /dev/null
+++ b/sql/my_decimal.h
@@ -0,0 +1,332 @@
+/* Copyright (C) 2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ It is interface module to fixed precision decimals library.
+
+ Most functions use 'uint mask' as parameter, if during operation error
+ which fit in this mask is detected then it will be processed automatically
+ here. (errors are E_DEC_* constants, see include/decimal.h)
+
+ Most function are just inline wrappers around library calls
+*/
+
+#ifndef my_decimal_h
+#define my_decimal_h
+
+C_MODE_START
+#include <decimal.h>
+C_MODE_END
+
+#define DECIMAL_LONGLONG_DIGITS 22
+#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
+/*
+ maximum guaranteed length 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)
+/*
+ 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)
+/*
+ maximum size of packet length
+*/
+#define DECIMAL_MAX_FIELD_SIZE DECIMAL_MAX_LENGTH
+
+
+inline uint my_decimal_size(uint precision, uint scale)
+{
+ /*
+ Always allocate more space to allow library to put decimal point
+ where it want
+ */
+ return decimal_size(precision, scale) + 1;
+}
+
+
+/* my_decimal class limits 'decimal' type to what we need in MySQL */
+/* It internally all necessary space iside the instance so no extra */
+/* memory is needed. One should call fix_buffer_pointer() function */
+/* when he moves my_decimal objects in memory */
+class my_decimal :public decimal
+{
+ decimal_digit buffer[DECIMAL_BUFF_LENGTH];
+
+public:
+
+ void init()
+ {
+ len= DECIMAL_BUFF_LENGTH;
+ buf= buffer;
+#if !defined(HAVE_purify) && !defined(DBUG_OFF)
+ for (uint i= 0; i < DECIMAL_BUFF_LENGTH; i++)
+ buffer[i]= i;
+#endif
+ }
+ my_decimal()
+ {
+ init();
+ }
+ void fix_buffer_pointer() { buf= buffer; }
+
+ bool sign() const { return decimal::sign; }
+ void sign(bool s) { decimal::sign= s; }
+};
+
+
+#ifndef DBUG_OFF
+void print_decimal(const my_decimal *dec);
+void print_decimal_buff(const my_decimal *dec, const byte* ptr, int length);
+#endif
+
+#ifndef MYSQL_CLIENT
+int decimal_operation_results(int result);
+#else
+inline int decimal_operation_results(int result)
+{
+ return result;
+}
+#endif /*MYSQL_CLIENT*/
+
+inline int check_result(uint mask, int result)
+{
+ if (result & mask)
+ decimal_operation_results(result);
+ return result;
+}
+
+
+inline
+int my_decimal_string_length(const my_decimal *d)
+{
+ return decimal_string_size(d);
+}
+
+
+inline
+int my_decimal_max_length(const my_decimal *d)
+{
+ /* -1 because we do not count \0 */
+ return decimal_string_size(d) - 1;
+}
+
+
+inline
+int my_decimal_get_binary_size(uint precision, uint scale)
+{
+ return decimal_bin_size((int)precision, (int)scale);
+}
+
+
+inline
+void my_decimal2decimal(const my_decimal *from, my_decimal *to)
+{
+ *to= *from;
+ to->fix_buffer_pointer();
+}
+
+
+int my_decimal2binary(uint mask, const my_decimal *d, byte *bin, int prec,
+ int scale);
+
+
+inline
+int binary2my_decimal(uint mask, const byte *bin, my_decimal *d, int prec,
+ int scale)
+{
+ return check_result(mask, bin2decimal((char *)bin, (decimal *)d, prec,
+ scale));
+}
+
+
+inline
+int my_decimal_set_zero(my_decimal *d)
+{
+ decimal_make_zero(((decimal *)d));
+ return 0;
+}
+
+
+inline
+bool my_decimal_is_zero(const my_decimal *decimal_value)
+{
+ return decimal_is_zero((decimal *)decimal_value);
+}
+
+
+inline
+int my_decimal_round(uint mask, const my_decimal *from, int scale,
+ bool truncate, my_decimal *to)
+{
+ return check_result(mask, decimal_round((decimal *)from, to, scale,
+ (truncate ? TRUNCATE : HALF_UP)));
+}
+
+
+inline
+int my_decimal_floor(uint mask, const my_decimal *from, my_decimal *to)
+{
+ return check_result(mask, decimal_round((decimal *)from, to, 0, FLOOR));
+}
+
+
+inline
+int my_decimal_ceiling(uint mask, const my_decimal *from, my_decimal *to)
+{
+ return check_result(mask, decimal_round((decimal *)from, to, 0, CEILING));
+}
+
+
+#ifndef MYSQL_CLIENT
+int my_decimal2string(uint mask, const my_decimal *d, int fixed_prec,
+ int fixed_dec, char filler, String *str);
+#endif
+
+inline
+int my_decimal2int(uint mask, const my_decimal *d, my_bool unsigned_flag,
+ longlong *l)
+{
+ my_decimal rounded;
+ /* decimal_round can return only E_DEC_TRUNCATED */
+ decimal_round((decimal*)d, &rounded, 0, HALF_UP);
+ return check_result(mask, (unsigned_flag ?
+ decimal2ulonglong(&rounded, (ulonglong *)l) :
+ decimal2longlong(&rounded, l)));
+}
+
+
+inline
+int my_decimal2double(uint mask, const my_decimal *d, double *result)
+{
+ return check_result(mask, decimal2double((decimal *)d, result));
+}
+
+
+inline
+int str2my_decimal(uint mask, const char *str, my_decimal *d,
+ char **end= 0)
+{
+ /* set it to 0 to avoid junk in value in case of error of conversion */
+ my_decimal_set_zero(d);
+ return check_result(mask, string2decimal((char *)str, (decimal *)d, end));
+}
+
+
+int str2my_decimal(uint mask, const char *from, uint length,
+ CHARSET_INFO *charset, my_decimal *decimal_value);
+
+
+#ifdef MYSQL_SERVER
+inline
+int string2my_decimal(uint mask, const String *str, my_decimal *d)
+{
+ return str2my_decimal(mask, str->ptr(), str->length(), str->charset(), d);
+}
+#endif
+
+
+inline
+int double2my_decimal(uint mask, double val, my_decimal *d)
+{
+ return check_result(mask, double2decimal(val, (decimal *)d));
+}
+
+
+inline
+int int2my_decimal(uint mask, longlong i, my_bool unsigned_flag, my_decimal *d)
+{
+ return check_result(mask, (unsigned_flag ?
+ ulonglong2decimal((ulonglong)i, d) :
+ longlong2decimal(i, d)));
+}
+
+
+inline
+int my_decimal_neg(st_decimal *arg)
+{
+ decimal_neg(arg);
+ return 0;
+}
+
+
+inline
+int my_decimal_add(uint mask, my_decimal *res, const my_decimal *a,
+ const my_decimal *b)
+{
+ return check_result(mask, decimal_add((decimal *)a, (decimal *)b, res));
+}
+
+
+inline
+int my_decimal_sub(uint mask, my_decimal *res, const my_decimal *a,
+ const my_decimal *b)
+{
+ return check_result(mask, decimal_sub((decimal *)a, (decimal *)b, res));
+}
+
+
+inline
+int my_decimal_mul(uint mask, my_decimal *res, const my_decimal *a,
+ const my_decimal *b)
+{
+ return check_result(mask, decimal_mul((decimal *)a, (decimal *)b, res));
+}
+
+
+inline
+int my_decimal_div(uint mask, my_decimal *res, const my_decimal *a,
+ const my_decimal *b, int div_scale_inc)
+{
+ return check_result(mask, decimal_div((decimal *)a, (decimal *)b, res,
+ div_scale_inc));
+}
+
+
+inline
+int my_decimal_mod(uint mask, my_decimal *res, const my_decimal *a,
+ const my_decimal *b)
+{
+ return check_result(mask, decimal_mod((decimal *)a, (decimal *)b, res));
+}
+
+
+/* Returns -1 if a<b, 1 if a>b and 0 if a==b */
+inline
+int my_decimal_cmp(const my_decimal *a, const my_decimal *b)
+{
+ return decimal_cmp((decimal *)a, (decimal *)b);
+}
+
+inline
+void max_my_decimal(my_decimal *to, int precision, int frac)
+{
+ DBUG_ASSERT(precision <= DECIMAL_MAX_LENGTH);
+ max_decimal(precision, frac, (decimal *)to);
+}
+
+#endif /*my_decimal_h*/
+
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 2cabcb6d49c..fdcf061ab7a 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -343,6 +343,8 @@ void debug_sync_point(const char* lock_name, uint lock_timeout);
#define WEEK_YEAR 2
#define WEEK_FIRST_WEEKDAY 4
+#define STRING_BUFFER_USUAL_SIZE 80
+
enum enum_parsing_place
{
NO_MATTER,
@@ -413,6 +415,7 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
#include "sql_string.h"
#include "sql_list.h"
#include "sql_map.h"
+#include "my_decimal.h"
#include "handler.h"
#include "parse_file.h"
#include "table.h"
@@ -421,6 +424,7 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
#include "sql_udf.h"
class user_var_entry;
#include "item.h"
+extern my_decimal decimal_zero;
typedef Comp_creator* (*chooser_compare_func_creator)(bool invert);
/* sql_parse.cc */
void free_items(Item *item);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 9400bedb585..668ef033414 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -261,11 +261,12 @@ bool opt_large_files= sizeof(my_off_t) > 4;
bool opt_help= 0;
bool opt_verbose= 0;
-arg_cmp_func Arg_comparator::comparator_matrix[4][2] =
+arg_cmp_func Arg_comparator::comparator_matrix[5][2] =
{{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string},
{&Arg_comparator::compare_real, &Arg_comparator::compare_e_real},
{&Arg_comparator::compare_int_signed, &Arg_comparator::compare_e_int},
- {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}};
+ {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row},
+ {&Arg_comparator::compare_decimal, &Arg_comparator::compare_e_decimal}};
/* Global variables */
@@ -372,6 +373,7 @@ const char *sql_mode_str="OFF";
const char *in_left_expr_name= "<left expr>";
/* name of additional condition */
const char *in_additional_cond= "<IN COND>";
+my_decimal decimal_zero;
/* classes for comparation parsing/processing */
Eq_creator eq_creator;
Ne_creator ne_creator;
@@ -2384,6 +2386,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
char **argv, const char **groups)
{
umask(((~my_umask) & 0666));
+ my_decimal_set_zero(&decimal_zero); // set decimal_zero constant;
tzset(); // Set tzname
max_system_variables.pseudo_thread_id= (ulong)~0;
diff --git a/sql/procedure.cc b/sql/procedure.cc
index 420a4f6262b..a31b93da358 100644
--- a/sql/procedure.cc
+++ b/sql/procedure.cc
@@ -41,6 +41,34 @@ static struct st_procedure_def {
{ "analyse",proc_analyse_init } // Analyse a result
};
+
+my_decimal *Item_proc_string::val_decimal(my_decimal *decimal_value)
+{
+ if (null_value)
+ return 0;
+ string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value);
+ return (decimal_value);
+}
+
+
+my_decimal *Item_proc_int::val_decimal(my_decimal *decimal_value)
+{
+ if (null_value)
+ return 0;
+ int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_value);
+ return (decimal_value);
+}
+
+
+my_decimal *Item_proc_real::val_decimal(my_decimal *decimal_value)
+{
+ if (null_value)
+ return 0;
+ double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_value);
+ return (decimal_value);
+}
+
+
/*****************************************************************************
** Setup handling of procedure
** Return 0 if everything is ok
diff --git a/sql/procedure.h b/sql/procedure.h
index 33c1288c88e..4e5bf8a2f4b 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -71,6 +71,7 @@ public:
s->set(value,decimals,default_charset());
return s;
}
+ my_decimal *val_decimal(my_decimal *);
unsigned int size_of() { return sizeof(*this);}
};
@@ -89,6 +90,7 @@ public:
double val_real() { return (double) value; }
longlong val_int() { return value; }
String *val_str(String *s) { s->set(value, default_charset()); return s; }
+ my_decimal *val_decimal(my_decimal *);
unsigned int size_of() { return sizeof(*this);}
};
@@ -122,6 +124,7 @@ public:
{
return null_value ? (String*) 0 : (String*) &str_value;
}
+ my_decimal *val_decimal(my_decimal *);
unsigned int size_of() { return sizeof(*this);}
};
diff --git a/sql/protocol.cc b/sql/protocol.cc
index d537f9cf829..7c56bb3fc7a 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -735,6 +735,7 @@ bool Protocol_simple::store(const char *from, uint length,
DBUG_ASSERT(field_types == 0 ||
field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
field_types[field_pos] == MYSQL_TYPE_BIT ||
+ field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL ||
(field_types[field_pos] >= MYSQL_TYPE_ENUM &&
field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
field_pos++;
@@ -751,6 +752,7 @@ bool Protocol_simple::store(const char *from, uint length,
DBUG_ASSERT(field_types == 0 ||
field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
field_types[field_pos] == MYSQL_TYPE_BIT ||
+ field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL ||
(field_types[field_pos] >= MYSQL_TYPE_ENUM &&
field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
field_pos++;
@@ -813,6 +815,26 @@ bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag)
}
+bool Protocol_simple::store_decimal(const my_decimal *d)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
+ field_pos++;
+#endif
+ int buf_size= my_decimal_string_length(d);
+ char *buff= (char *)my_alloca(buf_size);
+ String str(buff, buf_size, &my_charset_bin);
+ if (my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str))
+ {
+ my_afree(buff);
+ return TRUE;
+ }
+ my_afree(buff);
+ return net_store_data(str.ptr(), str.length());
+}
+
+
bool Protocol_simple::store(float from, uint32 decimals, String *buffer)
{
#ifndef DEBUG_OFF
@@ -1027,6 +1049,24 @@ bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag)
return 0;
}
+bool Protocol_prep::store_decimal(const my_decimal *d)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_NEWDECIMAL);
+ field_pos++;
+#endif
+ int buf_size= my_decimal_string_length(d);
+ char *buff= (char *)my_alloca(buf_size);
+ String str(buff, buf_size, &my_charset_bin);
+ if (my_decimal2string(E_DEC_FATAL_ERROR, d, 0, 0, 0, &str))
+ {
+ my_afree(buff);
+ return TRUE;
+ }
+ my_afree(buff);
+ return store(str.ptr(), str.length(), str.charset());
+}
bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
{
diff --git a/sql/protocol.h b/sql/protocol.h
index fddd3ceba94..ad2593d3ab7 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -82,6 +82,7 @@ public:
virtual bool store_short(longlong from)=0;
virtual bool store_long(longlong from)=0;
virtual bool store_longlong(longlong from, bool unsigned_flag)=0;
+ virtual bool store_decimal(const my_decimal *)=0;
virtual bool store(const char *from, uint length, CHARSET_INFO *cs)=0;
virtual bool store(const char *from, uint length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs)=0;
@@ -107,6 +108,7 @@ public:
virtual bool store_short(longlong from);
virtual bool store_long(longlong from);
virtual bool store_longlong(longlong from, bool unsigned_flag);
+ virtual bool store_decimal(const my_decimal *);
virtual bool store(const char *from, uint length, CHARSET_INFO *cs);
virtual bool store(const char *from, uint length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
@@ -137,6 +139,7 @@ public:
virtual bool store_short(longlong from);
virtual bool store_long(longlong from);
virtual bool store_longlong(longlong from, bool unsigned_flag);
+ virtual bool store_decimal(const my_decimal *);
virtual bool store(const char *from,uint length, CHARSET_INFO *cs);
virtual bool store(const char *from, uint length,
CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 04bb2c5e78f..6fb44ae3ea3 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -1539,7 +1539,7 @@ byte *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type,
bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
const char *value;
String str(buff, sizeof(buff), system_charset_info), *res;
@@ -1576,7 +1576,7 @@ err:
bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names)
{
bool not_used;
- char buff[80], *error= 0;
+ char buff[STRING_BUFFER_USUAL_SIZE], *error= 0;
uint error_len= 0;
String str(buff, sizeof(buff), system_charset_info), *res;
@@ -1787,7 +1787,7 @@ bool sys_var_thd_date_time_format::update(THD *thd, set_var *var)
bool sys_var_thd_date_time_format::check(THD *thd, set_var *var)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String str(buff,sizeof(buff), system_charset_info), *res;
DATE_TIME_FORMAT *format;
@@ -1891,7 +1891,7 @@ bool sys_var_collation::check(THD *thd, set_var *var)
if (var->value->result_type() == STRING_RESULT)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String str(buff,sizeof(buff), system_charset_info), *res;
if (!(res=var->value->val_str(&str)))
{
@@ -1925,7 +1925,7 @@ bool sys_var_character_set::check(THD *thd, set_var *var)
if (var->value->result_type() == STRING_RESULT)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
String str(buff,sizeof(buff), system_charset_info), *res;
if (!(res=var->value->val_str(&str)))
{
@@ -2982,7 +2982,7 @@ int set_var::check(THD *thd)
return 0;
}
- if ((!value->fixed &&
+ if ((!value->fixed &&
value->fix_fields(thd, 0, &value)) || value->check_cols(1))
return -1;
if (var->check_update_type(value->result_type()))
@@ -3121,7 +3121,7 @@ int set_var_password::update(THD *thd)
bool sys_var_thd_storage_engine::check(THD *thd, set_var *var)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
const char *value;
String str(buff, sizeof(buff), &my_charset_latin1), *res;
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index d52474998a8..5ccbd9c518a 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -36,6 +36,8 @@ sp_map_result_type(enum enum_field_types type)
case MYSQL_TYPE_INT24:
return INT_RESULT;
case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ return DECIMAL_RESULT;
case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
return REAL_RESULT;
@@ -127,7 +129,7 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
else
{
DBUG_PRINT("info", ("INT_RESULT: %d", i));
- it= new Item_int(it->val_int());
+ it= new Item_int(i);
}
break;
}
@@ -147,13 +149,80 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
uint8 decimals= it->decimals;
uint32 max_length= it->max_length;
DBUG_PRINT("info", ("REAL_RESULT: %g", d));
- it= new Item_real(it->val_real());
+ it= new Item_float(d);
it->decimals= decimals;
it->max_length= max_length;
}
break;
}
- default:
+ case DECIMAL_RESULT:
+ {
+ switch (it->result_type())
+ {
+ case DECIMAL_RESULT:
+ {
+ my_decimal value, *val= it->val_decimal(&value);
+ if (it->null_value)
+ it= new Item_null();
+ else
+ it= new Item_decimal(val);
+ break;
+ }
+ case INT_RESULT:
+ {
+ longlong val= it->val_int();
+ if (it->null_value)
+ it= new Item_null();
+ else
+ it= new Item_decimal(val, (int)it->max_length,
+ (bool)it->unsigned_flag);
+ break;
+ }
+ case REAL_RESULT:
+ {
+ double val= it->val_real();
+ if (it->null_value)
+ it= new Item_null();
+ else
+ it= new Item_decimal(val, (int)it->max_length,
+ (int)it->decimals);
+ break;
+ }
+ case STRING_RESULT:
+ {
+ char buffer[MAX_FIELD_WIDTH];
+ String tmp(buffer, sizeof(buffer), it->collation.collation);
+ String *val= it->val_str(&tmp);
+ if (it->null_value)
+ it= new Item_null();
+ else
+ it= new Item_decimal(val->ptr(), val->length(), val->charset());
+ break;
+ }
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
+ }
+#ifndef DBUG_OFF
+ if (it->null_value)
+ {
+ DBUG_PRINT("info", ("DECIMAL_RESULT: null"));
+ }
+ else
+ {
+ my_decimal value, *val= it->val_decimal(&value);
+ int len;
+ char *buff=
+ (char *)my_alloca(len= my_decimal_string_length(val) + 3);
+ String str(buff, len, &my_charset_bin);
+ my_decimal2string(0, val, 0, 0, 0, &str);
+ DBUG_PRINT("info", ("DECIMAL_RESULT: %s", str.ptr()));
+ my_afree(buff);
+ }
+#endif
+ break;
+ }
+ case STRING_RESULT:
{
char buffer[MAX_FIELD_WIDTH];
String tmp(buffer, sizeof(buffer), it->collation.collation);
@@ -172,6 +241,9 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
}
break;
}
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
}
}
@@ -732,6 +804,10 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
static_cast<Item_func_get_user_var*>(fi);
suv= new Item_func_set_user_var(guv->get_name(), item);
+ /*
+ we do not check suv->fixed, bacause it can't be fixed after
+ creation
+ */
suv->fix_fields(thd, NULL, &item);
suv->fix_length_and_dec();
suv->check();
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 609882b84c6..0c6c8c5aa70 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -249,14 +249,20 @@ sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars)
it= new Item_int(s);
break;
case REAL_RESULT:
- it= new Item_real(s, strlen(s));
+ it= new Item_float(s, strlen(s));
break;
- default:
+ case DECIMAL_RESULT:
+ it= new Item_decimal(s, strlen(s), thd->db_charset);
+ break;
+ case STRING_RESULT:
{
uint len= strlen(s);
it= new Item_string(thd->strmake(s, len), len, thd->db_charset);
break;
}
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
}
thd->spcont->set_item(pv->offset, it);
}
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index b6bd49b1553..c2eea524cac 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -59,6 +59,11 @@ int compare_ulonglong2(void* cmp_arg __attribute__((unused)),
return compare_ulonglong(s,t);
}
+int compare_decimal2(int* len, const char *s, const char *t)
+{
+ return memcmp(s, t, *len);
+}
+
Procedure *
proc_analyse_init(THD *thd, ORDER *param, select_result *result,
@@ -140,6 +145,8 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
}
if (item->result_type() == REAL_RESULT)
*f_info++ = new field_real(item, pc);
+ if (item->result_type() == DECIMAL_RESULT)
+ *f_info++= new field_decimal(item, pc);
if (item->result_type() == STRING_RESULT)
*f_info++ = new field_str(item, pc);
}
@@ -261,7 +268,7 @@ bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num)
}
else // ulonglong is as big as bigint in MySQL
{
- if ((check_ulonglong(num, info->integers) == REAL_NUM))
+ if ((check_ulonglong(num, info->integers) == DECIMAL_NUM))
return 0;
ev_info->ullval = (ulonglong) max(ev_info->ullval, info->ullval);
ev_info->max_dval = (double) max(ev_info->max_dval, info->dval);
@@ -449,6 +456,80 @@ void field_real::add()
} // field_real::add
+void field_decimal::add()
+{
+ my_decimal dec_buf, *dec= item->val_decimal(&dec_buf);
+ uint length, zero_count, decs;
+ TREE_ELEMENT *element;
+
+ if (item->null_value)
+ {
+ nulls++;
+ return;
+ }
+
+ length= my_decimal_string_length(dec);
+
+ if (room_in_tree)
+ {
+ char buf[DECIMAL_MAX_FIELD_SIZE];
+ my_decimal2binary(E_DEC_FATAL_ERROR, dec, buf,
+ item->max_length, item->decimals);
+ if (!(element = tree_insert(&tree, (void*)buf, 0, tree.custom_arg)))
+ {
+ room_in_tree = 0; // Remove tree, out of RAM ?
+ delete_tree(&tree);
+ }
+ /*
+ if element->count == 1, this element can be found only once from tree
+ if element->count == 2, or more, this element is already in tree
+ */
+ else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
+ {
+ room_in_tree = 0; // Remove tree, too many elements
+ delete_tree(&tree);
+ }
+ }
+
+ if (!found)
+ {
+ found = 1;
+ min_arg = max_arg = sum[0] = *dec;
+ min_arg.fix_buffer_pointer();
+ max_arg.fix_buffer_pointer();
+ sum[0].fix_buffer_pointer();
+ my_decimal_mul(E_DEC_FATAL_ERROR, sum_sqr, dec, dec);
+ cur_sum= 0;
+ min_length = max_length = length;
+ }
+ else
+ {
+ int next_cur_sum= cur_sum ^ 1;
+ my_decimal sqr_buf;
+
+ my_decimal_add(E_DEC_FATAL_ERROR, sum+next_cur_sum, sum+cur_sum, dec);
+ my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec);
+ my_decimal_add(E_DEC_FATAL_ERROR,
+ sum_sqr+next_cur_sum, sum_sqr+cur_sum, &sqr_buf);
+ cur_sum= next_cur_sum;
+ if (length < min_length)
+ min_length = length;
+ if (length > max_length)
+ max_length = length;
+ if (my_decimal_cmp(dec, &min_arg) < 0)
+ {
+ min_arg= *dec;
+ min_arg.fix_buffer_pointer();
+ }
+ if (my_decimal_cmp(dec, &max_arg) > 0)
+ {
+ max_arg= *dec;
+ max_arg.fix_buffer_pointer();
+ }
+ }
+}
+
+
void field_longlong::add()
{
char buff[MAX_FIELD_WIDTH];
@@ -886,6 +967,70 @@ void field_ulonglong::get_opt_type(String *answer,
} //field_ulonglong::get_opt_type
+void field_decimal::get_opt_type(String *answer,
+ ha_rows total_rows __attribute__((unused)))
+{
+ my_decimal zero;
+ char buff[MAX_FIELD_WIDTH];
+
+ my_decimal_set_zero(&zero);
+ my_bool is_unsigned= (my_decimal_cmp(&zero, &min_arg) >= 0);
+
+ sprintf(buff, "DECIMAL(%d, %d)",
+ (int)(max_length - (item->decimals ? 1 : 0)), item->decimals);
+ if (is_unsigned)
+ strcat(buff, " UNSIGNED");
+ answer->append(buff, (uint) strlen(buff));
+}
+
+
+String *field_decimal::get_min_arg(String *str)
+{
+ my_decimal2string(E_DEC_FATAL_ERROR, &min_arg, 0, 0, '0', str);
+ return str;
+}
+
+
+String *field_decimal::get_max_arg(String *str)
+{
+ my_decimal2string(E_DEC_FATAL_ERROR, &max_arg, 0, 0, '0', str);
+ return str;
+}
+
+
+String *field_decimal::avg(String *s, ha_rows rows)
+{
+ if (!(rows - nulls))
+ {
+ s->set((double) 0.0, 1,my_thd_charset);
+ return s;
+ }
+ my_decimal num, avg_val;
+ int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
+ my_decimal_div(E_DEC_FATAL_ERROR, &avg_val, sum+cur_sum, &num, 0);
+ my_decimal2string(E_DEC_FATAL_ERROR, &avg_val, 0, 0, '0', s);
+ return s;
+}
+
+
+String *field_decimal::std(String *s, ha_rows rows)
+{
+ if (!(rows - nulls))
+ {
+ s->set((double) 0.0, 1,my_thd_charset);
+ return s;
+ }
+ my_decimal num, std_val, sum2, sum2d;
+ int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
+ my_decimal_mul(E_DEC_FATAL_ERROR, &sum2, sum+cur_sum, sum+cur_sum);
+ my_decimal_div(E_DEC_FATAL_ERROR, &std_val, &sum2, &num, 0);
+ my_decimal_sub(E_DEC_FATAL_ERROR, &sum2, sum_sqr+cur_sum, &std_val);
+ my_decimal_div(E_DEC_FATAL_ERROR, &std_val, &sum2, &num, 0);
+ my_decimal2string(E_DEC_FATAL_ERROR, &std_val, 0, 0, '0', s);
+ return s;
+}
+
+
int collect_string(String *element,
element_count count __attribute__((unused)),
TREE_INFO *info)
@@ -920,6 +1065,28 @@ int collect_real(double *element, element_count count __attribute__((unused)),
} // collect_real
+int collect_decimal(char *element, element_count count,
+ TREE_INFO *info)
+{
+ char buff[DECIMAL_MAX_STR_LENGTH];
+ String s(buff, sizeof(buff),&my_charset_bin);
+
+ if (info->found)
+ info->str->append(',');
+ else
+ info->found = 1;
+ my_decimal dec;
+ binary2my_decimal(E_DEC_FATAL_ERROR, element, &dec,
+ info->item->max_length, info->item->decimals);
+
+ info->str->append('\'');
+ my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, '0', &s);
+ info->str->append(s);
+ info->str->append('\'');
+ return 0;
+}
+
+
int collect_longlong(longlong *element,
element_count count __attribute__((unused)),
TREE_INFO *info)
@@ -1021,12 +1188,12 @@ uint check_ulonglong(const char *str, uint length)
bigger = LONG_NUM;
}
else if (length > ulonglong_len)
- return REAL_NUM;
+ return DECIMAL_NUM;
else
{
cmp = ulonglong_str;
smaller = LONG_NUM;
- bigger = REAL_NUM;
+ bigger = DECIMAL_NUM;
}
while (*cmp && *cmp++ == *str++) ;
return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h
index 3d1cffecaef..a0f0df9b43b 100644
--- a/sql/sql_analyse.h
+++ b/sql/sql_analyse.h
@@ -61,6 +61,7 @@ int compare_longlong2(void* cmp_arg __attribute__((unused)),
int compare_ulonglong(const ulonglong *s, const ulonglong *t);
int compare_ulonglong2(void* cmp_arg __attribute__((unused)),
const ulonglong *s, const ulonglong *t);
+int compare_decimal2(int* len, const char *s, const char *t);
Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result,
List<Item> &field_list);
void free_string(String*);
@@ -143,6 +144,36 @@ public:
};
+int collect_decimal(char *element, element_count count,
+ TREE_INFO *info);
+
+class field_decimal :public field_info
+{
+ my_decimal min_arg, max_arg;
+ my_decimal sum[2], sum_sqr[2];
+ int cur_sum;
+ int bin_size;
+public:
+ field_decimal(Item* a, analyse* b) :field_info(a,b)
+ {
+ bin_size= my_decimal_get_binary_size(a->max_length, a->decimals);
+ init_tree(&tree, 0, 0, bin_size, (qsort_cmp2)compare_decimal2,
+ 0, 0, (void *)&bin_size);
+ };
+
+ void add();
+ void get_opt_type(String*, ha_rows);
+ String *get_min_arg(String *);
+ String *get_max_arg(String *);
+ String *avg(String *s, ha_rows rows);
+ friend int collect_decimal(char *element, element_count count,
+ TREE_INFO *info);
+ tree_walk_action collect_enum()
+ { return (tree_walk_action) collect_decimal; }
+ String *std(String *s, ha_rows rows);
+};
+
+
int collect_real(double *element, element_count count, TREE_INFO *info);
class field_real: public field_info
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 0a57c0f6bc9..85e0d27160b 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2169,6 +2169,8 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
thd->change_item_tree(ref, item_ref);
else if (item_ref)
*ref= item_ref;
+ if (!(*ref)->fixed)
+ (*ref)->fix_fields(thd, 0, ref);
}
DBUG_RETURN((Field*) view_ref_found);
}
@@ -3389,7 +3391,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
if (cond_and->list.elements)
{
COND *on_expr= cond_and;
- on_expr->fix_fields(thd, 0, &on_expr);
+ if (!on_expr->fixed)
+ on_expr->fix_fields(thd, 0, &on_expr);
if (!embedded->outer_join) // Not left join
{
*conds= and_conds(*conds, cond_and);
@@ -3398,7 +3401,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
thd->restore_backup_item_arena(arena, &backup);
if (*conds && !(*conds)->fixed)
{
- if ((*conds)->fix_fields(thd, tables, conds))
+ if (!(*conds)->fixed &&
+ (*conds)->fix_fields(thd, tables, conds))
goto err_no_arena;
}
}
@@ -3410,8 +3414,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds)
thd->restore_backup_item_arena(arena, &backup);
if (embedded->on_expr && !embedded->on_expr->fixed)
{
- if (embedded->on_expr->fix_fields(thd, tables,
- &embedded->on_expr))
+ if (!embedded->on_expr->fixed &&
+ embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr))
goto err_no_arena;
}
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 89442d157c6..32c9e2a50f7 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1340,6 +1340,9 @@ bool select_max_min_finder_subselect::send_data(List<Item> &items)
case STRING_RESULT:
op= &select_max_min_finder_subselect::cmp_str;
break;
+ case DECIMAL_RESULT:
+ op= &select_max_min_finder_subselect::cmp_decimal;
+ break;
case ROW_RESULT:
// This case should never be choosen
DBUG_ASSERT(0);
@@ -1381,6 +1384,26 @@ bool select_max_min_finder_subselect::cmp_int()
val1 < val2);
}
+bool select_max_min_finder_subselect::cmp_decimal()
+{
+ String *val1, *val2, buf1, buf2;
+ Item *maxmin= ((Item_singlerow_subselect *)item)->el(0);
+ /*
+ as far as both operand is Item_cache buf1 & buf2 will not be used,
+ but added for safety
+ */
+ my_decimal cval, *cvalue= cache->val_decimal(&cval);
+ my_decimal mval, *mvalue= maxmin->val_decimal(&mval);
+ if (fmax)
+ return (cache->null_value && !maxmin->null_value) ||
+ (!cache->null_value && !maxmin->null_value &&
+ my_decimal_cmp(cvalue, mvalue) > 0) ;
+ else
+ return (maxmin->null_value && !cache->null_value) ||
+ (!cache->null_value && !maxmin->null_value &&
+ my_decimal_cmp(cvalue,mvalue) < 0);
+}
+
bool select_max_min_finder_subselect::cmp_str()
{
String *val1, *val2, buf1, buf2;
@@ -1447,6 +1470,8 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
/*
Item_func_set_user_var can't substitute something else on its place =>
0 can be passed as last argument (reference on item)
+ Item_func_set_user_var can't be fixed after creation, so we do not
+ check xx->fixed
*/
xx->fix_fields(thd, (TABLE_LIST*) thd->lex->select_lex.table_list.first,
0);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 29185dfbf7b..32a4093dee9 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1519,6 +1519,7 @@ public:
bool send_data(List<Item> &items);
bool cmp_real();
bool cmp_int();
+ bool cmp_decimal();
bool cmp_str();
};
@@ -1592,9 +1593,10 @@ class user_var_entry
ulong length, update_query_id, used_query_id;
Item_result type;
- double val(my_bool *null_value);
+ double val_real(my_bool *null_value);
longlong val_int(my_bool *null_value);
String *val_str(my_bool *null_value, String *str, uint decimals);
+ my_decimal *val_decimal(my_bool *null_value, my_decimal *result);
DTCollation collation;
};
@@ -1623,9 +1625,11 @@ public:
~Unique();
inline bool unique_add(void *ptr)
{
+ DBUG_ENTER("unique_add");
+ DBUG_PRINT("info", ("tree %u - %u", tree.elements_in_tree, max_elements));
if (tree.elements_in_tree > max_elements && flush())
- return 1;
- return !tree_insert(&tree, ptr, 0, tree.custom_arg);
+ DBUG_RETURN(1);
+ DBUG_RETURN(!tree_insert(&tree, ptr, 0, tree.custom_arg));
}
bool get(TABLE *table);
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index c9c21d82568..dd2ac3c013b 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -409,8 +409,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
tables->table=table;
- if (cond && ((!cond->fixed &&
- cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1)))
+ if (cond && ((!cond->fixed &&
+ cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1)))
goto err0;
table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it
@@ -495,7 +495,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
for (key_len=0 ; (item=it_ke++) ; key_part++)
{
// 'item' can be changed by fix_fields() call
- if ((!item->fixed &&
+ if ((!item->fixed &&
item->fix_fields(thd, tables, it_ke.ref())) ||
(item= *it_ke.ref())->check_cols(1))
goto err;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index b8c77a822c4..78ce3c95d6b 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -40,10 +40,6 @@ sys_var_long_ptr trg_new_row_fake_var(0, 0);
#define yySkip() lex->ptr++
#define yyLength() ((uint) (lex->ptr - lex->tok_start)-1)
-#if MYSQL_VERSION_ID < 32300
-#define FLOAT_NUM REAL_NUM
-#endif
-
pthread_key(LEX*,THR_LEX);
/* Longest standard keyword name */
@@ -437,12 +433,12 @@ inline static uint int_token(const char *str,uint length)
else if (length < signed_longlong_len)
return LONG_NUM;
else if (length > signed_longlong_len)
- return REAL_NUM;
+ return DECIMAL_NUM;
else
{
cmp=signed_longlong_str+1;
smaller=LONG_NUM; // If <= signed_longlong_str
- bigger=REAL_NUM;
+ bigger=DECIMAL_NUM;
}
}
else
@@ -458,10 +454,10 @@ inline static uint int_token(const char *str,uint length)
else if (length > longlong_len)
{
if (length > unsigned_longlong_len)
- return REAL_NUM;
+ return DECIMAL_NUM;
cmp=unsigned_longlong_str;
smaller=ULONGLONG_NUM;
- bigger=REAL_NUM;
+ bigger=DECIMAL_NUM;
}
else
{
@@ -799,7 +795,7 @@ int yylex(void *arg, void *yythd)
return(FLOAT_NUM);
}
yylval->lex_str=get_token(lex,yyLength());
- return(REAL_NUM);
+ return(DECIMAL_NUM);
case MY_LEX_HEX_NUMBER: // Found x'hexstring'
yyGet(); // Skip '
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 5981a8b2d4d..e712cda8073 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2527,7 +2527,8 @@ mysql_execute_command(THD *thd)
goto error;
/* PURGE MASTER LOGS BEFORE 'data' */
it= (Item *)lex->value_list.head();
- if (it->check_cols(1) || it->fix_fields(lex->thd, 0, &it))
+ if ((!it->fixed &&it->fix_fields(lex->thd, 0, &it)) ||
+ it->check_cols(1))
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE");
goto error;
@@ -3746,7 +3747,7 @@ unsent_create_error:
{
Item *it= (Item *)lex->value_list.head();
- if (it->fix_fields(lex->thd, 0, &it) || it->check_cols(1))
+ if ((!it->fixed && it->fix_fields(lex->thd, 0, &it)) || it->check_cols(1))
{
my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY),
MYF(0));
@@ -5070,21 +5071,19 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
break;
case FIELD_TYPE_NULL:
break;
- case FIELD_TYPE_DECIMAL:
+ case FIELD_TYPE_NEWDECIMAL:
if (!length)
{
- if ((new_field->length= new_field->decimals))
- new_field->length++;
- else
+ if (!(new_field->length= new_field->decimals))
new_field->length= 10; // Default length for DECIMAL
}
- if (new_field->length < MAX_FIELD_WIDTH) // Skip wrong argument
- {
- new_field->length+=sign_len;
- if (new_field->decimals)
- new_field->length++;
- }
- break;
+ new_field->pack_length=
+ my_decimal_get_binary_size(new_field->length, new_field->decimals);
+ if (new_field->length <= DECIMAL_MAX_LENGTH &&
+ new_field->length >= new_field->decimals)
+ break;
+ my_error(ER_WRONG_FIELD_SPEC, MYF(0), field_name);
+ DBUG_RETURN(1);
case MYSQL_TYPE_VARCHAR:
/*
Long VARCHAR's are automaticly converted to blobs in mysql_prepare_table
@@ -5270,6 +5269,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
new_field->pack_length= (new_field->length + 7) / 8;
break;
}
+ case FIELD_TYPE_DECIMAL:
+ DBUG_ASSERT(0); /* Was obsolete */
}
if (!(new_field->flags & BLOB_FLAG) &&
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index a71b8148f8e..6488820d2f9 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -332,6 +332,13 @@ static void set_param_double(Item_param *param, uchar **pos, ulong len)
*pos+= 8;
}
+static void set_param_decimal(Item_param *param, uchar **pos, ulong len)
+{
+ ulong length= get_param_length(pos, len);
+ param->set_decimal((char*)*pos, length);
+ *pos+= len;
+}
+
#ifndef EMBEDDED_LIBRARY
/*
@@ -508,6 +515,12 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
param->item_type= Item::REAL_ITEM;
param->item_result_type= REAL_RESULT;
break;
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ param->set_param_func= set_param_decimal;
+ param->item_type= Item::DECIMAL_ITEM;
+ param->item_result_type= DECIMAL_RESULT;
+ break;
case MYSQL_TYPE_TIME:
param->set_param_func= set_param_time;
param->item_type= Item::STRING_ITEM;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 68438f7a785..6af257893d4 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -542,6 +542,10 @@ JOIN::optimize()
}
else if ((conds=new Item_cond_and(conds,having)))
{
+ /*
+ Item_cond_and can't be fixed after creation, so we do not check
+ conds->fixed
+ */
conds->fix_fields(thd, tables_list, &conds);
conds->change_ref_to_fields(thd, tables_list);
conds->top_level_item();
@@ -7213,7 +7217,8 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
if (conds)
{
conds= and_conds(conds, table->on_expr);
- conds->fix_fields(join->thd, 0, &conds);
+ if (!conds->fixed)
+ conds->fix_fields(join->thd, 0, &conds);
}
else
conds= table->on_expr;
@@ -7432,6 +7437,11 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
21))))
{
cond=new_cond;
+ /*
+ Item_func_eq can't be fixed after creation so we do not check
+ cond->fixed, also it do not need tables so we use 0 as second
+ argument.
+ */
cond->fix_fields(thd, 0, &cond);
}
thd->insert_id(0); // Clear for next request
@@ -7446,6 +7456,11 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
if ((new_cond= new Item_func_eq(args[0],new Item_int("0", 0, 2))))
{
cond=new_cond;
+ /*
+ Item_func_eq can't be fixed after creation so we do not check
+ cond->fixed, also it do not need tables so we use 0 as second
+ argument.
+ */
cond->fix_fields(thd, 0, &cond);
}
}
@@ -7641,8 +7656,13 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
else
new_field= item->make_string_field(table);
break;
- case ROW_RESULT:
- default:
+ case DECIMAL_RESULT:
+ new_field= new Field_new_decimal(item->max_length - (item->decimals?1:0),
+ maybe_null,
+ item->name, table, item->decimals);
+ break;
+ case ROW_RESULT:
+ default:
// This case should never be choosen
DBUG_ASSERT(0);
new_field= 0; // to satisfy compiler (uninitialized variable)
@@ -7693,47 +7713,10 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
{
Item_sum *item_sum=(Item_sum*) item;
bool maybe_null=item_sum->maybe_null;
- switch (item_sum->sum_func()) {
- case Item_sum::AVG_FUNC: /* Place for sum & count */
- if (group)
- return new Field_string(sizeof(double)+sizeof(longlong),
- 0, item->name,table,&my_charset_bin);
- else
- return new Field_double(item_sum->max_length,maybe_null,
- item->name, table, item_sum->decimals);
- case Item_sum::VARIANCE_FUNC: /* Place for sum & count */
- case Item_sum::STD_FUNC:
- if (group)
- return new Field_string(sizeof(double)*2+sizeof(longlong),
- 0, item->name,table,&my_charset_bin);
- else
- return new Field_double(item_sum->max_length, maybe_null,
- item->name,table,item_sum->decimals);
- case Item_sum::UNIQUE_USERS_FUNC:
- return new Field_long(9,maybe_null,item->name,table,1);
- default:
- switch (item_sum->result_type()) {
- case REAL_RESULT:
- return new Field_double(item_sum->max_length,maybe_null,
- item->name,table,item_sum->decimals);
- case INT_RESULT:
- return new Field_longlong(item_sum->max_length,maybe_null,
- item->name,table,item->unsigned_flag);
- case STRING_RESULT:
- if (item_sum->max_length > 255 && convert_blob_length)
- return new Field_varstring(convert_blob_length, maybe_null,
- item->name, table,
- item->collation.collation);
- return item_sum->make_string_field(table);
- case ROW_RESULT:
- default:
- // This case should never be choosen
- DBUG_ASSERT(0);
- thd->fatal_error();
- return 0;
- }
- }
- /* We never come here */
+ Field *result= item_sum->create_tmp_field(group, table, convert_blob_length);
+ if (!result)
+ thd->fatal_error();
+ return result;
}
case Item::FIELD_ITEM:
case Item::DEFAULT_VALUE_ITEM:
@@ -7751,6 +7734,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::PROC_ITEM:
case Item::INT_ITEM:
case Item::REAL_ITEM:
+ case Item::DECIMAL_ITEM:
case Item::STRING_ITEM:
case Item::REF_ITEM:
case Item::NULL_ITEM:
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 5abfe44f51b..62c214923f8 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2250,15 +2250,21 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
table->field[6]->store((const char*) pos,
strlen((const char*) pos), cs);
if (field->has_charset())
- table->field[8]->store((longlong) field->field_length/
+ table->field[8]->store((longlong) field->representation_length()/
field->charset()->mbmaxlen);
else
- table->field[8]->store((longlong) field->field_length);
- table->field[9]->store((longlong) field->field_length);
+ table->field[8]->store((longlong) field->representation_length());
+ table->field[9]->store((longlong) field->representation_length());
{
uint dec =field->decimals();
switch (field->type()) {
+ case FIELD_TYPE_NEWDECIMAL:
+ table->field[10]->store((longlong) field->field_length);
+ table->field[10]->set_notnull();
+ table->field[11]->store((longlong) field->decimals());
+ table->field[11]->set_notnull();
+ break;
case FIELD_TYPE_DECIMAL:
{
uint int_part=field->field_length - (dec ? dec + 1 : 0);
@@ -2266,8 +2272,8 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
table->field[10]->set_notnull();
table->field[11]->store((longlong) field->decimals());
table->field[11]->set_notnull();
+ break;
}
- break;
case FIELD_TYPE_TINY:
case FIELD_TYPE_SHORT:
case FIELD_TYPE_LONG:
@@ -2283,8 +2289,8 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
table->field[11]->store((longlong) dec);
table->field[11]->set_notnull();
}
+ break;
}
- break;
default:
break;
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 38f1e6e7250..d7cefb3dceb 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -777,6 +777,14 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}
sql_field->pack_flag= FIELDFLAG_NUMBER;
break;
+ case FIELD_TYPE_NEWDECIMAL:
+ sql_field->pack_flag=(FIELDFLAG_NUMBER |
+ (sql_field->flags & UNSIGNED_FLAG ? 0 :
+ FIELDFLAG_DECIMAL) |
+ (sql_field->flags & ZEROFILL_FLAG ?
+ FIELDFLAG_ZEROFILL : 0) |
+ (sql_field->decimals << FIELDFLAG_DEC_SHIFT));
+ break;
case FIELD_TYPE_TIMESTAMP:
/* We should replace old TIMESTAMP fields with their newer analogs */
if (sql_field->unireg_check == Field::TIMESTAMP_OLD_FIELD)
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 5968d13efde..b9e837b0d64 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -176,7 +176,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
trg_field; trg_field= trg_field->next_trg_field)
{
trg_field->setup_field(thd, table, lex->trg_chistics.event);
- if (trg_field->fix_fields(thd, (TABLE_LIST *)0, (Item **)0))
+ if (!trg_field->fixed &&
+ trg_field->fix_fields(thd, (TABLE_LIST *)0, (Item **)0))
return 1;
}
diff --git a/sql/sql_udf.h b/sql/sql_udf.h
index d1f99a6d232..51ea6d4d627 100644
--- a/sql/sql_udf.h
+++ b/sql/sql_udf.h
@@ -103,6 +103,7 @@ class udf_handler :public Sql_alloc
*null_value=0;
return tmp;
}
+ my_decimal *val_decimal(my_bool *null_value, my_decimal *dec_buf);
void clear()
{
is_null= 0;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 82cc1394eaf..f9df1be2abd 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -501,7 +501,7 @@ int mysql_update(THD *thd,
free_underlaid_joins(thd, select_lex);
if (error < 0)
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
(ulong) thd->cuted_fields);
thd->row_count_func=
@@ -1383,7 +1383,7 @@ err:
bool multi_update::send_eof()
{
- char buff[80];
+ char buff[STRING_BUFFER_USUAL_SIZE];
thd->proc_info="updating reference tables";
/* Does updates for the last n - 1 tables, returns 0 if ok */
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 1402a85229b..012a64b36c2 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -239,6 +239,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token CURRENT_USER
%token DATABASES
%token DATA_SYM
+%token DECIMAL_NUM
%token DECLARE_SYM
%token DEFAULT
%token DELAYED_SYM
@@ -382,7 +383,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token RAID_CHUNKSIZE
%token READ_SYM
%token READS_SYM
-%token REAL_NUM
%token REDUNDANT_SYM
%token REFERENCES
%token REGEXP
@@ -667,7 +667,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%right BINARY COLLATE_SYM
%type <lex_str>
- IDENT IDENT_QUOTED TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM
+ IDENT IDENT_QUOTED TEXT_STRING DECIMAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM
LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text
UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
NCHAR_STRING opt_component key_cache_name
@@ -2658,6 +2658,7 @@ udf_func_type:
udf_type:
STRING_SYM {$$ = (int) STRING_RESULT; }
| REAL {$$ = (int) REAL_RESULT; }
+ | DECIMAL_SYM {$$ = (int) DECIMAL_RESULT; }
| INT_SYM {$$ = (int) INT_RESULT; };
field_list:
@@ -2838,11 +2839,11 @@ type:
| MEDIUMTEXT opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
| LONGTEXT opt_binary { $$=FIELD_TYPE_LONG_BLOB; }
| DECIMAL_SYM float_options field_options
- { $$=FIELD_TYPE_DECIMAL;}
+ { $$=FIELD_TYPE_NEWDECIMAL;}
| NUMERIC_SYM float_options field_options
- { $$=FIELD_TYPE_DECIMAL;}
+ { $$=FIELD_TYPE_NEWDECIMAL;}
| FIXED_SYM float_options field_options
- { $$=FIELD_TYPE_DECIMAL;}
+ { $$=FIELD_TYPE_NEWDECIMAL;}
| ENUM {Lex->interval_list.empty();} '(' string_list ')' opt_binary
{ $$=FIELD_TYPE_ENUM; }
| SET { Lex->interval_list.empty();} '(' string_list ')' opt_binary
@@ -2904,8 +2905,8 @@ real_type:
float_options:
- /* empty */ {}
- | '(' NUM ')' { Lex->length=$2.str; }
+ /* empty */ { Lex->dec=Lex->length= (char*)0; }
+ | '(' NUM ')' { Lex->length=$2.str; Lex->dec= (char*)0; }
| precision {};
precision:
@@ -4187,13 +4188,15 @@ simple_expr:
| ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); }
| BINARY simple_expr %prec NEG
{
- $$= create_func_cast($2, ITEM_CAST_CHAR, -1, &my_charset_bin);
+ $$= create_func_cast($2, ITEM_CAST_CHAR, -1, 0, &my_charset_bin);
}
| CAST_SYM '(' expr AS cast_type ')'
{
+ LEX *lex= Lex;
$$= create_func_cast($3, $5,
- Lex->length ? atoi(Lex->length) : -1,
- Lex->charset);
+ lex->length ? atoi(lex->length) : -1,
+ lex->dec ? atoi(lex->dec) : 0,
+ lex->charset);
}
| CASE_SYM opt_expr WHEN_SYM when_list opt_else END
{ $$= new Item_func_case(* $4, $2, $5 ); }
@@ -4201,6 +4204,7 @@ simple_expr:
{
$$= create_func_cast($3, $5,
Lex->length ? atoi(Lex->length) : -1,
+ Lex->dec ? atoi(Lex->dec) : 0,
Lex->charset);
}
| CONVERT_SYM '(' expr USING charset_name ')'
@@ -4565,6 +4569,22 @@ simple_expr:
$$ = new Item_sum_udf_int(udf);
}
break;
+ case DECIMAL_RESULT:
+ if (udf->type == UDFTYPE_FUNCTION)
+ {
+ if ($3 != NULL)
+ $$ = new Item_func_udf_decimal(udf, *$3);
+ else
+ $$ = new Item_func_udf_decimal(udf);
+ }
+ else
+ {
+ if ($3 != NULL)
+ $$ = new Item_sum_udf_decimal(udf, *$3);
+ else
+ $$ = new Item_sum_udf_decimal(udf);
+ }
+ break;
default:
YYABORT;
}
@@ -4814,16 +4834,17 @@ in_sum_expr:
};
cast_type:
- BINARY opt_len { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; }
- | CHAR_SYM opt_len opt_binary { $$=ITEM_CAST_CHAR; }
+ BINARY opt_len { $$=ITEM_CAST_CHAR; Lex->charset= &my_charset_bin; Lex->dec= 0; }
+ | CHAR_SYM opt_len opt_binary { $$=ITEM_CAST_CHAR; Lex->dec= 0; }
| NCHAR_SYM opt_len { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; }
- | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; }
- | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; }
- | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; }
- | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->length= (char*)0; }
- | DATE_SYM { $$=ITEM_CAST_DATE; Lex->charset= NULL; Lex->length= (char*)0; }
- | TIME_SYM { $$=ITEM_CAST_TIME; Lex->charset= NULL; Lex->length= (char*)0; }
- | DATETIME { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; Lex->length= (char*)0; }
+ | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | DATE_SYM { $$=ITEM_CAST_DATE; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | TIME_SYM { $$=ITEM_CAST_TIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | DATETIME { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; Lex->dec=Lex->length= (char*)0; }
+ | DECIMAL_SYM float_options { $$=ITEM_CAST_DECIMAL; Lex->charset= NULL; }
;
expr_list:
@@ -5326,7 +5347,7 @@ ULONG_NUM:
NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
| LONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
| ULONGLONG_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
- | REAL_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
+ | DECIMAL_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
| FLOAT_NUM { int error; $$= (ulong) my_strtoll10($1.str, (char**) 0, &error); }
;
@@ -5334,7 +5355,7 @@ ulonglong_num:
NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
| ULONGLONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
| LONG_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
- | REAL_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
+ | DECIMAL_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
| FLOAT_NUM { int error; $$= (ulonglong) my_strtoll10($1.str, (char**) 0, &error); }
;
@@ -6575,9 +6596,9 @@ NUM_literal:
NUM { int error; $$ = new Item_int($1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); }
| LONG_NUM { int error; $$ = new Item_int($1.str, (longlong) my_strtoll10($1.str, NULL, &error), $1.length); }
| ULONGLONG_NUM { $$ = new Item_uint($1.str, $1.length); }
- | REAL_NUM
+ | DECIMAL_NUM
{
- $$= new Item_real($1.str, $1.length);
+ $$= new Item_decimal($1.str, $1.length, YYTHD->charset());
if (YYTHD->net.report_error)
{
YYABORT;