summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <evgen@moonbone.local>2006-06-14 23:54:08 +0400
committerunknown <evgen@moonbone.local>2006-06-14 23:54:08 +0400
commit0e7f2f5bc2da67c8ba45b654b3ab6e8f691d7ab3 (patch)
tree9f2d34990366073803ede28b005fe7965ee7d736
parent834c1de13fe8edc69aedc14ca42192b81eab9d42 (diff)
parent2bb56f9b7d3a6838158f0ec0781ad4fe1a8c0b9d (diff)
downloadmariadb-git-0e7f2f5bc2da67c8ba45b654b3ab6e8f691d7ab3.tar.gz
Manually merged
mysql-test/r/cast.result: Auto merged mysql-test/t/func_time.test: Auto merged sql/item_cmpfunc.h: Auto merged sql/item_strfunc.cc: Auto merged sql/item_timefunc.cc: Auto merged sql/item_timefunc.h: Auto merged sql/opt_sum.cc: Auto merged sql/structs.h: Auto merged
-rw-r--r--client/mysqlbinlog.cc16
-rw-r--r--mysql-test/r/cast.result2
-rw-r--r--mysql-test/r/func_concat.result7
-rw-r--r--mysql-test/r/func_time.result41
-rw-r--r--mysql-test/t/func_concat.test7
-rw-r--r--mysql-test/t/func_time.test20
-rw-r--r--sql/field.cc43
-rw-r--r--sql/item.h16
-rw-r--r--sql/item_cmpfunc.cc129
-rw-r--r--sql/item_cmpfunc.h14
-rw-r--r--sql/item_strfunc.cc5
-rw-r--r--sql/item_timefunc.cc60
-rw-r--r--sql/item_timefunc.h12
-rw-r--r--sql/opt_sum.cc4
-rw-r--r--sql/structs.h8
15 files changed, 352 insertions, 32 deletions
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 60b54a2ed99..a8756964f26 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -71,6 +71,7 @@ static int port= 0;
static const char* sock= 0;
static const char* user = 0;
static char* pass = 0;
+static char *charset= 0;
static ulonglong start_position, stop_position;
#define start_position_mot ((my_off_t)start_position)
@@ -707,6 +708,9 @@ static struct my_option my_long_options[] =
"Used to reserve file descriptors for usage by this program",
(gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG,
REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
+ {"set-charset", OPT_SET_CHARSET,
+ "Add 'SET NAMES character_set' to the output.", (gptr*) &charset,
+ (gptr*) &charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"short-form", 's', "Just show the queries, no extra info.",
(gptr*) &short_form, (gptr*) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
@@ -1422,6 +1426,12 @@ int main(int argc, char** argv)
fprintf(result_file,
"/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n");
+ if (charset)
+ fprintf(result_file,
+ "\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
+ "\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
+ "\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
+ "\n/*!40101 SET NAMES %s */;\n", charset);
/*
In mysqlbinlog|mysql, don't want mysql to be disconnected after each
transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
@@ -1454,6 +1464,12 @@ int main(int argc, char** argv)
if (disable_log_bin)
fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");
+ if (charset)
+ fprintf(result_file,
+ "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
+ "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
+ "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
+
if (tmpdir.list)
free_tmpdir(&tmpdir);
if (result_file != stdout)
diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result
index d60efa083e0..8f5a5eea99f 100644
--- a/mysql-test/r/cast.result
+++ b/mysql-test/r/cast.result
@@ -254,7 +254,7 @@ cast("2001-1-1" as datetime) = "2001-01-01 00:00:00"
1
select cast("1:2:3" as TIME) = "1:02:03";
cast("1:2:3" as TIME) = "1:02:03"
-0
+1
select cast(NULL as DATE);
cast(NULL as DATE)
NULL
diff --git a/mysql-test/r/func_concat.result b/mysql-test/r/func_concat.result
index 712f0c0495e..7fb489f2a14 100644
--- a/mysql-test/r/func_concat.result
+++ b/mysql-test/r/func_concat.result
@@ -75,3 +75,10 @@ a
1234562
x
drop table t1;
+select concat((select x from (select 'a' as x) as t1 ),
+(select y from (select 'b' as y) as t2 )) from (select 1 union select 2 )
+as t3;
+concat((select x from (select 'a' as x) as t1 ),
+(select y from (select 'b' as y) as t2 ))
+ab
+ab
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result
index 0e029802555..a0faa05f988 100644
--- a/mysql-test/r/func_time.result
+++ b/mysql-test/r/func_time.result
@@ -751,6 +751,47 @@ select monthname(str_to_date(null, '%m')), monthname(str_to_date(null, '%m')),
monthname(str_to_date(1, '%m')), monthname(str_to_date(0, '%m'));
monthname(str_to_date(null, '%m')) monthname(str_to_date(null, '%m')) monthname(str_to_date(1, '%m')) monthname(str_to_date(0, '%m'))
NULL NULL January NULL
+create table t1(f1 date, f2 time, f3 datetime);
+insert into t1 values ("2006-01-01", "12:01:01", "2006-01-01 12:01:01");
+insert into t1 values ("2006-01-02", "12:01:02", "2006-01-02 12:01:02");
+select f1 from t1 where f1 between "2006-1-1" and 20060101;
+f1
+2006-01-01
+select f1 from t1 where f1 between "2006-1-1" and "2006.1.1";
+f1
+2006-01-01
+select f1 from t1 where date(f1) between "2006-1-1" and "2006.1.1";
+f1
+2006-01-01
+select f2 from t1 where f2 between "12:1:2" and "12:2:2";
+f2
+12:01:02
+select f2 from t1 where time(f2) between "12:1:2" and "12:2:2";
+f2
+12:01:02
+select f3 from t1 where f3 between "2006-1-1 12:1:1" and "2006-1-1 12:1:2";
+f3
+2006-01-01 12:01:01
+select f3 from t1 where timestamp(f3) between "2006-1-1 12:1:1" and "2006-1-1 12:1:2";
+f3
+2006-01-01 12:01:01
+select f1 from t1 where "2006-1-1" between f1 and f3;
+f1
+2006-01-01
+select f1 from t1 where "2006-1-1" between date(f1) and date(f3);
+f1
+2006-01-01
+select f1 from t1 where "2006-1-1" between f1 and 'zzz';
+f1
+Warnings:
+Warning 1292 Truncated incorrect date value: 'zzz'
+select f1 from t1 where makedate(2006,1) between date(f1) and date(f3);
+f1
+2006-01-01
+select f1 from t1 where makedate(2006,2) between date(f1) and date(f3);
+f1
+2006-01-02
+drop table t1;
explain extended select timestampdiff(SQL_TSI_WEEK, '2001-02-01', '2001-05-01') as a1,
timestampdiff(SQL_TSI_FRAC_SECOND, '2001-02-01 12:59:59.120000', '2001-05-01 12:58:58.119999') as a2;
id select_type table type possible_keys key key_len ref rows Extra
diff --git a/mysql-test/t/func_concat.test b/mysql-test/t/func_concat.test
index 42201961222..5487ad9c56b 100644
--- a/mysql-test/t/func_concat.test
+++ b/mysql-test/t/func_concat.test
@@ -52,6 +52,13 @@ select 'a' union select concat('a', -0.0);
--replace_result a-0.0000 a0.0000
select 'a' union select concat('a', -0.0000);
+#
+# Bug#16716: subselect in concat() may lead to a wrong result
+#
+select concat((select x from (select 'a' as x) as t1 ),
+ (select y from (select 'b' as y) as t2 )) from (select 1 union select 2 )
+ as t3;
+
# End of 4.1 tests
#
diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test
index 1c7f387e354..a76801a26fc 100644
--- a/mysql-test/t/func_time.test
+++ b/mysql-test/t/func_time.test
@@ -367,6 +367,26 @@ select last_day('2005-01-00');
select monthname(str_to_date(null, '%m')), monthname(str_to_date(null, '%m')),
monthname(str_to_date(1, '%m')), monthname(str_to_date(0, '%m'));
+#
+# Bug#16377 result of DATE/TIME functions were compared as strings which
+# can lead to a wrong result.
+#
+create table t1(f1 date, f2 time, f3 datetime);
+insert into t1 values ("2006-01-01", "12:01:01", "2006-01-01 12:01:01");
+insert into t1 values ("2006-01-02", "12:01:02", "2006-01-02 12:01:02");
+select f1 from t1 where f1 between "2006-1-1" and 20060101;
+select f1 from t1 where f1 between "2006-1-1" and "2006.1.1";
+select f1 from t1 where date(f1) between "2006-1-1" and "2006.1.1";
+select f2 from t1 where f2 between "12:1:2" and "12:2:2";
+select f2 from t1 where time(f2) between "12:1:2" and "12:2:2";
+select f3 from t1 where f3 between "2006-1-1 12:1:1" and "2006-1-1 12:1:2";
+select f3 from t1 where timestamp(f3) between "2006-1-1 12:1:1" and "2006-1-1 12:1:2";
+select f1 from t1 where "2006-1-1" between f1 and f3;
+select f1 from t1 where "2006-1-1" between date(f1) and date(f3);
+select f1 from t1 where "2006-1-1" between f1 and 'zzz';
+select f1 from t1 where makedate(2006,1) between date(f1) and date(f3);
+select f1 from t1 where makedate(2006,2) between date(f1) and date(f3);
+drop table t1;
# End of 4.1 tests
explain extended select timestampdiff(SQL_TSI_WEEK, '2001-02-01', '2001-05-01') as a1,
diff --git a/sql/field.cc b/sql/field.cc
index a920d6d91b1..64f888eb24d 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -9037,7 +9037,11 @@ bool
Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code,
int cuted_increment)
{
- THD *thd= table->in_use;
+ /*
+ If this field was created only for type conversion purposes it
+ will have table == NULL.
+ */
+ THD *thd= table ? table->in_use : current_thd;
if (thd->count_cuted_fields)
{
thd->cuted_fields+= cuted_increment;
@@ -9074,7 +9078,8 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
{
if (table->in_use->really_abort_on_warning() ||
set_warning(level, code, cuted_increment))
- make_truncated_value_warning(table->in_use, str, str_length, ts_type,
+ make_truncated_value_warning(table ? table->in_use : current_thd,
+ str, str_length, ts_type,
field_name);
}
@@ -9106,8 +9111,8 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
{
char str_nr[22];
char *str_end= longlong10_to_str(nr, str_nr, -10);
- make_truncated_value_warning(table->in_use, str_nr,
- (uint) (str_end - str_nr),
+ make_truncated_value_warning(table ? table->in_use : current_thd,
+ str_nr, (uint) (str_end - str_nr),
ts_type, field_name);
}
}
@@ -9139,7 +9144,35 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
/* DBL_DIG is enough to print '-[digits].E+###' */
char str_nr[DBL_DIG + 8];
uint str_len= my_sprintf(str_nr, (str_nr, "%g", nr));
- make_truncated_value_warning(table->in_use, str_nr, str_len, ts_type,
+ make_truncated_value_warning(table ? table->in_use : current_thd,
+ str_nr, str_len, ts_type,
field_name);
}
}
+
+/*
+ maximum possible display length for blob
+
+ SYNOPSIS
+ Field_blob::max_length()
+
+ RETURN
+ length
+*/
+uint32 Field_blob::max_length()
+{
+ switch (packlength)
+ {
+ case 1:
+ return 255 * field_charset->mbmaxlen;
+ case 2:
+ return 65535 * field_charset->mbmaxlen;
+ case 3:
+ return 16777215 * field_charset->mbmaxlen;
+ case 4:
+ return (uint32) 4294967295U;
+ default:
+ DBUG_ASSERT(0); // we should never go here
+ return 0;
+ }
+}
diff --git a/sql/item.h b/sql/item.h
index 2311133b86b..2cadfda6895 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -794,6 +794,14 @@ public:
{
return 0;
}
+ /*
+ result_as_longlong() must return TRUE for Items representing DATE/TIME
+ functions and DATE/TIME table fields.
+ Those Items have result_type()==STRING_RESULT (and not INT_RESULT), but
+ their values should be compared as integers (because the integer
+ representation is more precise than the string one).
+ */
+ virtual bool result_as_longlong() { return FALSE; }
};
@@ -1219,6 +1227,10 @@ public:
return 0;
}
void cleanup();
+ bool result_as_longlong()
+ {
+ return field->can_be_compared_as_longlong();
+ }
Item_equal *find_item_equal(COND_EQUAL *cond_equal);
Item *equal_fields_propagator(byte *arg);
Item *set_no_const_sub(byte *arg);
@@ -1827,6 +1839,10 @@ public:
bool walk(Item_processor processor, byte *arg)
{ return (*ref)->walk(processor, arg); }
void print(String *str);
+ bool result_as_longlong()
+ {
+ return (*ref)->result_as_longlong();
+ }
void cleanup();
Item_field *filed_for_view_update()
{ return (*ref)->filed_for_view_update(); }
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index cbf77507b84..6a1ec1de7e7 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -68,6 +68,7 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
SYNOPSIS:
agg_cmp_type()
+ thd thread handle
type [out] the aggregated type
items array of items to aggregate the type from
nitems number of items in the array
@@ -82,36 +83,133 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
If all items are constants the type will be aggregated from all items.
If there are some non-constant items then only types of non-constant
items will be used for aggregation.
+ If there are DATE/TIME fields/functions in the list and no string
+ fields/functions in the list then:
+ The INT_RESULT type will be used for aggregation instead of orginal
+ result type of any DATE/TIME field/function in the list
+ All constant items in the list will be converted to a DATE/TIME using
+ found field or result field of found function.
+
+ Implementation notes:
+ The code is equvalent to:
+ 1. Check the list for presense of a STRING field/function.
+ Collect the is_const flag.
+ 2. Get a Field* object to use for type coercion
+ 3. Perform type conversion.
+ 1 and 2 are implemented in 2 loops. The first searches for a DATE/TIME
+ field/function and checks presense of a STRING field/function.
+ The second loop works only if a DATE/TIME field/function is found.
+ It checks presense of a STRING field/function in the rest of the list.
+
+ TODO
+ 1) The current implementation can produce false comparison results for
+ expressions like:
+ date_time_field BETWEEN string_field_with_dates AND string_constant
+ if the string_constant will omit some of leading zeroes.
+ In order to fully implement correct comparison of DATE/TIME the new
+ DATETIME_RESULT result type should be introduced and agg_cmp_type()
+ should return the DATE/TIME field used for the conversion. Later
+ this field can be used by comparison functions like Item_func_between to
+ convert string values to ints on the fly and thus return correct results.
+ This modification will affect functions BETWEEN, IN and CASE.
+
+ 2) If in the list a DATE field/function and a DATETIME field/function
+ are present in the list then the first found field/function will be
+ used for conversion. This may lead to wrong results and probably should
+ be fixed.
*/
static void agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems)
{
uint i;
+ Item::Type res;
+ char *buff= NULL;
+ uchar null_byte;
Field *field= NULL;
- /* If the first argument is a FIELD_ITEM, pull out the field. */
- if (items[0]->real_item()->type() == Item::FIELD_ITEM)
- field=((Item_field *)(items[0]->real_item()))->field;
- /* But if it can't be compared as a longlong, we don't really care. */
- if (field && !field->can_be_compared_as_longlong())
- field= NULL;
-
- type[0]= items[0]->result_type();
+ /* Search for date/time fields/functions */
+ for (i= 0; i < nitems; i++)
+ {
+ if (!items[i]->result_as_longlong())
+ {
+ /* Do not convert anything if a string field/function is present */
+ if (!items[i]->const_item() && items[i]->result_type() == STRING_RESULT)
+ {
+ i= nitems;
+ break;
+ }
+ continue;
+ }
+ if ((res= items[i]->real_item()->type()) == Item::FIELD_ITEM)
+ {
+ field= ((Item_field *)items[i]->real_item())->field;
+ break;
+ }
+ else if (res == Item::FUNC_ITEM)
+ {
+ field= items[i]->tmp_table_field_from_field_type(0);
+ if (field)
+ buff= alloc_root(thd->mem_root, field->max_length());
+ if (!buff || !field)
+ {
+ if (field)
+ delete field;
+ if (buff)
+ my_free(buff, MYF(MY_WME));
+ field= 0;
+ }
+ else
+ field->move_field(buff, &null_byte, 0);
+ break;
+ }
+ }
+ if (field)
+ {
+ /* Check the rest of the list for presense of a string field/function. */
+ for (i++ ; i < nitems; i++)
+ {
+ if (!items[i]->const_item() && items[i]->result_type() == STRING_RESULT &&
+ !items[i]->result_as_longlong())
+ {
+ field= 0;
+ break;
+ }
+ }
+ }
/* Reset to 0 on first occurence of non-const item. 1 otherwise */
bool is_const= items[0]->const_item();
+ /*
+ If the first item is a date/time function then its result should be
+ compared as int
+ */
+ if (field)
+ {
+ /* Suppose we are comparing dates and some non-constant items are present. */
+ type[0]= INT_RESULT;
+ is_const= 0;
+ }
+ else
+ type[0]= items[0]->result_type();
- for (i= 1 ; i < nitems ; i++)
+ for (i= 0; i < nitems ; i++)
{
if (!items[i]->const_item())
{
- type[0]= is_const ? items[i]->result_type() :
- item_cmp_type(type[0], items[i]->result_type());
+ Item_result result= field && items[i]->result_as_longlong() ?
+ INT_RESULT : items[i]->result_type();
+ type[0]= is_const ? result : item_cmp_type(type[0], result);
is_const= 0;
}
else if (is_const)
type[0]= item_cmp_type(type[0], items[i]->result_type());
- else if (field && convert_constant_item(thd, field, &items[i]))
- type[0]= INT_RESULT;
+ else if (field)
+ convert_constant_item(thd, field, &items[i]);
+ }
+
+ if (res == Item::FUNC_ITEM && field)
+ {
+ delete field;
+ my_free(buff, MYF(MY_WME));
}
}
@@ -1129,9 +1227,8 @@ void Item_func_between::fix_length_and_dec()
return;
agg_cmp_type(thd, &cmp_type, args, 3);
- if (cmp_type == STRING_RESULT &&
- agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV))
- return;
+ if (cmp_type == STRING_RESULT)
+ agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV);
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 1cfdcef02d0..340bf2bb2bf 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -45,8 +45,11 @@ public:
int set_compare_func(Item_bool_func2 *owner, Item_result type);
inline int set_compare_func(Item_bool_func2 *owner_arg)
{
- return set_compare_func(owner_arg, item_cmp_type((*a)->result_type(),
- (*b)->result_type()));
+ Item_result ar= (*a)->result_as_longlong() && (*b)->const_item() ?
+ INT_RESULT : (*a)->result_type();
+ Item_result br= (*b)->result_as_longlong() && (*a)->const_item() ?
+ INT_RESULT : (*b)->result_type();
+ return set_compare_func(owner_arg, item_cmp_type(ar, br));
}
inline int set_cmp_func(Item_bool_func2 *owner_arg,
Item **a1, Item **a2,
@@ -59,8 +62,11 @@ public:
inline int set_cmp_func(Item_bool_func2 *owner_arg,
Item **a1, Item **a2)
{
- return set_cmp_func(owner_arg, a1, a2, item_cmp_type((*a1)->result_type(),
- (*a2)->result_type()));
+ Item_result ar= (*a1)->result_as_longlong() && (*a2)->const_item() ?
+ INT_RESULT : (*a1)->result_type();
+ Item_result br= (*a2)->result_as_longlong() && (*a1)->const_item() ?
+ INT_RESULT : (*a2)->result_type();
+ return set_cmp_func(owner_arg, a1, a2, item_cmp_type(ar, br));
}
inline int compare() { return (this->*func)(); }
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index d8082440f1a..c7fa049a0d5 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -288,11 +288,13 @@ String *Item_func_concat::val_str(String *str)
DBUG_ASSERT(fixed == 1);
String *res,*res2,*use_as_buff;
uint i;
+ bool is_const= 0;
null_value=0;
if (!(res=args[0]->val_str(str)))
goto null;
use_as_buff= &tmp_value;
+ is_const= args[0]->const_item();
for (i=1 ; i < arg_count ; i++)
{
if (res->length() == 0)
@@ -315,7 +317,7 @@ String *Item_func_concat::val_str(String *str)
current_thd->variables.max_allowed_packet);
goto null;
}
- if (res->alloced_length() >= res->length()+res2->length())
+ if (!is_const && res->alloced_length() >= res->length()+res2->length())
{ // Use old buffer
res->append(*res2);
}
@@ -370,6 +372,7 @@ String *Item_func_concat::val_str(String *str)
res= &tmp_value;
use_as_buff=str;
}
+ is_const= 0;
}
}
res->set_charset(collation.collation);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index ca7028dae1e..efaccf674ef 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2464,6 +2464,20 @@ String *Item_datetime_typecast::val_str(String *str)
}
+longlong Item_datetime_typecast::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ TIME ltime;
+ if (get_arg0_date(&ltime,1))
+ {
+ null_value= 1;
+ return 0;
+ }
+
+ return TIME_to_ulonglong_datetime(&ltime);
+}
+
+
bool Item_time_typecast::get_time(TIME *ltime)
{
bool res= get_arg0_time(ltime);
@@ -2478,6 +2492,17 @@ bool Item_time_typecast::get_time(TIME *ltime)
}
+longlong Item_time_typecast::val_int()
+{
+ TIME ltime;
+ if (get_time(&ltime))
+ {
+ null_value= 1;
+ return 0;
+ }
+ return ltime.hour * 10000L + ltime.minute * 100 + ltime.second;
+}
+
String *Item_time_typecast::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
@@ -2517,6 +2542,14 @@ String *Item_date_typecast::val_str(String *str)
return 0;
}
+longlong Item_date_typecast::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ TIME ltime;
+ if (args[0]->get_date(&ltime, TIME_FUZZY_DATE))
+ return 0;
+ return (longlong) (ltime.year * 10000L + ltime.month * 100 + ltime.day);
+}
/*
MAKEDATE(a,b) is a date function that creates a date value
@@ -2553,6 +2586,33 @@ err:
}
+longlong Item_func_makedate::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ TIME l_time;
+ long daynr= (long) args[1]->val_int();
+ long yearnr= (long) args[0]->val_int();
+ long days;
+
+ if (args[0]->null_value || args[1]->null_value ||
+ yearnr < 0 || daynr <= 0)
+ goto err;
+
+ days= calc_daynr(yearnr,1,1) + daynr - 1;
+ /* Day number from year 0 to 9999-12-31 */
+ if (days >= 0 && days < MAX_DAY_NUMBER)
+ {
+ null_value=0;
+ get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day);
+ return (longlong) (l_time.year * 10000L + l_time.month * 100 + l_time.day);
+ }
+
+err:
+ null_value= 1;
+ return 0;
+}
+
+
void Item_func_add_time::fix_length_and_dec()
{
enum_field_types arg0_field_type;
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index b2f0dab0837..24960bf9ed2 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -344,6 +344,7 @@ public:
{
return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
}
+ bool result_as_longlong() { return TRUE; }
};
@@ -359,6 +360,7 @@ public:
{
return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin));
}
+ bool result_as_longlong() { return TRUE; }
};
@@ -388,6 +390,7 @@ public:
TIME representation using UTC-SYSTEM or per-thread time zone.
*/
virtual void store_now_in_TIME(TIME *now_time)=0;
+ bool result_as_longlong() { return TRUE; }
};
@@ -622,6 +625,7 @@ public:
{
return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
}
+ bool result_as_longlong() { return TRUE; }
};
/*
@@ -752,6 +756,8 @@ public:
max_length= 10;
maybe_null= 1;
}
+ bool result_as_longlong() { return TRUE; }
+ longlong val_int();
};
@@ -768,6 +774,8 @@ public:
{
return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
}
+ bool result_as_longlong() { return TRUE; }
+ longlong val_int();
};
@@ -783,6 +791,8 @@ public:
{
return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin));
}
+ bool result_as_longlong() { return TRUE; }
+ longlong val_int();
};
class Item_func_makedate :public Item_str_func
@@ -801,6 +811,8 @@ public:
{
return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
}
+ bool result_as_longlong() { return TRUE; }
+ longlong val_int();
};
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 4a7ec0c5928..9770198640c 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -569,10 +569,6 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
break; // Found a part od the key for the field
}
-#if 0
- if (part->length != (((Item_field*) args[0])->field)->field_length)
- return 0;
-#endif
bool is_field_part= part == field_part;
if (!(is_field_part || eq_type))
return 0;
diff --git a/sql/structs.h b/sql/structs.h
index 9421ebdc2af..41b5f3b39c5 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -70,7 +70,13 @@ typedef struct st_key_part_info { /* Info about a key part */
Field *field;
uint offset; /* offset in record (from 0) */
uint null_offset; /* Offset to null_bit in record */
- uint16 length; /* Length of key_part */
+ uint16 length; /* Length of keypart value in bytes */
+ /*
+ Number of bytes required to store the keypart value. This may be
+ different from the "length" field as it also counts
+ - possible NULL-flag byte (see HA_KEY_NULL_LENGTH)
+ - possible HA_KEY_BLOB_LENGTH bytes needed to store actual value length.
+ */
uint16 store_length;
uint16 key_type;
uint16 fieldnr; /* Fieldnum in UNIREG */