summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am4
-rw-r--r--sql/examples/ha_archive.cc27
-rw-r--r--sql/field.cc621
-rw-r--r--sql/field.h193
-rw-r--r--sql/field_conv.cc8
-rw-r--r--sql/filesort.cc22
-rw-r--r--sql/ha_federated.cc22
-rw-r--r--sql/ha_innodb.cc118
-rw-r--r--sql/ha_innodb.h20
-rw-r--r--sql/ha_myisam.cc2
-rw-r--r--sql/ha_myisam.h8
-rw-r--r--sql/ha_ndbcluster.cc399
-rw-r--r--sql/ha_ndbcluster.h10
-rw-r--r--sql/handler.cc9
-rw-r--r--sql/handler.h15
-rw-r--r--sql/item.cc899
-rw-r--r--sql/item.h414
-rw-r--r--sql/item_buff.cc37
-rw-r--r--sql/item_cmpfunc.cc493
-rw-r--r--sql/item_cmpfunc.h132
-rw-r--r--sql/item_create.cc7
-rw-r--r--sql/item_create.h3
-rw-r--r--sql/item_func.cc1227
-rw-r--r--sql/item_func.h298
-rw-r--r--sql/item_row.cc14
-rw-r--r--sql/item_row.h5
-rw-r--r--sql/item_strfunc.cc32
-rw-r--r--sql/item_strfunc.h4
-rw-r--r--sql/item_subselect.cc141
-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.cc8
-rw-r--r--sql/log_event.cc214
-rw-r--r--sql/log_event.h19
-rw-r--r--sql/my_decimal.cc212
-rw-r--r--sql/my_decimal.h332
-rw-r--r--sql/mysql_priv.h16
-rw-r--r--sql/mysqld.cc74
-rw-r--r--sql/opt_range.cc2
-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.cc41
-rw-r--r--sql/set_var.h4
-rw-r--r--sql/share/errmsg.txt2
-rw-r--r--sql/slave.cc51
-rw-r--r--sql/slave.h10
-rw-r--r--sql/sp.cc55
-rw-r--r--sql/sp.h13
-rw-r--r--sql/sp_head.cc375
-rw-r--r--sql/sp_head.h24
-rw-r--r--sql/sp_rcontext.cc10
-rw-r--r--sql/sql_analyse.cc210
-rw-r--r--sql/sql_analyse.h31
-rw-r--r--sql/sql_base.cc129
-rw-r--r--sql/sql_cache.cc67
-rw-r--r--sql/sql_cache.h12
-rw-r--r--sql/sql_class.cc33
-rw-r--r--sql/sql_class.h18
-rw-r--r--sql/sql_derived.cc5
-rw-r--r--sql/sql_handler.cc6
-rw-r--r--sql/sql_insert.cc11
-rw-r--r--sql/sql_lex.cc32
-rw-r--r--sql/sql_lex.h14
-rw-r--r--sql/sql_parse.cc139
-rw-r--r--sql/sql_prepare.cc21
-rw-r--r--sql/sql_select.cc78
-rw-r--r--sql/sql_show.cc94
-rw-r--r--sql/sql_string.h10
-rw-r--r--sql/sql_table.cc17
-rw-r--r--sql/sql_trigger.cc3
-rw-r--r--sql/sql_udf.h1
-rw-r--r--sql/sql_union.cc14
-rw-r--r--sql/sql_update.cc9
-rw-r--r--sql/sql_view.cc41
-rw-r--r--sql/sql_yacc.yy237
-rw-r--r--sql/table.h19
-rw-r--r--sql/unireg.h2
83 files changed, 7745 insertions, 1591 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/examples/ha_archive.cc b/sql/examples/ha_archive.cc
index 436c72702a0..b33b5102e69 100644
--- a/sql/examples/ha_archive.cc
+++ b/sql/examples/ha_archive.cc
@@ -43,18 +43,20 @@
handle bulk inserts as well (that is if someone was trying to read at
the same time since we would want to flush).
- A "meta" file is kept. All this file does is contain information on
- the number of rows.
+ A "meta" file is kept alongside the data file. This file serves two purpose.
+ The first purpose is to track the number of rows in the table. The second
+ purpose is to determine if the table was closed properly or not. When the
+ meta file is first opened it is marked as dirty. It is opened when the table
+ itself is opened for writing. When the table is closed the new count for rows
+ is written to the meta file and the file is marked as clean. If the meta file
+ is opened and it is marked as dirty, it is assumed that a crash occured. At
+ this point an error occurs and the user is told to rebuild the file.
+ A rebuild scans the rows and rewrites the meta file. If corruption is found
+ in the data file then the meta file is not repaired.
- No attempts at durability are made. You can corrupt your data. A repair
- method was added to repair the meta file that stores row information,
- but if your data file gets corrupted I haven't solved that. I could
- create a repair that would solve this, but do you want to take a
- chance of loosing your data?
+ At some point a recovery method for such a drastic case needs to be divised.
- Locks are row level, and you will get a consistant read. Transactions
- will be added later (they are not that hard to add at this
- stage).
+ Locks are row level, and you will get a consistant read.
For performance as far as table scans go it is quite fast. I don't have
good numbers but locally it has out performed both Innodb and MyISAM. For
@@ -89,7 +91,6 @@
compression but may speed up ordered searches).
Checkpoint the meta file to allow for faster rebuilds.
Dirty open (right now the meta file is repaired if a crash occured).
- Transactions.
Option to allow for dirty reads, this would lower the sync calls, which would make
inserts a lot faster, but would mean highly arbitrary reads.
@@ -347,6 +348,7 @@ ARCHIVE_SHARE *ha_archive::get_share(const char *table_name, TABLE *table)
share->crashed= TRUE;
else
(void)write_meta_file(share->meta_file, share->rows_recorded, TRUE);
+
/*
It is expensive to open and close the data files and since you can't have
a gzip file that can be both read and written we keep a writer open
@@ -393,7 +395,8 @@ int ha_archive::free_share(ARCHIVE_SHARE *share)
(void)write_meta_file(share->meta_file, share->rows_recorded, FALSE);
if (gzclose(share->archive_write) == Z_ERRNO)
rc= 1;
- my_close(share->meta_file,MYF(0));
+ if (my_close(share->meta_file, MYF(0)))
+ rc= 1;
my_free((gptr) share, MYF(0));
}
pthread_mutex_unlock(&archive_mutex);
diff --git a/sql/field.cc b/sql/field.cc
index aa2c5805bfe..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,
@@ -261,6 +310,7 @@ static Field::field_cast_enum field_cast_date[]=
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
static Field::field_cast_enum field_cast_newdate[]=
{Field::FIELD_CAST_NEWDATE,
+ Field::FIELD_CAST_DATE,
Field::FIELD_CAST_DATETIME,
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
@@ -282,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
*/
@@ -301,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
};
@@ -397,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)
@@ -405,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;
@@ -419,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)
{
@@ -696,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 */
@@ -837,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.
*/
@@ -1254,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
****************************************************************************/
@@ -2553,7 +3028,6 @@ int Field_float::store(longlong nr)
return store((double)nr);
}
-
double Field_float::val_real(void)
{
float j;
@@ -2834,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)
{
@@ -2864,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)))
{
@@ -3031,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
@@ -3093,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).
*/
@@ -3597,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")
*/
@@ -4318,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));
@@ -4436,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;
@@ -4541,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)
{
@@ -4560,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)
{
@@ -4791,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;
@@ -4871,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)
{
@@ -5272,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)
@@ -5395,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)))
{
@@ -5414,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.
*/
@@ -5456,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;
@@ -5484,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)
{
@@ -5997,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;
@@ -6181,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;
@@ -6443,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();
@@ -6486,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)
@@ -6592,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;
@@ -6645,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;
}
@@ -6766,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,
@@ -6834,6 +7361,40 @@ Field *make_field(char *ptr, uint32 field_length,
}
+/*
+ Check if field_type is appropriate field type
+ to create field for tmp table using
+ item->tmp_table_field() method
+
+ SYNOPSIS
+ field_types_to_be_kept()
+ field_type - field type
+
+ NOTE
+ it is used in function get_holder_example_field()
+ from item.cc
+
+ RETURN
+ 1 - can use item->tmp_table_field() method
+ 0 - can not use item->tmp_table_field() method
+
+*/
+
+bool field_types_to_be_kept(enum_field_types field_type)
+{
+ switch (field_type)
+ {
+ case FIELD_TYPE_DATE:
+ case FIELD_TYPE_NEWDATE:
+ case FIELD_TYPE_TIME:
+ case FIELD_TYPE_DATETIME:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
/* Create a field suitable for create of table */
create_field::create_field(Field *old_field,Field *orig_field)
@@ -6924,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
@@ -6956,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
@@ -6985,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
@@ -7017,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 af300c8d471..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)
@@ -1333,6 +1407,7 @@ enum_field_types get_blob_type_from_length(ulong length);
uint32 calc_pack_length(enum_field_types type,uint32 length);
int set_field_to_null(Field *field);
int set_field_to_null_with_conversions(Field *field, bool no_conversions);
+bool field_types_to_be_kept(enum_field_types field_type);
/*
The following are for the interface with the .frm file
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_federated.cc b/sql/ha_federated.cc
index 5185e0bbe9a..695c71677c0 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -586,16 +586,13 @@ uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row)
DBUG_RETURN(0);
}
-bool ha_federated::create_where_from_key(
- String *to,
- KEY *key_info,
- const byte *key,
- uint key_length
- )
+bool ha_federated::create_where_from_key(String *to, KEY *key_info,
+ const byte *key, uint key_length)
{
uint second_loop= 0;
KEY_PART_INFO *key_part;
bool needs_quotes;
+ String tmp;
DBUG_ENTER("ha_federated::create_where_from_key");
for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++)
@@ -656,7 +653,9 @@ bool ha_federated::create_where_from_key(
uint blob_length= uint2korr(key);
key+= HA_KEY_BLOB_LENGTH;
key_length-= HA_KEY_BLOB_LENGTH;
- if (append_escaped(to, (char *)(key), blob_length))
+
+ tmp.set_quick((char*) key, blob_length, &my_charset_bin);
+ if (append_escaped(to, &tmp))
DBUG_RETURN(1);
DBUG_PRINT("ha_federated::create_where_from_key", ("blob type %s", to->c_ptr_quick()));
@@ -666,7 +665,8 @@ bool ha_federated::create_where_from_key(
{
length= uint2korr(key);
key+= HA_KEY_BLOB_LENGTH;
- if (append_escaped(to, (char *)(key), length))
+ tmp.set_quick((char*) key, length, &my_charset_bin);
+ if (append_escaped(to, &tmp))
DBUG_RETURN(1);
DBUG_PRINT("ha_federated::create_where_from_key", ("varchar type %s", to->c_ptr_quick()));
@@ -680,7 +680,7 @@ bool ha_federated::create_where_from_key(
res= field->val_str(&str, (char *)(key));
if (field->result_type() == STRING_RESULT)
{
- if (append_escaped(to, (char *) res->ptr(), res->length()))
+ if (append_escaped(to, res))
DBUG_RETURN(1);
res= field->val_str(&str, (char *)(key));
@@ -1235,7 +1235,7 @@ int ha_federated::update_row(
update_string.append(new_field_value);
new_field_value.length(0);
- if (x+1 < table->s->fields)
+ if ((uint) x+1 < table->s->fields)
{
update_string.append(", ");
if (! has_a_primary_key)
@@ -1311,7 +1311,7 @@ int ha_federated::delete_row(const byte * buf)
delete_string.append(data_string);
data_string.length(0);
- if (x+1 < table->s->fields)
+ if ((uint) x+1 < table->s->fields)
delete_string.append(" AND ");
}
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 32b203f7ad6..052ee0643ee 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -787,8 +787,9 @@ innobase_query_caching_of_table_permitted(
char* full_name, /* in: concatenation of database name,
the null character '\0', and the table
name */
- uint full_name_len) /* in: length of the full name, i.e.
+ uint full_name_len, /* in: length of the full name, i.e.
len(dbname) + len(tablename) + 1 */
+ ulonglong *unused) /* unused for this engine */
{
ibool is_autocommit;
trx_t* trx;
@@ -2158,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:
@@ -4871,12 +4874,12 @@ ha_innobase::update_table_comment(
dict_print_info_on_foreign_keys(FALSE, file,
prebuilt->trx, prebuilt->table);
flen = ftell(file);
- if(length + flen + 3 > 64000) {
+ if (flen < 0) {
+ flen = 0;
+ } else if (length + flen + 3 > 64000) {
flen = 64000 - 3 - length;
}
- ut_ad(flen > 0);
-
/* allocate buffer for the full string, and
read the contents of the temporary file */
@@ -4940,12 +4943,12 @@ ha_innobase::get_foreign_key_create_info(void)
prebuilt->trx->op_info = (char*)"";
flen = ftell(file);
- if(flen > 64000 - 1) {
+ if (flen < 0) {
+ flen = 0;
+ } else if(flen > 64000 - 1) {
flen = 64000 - 1;
}
- ut_ad(flen >= 0);
-
/* allocate buffer for the string, and
read the contents of the temporary file */
@@ -5546,12 +5549,12 @@ innodb_show_status(
srv_printf_innodb_monitor(srv_monitor_file);
flen = ftell(srv_monitor_file);
os_file_set_eof(srv_monitor_file);
- if(flen > 64000 - 1) {
+ if (flen < 0) {
+ flen = 0;
+ } else if (flen > 64000 - 1) {
flen = 64000 - 1;
}
- ut_ad(flen > 0);
-
/* allocate buffer for the string, and
read the contents of the temporary file */
@@ -5770,7 +5773,7 @@ ha_innobase::store_lock(
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
- if ((lock_type == TL_READ && thd->in_lock_tables) ||
+ if ((lock_type == TL_READ && thd->in_lock_tables) ||
(lock_type == TL_READ_HIGH_PRIORITY && thd->in_lock_tables) ||
lock_type == TL_READ_WITH_SHARED_LOCKS ||
lock_type == TL_READ_NO_INSERT ||
@@ -5793,8 +5796,27 @@ ha_innobase::store_lock(
unexpected if an obsolete consistent read view would be
used. */
- prebuilt->select_lock_type = LOCK_S;
- prebuilt->stored_select_lock_type = LOCK_S;
+ if (srv_locks_unsafe_for_binlog &&
+ prebuilt->trx->isolation_level != TRX_ISO_SERIALIZABLE &&
+ (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) &&
+ thd->lex->sql_command != SQLCOM_SELECT &&
+ thd->lex->sql_command != SQLCOM_UPDATE_MULTI &&
+ thd->lex->sql_command != SQLCOM_DELETE_MULTI ) {
+
+ /* In case we have innobase_locks_unsafe_for_binlog
+ option set and isolation level of the transaction
+ is not set to serializable and MySQL is doing
+ INSERT INTO...SELECT without FOR UPDATE or IN
+ SHARE MODE we use consistent read for select.
+ Similarly, in case of DELETE...SELECT and
+ UPDATE...SELECT when these are not multi table.*/
+
+ prebuilt->select_lock_type = LOCK_NONE;
+ prebuilt->stored_select_lock_type = LOCK_NONE;
+ } else {
+ prebuilt->select_lock_type = LOCK_S;
+ prebuilt->stored_select_lock_type = LOCK_S;
+ }
} else if (lock_type != TL_IGNORE) {
@@ -6142,13 +6164,19 @@ innobase_get_at_most_n_mbchars(
extern "C" {
/**********************************************************************
-This function returns true if SQL-query in the current thread
+This function returns true if
+
+1) SQL-query in the current thread
is either REPLACE or LOAD DATA INFILE REPLACE.
+
+2) SQL-query in the current thread
+is INSERT ON DUPLICATE KEY UPDATE.
+
NOTE that /mysql/innobase/row/row0ins.c must contain the
prototype for this function ! */
ibool
-innobase_query_is_replace(void)
+innobase_query_is_update(void)
/*===========================*/
{
THD* thd;
@@ -6160,17 +6188,23 @@ innobase_query_is_replace(void)
( thd->lex->sql_command == SQLCOM_LOAD &&
thd->lex->duplicates == DUP_REPLACE )) {
return true;
- } else {
- return false;
}
+
+ if ( thd->lex->sql_command == SQLCOM_INSERT &&
+ thd->lex->duplicates == DUP_UPDATE ) {
+ return true;
+ }
+
+ return false;
}
}
/***********************************************************************
This function is used to prepare X/Open XA distributed transaction */
-int innobase_xa_prepare(
-/*====================*/
+int
+innobase_xa_prepare(
+/*================*/
/* out: 0 or error number */
THD* thd, /* in: handle to the MySQL thread of the user
whose XA transaction should be prepared */
@@ -6233,12 +6267,13 @@ int innobase_xa_prepare(
/***********************************************************************
This function is used to recover X/Open XA distributed transactions */
-int innobase_xa_recover(
+int
+innobase_xa_recover(
+/*================*/
/* out: number of prepared transactions
stored in xid_list */
XID* xid_list, /* in/out: prepared transactions */
uint len) /* in: number of slots in xid_list */
-/*====================*/
{
if (len == 0 || xid_list == NULL) {
return 0;
@@ -6251,8 +6286,9 @@ int innobase_xa_recover(
This function is used to commit one X/Open XA distributed transaction
which is in the prepared state */
-int innobase_commit_by_xid(
-/*=======================*/
+int
+innobase_commit_by_xid(
+/*===================*/
/* out: 0 or error number */
XID* xid) /* in: X/Open XA Transaction Identification */
{
@@ -6273,7 +6309,9 @@ int innobase_commit_by_xid(
This function is used to rollback one X/Open XA distributed transaction
which is in the prepared state */
-int innobase_rollback_by_xid(
+int
+innobase_rollback_by_xid(
+/*=====================*/
/* out: 0 or error number */
XID *xid) /* in : X/Open XA Transaction Idenfification */
{
@@ -6288,36 +6326,4 @@ int innobase_rollback_by_xid(
}
}
-/***********************************************************************
-This function is used to test commit/rollback of XA transactions */
-
-int innobase_xa_end(
-/*================*/
- THD* thd) /* in: MySQL thread handle of the user for whom
- transactions should be recovered */
-{
- DBUG_ENTER("innobase_xa_end");
-
- XID trx_list[100];
- int trx_num, trx_num_max = 100;
- int i;
- XID xid;
-
- while((trx_num = innobase_xa_recover(trx_list, trx_num_max))) {
-
- for(i=0;i < trx_num; i++) {
- xid = trx_list[i];
-
- if ( i % 2) {
- innobase_commit_by_xid(&xid);
- } else {
- innobase_rollback_by_xid(&xid);
- }
- }
- }
-
- free(trx_list);
-
- DBUG_RETURN(0);
-}
#endif /* HAVE_INNOBASE_DB */
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 7a48de52422..cca33cbbe1c 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -33,6 +33,10 @@ typedef struct st_innobase_share {
} INNOBASE_SHARE;
+my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name,
+ uint full_name_len,
+ ulonglong *unused);
+
/* The class defining a handle to an Innodb table */
class ha_innobase: public handler
{
@@ -173,6 +177,20 @@ class ha_innobase: public handler
void init_table_handle_for_HANDLER();
ulonglong get_auto_increment();
uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; }
+ /*
+ ask handler about permission to cache table during query registration
+ */
+ my_bool register_query_cache_table(THD *thd, char *table_key,
+ uint key_length,
+ qc_engine_callback *call_back,
+ ulonglong *engine_data)
+ {
+ *call_back= innobase_query_caching_of_table_permitted;
+ *engine_data= 0;
+ return innobase_query_caching_of_table_permitted(thd, table_key,
+ key_length,
+ engine_data);
+ }
static char *get_mysql_bin_log_name();
static ulonglong get_mysql_bin_log_pos();
bool primary_key_is_clustered() { return true; }
@@ -253,8 +271,6 @@ bool innodb_show_status(THD* thd);
bool innodb_mutex_show_status(THD* thd);
void innodb_export_status(void);
-my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name,
- uint full_name_len);
void innobase_release_temporary_latches(void* innobase_tid);
void innobase_store_binlog_offset_and_flush_log(char *binlog_name,longlong offset);
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/ha_myisam.h b/sql/ha_myisam.h
index d2fe36c8357..7e14a3b7941 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -88,8 +88,12 @@ class ha_myisam: public handler
ft_handler->please->reinit_search(ft_handler);
return 0;
}
- FT_INFO *ft_init_ext(uint flags, uint inx,const byte *key, uint keylen)
- { return ft_init_search(flags,file,inx,(byte*) key,keylen, table->record[0]); }
+ FT_INFO *ft_init_ext(uint flags, uint inx,String *key)
+ {
+ return ft_init_search(flags,file,inx,
+ (byte *)key->ptr(), key->length(), key->charset(),
+ table->record[0]);
+ }
int ft_read(byte *buf);
int rnd_init(bool scan);
int rnd_next(byte *buf);
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index f2b159353e3..f77136a548e 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -87,6 +87,12 @@ static int unpackfrm(const void **data, uint *len,
static int ndb_get_table_statistics(Ndb*, const char *,
struct Ndb_statistics *);
+// Util thread variables
+static pthread_t ndb_util_thread;
+pthread_mutex_t LOCK_ndb_util_thread;
+pthread_cond_t COND_ndb_util_thread;
+extern "C" pthread_handler_decl(ndb_util_thread_func, arg);
+ulong ndb_cache_check_time;
/*
Dummy buffer to read zero pack_length fields
@@ -3053,9 +3059,13 @@ int ha_ndbcluster::reset()
DBUG_RETURN(1);
}
+static const char *ha_ndb_bas_ext[]= { ha_ndb_ext, NullS };
-const char **ha_ndbcluster::bas_ext() const
-{ static const char *ext[]= { ha_ndb_ext, NullS }; return ext; }
+const char**
+ha_ndbcluster::bas_ext() const
+{
+ return ha_ndb_bas_ext;
+}
/*
@@ -3223,7 +3233,6 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
m_transaction_on= FALSE;
else
m_transaction_on= thd->variables.ndb_use_transactions;
- // m_use_local_query_cache= thd->variables.ndb_use_local_query_cache;
m_active_trans= thd->transaction.all.ndb_tid ?
(NdbTransaction*)thd->transaction.all.ndb_tid:
@@ -3650,6 +3659,52 @@ static int create_ndb_column(NDBCOL &col,
Create a table in NDB Cluster
*/
+static void ndb_set_fragmentation(NDBTAB &tab, TABLE *form, uint pk_length)
+{
+ if (form->s->max_rows == 0) /* default setting, don't set fragmentation */
+ return;
+ /**
+ * get the number of fragments right
+ */
+ uint no_fragments;
+ {
+#if MYSQL_VERSION_ID >= 50000
+ uint acc_row_size= 25 + /*safety margin*/ 2;
+#else
+ uint acc_row_size= pk_length*4;
+ /* add acc overhead */
+ if (pk_length <= 8) /* main page will set the limit */
+ acc_row_size+= 25 + /*safety margin*/ 2;
+ else /* overflow page will set the limit */
+ acc_row_size+= 4 + /*safety margin*/ 4;
+#endif
+ ulonglong acc_fragment_size= 512*1024*1024;
+ ulonglong max_rows= form->s->max_rows;
+#if MYSQL_VERSION_ID >= 50100
+ no_fragments= (max_rows*acc_row_size)/acc_fragment_size+1;
+#else
+ no_fragments= ((max_rows*acc_row_size)/acc_fragment_size+1
+ +1/*correct rounding*/)/2;
+#endif
+ }
+ {
+ uint no_nodes= g_ndb_cluster_connection->no_db_nodes();
+ NDBTAB::FragmentType ftype;
+ if (no_fragments > 2*no_nodes)
+ {
+ ftype= NDBTAB::FragAllLarge;
+ if (no_fragments > 4*no_nodes)
+ push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
+ "Ndb might have problems storing the max amount of rows specified");
+ }
+ else if (no_fragments > no_nodes)
+ ftype= NDBTAB::FragAllMedium;
+ else
+ ftype= NDBTAB::FragAllSmall;
+ tab.setFragmentType(ftype);
+ }
+}
+
int ha_ndbcluster::create(const char *name,
TABLE *form,
HA_CREATE_INFO *info)
@@ -3751,7 +3806,9 @@ int ha_ndbcluster::create(const char *name,
break;
}
}
-
+
+ ndb_set_fragmentation(tab, form, pk_length);
+
if ((my_errno= check_ndb_connection()))
DBUG_RETURN(my_errno);
@@ -4017,7 +4074,6 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg):
m_force_send(TRUE),
m_autoincrement_prefetch(32),
m_transaction_on(TRUE),
- m_use_local_query_cache(FALSE),
m_multi_cursor(NULL)
{
int i;
@@ -4068,6 +4124,7 @@ ha_ndbcluster::~ha_ndbcluster()
}
+
/*
Open a table for further use
- fetch metadata for this table from NDB
@@ -4168,16 +4225,14 @@ void ha_ndbcluster::release_thd_ndb(Thd_ndb* thd_ndb)
Ndb* check_ndb_in_thd(THD* thd)
{
- DBUG_ENTER("check_ndb_in_thd");
- Thd_ndb *thd_ndb= (Thd_ndb*)thd->transaction.thd_ndb;
-
+ Thd_ndb *thd_ndb= (Thd_ndb*)thd->transaction.thd_ndb;
if (!thd_ndb)
{
if (!(thd_ndb= ha_ndbcluster::seize_thd_ndb()))
- DBUG_RETURN(NULL);
+ return NULL;
thd->transaction.thd_ndb= thd_ndb;
}
- DBUG_RETURN(thd_ndb->ndb);
+ return thd_ndb->ndb;
}
@@ -4530,13 +4585,21 @@ bool ndbcluster_init()
(void) hash_init(&ndbcluster_open_tables,system_charset_info,32,0,0,
(hash_get_key) ndbcluster_get_key,0,0);
pthread_mutex_init(&ndbcluster_mutex,MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_ndb_util_thread, MY_MUTEX_INIT_FAST);
+ pthread_cond_init(&COND_ndb_util_thread, NULL);
+
+ // Create utility thread
+ pthread_t tmp;
+ if (pthread_create(&tmp, &connection_attrib, ndb_util_thread_func, 0))
+ {
+ DBUG_PRINT("error", ("Could not create ndb utility thread"));
+ goto ndbcluster_init_error;
+ }
+
ndbcluster_inited= 1;
-#ifdef USE_DISCOVER_ON_STARTUP
- if (ndb_discover_tables() != 0)
- goto ndbcluster_init_error;
-#endif
DBUG_RETURN(FALSE);
+
ndbcluster_init_error:
ndbcluster_end();
DBUG_RETURN(TRUE);
@@ -4546,12 +4609,19 @@ bool ndbcluster_init()
/*
End use of the NDB Cluster table handler
- free all global variables allocated by
- ndcluster_init()
+ ndbcluster_init()
*/
bool ndbcluster_end()
{
DBUG_ENTER("ndbcluster_end");
+
+ // Kill ndb utility thread
+ (void) pthread_mutex_lock(&LOCK_ndb_util_thread);
+ DBUG_PRINT("exit",("killing ndb util thread: %lx", ndb_util_thread));
+ (void) pthread_cond_signal(&COND_ndb_util_thread);
+ (void) pthread_mutex_unlock(&LOCK_ndb_util_thread);
+
if(g_ndb)
delete g_ndb;
g_ndb= NULL;
@@ -4562,6 +4632,8 @@ bool ndbcluster_end()
DBUG_RETURN(0);
hash_free(&ndbcluster_open_tables);
pthread_mutex_destroy(&ndbcluster_mutex);
+ pthread_mutex_destroy(&LOCK_ndb_util_thread);
+ pthread_cond_destroy(&COND_ndb_util_thread);
ndbcluster_inited= 0;
DBUG_RETURN(0);
}
@@ -4754,16 +4826,174 @@ const char* ha_ndbcluster::index_type(uint key_number)
return "HASH";
}
}
+
uint8 ha_ndbcluster::table_cache_type()
{
- if (m_use_local_query_cache)
- return HA_CACHE_TBL_TRANSACT;
- else
- return HA_CACHE_TBL_NOCACHE;
+ DBUG_ENTER("ha_ndbcluster::table_cache_type=HA_CACHE_TBL_ASKTRANSACT");
+ DBUG_RETURN(HA_CACHE_TBL_ASKTRANSACT);
}
+
+uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
+ Uint64 *commit_count)
+{
+ DBUG_ENTER("ndb_get_commitcount");
+
+ if (ndb_cache_check_time > 0)
+ {
+ /* Use cached commit_count from share */
+ char name[FN_REFLEN];
+ NDB_SHARE *share;
+ (void)strxnmov(name, FN_REFLEN,
+ "./",dbname,"/",tabname,NullS);
+ DBUG_PRINT("info", ("name: %s", name));
+ pthread_mutex_lock(&ndbcluster_mutex);
+ if (!(share=(NDB_SHARE*) hash_search(&ndbcluster_open_tables,
+ (byte*) name,
+ strlen(name))))
+ {
+ pthread_mutex_unlock(&ndbcluster_mutex);
+ DBUG_RETURN(1);
+ }
+ *commit_count= share->commit_count;
+ DBUG_PRINT("info", ("commit_count: %d", *commit_count));
+ pthread_mutex_unlock(&ndbcluster_mutex);
+ DBUG_RETURN(0);
+ }
+
+ /* Get commit_count from NDB */
+ Ndb *ndb;
+ if (!(ndb= check_ndb_in_thd(thd)))
+ DBUG_RETURN(1);
+ ndb->setDatabaseName(dbname);
+
+ struct Ndb_statistics stat;
+ if (ndb_get_table_statistics(ndb, tabname, &stat))
+ DBUG_RETURN(1);
+ *commit_count= stat.commit_count;
+ DBUG_RETURN(0);
+}
+
+
/*
- Handling the shared NDB_SHARE structure that is needed to
+ Check if a cached query can be used.
+ This is done by comparing the supplied engine_data to commit_count of
+ the table.
+ The commit_count is either retrieved from the share for the table, where
+ it has been cached by the util thread. If the util thread is not started,
+ NDB has to be contacetd to retrieve the commit_count, this will introduce
+ a small delay while waiting for NDB to answer.
+
+
+ SYNOPSIS
+ ndbcluster_cache_retrieval_allowed
+ thd thread handle
+ full_name concatenation of database name,
+ the null character '\0', and the table
+ name
+ full_name_len length of the full name,
+ i.e. len(dbname) + len(tablename) + 1
+
+ engine_data parameter retrieved when query was first inserted into
+ the cache. If the value of engine_data is changed,
+ all queries for this table should be invalidated.
+
+ RETURN VALUE
+ TRUE Yes, use the query from cache
+ FALSE No, don't use the cached query, and if engine_data
+ has changed, all queries for this table should be invalidated
+
+*/
+
+static my_bool
+ndbcluster_cache_retrieval_allowed(THD *thd,
+ char *full_name, uint full_name_len,
+ ulonglong *engine_data)
+{
+ DBUG_ENTER("ndbcluster_cache_retrieval_allowed");
+
+ Uint64 commit_count;
+ bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
+ char *dbname= full_name;
+ char *tabname= dbname+strlen(dbname)+1;
+
+ DBUG_PRINT("enter",("dbname=%s, tabname=%s, autocommit=%d",
+ dbname, tabname, is_autocommit));
+
+ if (!is_autocommit)
+ DBUG_RETURN(FALSE);
+
+ if (ndb_get_commitcount(thd, dbname, tabname, &commit_count))
+ {
+ *engine_data+= 1; /* invalidate */
+ DBUG_RETURN(FALSE);
+ }
+ DBUG_PRINT("info", ("*engine_data=%llu, commit_count=%llu",
+ *engine_data, commit_count));
+ if (*engine_data != commit_count)
+ {
+ *engine_data= commit_count; /* invalidate */
+ DBUG_PRINT("exit",("Do not use cache, commit_count has changed"));
+ DBUG_RETURN(FALSE);
+ }
+
+ DBUG_PRINT("exit",("OK to use cache, *engine_data=%llu",*engine_data));
+ DBUG_RETURN(TRUE);
+}
+
+
+/**
+ Register a table for use in the query cache. Fetch the commit_count
+ for the table and return it in engine_data, this will later be used
+ to check if the table has changed, before the cached query is reused.
+
+ SYNOPSIS
+ ha_ndbcluster::can_query_cache_table
+ thd thread handle
+ full_name concatenation of database name,
+ the null character '\0', and the table
+ name
+ full_name_len length of the full name,
+ i.e. len(dbname) + len(tablename) + 1
+ qc_engine_callback function to be called before using cache on this table
+ engine_data out, commit_count for this table
+
+ RETURN VALUE
+ TRUE Yes, it's ok to cahce this query
+ FALSE No, don't cach the query
+
+*/
+
+my_bool
+ha_ndbcluster::register_query_cache_table(THD *thd,
+ char *full_name, uint full_name_len,
+ qc_engine_callback *engine_callback,
+ ulonglong *engine_data)
+{
+ DBUG_ENTER("ha_ndbcluster::register_query_cache_table");
+
+ bool is_autocommit= !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
+ DBUG_PRINT("enter",("dbname=%s, tabname=%s, is_autocommit=%d",
+ m_dbname,m_tabname,is_autocommit));
+ if (!is_autocommit)
+ DBUG_RETURN(FALSE);
+
+ Uint64 commit_count;
+ if (ndb_get_commitcount(thd, m_dbname, m_tabname, &commit_count))
+ {
+ *engine_data= 0;
+ DBUG_PRINT("error", ("Could not get commitcount"))
+ DBUG_RETURN(FALSE);
+ }
+ *engine_data= commit_count;
+ *engine_callback= ndbcluster_cache_retrieval_allowed;
+ DBUG_PRINT("exit",("*engine_data=%llu", *engine_data));
+ DBUG_RETURN(TRUE);
+}
+
+
+/*
+ Handling the shared NDB_SHARE structure that is needed to
provide table locking.
It's also used for sharing data with other NDB handlers
in the same MySQL Server. There is currently not much
@@ -4800,8 +5030,14 @@ static NDB_SHARE* get_share(const char *table_name)
}
thr_lock_init(&share->lock);
pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
+ share->commit_count= 0;
}
}
+ DBUG_PRINT("share",
+ ("table_name: %s, length: %d, use_count: %d, commit_count: %d",
+ share->table_name, share->table_name_length, share->use_count,
+ share->commit_count));
+
share->use_count++;
pthread_mutex_unlock(&ndbcluster_mutex);
return share;
@@ -5374,7 +5610,7 @@ ha_ndbcluster::update_table_comment(
const char* comment)/* in: table comment defined by user */
{
uint length= strlen(comment);
- if(length > 64000 - 3)
+ if(length > 64000 - 3)
{
return((char*)comment); /* string too long */
}
@@ -5407,4 +5643,125 @@ ha_ndbcluster::update_table_comment(
return str;
}
+
+// Utility thread main loop
+extern "C" pthread_handler_decl(ndb_util_thread_func,
+ arg __attribute__((unused)))
+{
+ THD *thd; /* needs to be first for thread_stack */
+ int error= 0;
+ struct timespec abstime;
+
+ my_thread_init();
+ DBUG_ENTER("ndb_util_thread");
+ DBUG_PRINT("enter", ("ndb_cache_check_time: %d", ndb_cache_check_time));
+
+ thd= new THD; /* note that contructor of THD uses DBUG_ */
+ THD_CHECK_SENTRY(thd);
+
+ pthread_detach_this_thread();
+ ndb_util_thread= pthread_self();
+
+ thd->thread_stack= (char*)&thd; /* remember where our stack is */
+ if (thd->store_globals())
+ {
+ thd->cleanup();
+ delete thd;
+ DBUG_RETURN(NULL);
+ }
+
+ List<NDB_SHARE> util_open_tables;
+ set_timespec(abstime, ndb_cache_check_time);
+ for (;;)
+ {
+
+ pthread_mutex_lock(&LOCK_ndb_util_thread);
+ error= pthread_cond_timedwait(&COND_ndb_util_thread,
+ &LOCK_ndb_util_thread,
+ &abstime);
+ pthread_mutex_unlock(&LOCK_ndb_util_thread);
+
+ DBUG_PRINT("ndb_util_thread", ("Started, ndb_cache_check_time: %d",
+ ndb_cache_check_time));
+
+ if (abort_loop)
+ break; /* Shutting down server */
+
+ if (ndb_cache_check_time == 0)
+ {
+ set_timespec(abstime, 10);
+ continue;
+ }
+
+ /* Set new time to wake up */
+ set_timespec(abstime, ndb_cache_check_time);
+
+ /* Lock mutex and fill list with pointers to all open tables */
+ NDB_SHARE *share;
+ pthread_mutex_lock(&ndbcluster_mutex);
+ for (uint i= 0; i < ndbcluster_open_tables.records; i++)
+ {
+ share= (NDB_SHARE *)hash_element(&ndbcluster_open_tables, i);
+ share->use_count++; /* Make sure the table can't be closed */
+
+ DBUG_PRINT("ndb_util_thread",
+ ("Found open table[%d]: %s, use_count: %d",
+ i, share->table_name, share->use_count));
+
+ /* Store pointer to table */
+ util_open_tables.push_back(share);
+ }
+ pthread_mutex_unlock(&ndbcluster_mutex);
+
+ /* Iterate through the open files list */
+ List_iterator_fast<NDB_SHARE> it(util_open_tables);
+ while (share= it++)
+ {
+ /* Split tab- and dbname */
+ char buf[FN_REFLEN];
+ char *tabname, *db;
+ uint length= dirname_length(share->table_name);
+ tabname= share->table_name+length;
+ memcpy(buf, share->table_name, length-1);
+ buf[length-1]= 0;
+ db= buf+dirname_length(buf);
+ DBUG_PRINT("ndb_util_thread",
+ ("Fetching commit count for: %s, db: %s, tab: %s",
+ share->table_name, db, tabname));
+
+ /* Contact NDB to get commit count for table */
+ g_ndb->setDatabaseName(db);
+ struct Ndb_statistics stat;;
+ if(ndb_get_table_statistics(g_ndb, tabname, &stat) == 0)
+ {
+ DBUG_PRINT("ndb_util_thread",
+ ("Table: %s, rows: %llu, commit_count: %llu",
+ share->table_name, stat.row_count, stat.commit_count));
+ share->commit_count= stat.commit_count;
+ }
+ else
+ {
+ DBUG_PRINT("ndb_util_thread",
+ ("Error: Could not get commit count for table %s",
+ share->table_name));
+ share->commit_count++; /* Invalidate */
+ }
+ /* Decrease the use count and possibly free share */
+ free_share(share);
+ }
+
+ /* Clear the list of open tables */
+ util_open_tables.empty();
+
+ }
+
+ thd->cleanup();
+ delete thd;
+ DBUG_PRINT("exit", ("ndb_util_thread"));
+ my_thread_end();
+ pthread_exit(0);
+ DBUG_RETURN(NULL);
+}
+
+
#endif /* HAVE_NDBCLUSTER_DB */
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index 942a4988252..b27908c20ea 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -37,6 +37,7 @@ class NdbBlob;
// connectstring to cluster if given by mysqld
extern const char *ndbcluster_connectstring;
+extern ulong ndb_cache_check_time;
typedef enum ndb_index_type {
UNDEFINED_INDEX = 0,
@@ -59,6 +60,7 @@ typedef struct st_ndbcluster_share {
pthread_mutex_t mutex;
char *table_name;
uint table_name_length,use_count;
+ ulonglong commit_count;
} NDB_SHARE;
/*
@@ -155,8 +157,11 @@ class ha_ndbcluster: public handler
static Thd_ndb* seize_thd_ndb();
static void release_thd_ndb(Thd_ndb* thd_ndb);
uint8 table_cache_type();
-
- private:
+ my_bool register_query_cache_table(THD *thd, char *table_key,
+ uint key_length,
+ qc_engine_callback *engine_callback,
+ ulonglong *engine_data);
+private:
int alter_table_name(const char *to);
int drop_table();
int create_index(const char *name, KEY *key_info, bool unique);
@@ -256,7 +261,6 @@ class ha_ndbcluster: public handler
bool m_force_send;
ha_rows m_autoincrement_prefetch;
bool m_transaction_on;
- bool m_use_local_query_cache;
bool m_disable_multi_read;
byte *m_multi_range_result_ptr;
diff --git a/sql/handler.cc b/sql/handler.cc
index a9bb19158dd..b4fed363e87 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -234,15 +234,6 @@ handler *get_new_handler(TABLE *table, enum db_type db_type)
}
}
-bool ha_caching_allowed(THD* thd, char* table_key,
- uint key_length, uint8 cache_type)
-{
-#ifdef HAVE_INNOBASE_DB
- if (cache_type == HA_CACHE_TBL_ASKTRANSACT)
- return innobase_query_caching_of_table_permitted(thd, table_key, key_length);
-#endif
- return 1;
-}
/*
diff --git a/sql/handler.h b/sql/handler.h
index 2b5c66fd886..8ad49456bf6 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -455,8 +455,7 @@ public:
int compare_key(key_range *range);
virtual int ft_init() { return HA_ERR_WRONG_COMMAND; }
void ft_end() { ft_handler=NULL; }
- virtual FT_INFO *ft_init_ext(uint flags,uint inx,const byte *key,
- uint keylen)
+ virtual FT_INFO *ft_init_ext(uint flags, uint inx,String *key)
{ return NULL; }
virtual int ft_read(byte *buf) { return HA_ERR_WRONG_COMMAND; }
virtual int rnd_next(byte *buf)=0;
@@ -592,6 +591,16 @@ public:
/* Type of table for caching query */
virtual uint8 table_cache_type() { return HA_CACHE_TBL_NONTRANSACT; }
+ /* ask handler about permission to cache table when query is to be cached */
+ virtual my_bool register_query_cache_table(THD *thd, char *table_key,
+ uint key_length,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data)
+ {
+ *engine_callback= 0;
+ return 1;
+ }
/*
RETURN
@@ -622,8 +631,6 @@ extern TYPELIB tx_isolation_typelib;
T != DB_TYPE_BERKELEY_DB && \
T != DB_TYPE_NDBCLUSTER)
-bool ha_caching_allowed(THD* thd, char* table_key,
- uint key_length, uint8 cache_type);
enum db_type ha_resolve_by_name(const char *name, uint namelen);
const char *ha_get_storage_engine(enum db_type db_type);
handler *get_new_handler(TABLE *table, enum db_type db_type);
diff --git a/sql/item.cc b/sql/item.cc
index 763ab84582d..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);
@@ -1775,12 +2164,13 @@ resolve_ref_in_select_and_group(THD *thd, Item_ident *ref, SELECT_LEX *select)
if (select_ref != not_found_item && !ambiguous_fields)
{
DBUG_ASSERT(*select_ref);
- if (! (*select_ref)->fixed)
+ if (!select->ref_pointer_array[counter])
{
my_error(ER_ILLEGAL_REFERENCE, MYF(0),
ref->name, "forward reference in item list");
return NULL;
}
+ DBUG_ASSERT((*select_ref)->fixed);
return (select->ref_pointer_array + counter);
}
if (group_by_ref)
@@ -1930,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);
@@ -1994,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);
@@ -2015,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));
}
}
}
@@ -2088,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;
@@ -2262,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;
+ };
}
@@ -2317,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);
@@ -2452,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
*/
@@ -2491,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();
@@ -2532,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();
}
@@ -2543,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;
@@ -2565,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)
@@ -2575,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)
{
@@ -2638,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;
@@ -2727,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)))
@@ -2817,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.
@@ -2887,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. */
{
@@ -2917,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);
@@ -3068,6 +3516,10 @@ void Item_ref::set_properties()
maybe_null= (*ref)->maybe_null;
decimals= (*ref)->decimals;
collation.set((*ref)->collation);
+ /*
+ We have to remember if we refer to a sum function, to ensure that
+ split_sum_func() doesn't try to change the reference.
+ */
with_sum_func= (*ref)->with_sum_func;
if ((*ref)->type() == FIELD_ITEM)
alias_name_used= ((Item_ident *) (*ref))->alias_name_used;
@@ -3140,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);
@@ -3151,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);
@@ -3375,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;
}
@@ -3389,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;
@@ -3402,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);
@@ -3448,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;
@@ -3462,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:
@@ -3489,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;
}
@@ -3499,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);
@@ -3520,7 +4240,6 @@ void Item_cache_str::store(Item *item)
}
}
-
double Item_cache_str::val_real()
{
DBUG_ASSERT(fixed == 1);
@@ -3544,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)
{
@@ -3632,7 +4361,53 @@ void Item_cache_row::bring_value()
}
-Item_type_holder::Item_type_holder(THD *thd, Item *item)
+/*
+ Returns field for temporary table dependind on item type
+
+ SYNOPSIS
+ get_holder_example_field()
+ thd - thread handler
+ item - pointer to item
+ table - empty table object
+
+ NOTE
+ It is possible to return field for Item_func
+ items only if field type of this item is
+ date or time or datetime type.
+ also see function field_types_to_be_kept() from
+ field.cc
+
+ RETURN
+ # - field
+ 0 - no field
+*/
+
+Field *get_holder_example_field(THD *thd, Item *item, TABLE *table)
+{
+ DBUG_ASSERT(table);
+
+ Item_func *tmp_item= 0;
+ if (item->type() == Item::FIELD_ITEM)
+ return (((Item_field*) item)->field);
+ if (item->type() == Item::FUNC_ITEM)
+ tmp_item= (Item_func *) item;
+ else if (item->type() == Item::SUM_FUNC_ITEM)
+ {
+ Item_sum *item_sum= (Item_sum *) item;
+ if (item_sum->keep_field_type())
+ {
+ if (item_sum->args[0]->type() == Item::FIELD_ITEM)
+ return (((Item_field*) item_sum->args[0])->field);
+ if (item_sum->args[0]->type() == Item::FUNC_ITEM)
+ tmp_item= (Item_func *) item_sum->args[0];
+ }
+ }
+ return (tmp_item && field_types_to_be_kept(tmp_item->field_type()) ?
+ tmp_item->tmp_table_field(table) : 0);
+}
+
+
+Item_type_holder::Item_type_holder(THD *thd, Item *item, TABLE *table)
:Item(thd, item), item_type(item->result_type()),
orig_type(item_type)
{
@@ -3642,10 +4417,7 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item)
It is safe assign pointer on field, because it will be used just after
all JOIN::prepare calls and before any SELECT execution
*/
- if (item->type() == Item::FIELD_ITEM)
- field_example= ((Item_field*) item)->field;
- else
- field_example= 0;
+ field_example= get_holder_example_field(thd, item, table);
max_length= real_length(item);
maybe_null= item->maybe_null;
collation.set(item->collation);
@@ -3653,18 +4425,18 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item)
/*
- 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.
@@ -3682,28 +4454,32 @@ 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 ||
- my_charset_same(from->collation.collation,
- to->collation.collation)));
+ (from->collation.collation == to->collation.collation)));
}
-bool Item_type_holder::join_types(THD *thd, Item *item)
+bool Item_type_holder::join_types(THD *thd, Item *item, TABLE *table)
{
uint32 new_length= real_length(item);
bool use_new_field= 0, use_expression_type= 0;
Item_result new_result_type= type_convertor[item_type][item->result_type()];
- bool item_is_a_field= item->type() == Item::FIELD_ITEM;
-
+ Field *field= get_holder_example_field(thd, item, table);
+ bool item_is_a_field= field;
/*
Check if both items point to fields: in this case we
can adjust column types of result table in the union smartly.
*/
if (field_example && item_is_a_field)
{
- Field *field= ((Item_field *)item)->field;
/* Can 'field_example' field store data of the column? */
if ((use_new_field=
(!field->field_cast_compatible(field_example->field_cast_type()) ||
@@ -3732,6 +4508,9 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
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))
{
@@ -3744,7 +4523,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
It is safe to assign a pointer to field here, because it will be used
before any table is closed.
*/
- field_example= ((Item_field*) item)->field;
+ field_example= field;
}
old_cs= collation.collation->name;
@@ -3759,8 +4538,20 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
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;
}
@@ -3777,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;
@@ -3802,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 6857b4acf82..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; }
@@ -1579,14 +1638,15 @@ protected:
Item_result orig_type;
Field *field_example;
public:
- Item_type_holder(THD*, Item*);
+ Item_type_holder(THD*, Item*, TABLE *);
Item_result result_type () const { return item_type; }
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 *);
+ bool join_types(THD *thd, Item *, TABLE *);
Field *example() { return field_example; }
static uint32 real_length(Item *item);
void cleanup()
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 96689bd0ac2..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);
@@ -1530,7 +1781,11 @@ void in_string::set(uint pos,Item *item)
String *str=((String*) base)+pos;
String *res=item->val_str(str);
if (res && res != str)
+ {
+ if (res->uses_buffer_owned_by(str))
+ res->copy();
*str= *res;
+ }
if (!str->charset())
{
CHARSET_INFO *cs;
@@ -1608,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)
{
- switch (item->result_type()) {
+ 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 (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;
@@ -1677,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;
@@ -1748,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;
@@ -1803,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;
@@ -1824,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;
}
@@ -1999,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
@@ -2025,6 +2345,35 @@ Item *Item_cond::transform(Item_transformer transformer, byte *arg)
}
+/*
+ Move SUM items out from item tree and replace with reference
+
+ SYNOPSIS
+ split_sum_func()
+ thd Thread handler
+ ref_pointer_array Pointer to array of reference fields
+ fields All fields in select
+
+ NOTES
+ This function is run on all expression (SELECT list, WHERE, HAVING etc)
+ that have or refer (HAVING) to a SUM expression.
+
+ The split is done to get an unique item for each SUM function
+ so that we can easily find and calculate them.
+ (Calculation done by update_sum_func() and copy_sum_funcs() in
+ sql_select.cc)
+
+ All found SUM items are added FIRST in the fields list and
+ we replace the item with a reference.
+
+ We also replace all functions without side effects (like RAND() or UDF's)
+ that uses columns as arguments.
+ For functions with side effects, we just remember any fields referred
+ by the function to ensure that we get a copy of the field value for the
+ first accepted row. This ensures that we can do things like
+ SELECT a*SUM(b) FROM t1 WHERE a=1
+*/
+
void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array,
List<Item> &fields)
{
@@ -2034,16 +2383,27 @@ void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array,
const_item_cache=1;
while ((item=li++))
{
- if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
+ /* with_sum_func is set for items that contains a SUM expression */
+ if (item->type() != SUM_FUNC_ITEM &&
+ (item->with_sum_func ||
+ (item->used_tables() & PSEUDO_TABLE_BITS)))
item->split_sum_func(thd, ref_pointer_array, fields);
- else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
+ else if (item->type() == SUM_FUNC_ITEM ||
+ (item->used_tables() && item->type() != REF_ITEM))
{
+ /*
+ Replace item with a reference so that we can easily calculate
+ it (in case of sum functions) or copy it (in case of fields)
+
+ The test above is to ensure we don't do a reference for things
+ that are constants or are not yet calculated as in:
+ SELECT RAND() as r1, SUM(a) as r2 FROM t1 HAVING r1 > 1 AND r2 > 0
+ */
Item **ref= li.ref();
uint el= fields.elements;
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();
@@ -2112,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
@@ -2137,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
@@ -2155,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;
@@ -2394,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;
@@ -2768,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
@@ -2946,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
@@ -2977,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
@@ -3114,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 a156322e13c..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;
};
@@ -215,7 +217,7 @@ class Item_bool_rowready_func2 :public Item_bool_func2
public:
Item_bool_rowready_func2(Item *a, Item *b) :Item_bool_func2(a, b)
{
- allowed_arg_cols= a->cols();
+ allowed_arg_cols= 0; // Fetch this value from first argument
}
Item *neg_transformer(THD *thd);
virtual Item *negated_item();
@@ -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,37 +423,67 @@ 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) { allowed_arg_cols= a->cols(); }
+ :Item_int_func(a),row(a),intervals(0)
+ {
+ allowed_arg_cols= 0; // Fetch this value from first argument
+ }
longlong val_int();
void fix_length_and_dec();
const char *func_name() const { return "interval"; }
};
-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; }
};
@@ -465,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)
{
@@ -488,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"; }
@@ -497,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;
@@ -526,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)
{
@@ -543,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; }
@@ -583,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);
@@ -610,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
*/
@@ -624,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)
{
@@ -645,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):
@@ -657,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 */
@@ -711,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;
@@ -780,7 +820,7 @@ class Item_func_in :public Item_int_func
Item_func_in(List<Item> &list)
:Item_int_func(list), array(0), in_item(0), have_null(0)
{
- allowed_arg_cols= args[0]->cols();
+ allowed_arg_cols= 0; // Fetch this value from first argument
}
longlong val_int();
void fix_length_and_dec();
@@ -993,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:
@@ -1023,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:
@@ -1041,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
@@ -1172,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
*/
@@ -1189,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 434a4741cf3..a4c1110da32 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);
}
@@ -308,10 +313,23 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
We can't yet set item to *arg as fix_fields may change *arg
We shouldn't call fix_fields() twice, so check 'fixed' field first
*/
- if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg)) ||
- (*arg)->check_cols(allowed_arg_cols))
+ if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg)))
return TRUE; /* purecov: inspected */
item= *arg;
+
+ if (allowed_arg_cols)
+ {
+ if (item->check_cols(allowed_arg_cols))
+ return 1;
+ }
+ else
+ {
+ /* we have to fetch allowed_arg_cols from first argument */
+ DBUG_ASSERT(arg == args); // it is first argument
+ allowed_arg_cols= item->cols();
+ DBUG_ASSERT(allowed_arg_cols); // Can't be 0 any more
+ }
+
if (item->maybe_null)
maybe_null=1;
@@ -343,6 +361,7 @@ bool Item_func::walk (Item_processor processor, byte *argument)
}
+
/*
Transform an Item_func object with a transformer callback function
@@ -389,15 +408,17 @@ void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array,
for (arg= args, arg_end= args+arg_count; arg != arg_end ; arg++)
{
Item *item=* arg;
- if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
+ if (item->type() != SUM_FUNC_ITEM &&
+ (item->with_sum_func ||
+ (item->used_tables() & PSEUDO_TABLE_BITS)))
item->split_sum_func(thd, ref_pointer_array, fields);
- else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
+ else if (item->type() == SUM_FUNC_ITEM ||
+ (item->used_tables() && item->type() != REF_ITEM))
{
uint el= fields.elements;
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);
}
}
@@ -502,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)
{
@@ -523,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(decimals,args[i]->decimals);
- max_length=float_length(decimals);
+ 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++)
+ {
+ 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;
@@ -585,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;
+}
+
+
+/*
+ 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;
}
-String *Item_num_op::val_str(String *str)
+
+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);
@@ -642,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);
}
@@ -679,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;
+}
+
+
+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::val_real()
+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;
}
-double Item_func_div::val_real()
+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::real_op()
{
DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real();
@@ -741,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;
}
@@ -791,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();
@@ -814,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;
+}
+
- if (args[0]->result_type() == INT_RESULT)
+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;
+}
+
+
+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
@@ -886,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;
}
@@ -1122,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;
/*
@@ -1184,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)
{
@@ -1274,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());
@@ -1302,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();
@@ -1340,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;
}
@@ -1393,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);
@@ -1516,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();
@@ -1759,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
@@ -1775,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);
@@ -1786,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))) ||
@@ -1886,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))
@@ -1913,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;
}
@@ -1958,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()
{
@@ -2004,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()
@@ -2364,20 +3086,17 @@ longlong Item_func_release_lock::val_int()
longlong Item_func_last_insert_id::val_int()
{
+ THD *thd= current_thd;
DBUG_ASSERT(fixed == 1);
if (arg_count)
{
- longlong value=args[0]->val_int();
- current_thd->insert_id(value);
- null_value=args[0]->null_value;
- return value;
- }
- else
- {
- Item *it= get_system_var(current_thd, OPT_SESSION, "last_insert_id", 14,
- "last_insert_id()");
- return it->val_int();
+ longlong value= args[0]->val_int();
+ thd->insert_id(value);
+ null_value= args[0]->null_value;
+ return value; // Avoid side effect of insert_id()
}
+ thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
+ return thd->insert_id();
}
/* This function is just used to test speed of different functions */
@@ -2403,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;
}
@@ -2569,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);
@@ -2584,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;
@@ -2594,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:
@@ -2616,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;
@@ -2644,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
@@ -2654,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.
@@ -2690,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;
}
@@ -2711,7 +3479,7 @@ Item_func_set_user_var::check()
the value method used by the user
RETURN
- 0 Ok
+ 0 OK
1 EOM Error
*/
@@ -2748,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;
}
@@ -2763,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()
@@ -2783,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);
@@ -2819,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);
}
@@ -2850,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
*/
@@ -2874,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();
@@ -2906,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;
@@ -2968,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;
}
}
@@ -3129,9 +3932,7 @@ void Item_func_match::init_search(bool no_order)
if (join_key && !no_order)
flags|=FT_SORTED;
- ft_handler=table->file->ft_init_ext(flags, key,
- (byte*) ft_tmp->ptr(),
- ft_tmp->length());
+ ft_handler=table->file->ft_init_ext(flags, key, ft_tmp);
if (join_key)
table->file->ft_handler=ft_handler;
@@ -3173,12 +3974,12 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
}
/*
Check that all columns come from the same table.
- We've already checked that columns in MATCH are fields so
+ We've already checked that columns in MATCH are fields so
PARAM_TABLE_BIT can only appear from AGAINST argument.
*/
if ((used_tables_cache & ~PARAM_TABLE_BIT) != item->used_tables())
key=NO_SUCH_KEY;
-
+
if (key == NO_SUCH_KEY && !(flags & FT_BOOL))
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH");
@@ -3527,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 `
@@ -3556,13 +4357,18 @@ Item_func_sp::execute(Item **itp)
#endif
if (! m_sp)
- m_sp= sp_find_function(thd, m_name);
+ m_sp= sp_find_function(thd, m_name, TRUE); // cache only
if (! m_sp)
{
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
DBUG_RETURN(-1);
}
+#ifndef EMBEDDED_LIBRARY
+ my_bool nsok= thd->net.no_send_ok;
+ thd->net.no_send_ok= TRUE;
+#endif
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_procedure_access(thd, EXECUTE_ACL,
m_sp->m_db.str, m_sp->m_name.str, 0))
@@ -3578,7 +4384,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.
*/
@@ -3588,6 +4394,9 @@ Item_func_sp::execute(Item **itp)
sp_restore_security_context(thd, m_sp, &save_ctx);
#endif
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
DBUG_RETURN(res);
}
@@ -3598,7 +4407,7 @@ Item_func_sp::field_type() const
DBUG_ENTER("Item_func_sp::field_type");
if (! m_sp)
- m_sp= sp_find_function(current_thd, m_name);
+ m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only
if (m_sp)
{
DBUG_PRINT("info", ("m_returns = %d", m_sp->m_returns));
@@ -3616,7 +4425,7 @@ Item_func_sp::result_type() const
DBUG_PRINT("info", ("m_sp = %p", m_sp));
if (! m_sp)
- m_sp= sp_find_function(current_thd, m_name);
+ m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only
if (m_sp)
{
DBUG_RETURN(m_sp->result());
@@ -3631,7 +4440,7 @@ Item_func_sp::fix_length_and_dec()
DBUG_ENTER("Item_func_sp::fix_length_and_dec");
if (! m_sp)
- m_sp= sp_find_function(current_thd, m_name);
+ m_sp= sp_find_function(current_thd, m_name, TRUE); // cache only
if (! m_sp)
{
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
@@ -3651,9 +4460,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 fb8d77d5b83..20f70fce575 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -32,6 +32,10 @@ class Item_func :public Item_result_field
{
protected:
Item **args, *tmp_arg[2];
+ /*
+ Allowed numbers of columns in result (usually 1, which means scalar value)
+ 0 means get this number from first argument
+ */
uint allowed_arg_cols;
public:
uint arg_count;
@@ -129,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));
@@ -144,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,
@@ -168,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) {}
+
+ void fix_num_length_and_dec();
+ void find_num_type();
+};
-class Item_num_op :public Item_func
+
+/* 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);
@@ -253,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();
};
@@ -278,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();
};
@@ -287,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; }
};
@@ -310,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
{
@@ -487,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();
};
@@ -550,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); }
};
@@ -565,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; }
@@ -751,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
@@ -805,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(); }
@@ -821,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();
};
@@ -848,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();
};
@@ -872,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:
@@ -930,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;
@@ -941,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;
@@ -957,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();
@@ -982,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);
@@ -1091,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
};
@@ -1157,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 62f31186b09..08c682afa85 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -84,21 +84,25 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref)
return FALSE;
}
+
void Item_row::split_sum_func(THD *thd, Item **ref_pointer_array,
List<Item> &fields)
{
Item **arg, **arg_end;
for (arg= items, arg_end= items+arg_count; arg != arg_end ; arg++)
{
- if ((*arg)->with_sum_func && (*arg)->type() != SUM_FUNC_ITEM)
- (*arg)->split_sum_func(thd, ref_pointer_array, fields);
- else if ((*arg)->used_tables() || (*arg)->type() == SUM_FUNC_ITEM)
+ Item *item= *arg;
+ if (item->type() != SUM_FUNC_ITEM &&
+ (item->with_sum_func ||
+ (item->used_tables() & PSEUDO_TABLE_BITS)))
+ item->split_sum_func(thd, ref_pointer_array, fields);
+ else if (item->type() == SUM_FUNC_ITEM ||
+ (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 f9843692b7b..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;
@@ -1776,15 +1778,17 @@ String *Item_func_elt::val_str(String *str)
void Item_func_make_set::split_sum_func(THD *thd, Item **ref_pointer_array,
List<Item> &fields)
{
- if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
+ if (item->type() != SUM_FUNC_ITEM &&
+ (item->with_sum_func ||
+ (item->used_tables() & PSEUDO_TABLE_BITS)))
item->split_sum_func(thd, ref_pointer_array, fields);
- else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
+ else if (item->type() == SUM_FUNC_ITEM ||
+ (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);
@@ -1800,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();
@@ -2189,6 +2193,7 @@ String *Item_func_conv::val_str(String *str)
return 0;
}
null_value=0;
+ unsigned_flag= !(from_base < 0);
if (from_base < 0)
dec= my_strntoll(res->charset(),res->ptr(),res->length(),-from_base,&endptr,&err);
else
@@ -2643,18 +2648,13 @@ String *Item_func_quote::val_str(String *str)
for (from= (char*) arg->ptr(), end= from + arg_length; from < end; from++)
new_length+= get_esc_bit(escmask, (uchar) *from);
- /*
- We have to use realloc() instead of alloc() as we want to keep the
- old result in arg
- */
- if (arg->realloc(new_length))
+ if (tmp_value.alloc(new_length))
goto null;
/*
- As 'arg' and 'str' may be the same string, we must replace characters
- from the end to the beginning
+ We replace characters from the end to the beginning
*/
- to= (char*) arg->ptr() + new_length - 1;
+ to= (char*) tmp_value.ptr() + new_length - 1;
*to--= '\'';
for (start= (char*) arg->ptr(),end= start + arg_length; end-- != start; to--)
{
@@ -2682,10 +2682,10 @@ String *Item_func_quote::val_str(String *str)
}
}
*to= '\'';
- arg->length(new_length);
- str->set_charset(collation.collation);
+ tmp_value.length(new_length);
+ tmp_value.set_charset(collation.collation);
null_value= 0;
- return arg;
+ return &tmp_value;
null:
null_value= 1;
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index e322e5616a1..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));
}
@@ -596,6 +595,7 @@ public:
class Item_func_quote :public Item_str_func
{
+ String tmp_value;
public:
Item_func_quote(Item *a) :Item_str_func(a) {}
const char *func_name() const { return "quote"; }
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index d6d58adaf7c..8d392232f02 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -53,7 +53,7 @@ void Item_subselect::init(st_select_lex *select_lex,
{
DBUG_ENTER("Item_subselect::init");
- DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex));
+ DBUG_PRINT("enter", ("select_lex: 0x%x", (ulong) select_lex));
unit= select_lex->master_unit();
if (unit->item)
@@ -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;
@@ -995,10 +1070,14 @@ Item_in_subselect::row_value_transformer(JOIN *join)
List_iterator_fast<Item> li(select_lex->item_list);
for (uint i= 0; i < n; i++)
{
+ DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed);
+ if (select_lex->ref_pointer_array[i]->
+ 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),
@@ -1019,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;
@@ -1034,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;
}
@@ -1117,6 +1204,7 @@ void subselect_single_select_engine::cleanup()
DBUG_ENTER("subselect_single_select_engine::cleanup");
prepared= optimized= executed= 0;
join= 0;
+ result->cleanup();
DBUG_VOID_RETURN;
}
@@ -1125,6 +1213,7 @@ void subselect_union_engine::cleanup()
{
DBUG_ENTER("subselect_union_engine::cleanup");
unit->reinit_exec_mechanism();
+ result->cleanup();
DBUG_VOID_RETURN;
}
@@ -1132,6 +1221,10 @@ void subselect_union_engine::cleanup()
void subselect_uniquesubquery_engine::cleanup()
{
DBUG_ENTER("subselect_uniquesubquery_engine::cleanup");
+ /*
+ subselect_uniquesubquery_engine have not 'result' assigbed, so we do not
+ cleanup() it
+ */
DBUG_VOID_RETURN;
}
@@ -1415,13 +1508,15 @@ int subselect_indexsubquery_engine::exec()
uint subselect_single_select_engine::cols()
{
- return select_lex->item_list.elements;
+ DBUG_ASSERT(select_lex->join); // should be called after fix_fields()
+ return select_lex->join->fields_list.elements;
}
uint subselect_union_engine::cols()
{
- return unit->first_select()->item_list.elements;
+ DBUG_ASSERT(unit->is_prepared()); // should be called after fix_fields()
+ return unit->types.elements;
}
@@ -1521,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);
@@ -1533,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
@@ -1555,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
@@ -1578,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
@@ -1599,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
@@ -1615,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
@@ -1636,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.cc b/sql/log.cc
index 6c97581d144..7d6854b6fb4 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1346,7 +1346,7 @@ bool MYSQL_LOG::write(Log_event* event_info)
if (thd)
{
- /* NOTE: CHARSET AND TZ REPL WILL BE REWRITTEN SHORTLY */
+#if MYSQL_VERSION_ID < 50003
/*
To make replication of charsets working in 4.1 we are writing values
of charset related variables before every statement in the binlog,
@@ -1375,9 +1375,15 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
if (e.write(file))
goto err;
}
+#endif
/*
We use the same ONE_SHOT trick for making replication of time zones
working in 4.1. Again in 5.0 we have better means for doing this.
+
+ TODO: we should do like we now do with charsets (no more ONE_SHOT;
+ logging in each event in a compact format). Dmitri says we can do:
+ if (time_zone_used) write the timezone to binlog (in a format to be
+ defined).
*/
if (thd->time_zone_used &&
thd->variables.time_zone != global_system_variables.time_zone)
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 5ee034d785e..d2a0e8642f9 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -953,7 +953,13 @@ void Query_log_event::pack_info(Protocol *protocol)
bool Query_log_event::write(IO_CACHE* file)
{
- uchar buf[QUERY_HEADER_LEN+1+4+1+8+1+1+FN_REFLEN+5], *start, *start_of_status;
+ uchar buf[QUERY_HEADER_LEN+
+ 1+4+ // code of flags2 and flags2
+ 1+8+ // code of sql_mode and sql_mode
+ 1+1+FN_REFLEN+ // code of catalog and catalog length and catalog
+ 1+4+ // code of autoinc and the 2 autoinc variables
+ 1+6 // code of charset and charset
+ ], *start, *start_of_status;
ulong event_length;
if (!query)
@@ -1048,9 +1054,15 @@ bool Query_log_event::write(IO_CACHE* file)
int2store(start+2, auto_increment_offset);
start+= 4;
}
+ if (charset_inited)
+ {
+ *(start++)= Q_CHARSET_CODE;
+ memcpy(start, charset, 6);
+ start+= 6;
+ }
/*
Here there could be code like
- if (command-line-option-which-says-"log_this_variable")
+ if (command-line-option-which-says-"log_this_variable" && inited)
{
*(start++)= Q_THIS_VARIABLE_CODE;
int4store(start, this_variable);
@@ -1095,7 +1107,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
thread_id(thd_arg->thread_id),
/* save the original thread id; we already know the server id */
slave_proxy_id(thd_arg->variables.pseudo_thread_id),
- flags2_inited(1), sql_mode_inited(1), flags2(0),
+ flags2_inited(1), sql_mode_inited(1), charset_inited(1),
sql_mode(thd_arg->variables.sql_mode),
auto_increment_increment(thd_arg->variables.auto_increment_increment),
auto_increment_offset(thd_arg->variables.auto_increment_offset)
@@ -1104,7 +1116,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
time(&end_time);
exec_time = (ulong) (end_time - thd->start_time);
catalog_len = (catalog) ? (uint32) strlen(catalog) : 0;
- status_vars_len= 1+4+1+8+1+1+catalog_len+1;
+ /* status_vars_len is set just before writing the event */
db_len = (db) ? (uint32) strlen(db) : 0;
/*
If we don't use flags2 for anything else than options contained in
@@ -1114,7 +1126,12 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
we will probably want to reclaim the 29 bits. So we need the &.
*/
flags2= thd_arg->options & OPTIONS_WRITTEN_TO_BIN_LOG;
-
+ DBUG_ASSERT(thd->variables.character_set_client->number < 256*256);
+ DBUG_ASSERT(thd->variables.collation_connection->number < 256*256);
+ DBUG_ASSERT(thd->variables.collation_server->number < 256*256);
+ int2store(charset, thd_arg->variables.character_set_client->number);
+ int2store(charset+2, thd_arg->variables.collation_connection->number);
+ int2store(charset+4, thd_arg->variables.collation_server->number);
DBUG_PRINT("info",("Query_log_event has flags2=%lu sql_mode=%lu",flags2,sql_mode));
}
#endif /* MYSQL_CLIENT */
@@ -1129,7 +1146,8 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
const Format_description_log_event *description_event)
:Log_event(buf, description_event), data_buf(0), query(NullS), catalog(NullS),
db(NullS), catalog_len(0), status_vars_len(0),
- flags2_inited(0), sql_mode_inited(0)
+ flags2_inited(0), sql_mode_inited(0), charset_inited(0),
+ auto_increment_increment(1), auto_increment_offset(1)
{
ulong data_len;
uint32 tmp;
@@ -1156,8 +1174,6 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
exec_time = uint4korr(buf + Q_EXEC_TIME_OFFSET);
db_len = (uint)buf[Q_DB_LEN_OFFSET];
error_code = uint2korr(buf + Q_ERR_CODE_OFFSET);
- /* If auto_increment is not set by query_event, they should not be used */
- auto_increment_increment= auto_increment_offset= 1;
/*
5.0 format starts here.
@@ -1216,6 +1232,13 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
auto_increment_offset= uint2korr(pos+2);
pos+= 4;
break;
+ case Q_CHARSET_CODE:
+ {
+ charset_inited= 1;
+ memcpy(charset, pos, 6);
+ pos+= 6;
+ break;
+ }
default:
/* That's why you must write status vars in growing order of code */
DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\
@@ -1348,6 +1371,27 @@ void Query_log_event::print(FILE* file, bool short_form,
last_event_info->auto_increment_offset= auto_increment_offset;
}
+ if (likely(charset_inited))
+ {
+ if (unlikely(!last_event_info->charset_inited)) /* first Query event */
+ {
+ last_event_info->charset_inited= 1;
+ last_event_info->charset[0]= ~charset[0]; // force a difference to force write
+ }
+ if (unlikely(bcmp(last_event_info->charset, charset, 6)))
+ {
+ fprintf(file,"SET "
+ "@@session.character_set_client=%d,"
+ "@@session.collation_connection=%d,"
+ "@@session.collation_server=%d"
+ ";\n",
+ uint2korr(charset),
+ uint2korr(charset+2),
+ uint2korr(charset+4));
+ memcpy(last_event_info->charset, charset, 6);
+ }
+ }
+
my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
fputs(";\n", file);
}
@@ -1400,34 +1444,64 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
thd->variables.pseudo_thread_id= thread_id; // for temp tables
mysql_log.write(thd,COM_QUERY,"%s",thd->query);
DBUG_PRINT("query",("%s",thd->query));
-
- if (flags2_inited)
- /*
- all bits of thd->options which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG must
- take their value from flags2.
- */
- thd->options= flags2|(thd->options & ~(ulong)OPTIONS_WRITTEN_TO_BIN_LOG);
- /*
- else, we are in a 3.23/4.0 binlog; we previously received a
- Rotate_log_event which reset thd->options and sql_mode, so nothing to do.
- */
-
- /*
- We do not replicate IGNORE_DIR_IN_CREATE. That is, if the master is a
- slave which runs with SQL_MODE=IGNORE_DIR_IN_CREATE, this should not
- force us to ignore the dir too. Imagine you are a ring of machines, and
- one has a disk problem so that you temporarily need IGNORE_DIR_IN_CREATE
- on this machine; you don't want it to propagate elsewhere (you don't want
- all slaves to start ignoring the dirs).
- */
- if (sql_mode_inited)
- thd->variables.sql_mode=
- (ulong) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) |
- (sql_mode & ~(ulong) MODE_NO_DIR_IN_CREATE));
if (ignored_error_code((expected_error= error_code)) ||
!check_expected_error(thd,rli,expected_error))
+ {
+ if (flags2_inited)
+ /*
+ all bits of thd->options which are 1 in OPTIONS_WRITTEN_TO_BIN_LOG must
+ take their value from flags2.
+ */
+ thd->options= flags2|(thd->options & ~(ulong)OPTIONS_WRITTEN_TO_BIN_LOG);
+ /*
+ else, we are in a 3.23/4.0 binlog; we previously received a
+ Rotate_log_event which reset thd->options and sql_mode etc, so nothing to do.
+ */
+ /*
+ We do not replicate IGNORE_DIR_IN_CREATE. That is, if the master is a
+ slave which runs with SQL_MODE=IGNORE_DIR_IN_CREATE, this should not
+ force us to ignore the dir too. Imagine you are a ring of machines, and
+ one has a disk problem so that you temporarily need IGNORE_DIR_IN_CREATE
+ on this machine; you don't want it to propagate elsewhere (you don't want
+ all slaves to start ignoring the dirs).
+ */
+ if (sql_mode_inited)
+ thd->variables.sql_mode=
+ (ulong) ((thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) |
+ (sql_mode & ~(ulong) MODE_NO_DIR_IN_CREATE));
+ if (charset_inited)
+ {
+ if (rli->cached_charset_compare(charset))
+ {
+ /* Verify that we support the charsets found in the event. */
+ if (!(thd->variables.character_set_client=
+ get_charset(uint2korr(charset), MYF(MY_WME))) ||
+ !(thd->variables.collation_connection=
+ get_charset(uint2korr(charset+2), MYF(MY_WME))) ||
+ !(thd->variables.collation_server=
+ get_charset(uint2korr(charset+4), MYF(MY_WME))))
+ {
+ /*
+ We updated the thd->variables with nonsensical values (0), and the
+ thread is not guaranteed to terminate now (as it may be configured
+ to ignore EE_UNKNOWN_CHARSET);if we're going to execute a next
+ statement we'll have a new charset info with it, so no problem to
+ have stored 0 in thd->variables. But we invalidate cached
+ charset to force a check next time (otherwise if next time
+ charset is unknown again we won't detect it).
+ */
+ rli->cached_charset_invalidate();
+ goto compare_errors;
+ }
+ thd->update_charset(); // for the charset change to take effect
+ }
+ }
+
+ /* Execute the query (note that we bypass dispatch_command()) */
mysql_parse(thd, thd->query, q_len);
+
+ }
else
{
/*
@@ -1452,6 +1526,8 @@ START SLAVE; . Query: '%s'", expected_error, thd->query);
}
goto end;
}
+
+compare_errors:
/*
If we expected a non-zero error code, and we don't get the same error
@@ -1666,12 +1742,7 @@ bool Start_log_event_v3::write(IO_CACHE* file)
int Start_log_event_v3::exec_event(struct st_relay_log_info* rli)
{
DBUG_ENTER("Start_log_event_v3::exec_event");
- /*
- If the I/O thread has not started, mi->old_format is BINLOG_FORMAT_CURRENT
- (that's what the MASTER_INFO constructor does), so the test below is not
- perfect at all.
- */
- switch (rli->relay_log.description_event_for_exec->binlog_version)
+ switch (binlog_version)
{
case 3:
case 4:
@@ -2789,14 +2860,24 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
rli->group_master_log_name,
(ulong) rli->group_master_log_pos));
/*
- Reset thd->options and sql_mode, because this could be the signal of a
- master's downgrade from 5.0 to 4.0.
+ Reset thd->options and sql_mode etc, because this could be the signal of
+ a master's downgrade from 5.0 to 4.0.
However, no need to reset description_event_for_exec: indeed, if the next
master is 5.0 (even 5.0.1) we will soon get a Format_desc; if the next
master is 4.0 then the events are in the slave's format (conversion).
*/
set_slave_thread_options(thd);
thd->variables.sql_mode= global_system_variables.sql_mode;
+ thd->variables.auto_increment_increment=
+ thd->variables.auto_increment_offset= 1;
+ thd->variables.character_set_client=
+ global_system_variables.character_set_client;
+ thd->variables.collation_connection=
+ global_system_variables.collation_connection;
+ thd->variables.collation_server=
+ global_system_variables.collation_server;
+ thd->update_charset();
+ rli->cached_charset_invalidate();
}
pthread_mutex_unlock(&rli->data_lock);
pthread_cond_broadcast(&rli->data_cond);
@@ -3018,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));
@@ -3086,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;
@@ -3101,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:
@@ -3111,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;
@@ -3119,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 */
@@ -3166,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:
{
/*
@@ -3242,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;
@@ -3252,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/log_event.h b/sql/log_event.h
index 64bb9d502e9..7f04582a32d 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -232,6 +232,7 @@ struct sql_ex_info
#define Q_SQL_MODE_CODE 1
#define Q_CATALOG_CODE 2
#define Q_AUTO_INCREMENT 3
+#define Q_CHARSET_CODE 4
/* Intvar event post-header */
@@ -401,11 +402,19 @@ typedef struct st_last_event_info
bool sql_mode_inited;
ulong sql_mode; /* must be same as THD.variables.sql_mode */
ulong auto_increment_increment, auto_increment_offset;
+ bool charset_inited;
+ char charset[6]; // 3 variables, each of them storable in 2 bytes
st_last_event_info()
- :flags2_inited(0), flags2(0), sql_mode_inited(0), sql_mode(0),
- auto_increment_increment(1),auto_increment_offset(1)
+ :flags2_inited(0), sql_mode_inited(0),
+ auto_increment_increment(1),auto_increment_offset(1), charset_inited(0)
{
- db[0]= 0; /* initially, the db is unknown */
+ /*
+ Currently we only use static LAST_EVENT_INFO objects, so zeroed at
+ program's startup, but these explicit bzero() is for the day someone
+ creates dynamic instances.
+ */
+ bzero(db, sizeof(db));
+ bzero(charset, sizeof(charset));
}
} LAST_EVENT_INFO;
#endif
@@ -634,7 +643,7 @@ public:
status_vars on disk is a sequence of pairs (code, value) where 'code' means
'sql_mode', 'affected' etc. Sometimes 'value' must be a short string, so
its first byte is its length. For now the order of status vars is:
- flags2 - sql_mode - catalog.
+ flags2 - sql_mode - catalog - autoinc - charset
We should add the same thing to Load_log_event, but in fact
LOAD DATA INFILE is going to be logged with a new type of event (logging of
the plain text query), so Load_log_event would be frozen, so no need. The
@@ -655,11 +664,13 @@ public:
*/
bool flags2_inited;
bool sql_mode_inited;
+ bool charset_inited;
uint32 flags2;
/* In connections sql_mode is 32 bits now but will be 64 bits soon */
ulong sql_mode;
ulong auto_increment_increment, auto_increment_offset;
+ char charset[6];
#ifndef MYSQL_CLIENT
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
new file mode 100644
index 00000000000..027b33f1d1c
--- /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-from) != length && !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 e725cd177c3..fdcf061ab7a 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -285,6 +285,12 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define MODE_TRADITIONAL (MODE_ERROR_FOR_DIVISION_BY_ZERO*2)
#define MODE_NO_AUTO_CREATE_USER (MODE_TRADITIONAL*2)
#define MODE_HIGH_NOT_PRECEDENCE (MODE_NO_AUTO_CREATE_USER*2)
+/*
+ Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
+ use strictly more than 64 bits by adding one more define above, you should
+ contact the replication team because the replication code should then be
+ updated (to store more bytes on disk).
+*/
#define RAID_BLOCK_SIZE 1024
@@ -337,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,
@@ -401,9 +409,13 @@ inline THD *_current_thd(void)
}
#define current_thd _current_thd()
+typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
+ uint key_length,
+ ulonglong *engine_data);
#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"
@@ -412,6 +424,7 @@ inline THD *_current_thd(void)
#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);
@@ -715,7 +728,6 @@ bool mysql_do(THD *thd, List<Item> &values);
/* sql_analyse.h */
bool append_escaped(String *to_str, String *from_str);
-bool append_escaped(String *to_str, char *from, uint from_len);
/* sql_show.cc */
bool mysqld_show_open_tables(THD *thd,const char *wild);
@@ -1324,7 +1336,7 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
table->null_row= 0;
table->status= STATUS_NO_RECORD;
table->keys_in_use_for_query= table->s->keys_in_use;
- table->maybe_null= test(table->outer_join= table_list->outer_join);
+ table->maybe_null= table_list->outer_join;
table->tablenr= tablenr;
table->map= (table_map) 1 << tablenr;
table->force_index= table_list->force_index;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index e4df359d35c..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 */
@@ -291,6 +292,7 @@ my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam, opt_ndbcluster;
#ifdef HAVE_NDBCLUSTER_DB
const char *opt_ndbcluster_connectstring= 0;
my_bool opt_ndb_shm, opt_ndb_optimized_node_selection;
+ulong opt_ndb_cache_check_time= 0;
#endif
my_bool opt_readonly, use_temp_pool, relay_log_purge;
my_bool opt_sync_bdb_logs, opt_sync_frm;
@@ -371,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;
@@ -2383,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;
@@ -3375,39 +3379,34 @@ int main(int argc, char **argv)
return 0;
}
}
- else if (argc >= 4)
+ else if (argc == 4 || argc == 5)
{
- const char *defaults_file = "--defaults-file";
- const char *service = "--local-service";
- char extra_opt[FN_REFLEN] = "";
+ /*
+ This may seem strange, because we handle --local-service while
+ preserving 4.1's behavior of allowing any one other argument that is
+ passed to the service on startup. (The assumption is that this is
+ --defaults-file=file, but that was not enforced in 4.1, so we don't
+ enforce it here.)
+ */
+ char *extra_opt= NULL;
char *account_name = NULL;
- char *option;
int index;
for (index = 3; index < argc; index++)
{
- option= argv[index];
- /*
- Install an optional service with optional config file
- mysqld --install-manual mysqldopt --defaults-file=c:\miguel\my.ini
- */
- if (strncmp(option, defaults_file, strlen(defaults_file)) == 0)
+ if (strncmp(argv[index], "--local-service", 15) == 0)
{
- strmov(extra_opt, option);
+ account_name=(char*)malloc(27);
+ strmov(account_name, "NT AUTHORITY\\LocalService\0");
}
else
- /*
- Install an optional service as local service
- mysqld --install-manual mysqldopt --local-service
- */
- if (strncmp(option, service, strlen(service)) == 0)
{
- account_name=(char*)malloc(27);
- strmov(account_name, "NT AUTHORITY\\LocalService\0");
+ extra_opt= argv[index];
}
}
- if (!default_service_handling(argv, argv[2], argv[2], file_path, extra_opt, account_name))
- return 0;
+ if (argc != 5 || account_name)
+ if (!default_service_handling(argv, argv[2], argv[2], file_path, extra_opt, account_name))
+ return 0;
}
else if (argc == 1 && Service.IsService(MYSQL_SERVICENAME))
{
@@ -4174,7 +4173,7 @@ enum options_mysqld
OPT_INNODB, OPT_ISAM,
OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, OPT_NDB_USE_EXACT_COUNT,
OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
- OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION,
+ OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION, OPT_NDB_CACHE_CHECK_TIME,
OPT_SKIP_SAFEMALLOC,
OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_COMPLETION_TYPE,
OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
@@ -4251,7 +4250,11 @@ enum options_mysqld
OPT_RANGE_ALLOC_BLOCK_SIZE,
OPT_QUERY_ALLOC_BLOCK_SIZE, OPT_QUERY_PREALLOC_SIZE,
OPT_TRANS_ALLOC_BLOCK_SIZE, OPT_TRANS_PREALLOC_SIZE,
- OPT_SYNC_FRM, OPT_SYNC_BINLOG, OPT_BDB_NOSYNC,
+ OPT_SYNC_FRM, OPT_SYNC_BINLOG,
+ OPT_SYNC_REPLICATION,
+ OPT_SYNC_REPLICATION_SLAVE_ID,
+ OPT_SYNC_REPLICATION_TIMEOUT,
+ OPT_BDB_NOSYNC,
OPT_ENABLE_SHARED_MEMORY,
OPT_SHARED_MEMORY_BASE_NAME,
OPT_OLD_PASSWORDS,
@@ -4702,6 +4705,10 @@ Disable with --skip-ndbcluster (will save memory).",
(gptr*) &opt_ndb_optimized_node_selection,
(gptr*) &opt_ndb_optimized_node_selection,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
+ { "ndb_cache_check_time", OPT_NDB_CACHE_CHECK_TIME,
+ "A dedicated thread is created to update cached commit count value at the given interval.",
+ (gptr*) &opt_ndb_cache_check_time, (gptr*) &opt_ndb_cache_check_time, 0, GET_ULONG, REQUIRED_ARG,
+ 0, 0, LONG_TIMEOUT, 0, 1, 0},
#endif
{"new", 'n', "Use very new possible 'unsafe' functions.",
(gptr*) &global_system_variables.new_mode,
@@ -5447,6 +5454,23 @@ The minimum value for this variable is 4096.",
(gptr*) &sync_binlog_period,
(gptr*) &sync_binlog_period, 0, GET_ULONG, REQUIRED_ARG, 0, 0, ~0L, 0, 1,
0},
+#ifdef DOES_NOTHING_YET
+ {"sync-replication", OPT_SYNC_REPLICATION,
+ "Enable synchronous replication",
+ (gptr*) &global_system_variables.sync_replication,
+ (gptr*) &global_system_variables.sync_replication,
+ 0, GET_ULONG, REQUIRED_ARG, 0, 0, 1, 0, 1, 0},
+ {"sync-replication-slave-id", OPT_SYNC_REPLICATION_SLAVE_ID,
+ "Synchronous replication is wished for this slave",
+ (gptr*) &global_system_variables.sync_replication_slave_id,
+ (gptr*) &global_system_variables.sync_replication_slave_id,
+ 0, GET_ULONG, REQUIRED_ARG, 0, 0, ~0L, 0, 1, 0},
+ {"sync-replication-timeout", OPT_SYNC_REPLICATION_TIMEOUT,
+ "Synchronous replication timeout",
+ (gptr*) &global_system_variables.sync_replication_timeout,
+ (gptr*) &global_system_variables.sync_replication_timeout,
+ 0, GET_ULONG, REQUIRED_ARG, 10, 0, ~0L, 0, 1, 0},
+#endif
{"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default",
(gptr*) &opt_sync_frm, (gptr*) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0,
0, 0, 0, 0},
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index e5799bfd509..ceb9f97bbbc 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3611,7 +3611,7 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
if (!value) // IS NULL or IS NOT NULL
{
- if (field->table->outer_join) // Can't use a key on this
+ if (field->table->maybe_null) // Can't use a key on this
DBUG_RETURN(0);
if (!maybe_null) // Not null field
DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 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 541bcf0ff7d..6fb44ae3ea3 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -358,6 +358,14 @@ sys_var_thd_storage_engine sys_storage_engine("storage_engine",
&SV::table_type);
#ifdef HAVE_REPLICATION
sys_var_sync_binlog_period sys_sync_binlog_period("sync_binlog", &sync_binlog_period);
+sys_var_thd_ulong sys_sync_replication("sync_replication",
+ &SV::sync_replication);
+sys_var_thd_ulong sys_sync_replication_slave_id(
+ "sync_replication_slave_id",
+ &SV::sync_replication_slave_id);
+sys_var_thd_ulong sys_sync_replication_timeout(
+ "sync_replication_timeout",
+ &SV::sync_replication_timeout);
#endif
sys_var_bool_ptr sys_sync_frm("sync_frm", &opt_sync_frm);
sys_var_long_ptr sys_table_cache_size("table_cache",
@@ -405,6 +413,7 @@ sys_var_thd_bool
sys_ndb_use_exact_count("ndb_use_exact_count", &SV::ndb_use_exact_count);
sys_var_thd_bool
sys_ndb_use_transactions("ndb_use_transactions", &SV::ndb_use_transactions);
+sys_var_long_ptr sys_ndb_cache_check_time("ndb_cache_check_time", &ndb_cache_check_time);
#endif
/* Time/date/datetime formats */
@@ -647,6 +656,9 @@ sys_var *sys_variables[]=
&sys_storage_engine,
#ifdef HAVE_REPLICATION
&sys_sync_binlog_period,
+ &sys_sync_replication,
+ &sys_sync_replication_slave_id,
+ &sys_sync_replication_timeout,
#endif
&sys_sync_frm,
&sys_table_cache_size,
@@ -677,6 +689,7 @@ sys_var *sys_variables[]=
&sys_ndb_force_send,
&sys_ndb_use_exact_count,
&sys_ndb_use_transactions,
+ &sys_ndb_cache_check_time,
#endif
&sys_unique_checks,
&sys_updatable_views_with_limit,
@@ -857,6 +870,7 @@ struct show_var_st init_vars[]= {
{sys_ndb_force_send.name, (char*) &sys_ndb_force_send, SHOW_SYS},
{sys_ndb_use_exact_count.name,(char*) &sys_ndb_use_exact_count, SHOW_SYS},
{sys_ndb_use_transactions.name,(char*) &sys_ndb_use_transactions, SHOW_SYS},
+ {sys_ndb_cache_check_time.name,(char*) &sys_ndb_cache_check_time, SHOW_SYS},
#endif
{sys_net_buffer_length.name,(char*) &sys_net_buffer_length, SHOW_SYS},
{sys_net_read_timeout.name, (char*) &sys_net_read_timeout, SHOW_SYS},
@@ -915,6 +929,9 @@ struct show_var_st init_vars[]= {
{sys_storage_engine.name, (char*) &sys_storage_engine, SHOW_SYS},
#ifdef HAVE_REPLICATION
{sys_sync_binlog_period.name,(char*) &sys_sync_binlog_period, SHOW_SYS},
+ {sys_sync_replication.name, (char*) &sys_sync_replication, SHOW_SYS},
+ {sys_sync_replication_slave_id.name, (char*) &sys_sync_replication_slave_id,SHOW_SYS},
+ {sys_sync_replication_timeout.name, (char*) &sys_sync_replication_timeout,SHOW_SYS},
#endif
{sys_sync_frm.name, (char*) &sys_sync_frm, SHOW_SYS},
#ifdef HAVE_TZNAME
@@ -1522,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;
@@ -1559,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;
@@ -1770,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;
@@ -1874,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)))
{
@@ -1908,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)))
{
@@ -2047,9 +2064,15 @@ void sys_var_character_set_server::set_default(THD *thd, enum_var_type type)
}
}
-#if defined(HAVE_REPLICATION)
+#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
bool sys_var_character_set_server::check(THD *thd, set_var *var)
{
+ /*
+ To be perfect we should fail even if we are a 5.0.3 slave, a 4.1 master,
+ and user wants to change our global character set variables. Because
+ replicating a 4.1 assumes those are not changed. But that's not easy to
+ do.
+ */
if ((var->type == OPT_GLOBAL) &&
(mysql_bin_log.is_open() ||
active_mi->slave_running || active_mi->rli.slave_running))
@@ -2154,7 +2177,7 @@ void sys_var_collation_database::set_default(THD *thd, enum_var_type type)
}
}
-#if defined(HAVE_REPLICATION)
+#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
bool sys_var_collation_server::check(THD *thd, set_var *var)
{
if ((var->type == OPT_GLOBAL) &&
@@ -2959,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()))
@@ -3098,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/set_var.h b/sql/set_var.h
index 8514b518660..3104fd38976 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -564,7 +564,7 @@ class sys_var_character_set_server :public sys_var_character_set
public:
sys_var_character_set_server(const char *name_arg) :
sys_var_character_set(name_arg) {}
-#if defined(HAVE_REPLICATION)
+#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
bool check(THD *thd, set_var *var);
#endif
void set_default(THD *thd, enum_var_type type);
@@ -602,7 +602,7 @@ class sys_var_collation_server :public sys_var_collation
{
public:
sys_var_collation_server(const char *name_arg) :sys_var_collation(name_arg) {}
-#if defined(HAVE_REPLICATION)
+#if defined(HAVE_REPLICATION) && (MYSQL_VERSION_ID < 50003)
bool check(THD *thd, set_var *var);
#endif
bool update(THD *thd, set_var *var);
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 7826be85679..030949e15d1 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5094,7 +5094,7 @@ ER_SP_BADSELECT 0A000
ER_SP_BADRETURN 42000
eng "RETURN is only allowed in a FUNCTION"
ER_SP_BADSTATEMENT 0A000
- eng "Statements like SELECT, INSERT, UPDATE (and others) are not allowed in a FUNCTION"
+ eng "LOCK and UNLOCK tables are not allowed in stored procedures"
ER_UPDATE_LOG_DEPRECATED_IGNORED 42000
eng "The update log is deprecated and replaced by the binary log; SET SQL_LOG_UPDATE has been ignored"
ER_UPDATE_LOG_DEPRECATED_TRANSLATED 42000
diff --git a/sql/slave.cc b/sql/slave.cc
index 0c5ebe0744a..f3ab4b21832 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -660,13 +660,14 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
pthread_cond_t* term_cond,
volatile uint *slave_running)
{
+ DBUG_ENTER("terminate_slave_thread");
if (term_lock)
{
pthread_mutex_lock(term_lock);
if (!*slave_running)
{
pthread_mutex_unlock(term_lock);
- return ER_SLAVE_NOT_RUNNING;
+ DBUG_RETURN(ER_SLAVE_NOT_RUNNING);
}
}
DBUG_ASSERT(thd != 0);
@@ -678,6 +679,7 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
while (*slave_running) // Should always be true
{
+ DBUG_PRINT("loop", ("killing slave thread"));
KICK_SLAVE(thd);
/*
There is a small chance that slave thread might miss the first
@@ -689,7 +691,7 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
}
if (term_lock)
pthread_mutex_unlock(term_lock);
- return 0;
+ DBUG_RETURN(0);
}
@@ -1418,13 +1420,20 @@ not always make sense; please check the manual before using it).";
values of these 2 are never used (new connections don't use them).
We don't test equality of global collation_database either as it's is
going to be deprecated (made read-only) in 4.1 very soon.
- We don't do it for <3.23.57 because masters <3.23.50 hang on
- SELECT @@unknown_var (BUG#7965 - see changelog of 3.23.50).
+ The test is only relevant if master < 5.0.3 (we'll test only if it's older
+ than the 5 branch; < 5.0.3 was alpha...), as >= 5.0.3 master stores
+ charset info in each binlog event.
+ We don't do it for 3.23 because masters <3.23.50 hang on
+ SELECT @@unknown_var (BUG#7965 - see changelog of 3.23.50). So finally we
+ test only if master is 4.x.
*/
- if (strncmp(mi->rli.relay_log.description_event_for_queue->server_version,
- "3.23.57",7) < 0)
+
+ /* redundant with rest of code but safer against later additions */
+ if (*mysql->server_version == '3')
goto err;
- if (!mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) &&
+
+ if ((*mysql->server_version == '4') &&
+ !mysql_real_query(mysql, "SELECT @@GLOBAL.COLLATION_SERVER", 32) &&
(master_res= mysql_store_result(mysql)))
{
if ((master_row= mysql_fetch_row(master_res)) &&
@@ -1447,8 +1456,12 @@ be equal for replication to work";
such check will broke everything for them. (And now everything will
work for them because by default both their master and slave will have
'SYSTEM' time zone).
+
+ TODO: when the new replication of timezones is sorted out with Dmitri,
+ change >= '4' to == '4'.
*/
- if (!mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) &&
+ if ((*mysql->server_version >= '4') &&
+ !mysql_real_query(mysql, "SELECT @@GLOBAL.TIME_ZONE", 25) &&
(master_res= mysql_store_result(mysql)))
{
if ((master_row= mysql_fetch_row(master_res)) &&
@@ -2527,6 +2540,7 @@ st_relay_log_info::st_relay_log_info()
bzero((char*) &info_file, sizeof(info_file));
bzero((char*) &cache_buf, sizeof(cache_buf));
+ cached_charset_invalidate();
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST);
@@ -2755,6 +2769,7 @@ void set_slave_thread_options(THD* thd)
{
thd->options = ((opt_log_slave_updates) ? OPTION_BIN_LOG:0) |
OPTION_AUTO_IS_NULL;
+ thd->variables.completion_type= 0;
}
/*
@@ -3078,6 +3093,24 @@ bool st_relay_log_info::is_until_satisfied()
}
+void st_relay_log_info::cached_charset_invalidate()
+{
+ /* Full of zeroes means uninitialized. */
+ bzero(cached_charset, sizeof(cached_charset));
+}
+
+
+bool st_relay_log_info::cached_charset_compare(char *charset)
+{
+ if (bcmp(cached_charset, charset, sizeof(cached_charset)))
+ {
+ memcpy(cached_charset, charset, sizeof(cached_charset));
+ return 1;
+ }
+ return 0;
+}
+
+
static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
{
/*
@@ -3722,6 +3755,8 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions"));
pthread_cond_broadcast(&rli->data_cond);
rli->ignore_log_space_limit= 0; /* don't need any lock */
+ /* we die so won't remember charset - re-update them on next thread start */
+ rli->cached_charset_invalidate();
rli->save_temporary_tables = thd->temporary_tables;
/*
diff --git a/sql/slave.h b/sql/slave.h
index e0816fd45a7..598ff0a7845 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -291,6 +291,8 @@ typedef struct st_relay_log_info
UNTIL_LOG_NAMES_CMP_UNKNOWN= -2, UNTIL_LOG_NAMES_CMP_LESS= -1,
UNTIL_LOG_NAMES_CMP_EQUAL= 0, UNTIL_LOG_NAMES_CMP_GREATER= 1
} until_log_names_cmp_result;
+
+ char cached_charset[6];
st_relay_log_info();
~st_relay_log_info();
@@ -334,6 +336,14 @@ typedef struct st_relay_log_info
return ((until_condition == UNTIL_MASTER_POS) ? group_master_log_pos :
group_relay_log_pos);
}
+ /*
+ Last charset (6 bytes) seen by slave SQL thread is cached here; it helps
+ the thread save 3 get_charset() per Query_log_event if the charset is not
+ changing from event to event (common situation).
+ When the 6 bytes are equal to 0 is used to mean "cache is invalidated".
+ */
+ void cached_charset_invalidate();
+ bool cached_charset_compare(char *charset);
} RELAY_LOG_INFO;
diff --git a/sql/sp.cc b/sql/sp.cc
index 84b126e5ecd..46b08c3e847 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -854,13 +854,14 @@ sp_show_status_procedure(THD *thd, const char *wild)
******************************************************************************/
sp_head *
-sp_find_function(THD *thd, sp_name *name)
+sp_find_function(THD *thd, sp_name *name, bool cache_only)
{
sp_head *sp;
DBUG_ENTER("sp_find_function");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
- if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name)))
+ if (!(sp= sp_cache_lookup(&thd->sp_func_cache, name)) &&
+ !cache_only)
{
if (db_find_routine(thd, TYPE_ENUM_FUNCTION, name, &sp) != SP_OK)
sp= NULL;
@@ -963,7 +964,7 @@ sp_function_exists(THD *thd, sp_name *name)
byte *
-sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first)
+sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first)
{
LEX_STRING *lsp= (LEX_STRING *)ptr;
*plen= lsp->length;
@@ -972,37 +973,36 @@ sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first)
void
-sp_add_fun_to_lex(LEX *lex, sp_name *fun)
+sp_add_to_hash(HASH *h, sp_name *fun)
{
- if (! hash_search(&lex->spfuns,
- (byte *)fun->m_qname.str, fun->m_qname.length))
+ if (! hash_search(h, (byte *)fun->m_qname.str, fun->m_qname.length))
{
LEX_STRING *ls= (LEX_STRING *)sql_alloc(sizeof(LEX_STRING));
ls->str= sql_strmake(fun->m_qname.str, fun->m_qname.length);
ls->length= fun->m_qname.length;
- my_hash_insert(&lex->spfuns, (byte *)ls);
+ my_hash_insert(h, (byte *)ls);
}
}
void
-sp_merge_funs(LEX *dst, LEX *src)
+sp_merge_hash(HASH *dst, HASH *src)
{
- for (uint i=0 ; i < src->spfuns.records ; i++)
+ for (uint i=0 ; i < src->records ; i++)
{
- LEX_STRING *ls= (LEX_STRING *)hash_element(&src->spfuns, i);
+ LEX_STRING *ls= (LEX_STRING *)hash_element(src, i);
- if (! hash_search(&dst->spfuns, (byte *)ls->str, ls->length))
- my_hash_insert(&dst->spfuns, (byte *)ls);
+ if (! hash_search(dst, (byte *)ls->str, ls->length))
+ my_hash_insert(dst, (byte *)ls);
}
}
int
-sp_cache_functions(THD *thd, LEX *lex)
+sp_cache_routines(THD *thd, LEX *lex, int type)
{
- HASH *h= &lex->spfuns;
+ HASH *h= (type == TYPE_ENUM_FUNCTION ? &lex->spfuns : &lex->spprocs);
int ret= 0;
for (uint i=0 ; i < h->records ; i++)
@@ -1011,7 +1011,9 @@ sp_cache_functions(THD *thd, LEX *lex)
sp_name name(*ls);
name.m_qname= *ls;
- if (! sp_cache_lookup(&thd->sp_func_cache, &name))
+ if (! sp_cache_lookup((type == TYPE_ENUM_FUNCTION ?
+ &thd->sp_func_cache : &thd->sp_proc_cache),
+ &name))
{
sp_head *sp;
LEX *oldlex= thd->lex;
@@ -1027,11 +1029,23 @@ sp_cache_functions(THD *thd, LEX *lex)
name.m_name.str+= 1;
name.m_name.length= name.m_qname.length - name.m_db.length - 1;
- if (db_find_routine(thd, TYPE_ENUM_FUNCTION, &name, &sp)
- == SP_OK)
+ if (db_find_routine(thd, type, &name, &sp) == SP_OK)
{
- sp_cache_insert(&thd->sp_func_cache, sp);
- ret= sp_cache_functions(thd, newlex);
+ if (type == TYPE_ENUM_FUNCTION)
+ sp_cache_insert(&thd->sp_func_cache, sp);
+ else
+ sp_cache_insert(&thd->sp_proc_cache, sp);
+ ret= sp_cache_routines(thd, newlex, TYPE_ENUM_FUNCTION);
+ if (!ret)
+ {
+ sp_merge_hash(&lex->spfuns, &newlex->spfuns);
+ ret= sp_cache_routines(thd, newlex, TYPE_ENUM_PROCEDURE);
+ }
+ if (!ret)
+ {
+ sp_merge_hash(&lex->spprocs, &newlex->spprocs);
+ sp_merge_table_hash(&lex->sptabs, &sp->m_sptabs);
+ }
delete newlex;
thd->lex= oldlex;
if (ret)
@@ -1041,9 +1055,6 @@ sp_cache_functions(THD *thd, LEX *lex)
{
delete newlex;
thd->lex= oldlex;
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", ls->str);
- ret= 1;
- break;
}
}
}
diff --git a/sql/sp.h b/sql/sp.h
index 152c59d0d02..6290324bb86 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -56,7 +56,7 @@ int
sp_show_status_procedure(THD *thd, const char *wild);
sp_head *
-sp_find_function(THD *thd, sp_name *name);
+sp_find_function(THD *thd, sp_name *name, bool cache_only = 0);
int
sp_create_function(THD *thd, sp_head *sp);
@@ -77,14 +77,15 @@ bool
sp_function_exists(THD *thd, sp_name *name);
-// This is needed since we have to read the functions before we
-// do anything else.
+/*
+ * For precaching of functions and procedures
+ */
void
-sp_add_fun_to_lex(LEX *lex, sp_name *fun);
+sp_add_to_hash(HASH *h, sp_name *fun);
void
-sp_merge_funs(LEX *dst, LEX *src);
+sp_merge_hash(HASH *dst, HASH *src);
int
-sp_cache_functions(THD *thd, LEX *lex);
+sp_cache_routines(THD *thd, LEX *lex, int type);
//
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 3f2969768c5..075aef9d286 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -23,6 +23,7 @@
#include "sp.h"
#include "sp_pcontext.h"
#include "sp_rcontext.h"
+#include "sp_cache.h"
Item_result
sp_map_result_type(enum enum_field_types type)
@@ -36,6 +37,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 +130,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 +150,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 +242,9 @@ sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type)
}
break;
}
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(0);
}
}
@@ -259,11 +332,14 @@ sp_head::sp_head()
:Item_arena((bool)FALSE), m_returns_cs(NULL), m_has_return(FALSE),
m_simple_case(FALSE), m_multi_results(FALSE), m_in_handler(FALSE)
{
+ extern byte *
+ sp_table_key(const byte *ptr, uint *plen, my_bool first);
DBUG_ENTER("sp_head::sp_head");
state= INITIALIZED;
m_backpatch.empty();
m_lex.empty();
+ hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
DBUG_VOID_RETURN;
}
@@ -424,10 +500,10 @@ sp_head::~sp_head()
void
sp_head::destroy()
{
- DBUG_ENTER("sp_head::destroy");
- DBUG_PRINT("info", ("name: %s", m_name.str));
sp_instr *i;
LEX *lex;
+ DBUG_ENTER("sp_head::destroy");
+ DBUG_PRINT("info", ("name: %s", m_name.str));
for (uint ip = 0 ; (i = get_instr(ip)) ; ip++)
delete i;
@@ -439,6 +515,8 @@ sp_head::destroy()
if (lex != &m_thd->main_lex) // We got interrupted and have lex'es left
delete lex;
}
+ if (m_sptabs.array.buffer)
+ hash_free(&m_sptabs);
DBUG_VOID_RETURN;
}
@@ -732,6 +810,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();
@@ -799,48 +881,10 @@ sp_head::restore_lex(THD *thd)
oldlex->trg_table_fields.push_back(&sublex->trg_table_fields);
// Collect some data from the sub statement lex.
- sp_merge_funs(oldlex, sublex);
-#ifdef NOT_USED_NOW
- // QQ We're not using this at the moment.
- if (sublex.sql_command == SQLCOM_CALL)
- {
- // It would be slightly faster to keep the list sorted, but we need
- // an "insert before" method to do that.
- char *proc= sublex.udf.name.str;
-
- List_iterator_fast<char *> li(m_calls);
- char **it;
-
- while ((it= li++))
- if (my_strcasecmp(system_charset_info, proc, *it) == 0)
- break;
- if (! it)
- m_calls.push_back(&proc);
-
- }
+ sp_merge_hash(&oldlex->spfuns, &sublex->spfuns);
+ sp_merge_hash(&oldlex->spprocs, &sublex->spprocs);
// Merge used tables
- // QQ ...or just open tables in thd->open_tables?
- // This is not entirerly clear at the moment, but for now, we collect
- // tables here.
- for (sl= sublex.all_selects_list ;
- sl ;
- sl= sl->next_select())
- {
- for (TABLE_LIST *tables= sl->get_table_list() ;
- tables ;
- tables= tables->next)
- {
- List_iterator_fast<char *> li(m_tables);
- char **tb;
-
- while ((tb= li++))
- if (my_strcasecmp(system_charset_info, tables->table_name, *tb) == 0)
- break;
- if (! tb)
- m_tables.push_back(&tables->table_name);
- }
- }
-#endif
+ sp_merge_table_list(thd, &m_sptabs, sublex->query_tables, sublex);
if (! sublex->sp_lex_in_use)
delete sublex;
thd->lex= oldlex;
@@ -1864,3 +1908,242 @@ sp_restore_security_context(THD *thd, sp_head *sp, st_sp_security_context *ctxp)
}
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+
+/*
+ * Table merge hash table
+ *
+ */
+typedef struct st_sp_table
+{
+ LEX_STRING qname;
+ bool temp;
+ TABLE_LIST *table;
+} SP_TABLE;
+
+byte *
+sp_table_key(const byte *ptr, uint *plen, my_bool first)
+{
+ SP_TABLE *tab= (SP_TABLE *)ptr;
+ *plen= tab->qname.length;
+ return (byte *)tab->qname.str;
+}
+
+/*
+ * Merge the table list into the hash table.
+ * If the optional lex is provided, it's used to check and set
+ * the flag for creation of a temporary table.
+ */
+bool
+sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table,
+ LEX *lex_for_tmp_check)
+{
+ for (; table ; table= table->next_global)
+ if (!table->derived &&
+ (!table->select_lex ||
+ !(table->select_lex->options & OPTION_SCHEMA_TABLE)))
+ {
+ char tname[64+1+64+1+64+1]; // db.table.alias\0
+ uint tlen, alen;
+ SP_TABLE *tab;
+
+ tlen= table->db_length;
+ memcpy(tname, table->db, tlen);
+ tname[tlen++]= '.';
+ memcpy(tname+tlen, table->table_name, table->table_name_length);
+ tlen+= table->table_name_length;
+ tname[tlen++]= '.';
+ alen= strlen(table->alias);
+ memcpy(tname+tlen, table->alias, alen);
+ tlen+= alen;
+ tname[tlen]= '\0';
+
+ if ((tab= (SP_TABLE *)hash_search(h, (byte *)tname, tlen)))
+ {
+ if (tab->table->lock_type < table->lock_type)
+ tab->table= table; // Use the table with the highest lock type
+ }
+ else
+ {
+ if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE))))
+ return FALSE;
+ tab->qname.length= tlen;
+ tab->qname.str= (char *)thd->strmake(tname, tab->qname.length);
+ if (!tab->qname.str)
+ return FALSE;
+ if (lex_for_tmp_check &&
+ lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE &&
+ lex_for_tmp_check->query_tables == table &&
+ lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE)
+ tab->temp= TRUE;
+ tab->table= table;
+ my_hash_insert(h, (byte *)tab);
+ }
+ }
+ return TRUE;
+}
+
+void
+sp_merge_routine_tables(THD *thd, LEX *lex)
+{
+ uint i;
+
+ for (i= 0 ; i < lex->spfuns.records ; i++)
+ {
+ sp_head *sp;
+ LEX_STRING *ls= (LEX_STRING *)hash_element(&lex->spfuns, i);
+ sp_name name(*ls);
+
+ name.m_qname= *ls;
+ if ((sp= sp_cache_lookup(&thd->sp_func_cache, &name)))
+ sp_merge_table_hash(&lex->sptabs, &sp->m_sptabs);
+ }
+ for (i= 0 ; i < lex->spprocs.records ; i++)
+ {
+ sp_head *sp;
+ LEX_STRING *ls= (LEX_STRING *)hash_element(&lex->spprocs, i);
+ sp_name name(*ls);
+
+ name.m_qname= *ls;
+ if ((sp= sp_cache_lookup(&thd->sp_proc_cache, &name)))
+ sp_merge_table_hash(&lex->sptabs, &sp->m_sptabs);
+ }
+}
+
+void
+sp_merge_table_hash(HASH *hdst, HASH *hsrc)
+{
+ for (uint i=0 ; i < hsrc->records ; i++)
+ {
+ SP_TABLE *tabdst;
+ SP_TABLE *tabsrc= (SP_TABLE *)hash_element(hsrc, i);
+
+ if (! (tabdst= (SP_TABLE *)hash_search(hdst,
+ tabsrc->qname.str,
+ tabsrc->qname.length)))
+ {
+ my_hash_insert(hdst, (byte *)tabsrc);
+ }
+ else
+ {
+ if (tabdst->table->lock_type < tabsrc->table->lock_type)
+ tabdst->table= tabsrc->table; // Use the highest lock type
+ }
+ }
+}
+
+TABLE_LIST *
+sp_hash_to_table_list(THD *thd, HASH *h)
+{
+ uint i;
+ TABLE_LIST *tables= NULL;
+ DBUG_ENTER("sp_hash_to_table_list");
+
+ for (i=0 ; i < h->records ; i++)
+ {
+ SP_TABLE *stab= (SP_TABLE *)hash_element(h, i);
+ if (stab->temp)
+ continue;
+ TABLE_LIST *table, *otable= stab->table;
+
+ if (! (table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST))))
+ return NULL;
+ table->db= otable->db;
+ table->db_length= otable->db_length;
+ table->alias= otable->alias;
+ table->table_name= otable->table_name;
+ table->table_name_length= otable->table_name_length;
+ table->lock_type= otable->lock_type;
+ table->updating= otable->updating;
+ table->force_index= otable->force_index;
+ table->ignore_leaves= otable->ignore_leaves;
+ table->derived= otable->derived;
+ table->schema_table= otable->schema_table;
+ table->select_lex= otable->select_lex;
+ table->cacheable_table= otable->cacheable_table;
+ table->use_index= otable->use_index;
+ table->ignore_index= otable->ignore_index;
+ table->option= otable->option;
+
+ table->next_global= tables;
+ tables= table;
+ }
+ DBUG_RETURN(tables);
+}
+
+bool
+sp_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
+{
+ DBUG_ENTER("sp_open_and_lock_tables");
+ bool ret;
+
+ thd->in_lock_tables= 1;
+ thd->options|= OPTION_TABLE_LOCK;
+ if (simple_open_n_lock_tables(thd, tables))
+ {
+ thd->options&= ~(ulong)(OPTION_TABLE_LOCK);
+ ret= FALSE;
+ }
+ else
+ {
+#if 0
+ // QQ What about this?
+#ifdef HAVE_QUERY_CACHE
+ if (thd->variables.query_cache_wlock_invalidate)
+ query_cache.invalidate_locked_for_write(first_table); // QQ first_table?
+#endif /* HAVE_QUERY_CACHE */
+#endif
+ thd->locked_tables= thd->lock;
+ thd->lock= 0;
+ ret= TRUE;
+ }
+ thd->in_lock_tables= 0;
+ DBUG_RETURN(ret);
+}
+
+void
+sp_unlock_tables(THD *thd)
+{
+ thd->lock= thd->locked_tables;
+ thd->locked_tables= 0;
+ close_thread_tables(thd); // Free tables
+ if (thd->options & OPTION_TABLE_LOCK)
+ {
+#if 0
+ // QQ What about this?
+ end_active_trans(thd);
+#endif
+ thd->options&= ~(ulong)(OPTION_TABLE_LOCK);
+ }
+ if (thd->global_read_lock)
+ unlock_global_read_lock(thd);
+}
+
+/*
+ * Simple function for adding an explicetly named (systems) table to
+ * the global table list, e.g. "mysql", "proc".
+ *
+ */
+TABLE_LIST *
+sp_add_to_query_tables(THD *thd, LEX *lex,
+ const char *db, const char *name,
+ thr_lock_type locktype)
+{
+ TABLE_LIST *table;
+
+ if (!(table= (TABLE_LIST *)thd->calloc(sizeof(TABLE_LIST))))
+ {
+ my_error(ER_OUTOFMEMORY, MYF(0), sizeof(TABLE_LIST));
+ return NULL;
+ }
+ table->db_length= strlen(db);
+ table->db= thd->strmake(db, table->db_length);
+ table->table_name_length= strlen(name);
+ table->table_name= thd->strmake(name, table->table_name_length);
+ table->alias= thd->strdup(name);
+ table->lock_type= locktype;
+ table->select_lex= lex->current_select; // QQ?
+ table->cacheable_table= 1;
+
+ lex->add_to_query_tables(table);
+ return table;
+}
diff --git a/sql/sp_head.h b/sql/sp_head.h
index c4d2068661c..5df9c753048 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -92,11 +92,6 @@ public:
uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value
st_sp_chistics *m_chistics;
ulong m_sql_mode; // For SHOW CREATE
-#if NOT_USED_NOW
- // QQ We're not using this at the moment.
- List<char *> m_calls; // Called procedures.
- List<char *> m_tables; // Used tables.
-#endif
LEX_STRING m_qname; // db.name
LEX_STRING m_db;
LEX_STRING m_name;
@@ -108,6 +103,7 @@ public:
LEX_STRING m_definer_host;
longlong m_created;
longlong m_modified;
+ HASH m_sptabs; /* Merged table lists */
// Pointers set during parsing
uchar *m_param_begin, *m_param_end, *m_returns_begin, *m_returns_end,
*m_body_begin;
@@ -897,4 +893,22 @@ void
sp_restore_security_context(THD *thd, sp_head *sp,st_sp_security_context *ctxp);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
+bool
+sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table,
+ LEX *lex_for_tmp_check = 0);
+void
+sp_merge_routine_tables(THD *thd, LEX *lex);
+void
+sp_merge_table_hash(HASH *hdst, HASH *hsrc);
+TABLE_LIST *
+sp_hash_to_table_list(THD *thd, HASH *h);
+bool
+sp_open_and_lock_tables(THD *thd, TABLE_LIST *tables);
+void
+sp_unlock_tables(THD *thd);
+TABLE_LIST *
+sp_add_to_query_tables(THD *thd, LEX *lex,
+ const char *db, const char *name,
+ thr_lock_type locktype);
+
#endif /* _SP_HEAD_H_ */
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 3f97cab1511..c2eea524cac 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -59,8 +59,11 @@ int compare_ulonglong2(void* cmp_arg __attribute__((unused)),
return compare_ulonglong(s,t);
}
-bool append_escaped(String *to_str, String *from_str);
-bool append_escaped(String *to_str, char *from, uint from_len);
+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,
@@ -142,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);
}
@@ -263,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);
@@ -451,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];
@@ -888,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)
@@ -922,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)
@@ -1023,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;
@@ -1087,38 +1252,3 @@ bool append_escaped(String *to_str, String *from_str)
}
return 0;
}
-
-bool append_escaped(String *to_str, char *from, uint from_len)
-{
- char *end, c;
-
- if (to_str->realloc(to_str->length() + from_len))
- return 1;
-
- end= from + from_len;
-
- for (; from < end; from++)
- {
- c= *from;
- switch (c) {
- case '\0':
- c= '0';
- break;
- case '\032':
- c= 'Z';
- break;
- case '\\':
- case '\'':
- break;
- default:
- goto normal_character;
- }
- if (to_str->append('\\'))
- return 1;
-
- normal_character:
- if (to_str->append(c))
- return 1;
- }
- return 0;
-}
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 0b78f9a4dfb..eef86921012 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -496,58 +496,58 @@ void close_temporary(TABLE *table,bool delete_table)
void close_temporary_tables(THD *thd)
{
TABLE *table,*next;
- char *query, *end;
- uint query_buf_size;
- bool found_user_tables = 0;
+ char *query, *name_in_query, *end;
+ uint greatest_key_length= 0;
if (!thd->temporary_tables)
return;
+ /*
+ We write a DROP TEMPORARY TABLE for each temp table left, so that our
+ replication slave can clean them up. Not one multi-table DROP TABLE binlog
+ event: this would cause problems if slave uses --replicate-*-table.
+ */
LINT_INIT(end);
- query_buf_size= 50; // Enough for DROP ... TABLE IF EXISTS
+ /* We'll re-use always same buffer so make it big enough for longest name */
for (table=thd->temporary_tables ; table ; table=table->next)
- /*
- We are going to add 4 ` around the db/table names, so 1 does not look
- enough; indeed it is enough, because table->key_length is greater (by 8,
- because of server_id and thread_id) than db||table.
- */
- query_buf_size+= table->s->key_length+1;
+ greatest_key_length= max(greatest_key_length, table->s->key_length);
- if ((query = alloc_root(thd->mem_root, query_buf_size)))
+ if ((query = alloc_root(thd->mem_root, greatest_key_length+50)))
// Better add "if exists", in case a RESET MASTER has been done
- end=strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS ");
+ name_in_query= strmov(query, "DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `");
for (table=thd->temporary_tables ; table ; table=next)
{
- if (query) // we might be out of memory, but this is not fatal
+ /*
+ In we are OOM for 'query' this is not fatal. We skip temporary tables
+ not created directly by the user.
+ */
+ if (query && mysql_bin_log.is_open() && (table->s->table_name[0] != '#'))
{
- // skip temporary tables not created directly by the user
- if (table->s->table_name[0] != '#')
- found_user_tables = 1;
- end = strxmov(end,"`",table->s->db,"`.`",
- table->s->table_name,"`,", NullS);
+ /*
+ Here we assume table_cache_key always starts
+ with \0 terminated db name
+ */
+ end = strxmov(name_in_query, table->s->db, "`.`",
+ table->s->table_name, "`", NullS);
+ Query_log_event qinfo(thd, query, (ulong)(end-query), 0, FALSE);
+ /*
+ Imagine the thread had created a temp table, then was doing a SELECT, and
+ the SELECT was killed. Then it's not clever to mark the statement above as
+ "killed", because it's not really a statement updating data, and there
+ are 99.99% chances it will succeed on slave. And, if thread is
+ killed now, it's not clever either.
+ If a real update (one updating a persistent table) was killed on the
+ master, then this real update will be logged with error_code=killed,
+ rightfully causing the slave to stop.
+ */
+ qinfo.error_code= 0;
+ mysql_bin_log.write(&qinfo);
}
next=table->next;
close_temporary(table);
}
- if (query && found_user_tables && mysql_bin_log.is_open())
- {
- /* The -1 is to remove last ',' */
- thd->clear_error();
- Query_log_event qinfo(thd, query, (ulong)(end-query)-1, 0, FALSE);
- /*
- Imagine the thread had created a temp table, then was doing a SELECT, and
- the SELECT was killed. Then it's not clever to mark the statement above as
- "killed", because it's not really a statement updating data, and there
- are 99.99% chances it will succeed on slave.
- If a real update (one updating a persistent table) was killed on the
- master, then this real update will be logged with error_code=killed,
- rightfully causing the slave to stop.
- */
- qinfo.error_code= 0;
- mysql_bin_log.write(&qinfo);
- }
thd->temporary_tables=0;
}
@@ -853,7 +853,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
table->tablenr=thd->current_tablenr++;
table->used_fields=0;
table->const_table=0;
- table->outer_join= table->null_row= table->maybe_null= table->force_index= 0;
+ table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
table->keys_in_use_for_query= share->keys_in_use;
table->used_keys= share->keys_for_keyread;
@@ -918,10 +918,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
{
if (table->s->key_length == key_length &&
!memcmp(table->s->table_cache_key,key,key_length) &&
- !my_strcasecmp(system_charset_info, table->alias, alias) &&
- table->query_id != thd->query_id)
+ !my_strcasecmp(system_charset_info, table->alias, alias))
{
- table->query_id=thd->query_id;
+ if (table->query_id != thd->query_id)
+ table->query_id=thd->query_id;
DBUG_PRINT("info",("Using locked table"));
goto reset;
}
@@ -1077,7 +1077,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
table->tablenr=thd->current_tablenr++;
table->used_fields=0;
table->const_table=0;
- table->outer_join= table->null_row= table->maybe_null= table->force_index= 0;
+ table->null_row= table->maybe_null= table->force_index= 0;
table->status=STATUS_NO_RECORD;
table->keys_in_use_for_query= table->s->keys_in_use;
table->insert_values= 0;
@@ -1149,7 +1149,6 @@ bool reopen_table(TABLE *table,bool locked)
tmp.tablenr= table->tablenr;
tmp.used_fields= table->used_fields;
tmp.const_table= table->const_table;
- tmp.outer_join= table->outer_join;
tmp.null_row= table->null_row;
tmp.maybe_null= table->maybe_null;
tmp.status= table->status;
@@ -2119,13 +2118,31 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
table_list->alias, name, item_name, (ulong) ref));
if (table_list->field_translation)
{
- DBUG_ASSERT(ref != 0 && table_list->view != 0);
- uint num= table_list->view->select_lex.item_list.elements;
+ uint num;
+ if (table_list->schema_table_reformed)
+ {
+ num= thd->lex->current_select->item_list.elements;
+ }
+ else
+ {
+ DBUG_ASSERT(ref != 0 && table_list->view != 0);
+ num= table_list->view->select_lex.item_list.elements;
+ }
Field_translator *trans= table_list->field_translation;
for (uint i= 0; i < num; i ++)
{
if (!my_strcasecmp(system_charset_info, trans[i].name, name))
{
+ if (table_list->schema_table_reformed)
+ {
+ /*
+ Translation table items are always Item_fields
+ and fixed already('mysql_schema_table' function).
+ So we can return ->field. It is used only for
+ 'show & where' commands.
+ */
+ DBUG_RETURN(((Item_field*) (trans[i].item))->field);
+ }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_grants_view &&
check_grant_column(thd, &table_list->grant,
@@ -2151,6 +2168,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);
}
@@ -2757,6 +2776,20 @@ bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
thd->allow_sum_func= allow_sum_func;
thd->where="field list";
+ /*
+ To prevent fail on forward lookup we fill it with zerows,
+ then if we got pointer on zero after find_item_in_list we will know
+ that it is forward lookup.
+
+ There is other way to solve problem: fill array with pointers to list,
+ but it will be slower.
+
+ TODO: remove it when (if) we made one list for allfields and
+ ref_pointer_array
+ */
+ if (ref_pointer_array)
+ bzero(ref_pointer_array, sizeof(Item *) * fields.elements);
+
Item **ref= ref_pointer_array;
while ((item= it++))
{
@@ -3357,7 +3390,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);
@@ -3366,7 +3400,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;
}
}
@@ -3378,8 +3413,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_cache.cc b/sql/sql_cache.cc
index d63877dc755..e38e417e6df 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -914,12 +914,12 @@ end:
int
Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
{
+ ulonglong engine_data;
Query_cache_query *query;
Query_cache_block *first_result_block, *result_block;
Query_cache_block_table *block_table, *block_table_end;
ulong tot_length;
Query_cache_query_flags flags;
- bool check_tables;
DBUG_ENTER("Query_cache::send_result_to_client");
if (query_cache_size == 0 || thd->variables.query_cache_type == 0)
@@ -1027,7 +1027,6 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
goto err_unlock;
}
- check_tables= query->tables_type() & HA_CACHE_TBL_ASKTRANSACT;
// Check access;
block_table= query_block->table(0);
block_table_end= block_table+query_block->n_tables;
@@ -1088,19 +1087,30 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
goto err_unlock; // Parse query
}
#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
- if (check_tables && !ha_caching_allowed(thd, table->db(),
- table->key_length(),
- table->type()))
+ engine_data= table->engine_data();
+ if (table->callback() &&
+ !(*table->callback())(thd, table->db(),
+ table->key_length(),
+ &engine_data))
{
DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
table_list.db, table_list.alias));
BLOCK_UNLOCK_RD(query_block);
- thd->lex->safe_to_cache_query= 0; // Don't try to cache this
+ if (engine_data != table->engine_data())
+ {
+ DBUG_PRINT("qcache",
+ ("Handler require invalidation queries of %s.%s %lld-%lld",
+ table_list.db, table_list.alias,
+ engine_data, table->engine_data()));
+ invalidate_table(table->db(), table->key_length());
+ }
+ else
+ thd->lex->safe_to_cache_query= 0; // Don't try to cache this
goto err_unlock; // Parse query
}
else
- DBUG_PRINT("qcache", ("handler allow caching (%d) %s,%s",
- check_tables, table_list.db, table_list.alias));
+ DBUG_PRINT("qcache", ("handler allow caching %s,%s",
+ table_list.db, table_list.alias));
}
move_to_query_list_end(query_block);
hits++;
@@ -2128,7 +2138,9 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block,
if (!insert_table(tables_used->table->s->key_length,
tables_used->table->s->table_cache_key, block_table,
tables_used->db_length,
- tables_used->table->file->table_cache_type()))
+ tables_used->table->file->table_cache_type(),
+ tables_used->callback_func,
+ tables_used->engine_data))
break;
if (tables_used->table->s->db_type == DB_TYPE_MRG_MYISAM)
@@ -2144,9 +2156,13 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block,
uint key_length= filename_2_table_key(key, table->table->filename,
&db_length);
(++block_table)->n= ++n;
+ /*
+ There are not callback function for for MyISAM, and engine data
+ */
if (!insert_table(key_length, key, block_table,
db_length,
- tables_used->table->file->table_cache_type()))
+ tables_used->table->file->table_cache_type(),
+ 0, 0))
goto err;
}
}
@@ -2173,7 +2189,9 @@ err:
my_bool
Query_cache::insert_table(uint key_len, char *key,
Query_cache_block_table *node,
- uint32 db_length, uint8 cache_type)
+ uint32 db_length, uint8 cache_type,
+ qc_engine_callback callback,
+ ulonglong engine_data)
{
DBUG_ENTER("Query_cache::insert_table");
DBUG_PRINT("qcache", ("insert table node 0x%lx, len %d",
@@ -2183,6 +2201,23 @@ Query_cache::insert_table(uint key_len, char *key,
hash_search(&tables, (byte*) key,
key_len));
+ if (table_block &&
+ table_block->table()->engine_data() != engine_data)
+ {
+ DBUG_PRINT("qcache",
+ ("Handler require invalidation queries of %s.%s %lld-%lld",
+ table_block->table()->db(),
+ table_block->table()->table(),
+ engine_data,
+ table_block->table()->engine_data()));
+ /*
+ as far as we delete all queries with this table, table block will be
+ deleted, too
+ */
+ invalidate_table(table_block);
+ table_block= 0;
+ }
+
if (table_block == 0)
{
DBUG_PRINT("qcache", ("new table block from 0x%lx (%u)",
@@ -2213,6 +2248,8 @@ Query_cache::insert_table(uint key_len, char *key,
header->table(db + db_length + 1);
header->key_length(key_len);
header->type(cache_type);
+ header->callback(callback);
+ header->engine_data(engine_data);
}
Query_cache_block_table *list_root = table_block->table(0);
@@ -2733,9 +2770,11 @@ my_bool Query_cache::ask_handler_allowance(THD *thd,
for (; tables_used; tables_used= tables_used->next_global)
{
TABLE *table= tables_used->table;
- if (!ha_caching_allowed(thd, table->s->table_cache_key,
- table->s->key_length,
- table->file->table_cache_type()))
+ handler *handler= table->file;
+ if (!handler->register_query_cache_table(thd, table->s->table_cache_key,
+ table->s->key_length,
+ &tables_used->callback_func,
+ &tables_used->engine_data))
{
DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
tables_used->db, tables_used->alias));
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index 93d89aeae4f..e7116c7718a 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -146,6 +146,10 @@ struct Query_cache_table
char *tbl;
uint32 key_len;
uint8 table_type;
+ /* unique for every engine reference */
+ qc_engine_callback callback_func;
+ /* data need by some engines */
+ ulonglong engine_data_buff;
inline char *db() { return (char *) data(); }
inline char *table() { return tbl; }
@@ -154,6 +158,10 @@ struct Query_cache_table
inline void key_length(uint32 len) { key_len= len; }
inline uint8 type() { return table_type; }
inline void type(uint8 t) { table_type= t; }
+ inline qc_engine_callback callback() { return callback_func; }
+ inline void callback(qc_engine_callback fn){ callback_func= fn; }
+ inline ulonglong engine_data() { return engine_data_buff; }
+ inline void engine_data(ulonglong data) { engine_data_buff= data; }
inline gptr data()
{
return (gptr)(((byte*)this)+
@@ -282,7 +290,9 @@ protected:
TABLE_COUNTER_TYPE tables);
my_bool insert_table(uint key_len, char *key,
Query_cache_block_table *node,
- uint32 db_length, uint8 cache_type);
+ uint32 db_length, uint8 cache_type,
+ qc_engine_callback callback,
+ ulonglong engine_data);
void unlink_table(Query_cache_block_table *node);
Query_cache_block *get_free_block (ulong len, my_bool not_less,
ulong min);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index c9545a0141e..32c9e2a50f7 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1303,6 +1303,14 @@ bool select_singlerow_subselect::send_data(List<Item> &items)
}
+void select_max_min_finder_subselect::cleanup()
+{
+ DBUG_ENTER("select_max_min_finder_subselect::cleanup");
+ cache= 0;
+ DBUG_VOID_RETURN;
+}
+
+
bool select_max_min_finder_subselect::send_data(List<Item> &items)
{
DBUG_ENTER("select_max_min_finder_subselect::send_data");
@@ -1332,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);
@@ -1373,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;
@@ -1439,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 561cf099592..b04ad449ba3 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -431,6 +431,11 @@ struct system_variables
my_bool low_priority_updates;
my_bool new_mode;
my_bool query_cache_wlock_invalidate;
+#ifdef HAVE_REPLICATION
+ ulong sync_replication;
+ ulong sync_replication_slave_id;
+ ulong sync_replication_timeout;
+#endif /* HAVE_REPLICATION */
#ifdef HAVE_INNOBASE_DB
my_bool innodb_table_locks;
#endif /* HAVE_INNOBASE_DB */
@@ -1026,6 +1031,8 @@ public:
sp_rcontext *spcont; // SP runtime context
sp_cache *sp_proc_cache;
sp_cache *sp_func_cache;
+ bool shortcut_make_view; /* Don't do full mysql_make_view()
+ during pre-opening of tables. */
/*
If we do a purge of binary logs, log index info of the threads
@@ -1510,9 +1517,11 @@ public:
select_max_min_finder_subselect(Item_subselect *item, bool mx)
:select_subselect(item), cache(0), fmax(mx)
{}
+ void cleanup();
bool send_data(List<Item> &items);
bool cmp_real();
bool cmp_int();
+ bool cmp_decimal();
bool cmp_str();
};
@@ -1586,9 +1595,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;
};
@@ -1617,9 +1627,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_derived.cc b/sql/sql_derived.cc
index bed65f90c00..c01728e68d5 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -165,16 +165,21 @@ exit:
else
{
if (!thd->fill_derived_tables())
+ {
delete derived_result;
+ derived_result= NULL;
+ }
orig_table_list->derived_result= derived_result;
orig_table_list->table= table;
orig_table_list->table_name= (char*) table->s->table_name;
+ orig_table_list->table_name_length= strlen((char*)table->s->table_name);
table->derived_select_number= first_select->select_number;
table->s->tmp_table= TMP_TABLE;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
table->grant.privilege= SELECT_ACL;
#endif
orig_table_list->db= (char *)"";
+ orig_table_list->db_length= 0;
// Force read of table stats in the optimizer
table->file->info(HA_STATUS_VARIABLE);
/* Add new temporary table to list of open derived tables */
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_insert.cc b/sql/sql_insert.cc
index 4cb62d5e9d7..fa6f1e05dc6 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1811,13 +1811,13 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
is the same table (Bug #6034). Do the preparation after the select phase
in select_insert::prepare2().
*/
- if (info.ignore || info.handle_duplicates != DUP_ERROR)
- table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
table->file->start_bulk_insert((ha_rows) 0);
}
restore_record(table,s->default_values); // Get empty record
table->next_number_field=table->found_next_number_field;
thd->cuted_fields=0;
+ if (info.ignore || info.handle_duplicates != DUP_ERROR)
+ table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
thd->no_trans_update= 0;
thd->abort_on_warning= (!info.ignore &&
(thd->variables.sql_mode &
@@ -1847,14 +1847,9 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
int select_insert::prepare2(void)
{
DBUG_ENTER("select_insert::prepare2");
-
if (thd->lex->current_select->options & OPTION_BUFFER_RESULT)
- {
- if (info.ignore || info.handle_duplicates != DUP_ERROR)
- table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
table->file->start_bulk_insert((ha_rows) 0);
- }
- return 0;
+ DBUG_RETURN(0);
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 43e82ff57c9..30c657c3b79 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 */
@@ -115,9 +111,14 @@ void lex_free(void)
void lex_start(THD *thd, uchar *buf,uint length)
{
LEX *lex= thd->lex;
+ DBUG_ENTER("lex_start");
+
+ lex->thd= lex->unit.thd= thd;
+ lex->buf= lex->ptr= buf;
+ lex->end_of_query= buf+length;
+
lex->unit.init_query();
lex->unit.init_select();
- lex->thd= lex->unit.thd= thd;
lex->select_lex.init_query();
lex->value_list.empty();
lex->update_list.empty();
@@ -150,8 +151,6 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->empty_field_list_on_rset= 0;
lex->select_lex.select_number= 1;
lex->next_state=MY_LEX_START;
- lex->buf= lex->ptr= buf;
- lex->end_of_query=buf+length;
lex->yylineno = 1;
lex->in_comment=0;
lex->length=0;
@@ -173,11 +172,15 @@ void lex_start(THD *thd, uchar *buf,uint length)
if (lex->spfuns.records)
my_hash_reset(&lex->spfuns);
+ if (lex->spprocs.records)
+ my_hash_reset(&lex->spprocs);
+ if (lex->sptabs.records)
+ my_hash_reset(&lex->sptabs);
+ DBUG_VOID_RETURN;
}
void lex_end(LEX *lex)
{
- lex->select_lex.expr_list.delete_elements(); // If error when parsing sql-varargs
x_free(lex->yacc_yyss);
x_free(lex->yacc_yyvs);
}
@@ -334,7 +337,8 @@ static char *get_text(LEX *lex)
continue;
}
#endif
- if (*str == '\\' && str+1 != end)
+ if (!(lex->thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) &&
+ *str == '\\' && str+1 != end)
{
switch(*++str) {
case 'n':
@@ -433,12 +437,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
@@ -454,10 +458,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
{
@@ -795,7 +799,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_lex.h b/sql/sql_lex.h
index b2c214bf1fa..5d232d60e79 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -416,6 +416,7 @@ public:
void print(String *str);
ulong init_prepare_fake_select_lex(THD *thd);
+ inline bool is_prepared() { return prepared; }
bool change_result(select_subselect *result, select_subselect *old_result);
void set_limit(st_select_lex *values, st_select_lex *sl);
@@ -747,6 +748,8 @@ typedef struct st_lex
bool all_privileges;
sp_pcontext *spcont;
HASH spfuns; /* Called functions */
+ HASH spprocs; /* Called procedures */
+ HASH sptabs; /* Merged table lists */
st_sp_chistics sp_chistics;
bool only_view; /* used for SHOW CREATE TABLE/VIEW */
/*
@@ -767,14 +770,21 @@ typedef struct st_lex
st_lex() :result(0), sql_command(SQLCOM_END)
{
- extern byte *sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first);
- hash_init(&spfuns, system_charset_info, 0, 0, 0, sp_lex_spfuns_key, 0, 0);
+ extern byte *sp_lex_sp_key(const byte *ptr, uint *plen, my_bool first);
+ extern byte *sp_table_key(const byte *ptr, uint *plen, my_bool first);
+ hash_init(&spfuns, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
+ hash_init(&spprocs, system_charset_info, 0, 0, 0, sp_lex_sp_key, 0, 0);
+ hash_init(&sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0);
}
~st_lex()
{
if (spfuns.array.buffer)
hash_free(&spfuns);
+ if (spprocs.array.buffer)
+ hash_free(&spprocs);
+ if (sptabs.array.buffer)
+ hash_free(&sptabs);
}
inline void uncacheable(uint8 cause)
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 05d6a00805c..8462066dcff 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -712,6 +712,8 @@ static int check_connection(THD *thd)
DBUG_PRINT("info",
("New connection received on %s", vio_description(net->vio)));
+ vio_in_addr(net->vio,&thd->remote.sin_addr);
+
if (!thd->host) // If TCP/IP connection
{
char ip[30];
@@ -756,7 +758,6 @@ static int check_connection(THD *thd)
DBUG_PRINT("info",("Host: %s",thd->host));
thd->host_or_ip= thd->host;
thd->ip= 0;
- bzero((char*) &thd->remote, sizeof(struct sockaddr));
}
vio_keepalive(net->vio, TRUE);
ulong pkt_len= 0;
@@ -2155,6 +2156,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
}
TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
table_list->schema_select_lex= sel;
+ table_list->schema_table_reformed= 1;
DBUG_RETURN(0);
}
@@ -2229,6 +2231,10 @@ mysql_execute_command(THD *thd)
TABLE_LIST *all_tables;
/* most outer SELECT_LEX_UNIT of query */
SELECT_LEX_UNIT *unit= &lex->unit;
+ /* Locked closure of all tables */
+ TABLE_LIST *locked_tables= NULL;
+ /* Saved variable value */
+ my_bool old_innodb_table_locks= thd->variables.innodb_table_locks;
DBUG_ENTER("mysql_execute_command");
/*
@@ -2250,11 +2256,89 @@ mysql_execute_command(THD *thd)
/* should be assigned after making first tables same */
all_tables= lex->query_tables;
+ thd->shortcut_make_view= 0;
if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
- lex->sql_command != SQLCOM_CREATE_SPFUNCTION)
+ lex->sql_command != SQLCOM_CREATE_SPFUNCTION &&
+ lex->sql_command != SQLCOM_LOCK_TABLES &&
+ lex->sql_command != SQLCOM_UNLOCK_TABLES)
{
- if (sp_cache_functions(thd, lex))
- DBUG_RETURN(-1);
+ while (1)
+ {
+ if (sp_cache_routines(thd, lex, TYPE_ENUM_FUNCTION))
+ DBUG_RETURN(-1);
+ if (sp_cache_routines(thd, lex, TYPE_ENUM_PROCEDURE))
+ DBUG_RETURN(-1);
+ if (!thd->locked_tables &&
+ lex->sql_command != SQLCOM_CREATE_TABLE &&
+ lex->sql_command != SQLCOM_CREATE_VIEW)
+ {
+ MEM_ROOT *thdmemroot= NULL;
+
+ sp_merge_routine_tables(thd, lex);
+ // QQ Preopen tables to find views and triggers.
+ // This means we open, close and open again, which sucks, but
+ // right now it's the easiest way to get it to work. A better
+ // solution will hopefully be found soon...
+ if (lex->sptabs.records || lex->query_tables)
+ {
+ uint procs, funs, tabs;
+
+ if (thd->mem_root != thd->current_arena->mem_root)
+ {
+ thdmemroot= thd->mem_root;
+ thd->mem_root= thd->current_arena->mem_root;
+ }
+ if (!sp_merge_table_list(thd, &lex->sptabs, lex->query_tables))
+ DBUG_RETURN(-1);
+ procs= lex->spprocs.records;
+ funs= lex->spfuns.records;
+ tabs= lex->sptabs.records;
+
+ if ((locked_tables= sp_hash_to_table_list(thd, &lex->sptabs)))
+ {
+ // We don't want these updated now
+ uint ctmpdtabs= thd->status_var.created_tmp_disk_tables;
+ uint ctmptabs= thd->status_var.created_tmp_tables;
+ uint count;
+
+ thd->shortcut_make_view= TRUE;
+ open_tables(thd, locked_tables, &count);
+ thd->shortcut_make_view= FALSE;
+ close_thread_tables(thd);
+ thd->status_var.created_tmp_disk_tables= ctmpdtabs;
+ thd->status_var.created_tmp_tables= ctmptabs;
+ thd->clear_error();
+ mysql_reset_errors(thd);
+ locked_tables= NULL;
+ }
+ // A kludge: Decrease all temp. table's query ids to allow a
+ // second opening.
+ for (TABLE *table= thd->temporary_tables; table ; table=table->next)
+ table->query_id-= 1;
+ if (procs < lex->spprocs.records ||
+ funs < lex->spfuns.records ||
+ tabs < lex->sptabs.records)
+ {
+ if (thdmemroot)
+ thd->mem_root= thdmemroot;
+ continue; // Found more SPs or tabs, try again
+ }
+ }
+ if (lex->sptabs.records &&
+ (lex->spfuns.records || lex->spprocs.records) &&
+ sp_merge_table_list(thd, &lex->sptabs, lex->query_tables))
+ {
+ if ((locked_tables= sp_hash_to_table_list(thd, &lex->sptabs)))
+ {
+ thd->variables.innodb_table_locks= FALSE;
+ sp_open_and_lock_tables(thd, locked_tables);
+ }
+ }
+ if (thdmemroot)
+ thd->mem_root= thdmemroot;
+ }
+ break;
+ } // while (1)
}
/*
@@ -2525,7 +2609,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;
@@ -3744,7 +3829,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));
@@ -4259,6 +4344,12 @@ cleanup:
thd->lock= 0;
}
+ if (locked_tables)
+ {
+ thd->variables.innodb_table_locks= old_innodb_table_locks;
+ if (thd->locked_tables)
+ sp_unlock_tables(thd);
+ }
DBUG_RETURN(res || thd->net.report_error);
}
@@ -4718,19 +4809,21 @@ bool
mysql_new_select(LEX *lex, bool move_down)
{
SELECT_LEX *select_lex;
+ DBUG_ENTER("mysql_new_select");
+
if (!(select_lex= new(lex->thd->mem_root) SELECT_LEX()))
- return 1;
+ DBUG_RETURN(1);
select_lex->select_number= ++lex->thd->select_number;
select_lex->init_query();
select_lex->init_select();
select_lex->parent_lex= lex;
if (move_down)
{
+ SELECT_LEX_UNIT *unit;
lex->subqueries= TRUE;
/* first select_lex of subselect or derived table */
- SELECT_LEX_UNIT *unit;
if (!(unit= new(lex->thd->mem_root) SELECT_LEX_UNIT()))
- return 1;
+ DBUG_RETURN(1);
unit->init_query();
unit->init_select();
@@ -4747,7 +4840,7 @@ mysql_new_select(LEX *lex, bool move_down)
if (lex->current_select->order_list.first && !lex->current_select->braces)
{
my_error(ER_WRONG_USAGE, MYF(0), "UNION", "ORDER BY");
- return 1;
+ DBUG_RETURN(1);
}
select_lex->include_neighbour(lex->current_select);
SELECT_LEX_UNIT *unit= select_lex->master_unit();
@@ -4759,7 +4852,7 @@ mysql_new_select(LEX *lex, bool move_down)
fake SELECT_LEX for UNION processing
*/
if (!(fake= unit->fake_select_lex= new(lex->thd->mem_root) SELECT_LEX()))
- return 1;
+ DBUG_RETURN(1);
fake->include_standalone(unit,
(SELECT_LEX_NODE**)&unit->fake_select_lex);
fake->select_number= INT_MAX;
@@ -4773,7 +4866,7 @@ mysql_new_select(LEX *lex, bool move_down)
select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
lex->current_select= select_lex;
select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
- return 0;
+ DBUG_RETURN(0);
}
/*
@@ -5066,21 +5159,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
@@ -5266,6 +5357,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..93197b1a2eb 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;
@@ -1541,9 +1554,11 @@ static int check_prepared_statement(Prepared_statement *stmt,
if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
lex->sql_command != SQLCOM_CREATE_SPFUNCTION)
{
- /* the error is print inside */
- if (sp_cache_functions(thd, lex))
- DBUG_RETURN(1);
+ /* The error is printed inside */
+ if (sp_cache_routines(thd, lex, TYPE_ENUM_FUNCTION))
+ DBUG_RETURN(-1);
+ if (sp_cache_routines(thd, lex, TYPE_ENUM_PROCEDURE))
+ DBUG_RETURN(-1);
}
switch (sql_command) {
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 69b5c667f6b..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();
@@ -1435,7 +1439,7 @@ JOIN::exec()
curr_join->select_distinct=0; /* Each row is unique */
curr_join->join_free(0); /* Free quick selects */
- if (select_distinct && ! group_list)
+ if (curr_join->select_distinct && ! curr_join->group_list)
{
thd->proc_info="Removing duplicates";
if (curr_join->tmp_having)
@@ -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:
@@ -9181,7 +9165,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
tab->info="const row not found";
/* Mark for EXPLAIN that the row was not found */
pos->records_read=0.0;
- if (!table->outer_join || error > 0)
+ if (!table->maybe_null || error > 0)
DBUG_RETURN(error);
}
}
@@ -9200,7 +9184,7 @@ join_read_const_table(JOIN_TAB *tab, POSITION *pos)
tab->info="unique row not found";
/* Mark for EXPLAIN that the row was not found */
pos->records_read=0.0;
- if (!table->outer_join || error > 0)
+ if (!table->maybe_null || error > 0)
DBUG_RETURN(error);
}
if (table->key_read)
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index e9126871045..c50d594a7aa 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -311,7 +311,9 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
if (db && !(col_access & TABLE_ACLS))
{
table_list.db= (char*) db;
+ table_list.db_length= strlen(db);
table_list.table_name= file->name;
+ table_list.table_name_length= strlen(file->name);
table_list.grant.privilege=col_access;
if (check_grant(thd, TABLE_ACLS, &table_list, 1, UINT_MAX, 1))
continue;
@@ -1786,7 +1788,9 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
enum enum_schema_tables schema_table_idx;
thr_lock_type lock_type;
List<char> bases;
+ List_iterator_fast<char> it(bases);
COND *partial_cond;
+ int error= 1;
DBUG_ENTER("get_all_tables");
LINT_INIT(end);
@@ -1803,13 +1807,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
if (schema_table->process_table(thd, show_table_list,
table, res, show_table_list->db,
show_table_list->alias))
- {
- DBUG_RETURN(1);
- }
+ goto err;
close_thread_tables(thd, 0, 0, old_open_tables);
show_table_list->table= 0;
- lex->all_selects_list= select_lex;
- DBUG_RETURN(0);
+ error= 0;
+ goto err;
}
lex->all_selects_list= &sel;
@@ -1822,14 +1824,14 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
/* information schema name always is first in list */
if (schema_db_add(thd, &bases, idx_field_vals.db_value, &with_i_schema))
- return 1;
+ goto err;
if (mysql_find_files(thd, &bases, NullS, mysql_data_home,
idx_field_vals.db_value, 1))
- return 1;
+ goto err;
- List_iterator_fast<char> it(bases);
partial_cond= make_cond_for_info_schema(cond, tables);
+ it.rewind(); /* To get access to new elements in basis list */
while ((base_name= it++) ||
/*
generate error for non existing database.
@@ -1851,7 +1853,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
if (with_i_schema) // information schema table names
{
if (schema_tables_add(thd, &files, idx_field_vals.table_value))
- DBUG_RETURN(1);
+ goto err;
}
else
{
@@ -1860,7 +1862,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
len= FN_LEN - len;
if (mysql_find_files(thd, &files, base_name,
path, idx_field_vals.table_value, 0))
- DBUG_RETURN(1);
+ goto err;
}
List_iterator_fast<char> it_files(files);
@@ -1906,16 +1908,14 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
int res;
TABLE *old_open_tables= thd->open_tables;
if (make_table_list(thd, &sel, base_name, file_name))
- DBUG_RETURN(1);
+ goto err;
TABLE_LIST *show_table_list= (TABLE_LIST*) sel.table_list.first;
show_table_list->lock_type= lock_type;
res= open_and_lock_tables(thd, show_table_list);
if (schema_table->process_table(thd, show_table_list, table,
res, base_name,
show_table_list->alias))
- {
- DBUG_RETURN(1);
- }
+ goto err;
close_thread_tables(thd, 0, 0, old_open_tables);
}
}
@@ -1927,8 +1927,11 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
with_i_schema= 0;
}
}
+
+ error= 0;
+err:
lex->all_selects_list= select_lex;
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
@@ -2249,15 +2252,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);
@@ -2265,8 +2274,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:
@@ -2282,8 +2291,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;
}
@@ -2518,7 +2527,9 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
bzero((char*) &proc_tables,sizeof(proc_tables));
proc_tables.db= (char*) "mysql";
+ proc_tables.db_length= 5;
proc_tables.table_name= proc_tables.alias= (char*) "proc";
+ proc_tables.table_name_length= 4;
proc_tables.lock_type= TL_READ;
if (!(proc_table= open_ltable(thd, &proc_tables, TL_READ)))
{
@@ -3196,11 +3207,51 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list)
table_list->schema_table_name,
table_list->alias);
table_list->table_name= (char*) table->s->table_name;
+ table_list->table_name_length= strlen(table->s->table_name);
table_list->table= table;
table->next= thd->derived_tables;
thd->derived_tables= table;
table_list->select_lex->options |= OPTION_SCHEMA_TABLE;
lex->safe_to_cache_query= 0;
+
+ if (table_list->schema_table_reformed) // show command
+ {
+ SELECT_LEX *sel= lex->current_select;
+ uint i= 0;
+ Item *item;
+ Field_translator *transl;
+
+ if (table_list->field_translation)
+ {
+ Field_translator *end= table_list->field_translation +
+ sel->item_list.elements;
+ for (transl= table_list->field_translation; transl < end; transl++)
+ {
+ if (!transl->item->fixed &&
+ transl->item->fix_fields(thd, table_list, &transl->item))
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+ }
+ List_iterator_fast<Item> it(sel->item_list);
+ if (!(transl=
+ (Field_translator*)(thd->current_arena->
+ alloc(sel->item_list.elements *
+ sizeof(Field_translator)))))
+ {
+ DBUG_RETURN(1);
+ }
+ while ((item= it++))
+ {
+ char *name= item->name;
+ transl[i].item= item;
+ if (!item->fixed && item->fix_fields(thd, table_list, &transl[i].item))
+ DBUG_RETURN(1);
+ transl[i++].name= name;
+ }
+ table_list->field_translation= transl;
+ }
+
DBUG_RETURN(0);
}
@@ -3233,8 +3284,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
information_schema_name.length, 0);
make_lex_string(thd, &table, schema_table->table_name,
strlen(schema_table->table_name), 0);
- if (!sel->item_list.elements && /* Handle old syntax */
- schema_table->old_format(thd, schema_table) ||
+ if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */
!sel->add_table_to_list(thd, new Table_ident(thd, db, table, 0),
0, 0, TL_READ, (List<String> *) 0,
(List<String> *) 0))
diff --git a/sql/sql_string.h b/sql/sql_string.h
index cb9db52c830..a5c7cf77630 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -210,6 +210,11 @@ public:
{
if (&s != this)
{
+ /*
+ It is forbidden to do assignments like
+ some_string = substring_of_that_string
+ */
+ DBUG_ASSERT(!s.uses_buffer_owned_by(this));
free();
Ptr=s.Ptr ; str_length=s.str_length ; Alloced_length=s.Alloced_length;
alloced=0;
@@ -343,4 +348,9 @@ public:
/* Swap two string objects. Efficient way to exchange data without memcpy. */
void swap(String &s);
+
+ inline bool uses_buffer_owned_by(const String *s) const
+ {
+ return (s->alloced && Ptr >= s->Ptr && Ptr < s->Ptr + s->str_length);
+ }
};
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 880cce06c27..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)
@@ -2394,7 +2402,10 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
strxmov(src_path, (*tmp_table)->s->path, reg_ext, NullS);
else
{
- fn_format( src_path, src_table, src_db, reg_ext, MYF(MY_UNPACK_FILENAME));
+ strxmov(src_path, mysql_data_home, "/", src_db, "/", src_table,
+ reg_ext, NullS);
+ /* Resolve symlinks (for windows) */
+ fn_format(src_path, src_path, "", "", MYF(MY_UNPACK_FILENAME));
if (access(src_path, F_OK))
{
my_error(ER_BAD_TABLE_ERROR, MYF(0), src_table);
@@ -2421,7 +2432,9 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
}
else
{
- fn_format( dst_path, table_name, db, reg_ext, MYF(MY_UNPACK_FILENAME));
+ strxmov(dst_path, mysql_data_home, "/", db, "/", table_name,
+ reg_ext, NullS);
+ fn_format(dst_path, dst_path, "", "", MYF(MY_UNPACK_FILENAME));
if (!access(dst_path, F_OK))
goto table_exists;
}
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_union.cc b/sql/sql_union.cc
index 0a91eb4c0e1..29897c70023 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -153,6 +153,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
SELECT_LEX *sl, *first_select;
select_result *tmp_result;
bool is_union;
+ TABLE *empty_table= 0;
DBUG_ENTER("st_select_lex_unit::prepare");
describe= test(additional_options & SELECT_DESCRIBE);
@@ -249,13 +250,21 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
goto err;
if (sl == first_select)
{
+ /*
+ We need to create an empty table object. It is used
+ to create tmp_table fields in Item_type_holder.
+ The main reason of this is that we can't create
+ field object without table.
+ */
+ DBUG_ASSERT(!empty_table);
+ empty_table= (TABLE*) thd->calloc(sizeof(TABLE));
types.empty();
List_iterator_fast<Item> it(sl->item_list);
Item *item_tmp;
while ((item_tmp= it++))
{
/* Error's in 'new' will be detected after loop */
- types.push_back(new Item_type_holder(thd_arg, item_tmp));
+ types.push_back(new Item_type_holder(thd_arg, item_tmp, empty_table));
}
if (thd_arg->is_fatal_error)
@@ -274,7 +283,8 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
Item *type, *item_tmp;
while ((type= tp++, item_tmp= it++))
{
- if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp))
+ if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp,
+ empty_table))
DBUG_RETURN(TRUE);
}
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index f9ad513ea6a..f9df1be2abd 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -120,7 +120,7 @@ int mysql_update(THD *thd,
bool used_key_is_modified, transactional_table, log_delayed;
int res;
int error=0;
- uint used_index= MAX_KEY;
+ uint used_index;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint want_privilege;
#endif
@@ -264,7 +264,10 @@ int mysql_update(THD *thd,
else if ((used_index=table->file->key_used_on_scan) < MAX_KEY)
used_key_is_modified=check_if_key_used(table, used_index, fields);
else
+ {
used_key_is_modified=0;
+ used_index= MAX_KEY;
+ }
if (used_key_is_modified || order)
{
/*
@@ -498,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=
@@ -1380,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_view.cc b/sql/sql_view.cc
index e2c4b1289fd..456f513dab0 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -556,6 +556,7 @@ my_bool
mysql_make_view(File_parser *parser, TABLE_LIST *table)
{
DBUG_ENTER("mysql_make_view");
+ DBUG_PRINT("info", ("table=%p (%s)", table, table->table_name));
if (table->view)
{
@@ -612,7 +613,9 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local;
lex_start(thd, (uchar*)table->query.str, table->query.length);
view_select= &lex->select_lex;
- view_select->select_number= ++thd->select_number;
+ /* Only if we're not in the pre-open phase */
+ if (!thd->shortcut_make_view)
+ view_select->select_number= ++thd->select_number;
old_lex->derived_tables|= DERIVED_VIEW;
{
ulong options= thd->options;
@@ -657,27 +660,29 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
TABLE_LIST *view_tables_tail= 0;
TABLE_LIST *tbl;
+ /* move SP to main LEX */
if (lex->spfuns.records)
- {
- /* move SP to main LEX */
- sp_merge_funs(old_lex, lex);
- /* open mysq.proc for functions which are not in cache */
- if (old_lex->proc_table == 0 &&
- (old_lex->proc_table=
- (TABLE_LIST*)thd->calloc(sizeof(TABLE_LIST))) != 0)
- {
- TABLE_LIST *table= old_lex->proc_table;
- table->db= (char*)"mysql";
- table->db_length= 5;
- table->table_name= table->alias= (char*)"proc";
- table->table_name_length= 4;
- table->cacheable_table= 1;
- old_lex->add_to_query_tables(table);
- }
- }
+ sp_merge_hash(&old_lex->spfuns, &lex->spfuns);
+
/* cleanup LEX */
if (lex->spfuns.array.buffer)
hash_free(&lex->spfuns);
+ if (lex->spprocs.array.buffer)
+ hash_free(&lex->spprocs);
+ if (lex->sptabs.array.buffer)
+ hash_free(&lex->sptabs);
+
+ /* If we're pre-opening tables to find SPs and tables we need
+ not go any further; doing so will cause an infinite loop. */
+ if (thd->shortcut_make_view)
+ {
+ extern bool
+ sp_merge_table_list(THD *thd, HASH *h, TABLE_LIST *table,
+ LEX *lex_for_tmp_check = 0);
+
+ sp_merge_table_list(thd, &old_lex->sptabs, view_tables);
+ goto ok;
+ }
/*
check rights to run commands (EXPLAIN SELECT & SHOW CREATE) which show
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index e1c7c26060a..c4649c57269 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
@@ -1464,6 +1464,7 @@ call:
lex->sql_command= SQLCOM_CALL;
lex->spname= $2;
lex->value_list.empty();
+ sp_add_to_hash(&lex->spprocs, $2);
}
'(' sp_cparam_list ')' {}
;
@@ -1869,36 +1870,21 @@ sp_proc_stmt:
if (lex->sql_command != SQLCOM_SET_OPTION ||
! lex->var_list.is_empty())
{
- /*
- Currently we can't handle queries inside a FUNCTION or
- TRIGGER, because of the way table locking works. This is
- unfortunate, and limits the usefulness of functions and
- especially triggers a tremendously, but it's nothing we
- can do about this at the moment.
- */
- if (sp->m_type != TYPE_ENUM_PROCEDURE)
- {
- my_message(ER_SP_BADSTATEMENT, ER(ER_SP_BADSTATEMENT), MYF(0));
- YYABORT;
- }
+ sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(),
+ lex->spcont);
+
+ /* Extract the query statement from the tokenizer:
+ The end is either lex->tok_end or tok->ptr. */
+ if (lex->ptr - lex->tok_end > 1)
+ i->m_query.length= lex->ptr - sp->m_tmp_query;
else
- {
- sp_instr_stmt *i=new sp_instr_stmt(sp->instructions(),
- lex->spcont);
-
- /* Extract the query statement from the tokenizer:
- The end is either lex->tok_end or tok->ptr. */
- if (lex->ptr - lex->tok_end > 1)
- i->m_query.length= lex->ptr - sp->m_tmp_query;
- else
- i->m_query.length= lex->tok_end - sp->m_tmp_query;
- i->m_query.str= strmake_root(YYTHD->mem_root,
- (char *)sp->m_tmp_query,
- i->m_query.length);
- i->set_lex(lex);
- sp->add_instr(i);
- lex->sp_lex_in_use= TRUE;
- }
+ i->m_query.length= lex->tok_end - sp->m_tmp_query;
+ i->m_query.str= strmake_root(YYTHD->mem_root,
+ (char *)sp->m_tmp_query,
+ i->m_query.length);
+ i->set_lex(lex);
+ sp->add_instr(i);
+ lex->sp_lex_in_use= TRUE;
}
sp->restore_lex(YYTHD);
}
@@ -1915,11 +1901,6 @@ sp_proc_stmt:
{
sp_instr_freturn *i;
- if ($2->type() == Item::SUBSELECT_ITEM)
- { /* QQ For now, just disallow subselects as values */
- my_message(ER_SP_BADSTATEMENT, ER(ER_SP_BADSTATEMENT), MYF(0));
- YYABORT;
- }
i= new sp_instr_freturn(lex->sphead->instructions(),
lex->spcont,
$2, lex->sphead->m_returns);
@@ -2658,6 +2639,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 +2820,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 +2886,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:
@@ -3895,10 +3877,11 @@ select_into:
select_from:
FROM join_table_list where_clause group_clause having_clause
opt_order_clause opt_limit_clause procedure_clause
- | FROM DUAL_SYM /* oracle compatibility: oracle always requires FROM
- clause, and DUAL is system table without fields.
- Is "SELECT 1 FROM DUAL" any better than
- "SELECT 1" ? Hmmm :) */
+ | FROM DUAL_SYM opt_limit_clause
+ /* oracle compatibility: oracle always requires FROM clause,
+ and DUAL is system table without fields.
+ Is "SELECT 1 FROM DUAL" any better than "SELECT 1" ?
+ Hmmm :) */
;
select_options:
@@ -4032,14 +4015,15 @@ bool_test:
bool_pri:
bool_pri IS NULL_SYM { $$= new Item_func_isnull($1); }
| bool_pri IS not NULL_SYM { $$= new Item_func_isnotnull($1); }
- | predicate BETWEEN_SYM bit_expr AND_SYM bool_pri
- { $$= new Item_func_between($1,$3,$5); }
- | predicate not BETWEEN_SYM bit_expr AND_SYM bool_pri
- { $$= negate_expression(YYTHD, new Item_func_between($1,$4,$6)); }
+ | bool_pri EQUAL_SYM predicate { $$= new Item_func_equal($1,$3); }
+ | bool_pri comp_op predicate %prec EQ
+ { $$= (*$2)(0)->create($1,$3); }
+ | bool_pri comp_op all_or_any in_subselect %prec EQ
+ { $$= all_any_subquery_creator($1, $2, $3, $4); }
| predicate ;
predicate:
- bit_expr IN_SYM '(' expr_list ')'
+ bit_expr IN_SYM '(' expr_list ')'
{ $4->push_front($1); $$= new Item_func_in(*$4); }
| bit_expr not IN_SYM '(' expr_list ')'
{ $5->push_front($1); $$= negate_expression(YYTHD, new Item_func_in(*$5)); }
@@ -4047,6 +4031,10 @@ predicate:
{ $$= new Item_in_subselect($1, $3); }
| bit_expr not IN_SYM in_subselect
{ $$= negate_expression(YYTHD, new Item_in_subselect($1, $4)); }
+ | bit_expr BETWEEN_SYM bit_expr AND_SYM predicate
+ { $$= new Item_func_between($1,$3,$5); }
+ | bit_expr not BETWEEN_SYM bit_expr AND_SYM predicate
+ { $$= negate_expression(YYTHD, new Item_func_between($1,$4,$6)); }
| bit_expr SOUNDS_SYM LIKE bit_expr
{ $$= new Item_func_eq(new Item_func_soundex($1),
new Item_func_soundex($4)); }
@@ -4057,11 +4045,6 @@ predicate:
| bit_expr REGEXP bit_expr { $$= new Item_func_regex($1,$3); }
| bit_expr not REGEXP bit_expr
{ $$= negate_expression(YYTHD, new Item_func_regex($1,$4)); }
- | bit_expr EQUAL_SYM bit_expr { $$= new Item_func_equal($1,$3); }
- | bit_expr comp_op bit_expr %prec EQ
- { $$= (*$2)(0)->create($1,$3); }
- | bit_expr comp_op all_or_any in_subselect %prec EQ
- { $$= all_any_subquery_creator($1, $2, $3, $4); }
| bit_expr ;
bit_expr:
@@ -4186,13 +4169,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 ); }
@@ -4200,6 +4185,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 ')'
@@ -4502,7 +4488,7 @@ simple_expr:
sp_name *name= new sp_name($1, $3);
name->init_qname(YYTHD);
- sp_add_fun_to_lex(Lex, name);
+ sp_add_to_hash(&Lex->spfuns, name);
if ($5)
$$= new Item_func_sp(name, *$5);
else
@@ -4564,6 +4550,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;
}
@@ -4573,7 +4575,7 @@ simple_expr:
{
sp_name *name= sp_name_current_db_new(YYTHD, $1);
- sp_add_fun_to_lex(Lex, name);
+ sp_add_to_hash(&Lex->spfuns, name);
if ($3)
$$= new Item_func_sp(name, *$3);
else
@@ -4813,16 +4815,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; }
- | 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; }
+ 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; Lex->dec=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:
@@ -5325,7 +5328,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); }
;
@@ -5333,7 +5336,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); }
;
@@ -5879,6 +5882,9 @@ show: SHOW
{
LEX *lex=Lex;
lex->wild=0;
+ lex->lock_option= TL_READ;
+ mysql_init_select(lex);
+ lex->current_select->parsing_place= SELECT_LIST;
bzero((char*) &lex->create_info,sizeof(lex->create_info));
}
show_param
@@ -5886,7 +5892,7 @@ show: SHOW
;
show_param:
- DATABASES ext_select_item_list wild_and_where
+ DATABASES wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
@@ -5894,44 +5900,44 @@ show_param:
if (prepare_schema_table(YYTHD, lex, 0, SCH_SCHEMATA))
YYABORT;
}
- | opt_full TABLES ext_select_item_list opt_db wild_and_where
+ | opt_full TABLES opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
lex->orig_sql_command= SQLCOM_SHOW_TABLES;
- lex->select_lex.db= $4;
+ lex->select_lex.db= $3;
if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES))
YYABORT;
}
- | TABLE_SYM STATUS_SYM ext_select_item_list opt_db wild_and_where
+ | TABLE_SYM STATUS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
lex->orig_sql_command= SQLCOM_SHOW_TABLE_STATUS;
- lex->select_lex.db= $4;
+ lex->select_lex.db= $3;
if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLES))
YYABORT;
}
- | OPEN_SYM TABLES ext_select_item_list opt_db wild_and_where
+ | OPEN_SYM TABLES opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
lex->orig_sql_command= SQLCOM_SHOW_OPEN_TABLES;
- lex->select_lex.db= $4;
+ lex->select_lex.db= $3;
if (prepare_schema_table(YYTHD, lex, 0, SCH_OPEN_TABLES))
YYABORT;
}
| ENGINE_SYM storage_engines
{ Lex->create_info.db_type= $2; }
show_engine_param
- | opt_full COLUMNS ext_select_item_list from_or_in table_ident opt_db wild_and_where
+ | opt_full COLUMNS from_or_in table_ident opt_db wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
lex->orig_sql_command= SQLCOM_SHOW_FIELDS;
- if ($6)
- $5->change_db($6);
- if (prepare_schema_table(YYTHD, lex, $5, SCH_COLUMNS))
+ if ($5)
+ $4->change_db($5);
+ if (prepare_schema_table(YYTHD, lex, $4, SCH_COLUMNS))
YYABORT;
}
| NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ
@@ -5957,14 +5963,14 @@ show_param:
LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS;
} opt_limit_clause_init
- | keys_or_index ext_select_item_list from_or_in table_ident opt_db where_clause
+ | keys_or_index from_or_in table_ident opt_db where_clause
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
lex->orig_sql_command= SQLCOM_SHOW_KEYS;
- if ($5)
- $4->change_db($5);
- if (prepare_schema_table(YYTHD, lex, $4, SCH_STATISTICS))
+ if ($4)
+ $3->change_db($4);
+ if (prepare_schema_table(YYTHD, lex, $3, SCH_STATISTICS))
YYABORT;
}
| COLUMN_SYM TYPES_SYM
@@ -5996,7 +6002,7 @@ show_param:
{ Lex->sql_command = SQLCOM_SHOW_WARNS;}
| ERRORS opt_limit_clause_init
{ Lex->sql_command = SQLCOM_SHOW_ERRORS;}
- | opt_var_type STATUS_SYM ext_select_item_list wild_and_where
+ | opt_var_type STATUS_SYM wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
@@ -6011,7 +6017,7 @@ show_param:
{ Lex->sql_command = SQLCOM_SHOW_MUTEX_STATUS; }
| opt_full PROCESSLIST_SYM
{ Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;}
- | opt_var_type VARIABLES ext_select_item_list wild_and_where
+ | opt_var_type VARIABLES wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
@@ -6020,7 +6026,7 @@ show_param:
if (prepare_schema_table(YYTHD, lex, 0, SCH_VARIABLES))
YYABORT;
}
- | charset ext_select_item_list wild_and_where
+ | charset wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
@@ -6028,7 +6034,7 @@ show_param:
if (prepare_schema_table(YYTHD, lex, 0, SCH_CHARSETS))
YYABORT;
}
- | COLLATION_SYM ext_select_item_list wild_and_where
+ | COLLATION_SYM wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
@@ -6114,19 +6120,23 @@ show_param:
lex->sql_command = SQLCOM_SHOW_CREATE_FUNC;
lex->spname= $3;
}
- | PROCEDURE STATUS_SYM ext_select_item_list wild_and_where
+ | PROCEDURE STATUS_SYM wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
lex->orig_sql_command= SQLCOM_SHOW_STATUS_PROC;
+ if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ))
+ YYABORT;
if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
YYABORT;
}
- | FUNCTION_SYM STATUS_SYM ext_select_item_list wild_and_where
+ | FUNCTION_SYM STATUS_SYM wild_and_where
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_SELECT;
lex->orig_sql_command= SQLCOM_SHOW_STATUS_FUNC;
+ if (!sp_add_to_query_tables(YYTHD, lex, "mysql", "proc", TL_READ))
+ YYABORT;
if (prepare_schema_table(YYTHD, lex, 0, SCH_PROCEDURES))
YYABORT;
};
@@ -6196,20 +6206,6 @@ wild_and_where:
}
;
-ext_select_item_list:
- {
- LEX *lex=Lex;
- SELECT_LEX *sel= lex->current_select;
- lex->lock_option= TL_READ;
- mysql_init_select(lex);
- lex->current_select->parsing_place= SELECT_LIST;
- }
- ext_select_item_list2;
-
-ext_select_item_list2:
- /* empty */ {}
- | select_item_list {};
-
/* A Oracle compatible synonym for show */
describe:
@@ -6585,9 +6581,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;
@@ -7444,7 +7440,14 @@ set_expr_or_default:
lock:
LOCK_SYM table_or_tables
{
- Lex->sql_command=SQLCOM_LOCK_TABLES;
+ LEX *lex= Lex;
+
+ if (lex->sphead)
+ {
+ my_message(ER_SP_BADSTATEMENT, ER(ER_SP_BADSTATEMENT), MYF(0));
+ YYABORT;
+ }
+ lex->sql_command= SQLCOM_LOCK_TABLES;
}
table_lock_list
{}
@@ -7474,7 +7477,19 @@ lock_option:
;
unlock:
- UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; }
+ UNLOCK_SYM
+ {
+ LEX *lex= Lex;
+
+ if (lex->sphead)
+ {
+ my_message(ER_SP_BADSTATEMENT, ER(ER_SP_BADSTATEMENT), MYF(0));
+ YYABORT;
+ }
+ lex->sql_command= SQLCOM_UNLOCK_TABLES;
+ }
+ table_or_tables
+ {}
;
diff --git a/sql/table.h b/sql/table.h
index 8240a3445ec..5ab1f900195 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -217,14 +217,18 @@ struct st_table {
uint derived_select_number;
int current_lock; /* Type of lock on table */
my_bool copy_blobs; /* copy_blobs when storing */
+
+ /*
+ 0 or JOIN_TYPE_{LEFT|RIGHT}. Currently this is only compared to 0.
+ If maybe_null !=0, this table is inner w.r.t. some outer join operation,
+ and null_row may be true.
+ */
+ uint maybe_null;
/*
- Used in outer joins: if true, all columns are considered to have NULL
- values, including columns declared as "not null".
+ If true, the current table row is considered to have all columns set to
+ NULL, including columns declared as "not null" (see maybe_null).
*/
my_bool null_row;
- /* 0 or JOIN_TYPE_{LEFT|RIGHT}, same as TABLE_LIST::outer_join */
- my_bool outer_join;
- my_bool maybe_null; /* true if (outer_join != 0) */
my_bool force_index;
my_bool distinct,const_table,no_rows;
my_bool key_read, no_keyread;
@@ -356,6 +360,7 @@ typedef struct st_table_list
st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
ST_SCHEMA_TABLE *schema_table; /* Information_schema table */
st_select_lex *schema_select_lex;
+ bool schema_table_reformed;
/* link to select_lex where this table was used */
st_select_lex *select_lex;
st_lex *view; /* link on VIEW lex for merging */
@@ -387,6 +392,10 @@ typedef struct st_table_list
uint effective_algorithm; /* which algorithm was really used */
uint privilege_backup; /* place for saving privileges */
GRANT_INFO grant;
+ /* data need by some engines in query cache*/
+ ulonglong engine_data;
+ /* call back function for asking handler about caching in query cache */
+ qc_engine_callback callback_func;
thr_lock_type lock_type;
uint outer_join; /* Which join type */
uint shared; /* Used in multi-upd */
diff --git a/sql/unireg.h b/sql/unireg.h
index eca540b61b9..8d88683241b 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -77,6 +77,8 @@
#define PARAM_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-3))
#define OUTER_REF_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-2))
#define RAND_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-1))
+#define PSEUDO_TABLE_BITS (PARAM_TABLE_BIT | OUTER_REF_TABLE_BIT | \
+ RAND_TABLE_BIT)
#define MAX_FIELDS 4096 /* Limit in the .frm file */
#define MAX_SORT_MEMORY (2048*1024-MALLOC_OVERHEAD)