Commit 1fd1f3d4 authored by unknown's avatar unknown

Merge ibabaev@bk-internal.mysql.com:/home/bk/mysql-5.0-opt

into  rurik.mysql.com:/home/igor/mysql-5.0-opt


sql/field.cc:
  Auto merged
sql/opt_sum.cc:
  Auto merged
parents 52243b83 cafb1155
......@@ -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)
......
......@@ -39,3 +39,33 @@ select * from t1;
a
1
drop table t1;
CREATE TABLE t1 ( a int(10) NOT NULL auto_increment, PRIMARY KEY (a));
insert delayed into t1 values(null);
insert into t1 values(null);
insert into t1 values(null);
insert delayed into t1 values(null);
insert delayed into t1 values(null);
insert delayed into t1 values(null);
insert into t1 values(null);
insert into t1 values(null);
insert into t1 values(null);
delete from t1 where a=6;
insert delayed into t1 values(null);
insert delayed into t1 values(null);
insert delayed into t1 values(null);
insert delayed into t1 values(null);
select * from t1 order by a;
a
1
2
3
4
5
7
8
9
10
11
12
13
DROP TABLE t1;
......@@ -68,3 +68,17 @@ select 'a' union select concat('a', -0.0000);
a
a
a0.0000
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
create table t1(f1 varchar(6)) charset=utf8;
insert into t1 values ("123456");
select concat(f1, 2) a from t1 union select 'x' a from t1;
a
1234562
x
drop table t1;
......@@ -751,6 +751,49 @@ 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 Incorrect date value: 'zzz' for column 'f1' at row 1
Warning 1292 Truncated incorrect INTEGER value: 'zzz'
Warning 1292 Truncated incorrect INTEGER 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
......
......@@ -24,3 +24,9 @@ a b
63 default_value
127 last
drop table t1;
CREATE TABLE t1 (f1 INT);
CREATE VIEW v1 AS SELECT f1 FROM t1 WHERE f1 = 0 WITH CHECK OPTION;
REPLACE INTO v1 (f1) VALUES (1);
ERROR HY000: CHECK OPTION failed 'test.v1'
DROP TABLE t1;
DROP VIEW v1;
......@@ -3359,3 +3359,23 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 range PRIMARY,b b 5 NULL 3 Using where
1 SIMPLE t2 ref c c 5 test.t1.a 2 Using where
DROP TABLE t1, t2;
create table t1 (
a int unsigned not null auto_increment primary key,
b bit not null,
c bit not null
);
create table t2 (
a int unsigned not null auto_increment primary key,
b bit not null,
c int unsigned not null,
d varchar(50)
);
insert into t1 (b,c) values (0,1), (0,1);
insert into t2 (b,c) values (0,1);
select t1.a, t1.b + 0, t1.c + 0, t2.a, t2.b + 0, t2.c, t2.d
from t1 left outer join t2 on t1.a = t2.c and t2.b <> 1
where t1.b <> 1 order by t1.a;
a t1.b + 0 t1.c + 0 a t2.b + 0 c d
1 0 1 1 0 1 NULL
2 0 1 NULL NULL NULL NULL
drop table t1,t2;
......@@ -1306,3 +1306,48 @@ id
5
99
drop table t1;
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1));
avg(1)
NULL
......@@ -50,3 +50,52 @@ insert into t1 values (1);
insert delayed into t1 values (1);
select * from t1;
drop table t1;
#
# Bug #20195: INSERT DELAYED with auto_increment is assigned wrong values
#
CREATE TABLE t1 ( a int(10) NOT NULL auto_increment, PRIMARY KEY (a));
# Make one delayed insert to start the separate thread
insert delayed into t1 values(null);
# Do some normal inserts
insert into t1 values(null);
insert into t1 values(null);
# Discarded, since the delayed-counter is 2, which is already used
insert delayed into t1 values(null);
# Discarded, since the delayed-counter is 3, which is already used
insert delayed into t1 values(null);
# Works, since the delayed-counter is 4, which is unused
insert delayed into t1 values(null);
# Do some more inserts
insert into t1 values(null);
insert into t1 values(null);
insert into t1 values(null);
# Delete one of the above to make a hole
delete from t1 where a=6;
# Discarded, since the delayed-counter is 5, which is already used
insert delayed into t1 values(null);
# Works, since the delayed-counter is 6, which is unused (the row we deleted)
insert delayed into t1 values(null);
# Discarded, since the delayed-counter is 7, which is already used
insert delayed into t1 values(null);
# Works, since the delayed-counter is 8, which is unused
insert delayed into t1 values(null);
# Check what we have now
# must wait so that the delayed thread finishes
# Note: this must be increased if the test fails
--sleep 1
select * from t1 order by a;
DROP TABLE t1;
......@@ -52,4 +52,19 @@ 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
#
# Bug#15962: CONCAT() in UNION may lead to a data trucation.
#
create table t1(f1 varchar(6)) charset=utf8;
insert into t1 values ("123456");
select concat(f1, 2) a from t1 union select 'x' a from t1;
drop table t1;
......@@ -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,
......
......@@ -35,3 +35,13 @@ select * from t1;
drop table t1;
# End of 4.1 tests
#
# Bug#19789: REPLACE was allowed for a VIEW with CHECK OPTION enabled.
#
CREATE TABLE t1 (f1 INT);
CREATE VIEW v1 AS SELECT f1 FROM t1 WHERE f1 = 0 WITH CHECK OPTION;
--error 1369
REPLACE INTO v1 (f1) VALUES (1);
DROP TABLE t1;
DROP VIEW v1;
......@@ -2840,3 +2840,29 @@ EXPLAIN
SELECT a, c, d, f FROM t1,t2 WHERE a=c AND b BETWEEN 4 AND 6 AND a > 0;
DROP TABLE t1, t2;
#
# Bug #18895: BIT values cause joins to fail
#
create table t1 (
a int unsigned not null auto_increment primary key,
b bit not null,
c bit not null
);
create table t2 (
a int unsigned not null auto_increment primary key,
b bit not null,
c int unsigned not null,
d varchar(50)
);
insert into t1 (b,c) values (0,1), (0,1);
insert into t2 (b,c) values (0,1);
-- Row 1 should succeed. Row 2 should fail. Both fail.
select t1.a, t1.b + 0, t1.c + 0, t2.a, t2.b + 0, t2.c, t2.d
from t1 left outer join t2 on t1.a = t2.c and t2.b <> 1
where t1.b <> 1 order by t1.a;
drop table t1,t2;
......@@ -793,3 +793,51 @@ select id from t1 union all select 99 order by 1;
drop table t1;
# End of 4.1 tests
#
# Bug#18175: Union select over 129 tables with a sum function fails.
#
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1)) union
(select avg(1)) union (select avg(1)) union (select avg(1));
......@@ -4530,11 +4530,11 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
int error;
bool have_smth_to_conv;
my_bool in_dst_time_gap;
THD *thd= table->in_use;
THD *thd= table ? table->in_use : current_thd;
/* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
have_smth_to_conv= (str_to_datetime(from, len, &l_time,
(table->in_use->variables.sql_mode &
(thd->variables.sql_mode &
MODE_NO_ZERO_DATE) |
MODE_NO_ZERO_IN_DATE, &error) >
MYSQL_TIMESTAMP_ERROR);
......@@ -4599,7 +4599,7 @@ int Field_timestamp::store(longlong nr, bool unsigned_val)
my_time_t timestamp= 0;
int error;
my_bool in_dst_time_gap;
THD *thd= table->in_use;
THD *thd= table ? table->in_use : current_thd;
/* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
longlong tmp= number_to_datetime(nr, &l_time, (thd->variables.sql_mode &
......@@ -4653,7 +4653,7 @@ longlong Field_timestamp::val_int(void)
{
uint32 temp;
TIME time_tmp;
THD *thd= table->in_use;
THD *thd= table ? table->in_use : current_thd;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
......@@ -4678,7 +4678,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
{
uint32 temp, temp2;
TIME time_tmp;
THD *thd= table->in_use;
THD *thd= table ? table->in_use : current_thd;
char *to;
val_buffer->alloc(field_length+1);
......@@ -4749,7 +4749,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr)
bool Field_timestamp::get_date(TIME *ltime, uint fuzzydate)
{
long temp;
THD *thd= table->in_use;
THD *thd= table ? table->in_use : current_thd;
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
temp=uint4korr(ptr);
......@@ -4832,7 +4832,8 @@ void Field_timestamp::sql_type(String &res) const
void Field_timestamp::set_time()
{
long tmp= (long) table->in_use->query_start();
THD *thd= table ? table->in_use : current_thd;
long tmp= (long) thd->query_start();
set_notnull();
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
......@@ -5024,12 +5025,13 @@ String *Field_time::val_str(String *val_buffer,
bool Field_time::get_date(TIME *ltime, uint fuzzydate)
{
long tmp;
THD *thd= table ? table->in_use : current_thd;
if (!(fuzzydate & TIME_FUZZY_DATE))
{
push_warning_printf(table->in_use, MYSQL_ERROR::WARN_LEVEL_WARN,
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
ER(ER_WARN_DATA_OUT_OF_RANGE), field_name,
table->in_use->row_count);
thd->row_count);
return 1;
}
tmp=(long) sint3korr(ptr);
......@@ -5217,9 +5219,10 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
TIME l_time;
uint32 tmp;
int error;
THD *thd= table ? table->in_use : current_thd;
if (str_to_datetime(from, len, &l_time, TIME_FUZZY_DATE |
(table->in_use->variables.sql_mode &
(thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
MODE_INVALID_DATES)),
&error) <= MYSQL_TIMESTAMP_ERROR)
......@@ -5272,9 +5275,10 @@ int Field_date::store(longlong nr, bool unsigned_val)
TIME not_used;
int error;
longlong initial_nr= nr;
THD *thd= table ? table->in_use : current_thd;
nr= number_to_datetime(nr, &not_used, (TIME_FUZZY_DATE |
(table->in_use->variables.sql_mode &
(thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE |
MODE_NO_ZERO_DATE |
MODE_INVALID_DATES))), &error);
......@@ -5420,9 +5424,10 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
TIME l_time;
long tmp;
int error;
THD *thd= table ? table->in_use : current_thd;
if (str_to_datetime(from, len, &l_time,
(TIME_FUZZY_DATE |
(table->in_use->variables.sql_mode &
(thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
MODE_INVALID_DATES))),
&error) <= MYSQL_TIMESTAMP_ERROR)
......@@ -5460,9 +5465,10 @@ int Field_newdate::store(longlong nr, bool unsigned_val)
TIME l_time;
longlong tmp;
int error;
THD *thd= table ? table->in_use : current_thd;
if (number_to_datetime(nr, &l_time,
(TIME_FUZZY_DATE |
(table->in_use->variables.sql_mode &
(thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
MODE_INVALID_DATES))),
&error) == LL(-1))
......@@ -5605,10 +5611,11 @@ int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
int error;
ulonglong tmp= 0;
enum enum_mysql_timestamp_type func_res;
THD *thd= table ? table->in_use : current_thd;
func_res= str_to_datetime(from, len, &time_tmp,
(TIME_FUZZY_DATE |
(table->in_use->variables.sql_mode &
(thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
MODE_INVALID_DATES))),
&error);
......@@ -5655,9 +5662,10 @@ int Field_datetime::store(longlong nr, bool unsigned_val)
TIME not_used;
int error;
longlong initial_nr= nr;
THD *thd= table ? table->in_use : current_thd;
nr= number_to_datetime(nr, &not_used, (TIME_FUZZY_DATE |
(table->in_use->variables.sql_mode &
(thd->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE |
MODE_NO_ZERO_DATE |
MODE_INVALID_DATES))), &error);
......@@ -9032,7 +9040,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;
......@@ -9067,9 +9079,10 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
const char *str, uint str_length,
timestamp_type ts_type, int cuted_increment)
{
if (table->in_use->really_abort_on_warning() ||
THD *thd= table ? table->in_use : current_thd;
if (thd->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(thd, str, str_length, ts_type,
field_name);
}
......@@ -9096,13 +9109,13 @@ Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
longlong nr, timestamp_type ts_type,
int cuted_increment)
{
if (table->in_use->really_abort_on_warning() ||
THD *thd= table ? table->in_use : current_thd;
if (thd->really_abort_on_warning() ||
set_warning(level, code, cuted_increment))
{
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(thd, str_nr, (uint) (str_end - str_nr),
ts_type, field_name);
}
}
......@@ -9128,13 +9141,15 @@ void
Field::set_datetime_warning(MYSQL_ERROR::enum_warning_level level, uint code,
double nr, timestamp_type ts_type)
{
if (table->in_use->really_abort_on_warning() ||
THD *thd= table ? table->in_use : current_thd;
if (thd->really_abort_on_warning() ||
set_warning(level, code, 1))
{
/* 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(thd, str_nr, str_len, ts_type,
field_name);
}
}
......@@ -124,7 +124,7 @@ class Field
static bool type_can_have_key_part(enum_field_types);
static enum_field_types field_type_merge(enum_field_types, enum_field_types);
static Item_result result_merge_type(enum_field_types);
bool eq(Field *field)
virtual bool eq(Field *field)
{
return (ptr == field->ptr && null_ptr == field->null_ptr &&
null_bit == field->null_bit);
......@@ -1358,6 +1358,13 @@ class Field_bit :public Field {
bit_ptr= bit_ptr_arg;
bit_ofs= bit_ofs_arg;
}
bool eq(Field *field)
{
return (Field::eq(field) &&
field->type() == type() &&
bit_ptr == ((Field_bit *)field)->bit_ptr &&
bit_ofs == ((Field_bit *)field)->bit_ofs);
}
};
......
......@@ -794,6 +794,14 @@ class Item {
{
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 @@ class Item_field :public Item_ident
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 @@ class Item_ref :public Item_ident
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(); }
......
......@@ -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));
}
}
......@@ -268,18 +366,18 @@ static bool convert_constant_item(THD *thd, Field *field, Item **item)
if (!(*item)->with_subselect && (*item)->const_item())
{
/* For comparison purposes allow invalid dates like 2000-01-32 */
ulong orig_sql_mode= field->table->in_use->variables.sql_mode;
field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES;
ulong orig_sql_mode= thd->variables.sql_mode;
thd->variables.sql_mode|= MODE_INVALID_DATES;
if (!(*item)->save_in_field(field, 1) && !((*item)->null_value))
{
Item *tmp=new Item_int_with_ref(field->val_int(), *item,
test(field->flags & UNSIGNED_FLAG));
field->table->in_use->variables.sql_mode= orig_sql_mode;
thd->variables.sql_mode= orig_sql_mode;
if (tmp)
thd->change_item_tree(item, tmp);
return 1; // Item was replaced
}
field->table->in_use->variables.sql_mode= orig_sql_mode;
thd->variables.sql_mode= orig_sql_mode;
}
return 0;
}
......@@ -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);
}
......
......@@ -59,7 +59,8 @@ class Arg_comparator: public Sql_alloc
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(),
return set_cmp_func(owner_arg, a1, a2,
item_cmp_type((*a1)->result_type(),
(*a2)->result_type()));
}
inline int compare() { return (this->*func)(); }
......
......@@ -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);
......@@ -389,7 +392,14 @@ void Item_func_concat::fix_length_and_dec()
return;
for (uint i=0 ; i < arg_count ; i++)
{
if (args[i]->collation.collation->mbmaxlen != collation.collation->mbmaxlen)
max_result_length+= (args[i]->max_length /
args[i]->collation.collation->mbmaxlen) *
collation.collation->mbmaxlen;
else
max_result_length+= args[i]->max_length;
}
if (max_result_length >= MAX_BLOB_WIDTH)
{
......
......@@ -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 @@ String *Item_func_makedate::val_str(String *str)
}
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;
......
......@@ -344,6 +344,7 @@ class Item_date :public Item_func
{
return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
}
bool result_as_longlong() { return TRUE; }
};
......@@ -359,6 +360,7 @@ class Item_date_func :public Item_str_func
{
return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin));
}
bool result_as_longlong() { return TRUE; }
};
......@@ -388,6 +390,7 @@ class Item_func_curtime :public Item_func
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 @@ class Item_func_sec_to_time :public Item_str_func
{
return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
}
bool result_as_longlong() { return TRUE; }
};
/*
......@@ -752,6 +756,8 @@ class Item_date_typecast :public Item_typecast_maybe_null
max_length= 10;
maybe_null= 1;
}
bool result_as_longlong() { return TRUE; }
longlong val_int();
};
......@@ -768,6 +774,8 @@ class Item_time_typecast :public Item_typecast_maybe_null
{
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 @@ class Item_datetime_typecast :public Item_typecast_maybe_null
{
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 @@ class Item_func_makedate :public Item_str_func
{
return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
}
bool result_as_longlong() { return TRUE; }
longlong val_int();
};
......
......@@ -1938,6 +1938,14 @@ bool delayed_insert::handle_inserts(void)
if (!using_bin_log)
table->file->extra(HA_EXTRA_WRITE_CACHE);
pthread_mutex_lock(&mutex);
/* Reset auto-increment cacheing */
if (thd.clear_next_insert_id)
{
thd.next_insert_id= 0;
thd.clear_next_insert_id= 0;
}
while ((row=rows.get()))
{
stacked_inserts--;
......
......@@ -1000,6 +1000,8 @@ typedef struct st_lex
case SQLCOM_UPDATE_MULTI:
case SQLCOM_INSERT:
case SQLCOM_INSERT_SELECT:
case SQLCOM_REPLACE:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_LOAD:
return TRUE;
default:
......
......@@ -8752,6 +8752,8 @@ union_list:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
/* This counter shouldn't be incremented for UNION parts */
Lex->nest_level--;
if (mysql_new_select(lex, 0))
YYABORT;
mysql_init_select(lex);
......
......@@ -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 */
......
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