Commit e35a0ca4 authored by evgen@moonbone.local's avatar evgen@moonbone.local

Manually merged

parents 36fae7be c9077f07
...@@ -71,6 +71,7 @@ static int port= 0; ...@@ -71,6 +71,7 @@ static int port= 0;
static const char* sock= 0; static const char* sock= 0;
static const char* user = 0; static const char* user = 0;
static char* pass = 0; static char* pass = 0;
static char *charset= 0;
static ulonglong start_position, stop_position; static ulonglong start_position, stop_position;
#define start_position_mot ((my_off_t)start_position) #define start_position_mot ((my_off_t)start_position)
...@@ -707,6 +708,9 @@ static struct my_option my_long_options[] = ...@@ -707,6 +708,9 @@ static struct my_option my_long_options[] =
"Used to reserve file descriptors for usage by this program", "Used to reserve file descriptors for usage by this program",
(gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG, (gptr*) &open_files_limit, (gptr*) &open_files_limit, 0, GET_ULONG,
REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0}, 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.", {"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, (gptr*) &short_form, (gptr*) &short_form, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0}, 0, 0},
...@@ -1422,6 +1426,12 @@ int main(int argc, char** argv) ...@@ -1422,6 +1426,12 @@ int main(int argc, char** argv)
fprintf(result_file, fprintf(result_file,
"/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n"); "/*!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 In mysqlbinlog|mysql, don't want mysql to be disconnected after each
transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2). transaction (which would be the case with GLOBAL.COMPLETION_TYPE==2).
...@@ -1454,6 +1464,12 @@ int main(int argc, char** argv) ...@@ -1454,6 +1464,12 @@ int main(int argc, char** argv)
if (disable_log_bin) if (disable_log_bin)
fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n"); 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) if (tmpdir.list)
free_tmpdir(&tmpdir); free_tmpdir(&tmpdir);
if (result_file != stdout) if (result_file != stdout)
......
...@@ -254,7 +254,7 @@ cast("2001-1-1" as datetime) = "2001-01-01 00:00:00" ...@@ -254,7 +254,7 @@ cast("2001-1-1" as datetime) = "2001-01-01 00:00:00"
1 1
select cast("1:2:3" as TIME) = "1:02:03"; select cast("1:2:3" as TIME) = "1:02:03";
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); select cast(NULL as DATE);
cast(NULL as DATE) cast(NULL as DATE)
NULL NULL
......
...@@ -75,3 +75,10 @@ a ...@@ -75,3 +75,10 @@ a
1234562 1234562
x x
drop table t1; 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
...@@ -751,6 +751,47 @@ select monthname(str_to_date(null, '%m')), monthname(str_to_date(null, '%m')), ...@@ -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(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')) 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 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, 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; 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 id select_type table type possible_keys key key_len ref rows Extra
......
...@@ -52,6 +52,13 @@ select 'a' union select concat('a', -0.0); ...@@ -52,6 +52,13 @@ select 'a' union select concat('a', -0.0);
--replace_result a-0.0000 a0.0000 --replace_result a-0.0000 a0.0000
select 'a' union select concat('a', -0.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 # End of 4.1 tests
# #
......
...@@ -367,6 +367,26 @@ select last_day('2005-01-00'); ...@@ -367,6 +367,26 @@ select last_day('2005-01-00');
select monthname(str_to_date(null, '%m')), monthname(str_to_date(null, '%m')), 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(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 # End of 4.1 tests
explain extended select timestampdiff(SQL_TSI_WEEK, '2001-02-01', '2001-05-01') as a1, explain extended select timestampdiff(SQL_TSI_WEEK, '2001-02-01', '2001-05-01') as a1,
......
...@@ -9037,7 +9037,11 @@ bool ...@@ -9037,7 +9037,11 @@ bool
Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code, Field::set_warning(MYSQL_ERROR::enum_warning_level level, uint code,
int cuted_increment) 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) if (thd->count_cuted_fields)
{ {
thd->cuted_fields+= cuted_increment; thd->cuted_fields+= cuted_increment;
...@@ -9074,7 +9078,8 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, ...@@ -9074,7 +9078,8 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
{ {
if (table->in_use->really_abort_on_warning() || if (table->in_use->really_abort_on_warning() ||
set_warning(level, code, cuted_increment)) 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); field_name);
} }
...@@ -9106,8 +9111,8 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, ...@@ -9106,8 +9111,8 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
{ {
char str_nr[22]; char str_nr[22];
char *str_end= longlong10_to_str(nr, str_nr, -10); char *str_end= longlong10_to_str(nr, str_nr, -10);
make_truncated_value_warning(table->in_use, str_nr, make_truncated_value_warning(table ? table->in_use : current_thd,
(uint) (str_end - str_nr), str_nr, (uint) (str_end - str_nr),
ts_type, field_name); ts_type, field_name);
} }
} }
...@@ -9139,7 +9144,35 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code, ...@@ -9139,7 +9144,35 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
/* DBL_DIG is enough to print '-[digits].E+###' */ /* DBL_DIG is enough to print '-[digits].E+###' */
char str_nr[DBL_DIG + 8]; char str_nr[DBL_DIG + 8];
uint str_len= my_sprintf(str_nr, (str_nr, "%g", nr)); 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); 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;
}
}
...@@ -794,6 +794,14 @@ public: ...@@ -794,6 +794,14 @@ public:
{ {
return 0; 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: ...@@ -1219,6 +1227,10 @@ public:
return 0; return 0;
} }
void cleanup(); void cleanup();
bool result_as_longlong()
{
return field->can_be_compared_as_longlong();
}
Item_equal *find_item_equal(COND_EQUAL *cond_equal); Item_equal *find_item_equal(COND_EQUAL *cond_equal);
Item *equal_fields_propagator(byte *arg); Item *equal_fields_propagator(byte *arg);
Item *set_no_const_sub(byte *arg); Item *set_no_const_sub(byte *arg);
...@@ -1827,6 +1839,10 @@ public: ...@@ -1827,6 +1839,10 @@ public:
bool walk(Item_processor processor, byte *arg) bool walk(Item_processor processor, byte *arg)
{ return (*ref)->walk(processor, arg); } { return (*ref)->walk(processor, arg); }
void print(String *str); void print(String *str);
bool result_as_longlong()
{
return (*ref)->result_as_longlong();
}
void cleanup(); void cleanup();
Item_field *filed_for_view_update() Item_field *filed_for_view_update()
{ return (*ref)->filed_for_view_update(); } { return (*ref)->filed_for_view_update(); }
......
...@@ -68,6 +68,7 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) ...@@ -68,6 +68,7 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems)
SYNOPSIS: SYNOPSIS:
agg_cmp_type() agg_cmp_type()
thd thread handle
type [out] the aggregated type type [out] the aggregated type
items array of items to aggregate the type from items array of items to aggregate the type from
nitems number of items in the array nitems number of items in the array
...@@ -82,36 +83,133 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) ...@@ -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 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 If there are some non-constant items then only types of non-constant
items will be used for aggregation. 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) static void agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems)
{ {
uint i; uint i;
Item::Type res;
char *buff= NULL;
uchar null_byte;
Field *field= NULL; Field *field= NULL;
/* If the first argument is a FIELD_ITEM, pull out the field. */ /* Search for date/time fields/functions */
if (items[0]->real_item()->type() == Item::FIELD_ITEM) for (i= 0; i < nitems; i++)
field=((Item_field *)(items[0]->real_item()))->field; {
/* But if it can't be compared as a longlong, we don't really care. */ if (!items[i]->result_as_longlong())
if (field && !field->can_be_compared_as_longlong()) {
field= NULL; /* Do not convert anything if a string field/function is present */
if (!items[i]->const_item() && items[i]->result_type() == STRING_RESULT)
type[0]= items[0]->result_type(); {
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 */ /* Reset to 0 on first occurence of non-const item. 1 otherwise */
bool is_const= items[0]->const_item(); 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()) if (!items[i]->const_item())
{ {
type[0]= is_const ? items[i]->result_type() : Item_result result= field && items[i]->result_as_longlong() ?
item_cmp_type(type[0], items[i]->result_type()); INT_RESULT : items[i]->result_type();
type[0]= is_const ? result : item_cmp_type(type[0], result);
is_const= 0; is_const= 0;
} }
else if (is_const) else if (is_const)
type[0]= item_cmp_type(type[0], items[i]->result_type()); type[0]= item_cmp_type(type[0], items[i]->result_type());
else if (field && convert_constant_item(thd, field, &items[i])) else if (field)
type[0]= INT_RESULT; 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() ...@@ -1129,9 +1227,8 @@ void Item_func_between::fix_length_and_dec()
return; return;
agg_cmp_type(thd, &cmp_type, args, 3); agg_cmp_type(thd, &cmp_type, args, 3);
if (cmp_type == STRING_RESULT && if (cmp_type == STRING_RESULT)
agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV)) agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV);
return;
} }
......
...@@ -45,8 +45,11 @@ public: ...@@ -45,8 +45,11 @@ public:
int set_compare_func(Item_bool_func2 *owner, Item_result type); int set_compare_func(Item_bool_func2 *owner, Item_result type);
inline int set_compare_func(Item_bool_func2 *owner_arg) inline int set_compare_func(Item_bool_func2 *owner_arg)
{ {
return set_compare_func(owner_arg, item_cmp_type((*a)->result_type(), Item_result ar= (*a)->result_as_longlong() && (*b)->const_item() ?
(*b)->result_type())); 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, inline int set_cmp_func(Item_bool_func2 *owner_arg,
Item **a1, Item **a2, Item **a1, Item **a2,
...@@ -59,8 +62,11 @@ public: ...@@ -59,8 +62,11 @@ public:
inline int set_cmp_func(Item_bool_func2 *owner_arg, inline int set_cmp_func(Item_bool_func2 *owner_arg,
Item **a1, Item **a2) Item **a1, Item **a2)
{ {
return set_cmp_func(owner_arg, a1, a2, item_cmp_type((*a1)->result_type(), Item_result ar= (*a1)->result_as_longlong() && (*a2)->const_item() ?
(*a2)->result_type())); 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)(); } inline int compare() { return (this->*func)(); }
......
...@@ -288,11 +288,13 @@ String *Item_func_concat::val_str(String *str) ...@@ -288,11 +288,13 @@ String *Item_func_concat::val_str(String *str)
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
String *res,*res2,*use_as_buff; String *res,*res2,*use_as_buff;
uint i; uint i;
bool is_const= 0;
null_value=0; null_value=0;
if (!(res=args[0]->val_str(str))) if (!(res=args[0]->val_str(str)))
goto null; goto null;
use_as_buff= &tmp_value; use_as_buff= &tmp_value;
is_const= args[0]->const_item();
for (i=1 ; i < arg_count ; i++) for (i=1 ; i < arg_count ; i++)
{ {
if (res->length() == 0) if (res->length() == 0)
...@@ -315,7 +317,7 @@ String *Item_func_concat::val_str(String *str) ...@@ -315,7 +317,7 @@ String *Item_func_concat::val_str(String *str)
current_thd->variables.max_allowed_packet); current_thd->variables.max_allowed_packet);
goto null; goto null;
} }
if (res->alloced_length() >= res->length()+res2->length()) if (!is_const && res->alloced_length() >= res->length()+res2->length())
{ // Use old buffer { // Use old buffer
res->append(*res2); res->append(*res2);
} }
...@@ -370,6 +372,7 @@ String *Item_func_concat::val_str(String *str) ...@@ -370,6 +372,7 @@ String *Item_func_concat::val_str(String *str)
res= &tmp_value; res= &tmp_value;
use_as_buff=str; use_as_buff=str;
} }
is_const= 0;
} }
} }
res->set_charset(collation.collation); res->set_charset(collation.collation);
......
...@@ -2464,6 +2464,20 @@ String *Item_datetime_typecast::val_str(String *str) ...@@ -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 Item_time_typecast::get_time(TIME *ltime)
{ {
bool res= get_arg0_time(ltime); bool res= get_arg0_time(ltime);
...@@ -2478,6 +2492,17 @@ bool Item_time_typecast::get_time(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) String *Item_time_typecast::val_str(String *str)
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
...@@ -2517,6 +2542,14 @@ String *Item_date_typecast::val_str(String *str) ...@@ -2517,6 +2542,14 @@ String *Item_date_typecast::val_str(String *str)
return 0; 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 MAKEDATE(a,b) is a date function that creates a date value
...@@ -2553,6 +2586,33 @@ err: ...@@ -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() void Item_func_add_time::fix_length_and_dec()
{ {
enum_field_types arg0_field_type; enum_field_types arg0_field_type;
......
...@@ -344,6 +344,7 @@ public: ...@@ -344,6 +344,7 @@ public:
{ {
return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
} }
bool result_as_longlong() { return TRUE; }
}; };
...@@ -359,6 +360,7 @@ public: ...@@ -359,6 +360,7 @@ public:
{ {
return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin));
} }
bool result_as_longlong() { return TRUE; }
}; };
...@@ -388,6 +390,7 @@ public: ...@@ -388,6 +390,7 @@ public:
TIME representation using UTC-SYSTEM or per-thread time zone. TIME representation using UTC-SYSTEM or per-thread time zone.
*/ */
virtual void store_now_in_TIME(TIME *now_time)=0; virtual void store_now_in_TIME(TIME *now_time)=0;
bool result_as_longlong() { return TRUE; }
}; };
...@@ -622,6 +625,7 @@ public: ...@@ -622,6 +625,7 @@ public:
{ {
return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
} }
bool result_as_longlong() { return TRUE; }
}; };
/* /*
...@@ -752,6 +756,8 @@ public: ...@@ -752,6 +756,8 @@ public:
max_length= 10; max_length= 10;
maybe_null= 1; maybe_null= 1;
} }
bool result_as_longlong() { return TRUE; }
longlong val_int();
}; };
...@@ -768,6 +774,8 @@ public: ...@@ -768,6 +774,8 @@ public:
{ {
return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); 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: ...@@ -783,6 +791,8 @@ public:
{ {
return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); 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 class Item_func_makedate :public Item_str_func
...@@ -801,6 +811,8 @@ public: ...@@ -801,6 +811,8 @@ public:
{ {
return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
} }
bool result_as_longlong() { return TRUE; }
longlong val_int();
}; };
......
...@@ -569,10 +569,6 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, ...@@ -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 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; bool is_field_part= part == field_part;
if (!(is_field_part || eq_type)) if (!(is_field_part || eq_type))
return 0; return 0;
......
...@@ -70,7 +70,13 @@ typedef struct st_key_part_info { /* Info about a key part */ ...@@ -70,7 +70,13 @@ typedef struct st_key_part_info { /* Info about a key part */
Field *field; Field *field;
uint offset; /* offset in record (from 0) */ uint offset; /* offset in record (from 0) */
uint null_offset; /* Offset to null_bit in record */ 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 store_length;
uint16 key_type; uint16 key_type;
uint16 fieldnr; /* Fieldnum in UNIREG */ uint16 fieldnr; /* Fieldnum in UNIREG */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment