From d915b63db0fc2d501eed5c7742768df7a31a6187 Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Thu, 22 May 2003 16:00:19 +0200 Subject: [PATCH 01/54] - ISAM storage engine is now disabled by default. To enable it, configure the sources with "--with-isam" --- acinclude.m4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index 269b505386c..e347276dddb 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -868,9 +868,9 @@ AC_SUBST(orbit_idl) AC_DEFUN([MYSQL_CHECK_ISAM], [ AC_ARG_WITH([isam], [ - --without-isam Disable the ISAM table type], + --with-isam Enable the ISAM table type], [with_isam="$withval"], - [with_isam=yes]) + [with_isam=no]) isam_libs= if test X"$with_isam" = X"yes" From 98ffed180888b9e3ec1d7f27f8aa2ae6117522b1 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Fri, 30 May 2003 22:14:52 +0300 Subject: [PATCH 02/54] priventing allocation unused Item_buff (alloc_group_fields()) --- mysql-test/r/subselect.result | 12 ++++++++++ mysql-test/t/subselect.test | 12 ++++++++++ sql/sql_select.cc | 45 +++++++++++++++++++++++++++++++---- sql/sql_select.h | 2 +- 4 files changed, 66 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 41620bb6e7f..0b415587f47 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1134,3 +1134,15 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ref salary salary 5 const 1 Using where 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away drop table t1; +create table t1 (a int, b int); +create table t2 (a int, b int); +create table t3 (a int, b int); +insert into t1 values (0,100),(1,2), (1,3), (2,2), (2,7), (2,-1), (3,10); +insert into t2 values (0,0), (1,1), (2,1), (3,1), (4,1); +insert into t3 values (3,3), (2,2), (1,1); +select a,(select count(distinct t1.b) as sum from t1,t2 where t1.a=t2.a and t2.b > 0 and t1.a <= t3.b group by t1.a order by sum limit 1) from t3; +a (select count(distinct t1.b) as sum from t1,t2 where t1.a=t2.a and t2.b > 0 and t1.a <= t3.b group by t1.a order by sum limit 1) +3 1 +2 2 +1 2 +drop table t1,t2,t3; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 8377a756c5b..b8e820a7f68 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -716,3 +716,15 @@ create table t1 (id int not null auto_increment primary key, salary int, key(sal insert into t1 (salary) values (100),(1000),(10000),(10),(500),(5000),(50000); explain SELECT id FROM t1 where salary = (SELECT MAX(salary) FROM t1); drop table t1; + +# +# alloc_group_fields() working +# +create table t1 (a int, b int); +create table t2 (a int, b int); +create table t3 (a int, b int); +insert into t1 values (0,100),(1,2), (1,3), (2,2), (2,7), (2,-1), (3,10); +insert into t2 values (0,0), (1,1), (2,1), (3,1), (4,1); +insert into t3 values (3,3), (2,2), (1,1); +select a,(select count(distinct t1.b) as sum from t1,t2 where t1.a=t2.a and t2.b > 0 and t1.a <= t3.b group by t1.a order by sum limit 1) from t3; +drop table t1,t2,t3; \ No newline at end of file diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 4167da5802a..6f692b3bfe7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -137,6 +137,7 @@ static ORDER *create_distinct_group(THD *thd, ORDER *order, static bool test_if_subpart(ORDER *a,ORDER *b); static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables); static void calc_group_buffer(JOIN *join,ORDER *group); +static bool make_group_fields(JOIN *main_join, JOIN *curr_join); static bool alloc_group_fields(JOIN *join,ORDER *group); static bool make_sum_func_list(JOIN *join,List &fields); // Create list for using with tempory table @@ -1103,12 +1104,12 @@ JOIN::exec() DBUG_VOID_RETURN; curr_join->exec_tmp_table2= exec_tmp_table2; } - if (group_list) + if (curr_join->group_list) { thd->proc_info= "Creating sort index"; if (create_sort_index(thd, curr_join->join_tab, curr_join->group_list, HA_POS_ERROR, HA_POS_ERROR) || - alloc_group_fields(curr_join, curr_join->group_list)) + make_group_fields(this, curr_join)) { DBUG_VOID_RETURN; } @@ -1176,7 +1177,10 @@ JOIN::exec() if (curr_join->group || curr_join->tmp_table_param.sum_func_count || (procedure && (procedure->flags & PROC_GROUP))) { - alloc_group_fields(curr_join, curr_join->group_list); + if (make_group_fields(this, curr_join)) + { + DBUG_VOID_RETURN; + } if (!items3) { if (!items0) @@ -7525,6 +7529,37 @@ calc_group_buffer(JOIN *join,ORDER *group) join->tmp_table_param.group_null_parts=null_parts; } +/* + alloc group fields or take prepared (chached) + + SYNOPSYS + make_group_fields() + main_join - join of current select + curr_join - current join (join of current select or temporary copy of it) + + RETURN + 0 - ok + 1 - failed +*/ + +static bool +make_group_fields(JOIN *main_join, JOIN *curr_join) +{ + if (main_join->group_fields_cache.elements) + { + curr_join->group_fields= main_join->group_fields_cache; + curr_join->sort_and_group= 1; + } + else + { + if (alloc_group_fields(curr_join, curr_join->group_list)) + { + return (1); + } + main_join->group_fields_cache= curr_join->group_fields; + } + return (0); +} /* Get a list of buffers for saveing last group @@ -7551,6 +7586,7 @@ alloc_group_fields(JOIN *join,ORDER *group) static int test_if_group_changed(List &list) { + DBUG_ENTER("test_if_group_changed"); List_iterator li(list); int idx= -1,i; Item_buff *buff; @@ -7560,7 +7596,8 @@ test_if_group_changed(List &list) if (buff->cmp()) idx=i; } - return idx; + DBUG_PRINT("info", ("idx: %d", idx)); + DBUG_RETURN(idx); } diff --git a/sql/sql_select.h b/sql/sql_select.h index 7f3669f7478..1e0f7314e7c 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -127,7 +127,7 @@ class JOIN :public Sql_alloc POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1]; double best_read; List *fields; - List group_fields; + List group_fields, group_fields_cache; TABLE *tmp_table; // used to store 2 possible tmp table of SELECT TABLE *exec_tmp_table1, *exec_tmp_table2; From 66af4b5c9ab11f2bbe2bc5d9aec9bcee21d8063b Mon Sep 17 00:00:00 2001 From: "gluh@gluh.mysql.r18.ru" <> Date: Mon, 23 Jun 2003 12:56:44 +0500 Subject: [PATCH 03/54] Internal commit --- mysql-test/r/func_sapdb.result | 194 ++++++++++++ mysql-test/t/func_sapdb.test | 97 ++++++ sql/field.cc | 2 + sql/item_create.cc | 35 +++ sql/item_create.h | 7 + sql/item_timefunc.cc | 538 +++++++++++++++++++++++++++++++-- sql/item_timefunc.h | 161 +++++++++- sql/lex.h | 16 +- sql/mysql_priv.h | 1 + sql/protocol.cc | 4 + sql/sql_yacc.yy | 33 ++ sql/time.cc | 13 +- 12 files changed, 1067 insertions(+), 34 deletions(-) create mode 100644 mysql-test/r/func_sapdb.result create mode 100644 mysql-test/t/func_sapdb.test diff --git a/mysql-test/r/func_sapdb.result b/mysql-test/r/func_sapdb.result new file mode 100644 index 00000000000..5c044d00726 --- /dev/null +++ b/mysql-test/r/func_sapdb.result @@ -0,0 +1,194 @@ +drop table if exists t1, test; +select extract(DAY_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +extract(DAY_MICROSECOND FROM "1999-01-02 10:11:12.000123") +2101112000123 +select extract(HOUR_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +extract(HOUR_MICROSECOND FROM "1999-01-02 10:11:12.000123") +101112000123 +select extract(MINUTE_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +extract(MINUTE_MICROSECOND FROM "1999-01-02 10:11:12.000123") +1112000123 +select extract(SECOND_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +extract(SECOND_MICROSECOND FROM "1999-01-02 10:11:12.000123") +12000123 +select extract(MICROSECOND FROM "1999-01-02 10:11:12.000123"); +extract(MICROSECOND FROM "1999-01-02 10:11:12.000123") +123 +select date_format("1997-12-31 23:59:59.000002", "%f"); +date_format("1997-12-31 23:59:59.000002", "%f") +000002 +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000 99:99:99.999999" DAY_MICROSECOND); +date_add("1997-12-31 23:59:59.000002",INTERVAL "10000 99:99:99.999999" DAY_MICROSECOND) +2025-05-23 04:40:39.000001 +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000:99:99.999999" HOUR_MICROSECOND); +date_add("1997-12-31 23:59:59.000002",INTERVAL "10000:99:99.999999" HOUR_MICROSECOND) +1999-02-21 17:40:39.000001 +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000:99.999999" MINUTE_MICROSECOND); +date_add("1997-12-31 23:59:59.000002",INTERVAL "10000:99.999999" MINUTE_MICROSECOND) +1998-01-07 22:41:39.000001 +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000.999999" SECOND_MICROSECOND); +date_add("1997-12-31 23:59:59.000002",INTERVAL "10000.999999" SECOND_MICROSECOND) +1998-01-01 02:46:40.000001 +select date_add("1997-12-31 23:59:59.000002",INTERVAL "999999" MICROSECOND); +date_add("1997-12-31 23:59:59.000002",INTERVAL "999999" MICROSECOND) +1998-01-01 00:00:00.000001 +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1 1:1:1.000002" DAY_MICROSECOND); +date_sub("1998-01-01 00:00:00.000001",INTERVAL "1 1:1:1.000002" DAY_MICROSECOND) +1997-12-30 22:58:58.999999 +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1:1:1.000002" HOUR_MICROSECOND); +date_sub("1998-01-01 00:00:00.000001",INTERVAL "1:1:1.000002" HOUR_MICROSECOND) +1997-12-31 22:58:58.999999 +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1:1.000002" MINUTE_MICROSECOND); +date_sub("1998-01-01 00:00:00.000001",INTERVAL "1:1.000002" MINUTE_MICROSECOND) +1997-12-31 23:58:58.999999 +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1.000002" SECOND_MICROSECOND); +date_sub("1998-01-01 00:00:00.000001",INTERVAL "1.000002" SECOND_MICROSECOND) +1997-12-31 23:59:58.999999 +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "000002" MICROSECOND); +date_sub("1998-01-01 00:00:00.000001",INTERVAL "000002" MICROSECOND) +1997-12-31 23:59:59.999999 +select adddate("1997-12-31 23:59:59.000001", 10); +adddate("1997-12-31 23:59:59.000001", 10) +1998-01-10 23:59:59.000001 +select subdate("1997-12-31 23:59:59.000001", 10); +subdate("1997-12-31 23:59:59.000001", 10) +1997-12-21 23:59:59.000001 +select datediff("1997-12-31 23:59:59.000001","1997-12-30"); +datediff("1997-12-31 23:59:59.000001","1997-12-30") +1 +select datediff("1997-11-31 23:59:59.000001","1997-12-31"); +datediff("1997-11-31 23:59:59.000001","1997-12-31") +-30 +select datediff("1997-11-31 23:59:59.000001",null); +datediff("1997-11-31 23:59:59.000001",null) +NULL +select weekofyear("1997-11-31 23:59:59.000001"); +weekofyear("1997-11-31 23:59:59.000001") +49 +select makedate(1997,1); +makedate(1997,1) +1997-01-01 +select makedate(1997,0); +makedate(1997,0) +NULL +select addtime("1997-12-31 23:59:59.999999", "1 1:1:1.000002"); +addtime("1997-12-31 23:59:59.999999", "1 1:1:1.000002") +1998-01-02 01:01:01.000001 +select subtime("1997-12-31 23:59:59.000001", "1 1:1:1.000002"); +subtime("1997-12-31 23:59:59.000001", "1 1:1:1.000002") +1997-12-30 22:58:57.999999 +select addtime("1997-12-31 23:59:59.999999", "1998-01-01 01:01:01.999999"); +addtime("1997-12-31 23:59:59.999999", "1998-01-01 01:01:01.999999") +NULL +select subtime("1997-12-31 23:59:59.999999", "1998-01-01 01:01:01.999999"); +subtime("1997-12-31 23:59:59.999999", "1998-01-01 01:01:01.999999") +NULL +select subtime("01:00:00.999999", "02:00:00.999998"); +subtime("01:00:00.999999", "02:00:00.999998") +-00:59:59.999999 +select subtime("02:01:01.999999", "01:01:01.999999"); +subtime("02:01:01.999999", "01:01:01.999999") +01:00:00.000000 +select timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002"); +timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002") +8807:59:59.999999 +select timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002"); +timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") +46:58:57.999999 +select timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002"); +timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") +-23:59:59.999999 +select timediff("1997-12-31 23:59:59.000001","23:59:59.000001"); +timediff("1997-12-31 23:59:59.000001","23:59:59.000001") +NULL +select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.1"); +timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.1") +-00:00:00.000001 +select maketime(10,11,12); +maketime(10,11,12) +10:11:12 +select maketime(25,11,12); +maketime(25,11,12) +25:11:12 +select maketime(-25,11,12); +maketime(-25,11,12) +-25:11:12 +select timestamp("2001-12-01", "01:01:01.999999"); +timestamp("2001-12-01", "01:01:01.999999") +2001-12-01 01:01:01.999999 +select timestamp("2001-13-01", "01:01:01.000001"); +timestamp("2001-13-01", "01:01:01.000001") +NULL +select timestamp("2001-12-01", "25:01:01"); +timestamp("2001-12-01", "25:01:01") +2001-12-02 01:01:01 +select day("1997-12-31 23:59:59.000001"); +day("1997-12-31 23:59:59.000001") +31 +select date("1997-12-31 23:59:59.000001"); +date("1997-12-31 23:59:59.000001") +1997-12-31 +select date("1997-13-31 23:59:59.000001"); +date("1997-13-31 23:59:59.000001") +NULL +select time("1997-12-31 23:59:59.000001"); +time("1997-12-31 23:59:59.000001") +23:59:59.000001 +select time("1997-12-31 25:59:59.000001"); +time("1997-12-31 25:59:59.000001") +NULL +select microsecond("1997-12-31 23:59:59.000001"); +microsecond("1997-12-31 23:59:59.000001") +1 +create table t1 +select makedate(1997,1) as f1, +addtime(cast("1997-12-31 23:59:59.000001" as datetime), "1 1:1:1.000002") as f2, +addtime(cast("23:59:59.999999" as time) , "1 1:1:1.000002") as f3, +timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") as f4, +timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") as f5, +maketime(10,11,12) as f6, +timestamp("2001-12-01", "01:01:01") as f7, +date("1997-12-31 23:59:59.000001") as f8, +time("1997-12-31 23:59:59.000001") as f9; +describe t1; +Field Type Null Key Default Extra +f1 date 0000-00-00 +f2 datetime 0000-00-00 00:00:00 +f3 time 00:00:00 +f4 time 00:00:00 +f5 time 00:00:00 +f6 time 00:00:00 +f7 datetime 0000-00-00 00:00:00 +f8 date 0000-00-00 +f9 time 00:00:00 +select * from t1; +f1 f2 f3 f4 f5 f6 f7 f8 f9 +1997-01-01 1998-01-02 01:01:00 49:01:01 46:58:57 -23:59:59 10:11:12 2001-12-01 01:01:01 1997-12-31 23:59:59 +create table test(t1 datetime, t2 time, t3 time, t4 datetime); +insert into test values +('2001-01-01 01:01:01', '01:01:01', null, '2001-02-01 01:01:01'), +('2001-01-01 01:01:01', '-01:01:01', '-23:59:59', "1997-12-31 23:59:59.000001"), +('1997-12-31 23:59:59.000001', '-23:59:59', '-01:01:01', '2001-01-01 01:01:01'), +('2001-01-01 01:01:01', '01:01:01', '-1 01:01:01', null), +('2001-01-01 01:01:01', null, '-1 01:01:01', null), +(null, null, null, null), +('2001-01-01 01:01:01', '01:01:01', '1 01:01:01', '2001-01-01 01:01:01'); +SELECT ADDTIME(t1,t2) As ttt, ADDTIME(t2, t3) As qqq from test; +ttt qqq +2001-01-01 02:02:02 NULL +2001-01-01 00:00:00 -25:01:00 +1997-12-31 00:00:00 -25:01:00 +2001-01-01 02:02:02 -24:00:00 +NULL NULL +NULL NULL +2001-01-01 02:02:02 26:02:02 +SELECT TIMEDIFF(t1,t4) As ttt, TIMEDIFF(t2, t3) As qqq from test; +ttt qqq +-744:00:00 NULL +26305:01:02 22:58:58 +-26305:01:02 -22:58:58 +NULL 26:02:02 +NULL NULL +NULL NULL +00:00:00 -24:00:00 +drop table t1, test; diff --git a/mysql-test/t/func_sapdb.test b/mysql-test/t/func_sapdb.test new file mode 100644 index 00000000000..05e1f20fe1e --- /dev/null +++ b/mysql-test/t/func_sapdb.test @@ -0,0 +1,97 @@ +--disable_warnings +drop table if exists t1, test; +--enable_warnings + + +# +# time functions +# +select extract(DAY_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +select extract(HOUR_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +select extract(MINUTE_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +select extract(SECOND_MICROSECOND FROM "1999-01-02 10:11:12.000123"); +select extract(MICROSECOND FROM "1999-01-02 10:11:12.000123"); +select date_format("1997-12-31 23:59:59.000002", "%f"); + +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000 99:99:99.999999" DAY_MICROSECOND); +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000:99:99.999999" HOUR_MICROSECOND); +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000:99.999999" MINUTE_MICROSECOND); +select date_add("1997-12-31 23:59:59.000002",INTERVAL "10000.999999" SECOND_MICROSECOND); +select date_add("1997-12-31 23:59:59.000002",INTERVAL "999999" MICROSECOND); + +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1 1:1:1.000002" DAY_MICROSECOND); +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1:1:1.000002" HOUR_MICROSECOND); +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1:1.000002" MINUTE_MICROSECOND); +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "1.000002" SECOND_MICROSECOND); +select date_sub("1998-01-01 00:00:00.000001",INTERVAL "000002" MICROSECOND); + +#Date functions +select adddate("1997-12-31 23:59:59.000001", 10); +select subdate("1997-12-31 23:59:59.000001", 10); + +select datediff("1997-12-31 23:59:59.000001","1997-12-30"); +select datediff("1997-11-31 23:59:59.000001","1997-12-31"); +select datediff("1997-11-31 23:59:59.000001",null); + +select weekofyear("1997-11-31 23:59:59.000001"); + +select makedate(1997,1); +select makedate(1997,0); + +#Time functions + +select addtime("1997-12-31 23:59:59.999999", "1 1:1:1.000002"); +select subtime("1997-12-31 23:59:59.000001", "1 1:1:1.000002"); +select addtime("1997-12-31 23:59:59.999999", "1998-01-01 01:01:01.999999"); +select subtime("1997-12-31 23:59:59.999999", "1998-01-01 01:01:01.999999"); +select subtime("01:00:00.999999", "02:00:00.999998"); +select subtime("02:01:01.999999", "01:01:01.999999"); + +select timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002"); +select timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002"); +select timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002"); +select timediff("1997-12-31 23:59:59.000001","23:59:59.000001"); +select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.1"); + +select maketime(10,11,12); +select maketime(25,11,12); +select maketime(-25,11,12); + +#Extraction functions +select timestamp("2001-12-01", "01:01:01.999999"); +select timestamp("2001-13-01", "01:01:01.000001"); +select timestamp("2001-12-01", "25:01:01"); +select day("1997-12-31 23:59:59.000001"); +select date("1997-12-31 23:59:59.000001"); +select date("1997-13-31 23:59:59.000001"); +select time("1997-12-31 23:59:59.000001"); +select time("1997-12-31 25:59:59.000001"); +select microsecond("1997-12-31 23:59:59.000001"); + +create table t1 +select makedate(1997,1) as f1, + addtime(cast("1997-12-31 23:59:59.000001" as datetime), "1 1:1:1.000002") as f2, + addtime(cast("23:59:59.999999" as time) , "1 1:1:1.000002") as f3, + timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") as f4, + timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") as f5, + maketime(10,11,12) as f6, + timestamp("2001-12-01", "01:01:01") as f7, + date("1997-12-31 23:59:59.000001") as f8, + time("1997-12-31 23:59:59.000001") as f9; +describe t1; +select * from t1; + +create table test(t1 datetime, t2 time, t3 time, t4 datetime); +insert into test values +('2001-01-01 01:01:01', '01:01:01', null, '2001-02-01 01:01:01'), +('2001-01-01 01:01:01', '-01:01:01', '-23:59:59', "1997-12-31 23:59:59.000001"), +('1997-12-31 23:59:59.000001', '-23:59:59', '-01:01:01', '2001-01-01 01:01:01'), +('2001-01-01 01:01:01', '01:01:01', '-1 01:01:01', null), +('2001-01-01 01:01:01', null, '-1 01:01:01', null), +(null, null, null, null), +('2001-01-01 01:01:01', '01:01:01', '1 01:01:01', '2001-01-01 01:01:01'); + +SELECT ADDTIME(t1,t2) As ttt, ADDTIME(t2, t3) As qqq from test; +SELECT TIMEDIFF(t1,t4) As ttt, TIMEDIFF(t2, t3) As qqq from test; + +drop table t1, test; diff --git a/sql/field.cc b/sql/field.cc index a61654ed8f4..07682e36287 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3150,11 +3150,13 @@ bool Field_time::get_time(TIME *ltime) ltime->neg= 1; tmp=-tmp; } + ltime->day= 0; ltime->hour= (int) (tmp/10000); tmp-=ltime->hour*10000; ltime->minute= (int) tmp/100; ltime->second= (int) tmp % 100; ltime->second_part=0; + ltime->time_type= TIMESTAMP_TIME; return 0; } diff --git a/sql/item_create.cc b/sql/item_create.cc index 3edec7fdab0..19edcaad3f6 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -678,3 +678,38 @@ Item *create_func_uncompressed_length(Item* a) #endif +Item *create_func_datediff(Item *a, Item *b) +{ + return new Item_func_minus(new Item_func_to_days(a), + new Item_func_to_days(b)); +} + +Item *create_func_weekofyear(Item *a) +{ + return new Item_func_week(a, new Item_int((char*) "0", 3, 1)); +} + +Item *create_func_makedate(Item* a,Item* b) +{ + return new Item_func_makedate(a, b); +} + +Item *create_func_addtime(Item* a,Item* b) +{ + return new Item_func_add_time(a, b, 0); +} + +Item *create_func_subtime(Item* a,Item* b) +{ + return new Item_func_add_time(a, b, 1); +} + +Item *create_func_timediff(Item* a,Item* b) +{ + return new Item_func_timediff(a, b); +} + +Item *create_func_maketime(Item* a,Item* b,Item* c) +{ + return new Item_func_maketime(a, b, c); +} diff --git a/sql/item_create.h b/sql/item_create.h index b679c639244..f905e27ea00 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -146,3 +146,10 @@ Item *create_func_compress(Item *a); Item *create_func_uncompress(Item *a); Item *create_func_uncompressed_length(Item *a); +Item *create_func_datediff(Item *a, Item *b); +Item *create_func_weekofyear(Item *a); +Item *create_func_makedate(Item* a,Item* b); +Item *create_func_addtime(Item* a,Item* b); +Item *create_func_subtime(Item* a,Item* b); +Item *create_func_timediff(Item* a,Item* b); +Item *create_func_maketime(Item* a,Item* b,Item* c); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 61c869cddba..fd2bca591a7 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -55,6 +55,70 @@ static String day_names[] = String("Sunday", &my_charset_latin1) }; +enum date_time_format_types { TIME_ONLY= 0, TIME_MICROSECOND, + DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND}; + +typedef struct date_time_format { + const char* format_str; + uint length; +}; + +static struct date_time_format date_time_formats[]= +{ + {"%s%02d:%02d:%02d", 10}, + {"%s%02d:%02d:%02d.%06d", 17}, + {"%04d-%02d-%02d", 10}, + {"%04d-%02d-%02d %02d:%02d:%02d", 19}, + {"%04d-%02d-%02d %02d:%02d:%02d.%06d", 26} +}; + + +String *make_datetime(String *str, TIME *ltime, + enum date_time_format_types format) +{ + char *buff; + CHARSET_INFO *cs= &my_charset_bin; + uint length= date_time_formats[format].length + 32; + const char* format_str= date_time_formats[format].format_str; + + if (str->alloc(length)) + return 0; + + buff= (char*) str->ptr(); + switch (format) { + case TIME_ONLY: + length= cs->cset->snprintf(cs, buff, length, format_str, ltime->neg ? "-" : "", + ltime->hour, ltime->minute, ltime->second); + break; + case TIME_MICROSECOND: + length= cs->cset->snprintf(cs, buff, length, format_str, ltime->neg ? "-" : "", + ltime->hour, ltime->minute, ltime->second, + ltime->second_part); + break; + case DATE_ONLY: + length= cs->cset->snprintf(cs, buff, length, format_str, + ltime->year, ltime->month, ltime->day); + break; + case DATE_TIME: + length= cs->cset->snprintf(cs, buff, length, format_str, + ltime->year, ltime->month, ltime->day, + ltime->hour, ltime->minute, ltime->second); + break; + case DATE_TIME_MICROSECOND: + length= cs->cset->snprintf(cs, buff, length, format_str, + ltime->year, ltime->month, ltime->day, + ltime->hour, ltime->minute, ltime->second, + ltime->second_part); + break; + default: + return 0; + } + + str->length(length); + str->set_charset(cs); + return str; +} + /* ** Get a array of positive numbers from a string object. ** Each number is separated by 1 non digit character @@ -309,7 +373,7 @@ static bool get_interval_value(Item *args,interval_type int_type, CHARSET_INFO *cs=str_value->charset(); bzero((char*) t,sizeof(*t)); - if ((int) int_type <= INTERVAL_SECOND) + if ((int) int_type <= INTERVAL_MICROSECOND) { value=(long) args->val_int(); if (args->null_value) @@ -352,6 +416,9 @@ static bool get_interval_value(Item *args,interval_type int_type, case INTERVAL_HOUR: t->hour=value; break; + case INTERVAL_MICROSECOND: + t->second_part=value; + break; case INTERVAL_MINUTE: t->minute=value; break; @@ -370,6 +437,15 @@ static bool get_interval_value(Item *args,interval_type int_type, t->day=array[0]; t->hour=array[1]; break; + case INTERVAL_DAY_MICROSECOND: + if (get_interval_info(str,length,cs,5,array)) + return (1); + t->day=array[0]; + t->hour=array[1]; + t->minute=array[2]; + t->second=array[3]; + t->second_part=array[4]; + break; case INTERVAL_DAY_MINUTE: if (get_interval_info(str,length,cs,3,array)) return (1); @@ -385,6 +461,14 @@ static bool get_interval_value(Item *args,interval_type int_type, t->minute=array[2]; t->second=array[3]; break; + case INTERVAL_HOUR_MICROSECOND: + if (get_interval_info(str,length,cs,4,array)) + return (1); + t->hour=array[0]; + t->minute=array[1]; + t->second=array[2]; + t->second_part=array[3]; + break; case INTERVAL_HOUR_MINUTE: if (get_interval_info(str,length,cs,2,array)) return (1); @@ -398,12 +482,25 @@ static bool get_interval_value(Item *args,interval_type int_type, t->minute=array[1]; t->second=array[2]; break; + case INTERVAL_MINUTE_MICROSECOND: + if (get_interval_info(str,length,cs,3,array)) + return (1); + t->minute=array[0]; + t->second=array[1]; + t->second_part=array[2]; + break; case INTERVAL_MINUTE_SECOND: if (get_interval_info(str,length,cs,2,array)) return (1); t->minute=array[0]; t->second=array[1]; break; + case INTERVAL_SECOND_MICROSECOND: + if (get_interval_info(str,length,cs,2,array)) + return (1); + t->second=array[0]; + t->second_part=array[1]; + break; } return 0; } @@ -687,6 +784,9 @@ uint Item_func_date_format::format_length(const String *format) case 'T': /* time, 24-hour (hh:mm:ss) */ size += 8; break; + case 'f': /* microseconds */ + size += 6; + break; case 'w': /* day (of the week), numeric */ case '%': default: @@ -844,6 +944,10 @@ String *Item_func_date_format::val_str(String *str) sprintf(intbuff,"%d",l_time.day); str->append(intbuff); break; + case 'f': + sprintf(intbuff,"%06ld",l_time.second_part); + str->append(intbuff); + break; case 'H': sprintf(intbuff,"%02d",l_time.hour); str->append(intbuff,2); @@ -1005,7 +1109,7 @@ void Item_date_add_interval::fix_length_and_dec() enum_field_types arg0_field_type; set_charset(default_charset()); maybe_null=1; - max_length=19*default_charset()->mbmaxlen; + max_length=26*default_charset()->mbmaxlen; value.alloc(32); /* @@ -1051,27 +1155,43 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) null_value=0; switch (int_type) { case INTERVAL_SECOND: + case INTERVAL_SECOND_MICROSECOND: + case INTERVAL_MICROSECOND: case INTERVAL_MINUTE: case INTERVAL_HOUR: + case INTERVAL_MINUTE_MICROSECOND: case INTERVAL_MINUTE_SECOND: + case INTERVAL_HOUR_MICROSECOND: case INTERVAL_HOUR_SECOND: case INTERVAL_HOUR_MINUTE: + case INTERVAL_DAY_MICROSECOND: case INTERVAL_DAY_SECOND: case INTERVAL_DAY_MINUTE: case INTERVAL_DAY_HOUR: - long sec,days,daynr; + long sec,days,daynr,microseconds,extra_sec; ltime->time_type=TIMESTAMP_FULL; // Return full date + microseconds= ltime->second_part + sign*interval.second_part; + extra_sec= microseconds/1000000L; + microseconds= microseconds%1000000L; sec=((ltime->day-1)*3600*24L+ltime->hour*3600+ltime->minute*60+ ltime->second + sign*(interval.day*3600*24L + - interval.hour*3600+interval.minute*60+interval.second)); + interval.hour*3600+interval.minute*60+interval.second))+ + extra_sec; + + if (microseconds < 0) + { + microseconds+= 1000000L; + sec--; + } days=sec/(3600*24L); sec=sec-days*3600*24L; if (sec < 0) { days--; sec+=3600*24L; } + ltime->second_part= microseconds; ltime->second=sec % 60; ltime->minute=sec/60 % 60; ltime->hour=sec/3600; @@ -1124,34 +1244,21 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) String *Item_date_add_interval::val_str(String *str) { TIME ltime; - CHARSET_INFO *cs=default_charset(); - uint32 l; + enum date_time_format_types format; if (Item_date_add_interval::get_date(<ime,0)) return 0; - if (ltime.time_type == TIMESTAMP_DATE) - { - l=11*cs->mbmaxlen+32; - if (str->alloc(l)) - goto null_date; - l=cs->cset->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d", - ltime.year,ltime.month,ltime.day); - str->length(l); - } - else - { - l=20*cs->mbmaxlen+32; - if (str->alloc(l)) - goto null_date; - l=cs->cset->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d %02d:%02d:%02d", - ltime.year,ltime.month,ltime.day, - ltime.hour,ltime.minute,ltime.second); - str->length(l); - } - str->set_charset(cs); - return str; - null_date: + if (ltime.time_type == TIMESTAMP_DATE) + format= DATE_ONLY; + else if (ltime.second_part) + format= DATE_TIME_MICROSECOND; + else + format= DATE_TIME; + + if (make_datetime(str, <ime, format)) + return str; + null_value=1; return 0; } @@ -1188,6 +1295,11 @@ void Item_extract::fix_length_and_dec() case INTERVAL_MINUTE: max_length=2; date_value=0; break; case INTERVAL_MINUTE_SECOND: max_length=4; date_value=0; break; case INTERVAL_SECOND: max_length=2; date_value=0; break; + case INTERVAL_MICROSECOND: max_length=2; date_value=0; break; + case INTERVAL_DAY_MICROSECOND: max_length=20; date_value=0; break; + case INTERVAL_HOUR_MICROSECOND: max_length=13; date_value=0; break; + case INTERVAL_MINUTE_MICROSECOND: max_length=11; date_value=0; break; + case INTERVAL_SECOND_MICROSECOND: max_length=9; date_value=0; break; } } @@ -1234,6 +1346,21 @@ longlong Item_extract::val_int() case INTERVAL_MINUTE: return (long) ltime.minute*neg; case INTERVAL_MINUTE_SECOND: return (long) (ltime.minute*100+ltime.second)*neg; case INTERVAL_SECOND: return (long) ltime.second*neg; + case INTERVAL_MICROSECOND: return (long) ltime.second_part*neg; + case INTERVAL_DAY_MICROSECOND: return (((longlong)ltime.day*1000000L + + (longlong)ltime.hour*10000L + + ltime.minute*100 + + ltime.second)*1000000L + + ltime.second_part)*neg; + case INTERVAL_HOUR_MICROSECOND: return (((longlong)ltime.hour*10000L + + ltime.minute*100 + + ltime.second)*1000000L + + ltime.second_part)*neg; + case INTERVAL_MINUTE_MICROSECOND: return (((longlong)(ltime.minute*100+ + ltime.second))*1000000L+ + ltime.second_part)*neg; + case INTERVAL_SECOND_MICROSECOND: return ((longlong)ltime.second*1000000L+ + ltime.second_part)*neg; } return 0; // Impossible } @@ -1247,3 +1374,358 @@ void Item_typecast::print(String *str) str->append(func_name()); str->append(')'); } + +/* + MAKEDATE(a,b) is a date function that creates a date value + from a year and day value. +*/ + +String *Item_func_makedate::val_str(String *str) +{ + TIME l_time; + long daynr= args[1]->val_int(); + long yearnr= args[0]->val_int(); + long days; + + if (args[0]->null_value || args[1]->null_value || + yearnr < 0 || daynr <= 0) + goto null_date; + + days= calc_daynr(yearnr,1,1) + daynr - 1; + if (days > 0 || days < 3652424L) // Day number from year 0 to 9999-12-31 + { + null_value=0; + get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day); + if (make_datetime(str, &l_time, DATE_ONLY)) + return str; + } + +null_date: + null_value=1; + return 0; +} + + +void Item_func_add_time::fix_length_and_dec() +{ + enum_field_types arg0_field_type; + decimals=0; + max_length=26*my_charset_bin.mbmaxlen; + + /* + The field type for the result of an Item_func_add_time function is defined as + follows: + + - If first arg is a MYSQL_TYPE_DATETIME or MYSQL_TYPE_TIMESTAMP + result is MYSQL_TYPE_DATETIME + - If first arg is a MYSQL_TYPE_TIME result is MYSQL_TYPE_TIME + - Otherwise the result is MYSQL_TYPE_STRING + */ + + cached_field_type= MYSQL_TYPE_STRING; + arg0_field_type= args[0]->field_type(); + if (arg0_field_type == MYSQL_TYPE_DATETIME || + arg0_field_type == MYSQL_TYPE_TIMESTAMP) + cached_field_type= MYSQL_TYPE_DATETIME; + else if (arg0_field_type == MYSQL_TYPE_TIME) + cached_field_type= MYSQL_TYPE_TIME; +} + +/* + ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a time/datetime value + + t: time_or_datetime_expression + a: time_expression + + Result: Time value or datetime value +*/ + +String *Item_func_add_time::val_str(String *str) +{ + TIME l_time1, l_time2, l_time3; + bool is_time; + long microseconds, seconds, days= 0; + int l_sign= sign; + + null_value=0; + if (args[0]->get_time(&l_time1) || + args[1]->get_time(&l_time2) || + l_time2.time_type == TIMESTAMP_FULL) + goto null_date; + is_time= (l_time1.time_type == TIMESTAMP_TIME); + l_time3.neg= 0; + if (is_time) + { + if ((l_time2.neg == l_time1.neg) && l_time1.neg) + l_time3.neg= 1; + } + if (l_time1.neg != l_time2.neg) + l_sign= -l_sign; + + microseconds= l_time1.second_part + l_sign*l_time2.second_part; + seconds= (l_time1.hour*3600L + l_time1.minute*60L + l_time1.second + + (l_time2.day*86400L + l_time2.hour*3600L + + l_time2.minute*60L + l_time2.second)*l_sign); + if (is_time) + seconds+= l_time1.day*86400L; + else + days+= calc_daynr((uint) l_time1.year,(uint) l_time1.month, (uint) l_time1.day); + seconds= seconds + microseconds/1000000L; + microseconds= microseconds%1000000L; + days+= seconds/86400L; + seconds= seconds%86400L; + + if (microseconds < 0) + { + microseconds+= 1000000L; + seconds--; + } + if (seconds < 0) + { + days+= seconds/86400L - 1; + seconds+= 86400L; + } + if (days < 0) + { + if (!is_time) + goto null_date; + if (microseconds) + { + microseconds= 1000000L - microseconds; + seconds++; + } + seconds= 86400L - seconds; + days= -(++days); + l_time3.neg= 1; + } + + calc_time_from_sec(&l_time3, seconds, microseconds); + if (!is_time) + { + get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day); + if (l_time3.day && + make_datetime(str, &l_time3, DATE_TIME_MICROSECOND)) + return str; + goto null_date; + } + + l_time3.hour+= days*24; + if (make_datetime(str, &l_time3, TIME_MICROSECOND)) + return str; + +null_date: + null_value=1; + return 0; +} + +/* + TIMEDIFF(t,s) is a time function that calculates the + time value between a start and end time. + + t and s: time_or_datetime_expression + Result: Time value +*/ + +String *Item_func_timediff::val_str(String *str) +{ + longlong seconds; + long microseconds; + long days; + int l_sign= 1; + TIME l_time1 ,l_time2, l_time3; + + null_value= 0; + if (args[0]->get_time(&l_time1) || + args[1]->get_time(&l_time2) || + l_time1.time_type != l_time2.time_type) + goto null_date; + + if (l_time1.neg != l_time2.neg) + l_sign= -l_sign; + + if (l_time1.time_type == TIMESTAMP_TIME) // Time value + days= l_time1.day - l_sign*l_time2.day; + else // DateTime value + days= (calc_daynr((uint) l_time1.year, + (uint) l_time1.month, + (uint) l_time1.day) - + l_sign*calc_daynr((uint) l_time2.year, + (uint) l_time2.month, + (uint) l_time2.day)); + + microseconds= l_time1.second_part - l_sign*l_time2.second_part; + seconds= ((longlong) days*86400L + l_time1.hour*3600L + + l_time1.minute*60L + l_time1.second + microseconds/1000000L - + (longlong)l_sign*(l_time2.hour*3600L+l_time2.minute*60L+l_time2.second)); + + l_time3.neg= 0; + if (seconds < 0) + { + seconds= -seconds; + l_time3.neg= 1; + } + else if (seconds == 0 && microseconds < 0) + { + microseconds= -microseconds; + l_time3.neg= 1; + } + if (microseconds < 0) + { + microseconds+= 1000000L; + seconds--; + } + if ((l_time2.neg == l_time1.neg) && l_time1.neg) + l_time3.neg= l_time3.neg ? 0 : 1; + + calc_time_from_sec(&l_time3, seconds, microseconds); + if (make_datetime(str, &l_time3, TIME_MICROSECOND)) + return str; + +null_date: + null_value=1; + return 0; +} + +/* + MAKETIME(h,m,s) is a time function that calculates a time value + from the total number of hours, minutes, and seconds. + Result: Time value +*/ + +String *Item_func_maketime::val_str(String *str) +{ + TIME ltime; + + long hour= args[0]->val_int(); + long minute= args[1]->val_int(); + long second= args[2]->val_int(); + + if ((null_value=(args[0]->null_value || + args[1]->null_value || + args[2]->null_value || + minute > 59 || minute < 0 || + second > 59 || second < 0))) + goto null_date; + + ltime.neg= 0; + if (hour < 0) + { + ltime.neg= 1; + hour= -hour; + } + ltime.hour= (ulong)hour; + ltime.minute= (ulong)minute; + ltime.second= (ulong)second; + if (make_datetime(str, <ime, TIME_ONLY)) + return str; + +null_date: + return 0; +} + +/* + TIMESTAMP(a,b) is a function ( extraction) that calculates a datetime value + comprising a date value, time value. + + a: Date_or_datetime value + b: Time value + Result: Datetime value +*/ + +String *Item_func_timestamp::val_str(String *str) +{ + TIME l_time1 ,l_time2, l_time3; + long seconds; + long microseconds; + long days; + int l_sign; + + if (get_arg0_date(&l_time1,1) || + args[1]->get_time(&l_time2) || + l_time1.time_type == TIMESTAMP_TIME || + l_time2.time_type != TIMESTAMP_TIME) + goto null_date; + + l_sign= l_time2.neg ? -1 : 1; + days= (calc_daynr((uint) l_time1.year,(uint) l_time1.month, + (uint) l_time1.day) + l_sign*l_time2.day); + + microseconds= l_time1.second_part + l_sign*l_time2.second_part; + seconds= (l_time1.hour*3600L + l_time1.minute*60L + l_time1.second + + (l_time2.day*86400L + l_time2.hour*3600L + + l_time2.minute*60L + l_time2.second)*l_sign); + days+= seconds/86400L; + seconds%= 86400L; + if (microseconds < 0) + { + microseconds+= 1000000L; + seconds--; + } + if (seconds < 0) + { + days--; + seconds+= 86400L; + } + if (days < 0) + goto null_date; + + calc_time_from_sec(&l_time3, seconds, microseconds); + get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day); + make_datetime(str, &l_time3, DATE_TIME_MICROSECOND); + return str; + +null_date: + null_value=1; + return 0; +} + +/* + DATE(a) is a function ( extraction) that calculates a date value. + + a: Datetime value + Result: Date value +*/ +String *Item_func_date::val_str(String *str) +{ + TIME ltime; + + if (!get_arg0_date(<ime,1) && + make_datetime(str, <ime, DATE_ONLY)) + return str; + +null_date: + null_value=1; + return 0; +} + +/* + TIME(a) is a function ( extraction) that calculates a time value. + + a: Datetime value + Result: Time value +*/ +String *Item_func_time::val_str(String *str) +{ + TIME ltime; + + if (!get_arg0_time(<ime) && + make_datetime(str, <ime, TIME_MICROSECOND)) + return str; + + null_value=1; + return 0; +} + +/* + MICROSECOND(a) is a function ( extraction) that extracts the microseconds from a. + + a: Datetime or time value + Result: int value +*/ +longlong Item_func_microsecond::val_int() +{ + TIME ltime; + if (!get_arg0_time(<ime)) + return ltime.second_part; + return 0; +} diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 87563cf9f47..ea29731fe35 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -478,9 +478,10 @@ public: enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY, INTERVAL_HOUR, INTERVAL_MINUTE, - INTERVAL_SECOND, INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE, - INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND, - INTERVAL_MINUTE_SECOND + INTERVAL_SECOND, INTERVAL_MICROSECOND ,INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, + INTERVAL_DAY_MINUTE, INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, + INTERVAL_HOUR_SECOND, INTERVAL_MINUTE_SECOND, INTERVAL_DAY_MICROSECOND, + INTERVAL_HOUR_MICROSECOND, INTERVAL_MINUTE_MICROSECOND, INTERVAL_SECOND_MICROSECOND }; @@ -592,3 +593,157 @@ public: return (new Field_datetime(maybe_null, name, t_arg, default_charset())); } }; + +class Item_func_makedate :public Item_str_func +{ +public: + Item_func_makedate(Item *a,Item *b) :Item_str_func(a,b) {} + String *val_str(String *str); + const char *func_name() const { return "makedate"; } + enum_field_types field_type() const { return MYSQL_TYPE_DATE; } + void fix_length_and_dec() + { + decimals=0; + max_length=8*my_charset_bin.mbmaxlen; + } + Field *tmp_table_field() { return result_field; } + Field *tmp_table_field(TABLE *t_arg) + { + return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); + } +}; + +class Item_func_add_time :public Item_str_func +{ + int sign; + enum_field_types cached_field_type; + +public: + Item_func_add_time(Item *a, Item *b, bool neg_arg) + :Item_str_func(a, b) { sign= neg_arg ? -1 : 1; } + String *val_str(String *str); + const char *func_name() const { return "addtime"; } + enum_field_types field_type() const { return cached_field_type; } + void fix_length_and_dec(); + Field *tmp_table_field() { return result_field; } + Field *tmp_table_field(TABLE *t_arg) + { + if (cached_field_type == MYSQL_TYPE_TIME) + return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); + else if (cached_field_type == MYSQL_TYPE_DATETIME) + return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); + return (new Field_string(max_length, maybe_null, name, t_arg, &my_charset_bin)); + } +}; + +class Item_func_timediff :public Item_str_func +{ +public: + Item_func_timediff(Item *a, Item *b) + :Item_str_func(a, b) {} + String *val_str(String *str); + const char *func_name() const { return "timediff"; } + enum_field_types field_type() const { return MYSQL_TYPE_TIME; } + void fix_length_and_dec() + { + decimals=0; + max_length=17*my_charset_bin.mbmaxlen; + } + Field *tmp_table_field() { return result_field; } + Field *tmp_table_field(TABLE *t_arg) + { + return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); + } +}; + +class Item_func_maketime :public Item_str_func +{ +public: + Item_func_maketime(Item *a, Item *b, Item *c) + :Item_str_func(a, b ,c) {} + String *val_str(String *str); + const char *func_name() const { return "maketime"; } + enum_field_types field_type() const { return MYSQL_TYPE_TIME; } + void fix_length_and_dec() + { + decimals=0; + max_length=8*my_charset_bin.mbmaxlen; + } + Field *tmp_table_field() { return result_field; } + Field *tmp_table_field(TABLE *t_arg) + { + return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); + } +}; + +class Item_func_timestamp :public Item_str_func +{ +public: + Item_func_timestamp(Item *a, Item *b) :Item_str_func(a, b) {} + String *val_str(String *str); + const char *func_name() const { return "timestamp"; } + enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } + void fix_length_and_dec() + { + decimals=0; + max_length=26*my_charset_bin.mbmaxlen; + } + Field *tmp_table_field() { return result_field; } + Field *tmp_table_field(TABLE *t_arg) + { + return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); + } +}; + +class Item_func_date :public Item_str_func +{ +public: + Item_func_date(Item *a) + :Item_str_func(a) {} + String *val_str(String *str); + const char *func_name() const { return "date"; } + enum_field_types field_type() const { return MYSQL_TYPE_DATE; } + void fix_length_and_dec() + { + decimals=0; + max_length=10*my_charset_bin.mbmaxlen; + } + Field *tmp_table_field() { return result_field; } + Field *tmp_table_field(TABLE *t_arg) + { + return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); + } +}; + +class Item_func_time :public Item_str_func +{ +public: + Item_func_time(Item *a) + :Item_str_func(a) {} + String *val_str(String *str); + const char *func_name() const { return "time"; } + enum_field_types field_type() const { return MYSQL_TYPE_TIME; } + void fix_length_and_dec() + { + decimals=0; + max_length=15*my_charset_bin.mbmaxlen; + } + Field *tmp_table_field() { return result_field; } + Field *tmp_table_field(TABLE *t_arg) + { + return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); + } +}; + +class Item_func_microsecond :public Item_int_func +{ +public: + Item_func_microsecond(Item *a) :Item_int_func(a) {} + longlong val_int(); + const char *func_name() const { return "microsecond"; } + void fix_length_and_dec() + { + decimals=0; + maybe_null=1; + } +}; diff --git a/sql/lex.h b/sql/lex.h index e89c9f51520..8abf96645ec 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -116,6 +116,7 @@ static SYMBOL symbols[] = { { "DATETIME", SYM(DATETIME),0,0}, { "DAY", SYM(DAY_SYM),0,0}, { "DAY_HOUR", SYM(DAY_HOUR_SYM),0,0}, + { "DAY_MICROSECOND", SYM(DAY_MICROSECOND_SYM),0,0}, { "DAY_MINUTE", SYM(DAY_MINUTE_SYM),0,0}, { "DAY_SECOND", SYM(DAY_SECOND_SYM),0,0}, { "DEC", SYM(DECIMAL_SYM),0,0}, @@ -186,6 +187,7 @@ static SYMBOL symbols[] = { { "HELP", SYM(HELP_SYM),0,0}, { "HIGH_PRIORITY", SYM(HIGH_PRIORITY),0,0}, { "HOUR", SYM(HOUR_SYM),0,0}, + { "HOUR_MICROSECOND", SYM(HOUR_MICROSECOND_SYM),0,0}, { "HOUR_MINUTE", SYM(HOUR_MINUTE_SYM),0,0}, { "HOUR_SECOND", SYM(HOUR_SECOND_SYM),0,0}, { "HOSTS", SYM(HOSTS_SYM),0,0}, @@ -258,9 +260,11 @@ static SYMBOL symbols[] = { { "MERGE", SYM(MERGE_SYM),0,0}, { "MEDIUM", SYM(MEDIUM_SYM),0,0}, { "MEMORY", SYM(MEMORY_SYM),0,0}, + { "MICROSECOND", SYM(MICROSECOND_SYM),0,0}, { "MIDDLEINT", SYM(MEDIUMINT),0,0}, /* For powerbuilder */ { "MIN_ROWS", SYM(MIN_ROWS),0,0}, { "MINUTE", SYM(MINUTE_SYM),0,0}, + { "MINUTE_MICROSECOND", SYM(MINUTE_MICROSECOND_SYM),0,0}, { "MINUTE_SECOND", SYM(MINUTE_SECOND_SYM),0,0}, { "MOD", SYM(MOD_SYM),0,0}, { "MODE", SYM(MODE_SYM),0,0}, @@ -336,6 +340,7 @@ static SYMBOL symbols[] = { { "ROWS", SYM(ROWS_SYM),0,0}, { "RTREE", SYM(RTREE_SYM),0,0}, { "SECOND", SYM(SECOND_SYM),0,0}, + { "SECOND_MICROSECOND", SYM(SECOND_MICROSECOND_SYM),0,0}, { "SEPARATOR", SYM(SEPARATOR_SYM),0,0}, { "SELECT", SYM(SELECT_SYM),0,0}, { "SERIAL", SYM(SERIAL_SYM),0,0}, @@ -425,7 +430,8 @@ static SYMBOL symbols[] = { static SYMBOL sql_functions[] = { { "ABS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_abs)}, { "ACOS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_acos)}, - { "ADDDATE", SYM(DATE_ADD_INTERVAL),0,0}, + { "ADDDATE", SYM(ADDDATE_SYM),0,0}, + { "ADDTIME", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_addtime)}, { "AES_ENCRYPT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_aes_encrypt)}, { "AES_DECRYPT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_aes_decrypt)}, { "AREA", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_area)}, @@ -467,6 +473,7 @@ static SYMBOL sql_functions[] = { { "CURDATE", SYM(CURDATE),0,0}, { "CURTIME", SYM(CURTIME),0,0}, { "DATE_ADD", SYM(DATE_ADD_INTERVAL),0,0}, + { "DATEDIFF", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_datediff)}, { "DATE_FORMAT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_date_format)}, { "DATE_SUB", SYM(DATE_SUB_INTERVAL),0,0}, { "DAYNAME", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_dayname)}, @@ -542,6 +549,8 @@ static SYMBOL sql_functions[] = { { "LPAD", SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_lpad)}, { "LTRIM", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ltrim)}, { "MAKE_SET", SYM(MAKE_SET_SYM),0,0}, + { "MAKEDATE", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_makedate)}, + { "MAKETIME", SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_maketime)}, { "MASTER_POS_WAIT", SYM(MASTER_POS_WAIT),0,0}, { "MAX", SYM(MAX_SYM),0,0}, { "MBRCONTAINS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_contains)}, @@ -602,7 +611,7 @@ static SYMBOL sql_functions[] = { { "RTRIM", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_rtrim)}, { "SEC_TO_TIME", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sec_to_time)}, { "SESSION_USER", SYM(USER),0,0}, - { "SUBDATE", SYM(DATE_SUB_INTERVAL),0,0}, + { "SUBDATE", SYM(SUBDATE_SYM),0,0}, { "SIGN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sign)}, { "SIN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sin)}, { "SHA", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sha)}, @@ -617,12 +626,14 @@ static SYMBOL sql_functions[] = { { "STRCMP", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_strcmp)}, { "SUBSTRING", SYM(SUBSTRING),0,0}, { "SUBSTRING_INDEX", SYM(SUBSTRING_INDEX),0,0}, + { "SUBTIME", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_subtime)}, { "SUM", SYM(SUM_SYM),0,0}, { "SYSDATE", SYM(NOW_SYM),0,0}, { "SYSTEM_USER", SYM(USER),0,0}, { "TAN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_tan)}, { "TIME_FORMAT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_time_format)}, { "TIME_TO_SEC", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_time_to_sec)}, + { "TIMEDIFF", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_timediff)}, { "TO_DAYS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_to_days)}, { "TOUCHES", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_touches)}, { "TRIM", SYM(TRIM),0,0}, @@ -637,6 +648,7 @@ static SYMBOL sql_functions[] = { { "VERSION", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_version)}, { "WEEK", SYM(WEEK_SYM),0,0}, { "WEEKDAY", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_weekday)}, + { "WEEKOFYEAR", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_weekofyear)}, { "WITHIN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_within)}, { "X", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_x)}, { "Y", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_y)}, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index a59f1d4b81a..9aad06bd21d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -844,6 +844,7 @@ longlong str_to_datetime(const char *str,uint length,bool fuzzy_date); timestamp_type str_to_TIME(const char *str, uint length, TIME *l_time, bool fuzzy_date); void localtime_to_TIME(TIME *to, struct tm *from); +void calc_time_from_sec(TIME *to, long seconds, long microseconds); int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(byte *,uint,char,char); diff --git a/sql/protocol.cc b/sql/protocol.cc index 7abbf3ce85b..b214b5627d5 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -862,6 +862,8 @@ bool Protocol_simple::store(TIME *tm) (int) tm->hour, (int) tm->minute, (int) tm->second)); + if (tm->second_part) + length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part)); return net_store_data((char*) buff, length); } @@ -898,6 +900,8 @@ bool Protocol_simple::store_time(TIME *tm) (long) day*24L+(long) tm->hour, (int) tm->minute, (int) tm->second)); + if (tm->second_part) + length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part)); return net_store_data((char*) buff, length); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1002d06be88..53fe2d4c123 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -163,6 +163,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token VARIANCE_SYM %token STOP_SYM %token SUM_SYM +%token ADDDATE_SYM %token SUPER_SYM %token TRUNCATE_SYM %token UNLOCK_SYM @@ -430,6 +431,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token VARYING %token ZEROFILL +%token ADDDATE_SYM %token AGAINST %token ATAN %token BETWEEN_SYM @@ -444,6 +446,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token DATE_ADD_INTERVAL %token DATE_SUB_INTERVAL %token DAY_HOUR_SYM +%token DAY_MICROSECOND_SYM %token DAY_MINUTE_SYM %token DAY_SECOND_SYM %token DAY_SYM @@ -466,6 +469,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token GEOMETRYCOLLECTION %token GROUP_CONCAT_SYM %token GROUP_UNIQUE_USERS +%token HOUR_MICROSECOND_SYM %token HOUR_MINUTE_SYM %token HOUR_SECOND_SYM %token HOUR_SYM @@ -480,6 +484,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token LOCATE %token MAKE_SET_SYM %token MASTER_POS_WAIT +%token MICROSECOND_SYM +%token MINUTE_MICROSECOND_SYM %token MINUTE_SECOND_SYM %token MINUTE_SYM %token MODE_SYM @@ -504,7 +510,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token RIGHT %token ROUND %token SECOND_SYM +%token SECOND_MICROSECOND_SYM %token SHARE_SYM +%token SUBDATE_SYM %token SUBSTRING %token SUBSTRING_INDEX %token TRIM @@ -2255,6 +2263,10 @@ simple_expr: { $$= ((Item*(*)(Item*,Item*))($1.symbol->create_func))($3,$5);} | FUNC_ARG3 '(' expr ',' expr ',' expr ')' { $$= ((Item*(*)(Item*,Item*,Item*))($1.symbol->create_func))($3,$5,$7);} + | ADDDATE_SYM '(' expr ',' expr ')' + { $$= new Item_date_add_interval($3, $5, INTERVAL_DAY, 0);} + | ADDDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')' + { $$= new Item_date_add_interval($3, $6, $7, 0); } | ATAN '(' expr ')' { $$= new Item_func_atan($3); } | ATAN '(' expr ',' expr ')' @@ -2289,6 +2301,10 @@ simple_expr: $$= new Item_func_database(); Lex->safe_to_cache_query=0; } + | DATE_SYM '(' expr ')' + { $$= new Item_func_date($3); } + | DAY_SYM '(' expr ')' + { $$= new Item_func_dayofmonth($3); } | ELT_FUNC '(' expr ',' expr_list ')' { $$= new Item_func_elt($3, *$5); } | MAKE_SET_SYM '(' expr ',' expr_list ')' @@ -2405,6 +2421,8 @@ simple_expr: $$= new Item_master_pos_wait($3, $5, $7); Lex->safe_to_cache_query=0; } + | MICROSECOND_SYM '(' expr ')' + { $$= new Item_func_microsecond($3); } | MINUTE_SYM '(' expr ')' { $$= new Item_func_minute($3); } | MOD_SYM '(' expr ',' expr ')' @@ -2466,6 +2484,10 @@ simple_expr: | ROUND '(' expr ')' { $$= new Item_func_round($3, new Item_int((char*)"0",0,1),0); } | ROUND '(' expr ',' expr ')' { $$= new Item_func_round($3,$5,0); } + | SUBDATE_SYM '(' expr ',' expr ')' + { $$= new Item_date_add_interval($3, $5, INTERVAL_DAY, 1);} + | SUBDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')' + { $$= new Item_date_add_interval($3, $6, $7, 1); } | SECOND_SYM '(' expr ')' { $$= new Item_func_second($3); } | SUBSTRING '(' expr ',' expr ',' expr ')' @@ -2478,6 +2500,10 @@ simple_expr: { $$= new Item_func_substr($3,$5); } | SUBSTRING_INDEX '(' expr ',' expr ',' expr ')' { $$= new Item_func_substr_index($3,$5,$7); } + | TIME_SYM '(' expr ')' + { $$= new Item_func_time($3); } + | TIMESTAMP '(' expr ',' expr ')' + { $$= new Item_func_timestamp($3, $5); } | TRIM '(' expr ')' { $$= new Item_func_trim($3,new Item_string(" ",1,default_charset_info)); } | TRIM '(' LEADING opt_pad FROM expr ')' @@ -2892,15 +2918,20 @@ using_list: interval: DAY_HOUR_SYM { $$=INTERVAL_DAY_HOUR; } + | DAY_MICROSECOND_SYM { $$=INTERVAL_DAY_MICROSECOND; } | DAY_MINUTE_SYM { $$=INTERVAL_DAY_MINUTE; } | DAY_SECOND_SYM { $$=INTERVAL_DAY_SECOND; } | DAY_SYM { $$=INTERVAL_DAY; } + | HOUR_MICROSECOND_SYM { $$=INTERVAL_HOUR_MICROSECOND; } | HOUR_MINUTE_SYM { $$=INTERVAL_HOUR_MINUTE; } | HOUR_SECOND_SYM { $$=INTERVAL_HOUR_SECOND; } | HOUR_SYM { $$=INTERVAL_HOUR; } + | MICROSECOND_SYM { $$=INTERVAL_MICROSECOND; } + | MINUTE_MICROSECOND_SYM { $$=INTERVAL_MINUTE_MICROSECOND; } | MINUTE_SECOND_SYM { $$=INTERVAL_MINUTE_SECOND; } | MINUTE_SYM { $$=INTERVAL_MINUTE; } | MONTH_SYM { $$=INTERVAL_MONTH; } + | SECOND_MICROSECOND_SYM { $$=INTERVAL_SECOND_MICROSECOND; } | SECOND_SYM { $$=INTERVAL_SECOND; } | YEAR_MONTH_SYM { $$=INTERVAL_YEAR_MONTH; } | YEAR_SYM { $$=INTERVAL_YEAR; }; @@ -4191,6 +4222,7 @@ user: keyword: ACTION {} + | ADDDATE_SYM {} | AFTER_SYM {} | AGAINST {} | AGGREGATE_SYM {} @@ -4349,6 +4381,7 @@ keyword: | STATUS_SYM {} | STOP_SYM {} | STRING_SYM {} + | SUBDATE_SYM {} | SUBJECT_SYM {} | SUPER_SYM {} | TEMPORARY {} diff --git a/sql/time.cc b/sql/time.cc index eba664a690d..81624ba7287 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -567,7 +567,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time) /* Get fractional second part */ if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1])) { - uint field_length=3; + uint field_length=5; str++; value=(uint) (uchar) (*str - '0'); while (++str != end && my_isdigit(&my_charset_latin1,str[0]) && @@ -590,6 +590,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time) l_time->minute=date[2]; l_time->second=date[3]; l_time->second_part=date[4]; + l_time->time_type= TIMESTAMP_TIME; /* Check if there is garbage at end of the TIME specification */ if (str != end && current_thd->count_cuted_fields) @@ -622,3 +623,13 @@ void localtime_to_TIME(TIME *to, struct tm *from) to->minute= (int) from->tm_min; to->second= (int) from->tm_sec; } + +void calc_time_from_sec(TIME *to, long seconds, long microseconds) +{ + long t_seconds; + to->hour= seconds/3600L; + t_seconds= seconds%3600L; + to->minute= t_seconds/60L; + to->second= t_seconds%60L; + to->second_part= microseconds; +} From 9c6070018a6d45f136feb0ecb6e1a024a26319a8 Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Tue, 24 Jun 2003 13:09:48 +0300 Subject: [PATCH 04/54] indentation change --- Docs/internals.texi | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Docs/internals.texi b/Docs/internals.texi index 9f9b08b96c3..8be0e522027 100644 --- a/Docs/internals.texi +++ b/Docs/internals.texi @@ -200,20 +200,21 @@ to disk (but of course not as optimally as simple calling a sync on all tables)! @item -When one does a @code{FLUSH TABLES}, the variable @code{refresh_version} +When one does a @code{FLUSH TABLES}, the variable @code{refresh_version} will be incremented. Every time a thread releases a table it checks if -the refresh version of the table (updated at open) is the same as -the current @code{refresh_version}. If not it will close it and broadcast -a signal on @code{COND_refresh} (to wait any thread that is waiting for -all instanses of a table to be closed). +the refresh version of the table (TABLE->version), which is updated at +open, is the same as the current @code{refresh_version}. If not it will +close it and broadcast a signal on @code{COND_refresh} (to wake up any +thread that is waiting for all instanses of a table to be closed). @item -The current @code{refresh_version} is also compared to the open -@code{refresh_version} after a thread gets a lock on a table. If the -refresh version is different the thread will free all locks, reopen the -table and try to get the locks again; This is just to quickly get all -tables to use the newest version. This is handled by -@file{sql/lock.cc::mysql_lock_tables()} and +The current @code{refresh_version} is also compared to the open +@code{refresh_version} after a thread gets a lock on a table. If the +refresh version is different the thread will free all locks, wait for +all 'old' tables to be closed (in wait_for_refresh() ) reopen the table +and try to get the locks again; This is just to quickly get all tables +to use the newest version. This is handled by +@file{sql/lock.cc::mysql_lock_tables()} and @file{sql/sql_base.cc::wait_for_tables()}. @item From 76315814b72c6238712916ec592f408e47f15af2 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Wed, 25 Jun 2003 01:19:09 +0300 Subject: [PATCH 05/54] Fixed error handling to be able do not interrupt update (907) (SCRUM) fixed bug of current select pointer in subselect execution fixed layuot --- mysql-test/r/subselect.result | 13 +++++++++++++ mysql-test/t/subselect.test | 14 ++++++++++++++ sql/item_subselect.cc | 9 ++++++--- sql/mysqld.cc | 22 +++++++++++++++------- sql/sql_lex.cc | 3 ++- sql/sql_lex.h | 1 + sql/sql_select.cc | 3 +++ 7 files changed, 54 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index c41434336e5..80b536bcac6 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1151,3 +1151,16 @@ INSERT INTO t1 VALUES (1,0,NULL,NULL),(2,0,NULL,NULL); SELECT DISTINCT REF_ID FROM t1 WHERE ID= (SELECT DISTINCT REF_ID FROM t1 WHERE ID=2); REF_ID DROP TABLE t1; +create table t1 (a int, b int); +create table t2 (a int, b int); +insert into t1 values (1,0), (2,0), (3,0); +insert into t2 values (1,1), (2,1), (3,1), (2,2); +update ignore t1 set b=(select b from t2 where t1.a=t2.a); +Warnings: +Error 1240 Subselect returns more than 1 record +select * from t1; +a b +1 1 +2 NULL +3 1 +drop table t1, t2; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 1528f53ff0d..0131c807b68 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -732,3 +732,17 @@ CREATE TABLE t1 ( INSERT INTO t1 VALUES (1,0,NULL,NULL),(2,0,NULL,NULL); SELECT DISTINCT REF_ID FROM t1 WHERE ID= (SELECT DISTINCT REF_ID FROM t1 WHERE ID=2); DROP TABLE t1; + +# +# uninterruptable update +# +create table t1 (a int, b int); +create table t2 (a int, b int); + +insert into t1 values (1,0), (2,0), (3,0); +insert into t2 values (1,1), (2,1), (3,1), (2,2); + +update ignore t1 set b=(select b from t2 where t1.a=t2.a); +select * from t1; + +drop table t1, t2; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 11f218341bd..cd78edfee7b 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -824,6 +824,8 @@ int subselect_single_select_engine::exec() { DBUG_ENTER("subselect_single_select_engine::exec"); char const *save_where= join->thd->where; + SELECT_LEX_NODE *save_select= join->thd->lex.current_select; + join->thd->lex.current_select= select_lex; if (!optimized) { optimized=1; @@ -831,6 +833,7 @@ int subselect_single_select_engine::exec() { join->thd->where= save_where; executed= 1; + join->thd->lex.current_select= save_select; DBUG_RETURN(join->error?join->error:1); } } @@ -839,6 +842,7 @@ int subselect_single_select_engine::exec() if (join->reinit()) { join->thd->where= save_where; + join->thd->lex.current_select= save_select; DBUG_RETURN(1); } item->reset(); @@ -846,15 +850,14 @@ int subselect_single_select_engine::exec() } if (!executed) { - SELECT_LEX_NODE *save_select= join->thd->lex.current_select; - join->thd->lex.current_select= select_lex; join->exec(); - join->thd->lex.current_select= save_select; executed= 1; join->thd->where= save_where; + join->thd->lex.current_select= save_select; DBUG_RETURN(join->error||thd->is_fatal_error); } join->thd->where= save_where; + join->thd->lex.current_select= save_select; DBUG_RETURN(0); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 68fa0cca2d5..ed4d683a9d5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1818,15 +1818,23 @@ extern "C" int my_message_sql(uint error, const char *str, { THD *thd; DBUG_ENTER("my_message_sql"); - DBUG_PRINT("error",("Message: '%s'",str)); - if ((thd=current_thd)) + DBUG_PRINT("error", ("Message: '%s'", str)); + if ((thd= current_thd)) { - NET *net= &thd->net; - net->report_error= 1; - if (!net->last_error[0]) // Return only first message + if (thd->lex.current_select->no_error && !thd->is_fatal_error) { - strmake(net->last_error,str,sizeof(net->last_error)-1); - net->last_errno=error ? error : ER_UNKNOWN_ERROR; + DBUG_PRINT("error", ("above error converted to warning")); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str); + } + else + { + NET *net= &thd->net; + net->report_error= 1; + if (!net->last_error[0]) // Return only first message + { + strmake(net->last_error, str, sizeof(net->last_error)-1); + net->last_errno= error ? error : ER_UNKNOWN_ERROR; + } } } else diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index bc9ad4f36b0..78f981d7759 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -122,6 +122,7 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) lex->yacc_yyss=lex->yacc_yyvs=0; lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE); lex->sql_command=SQLCOM_END; + lex->duplicates= DUP_ERROR; return lex; } @@ -965,7 +966,7 @@ void st_select_lex_node::init_query() { options= 0; linkage= UNSPECIFIED_TYPE; - no_table_names_allowed= uncacheable= dependent= 0; + no_error= no_table_names_allowed= uncacheable= dependent= 0; ref_pointer_array= 0; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 6226fbe1bb5..4844cb95f86 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -212,6 +212,7 @@ public: bool dependent; /* dependent from outer select subselect */ bool uncacheable; /* result of this query can't be cached */ bool no_table_names_allowed; /* used for global order by */ + bool no_error; /* suppress error message (convert it to warnings) */ static void *operator new(size_t size) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b8eb9e19cc7..02e502f0ba6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -436,6 +436,9 @@ JOIN::optimize() DBUG_RETURN(0); optimized= 1; + // Ignore errors of execution if option IGNORE present + if (thd->lex.duplicates == DUP_IGNORE) + thd->lex.current_select->no_error= 1; #ifdef HAVE_REF_TO_FIELDS // Not done yet /* Add HAVING to WHERE if possible */ if (having && !group_list && !sum_func_count) From fff60e3a86a7f5a02dbf273464e1ccc2d40c94fe Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Wed, 25 Jun 2003 19:43:06 +0300 Subject: [PATCH 06/54] Fixed slowdown problem on windows --- sql/protocol.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/protocol.cc b/sql/protocol.cc index 1d730836d6e..1a1d1f0a585 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -572,7 +572,7 @@ bool Protocol::send_fields(List *list, uint flag) #endif } - send_eof(thd); + send_eof(thd, 1); DBUG_RETURN(prepare_for_send(list)); err: From dfac0fc90acf8ba544b0ca6724bbd5992e8d1568 Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Fri, 27 Jun 2003 16:29:10 +0300 Subject: [PATCH 07/54] Allow one to use MERGE tables with tables from different databases Added command 'replace_column' to mysqltest --- client/mysqltest.c | 98 ++++++++++++++++++++++++--- mysql-test/r/merge.result | 38 +++++++---- mysql-test/t/innodb.test | 4 +- mysql-test/t/merge.test | 21 ++++-- scripts/mysql_create_system_tables.sh | 4 +- sql/ha_myisammrg.cc | 91 ++++++++++++++++++------- sql/mysql_priv.h | 2 + sql/sql_parse.cc | 6 +- sql/sql_show.cc | 52 +++++++------- 9 files changed, 226 insertions(+), 90 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 03a8206276f..18dd7a26f2d 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -42,7 +42,7 @@ **********************************************************************/ -#define MTEST_VERSION "1.28" +#define MTEST_VERSION "1.29" #include #include @@ -63,9 +63,10 @@ #include #include -#define MAX_QUERY 65536 +#define MAX_QUERY 65536 +#define MAX_COLUMNS 256 #define PAD_SIZE 128 -#define MAX_CONS 1024 +#define MAX_CONS 128 #define MAX_INCLUDE_DEPTH 16 #define LAZY_GUESS_BUF_SIZE 8192 #define INIT_Q_LINES 1024 @@ -192,7 +193,7 @@ Q_SYNC_WITH_MASTER, Q_SYNC_SLAVE_WITH_MASTER, Q_ERROR, Q_SEND, Q_REAP, -Q_DIRTY_CLOSE, Q_REPLACE, +Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN, Q_PING, Q_EVAL, Q_RPL_PROBE, Q_ENABLE_RPL_PARSE, Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT, @@ -246,6 +247,7 @@ const char *command_names[]= "reap", "dirty_close", "replace_result", + "replace_column", "ping", "eval", "rpl_probe", @@ -290,7 +292,7 @@ VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, int eval_expr(VAR* v, const char *p, const char** p_end); static int read_server_arguments(const char *name); -/* Definitions for replace */ +/* Definitions for replace result */ typedef struct st_pointer_array { /* when using array-strings */ TYPELIB typelib; /* Pointer to strings */ @@ -318,6 +320,13 @@ static char *out_buff; static uint out_length; static int eval_result = 0; +/* For column replace */ +char *replace_column[MAX_COLUMNS]; +uint max_replace_column= 0; + +static void get_replace_column(struct st_query *q); +static void free_replace_column(); + /* Disable functions that only exist in MySQL 4.0 */ #if MYSQL_VERSION_ID < 40000 || defined(EMBEDDED_LIBRARY) void mysql_enable_rpl_parse(MYSQL* mysql __attribute__((unused))) {} @@ -338,7 +347,6 @@ static const char *embedded_server_groups[] = { NullS }; - static void do_eval(DYNAMIC_STRING* query_eval, const char* query) { const char* p; @@ -433,6 +441,7 @@ static void free_used_memory() delete_dynamic(&q_lines); dynstr_free(&ds_res); free_replace(); + free_replace_column(); my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); free_defaults(default_argv); mysql_server_end(); @@ -2048,27 +2057,35 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, dynstr_append_mem(ds, val, len); } + /* Append all results to the dynamic string separated with '\t' + Values may be converted with 'replace_column' */ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) { MYSQL_ROW row; - int num_fields= mysql_num_fields(res); + uint num_fields= mysql_num_fields(res); unsigned long *lengths; while ((row = mysql_fetch_row(res))) { - int i; + uint i; lengths = mysql_fetch_lengths(res); for (i = 0; i < num_fields; i++) { const char *val= row[i]; ulonglong len= lengths[i]; + + if (i < max_replace_column && replace_column[i]) + { + val= replace_column[i]; + len= strlen(val); + } if (!val) { - val = "NULL"; - len = 4; + val= "NULL"; + len= 4; } if (i) dynstr_append_mem(ds, "\t", 1); @@ -2076,6 +2093,7 @@ static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) } dynstr_append_mem(ds, "\n", 1); } + free_replace_column(); } @@ -2539,6 +2557,9 @@ int main(int argc, char **argv) case Q_REPLACE: get_replace(q); break; + case Q_REPLACE_COLUMN: + get_replace_column(q); + break; case Q_SAVE_MASTER_POS: do_save_master_pos(); break; case Q_SYNC_WITH_MASTER: do_sync_with_master(q); break; case Q_SYNC_SLAVE_WITH_MASTER: @@ -3357,3 +3378,60 @@ static void free_replace_buffer(void) { my_free(out_buff,MYF(MY_WME)); } + + +/**************************************************************************** + Replace results for a column +*****************************************************************************/ + +static void free_replace_column() +{ + uint i; + for (i=0 ; i < max_replace_column ; i++) + { + if (replace_column[i]) + { + my_free(replace_column[i], 0); + replace_column[i]= 0; + } + } + max_replace_column= 0; +} + +/* + Get arguments for replace_columns. The syntax is: + replace-column column_number to_string [column_number to_string ...] + Where each argument may be quoted with ' or " + A argument may also be a variable, in which case the value of the + variable is replaced. +*/ + +static void get_replace_column(struct st_query *q) +{ + char *from=q->first_argument; + char *buff,*start; + DBUG_ENTER("get_replace_columns"); + + free_replace_column(); + if (!*from) + die("Missing argument in %s\n", q->query); + + /* Allocate a buffer for results */ + start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); + while (*from) + { + char *to; + uint column_number; + + to= get_string(&buff, &from, q); + if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS) + die("Wrong column number to replace_columns in %s\n", q->query); + if (!*from) + die("Wrong number of arguments to replace in %s\n", q->query); + to= get_string(&buff, &from, q); + my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR); + replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE)); + set_if_bigger(max_replace_column, column_number); + } + my_free(start, MYF(0)); +} diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 323931ae3eb..f970aafe516 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -1,4 +1,5 @@ drop table if exists t1,t2,t3,t4,t5,t6; +drop database if exists mysqltest; create table t1 (a int not null primary key auto_increment, message char(20)); create table t2 (a int not null primary key auto_increment, message char(20)); INSERT INTO t1 (message) VALUES ("Testing"),("table"),("t1"); @@ -174,15 +175,26 @@ t3 CREATE TABLE `t3` ( `a` int(11) NOT NULL default '0', `b` char(20) default NULL, KEY `a` (`a`) -) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(t1,t2) +) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(`t1`,`t2`) create table t4 (a int not null, b char(10), key(a)) type=MERGE UNION=(t1,t2); select * from t4; ERROR HY000: Can't open file: 't4.MRG'. (errno: 143) -create table t5 (a int not null, b char(10), key(a)) type=MERGE UNION=(test.t1,test_2.t2); -ERROR HY000: Incorrect table definition; All MERGE tables must be in the same database -drop table if exists t5,t4,t3,t1,t2; -Warnings: -Note 1051 Unknown table 't5' +alter table t4 add column c int; +ERROR HY000: Can't open file: 't4.MRG'. (errno: 143) +create database mysqltest; +create table mysqltest.t6 (a int not null primary key auto_increment, message char(20)); +create table t5 (a int not null, b char(20), key(a)) type=MERGE UNION=(test.t1,mysqltest.t6); +show create table t5; +Table Create Table +t5 CREATE TABLE `t5` ( + `a` int(11) NOT NULL default '0', + `b` char(20) default NULL, + KEY `a` (`a`) +) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(`t1`,`mysqltest`.`t6`) +alter table t5 type=myisam; +drop table t5, mysqltest.t6; +drop database mysqltest; +drop table if exists t4,t3,t1,t2; create table t1 (c char(10)) type=myisam; create table t2 (c char(10)) type=myisam; create table t3 (c char(10)) union=(t1,t2) type=merge; @@ -251,14 +263,14 @@ t3 CREATE TABLE `t3` ( `incr` int(11) NOT NULL default '0', `othr` int(11) NOT NULL default '0', PRIMARY KEY (`incr`) -) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(t1,t2) +) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(`t1`,`t2`) alter table t3 drop primary key; show create table t3; Table Create Table t3 CREATE TABLE `t3` ( `incr` int(11) NOT NULL default '0', `othr` int(11) NOT NULL default '0' -) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(t1,t2) +) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(`t1`,`t2`) drop table t3,t2,t1; create table t1 (a int not null, key(a)) type=merge; select * from t1; @@ -294,21 +306,21 @@ t4 CREATE TABLE `t4` ( `a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', KEY `a` (`a`,`b`) -) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(t1,t2) +) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(`t1`,`t2`) show create table t5; Table Create Table t5 CREATE TABLE `t5` ( `a` int(11) NOT NULL default '0', `b` int(11) NOT NULL auto_increment, PRIMARY KEY (`a`,`b`) -) TYPE=MRG_MyISAM CHARSET=latin1 INSERT_METHOD=FIRST UNION=(t1,t2) +) TYPE=MRG_MyISAM CHARSET=latin1 INSERT_METHOD=FIRST UNION=(`t1`,`t2`) show create table t6; Table Create Table t6 CREATE TABLE `t6` ( `a` int(11) NOT NULL default '0', `b` int(11) NOT NULL auto_increment, PRIMARY KEY (`a`,`b`) -) TYPE=MRG_MyISAM CHARSET=latin1 INSERT_METHOD=LAST UNION=(t1,t2) +) TYPE=MRG_MyISAM CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) insert into t1 values (1,NULL),(1,NULL),(1,NULL),(1,NULL); insert into t2 values (2,NULL),(2,NULL),(2,NULL),(2,NULL); select * from t3 order by b,a limit 3; @@ -373,7 +385,7 @@ t4 CREATE TABLE `t4` ( `a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', KEY `a` (`a`,`b`) -) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(t1,t2,t3) +) TYPE=MRG_MyISAM CHARSET=latin1 UNION=(`t1`,`t2`,`t3`) select * from t4 order by a,b; a b 1 1 @@ -399,7 +411,7 @@ t4 CREATE TABLE `t4` ( `a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', KEY `a` (`a`,`b`) -) TYPE=MRG_MyISAM CHARSET=latin1 INSERT_METHOD=FIRST UNION=(t1,t2,t3) +) TYPE=MRG_MyISAM CHARSET=latin1 INSERT_METHOD=FIRST UNION=(`t1`,`t2`,`t3`) insert into t4 values (4,1),(4,2); select * from t1 order by a,b; a b diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 3736f4a2ddc..17df79a69fa 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -22,7 +22,7 @@ drop table t1; # # A bit bigger test -# The 'replace_result' statements are needed because the cardinality calculated +# The 'replace_column' statements are needed because the cardinality calculated # by innodb is not always the same between runs # @@ -51,7 +51,7 @@ select * from t1 where parent_id=102; select level,id from t1 where level=1; select level,id,parent_id from t1 where level=1; optimize table t1; ---replace_result 87 # 50 # 48 # 43 # 25 # 24 # 6 # 3 # +--replace_column 7 # show keys from t1; drop table t1; diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 7a7678afca1..473e8aa9d00 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -4,6 +4,7 @@ --disable_warnings drop table if exists t1,t2,t3,t4,t5,t6; +drop database if exists mysqltest; --enable_warnings create table t1 (a int not null primary key auto_increment, message char(20)); @@ -48,13 +49,23 @@ show create table t3; create table t4 (a int not null, b char(10), key(a)) type=MERGE UNION=(t1,t2); --error 1016 select * from t4; ---error 1212 -create table t5 (a int not null, b char(10), key(a)) type=MERGE UNION=(test.t1,test_2.t2); +--error 1016 +alter table t4 add column c int; + +# +# Test tables in different databases +# +create database mysqltest; +create table mysqltest.t6 (a int not null primary key auto_increment, message char(20)); +create table t5 (a int not null, b char(20), key(a)) type=MERGE UNION=(test.t1,mysqltest.t6); +show create table t5; +alter table t5 type=myisam; +drop table t5, mysqltest.t6; +drop database mysqltest; # Because of windows, it's important that we drop the merge tables first! -# This should give a warning on table t5 -drop table if exists t5,t4,t3,t1,t2; - +drop table if exists t4,t3,t1,t2; + create table t1 (c char(10)) type=myisam; create table t2 (c char(10)) type=myisam; create table t3 (c char(10)) union=(t1,t2) type=merge; diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh index 1f0579f87c2..a98e1739260 100644 --- a/scripts/mysql_create_system_tables.sh +++ b/scripts/mysql_create_system_tables.sh @@ -153,8 +153,8 @@ then then i_u="$i_u INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0); - INSERT INTO user (host,user) values ('$hostname','');" - INSERT INTO user (host,user) values ('localhost',''); + INSERT INTO user (host,user) values ('$hostname',''); + INSERT INTO user (host,user) values ('localhost','');" else i_u="INSERT INTO user VALUES ('localhost','','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0);" fi diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 5f07bbc4140..a0449e83222 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -303,14 +303,40 @@ THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd, return to; } + +/* Find out database name and table name from a filename */ + +static void split_file_name(const char *file_name, + LEX_STRING *db, LEX_STRING *name) +{ + uint name_length, dir_length, prefix_length; + char buff[FN_REFLEN]; + + db->length= 0; + name_length= (uint) (strmake(buff, file_name, sizeof(buff)-1) - buff); + dir_length= dirname_length(buff); + if (dir_length > 1) + { + /* Get database */ + buff[dir_length-1]= 0; // Remove end '/' + prefix_length= dirname_length(buff); + db->str= (char*) file_name+ prefix_length; + db->length= dir_length - prefix_length -1; + } + name->str= (char*) file_name+ dir_length; + name->length= (uint) (fn_ext(name->str) - name->str); +} + + void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info) { - // [phi] auto_increment stuff is missing (but currently not needed) DBUG_ENTER("ha_myisammrg::update_create_info"); + if (!(create_info->used_fields & HA_CREATE_USED_UNION)) { MYRG_TABLE *open_table; THD *thd=current_thd; + create_info->merge_list.next= &create_info->merge_list.first; create_info->merge_list.elements=0; @@ -318,14 +344,17 @@ void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info) open_table != file->end_table ; open_table++) { - char *name=open_table->table->filename; - char buff[FN_REFLEN]; TABLE_LIST *ptr; + LEX_STRING db, name; + if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST)))) goto err; - fn_format(buff,name,"","",3); - if (!(ptr->real_name=thd->strdup(buff))) + split_file_name(open_table->table->filename, &db, &name); + if (!(ptr->real_name= thd->strmake(name.str, name.length))) goto err; + if (db.length && !(ptr->db= thd->strmake(db.str, db.length))) + goto err; + create_info->merge_list.elements++; (*create_info->merge_list.next) = (byte*) ptr; create_info->merge_list.next= (byte**) &ptr->next; @@ -344,37 +373,34 @@ err: DBUG_VOID_RETURN; } + int ha_myisammrg::create(const char *name, register TABLE *form, HA_CREATE_INFO *create_info) { char buff[FN_REFLEN],**table_names,**pos; TABLE_LIST *tables= (TABLE_LIST*) create_info->merge_list.first; + THD *thd= current_thd; DBUG_ENTER("ha_myisammrg::create"); - if (!(table_names= (char**) sql_alloc((create_info->merge_list.elements+1)* - sizeof(char*)))) + if (!(table_names= (char**) thd->alloc((create_info->merge_list.elements+1)* + sizeof(char*)))) DBUG_RETURN(1); for (pos=table_names ; tables ; tables=tables->next) { char *table_name; + TABLE **tbl= 0; if (create_info->options & HA_LEX_CREATE_TMP_TABLE) + tbl= find_temporary_table(thd, tables->db, tables->real_name); + if (!tbl) { - TABLE **tbl=find_temporary_table(current_thd, - tables->db, tables->real_name); - if (!tbl) - { - table_name=sql_alloc(1+ - my_snprintf(buff,FN_REFLEN,"%s/%s/%s",mysql_real_data_home, - tables->db, tables->real_name)); - if (!table_name) - DBUG_RETURN(1); - strcpy(table_name, buff); - } - else - table_name=(*tbl)->path; + uint length= my_snprintf(buff,FN_REFLEN,"%s%s/%s", + mysql_real_data_home, + tables->db, tables->real_name); + if (!(table_name= thd->strmake(buff, length))) + DBUG_RETURN(1); } else - table_name=tables->real_name; + table_name=(*tbl)->path; *pos++= table_name; } *pos=0; @@ -384,9 +410,13 @@ int ha_myisammrg::create(const char *name, register TABLE *form, (my_bool) 0)); } + void ha_myisammrg::append_create_info(String *packet) { - char buff[FN_REFLEN]; + const char *current_db; + uint db_length; + THD *thd= current_thd; + if (file->merge_insert_method != MERGE_INSERT_DISABLED) { packet->append(" INSERT_METHOD=",15); @@ -395,15 +425,26 @@ void ha_myisammrg::append_create_info(String *packet) packet->append(" UNION=(",8); MYRG_TABLE *open_table,*first; + current_db= table->table_cache_key; + db_length= strlen(current_db); + for (first=open_table=file->open_tables ; open_table != file->end_table ; open_table++) { - char *name= open_table->table->filename; - fn_format(buff,name,"","",3); + LEX_STRING db, name; + split_file_name(open_table->table->filename, &db, &name); if (open_table != first) packet->append(','); - packet->append(buff,(uint) strlen(buff)); + /* Report database for mapped table if it isn't in current database */ + if (db.length && + (db_length != db.length || + strncmp(current_db, db.str, db.length))) + { + append_identifier(thd, packet, db.str, db.length); + packet->append('.'); + } + append_identifier(thd, packet, name.str, name.length); } packet->append(')'); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index aca84f1bcb3..5ad2cc56b8c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -532,6 +532,8 @@ int mysqld_show_fields(THD *thd,TABLE_LIST *table, const char *wild, bool verbose); int mysqld_show_keys(THD *thd, TABLE_LIST *table); int mysqld_show_logs(THD *thd); +void append_identifier(THD *thd, String *packet, const char *name, + uint length); void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild); int mysqld_dump_create_info(THD *thd, TABLE *table, int fd = -1); int mysqld_show_create(THD *thd, TABLE_LIST *table_list); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5070466007e..3428b9805a0 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3388,11 +3388,6 @@ static bool check_merge_table_access(THD *thd, char *db, { if (!tmp->db || !tmp->db[0]) tmp->db=db; - else if (strcmp(tmp->db,db)) - { - send_error(thd,ER_UNION_TABLES_IN_DIFFERENT_DIR); - return 1; - } } error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL, table_list); @@ -4425,6 +4420,7 @@ static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name) return 0; } + /* Check if the select is a simple select (not an union) diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 1c4954e0276..fae01936357 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -27,8 +27,6 @@ #include "ha_berkeley.h" // For berkeley_show_logs #endif -/* extern "C" pthread_mutex_t THR_LOCK_keycache; */ - static const char *grant_names[]={ "select","insert","update","delete","create","drop","reload","shutdown", "process","file","grant","references","index","alter"}; @@ -43,15 +41,11 @@ static int mysql_find_files(THD *thd,List *files, const char *db, static int store_create_info(THD *thd, TABLE *table, String *packet); -static void -append_identifier(THD *thd, String *packet, const char *name); -extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd; - -/**************************************************************************** -** Send list of databases -** A database is a directory in the mysql_data_home directory -****************************************************************************/ +/* + Report list of databases + A database is a directory in the mysql_data_home directory +*/ int mysqld_show_dbs(THD *thd,const char *wild) @@ -1002,8 +996,8 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd) } -static void -append_identifier(THD *thd, String *packet, const char *name) +void +append_identifier(THD *thd, String *packet, const char *name, uint length) { char qtype; if (thd->variables.sql_mode & MODE_ANSI_QUOTES) @@ -1014,12 +1008,12 @@ append_identifier(THD *thd, String *packet, const char *name) if (thd->options & OPTION_QUOTE_SHOW_CREATE) { packet->append(&qtype, 1); - packet->append(name, 0, system_charset_info); + packet->append(name, length, system_charset_info); packet->append(&qtype, 1); } else { - packet->append(name, 0, system_charset_info); + packet->append(name, length, system_charset_info); } } @@ -1050,7 +1044,7 @@ store_create_info(THD *thd, TABLE *table, String *packet) packet->append("CREATE TEMPORARY TABLE ", 23); else packet->append("CREATE TABLE ", 13); - append_identifier(thd,packet,table->real_name); + append_identifier(thd,packet, table->real_name, strlen(table->real_name)); packet->append(" (\n", 3); Field **ptr,*field; @@ -1061,7 +1055,7 @@ store_create_info(THD *thd, TABLE *table, String *packet) uint flags = field->flags; packet->append(" ", 2); - append_identifier(thd,packet,field->field_name); + append_identifier(thd,packet,field->field_name, strlen(field->field_name)); packet->append(' '); // check for surprises from the previous call to Field::sql_type() if (type.ptr() != tmp) @@ -1152,7 +1146,7 @@ store_create_info(THD *thd, TABLE *table, String *packet) packet->append("KEY ", 4); if (!found_primary) - append_identifier(thd, packet, key_info->name); + append_identifier(thd, packet, key_info->name, strlen(key_info->name)); if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) && !limited_mysql_mode && !foreign_db_mode) @@ -1174,7 +1168,8 @@ store_create_info(THD *thd, TABLE *table, String *packet) packet->append(','); if (key_part->field) - append_identifier(thd,packet,key_part->field->field_name); + append_identifier(thd,packet,key_part->field->field_name, + strlen(key_part->field->field_name)); if (!key_part->field || (key_part->length != table->field[key_part->fieldnr-1]->key_length() && @@ -1190,17 +1185,17 @@ store_create_info(THD *thd, TABLE *table, String *packet) packet->append(')'); } + /* + Get possible foreign key definitions stored in InnoDB and append them + to the CREATE TABLE statement + */ handler *file = table->file; + char* for_str= file->get_foreign_key_create_info(); - /* Get possible foreign key definitions stored in InnoDB and append them - to the CREATE TABLE statement */ - - char* for_str = file->get_foreign_key_create_info(); - - if (for_str) { - packet->append(for_str, strlen(for_str)); - - file->free_foreign_key_create_info(for_str); + if (for_str) + { + packet->append(for_str, strlen(for_str)); + file->free_foreign_key_create_info(for_str); } packet->append("\n)", 2); @@ -1267,7 +1262,8 @@ store_create_info(THD *thd, TABLE *table, String *packet) { char buff[100]; sprintf(buff," RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld", - my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE); + my_raid_type(file->raid_type), file->raid_chunks, + file->raid_chunksize/RAID_BLOCK_SIZE); packet->append(buff); } } From dbebed97e4fe5b0aed8f4b67d259519e1ab59b7a Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Mon, 30 Jun 2003 13:23:54 +0300 Subject: [PATCH 08/54] Remove FORCE_INIT_OF_VARS when compiling for valgrind/purify to spot wrong LINT_INIT() options Fixed bug in ALTER TABLE ... MODIFY integer-column Added ref_or_null optimization (needed for subqueries) --- BUILD/compile-pentium-valgrind-max | 2 +- mysql-test/r/distinct.result | 6 +- mysql-test/r/null_key.result | 110 +++++- mysql-test/r/subselect.result | 2 +- mysql-test/t/null_key.test | 35 +- sql/sql_select.cc | 599 +++++++++++++++++------------ sql/sql_select.h | 7 +- sql/sql_yacc.yy | 1 + sql/table.cc | 4 +- sql/unireg.cc | 4 +- 10 files changed, 500 insertions(+), 270 deletions(-) diff --git a/BUILD/compile-pentium-valgrind-max b/BUILD/compile-pentium-valgrind-max index c6d8e4f21e8..20876d67472 100755 --- a/BUILD/compile-pentium-valgrind-max +++ b/BUILD/compile-pentium-valgrind-max @@ -3,7 +3,7 @@ path=`dirname $0` . "$path/SETUP.sh" -extra_flags="$pentium_cflags $debug_cflags -USAFEMALLOC -DHAVE_purify" +extra_flags="$pentium_cflags $debug_cflags -USAFEMALLOC -UFORCE_INIT_OF_VARS -DHAVE_purify" c_warnings="$c_warnings $debug_extra_warnings" cxx_warnings="$cxx_warnings $debug_extra_warnings" extra_configs="$pentium_configs $debug_configs" diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index 9ebcd1fb915..c5841f28830 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -173,9 +173,9 @@ INSERT INTO t2 values (1),(2),(3); INSERT INTO t3 VALUES (1,'1'),(2,'2'),(1,'1'),(2,'2'); explain SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 index a a 5 NULL 6 Using index; Using temporary -1 SIMPLE t2 index a a 4 NULL 5 Using index; Distinct -1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where; Distinct +1 SIMPLE t1 ALL PRIMARY NULL NULL NULL 2 Using temporary +1 SIMPLE t2 ref a a 4 test.t1.a 2 Using index +1 SIMPLE t3 ref a a 5 test.t1.b 2 Using where; Using index SELECT distinct t3.a FROM t3,t2,t1 WHERE t3.a=t1.b AND t1.a=t2.a; a 1 diff --git a/mysql-test/r/null_key.result b/mysql-test/r/null_key.result index 289290ba08c..7dc0b4bfdd3 100644 --- a/mysql-test/r/null_key.result +++ b/mysql-test/r/null_key.result @@ -21,7 +21,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range a,b a 9 NULL 3 Using where; Using index explain select * from t1 where (a is null or a = 7) and b=7; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref a,b b 4 const 2 Using where +1 SIMPLE t1 ref_or_null a,b a 9 const,const 2 Using where; Using index +explain select * from t1 where (a is null or a = 7) and b=7 order by a; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null a,b a 9 const,const 2 Using where; Using index; Using filesort explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref a,b a 5 const 3 Using where; Using index @@ -56,13 +59,15 @@ NULL 9 NULL 9 select * from t1 where (a is null or a = 7) and b=7; a b -NULL 7 7 7 +NULL 7 select * from t1 where a is null and b=9 or a is null and b=7 limit 3; a b NULL 7 NULL 9 NULL 9 +create table t2 like t1; +insert into t2 select * from t1; alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10)); explain select * from t1 where a is null and b = 2; id select_type table type possible_keys key key_len ref rows Extra @@ -84,7 +89,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range a,b a 5 NULL 5 Using where explain select * from t1 where (a is null or a = 7) and b=7 and c=0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL a,b NULL NULL NULL 12 Using where +1 SIMPLE t1 ref_or_null a,b a 5 const 4 Using where explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref a,b a 5 const 3 Using where @@ -125,8 +130,8 @@ NULL 9 0 NULL 9 0 select * from t1 where (a is null or a = 7) and b=7 and c=0; a b c -NULL 7 0 7 7 0 +NULL 7 0 select * from t1 where a is null and b=9 or a is null and b=7 limit 3; a b c NULL 7 0 @@ -136,6 +141,103 @@ select * from t1 where b like "6%"; a b c 6 6 0 drop table t1; +rename table t2 to t1; +alter table t1 modify b int null; +insert into t1 values (7,null), (8,null), (8,7); +explain select * from t1 where a = 7 and (b=7 or b is null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null a,b a 10 const,const 2 Using where; Using index +select * from t1 where a = 7 and (b=7 or b is null); +a b +7 7 +7 NULL +explain select * from t1 where (a = 7 or a is null) and (b=7 or b is null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a,b a 10 NULL 4 Using where; Using index +select * from t1 where (a = 7 or a is null) and (b=7 or b is null); +a b +NULL 7 +7 NULL +7 7 +explain select * from t1 where (a = 7 or a is null) and (a = 7 or a is null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ref_or_null a a 5 const 5 Using where; Using index +select * from t1 where (a = 7 or a is null) and (a = 7 or a is null); +a b +7 NULL +7 7 +NULL 7 +NULL 9 +NULL 9 +create table t2 (a int); +insert into t2 values (7),(8); +explain select * from t2 straight_join t1 where t1.a=t2.a and b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t1 ref a,b a 10 test.t2.a,const 2 Using where; Using index +drop index b on t1; +explain select * from t2,t1 where t1.a=t2.a and b is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t1 ref a a 10 test.t2.a,const 2 Using where; Using index +select * from t2,t1 where t1.a=t2.a and b is null; +a a b +7 7 NULL +8 8 NULL +explain select * from t2,t1 where t1.a=t2.a and (b= 7 or b is null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t1 ref_or_null a a 10 test.t2.a,const 4 Using where; Using index +select * from t2,t1 where t1.a=t2.a and (b= 7 or b is null); +a a b +7 7 7 +7 7 NULL +8 8 7 +8 8 NULL +explain select * from t2,t1 where (t1.a=t2.a or t1.a is null) and b= 7; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t1 ref_or_null a a 10 test.t2.a,const 4 Using where; Using index +select * from t2,t1 where (t1.a=t2.a or t1.a is null) and b= 7; +a a b +7 7 7 +7 NULL 7 +8 8 7 +8 NULL 7 +explain select * from t2,t1 where (t1.a=t2.a or t1.a is null) and (b= 7 or b is null); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 +1 SIMPLE t1 ref_or_null a a 5 test.t2.a 4 Using where; Using index +select * from t2,t1 where (t1.a=t2.a or t1.a is null) and (b= 7 or b is null); +a a b +7 7 NULL +7 7 7 +7 NULL 7 +8 8 NULL +8 8 7 +8 NULL 7 +insert into t2 values (null),(6); +delete from t1 where a=8; +explain select * from t2,t1 where t1.a=t2.a or t1.a is null; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 4 +1 SIMPLE t1 ref_or_null a a 5 test.t2.a 4 Using where; Using index +explain select * from t2,t1 where t1.a<=>t2.a or (t1.a is null and t1.b <> 9); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 4 +1 SIMPLE t1 ref_or_null a a 5 test.t2.a 4 Using where; Using index +select * from t2,t1 where t1.a<=>t2.a or (t1.a is null and t1.b <> 9); +a a b +7 7 NULL +7 7 7 +7 NULL 7 +8 NULL 7 +NULL NULL 7 +NULL NULL 9 +NULL NULL 9 +6 6 6 +6 NULL 7 +drop table t1,t2; CREATE TABLE t1 ( id int(10) unsigned NOT NULL auto_increment, uniq_id int(10) unsigned default NULL, diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index c41434336e5..354394e804c 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -827,7 +827,7 @@ a t1.a in (select t2.a from t2) explain SELECT t1.a, t1.a in (select t2.a from t2) FROM t1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 Using index -2 DEPENDENT SUBQUERY t2 index a a 5 NULL 3 Using where; Using index +2 DEPENDENT SUBQUERY t2 ref_or_null a a 5 const 2 Using where; Using index drop table t1,t2; create table t1 (a float); select 10.5 IN (SELECT * from t1 LIMIT 1); diff --git a/mysql-test/t/null_key.test b/mysql-test/t/null_key.test index 18d0d368891..7d9500e90dd 100644 --- a/mysql-test/t/null_key.test +++ b/mysql-test/t/null_key.test @@ -14,6 +14,7 @@ explain select * from t1 where a=2 and b = 2; explain select * from t1 where a<=>b limit 2; explain select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3; explain select * from t1 where (a is null or a = 7) and b=7; +explain select * from t1 where (a is null or a = 7) and b=7 order by a; explain select * from t1 where (a is null and b>a) or a is null and b=7 limit 2; explain select * from t1 where a is null and b=9 or a is null and b=7 limit 3; explain select * from t1 where a > 1 and a < 3 limit 1; @@ -25,6 +26,8 @@ select * from t1 where (a is null or a > 0 and a < 3) and b < 5 limit 3; select * from t1 where (a is null or a > 0 and a < 3) and b > 7 limit 3; select * from t1 where (a is null or a = 7) and b=7; select * from t1 where a is null and b=9 or a is null and b=7 limit 3; +create table t2 like t1; +insert into t2 select * from t1; alter table t1 modify b blob not null, add c int not null, drop key a, add unique key (a,b(20),c), drop key b, add key (b(10)); explain select * from t1 where a is null and b = 2; explain select * from t1 where a is null and b = 2 and c=0; @@ -47,8 +50,38 @@ select * from t1 where (a is null or a > 0 and a < 3) and b > 7 limit 3; select * from t1 where (a is null or a = 7) and b=7 and c=0; select * from t1 where a is null and b=9 or a is null and b=7 limit 3; select * from t1 where b like "6%"; -drop table t1; +# +# Test ref_or_null optimization +# +drop table t1; +rename table t2 to t1; +alter table t1 modify b int null; +insert into t1 values (7,null), (8,null), (8,7); +explain select * from t1 where a = 7 and (b=7 or b is null); +select * from t1 where a = 7 and (b=7 or b is null); +explain select * from t1 where (a = 7 or a is null) and (b=7 or b is null); +select * from t1 where (a = 7 or a is null) and (b=7 or b is null); +explain select * from t1 where (a = 7 or a is null) and (a = 7 or a is null); +select * from t1 where (a = 7 or a is null) and (a = 7 or a is null); +create table t2 (a int); +insert into t2 values (7),(8); +explain select * from t2 straight_join t1 where t1.a=t2.a and b is null; +drop index b on t1; +explain select * from t2,t1 where t1.a=t2.a and b is null; +select * from t2,t1 where t1.a=t2.a and b is null; +explain select * from t2,t1 where t1.a=t2.a and (b= 7 or b is null); +select * from t2,t1 where t1.a=t2.a and (b= 7 or b is null); +explain select * from t2,t1 where (t1.a=t2.a or t1.a is null) and b= 7; +select * from t2,t1 where (t1.a=t2.a or t1.a is null) and b= 7; +explain select * from t2,t1 where (t1.a=t2.a or t1.a is null) and (b= 7 or b is null); +select * from t2,t1 where (t1.a=t2.a or t1.a is null) and (b= 7 or b is null); +insert into t2 values (null),(6); +delete from t1 where a=8; +explain select * from t2,t1 where t1.a=t2.a or t1.a is null; +explain select * from t2,t1 where t1.a<=>t2.a or (t1.a is null and t1.b <> 9); +select * from t2,t1 where t1.a<=>t2.a or (t1.a is null and t1.b <> 9); +drop table t1,t2; # # The following failed for Matt Loschert diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b8eb9e19cc7..6ada6a1bfb7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -31,8 +31,11 @@ #include const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref", - "MAYBE_REF","ALL","range","index","fulltext" }; + "MAYBE_REF","ALL","range","index","fulltext", + "ref_or_null" +}; +static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array); static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, DYNAMIC_ARRAY *keyuse); static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse, @@ -106,6 +109,8 @@ static int join_read_prev_same(READ_RECORD *info); static int join_read_prev(READ_RECORD *info); static int join_ft_read_first(JOIN_TAB *tab); static int join_ft_read_next(READ_RECORD *info); +static int join_read_always_key_or_null(JOIN_TAB *tab); +static int join_read_next_same_or_null(READ_RECORD *info); static COND *make_cond_for_table(COND *cond,table_map table, table_map used_table); static Item* part_of_refkey(TABLE *form,Field *field); @@ -1456,8 +1461,9 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, DYNAMIC_ARRAY *keyuse_array) { int error; - uint i,table_count,const_count,found_ref,refs,key,const_ref,eq_part; - table_map found_const_table_map,all_table_map; + uint i,table_count,const_count,key; + table_map found_const_table_map, all_table_map, found_ref, refs; + key_map const_ref, eq_part; TABLE **table_vector; JOIN_TAB *stat,*stat_end,*s,**stat_ref; KEYUSE *keyuse,*start_keyuse; @@ -1475,7 +1481,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, join->best_ref=stat_vector; stat_end=stat+table_count; - found_const_table_map=all_table_map=0; + found_const_table_map= all_table_map=0; const_count=0; for (s=stat,i=0 ; tables ; s++,tables=tables->next,i++) @@ -1632,16 +1638,17 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, key=keyuse->key; s->keys|= (key_map) 1 << key; // QQ: remove this ? - refs=const_ref=eq_part=0; + refs=const_ref=0; + eq_part=0; do { - if (keyuse->val->type() != Item::NULL_ITEM) + if (keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize) { if (!((~found_const_table_map) & keyuse->used_tables)) const_ref|= (key_map) 1 << keyuse->keypart; else refs|=keyuse->used_tables; - eq_part|= (uint) 1 << keyuse->keypart; + eq_part|= (key_map) 1 << keyuse->keypart; } keyuse++; } while (keyuse->table == table && keyuse->key == key); @@ -1700,8 +1707,6 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, if (s->worst_seeks < 2.0) // Fix for small tables s->worst_seeks=2.0; - /* if (s->type == JT_EQ_REF) - continue; */ if (s->const_keys) { ha_rows records; @@ -1752,7 +1757,10 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, join->found_const_table_map=found_const_table_map; if (join->const_tables != join->tables) + { + optimize_keyuse(join, keyuse_array); find_best_combination(join,all_table_map & ~join->const_table_map); + } else { memcpy((gptr) join->best_positions,(gptr) join->positions, @@ -1774,13 +1782,26 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, typedef struct key_field_t { // Used when finding key fields Field *field; Item *val; // May be empty if diff constant - uint level,const_level; // QQ: Remove const_level + uint level; + uint optimize; bool eq_func; - bool exists_optimize; } KEY_FIELD; +/* Values in optimize */ +#define KEY_OPTIMIZE_EXISTS 1 +#define KEY_OPTIMIZE_REF_OR_NULL 2 -/* merge new key definitions to old ones, remove those not used in both */ +/* + Merge new key definitions to old ones, remove those not used in both + + This is called for OR between different levels + + To be able to do 'ref_or_null' we merge a comparison of a column + and 'column IS NULL' to one test. This is useful for sub select queries + that are internally transformed to something like: + + SELECT * FROM t1 WHERE t1.key=outer_ref_field or t1.key IS NULL +*/ static KEY_FIELD * merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, @@ -1802,20 +1823,46 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, { if (new_fields->val->used_tables()) { + /* + If the value matches, we can use the key reference. + If not, we keep it until we have examined all new values + */ if (old->val->eq(new_fields->val, old->field->binary())) { - old->level=old->const_level=and_level; - old->exists_optimize&=new_fields->exists_optimize; + old->level= and_level; + old->optimize= ((old->optimize & new_fields->optimize & + KEY_OPTIMIZE_EXISTS) | + ((old->optimize | new_fields->optimize) & + KEY_OPTIMIZE_REF_OR_NULL)); } } - else if (old->val->eq(new_fields->val, old->field->binary()) && - old->eq_func && new_fields->eq_func) + else if (old->eq_func && new_fields->eq_func && + old->val->eq(new_fields->val, old->field->binary())) + { - old->level=old->const_level=and_level; - old->exists_optimize&=new_fields->exists_optimize; + old->level= and_level; + old->optimize= ((old->optimize & new_fields->optimize & + KEY_OPTIMIZE_EXISTS) | + ((old->optimize | new_fields->optimize) & + KEY_OPTIMIZE_REF_OR_NULL)); } - else // Impossible; remove it + else if (old->eq_func && new_fields->eq_func && + (old->val->is_null() || new_fields->val->is_null())) { + /* field = expression OR field IS NULL */ + old->level= and_level; + old->optimize= KEY_OPTIMIZE_REF_OR_NULL; + /* Remember the NOT NULL value */ + if (old->val->is_null()) + old->val= new_fields->val; + } + else + { + /* + We are comparing two different const. In this case we can't + use a key-lookup on this so it's better to remove the value + and let the range optimzier handle it + */ if (old == --first_free) // If last item break; *old= *first_free; // Remove old value @@ -1827,7 +1874,7 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, /* Remove all not used items */ for (KEY_FIELD *old=start ; old != first_free ;) { - if (old->level != and_level && old->const_level != and_level) + if (old->level != and_level) { // Not used in all levels if (old == --first_free) break; @@ -1840,32 +1887,53 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, } +/* + Add a possible key to array of possible keys if it's usable as a key + + SYNPOSIS + add_key_field() + key_fields Pointer to add key, if usable + and_level And level, to be stored in KEY_FIELD + field Field used in comparision + eq_func True if we used =, <=> or IS NULL + value Value used for comparison with field + Is NULL for BETWEEN and IN + usable_tables Tables which can be used for key optimization + + NOTES + If we are doing a NOT NULL comparison on a NOT NULL field in a outer join + table, we store this to be able to do not exists optimization later. + + RETURN + *key_fields is incremented if we stored a key in the array +*/ + static void add_key_field(KEY_FIELD **key_fields,uint and_level, Field *field,bool eq_func,Item *value, table_map usable_tables) { - bool exists_optimize=0; + uint exists_optimize= 0; if (!(field->flags & PART_KEY_FLAG)) { // Don't remove column IS NULL on a LEFT JOIN table if (!eq_func || !value || value->type() != Item::NULL_ITEM || !field->table->maybe_null || field->null_ptr) return; // Not a key. Skip it - exists_optimize=1; + exists_optimize= KEY_OPTIMIZE_EXISTS; } else { table_map used_tables=0; - if (value && (used_tables=value->used_tables()) & - (field->table->map | RAND_TABLE_BIT)) + if (value && ((used_tables=value->used_tables()) & + (field->table->map | RAND_TABLE_BIT))) return; if (!(usable_tables & field->table->map)) { if (!eq_func || !value || value->type() != Item::NULL_ITEM || !field->table->maybe_null || field->null_ptr) return; // Can't use left join optimize - exists_optimize=1; + exists_optimize= KEY_OPTIMIZE_EXISTS; } else { @@ -1880,20 +1948,23 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, return; // Can't be used as eq key } - /* Save the following cases: - Field op constant - Field LIKE constant where constant doesn't start with a wildcard - Field = field2 where field2 is in a different table - Field op formula - Field IS NULL - Field IS NOT NULL + /* + Save the following cases: + Field op constant + Field LIKE constant where constant doesn't start with a wildcard + Field = field2 where field2 is in a different table + Field op formula + Field IS NULL + Field IS NOT NULL */ stat[0].key_dependent|=used_tables; if (value->const_item()) stat[0].const_keys |= possible_keys; - /* We can't always use indexes when comparing a string index to a - number. cmp_type() is checked to allow compare of dates to numbers */ + /* + We can't always use indexes when comparing a string index to a + number. cmp_type() is checked to allow compare of dates to numbers + */ if (!eq_func || field->result_type() == STRING_RESULT && value->result_type() != STRING_RESULT && @@ -1902,11 +1973,11 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, } } /* Store possible eq field */ - (*key_fields)->field=field; - (*key_fields)->eq_func=eq_func; - (*key_fields)->val=value; - (*key_fields)->level=(*key_fields)->const_level=and_level; - (*key_fields)->exists_optimize=exists_optimize; + (*key_fields)->field= field; + (*key_fields)->eq_func= eq_func; + (*key_fields)->val= value; + (*key_fields)->level= and_level; + (*key_fields)->optimize= exists_optimize; (*key_fields)++; } @@ -1926,12 +1997,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, while ((item=li++)) add_key_fields(stat,key_fields,and_level,item,usable_tables); for (; org_key_fields != *key_fields ; org_key_fields++) - { - if (org_key_fields->const_level == org_key_fields->level) - org_key_fields->const_level=org_key_fields->level= *and_level; - else - org_key_fields->const_level= *and_level; - } + org_key_fields->level= *and_level; } else { @@ -2024,7 +2090,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) TABLE *form= field->table; KEYUSE keyuse; - if (key_field->eq_func && !key_field->exists_optimize) + if (key_field->eq_func && !(key_field->optimize & KEY_OPTIMIZE_EXISTS)) { for (uint key=0 ; key < form->keys ; key++) { @@ -2042,7 +2108,9 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) keyuse.val = key_field->val; keyuse.key = key; keyuse.keypart=part; + keyuse.keypart_map= (key_part_map) 1 << part; keyuse.used_tables=key_field->val->used_tables(); + keyuse.optimize= key_field->optimize & KEY_OPTIMIZE_REF_OR_NULL; VOID(insert_dynamic(keyuse_array,(gptr) &keyuse)); } } @@ -2126,16 +2194,23 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array, VOID(insert_dynamic(keyuse_array,(gptr) &keyuse)); } + static int sort_keyuse(KEYUSE *a,KEYUSE *b) { + int res; if (a->table->tablenr != b->table->tablenr) return (int) (a->table->tablenr - b->table->tablenr); if (a->key != b->key) return (int) (a->key - b->key); if (a->keypart != b->keypart) return (int) (a->keypart - b->keypart); - return test(a->used_tables) - test(b->used_tables); // Place const first + // Place const values before other ones + if ((res= test(a->used_tables) - test(b->used_tables))) + return res; + /* Place rows that are not 'OPTIMIZE_REF_OR_NULL' first */ + return (int) ((a->optimize & KEY_OPTIMIZE_REF_OR_NULL) - + (b->optimize & KEY_OPTIMIZE_REF_OR_NULL)); } @@ -2151,30 +2226,27 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, SELECT_LEX *select_lex) { uint and_level,i,found_eq_constant; + KEY_FIELD *key_fields,*end; + if (!(key_fields=(KEY_FIELD*) + thd->alloc(sizeof(key_fields[0])*(thd->cond_count+1)*2))) + return TRUE; /* purecov: inspected */ + and_level=0; end=key_fields; + if (cond) + add_key_fields(join_tab,&end,&and_level,cond,normal_tables); + for (i=0 ; i < tables ; i++) { - KEY_FIELD *key_fields,*end; - - if (!(key_fields=(KEY_FIELD*) - thd->alloc(sizeof(key_fields[0])*(thd->cond_count+1)*2))) - return TRUE; /* purecov: inspected */ - and_level=0; end=key_fields; - if (cond) - add_key_fields(join_tab,&end,&and_level,cond,normal_tables); - for (i=0 ; i < tables ; i++) + if (join_tab[i].on_expr) { - if (join_tab[i].on_expr) - { - add_key_fields(join_tab,&end,&and_level,join_tab[i].on_expr, - join_tab[i].table->map); - } + add_key_fields(join_tab,&end,&and_level,join_tab[i].on_expr, + join_tab[i].table->map); } - if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64)) - return TRUE; - /* fill keyuse with found key parts */ - for (KEY_FIELD *field=key_fields ; field != end ; field++) - add_key_part(keyuse,field); } + if (my_init_dynamic_array(keyuse,sizeof(KEYUSE),20,64)) + return TRUE; + /* fill keyuse with found key parts */ + for (KEY_FIELD *field=key_fields ; field != end ; field++) + add_key_part(keyuse,field); if (select_lex->ftfunc_list->elements) { @@ -2182,9 +2254,10 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, } /* - Remove ref if there is a keypart which is a ref and a const. - Remove keyparts without previous keyparts. Special treatment for ft-keys. + Remove the following things from KEYUSE: + - ref if there is a keypart which is a ref and a const. + - keyparts without previous keyparts. */ if (keyuse->elements) { @@ -2202,8 +2275,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, for (i=0 ; i < keyuse->elements-1 ; i++,use++) { if (!use->used_tables) - use->table->const_key_parts[use->key] |= - (key_part_map) 1 << use->keypart; + use->table->const_key_parts[use->key]|= use->keypart_map; if (use->keypart != FT_KEYPART) { if (use->key == prev->key && use->table == prev->table) @@ -2232,6 +2304,41 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, return FALSE; } +/* + Update some values in keyuse for faster find_best_combination() loop +*/ + +static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array) +{ + KEYUSE *end,*keyuse= dynamic_element(keyuse_array, 0, KEYUSE*); + + for (end= keyuse+ keyuse_array->elements ; keyuse < end ; keyuse++) + { + table_map map; + /* + If we find a ref, assume this table matches a proportional + part of this table. + For example 100 records matching a table with 5000 records + gives 5000/100 = 50 records per key + Constant tables are ignored. + To avoid bad matches, we don't make ref_table_rows less than 100. + */ + keyuse->ref_table_rows= ~(table_map) 0; // If no ref + if (keyuse->used_tables & + (map= (keyuse->used_tables & ~join->const_table_map & + ~OUTER_REF_TABLE_BIT))) + { + uint tablenr; + for (tablenr=0 ; ! (map & 1) ; map>>=1, tablenr++) ; + if (map == 1) // Only one table + { + TABLE *tmp_table=join->all_tables[tablenr]; + keyuse->ref_table_rows= max(tmp_table->file->records, 100); + } + } + } +} + /***************************************************************************** Go through all combinations of not marked tables and find the one @@ -2318,7 +2425,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, uint max_key_part=0; /* Test how we can use keys */ - rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; /* Assumed records/key */ + rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; // Assumed records/key for (keyuse=s->keyuse ; keyuse->table == table ;) { key_map found_part=0; @@ -2326,44 +2433,27 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, uint key=keyuse->key; KEY *keyinfo=table->key_info+key; bool ft_key=(keyuse->keypart == FT_KEYPART); + uint found_ref_or_null= 0; + /* Calculate how many key segments of the current key we can use */ start_key=keyuse; do { uint keypart=keyuse->keypart; + uint found_part_ref_or_null= KEY_OPTIMIZE_REF_OR_NULL; do { - if (!ft_key) - { - table_map map; - if (!(rest_tables & keyuse->used_tables)) - { - found_part|= (key_part_map) 1 << keypart; - found_ref|= keyuse->used_tables; - } - /* - If we find a ref, assume this table matches a proportional - part of this table. - For example 100 records matching a table with 5000 records - gives 5000/100 = 50 records per key - Constant tables are ignored and to avoid bad matches, - we don't make rec less than 100. - */ - if (keyuse->used_tables & - (map=(keyuse->used_tables & ~join->const_table_map & - ~OUTER_REF_TABLE_BIT))) - { - uint tablenr; - for (tablenr=0 ; ! (map & 1) ; map>>=1, tablenr++) ; - if (map == 1) // Only one table - { - TABLE *tmp_table=join->all_tables[tablenr]; - if (rec > tmp_table->file->records && rec > 100) - rec=max(tmp_table->file->records,100); - } - } + if (!(rest_tables & keyuse->used_tables) && + !(found_ref_or_null & keyuse->optimize)) + { + found_part|=keyuse->keypart_map; + found_ref|= keyuse->used_tables; + if (rec > keyuse->ref_table_rows) + rec= keyuse->ref_table_rows; + found_part_ref_or_null&= keyuse->optimize; } keyuse++; + found_ref_or_null|= found_part_ref_or_null; } while (keyuse->table == table && keyuse->key == key && keyuse->keypart == keypart); } while (keyuse->table == table && keyuse->key == key); @@ -2373,8 +2463,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, */ if (!found_part && !ft_key) continue; // Nothing usable found - if (rec == 0) - rec=1L; // Fix for small tables + if (rec < MATCHING_ROWS_IN_OTHER_TABLE) + rec= MATCHING_ROWS_IN_OTHER_TABLE; // Fix for small tables /* ft-keys require special treatment @@ -2393,7 +2483,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, /* Check if we found full key */ - if (found_part == PREV_BITS(uint,keyinfo->key_parts)) + if (found_part == PREV_BITS(uint,keyinfo->key_parts) && + !found_ref_or_null) { /* use eq key */ max_key_part= (uint) ~0; if ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME) @@ -2446,7 +2537,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, Set tmp to (previous record count) * (records / combination) */ if ((found_part & 1) && - !(table->file->index_flags(key) & HA_ONLY_WHOLE_INDEX)) + (!(table->file->index_flags(key) & HA_ONLY_WHOLE_INDEX) || + found_part == PREV_BITS(uint,keyinfo->key_parts))) { max_key_part=max_part_bit(found_part); /* @@ -2496,6 +2588,12 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, } records=(ulong) tmp; } + if (found_ref_or_null) + { + /* We need to do two key searches to find key */ + tmp*= 2.0; + records*= 2.0; + } } if (table->used_keys & ((key_map) 1 << key)) { @@ -2745,9 +2843,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, TABLE *table; KEY *keyinfo; - /* - Use best key from find_best - */ + /* Use best key from find_best */ table=j->table; key=keyuse->key; keyinfo=table->key_info+key; @@ -2763,14 +2859,22 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, else { keyparts=length=0; + uint found_part_ref_or_null= 0; + /* + Calculate length for the used key + Stop if there is a missing key part or when we find second key_part + with KEY_OPTIMIZE_REF_OR_NULL + */ do { - if (!((~used_tables) & keyuse->used_tables)) + if (!(~used_tables & keyuse->used_tables)) { - if (keyparts == keyuse->keypart) + if (keyparts == keyuse->keypart && + !(found_part_ref_or_null & keyuse->optimize)) { keyparts++; - length+=keyinfo->key_part[keyuse->keypart].store_length; + length+= keyinfo->key_part[keyuse->keypart].store_length; + found_part_ref_or_null|= keyuse->optimize; } } keyuse++; @@ -2793,8 +2897,8 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, j->ref.key_err=1; keyuse=org_keyuse; - store_key **ref_key=j->ref.key_copy; - byte *key_buff=j->ref.key_buff; + store_key **ref_key= j->ref.key_copy; + byte *key_buff=j->ref.key_buff, *null_ref_key= 0; if (ftkey) { j->ref.items[0]=((Item_func*)(keyuse->val))->key_item(); @@ -2822,9 +2926,7 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, maybe_null ? (char*) key_buff : 0, keyinfo->key_part[i].length, keyuse->val); if (thd->is_fatal_error) - { return TRUE; - } tmp.copy(); } else @@ -2832,17 +2934,25 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, keyuse,join->const_table_map, &keyinfo->key_part[i], (char*) key_buff,maybe_null); + /* Remmeber if we are going to use REF_OR_NULL */ + if (keyuse->optimize & KEY_OPTIMIZE_REF_OR_NULL) + null_ref_key= key_buff; key_buff+=keyinfo->key_part[i].store_length; } } /* not ftkey */ *ref_key=0; // end_marker - if (j->type == JT_FT) /* no-op */; - else if (j->type == JT_CONST) - j->table->const_table=1; + if (j->type == JT_FT) + return 0; + if (j->type == JT_CONST) + j->table->const_table= 1; else if (((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) - != HA_NOSAME) || - keyparts != keyinfo->key_parts) - j->type=JT_REF; /* Must read with repeat */ + != HA_NOSAME) || keyparts != keyinfo->key_parts || + null_ref_key) + { + /* Must read with repeat */ + j->type= null_ref_key ? JT_REF_OR_NULL : JT_REF; + j->null_ref_key= null_ref_key; + } else if (ref_key == j->ref.key_copy) { /* @@ -3153,6 +3263,7 @@ make_join_readinfo(JOIN *join, uint options) table->file->extra(HA_EXTRA_KEYREAD); } break; + case JT_REF_OR_NULL: case JT_REF: table->status=STATUS_NO_RECORD; if (tab->select) @@ -3163,14 +3274,22 @@ make_join_readinfo(JOIN *join, uint options) delete tab->quick; tab->quick=0; table->file->index_init(tab->ref.key); - tab->read_first_record= join_read_always_key; - tab->read_record.read_record= join_read_next_same; if (table->used_keys & ((key_map) 1 << tab->ref.key) && !table->no_keyread) { table->key_read=1; table->file->extra(HA_EXTRA_KEYREAD); } + if (tab->type == JT_REF) + { + tab->read_first_record= join_read_always_key; + tab->read_record.read_record= join_read_next_same; + } + else + { + tab->read_first_record= join_read_always_key_or_null; + tab->read_record.read_record= join_read_next_same_or_null; + } break; case JT_FT: table->status=STATUS_NO_RECORD; @@ -5181,6 +5300,40 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last) The different ways to read a record Returns -1 if row was not found, 0 if row was found and 1 on errors *****************************************************************************/ + +/* Help function when we get some an error from the table handler */ + +static int report_error(TABLE *table, int error) +{ + if (error == HA_ERR_END_OF_FILE || error == HA_ERR_KEY_NOT_FOUND) + { + table->status= STATUS_GARBAGE; + return -1; // key not found; ok + } + /* + Locking reads can legally return also these errors, do not + print them to the .err log + */ + if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) + sql_print_error("Got error %d when reading table '%s'", + error, table->path); + table->file->print_error(error,MYF(0)); + return 1; +} + + +static int safe_index_read(JOIN_TAB *tab) +{ + int error; + TABLE *table= tab->table; + if ((error=table->file->index_read(table->record[0], + tab->ref.key_buff, + tab->ref.key_length, HA_READ_KEY_EXACT))) + return report_error(table, error); + return 0; +} + + static int join_read_const_table(JOIN_TAB *tab, POSITION *pos) { @@ -5235,10 +5388,7 @@ join_read_system(JOIN_TAB *tab) table->primary_key))) { if (error != HA_ERR_END_OF_FILE) - { - table->file->print_error(error,MYF(0)); - return 1; - } + return report_error(table, error); table->null_row=1; // This is ok. empty_record(table); // Make empty record return -1; @@ -5272,15 +5422,7 @@ join_read_const(JOIN_TAB *tab) table->null_row=1; empty_record(table); if (error != HA_ERR_KEY_NOT_FOUND) - { - /* Locking reads can legally return also these errors, do not - print them to the .err log */ - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) - sql_print_error("read_const: Got error %d when reading table %s", - error, table->path); - table->file->print_error(error,MYF(0)); - return 1; - } + return report_error(table, error); return -1; } store_record(table,record[1]); @@ -5313,12 +5455,7 @@ join_read_key(JOIN_TAB *tab) tab->ref.key_buff, tab->ref.key_length,HA_READ_KEY_EXACT); if (error && error != HA_ERR_KEY_NOT_FOUND) - { - sql_print_error("read_key: Got error %d when reading table '%s'",error, - table->path); - table->file->print_error(error,MYF(0)); - return 1; - } + return report_error(table, error); } table->null_row=0; return table->status ? -1 : 0; @@ -5338,18 +5475,13 @@ join_read_always_key(JOIN_TAB *tab) tab->ref.key_length,HA_READ_KEY_EXACT))) { if (error != HA_ERR_KEY_NOT_FOUND) - { - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) - sql_print_error("read_const: Got error %d when reading table %s",error, - table->path); - table->file->print_error(error,MYF(0)); - return 1; - } + return report_error(table, error); return -1; /* purecov: inspected */ } return 0; } + /* This function is used when optimizing away ORDER BY in SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC @@ -5368,13 +5500,7 @@ join_read_last_key(JOIN_TAB *tab) tab->ref.key_length))) { if (error != HA_ERR_KEY_NOT_FOUND) - { - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) - sql_print_error("read_const: Got error %d when reading table %s",error, - table->path); - table->file->print_error(error,MYF(0)); - return 1; - } + return report_error(table, error); return -1; /* purecov: inspected */ } return 0; @@ -5401,19 +5527,14 @@ join_read_next_same(READ_RECORD *info) tab->ref.key_length))) { if (error != HA_ERR_END_OF_FILE) - { - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) - sql_print_error("read_next: Got error %d when reading table %s",error, - table->path); - table->file->print_error(error,MYF(0)); - return 1; - } + return report_error(table, error); table->status= STATUS_GARBAGE; return -1; } return 0; } + static int join_read_prev_same(READ_RECORD *info) { @@ -5422,23 +5543,9 @@ join_read_prev_same(READ_RECORD *info) JOIN_TAB *tab=table->reginfo.join_tab; if ((error=table->file->index_prev(table->record[0]))) - { - if (error != HA_ERR_END_OF_FILE) - { - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) - sql_print_error("read_next: Got error %d when reading table %s",error, - table->path); - table->file->print_error(error,MYF(0)); - error= 1; - } - else - { - table->status= STATUS_GARBAGE; - error= -1; - } - } - else if (key_cmp(table, tab->ref.key_buff, tab->ref.key, - tab->ref.key_length)) + return report_error(table, error); + if (key_cmp(table, tab->ref.key_buff, tab->ref.key, + tab->ref.key_length)) { table->status=STATUS_NOT_FOUND; error= -1; @@ -5475,6 +5582,7 @@ join_init_read_record(JOIN_TAB *tab) return (*tab->read_record.read_record)(&tab->read_record); } + static int join_read_first(JOIN_TAB *tab) { @@ -5492,17 +5600,10 @@ join_read_first(JOIN_TAB *tab) tab->read_record.file=table->file; tab->read_record.index=tab->index; tab->read_record.record=table->record[0]; - error=tab->table->file->index_first(tab->table->record[0]); - if (error) + if ((error=tab->table->file->index_first(tab->table->record[0]))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) - { - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) - sql_print_error("read_first_with_key: Got error %d when reading table", - error); - table->file->print_error(error,MYF(0)); - return 1; - } + report_error(table, error); return -1; } return 0; @@ -5512,23 +5613,13 @@ join_read_first(JOIN_TAB *tab) static int join_read_next(READ_RECORD *info) { - int error=info->file->index_next(info->record); - if (error) - { - if (error != HA_ERR_END_OF_FILE) - { - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) - sql_print_error( - "read_next_with_key: Got error %d when reading table %s", - error, info->table->path); - info->file->print_error(error,MYF(0)); - return 1; - } - return -1; - } + int error; + if ((error=info->file->index_next(info->record))) + return report_error(info->table, error); return 0; } + static int join_read_last(JOIN_TAB *tab) { @@ -5546,19 +5637,8 @@ join_read_last(JOIN_TAB *tab) tab->read_record.file=table->file; tab->read_record.index=tab->index; tab->read_record.record=table->record[0]; - error=tab->table->file->index_last(tab->table->record[0]); - if (error) - { - if (error != HA_ERR_END_OF_FILE) - { - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) - sql_print_error("read_last_with_key: Got error %d when reading table", - error, table->path); - table->file->print_error(error,MYF(0)); - return 1; - } - return -1; - } + if ((error= tab->table->file->index_last(tab->table->record[0]))) + return report_error(table, error); return 0; } @@ -5566,20 +5646,9 @@ join_read_last(JOIN_TAB *tab) static int join_read_prev(READ_RECORD *info) { - int error=info->file->index_prev(info->record); - if (error) - { - if (error != HA_ERR_END_OF_FILE) - { - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) - sql_print_error( - "read_prev_with_key: Got error %d when reading table: %s", - error,info->table->path); - info->file->print_error(error,MYF(0)); - return 1; - } - return -1; - } + int error; + if ((error= info->file->index_prev(info->record))) + return report_error(info->table, error); return 0; } @@ -5596,42 +5665,57 @@ join_ft_read_first(JOIN_TAB *tab) #endif table->file->ft_init(); - error=table->file->ft_read(table->record[0]); - if (error) - { - if (error != HA_ERR_END_OF_FILE) - { - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) - sql_print_error("ft_read_first: Got error %d when reading table %s", - error, table->path); - table->file->print_error(error,MYF(0)); - return 1; - } - return -1; - } + if ((error= table->file->ft_read(table->record[0]))) + return report_error(table, error); return 0; } static int join_ft_read_next(READ_RECORD *info) { - int error=info->file->ft_read(info->table->record[0]); - if (error) - { - if (error != HA_ERR_END_OF_FILE) - { - if (error != HA_ERR_LOCK_DEADLOCK && error != HA_ERR_LOCK_WAIT_TIMEOUT) - sql_print_error("ft_read_next: Got error %d when reading table %s", - error, info->table->path); - info->file->print_error(error,MYF(0)); - return 1; - } - return -1; - } + int error; + if ((error= info->file->ft_read(info->table->record[0]))) + return report_error(info->table, error); return 0; } +/* + Reading of key with key reference and one part that may be NULL +*/ + +static int +join_read_always_key_or_null(JOIN_TAB *tab) +{ + int res; + + /* First read according to key which is NOT NULL */ + *tab->null_ref_key=0; + if ((res= join_read_always_key(tab)) >= 0) + return res; + + /* Then read key with null value */ + *tab->null_ref_key= 1; + return safe_index_read(tab); +} + + +static int +join_read_next_same_or_null(READ_RECORD *info) +{ + int error; + if ((error= join_read_next_same(info)) >= 0) + return error; + JOIN_TAB *tab= info->table->reginfo.join_tab; + + /* Test if we have already done a read after null key */ + if (*tab->null_ref_key) + return -1; // All keys read + *tab->null_ref_key= 1; // Read null key + return safe_index_read(tab); +} + + /***************************************************************************** The different end of select functions These functions returns < 0 when end is reached, 0 on ok and > 0 if a @@ -6358,10 +6442,13 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, } ref_key= -1; - if (tab->ref.key >= 0) // Constant range in WHERE + /* Test if constant range in WHERE */ + if (tab->ref.key >= 0) { ref_key= tab->ref.key; ref_key_parts= tab->ref.key_parts; + if (tab->type == JT_REF_OR_NULL) + DBUG_RETURN(0); } else if (select && select->quick) // Range found by opt_range { diff --git a/sql/sql_select.h b/sql/sql_select.h index df21d337b54..f29729fb5b3 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -27,8 +27,10 @@ typedef struct keyuse_t { TABLE *table; Item *val; /* or value if no field */ - uint key,keypart; table_map used_tables; + uint key, keypart, optimize; + key_map keypart_map; + ha_rows ref_table_rows; } KEYUSE; class store_key; @@ -73,7 +75,7 @@ typedef struct st_join_cache { */ enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF, - JT_ALL, JT_RANGE, JT_NEXT, JT_FT}; + JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL}; class JOIN; @@ -85,6 +87,7 @@ typedef struct st_join_table { QUICK_SELECT *quick; Item *on_expr; const char *info; + byte *null_ref_key; int (*read_first_record)(struct st_join_table *tab); int (*next_select)(JOIN *,struct st_join_table *,bool); READ_RECORD read_record; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e3fb81b39f2..435c892db63 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1597,6 +1597,7 @@ alter_list_item: LEX *lex=Lex; lex->length=lex->dec=0; lex->type=0; lex->interval=0; lex->default_value=lex->comment=0; + lex->charset= NULL; lex->simple_alter=0; } type opt_attribute diff --git a/sql/table.cc b/sql/table.cc index 908d6807450..0fc2a09f749 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -395,7 +395,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, } else { - if (!(charset=get_charset((uint) strpos[14], MYF(0)))) + if (!strpos[14]) + charset= &my_charset_bin; + else if (!(charset=get_charset((uint) strpos[14], MYF(0)))) charset= (outparam->table_charset ? outparam->table_charset: default_charset_info); } diff --git a/sql/unireg.cc b/sql/unireg.cc index 5e723281d3f..3e634f54b4f 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -460,8 +460,10 @@ static bool pack_fields(File file,List &create_fields) buff[13]= (uchar) field->sql_type; if (field->sql_type == FIELD_TYPE_GEOMETRY) buff[14]= (uchar) field->geom_type; - else + else if (field->charset) buff[14]= (uchar) field->charset->number; + else + buff[14]= 0; // Numerical int2store(buff+15, field->comment.length); comment_length+= field->comment.length; set_if_bigger(int_count,field->interval_id); From 6bc7b3a6be246f67b06c1e5e15ea0de97bf637f4 Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Mon, 30 Jun 2003 13:28:36 +0300 Subject: [PATCH 09/54] LAST_INSERT_ID() should not be set if we couldn't generate an auto_increment id. --- mysql-test/r/auto_increment.result | 7 ++++++- mysql-test/t/auto_increment.test | 4 ++++ sql/handler.cc | 2 ++ sql/sql_class.h | 19 +++++++++++++++++-- 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/auto_increment.result b/mysql-test/r/auto_increment.result index 5553f718799..19f8ffa84d4 100644 --- a/mysql-test/r/auto_increment.result +++ b/mysql-test/r/auto_increment.result @@ -111,11 +111,16 @@ insert into t1 set i = null; select last_insert_id(); last_insert_id() 255 +insert into t1 set i = 254; +ERROR 23000: Duplicate entry '254' for key 1 +select last_insert_id(); +last_insert_id() +255 insert into t1 set i = null; ERROR 23000: Duplicate entry '255' for key 1 select last_insert_id(); last_insert_id() -255 +0 drop table t1; create table t1 (i tinyint unsigned not null auto_increment, key (i)); insert into t1 set i = 254; diff --git a/mysql-test/t/auto_increment.test b/mysql-test/t/auto_increment.test index 63fdfded6d0..189320a8dcb 100644 --- a/mysql-test/t/auto_increment.test +++ b/mysql-test/t/auto_increment.test @@ -80,6 +80,9 @@ insert into t1 set i = 254; insert into t1 set i = null; select last_insert_id(); --error 1062 +insert into t1 set i = 254; +select last_insert_id(); +--error 1062 insert into t1 set i = null; select last_insert_id(); drop table t1; @@ -100,5 +103,6 @@ select last_insert_id(); --error 1062 insert into t1 values (NULL, 10); select last_insert_id(); + drop table t1; diff --git a/sql/handler.cc b/sql/handler.cc index 56319bcc91c..150a0d5329e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -709,6 +709,8 @@ void handler::update_auto_increment() nr=get_auto_increment(); if (!table->next_number_field->store(nr)) thd->insert_id((ulonglong) nr); + else + thd->insert_id(table->next_number_field->val_int()); auto_increment_column_changed=1; DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 33767bc4226..22956f16c83 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -503,8 +503,23 @@ public: #ifdef SIGNAL_WITH_VIO_CLOSE Vio* active_vio; #endif - ulonglong next_insert_id,last_insert_id,current_insert_id, - limit_found_rows; + /* + next_insert_id is set on SET INSERT_ID= #. This is used as the next + generated auto_increment value in handler.cc + */ + ulonglong next_insert_id; + /* + The insert_id used for the last statement or set by SET LAST_INSERT_ID=# + or SELECT LAST_INSERT_ID(#). Used for binary log and returned by + LAST_INSERT_ID() + */ + ulonglong last_insert_id; + /* + Set to the first value that LAST_INSERT_ID() returned for the last + statement. When this is set, last_insert_id_used is set to true. + */ + ulonglong current_insert_id; + ulonglong limit_found_rows; ha_rows select_limit, offset_limit, cuted_fields, sent_row_count, examined_row_count; table_map used_tables; From 5e65dcb9fb4e548d515ecf23110913c273d94405 Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Tue, 1 Jul 2003 00:30:16 -0700 Subject: [PATCH 10/54] sql_state.h: Minor fixups for SQLSTATE values to be compatible with ODBC spec --- include/sql_state.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/sql_state.h b/include/sql_state.h index c998beaf578..26568ac3e0d 100644 --- a/include/sql_state.h +++ b/include/sql_state.h @@ -36,8 +36,8 @@ ER_CON_COUNT_ERROR, "08004", "", ER_BAD_HOST_ERROR, "08S01", "", ER_HANDSHAKE_ERROR, "08S01", "", ER_DBACCESS_DENIED_ERROR, "42000", "", -ER_ACCESS_DENIED_ERROR, "42000", "28000", -ER_NO_DB_ERROR, "42000", "", +ER_ACCESS_DENIED_ERROR, "28000", "", +ER_NO_DB_ERROR, "3D000", "", ER_UNKNOWN_COM_ERROR, "08S01", "", ER_BAD_NULL_ERROR, "23000", "", ER_BAD_DB_ERROR, "42000", "", @@ -68,7 +68,7 @@ ER_BLOB_USED_AS_KEY, "42000", "S1009", ER_TOO_BIG_FIELDLENGTH, "42000", "S1009", ER_WRONG_AUTO_KEY, "42000", "S1009", ER_FORCING_CLOSE, "08S01", "", -ER_IPSOCK_ERROR, "088S01", "", +ER_IPSOCK_ERROR, "08S01", "", ER_NO_SUCH_INDEX, "42S12", "S1009", ER_WRONG_FIELD_TERMINATORS, "42000", "S1009", ER_BLOBS_AND_NO_TERMINATED, "42000", "S1009", From f6a1292fb49eeb7e749d86cdf7bbeac1f01f54f8 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Tue, 1 Jul 2003 14:54:34 +0300 Subject: [PATCH 11/54] fexed erroro message --- mysql-test/r/grant_cache.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/grant_cache.result b/mysql-test/r/grant_cache.result index 0ffc48ad879..c8ae0b4d9b3 100644 --- a/mysql-test/r/grant_cache.result +++ b/mysql-test/r/grant_cache.result @@ -122,7 +122,7 @@ select "user4"; user4 user4 select a from t1; -ERROR 42000: No Database Selected +ERROR 3D000: No Database Selected select * from mysqltest.t1,test.t1; a b c a 1 1 1 test.t1 From a6755acb4ec4f10c1aa8915d779a139b59d3007b Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Tue, 1 Jul 2003 15:49:32 +0300 Subject: [PATCH 12/54] Fix needed to support MERGE tables in different databases --- mysql-test/r/merge.result | 12 ++++++++---- mysql-test/t/merge.test | 10 ++++++---- mysys/mf_loadpath.c | 6 +++--- mysys/my_symlink.c | 12 +++++++----- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index f970aafe516..413277fee43 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -194,7 +194,7 @@ t5 CREATE TABLE `t5` ( alter table t5 type=myisam; drop table t5, mysqltest.t6; drop database mysqltest; -drop table if exists t4,t3,t1,t2; +drop table t4,t3,t1,t2; create table t1 (c char(10)) type=myisam; create table t2 (c char(10)) type=myisam; create table t3 (c char(10)) union=(t1,t2) type=merge; @@ -540,7 +540,11 @@ a b 6 1 6 2 6 3 -drop table if exists t6, t5, t4, t3, t2, t1; +insert into t1 values (99,NULL); +select * from t4 where a+0 > 90; +a b +99 1 +drop table t6, t5, t4, t3, t2, t1; CREATE TABLE t1 ( a int(11) NOT NULL default '0', b int(11) NOT NULL default '0', PRIMARY KEY (a,b)) TYPE=MyISAM; INSERT INTO t1 VALUES (1,1), (2,1); CREATE TABLE t2 ( a int(11) NOT NULL default '0', b int(11) NOT NULL default '0', PRIMARY KEY (a,b)) TYPE=MyISAM; @@ -552,7 +556,7 @@ max(b) select max(b) from t1 where a = 2; max(b) 1 -drop table if exists t3,t1,t2; +drop table t3,t1,t2; create table t1 (a int not null); create table t2 (a int not null); insert into t1 values (1); @@ -571,7 +575,7 @@ select * from t6; a 1 2 -drop table if exists t6, t3, t1, t2, t4, t5; +drop table t6, t3, t1, t2, t4, t5; CREATE TABLE t1 ( fileset_id tinyint(3) unsigned NOT NULL default '0', file_code varchar(32) NOT NULL default '', diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 473e8aa9d00..01ba8986474 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -64,7 +64,7 @@ drop table t5, mysqltest.t6; drop database mysqltest; # Because of windows, it's important that we drop the merge tables first! -drop table if exists t4,t3,t1,t2; +drop table t4,t3,t1,t2; create table t1 (c char(10)) type=myisam; create table t2 (c char(10)) type=myisam; @@ -188,7 +188,9 @@ select * from t1 order by a,b; select * from t2 order by a,b; select * from t5 order by a,b; select * from t6 order by a,b; -drop table if exists t6, t5, t4, t3, t2, t1; +insert into t1 values (99,NULL); +select * from t4 where a+0 > 90; +drop table t6, t5, t4, t3, t2, t1; CREATE TABLE t1 ( a int(11) NOT NULL default '0', b int(11) NOT NULL default '0', PRIMARY KEY (a,b)) TYPE=MyISAM; INSERT INTO t1 VALUES (1,1), (2,1); @@ -197,7 +199,7 @@ INSERT INTO t2 VALUES (1,2), (2,2); CREATE TABLE t3 ( a int(11) NOT NULL default '0', b int(11) NOT NULL default '0', KEY a (a,b)) TYPE=MRG_MyISAM UNION=(t1,t2); select max(b) from t3 where a = 2; select max(b) from t1 where a = 2; -drop table if exists t3,t1,t2; +drop table t3,t1,t2; # # temporary merge tables @@ -214,7 +216,7 @@ insert into t4 values (1); insert into t5 values (2); create temporary table t6 (a int not null) TYPE=MERGE UNION=(t4,t5); select * from t6; -drop table if exists t6, t3, t1, t2, t4, t5; +drop table t6, t3, t1, t2, t4, t5; # # testing merge::records_in_range and optimizer diff --git a/mysys/mf_loadpath.c b/mysys/mf_loadpath.c index 291ad62e297..2c90d9f90a6 100644 --- a/mysys/mf_loadpath.c +++ b/mysys/mf_loadpath.c @@ -39,10 +39,10 @@ my_string my_load_path(my_string to, const char *path, (is_prefix((gptr) path,FN_PARENTDIR)) || ! own_path_prefix) { - if (! my_getwd(buff,(uint) (FN_REFLEN-strlen(path)),MYF(0))) - VOID(strcat(buff,path)); + if (! my_getwd(buff,(uint) (FN_REFLEN+2-strlen(path)),MYF(0))) + VOID(strcat(buff,path+2)); else - VOID(strmov(buff,path)); + VOID(strmov(buff,path)); /* Return org file name */ } else VOID(strxmov(buff,own_path_prefix,path,NullS)); diff --git a/mysys/my_symlink.c b/mysys/my_symlink.c index abef0096e28..b9468d42cfc 100644 --- a/mysys/my_symlink.c +++ b/mysys/my_symlink.c @@ -123,20 +123,22 @@ int my_realpath(char *to, const char *filename, } else { - /* Realpath didn't work; Use original name */ + /* + Realpath didn't work; Use my_load_path() which is a poor substitute + original name but will at least be able to resolve paths that starts + with '.'. + */ DBUG_PRINT("error",("realpath failed with errno: %d", errno)); my_errno=errno; if (MyFlags & MY_WME) my_error(EE_REALPATH, MYF(0), filename, my_errno); - if (to != filename) - strmov(to,filename); + my_load_path(to, filename, NullS); result= -1; } } DBUG_RETURN(result); #else - if (to != filename) - strmov(to,filename); + my_load_path(to, filename, NullS); return 0; #endif } From cd2de0a5eb8cf4de5d173a2a824a38b2a3066653 Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Tue, 1 Jul 2003 17:59:42 +0300 Subject: [PATCH 13/54] Fixed testcases and bug introduced by last changeset --- mysql-test/r/func_gconcat.result | 2 +- mysql-test/r/grant_cache.result | 2 +- mysys/mf_loadpath.c | 9 ++++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index bf96727a6a7..d518cff45cf 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -169,7 +169,7 @@ select REQ_ID, Group_Concat(URL) as URL from T_URL, T_REQUEST where T_REQUEST.URL_ID = T_URL.URL_ID group by REQ_ID; REQ_ID URL 1 www.host.com -5 www.host.com,www.google.com,www.help.com +5 www.google.com,www.help.com,www.host.com drop table T_URL; drop table T_REQUEST; select group_concat(sum(a)) from t1 group by grp; diff --git a/mysql-test/r/grant_cache.result b/mysql-test/r/grant_cache.result index 0ffc48ad879..c8ae0b4d9b3 100644 --- a/mysql-test/r/grant_cache.result +++ b/mysql-test/r/grant_cache.result @@ -122,7 +122,7 @@ select "user4"; user4 user4 select a from t1; -ERROR 42000: No Database Selected +ERROR 3D000: No Database Selected select * from mysqltest.t1,test.t1; a b c a 1 1 1 test.t1 diff --git a/mysys/mf_loadpath.c b/mysys/mf_loadpath.c index 2c90d9f90a6..a46b43c34d4 100644 --- a/mysys/mf_loadpath.c +++ b/mysys/mf_loadpath.c @@ -28,6 +28,7 @@ my_string my_load_path(my_string to, const char *path, const char *own_path_prefix) { char buff[FN_REFLEN]; + int is_cur; DBUG_ENTER("my_load_path"); DBUG_PRINT("enter",("path: %s prefix: %s",path, own_path_prefix ? own_path_prefix : "")); @@ -35,12 +36,14 @@ my_string my_load_path(my_string to, const char *path, if ((path[0] == FN_HOMELIB && path[1] == FN_LIBCHAR) || test_if_hard_path(path)) VOID(strmov(buff,path)); - else if ((path[0] == FN_CURLIB && path[1] == FN_LIBCHAR) || + else if ((is_cur=(path[0] == FN_CURLIB && path[1] == FN_LIBCHAR)) || (is_prefix((gptr) path,FN_PARENTDIR)) || ! own_path_prefix) { - if (! my_getwd(buff,(uint) (FN_REFLEN+2-strlen(path)),MYF(0))) - VOID(strcat(buff,path+2)); + if (is_cur) + is_cur=2; /* Remove current dir */ + if (! my_getwd(buff,(uint) (FN_REFLEN-strlen(path)+is_cur),MYF(0))) + VOID(strcat(buff,path+is_cur)); else VOID(strmov(buff,path)); /* Return org file name */ } From 2a33b0514ee0dfb313bdb53551edc7df20ac1a05 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Tue, 1 Jul 2003 19:05:08 +0300 Subject: [PATCH 14/54] fixed uninitialized pointer --- sql/mysqld.cc | 7 ++++++- sql/sql_parse.cc | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 27fc8ea70ac..0ea6b0778d5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1821,7 +1821,12 @@ extern "C" int my_message_sql(uint error, const char *str, DBUG_PRINT("error", ("Message: '%s'", str)); if ((thd= current_thd)) { - if (thd->lex.current_select->no_error && !thd->is_fatal_error) + /* + thd->lex.current_select equel to zero if lex structure is not inited + (not query command (COM_QUERY)) + */ + if (thd->lex.current_select && + thd->lex.current_select->no_error && !thd->is_fatal_error) { DBUG_PRINT("error", ("above error converted to warning")); push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5070466007e..6ebb338f872 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1057,6 +1057,11 @@ bool do_command(THD *thd) net= &thd->net; thd->current_tablenr=0; + /* + indicator of uninitialized lex => normal flow of errors handling + (see my_message_sql) + */ + thd->lex.current_select= 0; packet=0; old_timeout=net->read_timeout; From 19bc36241ac8d572265b159de6348db5443e1eaf Mon Sep 17 00:00:00 2001 From: "venu@hundin.mysql.fi" <> Date: Wed, 2 Jul 2003 10:49:07 +0300 Subject: [PATCH 15/54] Removed dbug.h inclussion from client/get_password.c (windows build fix) --- client/get_password.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/get_password.c b/client/get_password.c index 9928d24de32..f187c113644 100644 --- a/client/get_password.c +++ b/client/get_password.c @@ -23,7 +23,6 @@ #include "mysql.h" #include #include -#include #if defined(HAVE_BROKEN_GETPASS) && !defined(HAVE_GETPASSPHRASE) #undef HAVE_GETPASS From feb425a9f21f10068116c0c59670fc953e0c459e Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Wed, 2 Jul 2003 14:45:35 +0300 Subject: [PATCH 16/54] fixed bug, which lead to crash mysqld by running 'mysql some_db_with_tables' --- sql/item.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sql/item.cc b/sql/item.cc index 3ea537a19de..9b3e367ccff 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -50,7 +50,13 @@ Item::Item(): next= thd->free_list; // Put in free list thd->free_list= this; loop_id= 0; - if (thd->lex.current_select->parsing_place == SELECT_LEX_NODE::SELECT_LIST) + /* + Item constractor can be called during execution other tnec SQL_COM + command => we should check thd->lex.current_select on zero (thd->lex + can be uninitialized) + */ + if (thd->lex.current_select && + thd->lex.current_select->parsing_place == SELECT_LEX_NODE::SELECT_LIST) thd->lex.current_select->select_items++; } From 5cd54c6945e1e0edeb3a6a8474f1dc3134fd3bd9 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Wed, 2 Jul 2003 15:03:49 +0300 Subject: [PATCH 17/54] fixed typos --- sql/item.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 9b3e367ccff..072dec4e6a6 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -51,9 +51,9 @@ Item::Item(): thd->free_list= this; loop_id= 0; /* - Item constractor can be called during execution other tnec SQL_COM + Item constructor can be called during execution other tnen SQL_COM command => we should check thd->lex.current_select on zero (thd->lex - can be uninitialized) + can be uninitialised) */ if (thd->lex.current_select && thd->lex.current_select->parsing_place == SELECT_LEX_NODE::SELECT_LIST) From 74b74ad5e7e3e7a350fbc26ad6c91abb783662e3 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Wed, 2 Jul 2003 18:34:43 +0500 Subject: [PATCH 18/54] There is no Item->binary() anymore. It was remain from 4.0. --- sql/item.h | 3 --- sql/item_cmpfunc.cc | 11 +++-------- sql/item_cmpfunc.h | 2 -- sql/item_func.cc | 13 ++++++++++++- sql/item_strfunc.cc | 2 +- sql/sql_analyse.cc | 6 ------ sql/sql_analyse.h | 5 +---- 7 files changed, 17 insertions(+), 25 deletions(-) diff --git a/sql/item.h b/sql/item.h index e80648b89de..57061221878 100644 --- a/sql/item.h +++ b/sql/item.h @@ -185,9 +185,6 @@ public: collation.collation= collation_arg->collation; collation.derivation= collation_arg->derivation; } - bool binary() const - { return charset()->state & MY_CS_BINSORT ? 1 : 0 ; } - virtual void set_outer_resolving() {} // Row emulation diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index e3586fef260..a19311cd2fe 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -380,12 +380,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, return 1; if (args[0]->maybe_null) maybe_null=1; - /* - TODO: Check if following is right - (set_charset set type of result, not how compare should be used) - */ - if (args[0]->binary()) - set_charset(&my_charset_bin); + with_sum_func= args[0]->with_sum_func; used_tables_cache= args[0]->used_tables(); const_item_cache= args[0]->const_item(); @@ -933,7 +928,7 @@ Item *Item_func_case::find_item(String *str) if ((tmp=args[i]->val_str(str))) // If not null { /* QQ: COERCIBILITY */ - if (first_expr_is_binary || args[i]->binary()) + if (first_expr_is_binary || (args[i]->charset()->state & MY_CS_BINSORT)) { if (sortcmp(tmp,first_expr_str,&my_charset_bin)==0) return args[i+1]; @@ -1044,7 +1039,7 @@ Item_func_case::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) used_tables_cache|=(first_expr)->used_tables(); const_item_cache&= (first_expr)->const_item(); with_sum_func= with_sum_func || (first_expr)->with_sum_func; - first_expr_is_binary= first_expr->binary(); + first_expr_is_binary= first_expr->charset()->state & MY_CS_BINSORT; } if (else_expr) { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 1311cae335f..1d93c9b6892 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -129,8 +129,6 @@ public: bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; } void print(String *str) { Item_func::print_op(str); } bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); } - virtual bool binary() const - { return test(cmp_collation.collation->state & MY_CS_BINSORT); } static Item_bool_func2* eq_creator(Item *a, Item *b); static Item_bool_func2* ne_creator(Item *a, Item *b); diff --git a/sql/item_func.cc b/sql/item_func.cc index d7237f55522..41daa09521c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1353,7 +1353,18 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, Item *item= *arg; if (item->fix_fields(thd, tables, arg) || item->check_cols(1)) return 1; - if (item->binary()) + /* + TODO: We should think about this. It is not always + right way just to set an UDF result to return my_charset_bin + if one argument has binary sorting order. + The result collation should be calculated according to arguments + derivations in some cases and should not in other cases. + 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. + */ + if (item->charset()->state & MY_CS_BINSORT) func->set_charset(&my_charset_bin); if (item->maybe_null) func->maybe_null=1; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index ae63ac85d4d..cbfe98bfd21 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -748,7 +748,7 @@ String *Item_func_replace::val_str(String *str) res->set_charset(collation.collation); #ifdef USE_MB - binary_cmp = (args[0]->binary() || args[1]->binary() || !use_mb(res->charset())); + binary_cmp = ((res->charset()->state & MY_CS_BINSORT) || !use_mb(res->charset())); #endif if (res2->length() == 0) diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 1b1f7c75c26..ced5993e293 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -44,12 +44,6 @@ int sortcmp2(void* cmp_arg __attribute__((unused)), return sortcmp(a,b,a->charset()); } -int stringcmp2(void* cmp_arg __attribute__((unused)), - const String *a,const String *b) -{ - return sortcmp(a,b,&my_charset_bin); -} - int compare_double2(void* cmp_arg __attribute__((unused)), const double *s, const double *t) { diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h index 2087e6b2b75..3d1cffecaef 100644 --- a/sql/sql_analyse.h +++ b/sql/sql_analyse.h @@ -99,8 +99,6 @@ int collect_string(String *element, element_count count, int sortcmp2(void* cmp_arg __attribute__((unused)), const String *a,const String *b); -int stringcmp2(void* cmp_arg __attribute__((unused)), - const String *a,const String *b); class field_str :public field_info { @@ -117,8 +115,7 @@ public: max_arg("",default_charset_info), sum(0), must_be_blob(0), was_zero_fill(0), was_maybe_zerofill(0), can_be_still_num(1) - { init_tree(&tree, 0, 0, sizeof(String), a->binary() ? - (qsort_cmp2) stringcmp2 : (qsort_cmp2) sortcmp2, + { init_tree(&tree, 0, 0, sizeof(String), (qsort_cmp2) sortcmp2, 0, (tree_element_free) free_string, NULL); }; void add(); From 9ef453c74b7d8cdec5a4d2ce4de33b00fc8c2af6 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Thu, 3 Jul 2003 14:11:08 +0300 Subject: [PATCH 19/54] after review fix --- sql/sql_select.cc | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 31bb8ffc032..416c6389e9c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1959,9 +1959,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, break; case Item_func::OPTIMIZE_KEY: if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM && - // field from outer query can't be used as key - !((Item_field*) (cond_func->key_item()->real_item())) - ->depended_from) + !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) add_key_field(key_fields,*and_level, ((Item_field*) (cond_func->key_item()->real_item())) ->field, @@ -1973,9 +1971,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, cond_func->functype() == Item_func::EQUAL_FUNC); if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM && - // field from outer query can't be used as key - !((Item_field*) (cond_func->arguments()[0]->real_item())) - ->depended_from) + !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) { add_key_field(key_fields,*and_level, ((Item_field*) (cond_func->arguments()[0])->real_item()) @@ -1985,9 +1981,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, } if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && cond_func->functype() != Item_func::LIKE_FUNC && - // field from outer query can't be used as key - !((Item_field*) (cond_func->arguments()[1]->real_item())) - ->depended_from) + !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) { add_key_field(key_fields,*and_level, ((Item_field*) (cond_func->arguments()[1])->real_item()) @@ -2000,9 +1994,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, case Item_func::OPTIMIZE_NULL: /* column_name IS [NOT] NULL */ if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM && - // field from outer query can't be used as key - !((Item_field*) (cond_func->arguments()[0]->real_item())) - ->depended_from) + !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) { add_key_field(key_fields,*and_level, ((Item_field*) (cond_func->arguments()[0])->real_item()) From bc2f77f224a69a0097b6143e55ddbeb833e65f70 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Thu, 3 Jul 2003 14:48:47 +0300 Subject: [PATCH 20/54] Fixed test case to be more portable --- mysql-test/r/func_gconcat.result | 4 ++-- mysql-test/t/func_gconcat.test | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index d518cff45cf..770a98f69f9 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -168,8 +168,8 @@ insert into T_REQUEST values (1,4), (5,4), (5,5); select REQ_ID, Group_Concat(URL) as URL from T_URL, T_REQUEST where T_REQUEST.URL_ID = T_URL.URL_ID group by REQ_ID; REQ_ID URL -1 www.host.com -5 www.google.com,www.help.com,www.host.com +1 X +5 X,X,X drop table T_URL; drop table T_REQUEST; select group_concat(sum(a)) from t1 group by grp; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index a5a7abe3b01..6409d8106c2 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -78,6 +78,8 @@ drop table if exists T_REQUEST; create table T_REQUEST ( REQ_ID int(11), URL_ID int(11)); insert into T_URL values (4,'www.host.com'), (5,'www.google.com'),(5,'www.help.com'); insert into T_REQUEST values (1,4), (5,4), (5,5); +# Make this order independent +--replace_result www.help.com X www.host.com X www.google.com X select REQ_ID, Group_Concat(URL) as URL from T_URL, T_REQUEST where T_REQUEST.URL_ID = T_URL.URL_ID group by REQ_ID; drop table T_URL; From 07f94cb7cdf621d1aa49f7ddaeb735f7e663f0c9 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Thu, 3 Jul 2003 17:00:01 +0500 Subject: [PATCH 21/54] Row comparison now does compare field collations, e.g. ROW('a','b','c) = ROW('A' collate latin1_bin,'b','c') returns 0 When a number is compared to a string, character sets and collations are not aggregated. e.g. this returned error in 4.1.0: SELECT 1=_latin2'1'; because character sets was aggregated, and 1 was considered as a string of latin1 charset during this aggregation. --- mysql-test/r/func_str.result | 29 +++++++++++++++++++++ mysql-test/t/func_str.test | 17 +++++++++++++ sql/item_cmpfunc.cc | 49 ++++++++++++++---------------------- sql/item_cmpfunc.h | 7 +++--- 4 files changed, 68 insertions(+), 34 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 34c7752798d..2865a019f4b 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -1,4 +1,5 @@ drop table if exists t1; +set names latin1; select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo'; hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo hello 'hello' ""hello"" 'h'e'l'l'o' hel"lo hel'lo @@ -249,6 +250,34 @@ INSERT INTO t1 VALUES (1, 'a545f661efdd1fb66fdee3aab79945bf'); SELECT 1 FROM t1 WHERE tmp=AES_DECRYPT(tmp,"password"); 1 DROP TABLE t1; +select 1=_latin1'1'; +1=_latin1'1' +1 +select _latin1'1'=1; +_latin1'1'=1 +1 +select _latin2'1'=1; +_latin2'1'=1 +1 +select 1=_latin2'1'; +1=_latin2'1' +1 +select _latin1'1'=_latin2'1'; +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation '=' +select row('a','b','c') = row('a','b','c'); +row('a','b','c') = row('a','b','c') +1 +select row('A','b','c') = row('a','b','c'); +row('A','b','c') = row('a','b','c') +1 +select row('A' COLLATE latin1_bin,'b','c') = row('a','b','c'); +row('A' COLLATE latin1_bin,'b','c') = row('a','b','c') +0 +select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c'); +row('A','b','c') = row('a' COLLATE latin1_bin,'b','c') +0 +select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); +ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation '=' select POSITION(_latin1'B' IN _latin1'abcd'); POSITION(_latin1'B' IN _latin1'abcd') 2 diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index a898d3551d7..7dc08dece55 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -8,6 +8,8 @@ drop table if exists t1; --enable_warnings +set names latin1; + select 'hello',"'hello'",'""hello""','''h''e''l''l''o''',"hel""lo",'hel\'lo'; select 'hello' 'monty'; select length('\n\t\r\b\0\_\%\\'); @@ -136,6 +138,21 @@ DROP TABLE t1; # # Test collation and coercibility # + +select 1=_latin1'1'; +select _latin1'1'=1; +select _latin2'1'=1; +select 1=_latin2'1'; +--error 1265 +select _latin1'1'=_latin2'1'; +select row('a','b','c') = row('a','b','c'); +select row('A','b','c') = row('a','b','c'); +select row('A' COLLATE latin1_bin,'b','c') = row('a','b','c'); +select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c'); +--error 1265 +select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); + + select POSITION(_latin1'B' IN _latin1'abcd'); select POSITION(_latin1'B' IN _latin1'abcd' COLLATE latin1_bin); select POSITION(_latin1'B' COLLATE latin1_bin IN _latin1'abcd'); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index a19311cd2fe..11a6e6604bf 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -109,15 +109,6 @@ static bool convert_constant_item(Field *field, Item **item) } -bool Item_bool_func2::fix_fields(THD *thd, struct st_table_list *tables, - Item ** ref) -{ - if (Item_int_func::fix_fields(thd, tables, ref)) - return 1; - return 0; -} - - void Item_bool_func2::fix_length_and_dec() { max_length= 1; // Function returns 0 or 1 @@ -191,8 +182,6 @@ void Item_bool_func2::fix_length_and_dec() { cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, INT_RESULT); // Works for all types. - cmp_collation.set(&my_charset_bin, - DERIVATION_NONE); // For test in fix_fields return; } } @@ -206,23 +195,11 @@ void Item_bool_func2::fix_length_and_dec() { cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, INT_RESULT); // Works for all types. - cmp_collation.set(&my_charset_bin, - DERIVATION_NONE); // For test in fix_fields return; } } } set_cmp_func(); - /* - We must set cmp_charset here as we may be called from for an automatic - generated item, like in natural join - */ - if (cmp_collation.set(args[0]->collation, args[1]->collation)) - { - /* set_cmp_charset() failed */ - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); - return; - } } @@ -252,6 +229,18 @@ 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)); } } + else if (type == STRING_RESULT) + { + /* + We must set cmp_charset here as we may be called from for an automatic + generated item, like in natural join + */ + if (cmp_collation.set((*a)->collation, (*b)->collation)) + { + my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name()); + return 1; + } + } return 0; } @@ -264,7 +253,7 @@ int Arg_comparator::compare_string() if ((res2= (*b)->val_str(&owner->tmp_value2))) { owner->null_value= 0; - return sortcmp(res1,res2,owner->cmp_collation.collation); + return sortcmp(res1,res2,cmp_collation.collation); } } owner->null_value= 1; @@ -278,7 +267,7 @@ int Arg_comparator::compare_e_string() res2= (*b)->val_str(&owner->tmp_value2); if (!res1 || !res2) return test(res1 == res2); - return test(sortcmp(res1, res2, owner->cmp_collation.collation) == 0); + return test(sortcmp(res1, res2, cmp_collation.collation) == 0); } @@ -502,7 +491,7 @@ longlong Item_func_strcmp::val_int() null_value=1; return 0; } - int value= sortcmp(a,b,cmp_collation.collation); + int value= sortcmp(a,b,cmp.cmp_collation.collation); null_value=0; return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1); } @@ -1893,7 +1882,7 @@ longlong Item_func_like::val_int() null_value=0; if (canDoTurboBM) return turboBM_matches(res->ptr(), res->length()) ? 1 : 0; - return my_wildcmp(cmp_collation.collation, + return my_wildcmp(cmp.cmp_collation.collation, res->ptr(),res->ptr()+res->length(), res2->ptr(),res2->ptr()+res2->length(), escape,wild_one,wild_many) ? 0 : 1; @@ -2103,7 +2092,7 @@ void Item_func_like::turboBM_compute_suffixes(int *suff) *splm1 = pattern_len; - if (cmp_collation.collation == &my_charset_bin) + if (cmp.cmp_collation.collation == &my_charset_bin) { int i; for (i = pattern_len - 2; i >= 0; i--) @@ -2206,7 +2195,7 @@ void Item_func_like::turboBM_compute_bad_character_shifts() for (i = bmBc; i < end; i++) *i = pattern_len; - if (cmp_collation.collation == &my_charset_bin) + if (cmp.cmp_collation.collation == &my_charset_bin) { for (j = 0; j < plm1; j++) bmBc[(uint) (uchar) pattern[j]] = plm1 - j; @@ -2237,7 +2226,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const const int tlmpl= text_len - pattern_len; /* Searching */ - if (cmp_collation.collation == &my_charset_bin) + if (cmp.cmp_collation.collation == &my_charset_bin) { while (j <= tlmpl) { diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 1d93c9b6892..8309cd25a72 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -35,6 +35,8 @@ class Arg_comparator: public Sql_alloc Arg_comparator *comparators; // used only for compare_row() public: + DTCollation cmp_collation; + Arg_comparator() {}; Arg_comparator(Item **a1, Item **a2): a(a1), b(a2) {}; @@ -112,13 +114,10 @@ class Item_bool_func2 :public Item_int_func protected: Arg_comparator cmp; String tmp_value1,tmp_value2; - DTCollation cmp_collation; public: Item_bool_func2(Item *a,Item *b): - Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) - { cmp_collation.set(0,DERIVATION_NONE);} - bool fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref); + Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {} void fix_length_and_dec(); void set_cmp_func() { From 0f0a0f95adbf99586353e02a086f65bc063f8d3b Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Thu, 3 Jul 2003 15:25:00 +0300 Subject: [PATCH 22/54] fixed typo in previous fix --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9b6ff826dec..962d430bbd9 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2050,7 +2050,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, } if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && cond_func->functype() != Item_func::LIKE_FUNC && - !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) + !(cond_func->arguments()[1]->used_tables() & OUTER_REF_TABLE_BIT)) { add_key_field(key_fields,*and_level, ((Item_field*) (cond_func->arguments()[1])->real_item()) From d1607a11fe894053164bde376986969322d23cda Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Thu, 3 Jul 2003 19:24:38 +0500 Subject: [PATCH 23/54] FIELD() now takes in account arguments collations --- mysql-test/r/func_str.result | 19 +++++++++++ mysql-test/t/func_str.test | 13 ++++++++ sql/item_func.cc | 62 +++++++++++++++++++++++++++++++----- sql/item_func.h | 10 ++---- 4 files changed, 89 insertions(+), 15 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 2865a019f4b..42b96956cef 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -278,6 +278,25 @@ row('A','b','c') = row('a' COLLATE latin1_bin,'b','c') 0 select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation '=' +select FIELD('b','A','B'); +FIELD('b','A','B') +2 +select FIELD('B','A','B'); +FIELD('B','A','B') +2 +select FIELD('b' COLLATE latin1_bin,'A','B'); +FIELD('b' COLLATE latin1_bin,'A','B') +0 +select FIELD('b','A' COLLATE latin1_bin,'B'); +FIELD('b','A' COLLATE latin1_bin,'B') +0 +select FIELD(_latin2'b','A','B'); +ERROR HY000: Illegal mix of collations for operation 'field' +select FIELD('b',_latin2'A','B'); +ERROR HY000: Illegal mix of collations for operation 'field' +select FIELD('b',_latin2'A','B',1); +FIELD('b',_latin2'A','B',1) +1 select POSITION(_latin1'B' IN _latin1'abcd'); POSITION(_latin1'B' IN _latin1'abcd') 2 diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 7dc08dece55..79d2b082d01 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -152,6 +152,19 @@ select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c'); --error 1265 select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); +# +# Test FIELD() and collations +# +select FIELD('b','A','B'); +select FIELD('B','A','B'); +select FIELD('b' COLLATE latin1_bin,'A','B'); +select FIELD('b','A' COLLATE latin1_bin,'B'); +--error 1269 +select FIELD(_latin2'b','A','B'); +--error 1269 +select FIELD('b',_latin2'A','B'); +select FIELD('b',_latin2'A','B',1); + select POSITION(_latin1'B' IN _latin1'abcd'); select POSITION(_latin1'B' IN _latin1'abcd' COLLATE latin1_bin); diff --git a/sql/item_func.cc b/sql/item_func.cc index 41daa09521c..eba6a2cc8d1 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1118,19 +1118,65 @@ longlong Item_func_locate::val_int() longlong Item_func_field::val_int() { - String *field; - if (!(field=item->val_str(&value))) - return 0; // -1 if null ? - for (uint i=0 ; i < arg_count ; i++) + if (cmp_type == STRING_RESULT) { - String *tmp_value=args[i]->val_str(&tmp); - if (tmp_value && field->length() == tmp_value->length() && - !memcmp(field->ptr(),tmp_value->ptr(),tmp_value->length())) - return (longlong) (i+1); + String *field; + if (!(field=item->val_str(&value))) + return 0; // -1 if null ? + for (uint i=0 ; i < arg_count ; i++) + { + String *tmp_value=args[i]->val_str(&tmp); + if (tmp_value && field->length() == tmp_value->length() && + !sortcmp(field,tmp_value,cmp_collation.collation)) + return (longlong) (i+1); + } + } + else if (cmp_type == INT_RESULT) + { + longlong val= item->val_int(); + for (uint i=0; i < arg_count ; i++) + { + if (val == args[i]->val_int()) + return (longlong) (i+1); + } + } + else + { + double val= item->val(); + for (uint i=0; i < arg_count ; i++) + { + if (val == args[i]->val()) + return (longlong) (i+1); + } } return 0; } +void Item_func_field::fix_length_and_dec() +{ + maybe_null=0; max_length=3; + used_tables_cache|= item->used_tables(); + const_item_cache&= item->const_item(); + with_sum_func= with_sum_func || item->with_sum_func; + + cmp_type= item->result_type(); + for (uint i=0; i < arg_count ; i++) + cmp_type= item_cmp_type(cmp_type, args[i]->result_type()); + + if (cmp_type == STRING_RESULT) + { + cmp_collation.set(item->collation); + for (uint i=0 ; i < arg_count ; i++) + { + if (cmp_collation.aggregate(args[i]->collation)) + { + my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),func_name()); + return; + } + } + } +} + void Item_func_field::split_sum_func(Item **ref_pointer_array, List &fields) diff --git a/sql/item_func.h b/sql/item_func.h index 9ba5bea8b87..6a08d961bc3 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -624,6 +624,8 @@ class Item_func_field :public Item_int_func { Item *item; String value,tmp; + Item_result cmp_type; + DTCollation cmp_collation; public: Item_func_field(Item *a,List &list) :Item_int_func(list),item(a) {} ~Item_func_field() { delete item; } @@ -641,13 +643,7 @@ public: const_item_cache&= item->const_item(); } const char *func_name() const { return "field"; } - void fix_length_and_dec() - { - maybe_null=0; max_length=3; - used_tables_cache|= item->used_tables(); - const_item_cache&= item->const_item(); - with_sum_func= with_sum_func || item->with_sum_func; - } + void fix_length_and_dec(); void set_outer_resolving() { item->set_outer_resolving(); From 42e5754a4b26428b98454e72cd15a8a47d620cb9 Mon Sep 17 00:00:00 2001 From: "monty@narttu.mysql.fi" <> Date: Fri, 4 Jul 2003 01:21:42 +0300 Subject: [PATCH 24/54] Fixed problem with stacksize on Unixware --- sql/mysqld.cc | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0ea6b0778d5..0a3985c3ee9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2001,22 +2001,6 @@ static int init_common_variables(const char *conf_file_name, int argc, DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname, server_version, SYSTEM_TYPE,MACHINE_TYPE)); -#ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE - { - /* Retrieve used stack size; Needed for checking stack overflows */ - size_t stack_size= 0; - pthread_attr_getstacksize(&connection_attrib, &stack_size); - /* We must check if stack_size = 0 as Solaris 2.9 can return 0 here */ - if (stack_size && stack_size < thread_stack) - { - if (global_system_variables.log_warnings) - sql_print_error("Warning: Asked for %ld thread stack, but got %ld", - thread_stack, stack_size); - thread_stack= stack_size; - } - } -#endif - #if defined( SET_RLIMIT_NOFILE) || defined( OS2) /* connections and databases needs lots of files */ { @@ -2366,6 +2350,21 @@ int main(int argc, char **argv) if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),CONNECT_PRIOR); pthread_attr_setstacksize(&connection_attrib,thread_stack); +#ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE + { + /* Retrieve used stack size; Needed for checking stack overflows */ + size_t stack_size= 0; + pthread_attr_getstacksize(&connection_attrib, &stack_size); + /* We must check if stack_size = 0 as Solaris 2.9 can return 0 here */ + if (stack_size && stack_size < thread_stack) + { + if (global_system_variables.log_warnings) + sql_print_error("Warning: Asked for %ld thread stack, but got %ld", + thread_stack, stack_size); + thread_stack= stack_size; + } + } +#endif (void) thr_setconcurrency(concurrency); // 10 by default select_thread=pthread_self(); From 2927f2a293328055345d2e2c41c25be3645dadc6 Mon Sep 17 00:00:00 2001 From: "ram@mysql.r18.ru" <> Date: Fri, 4 Jul 2003 14:41:01 +0500 Subject: [PATCH 25/54] fix and test case for the bug #787: HANDLER without INDEX doesn't work with deleted rows --- mysql-test/r/handler.result | 19 ++++++++++++++++++ mysql-test/t/handler.test | 14 +++++++++++++ sql/sql_handler.cc | 39 ++++++++++++++++--------------------- 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result index 26b3c700d59..4e0153006f8 100644 --- a/mysql-test/r/handler.result +++ b/mysql-test/r/handler.result @@ -148,3 +148,22 @@ alter table t1 type=MyISAM; handler t2 read first; ERROR 42S02: Unknown table 't2' in HANDLER drop table t1; +create table t1 (a int); +insert into t1 values (1),(2),(3),(4),(5),(6); +delete from t1 limit 2; +handler t1 open; +handler t1 read first; +a +3 +handler t1 read first limit 1,1; +a +4 +handler t1 read first limit 2,2; +a +5 +6 +delete from t1 limit 3; +handler t1 read first; +a +6 +drop table t1; diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index 30746f10c62..15d2e954a95 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -85,3 +85,17 @@ alter table t1 type=MyISAM; handler t2 read first; drop table t1; +# +# test case for the bug #787 +# + +create table t1 (a int); +insert into t1 values (1),(2),(3),(4),(5),(6); +delete from t1 limit 2; +handler t1 open; +handler t1 read first; +handler t1 read first limit 1,1; +handler t1 read first limit 2,2; +delete from t1 limit 3; +handler t1 read first; +drop table t1; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 7c07c08bcac..79d13039784 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -222,6 +222,8 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, goto err; } + if (err == HA_ERR_RECORD_DELETED) + continue; if (err) { if (err != HA_ERR_KEY_NOT_FOUND && err != HA_ERR_END_OF_FILE) @@ -233,31 +235,24 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } goto ok; } - if (cond) + if (cond && !cond->val_int()) + continue; + if (!err && num_rows >= offset_limit) { - err=err; - if (!cond->val_int()) - continue; - } - if (num_rows >= offset_limit) - { - if (!err) + String *packet = &thd->packet; + Item *item; + protocol->prepare_for_resend(); + it.rewind(); + while ((item=it++)) { - String *packet = &thd->packet; - Item *item; - protocol->prepare_for_resend(); - it.rewind(); - while ((item=it++)) - { - if (item->send(thd->protocol, &buffer)) - { - protocol->free(); // Free used - my_error(ER_OUT_OF_RESOURCES,MYF(0)); - goto err; - } - } - protocol->write(); + if (item->send(thd->protocol, &buffer)) + { + protocol->free(); // Free used + my_error(ER_OUT_OF_RESOURCES,MYF(0)); + goto err; + } } + protocol->write(); } num_rows++; } From 4aac5d99387cb12b5b06956746a396013cd97bea Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Fri, 4 Jul 2003 12:07:06 +0200 Subject: [PATCH 26/54] enabling HA_READ_PREFIX_LAST_OR_PREV --- mysql-test/t/subselect.test | 2 ++ sql/opt_range.cc | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 17738ae0c16..bec2303ad0c 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -781,6 +781,7 @@ drop table if exists t1; # # key field overflow test # +--disable_warnings CREATE TABLE t1 ( FOLDERID VARCHAR(32)BINARY NOT NULL @@ -798,6 +799,7 @@ FOLDERID VARCHAR(32)BINARY NOT NULL , PRIMARY KEY ( FOLDERID ) ) TYPE=InnoDB; +--enable_warnings CREATE INDEX FFOLDERID_IDX ON t1 (FOLDERID); CREATE INDEX CMFLDRPARNT_IDX ON t1 (PARENTID); INSERT INTO t1 VALUES("0c9aab05b15048c59bc35c8461507deb", "System", "System", "2003-06-05 16:30:00", "The system content repository folder.", "3", "2003-06-05 16:30:00", "System", "0", NULL, "9c9aab05b15048c59bc35c8461507deb", "1"); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 6c1c49e23fc..7eb66c4e30f 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2637,7 +2637,7 @@ int QUICK_SELECT_DESC::get_next() else { DBUG_ASSERT(range->flag & NEAR_MAX || range_reads_after_key(range)); -#ifdef NOT_IMPLEMENTED_YET +#ifndef NOT_IMPLEMENTED_YET result=file->index_read(record, (byte*) range->max_key, range->max_length, ((range->flag & NEAR_MAX) ? From 0c2041cfdf05a425330630816f15efc5da7b7c9f Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Fri, 4 Jul 2003 18:12:23 +0500 Subject: [PATCH 27/54] New methods Item_func::agg_arg_collations() Item_func::arr_arg_collations_for_comparison() to aggregate argument collations. It helps to reuse a lot of code. --- mysql-test/r/func_str.result | 6 +++ mysql-test/t/func_str.test | 8 ++++ sql/item_func.cc | 55 ++++++++++++++++++++++++++ sql/item_func.h | 3 ++ sql/item_strfunc.cc | 75 +++++++++--------------------------- 5 files changed, 90 insertions(+), 57 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 42b96956cef..c2a921e1a54 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -278,6 +278,12 @@ row('A','b','c') = row('a' COLLATE latin1_bin,'b','c') 0 select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation '=' +select concat(_latin1'a',_latin2'a'); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'concat' +select concat(_latin1'a',_latin2'a',_latin5'a'); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin5_turkish_ci,COERCIBLE) for operation 'concat' +select concat(_latin1'a',_latin2'a',_latin5'a',_latin7'a'); +ERROR HY000: Illegal mix of collations for operation 'concat' select FIELD('b','A','B'); FIELD('b','A','B') 2 diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 79d2b082d01..c9e7b1a529d 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -152,6 +152,14 @@ select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c'); --error 1265 select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c'); +--error 1265 +select concat(_latin1'a',_latin2'a'); +--error 1268 +select concat(_latin1'a',_latin2'a',_latin5'a'); +--error 1269 +select concat(_latin1'a',_latin2'a',_latin5'a',_latin7'a'); + + # # Test FIELD() and collations # diff --git a/sql/item_func.cc b/sql/item_func.cc index eba6a2cc8d1..df1bce37581 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -39,6 +39,61 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fnam fname); } +static void my_coll_agg_error(DTCollation &c1, + DTCollation &c2, + DTCollation &c3, + const char *fname) +{ + my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0), + c1.collation->name,c1.derivation_name(), + c2.collation->name,c2.derivation_name(), + c3.collation->name,c3.derivation_name(), + fname); +} + +static void my_coll_agg_error(Item** args, uint ac, const char *fname) +{ + if (2 == ac) + my_coll_agg_error(args[0]->collation, args[1]->collation, fname); + else if (3 == ac) + my_coll_agg_error(args[0]->collation, + args[1]->collation, + args[2]->collation, + fname); + else + my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),fname); +} + +bool Item_func::agg_arg_collations(DTCollation &c, uint from, uint argc) +{ + uint i; + c.set(args[from]->collation); + for (i= from+1; i < argc; i++) + { + if (c.aggregate(args[i]->collation)) + { + my_coll_agg_error(args+from, argc-from, func_name()); + return TRUE; + } + } + return FALSE; +} + +bool Item_func::agg_arg_collations_for_comparison(DTCollation &c, + uint from, uint argc) +{ + if (agg_arg_collations(c, from, argc)) + return FALSE; + + if (c.derivation == DERIVATION_NONE) + { + my_coll_agg_error(args+from, argc-from, func_name()); + return TRUE; + } + return FALSE; +} + + /* return TRUE if item is a constant */ bool diff --git a/sql/item_func.h b/sql/item_func.h index 6a08d961bc3..c7f227051f3 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -135,6 +135,9 @@ public: Field *tmp_table_field(TABLE *t_arg); void set_outer_resolving(); Item *get_tmp_table_item(THD *thd); + + bool agg_arg_collations(DTCollation &c, uint from, uint argc); + bool agg_arg_collations_for_comparison(DTCollation &c, uint from, uint argc); }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index cbfe98bfd21..8c3784a5d4e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -44,18 +44,6 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fnam fname); } -static void my_coll_agg3_error(DTCollation &c1, - DTCollation &c2, - DTCollation &c3, - const char *fname) -{ - my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0), - c1.collation->name,c1.derivation_name(), - c2.collation->name,c2.derivation_name(), - c3.collation->name,c3.derivation_name(), - fname); -} - uint nr_of_decimals(const char *str) { if ((str=strchr(str,'.'))) @@ -336,16 +324,11 @@ void Item_func_concat::fix_length_and_dec() bool first_coll= 1; max_length=0; - collation.set(args[0]->collation); + if (agg_arg_collations(collation, 0, arg_count)) + return; + for (uint i=0 ; i < arg_count ; i++) - { max_length+=args[i]->max_length; - if (collation.aggregate(args[i]->collation)) - { - my_coll_agg_error(collation, args[i]->collation, func_name()); - break; - } - } if (max_length > MAX_BLOB_WIDTH) { @@ -840,13 +823,8 @@ void Item_func_replace::fix_length_and_dec() maybe_null=1; } - collation.set(args[0]->collation); - if (!collation.aggregate(args[1]->collation)) - collation.aggregate(args[2]->collation); - - if (collation.derivation == DERIVATION_NONE) - my_coll_agg3_error(args[0]->collation, args[1]->collation, - args[2]->collation, func_name()); + if (agg_arg_collations_for_comparison(collation, 0, 3)) + return; } @@ -1050,9 +1028,9 @@ void Item_func_substr::fix_length_and_dec() void Item_func_substr_index::fix_length_and_dec() { max_length= args[0]->max_length; - if (collation.set(args[0]->collation, args[1]->collation) || - (collation.derivation == DERIVATION_NONE)) - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); + + if (agg_arg_collations_for_comparison(collation, 0, 2)) + return; } @@ -1680,20 +1658,13 @@ void Item_func_elt::fix_length_and_dec() max_length=0; decimals=0; + if (agg_arg_collations(collation, 0, arg_count)) + return; + for (uint i=0 ; i < arg_count ; i++) { set_if_bigger(max_length,args[i]->max_length); set_if_bigger(decimals,args[i]->decimals); - if (i == 0) - collation.set(args[0]->collation); - else - { - if (collation.aggregate(args[i]->collation)) - { - my_coll_agg_error(collation, args[i]->collation, func_name()); - break; - } - } } maybe_null=1; // NULL if wrong first arg with_sum_func= with_sum_func || item->with_sum_func; @@ -1786,16 +1757,13 @@ void Item_func_make_set::split_sum_func(Item **ref_pointer_array, void Item_func_make_set::fix_length_and_dec() { max_length=arg_count-1; - collation.set(args[0]->collation); + + if (agg_arg_collations(collation, 0, arg_count)) + return; + for (uint i=0 ; i < arg_count ; i++) - { max_length+=args[i]->max_length; - if (collation.aggregate(args[i]->collation)) - { - my_coll_agg_error(collation, args[i]->collation, func_name()); - break; - } - } + used_tables_cache|=item->used_tables(); const_item_cache&=item->const_item(); with_sum_func= with_sum_func || item->with_sum_func; @@ -2463,15 +2431,8 @@ void Item_func_export_set::fix_length_and_dec() uint sep_length=(arg_count > 3 ? args[3]->max_length : 1); max_length=length*64+sep_length*63; - collation.set(args[1]->collation); - for (i=2 ; i < 4 && i < arg_count ; i++) - { - if (collation.aggregate(args[i]->collation)) - { - my_coll_agg_error(collation, args[i]->collation, func_name()); - break; - } - } + if (agg_arg_collations(collation,1, min(4,arg_count))) + return; } String* Item_func_inet_ntoa::val_str(String* str) From 3fbc765b048a3802a3c3f997071b567447db6c04 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Fri, 4 Jul 2003 19:56:32 +0500 Subject: [PATCH 28/54] Better arguments format to allow reuse more code --- sql/item_func.cc | 20 ++++++++++---------- sql/item_func.h | 4 ++-- sql/item_strfunc.cc | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/sql/item_func.cc b/sql/item_func.cc index df1bce37581..0080a2bcff1 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -64,15 +64,15 @@ static void my_coll_agg_error(Item** args, uint ac, const char *fname) my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),fname); } -bool Item_func::agg_arg_collations(DTCollation &c, uint from, uint argc) +bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint ac) { uint i; - c.set(args[from]->collation); - for (i= from+1; i < argc; i++) + c.set(av[0]->collation); + for (i= 1; i < ac; i++) { - if (c.aggregate(args[i]->collation)) + if (c.aggregate(av[i]->collation)) { - my_coll_agg_error(args+from, argc-from, func_name()); + my_coll_agg_error(av, ac, func_name()); return TRUE; } } @@ -80,14 +80,14 @@ bool Item_func::agg_arg_collations(DTCollation &c, uint from, uint argc) } bool Item_func::agg_arg_collations_for_comparison(DTCollation &c, - uint from, uint argc) + Item **av, uint ac) { - if (agg_arg_collations(c, from, argc)) - return FALSE; - + if (agg_arg_collations(c, av, ac)) + return TRUE; + if (c.derivation == DERIVATION_NONE) { - my_coll_agg_error(args+from, argc-from, func_name()); + my_coll_agg_error(av, ac, func_name()); return TRUE; } return FALSE; diff --git a/sql/item_func.h b/sql/item_func.h index c7f227051f3..a5575a35851 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -136,8 +136,8 @@ public: void set_outer_resolving(); Item *get_tmp_table_item(THD *thd); - bool agg_arg_collations(DTCollation &c, uint from, uint argc); - bool agg_arg_collations_for_comparison(DTCollation &c, uint from, uint argc); + bool agg_arg_collations(DTCollation &c, Item **items, uint nitems); + bool agg_arg_collations_for_comparison(DTCollation &c, Item **items, uint nitems); }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 8c3784a5d4e..f46959e5365 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -324,7 +324,7 @@ void Item_func_concat::fix_length_and_dec() bool first_coll= 1; max_length=0; - if (agg_arg_collations(collation, 0, arg_count)) + if (agg_arg_collations(collation, args, arg_count)) return; for (uint i=0 ; i < arg_count ; i++) @@ -823,7 +823,7 @@ void Item_func_replace::fix_length_and_dec() maybe_null=1; } - if (agg_arg_collations_for_comparison(collation, 0, 3)) + if (agg_arg_collations_for_comparison(collation, args, 3)) return; } @@ -1029,7 +1029,7 @@ void Item_func_substr_index::fix_length_and_dec() { max_length= args[0]->max_length; - if (agg_arg_collations_for_comparison(collation, 0, 2)) + if (agg_arg_collations_for_comparison(collation, args, 2)) return; } @@ -1658,7 +1658,7 @@ void Item_func_elt::fix_length_and_dec() max_length=0; decimals=0; - if (agg_arg_collations(collation, 0, arg_count)) + if (agg_arg_collations(collation, args, arg_count)) return; for (uint i=0 ; i < arg_count ; i++) @@ -1758,7 +1758,7 @@ void Item_func_make_set::fix_length_and_dec() { max_length=arg_count-1; - if (agg_arg_collations(collation, 0, arg_count)) + if (agg_arg_collations(collation, args, arg_count)) return; for (uint i=0 ; i < arg_count ; i++) @@ -2431,7 +2431,7 @@ void Item_func_export_set::fix_length_and_dec() uint sep_length=(arg_count > 3 ? args[3]->max_length : 1); max_length=length*64+sep_length*63; - if (agg_arg_collations(collation,1, min(4,arg_count))) + if (agg_arg_collations(collation, args+1, min(4,arg_count)-1)) return; } From d209cf70f833c6e8c6e4a026b57e6c27e3c54a19 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Fri, 4 Jul 2003 20:19:07 +0500 Subject: [PATCH 29/54] More code was reused --- sql/item_cmpfunc.cc | 41 +++++++---------------------------------- sql/item_func.cc | 15 ++++----------- sql/item_strfunc.cc | 3 ++- 3 files changed, 13 insertions(+), 46 deletions(-) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 11a6e6604bf..326138d798d 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -32,18 +32,6 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fnam fname); } -static void my_coll_agg3_error(DTCollation &c1, - DTCollation &c2, - DTCollation &c3, - const char *fname) -{ - my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0), - c1.collation->name,c1.derivation_name(), - c2.collation->name,c2.derivation_name(), - c3.collation->name,c3.derivation_name(), - fname); -} - Item_bool_func2* Item_bool_func2::eq_creator(Item *a, Item *b) { return new Item_func_eq(a, b); @@ -572,18 +560,9 @@ void Item_func_between::fix_length_and_dec() item_cmp_type(args[1]->result_type(), args[2]->result_type())); - if (cmp_type == STRING_RESULT) - { - cmp_collation.set(args[0]->collation); - if (!cmp_collation.aggregate(args[1]->collation)) - cmp_collation.aggregate(args[2]->collation); - if (cmp_collation.derivation == DERIVATION_NONE) - { - my_coll_agg3_error(args[0]->collation, args[1]->collation, - args[2]->collation, func_name()); - return; - } - } + if (cmp_type == STRING_RESULT && + agg_arg_collations_for_comparison(cmp_collation, args, 3)) + return; /* Make a special case of compare with date/time and longlong fields. @@ -691,8 +670,8 @@ Item_func_ifnull::fix_length_and_dec() args[1]->result_type())) != REAL_RESULT) decimals= 0; - if (collation.set(args[0]->collation,args[1]->collation)) - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); + if (cached_result_type == STRING_RESULT) + agg_arg_collations(collation, args, arg_count); } @@ -768,11 +747,8 @@ Item_func_if::fix_length_and_dec() else if (arg1_type == STRING_RESULT || arg2_type == STRING_RESULT) { cached_result_type = STRING_RESULT; - if (collation.set(args[1]->collation, args[2]->collation)) - { - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); + if (agg_arg_collations(collation, args+1, 2)) return; - } } else { @@ -1972,11 +1948,8 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) max_length= 1; decimals= 0; - if (cmp_collation.set(args[0]->collation, args[1]->collation)) - { - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); + if (agg_arg_collations(cmp_collation, args, 2)) return 1; - } used_tables_cache=args[0]->used_tables() | args[1]->used_tables(); const_item_cache=args[0]->const_item() && args[1]->const_item(); diff --git a/sql/item_func.cc b/sql/item_func.cc index 0080a2bcff1..ad2bebf9efb 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -921,14 +921,9 @@ void Item_func_min_max::fix_length_and_dec() if (!args[i]->maybe_null) maybe_null=0; cmp_type=item_cmp_type(cmp_type,args[i]->result_type()); - if (i==0) - collation.set(args[0]->collation); - if (collation.aggregate(args[i]->collation)) - { - my_coll_agg_error(collation, args[i]->collation, func_name()); - break; - } } + if (cmp_type == STRING_RESULT) + agg_arg_collations_for_comparison(collation, args, arg_count); } @@ -1103,8 +1098,7 @@ longlong Item_func_coercibility::val_int() void Item_func_locate::fix_length_and_dec() { maybe_null=0; max_length=11; - if (cmp_collation.set(args[0]->collation, args[1]->collation)) - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); + agg_arg_collations_for_comparison(cmp_collation, args, 2); } longlong Item_func_locate::val_int() @@ -1310,8 +1304,7 @@ void Item_func_find_in_set::fix_length_and_dec() } } } - if (cmp_collation.set(args[0]->collation, args[1]->collation)) - my_coll_agg_error(args[0]->collation, args[1]->collation, func_name()); + agg_arg_collations_for_comparison(cmp_collation, args, 2); } static const char separator=','; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index f46959e5365..2d29f76c2d7 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1317,7 +1317,8 @@ void Item_func_trim::fix_length_and_dec() remove.set_ascii(" ",1); } else - if (collation.set(args[1]->collation, args[0]->collation)) + if (collation.set(args[1]->collation, args[0]->collation) || + collation.derivation == DERIVATION_NONE) { my_coll_agg_error(args[1]->collation, args[0]->collation, func_name()); } From 715dda10cc6d8f15afc91a35f894155de87e3328 Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Fri, 4 Jul 2003 10:54:10 -0700 Subject: [PATCH 30/54] Fix for send_fields flush after a fix for windows slowdown issue --- sql/sql_prepare.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index fcddc2d2252..c38fb44db1c 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -659,10 +659,13 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, wild_num, conds, og_num, order, group, having, proc, select_lex, unit, 0)) DBUG_RETURN(1); +#ifndef EMBEDDED_LIBRARY if (send_prep_stmt(stmt, fields.elements) || thd->protocol_simple.send_fields(&fields, 0) || + net_flush(&thd->net) || send_item_params(stmt)) DBUG_RETURN(1); +#endif join->cleanup(); } DBUG_RETURN(0); From 45e001f465ca2f9ccc659446b50dc20fb640224e Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Sat, 5 Jul 2003 03:03:31 +0300 Subject: [PATCH 31/54] reduced using of slow current_thd/current_lex macro initialization of item_thd moved to constructor (in any case we need thd in constructor) initialization of group_concat_max_len to constructor to avoid incorrect length reporting (BUG#757) removed Item_func_group_concat::fix_length_and_dec() because item have its own fix_fields and will not have inherited items --- mysql-test/r/func_gconcat.result | 9 +++++++++ mysql-test/t/func_gconcat.test | 6 ++++++ sql/item_sum.cc | 16 ++++++++-------- sql/item_sum.h | 1 - 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 770a98f69f9..3b8d8abed9e 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -177,3 +177,12 @@ ERROR HY000: Invalid use of group function select grp,group_concat(c order by 2) from t1 group by grp; ERROR 42S22: Unknown column '2' in 'group statement' drop table t1; +create table t1 (id int, name varchar(16)); +insert into t1 values (1,'longername'),(1,'evenlongername'); +select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'without distinct: how it should be' from t1; +without distinct: how it should be +1:longername,1:evenlongername +select distinct ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'with distinct: cutoff at length of shortname' from t1; +with distinct: cutoff at length of shortname +1:longername,1:evenlongername +drop table t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 6409d8106c2..7a13e396844 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -93,3 +93,9 @@ select group_concat(sum(a)) from t1 group by grp; select grp,group_concat(c order by 2) from t1 group by grp; drop table t1; + +create table t1 (id int, name varchar(16)); +insert into t1 values (1,'longername'),(1,'evenlongername'); +select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'without distinct: how it should be' from t1; +select distinct ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'with distinct: cutoff at length of shortname' from t1; +drop table t1; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 67dffb35724..e16ff6969d3 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1114,7 +1114,7 @@ void Item_sum_count_distinct::make_unique() bool Item_sum_count_distinct::setup(THD *thd) { List list; - SELECT_LEX *select_lex= current_lex->current_select->select_lex(); + SELECT_LEX *select_lex= thd->lex.current_select->select_lex(); if (select_lex->linkage == GLOBAL_OPTIONS_TYPE) return 1; @@ -1599,7 +1599,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct, warning_available(0), key_length(0), rec_offset(0), tree_mode(0), distinct(is_distinct), warning_for_row(0), separator(is_separator), tree(&tree_base), table(0), - order(0), tables_list(0), group_concat_max_len(0), + order(0), tables_list(0), show_elements(0), arg_count_order(0), arg_count_field(0), arg_show_fields(0), count_cut_values(0) @@ -1607,8 +1607,11 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct, original= 0; quick_group= 0; mark_as_sum_func(); - SELECT_LEX *select_lex= current_lex->current_select->select_lex(); + item_thd= current_thd; + SELECT_LEX *select_lex= item_thd->lex.current_select->select_lex(); order= 0; + group_concat_max_len= item_thd->variables.group_concat_max_len; + arg_show_fields= arg_count_field= is_select->elements; arg_count_order= is_order ? is_order->elements : 0; @@ -1773,7 +1776,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) } result_field= 0; null_value= 1; - fix_length_and_dec(); + max_length= group_concat_max_len; thd->allow_sum_func= 1; if (!(tmp_table_param= new TMP_TABLE_PARAM)) return 1; @@ -1786,7 +1789,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) bool Item_func_group_concat::setup(THD *thd) { List list; - SELECT_LEX *select_lex= current_lex->current_select->select_lex(); + SELECT_LEX *select_lex= thd->lex.current_select->select_lex(); if (select_lex->linkage == GLOBAL_OPTIONS_TYPE) return 1; @@ -1873,9 +1876,6 @@ bool Item_func_group_concat::setup(THD *thd) max_elements_in_tree= ((key_length) ? thd->variables.max_heap_table_size/key_length : 1); }; - item_thd= thd; - - group_concat_max_len= thd->variables.group_concat_max_len; /* Copy table and tree_mode if they belong to this item (if item have not diff --git a/sql/item_sum.h b/sql/item_sum.h index c4876201a7c..6f0d7a028a7 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -713,7 +713,6 @@ class Item_func_group_concat : public Item_sum enum Sumfunctype sum_func () const {return GROUP_CONCAT_FUNC;} const char *func_name() const { return "group_concat"; } enum Type type() const { return SUM_FUNC_ITEM; } - void fix_length_and_dec() { max_length=group_concat_max_len; } virtual Item_result result_type () const { return STRING_RESULT; } bool reset(); bool add(); From 9b6083dbe72f8c5328b33fceacf1884c370ccd38 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Sun, 6 Jul 2003 18:11:19 +0300 Subject: [PATCH 32/54] fixed memory leak in group_concat function (BUG#796) fixed test func_gconcat to be repeatable independent of presend tables and avoid removing user tables --- mysql-test/r/func_gconcat.result | 32 ++++++++++++-------------------- mysql-test/t/func_gconcat.test | 32 ++++++++++++++++---------------- sql/item_sum.cc | 18 ++++++++++++------ 3 files changed, 40 insertions(+), 42 deletions(-) diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 3b8d8abed9e..15b406bcdda 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -1,6 +1,4 @@ -drop table if exists t1; -Warnings: -Note 1051 Unknown table 't1' +drop table if exists t1, t2; create table t1 (grp int, a bigint unsigned, c char(10) not null, d char(10) not null); insert into t1 values (1,1,"a","a"); insert into t1 values (2,2,"b","a"); @@ -155,28 +153,22 @@ show warnings; Level Code Message Warning 1258 1 line(s) was(were) cut by group_concat() set group_concat_max_len = 1024; -drop table if exists T_URL; -Warnings: -Note 1051 Unknown table 'T_URL' -create table T_URL ( URL_ID int(11), URL varchar(80)); -drop table if exists T_REQUEST; -Warnings: -Note 1051 Unknown table 'T_REQUEST' -create table T_REQUEST ( REQ_ID int(11), URL_ID int(11)); -insert into T_URL values (4,'www.host.com'), (5,'www.google.com'),(5,'www.help.com'); -insert into T_REQUEST values (1,4), (5,4), (5,5); -select REQ_ID, Group_Concat(URL) as URL from T_URL, T_REQUEST where -T_REQUEST.URL_ID = T_URL.URL_ID group by REQ_ID; -REQ_ID URL -1 X -5 X,X,X -drop table T_URL; -drop table T_REQUEST; select group_concat(sum(a)) from t1 group by grp; ERROR HY000: Invalid use of group function select grp,group_concat(c order by 2) from t1 group by grp; ERROR 42S22: Unknown column '2' in 'group statement' drop table t1; +create table t1 ( URL_ID int(11), URL varchar(80)); +create table t2 ( REQ_ID int(11), URL_ID int(11)); +insert into t1 values (4,'www.host.com'), (5,'www.google.com'),(5,'www.help.com'); +insert into t2 values (1,4), (5,4), (5,5); +select REQ_ID, Group_Concat(URL) as URL from t1, t2 where +t2.URL_ID = t1.URL_ID group by REQ_ID; +REQ_ID URL +1 X +5 X,X,X +drop table t1; +drop table t2; create table t1 (id int, name varchar(16)); insert into t1 values (1,'longername'),(1,'evenlongername'); select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'without distinct: how it should be' from t1; diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 7a13e396844..f426f9ca4ee 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -1,8 +1,10 @@ # # simple test of group_concat function # +--disable_warnings +drop table if exists t1, t2; +--enable_warnings -drop table if exists t1; create table t1 (grp int, a bigint unsigned, c char(10) not null, d char(10) not null); insert into t1 values (1,1,"a","a"); insert into t1 values (2,2,"b","a"); @@ -70,21 +72,6 @@ select grp,group_concat(c) from t1 group by grp; show warnings; set group_concat_max_len = 1024; -# Test variable length - -drop table if exists T_URL; -create table T_URL ( URL_ID int(11), URL varchar(80)); -drop table if exists T_REQUEST; -create table T_REQUEST ( REQ_ID int(11), URL_ID int(11)); -insert into T_URL values (4,'www.host.com'), (5,'www.google.com'),(5,'www.help.com'); -insert into T_REQUEST values (1,4), (5,4), (5,5); -# Make this order independent ---replace_result www.help.com X www.host.com X www.google.com X -select REQ_ID, Group_Concat(URL) as URL from T_URL, T_REQUEST where -T_REQUEST.URL_ID = T_URL.URL_ID group by REQ_ID; -drop table T_URL; -drop table T_REQUEST; - # Test errors --error 1111 @@ -94,6 +81,19 @@ select grp,group_concat(c order by 2) from t1 group by grp; drop table t1; +# Test variable length + +create table t1 ( URL_ID int(11), URL varchar(80)); +create table t2 ( REQ_ID int(11), URL_ID int(11)); +insert into t1 values (4,'www.host.com'), (5,'www.google.com'),(5,'www.help.com'); +insert into t2 values (1,4), (5,4), (5,5); +# Make this order independent +--replace_result www.help.com X www.host.com X www.google.com X +select REQ_ID, Group_Concat(URL) as URL from t1, t2 where +t2.URL_ID = t1.URL_ID group by REQ_ID; +drop table t1; +drop table t2; + create table t1 (id int, name varchar(16)); insert into t1 values (1,'longername'),(1,'evenlongername'); select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'without distinct: how it should be' from t1; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index e16ff6969d3..8d3d0de466a 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1788,11 +1788,12 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) bool Item_func_group_concat::setup(THD *thd) { + DBUG_ENTER("Item_func_group_concat::setup"); List list; SELECT_LEX *select_lex= thd->lex.current_select->select_lex(); if (select_lex->linkage == GLOBAL_OPTIONS_TYPE) - return 1; + DBUG_RETURN(1); /* all not constant fields are push to list and create temp table */ @@ -1801,7 +1802,7 @@ bool Item_func_group_concat::setup(THD *thd) { Item *item= args[i]; if (list.push_back(item)) - return 1; + DBUG_RETURN(1); if (item->const_item()) { (void) item->val_int(); @@ -1810,7 +1811,7 @@ bool Item_func_group_concat::setup(THD *thd) } } if (always_null) - return 0; + DBUG_RETURN(0); List all_fields(list); if (arg_count_order) @@ -1821,13 +1822,18 @@ bool Item_func_group_concat::setup(THD *thd) } count_field_types(tmp_table_param,all_fields,0); + if (table) + { + free_tmp_table(thd, table); + tmp_table_param->cleanup(); + } /* We have to create a temporary table for that we get descriptions of fields (types, sizes and so on). */ if (!(table=create_tmp_table(thd, tmp_table_param, all_fields, 0, - 0, 0, 0,select_lex->options | thd->options))) - return 1; + 0, 0, 0,select_lex->options | thd->options))) + DBUG_RETURN(1); table->file->extra(HA_EXTRA_NO_ROWS); table->no_rows= 1; @@ -1886,7 +1892,7 @@ bool Item_func_group_concat::setup(THD *thd) original->table= table; original->tree_mode= tree_mode; } - return 0; + DBUG_RETURN(0); } /* This is used by rollup to create a separate usable copy of the function */ From ebcc7b5a4fca8fb8706e2dd8e5ae79c0d0fd5ca7 Mon Sep 17 00:00:00 2001 From: "monty@mashka.mysql.fi" <> Date: Sun, 6 Jul 2003 19:09:57 +0300 Subject: [PATCH 33/54] Support for variables with components Added framework to create/drop and manager buffers for multiple key caches --- include/my_getopt.h | 2 +- include/my_sys.h | 6 + include/mysqld_error.h | 3 +- mysql-test/r/key_cache.result | 43 ++++++ mysql-test/r/select_safe.result | 2 +- mysql-test/r/variables.result | 2 +- mysql-test/t/key_cache-master.opt | 1 + mysql-test/t/key_cache.test | 42 ++++++ mysys/my_getopt.c | 61 +++++---- sql/Makefile.am | 2 +- sql/item_func.cc | 78 +++++++++-- sql/mysql_priv.h | 8 +- sql/mysqld.cc | 31 ++++- sql/set_var.cc | 218 +++++++++++++++++++++++++----- sql/set_var.h | 105 ++++++++++---- sql/share/czech/errmsg.txt | 1 + sql/share/danish/errmsg.txt | 1 + sql/share/dutch/errmsg.txt | 1 + sql/share/english/errmsg.txt | 1 + sql/share/estonian/errmsg.txt | 1 + sql/share/french/errmsg.txt | 1 + sql/share/german/errmsg.txt | 1 + sql/share/greek/errmsg.txt | 1 + sql/share/hungarian/errmsg.txt | 1 + sql/share/italian/errmsg.txt | 1 + sql/share/japanese/errmsg.txt | 1 + sql/share/korean/errmsg.txt | 1 + sql/share/norwegian-ny/errmsg.txt | 1 + sql/share/norwegian/errmsg.txt | 1 + sql/share/polish/errmsg.txt | 1 + sql/share/portuguese/errmsg.txt | 1 + sql/share/romanian/errmsg.txt | 1 + sql/share/russian/errmsg.txt | 1 + sql/share/serbian/errmsg.txt | 1 + sql/share/slovak/errmsg.txt | 1 + sql/share/spanish/errmsg.txt | 1 + sql/share/swedish/errmsg.txt | 1 + sql/share/ukrainian/errmsg.txt | 1 + sql/sql_lex.cc | 23 ++-- sql/sql_parse.cc | 11 +- sql/sql_show.cc | 5 +- sql/sql_yacc.yy | 33 ++++- 42 files changed, 572 insertions(+), 127 deletions(-) create mode 100644 mysql-test/r/key_cache.result create mode 100644 mysql-test/t/key_cache-master.opt create mode 100644 mysql-test/t/key_cache.test diff --git a/include/my_getopt.h b/include/my_getopt.h index 213c8c3570e..148238f8d1b 100644 --- a/include/my_getopt.h +++ b/include/my_getopt.h @@ -53,7 +53,7 @@ extern int handle_options (int *argc, char ***argv, char *)); extern void my_print_help(const struct my_option *options); extern void my_print_variables(const struct my_option *options); -extern void my_getopt_register_get_addr(gptr* (*func_addr)(char *, uint, +extern void my_getopt_register_get_addr(gptr* (*func_addr)(const char *, uint, const struct my_option *)); ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp); diff --git a/include/my_sys.h b/include/my_sys.h index 48ebdc22f37..7ea9f63a50f 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -501,6 +501,12 @@ my_off_t my_b_append_tell(IO_CACHE* info); #define my_b_bytes_in_cache(info) (uint) (*(info)->current_end - \ *(info)->current_pos) +/* key_cache_variables */ +typedef struct st_keycache +{ + ulonglong size; +} KEY_CACHE; + #include /* Prototypes for mysys and my_func functions */ diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 565c2812c50..0468663239b 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -286,4 +286,5 @@ #define ER_REVOKE_GRANTS 1267 #define ER_CANT_AGGREGATE_3COLLATIONS 1268 #define ER_CANT_AGGREGATE_NCOLLATIONS 1269 -#define ER_ERROR_MESSAGES 270 +#define ER_VARIABLE_IS_NOT_STRUCT 1270 +#define ER_ERROR_MESSAGES 271 diff --git a/mysql-test/r/key_cache.result b/mysql-test/r/key_cache.result new file mode 100644 index 00000000000..8ec507b2a3f --- /dev/null +++ b/mysql-test/r/key_cache.result @@ -0,0 +1,43 @@ +SET @save_key_buffer=@@key_buffer_size; +SELECT @@key_buffer_size, @@small.key_buffer_size; +@@key_buffer_size @@small.key_buffer_size +2097152 131072 +SET @@global.key_buffer_size=16*1024*1024; +SET @@global.default.key_buffer_size=16*1024*1024; +SET @@global.default.key_buffer_size=16*1024*1024; +SET @@global.small.key_buffer_size=1*1024*1024; +SET @@global.medium.key_buffer_size=4*1024*1024; +SET @@global.medium.key_buffer_size=0; +SET @@global.medium.key_buffer_size=0; +SHOW VARIABLES like "key_buffer_size"; +Variable_name Value +key_buffer_size 16777216 +SELECT @@key_buffer_size; +@@key_buffer_size +16777216 +SELECT @@global.key_buffer_size; +@@global.key_buffer_size +16777216 +SELECT @@global.default.key_buffer_size; +@@global.default.key_buffer_size +16777216 +SELECT @@global.default.`key_buffer_size`; +@@global.default.key_buffer_size +16777216 +SELECT @@global.`default`.`key_buffer_size`; +@@global.default.key_buffer_size +16777216 +SELECT @@`default`.key_buffer_size; +@@default.key_buffer_size +16777216 +SELECT @@small.key_buffer_size; +@@small.key_buffer_size +1048576 +SELECT @@medium.key_buffer_size; +@@medium.key_buffer_size +4194304 +SET @@global.key_buffer_size=@save_key_buffer; +SELECT @@default.key_buffer_size; +ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near 'default.key_buffer_size' at line 1 +SELECT @@skr.table_type="test"; +ERROR HY000: Variable 'table_type' is not a variable component (Can't be used as XXXX.variable_name) diff --git a/mysql-test/r/select_safe.result b/mysql-test/r/select_safe.result index e73161996b8..0f2a781d073 100644 --- a/mysql-test/r/select_safe.result +++ b/mysql-test/r/select_safe.result @@ -37,7 +37,7 @@ delete from t1 where b="test" limit 1; delete from t1 where a+0=1 limit 2; SET MAX_JOIN_SIZE=2; SELECT @@MAX_JOIN_SIZE, @@SQL_BIG_SELECTS; -@@max_join_size @@sql_big_selects +@@MAX_JOIN_SIZE @@SQL_BIG_SELECTS 2 0 insert into t1 values (null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"),(null,"a"); SELECT * from t1; diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 1a773acd23e..4db791c993e 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -77,7 +77,7 @@ select last_insert_id(345); last_insert_id(345) 345 select @@IDENTITY,last_insert_id(), @@identity; -@@identity last_insert_id() @@identity +@@IDENTITY last_insert_id() @@identity 345 345 345 set big_tables=OFF, big_tables=ON, big_tables=0, big_tables=1, big_tables="OFF", big_tables="ON"; set global concurrent_insert=ON; diff --git a/mysql-test/t/key_cache-master.opt b/mysql-test/t/key_cache-master.opt new file mode 100644 index 00000000000..66e19c18a8a --- /dev/null +++ b/mysql-test/t/key_cache-master.opt @@ -0,0 +1 @@ +--key_buffer_size=2M --small.key_buffer_size=256K --small.key_buffer_size=128K diff --git a/mysql-test/t/key_cache.test b/mysql-test/t/key_cache.test new file mode 100644 index 00000000000..2da18b68624 --- /dev/null +++ b/mysql-test/t/key_cache.test @@ -0,0 +1,42 @@ +# +# Test of key cache +# + +SET @save_key_buffer=@@key_buffer_size; + +SELECT @@key_buffer_size, @@small.key_buffer_size; + +# Change default key cache size +SET @@global.key_buffer_size=16*1024*1024; +SET @@global.default.key_buffer_size=16*1024*1024; +SET @@global.default.key_buffer_size=16*1024*1024; + +SET @@global.small.key_buffer_size=1*1024*1024; +SET @@global.medium.key_buffer_size=4*1024*1024; +# Drop buffer +SET @@global.medium.key_buffer_size=0; +# Test double drop +SET @@global.medium.key_buffer_size=0; + +# Print key buffer with different syntaxes +SHOW VARIABLES like "key_buffer_size"; +SELECT @@key_buffer_size; +SELECT @@global.key_buffer_size; +SELECT @@global.default.key_buffer_size; +SELECT @@global.default.`key_buffer_size`; +SELECT @@global.`default`.`key_buffer_size`; +SELECT @@`default`.key_buffer_size; + +SELECT @@small.key_buffer_size; +SELECT @@medium.key_buffer_size; + +SET @@global.key_buffer_size=@save_key_buffer; + +# +# Errors +# + +--error 1064 +SELECT @@default.key_buffer_size; +--error 1270 +SELECT @@skr.table_type="test"; diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index 83ba8b98843..d539489cf1e 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -32,7 +32,7 @@ static longlong getopt_ll(char *arg, const struct my_option *optp, int *err); static ulonglong getopt_ull(char *arg, const struct my_option *optp, int *err); static void init_variables(const struct my_option *options); -static int setval(const struct my_option *opts, char *argument, +static int setval(const struct my_option *opts, gptr *value, char *argument, my_bool set_maximum_value); static char *check_struct_option(char *cur_arg, char *key_name); @@ -68,9 +68,9 @@ my_bool my_getopt_print_errors= 1; one. Call function 'get_one_option()' once for each option. */ -static gptr* (*getopt_get_addr)(char *, uint, const struct my_option *); +static gptr* (*getopt_get_addr)(const char *, uint, const struct my_option *); -void my_getopt_register_get_addr(gptr* (*func_addr)(char *, uint, +void my_getopt_register_get_addr(gptr* (*func_addr)(const char *, uint, const struct my_option *)) { getopt_get_addr= func_addr; @@ -395,7 +395,8 @@ int handle_options(int *argc, char ***argv, /* the other loop will break, because *optend + 1 == 0 */ } } - if ((error= setval(optp, argument, set_maximum_value))) + if ((error= setval(optp, optp->value, argument, + set_maximum_value))) { fprintf(stderr, "%s: Error while setting value '%s' to '%s'\n", @@ -417,7 +418,7 @@ int handle_options(int *argc, char ***argv, (*argc)--; /* option handled (short), decrease argument count */ continue; } - if ((error= setval(optp, argument, set_maximum_value))) + if ((error= setval(optp, value, argument, set_maximum_value))) { fprintf(stderr, "%s: Error while setting value '%s' to '%s'\n", @@ -473,13 +474,13 @@ static char *check_struct_option(char *cur_arg, char *key_name) if (end - ptr > 1) { uint len= ptr - cur_arg; - strnmov(key_name, cur_arg, len); - key_name[len]= '\0'; + set_if_smaller(len, FN_REFLEN-1); + strmake(key_name, cur_arg, len); return ++ptr; } else { - key_name= 0; + key_name[0]= 0; return cur_arg; } } @@ -491,15 +492,15 @@ static char *check_struct_option(char *cur_arg, char *key_name) Will set the option value to given value */ -static int setval(const struct my_option *opts, char *argument, +static int setval(const struct my_option *opts, gptr *value, char *argument, my_bool set_maximum_value) { int err= 0; - if (opts->value && argument) + if (value && argument) { gptr *result_pos= ((set_maximum_value) ? - opts->u_max_value : opts->value); + opts->u_max_value : value); if (!result_pos) return EXIT_NO_PTR_TO_VARIABLE; @@ -692,43 +693,45 @@ static void init_variables(const struct my_option *options) { for (; options->name; options++) { - if (options->value) + gptr *value= (options->var_type & GET_ASK_ADDR ? + (*getopt_get_addr)("", 0, options) : options->value); + if (value) { switch ((options->var_type & GET_TYPE_MASK)) { case GET_BOOL: if (options->u_max_value) *((my_bool*) options->u_max_value)= (my_bool) options->max_value; - *((my_bool*) options->value)= (my_bool) options->def_value; + *((my_bool*) value)= (my_bool) options->def_value; break; case GET_INT: if (options->u_max_value) *((int*) options->u_max_value)= (int) options->max_value; - *((int*) options->value)= (int) options->def_value; + *((int*) value)= (int) options->def_value; break; case GET_UINT: if (options->u_max_value) *((uint*) options->u_max_value)= (uint) options->max_value; - *((uint*) options->value)= (uint) options->def_value; + *((uint*) value)= (uint) options->def_value; break; case GET_LONG: if (options->u_max_value) *((long*) options->u_max_value)= (long) options->max_value; - *((long*) options->value)= (long) options->def_value; + *((long*) value)= (long) options->def_value; break; case GET_ULONG: if (options->u_max_value) *((ulong*) options->u_max_value)= (ulong) options->max_value; - *((ulong*) options->value)= (ulong) options->def_value; + *((ulong*) value)= (ulong) options->def_value; break; case GET_LL: if (options->u_max_value) *((longlong*) options->u_max_value)= (longlong) options->max_value; - *((longlong*) options->value)= (longlong) options->def_value; + *((longlong*) value)= (longlong) options->def_value; break; case GET_ULL: if (options->u_max_value) *((ulonglong*) options->u_max_value)= (ulonglong) options->max_value; - *((ulonglong*) options->value)= (ulonglong) options->def_value; + *((ulonglong*) value)= (ulonglong) options->def_value; break; default: /* dummy default to avoid compiler warnings */ break; @@ -831,7 +834,9 @@ void my_print_variables(const struct my_option *options) printf("--------------------------------- -----------------------------\n"); for (optp= options; optp->id; optp++) { - if (optp->value) + gptr *value= (optp->var_type & GET_ASK_ADDR ? + (*getopt_get_addr)("", 0, optp) : optp->value); + if (value) { printf("%s", optp->name); length= strlen(optp->name); @@ -840,29 +845,29 @@ void my_print_variables(const struct my_option *options) switch ((optp->var_type & GET_TYPE_MASK)) { case GET_STR: case GET_STR_ALLOC: /* fall through */ - printf("%s\n", *((char**) optp->value) ? *((char**) optp->value) : + printf("%s\n", *((char**) value) ? *((char**) value) : "(No default value)"); break; case GET_BOOL: - printf("%s\n", *((my_bool*) optp->value) ? "TRUE" : "FALSE"); + printf("%s\n", *((my_bool*) value) ? "TRUE" : "FALSE"); break; case GET_INT: - printf("%d\n", *((int*) optp->value)); + printf("%d\n", *((int*) value)); break; case GET_UINT: - printf("%d\n", *((uint*) optp->value)); + printf("%d\n", *((uint*) value)); break; case GET_LONG: - printf("%lu\n", *((long*) optp->value)); + printf("%lu\n", *((long*) value)); break; case GET_ULONG: - printf("%lu\n", *((ulong*) optp->value)); + printf("%lu\n", *((ulong*) value)); break; case GET_LL: - printf("%s\n", llstr(*((longlong*) optp->value), buff)); + printf("%s\n", llstr(*((longlong*) value), buff)); break; case GET_ULL: - longlong2str(*((ulonglong*) optp->value), buff, 10); + longlong2str(*((ulonglong*) value), buff, 10); printf("%s\n", buff); break; default: /* dummy default to avoid compiler warnings */ diff --git a/sql/Makefile.am b/sql/Makefile.am index fd02cc906d7..5781b6181d2 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -117,7 +117,7 @@ gen_lex_hash.o: gen_lex_hash.cc lex.h sql_yacc.cc: sql_yacc.yy sql_yacc.h: sql_yacc.yy -sql_yacc.o: sql_yacc.cc sql_yacc.h +sql_yacc.o: sql_yacc.cc sql_yacc.h $(HEADERS) @echo "Note: The following compile may take a long time." @echo "If it fails, re-run configure with --with-low-memory" $(CXXCOMPILE) $(LM_CFLAGS) -c $< diff --git a/sql/item_func.cc b/sql/item_func.cc index ad2bebf9efb..7264a3b5225 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2694,21 +2694,61 @@ longlong Item_func_bit_xor::val_int() System variables ****************************************************************************/ -Item *get_system_var(enum_var_type var_type, LEX_STRING name) +/* + Return value of an system variable base[.name] as a constant item + + SYNOPSIS + get_system_var() + thd Thread handler + var_type global / session + name Name of base or system variable + component Component. + + NOTES + If component.str = 0 then the variable name is in 'name' + + RETURN + 0 error + # constant item +*/ + + +Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name, + LEX_STRING component) { - if (!my_strcasecmp(system_charset_info, name.str, "VERSION")) + if (component.str == 0 && + !my_strcasecmp(system_charset_info, name.str, "VERSION")) return new Item_string("@@VERSION", server_version, (uint) strlen(server_version), system_charset_info); - THD *thd=current_thd; Item *item; sys_var *var; - char buff[MAX_SYS_VAR_LENGTH+3+8], *pos; + char buff[MAX_SYS_VAR_LENGTH*2+4+8], *pos; + LEX_STRING *base_name, *component_name; - if (!(var= find_sys_var(name.str, name.length))) + if (component.str) + { + base_name= &component; + component_name= &name; + } + else + { + base_name= &name; + component_name= &component; // Empty string + } + + if (!(var= find_sys_var(base_name->str, base_name->length))) return 0; - if (!(item=var->item(thd, var_type))) + if (component.str) + { + if (!var->is_struct()) + { + net_printf(thd, ER_VARIABLE_IS_NOT_STRUCT, base_name->str); + return 0; + } + } + if (!(item=var->item(thd, var_type, component_name))) return 0; // Impossible thd->lex.uncacheable(); buff[0]='@'; @@ -2718,23 +2758,37 @@ Item *get_system_var(enum_var_type var_type, LEX_STRING name) pos=strmov(pos,"session."); else if (var_type == OPT_GLOBAL) pos=strmov(pos,"global."); - memcpy(pos, var->name, var->name_length+1); + + set_if_smaller(component_name->length, MAX_SYS_VAR_LENGTH); + set_if_smaller(base_name->length, MAX_SYS_VAR_LENGTH); + + if (component_name->str) + { + memcpy(pos, component_name->str, component_name->length); + pos+= component_name->length; + *pos++= '.'; + } + memcpy(pos, base_name->str, base_name->length); + pos+= base_name->length; + // set_name() will allocate the name - item->set_name(buff,(uint) (pos-buff)+var->name_length, system_charset_info); + item->set_name(buff,(uint) (pos-buff), system_charset_info); return item; } -Item *get_system_var(enum_var_type var_type, const char *var_name, uint length, - const char *item_name) +Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name, + uint length, const char *item_name) { - THD *thd=current_thd; Item *item; sys_var *var; + LEX_STRING null_lex_string; + + null_lex_string.str= 0; var= find_sys_var(var_name, length); DBUG_ASSERT(var != 0); - if (!(item=var->item(thd, var_type))) + if (!(item=var->item(thd, var_type, &null_lex_string))) return 0; // Impossible thd->lex.uncacheable(); item->set_name(item_name, 0, system_charset_info); // Will use original name diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 5ad2cc56b8c..e54e66a236a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -770,6 +770,7 @@ extern rw_lock_t LOCK_grant; extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager; extern pthread_attr_t connection_attrib; extern I_List threads; +extern I_List key_caches; extern MY_BITMAP temp_pool; extern DATE_FORMAT dayord; extern String empty_string; @@ -903,9 +904,10 @@ extern void sql_cache_free(); extern int sql_cache_hit(THD *thd, char *inBuf, uint length); /* item.cc */ -Item *get_system_var(enum_var_type var_type, LEX_STRING name); -Item *get_system_var(enum_var_type var_type, const char *var_name, uint length, - const char *item_name); +Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name, + LEX_STRING component); +Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name, + uint length, const char *item_name); /* log.cc */ bool flush_error_log(void); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 0a3985c3ee9..709ba036f7e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -312,11 +312,12 @@ const char *sql_mode_str="OFF"; FILE *bootstrap_file; -I_List replicate_rewrite_db; +I_List replicate_rewrite_db; I_List replicate_do_db, replicate_ignore_db; // allow the user to tell us which db to replicate and which to ignore I_List binlog_do_db, binlog_ignore_db; I_List threads,thread_cache; +I_List key_caches; struct system_variables global_system_variables; struct system_variables max_system_variables; @@ -875,6 +876,7 @@ void clean_up(bool print_message) #endif (void) ha_panic(HA_PANIC_CLOSE); /* close all tables and logs */ end_key_cache(); + delete_elements(&key_caches, free_key_cache); end_thr_alarm(1); /* Free allocated memory */ #ifdef USE_RAID end_raid(); @@ -4103,7 +4105,7 @@ replicating a LOAD DATA INFILE command.", REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE, 0}, {"key_buffer_size", OPT_KEY_BUFFER_SIZE, - "The size of the buffer used for index blocks. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.", + "The size of the buffer used for index blocks for MyISAM tables. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.", (gptr*) &keybuff_size, (gptr*) &keybuff_size, 0, (enum get_opt_var_type) (GET_ULL | GET_ASK_ADDR), REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, @@ -4679,6 +4681,9 @@ static void mysql_init_variables(void) my_bind_addr = htonl(INADDR_ANY); threads.empty(); thread_cache.empty(); + key_caches.empty(); + if (!get_or_create_key_cache("default", 7)) + exit(1); /* Initialize structures that is used when processing options */ replicate_rewrite_db.empty(); @@ -5309,16 +5314,30 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), } return 0; } - /* Initiates DEBUG - but no debugging here ! */ extern "C" gptr * -mysql_getopt_value(char *keyname, uint key_length, +mysql_getopt_value(const char *keyname, uint key_length, const struct my_option *option) { + if (!key_length) + { + keyname= "default"; + key_length= 7; + } + switch (option->id) { + case OPT_KEY_BUFFER_SIZE: + { + KEY_CACHE *key_cache; + if (!(key_cache= get_or_create_key_cache(keyname, key_length))) + exit(1); + return (gptr*) &key_cache->size; + } + } return option->value; } + static void get_options(int argc,char **argv) { int ho_error; @@ -5366,6 +5385,8 @@ static void get_options(int argc,char **argv) table_alias_charset= (lower_case_table_names ? files_charset_info : &my_charset_bin); + /* QQ To be deleted when we have key cache variables in a struct */ + keybuff_size= (((KEY_CACHE *) find_named(&key_caches, "default", 7))->size); } @@ -5580,6 +5601,6 @@ template class I_List; template class I_List_iterator; template class I_List; template class I_List; - +template class I_List; FIX_GCC_LINKING_PROBLEM #endif diff --git a/sql/set_var.cc b/sql/set_var.cc index a281fac530a..cb6c875d513 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2003 MySQL 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 @@ -86,9 +86,9 @@ static void fix_net_retry_count(THD *thd, enum_var_type type); static void fix_max_join_size(THD *thd, enum_var_type type); static void fix_query_cache_size(THD *thd, enum_var_type type); static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type); -static void fix_key_buffer_size(THD *thd, enum_var_type type); static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type); static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type); +static KEY_CACHE *create_key_cache(const char *name, uint length); void fix_sql_mode_var(THD *thd, enum_var_type type); static byte *get_error_count(THD *thd); static byte *get_warning_count(THD *thd); @@ -136,9 +136,7 @@ sys_var_thd_ulong sys_interactive_timeout("interactive_timeout", &SV::net_interactive_timeout); sys_var_thd_ulong sys_join_buffer_size("join_buffer_size", &SV::join_buff_size); -sys_var_ulonglong_ptr sys_key_buffer_size("key_buffer_size", - &keybuff_size, - fix_key_buffer_size); +sys_var_key_buffer_size sys_key_buffer_size("key_buffer_size"); sys_var_bool_ptr sys_local_infile("local_infile", &opt_local_infile); sys_var_thd_bool sys_log_warnings("log_warnings", &SV::log_warnings); @@ -793,12 +791,6 @@ static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type) #endif -static void fix_key_buffer_size(THD *thd, enum_var_type type) -{ - ha_resize_key_cache(); -} - - void fix_delay_key_write(THD *thd, enum_var_type type) { switch ((enum_delay_key_write) delay_key_write_options) { @@ -870,7 +862,7 @@ bool sys_var_enum::update(THD *thd, set_var *var) } -byte *sys_var_enum::value_ptr(THD *thd, enum_var_type type) +byte *sys_var_enum::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) { return (byte*) enum_names->type_names[*value]; } @@ -906,7 +898,8 @@ void sys_var_thd_ulong::set_default(THD *thd, enum_var_type type) } -byte *sys_var_thd_ulong::value_ptr(THD *thd, enum_var_type type) +byte *sys_var_thd_ulong::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) { if (type == OPT_GLOBAL) return (byte*) &(global_system_variables.*offset); @@ -951,7 +944,8 @@ void sys_var_thd_ha_rows::set_default(THD *thd, enum_var_type type) } -byte *sys_var_thd_ha_rows::value_ptr(THD *thd, enum_var_type type) +byte *sys_var_thd_ha_rows::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) { if (type == OPT_GLOBAL) return (byte*) &(global_system_variables.*offset); @@ -994,7 +988,8 @@ void sys_var_thd_ulonglong::set_default(THD *thd, enum_var_type type) } -byte *sys_var_thd_ulonglong::value_ptr(THD *thd, enum_var_type type) +byte *sys_var_thd_ulonglong::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) { if (type == OPT_GLOBAL) return (byte*) &(global_system_variables.*offset); @@ -1021,7 +1016,8 @@ void sys_var_thd_bool::set_default(THD *thd, enum_var_type type) } -byte *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type) +byte *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) { if (type == OPT_GLOBAL) return (byte*) &(global_system_variables.*offset); @@ -1115,7 +1111,7 @@ err: to create an item that gets the current value at fix_fields() stage. */ -Item *sys_var::item(THD *thd, enum_var_type var_type) +Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) { if (check_type(var_type)) { @@ -1131,16 +1127,16 @@ Item *sys_var::item(THD *thd, enum_var_type var_type) } switch (type()) { case SHOW_LONG: - return new Item_uint((int32) *(ulong*) value_ptr(thd, var_type)); + return new Item_uint((int32) *(ulong*) value_ptr(thd, var_type, base)); case SHOW_LONGLONG: - return new Item_int(*(longlong*) value_ptr(thd, var_type)); + return new Item_int(*(longlong*) value_ptr(thd, var_type, base)); case SHOW_HA_ROWS: - return new Item_int((longlong) *(ha_rows*) value_ptr(thd, var_type)); + return new Item_int((longlong) *(ha_rows*) value_ptr(thd, var_type, base)); case SHOW_MY_BOOL: - return new Item_int((int32) *(my_bool*) value_ptr(thd, var_type),1); + return new Item_int((int32) *(my_bool*) value_ptr(thd, var_type, base),1); case SHOW_CHAR: { - char *str= (char*) value_ptr(thd, var_type); + char *str= (char*) value_ptr(thd, var_type, base); return new Item_string(str, strlen(str), system_charset_info); } default: @@ -1169,7 +1165,8 @@ void sys_var_thd_enum::set_default(THD *thd, enum_var_type type) } -byte *sys_var_thd_enum::value_ptr(THD *thd, enum_var_type type) +byte *sys_var_thd_enum::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) { ulong tmp= ((type == OPT_GLOBAL) ? global_system_variables.*offset : @@ -1186,7 +1183,8 @@ bool sys_var_thd_bit::update(THD *thd, set_var *var) } -byte *sys_var_thd_bit::value_ptr(THD *thd, enum_var_type type) +byte *sys_var_thd_bit::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) { /* If reverse is 0 (default) return 1 if bit is set. @@ -1249,6 +1247,7 @@ bool sys_var_collation::check(THD *thd, set_var *var) return 0; } + bool sys_var_character_set::check(THD *thd, set_var *var) { CHARSET_INFO *tmp; @@ -1274,20 +1273,24 @@ bool sys_var_character_set::check(THD *thd, set_var *var) return 0; } + bool sys_var_character_set::update(THD *thd, set_var *var) { ci_ptr(thd,var->type)[0]= var->save_result.charset; return 0; } -byte *sys_var_character_set::value_ptr(THD *thd, enum_var_type type) + +byte *sys_var_character_set::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) { CHARSET_INFO *cs= ci_ptr(thd,type)[0]; return cs ? (byte*) cs->csname : (byte*) "NULL"; } -CHARSET_INFO ** sys_var_character_set_connection::ci_ptr(THD *thd, enum_var_type type) +CHARSET_INFO ** sys_var_character_set_connection::ci_ptr(THD *thd, + enum_var_type type) { if (type == OPT_GLOBAL) return &global_system_variables.collation_connection; @@ -1295,7 +1298,9 @@ CHARSET_INFO ** sys_var_character_set_connection::ci_ptr(THD *thd, enum_var_type return &thd->variables.collation_connection; } -void sys_var_character_set_connection::set_default(THD *thd, enum_var_type type) + +void sys_var_character_set_connection::set_default(THD *thd, + enum_var_type type) { if (type == OPT_GLOBAL) global_system_variables.collation_connection= default_charset_info; @@ -1304,7 +1309,8 @@ void sys_var_character_set_connection::set_default(THD *thd, enum_var_type type) } -CHARSET_INFO ** sys_var_character_set_client::ci_ptr(THD *thd, enum_var_type type) +CHARSET_INFO ** sys_var_character_set_client::ci_ptr(THD *thd, + enum_var_type type) { if (type == OPT_GLOBAL) return &global_system_variables.character_set_client; @@ -1312,6 +1318,7 @@ CHARSET_INFO ** sys_var_character_set_client::ci_ptr(THD *thd, enum_var_type typ return &thd->variables.character_set_client; } + void sys_var_character_set_client::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) @@ -1320,6 +1327,7 @@ void sys_var_character_set_client::set_default(THD *thd, enum_var_type type) thd->variables.character_set_client= global_system_variables.character_set_client; } + CHARSET_INFO ** sys_var_character_set_results::ci_ptr(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) @@ -1328,6 +1336,7 @@ CHARSET_INFO ** sys_var_character_set_results::ci_ptr(THD *thd, enum_var_type ty return &thd->variables.character_set_results; } + void sys_var_character_set_results::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) @@ -1336,6 +1345,7 @@ void sys_var_character_set_results::set_default(THD *thd, enum_var_type type) thd->variables.character_set_results= global_system_variables.character_set_results; } + CHARSET_INFO ** sys_var_character_set_server::ci_ptr(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) @@ -1344,6 +1354,7 @@ CHARSET_INFO ** sys_var_character_set_server::ci_ptr(THD *thd, enum_var_type typ return &thd->variables.character_set_server; } + void sys_var_character_set_server::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) @@ -1352,7 +1363,9 @@ void sys_var_character_set_server::set_default(THD *thd, enum_var_type type) thd->variables.character_set_server= global_system_variables.character_set_server; } -CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd, enum_var_type type) + +CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd, + enum_var_type type) { if (type == OPT_GLOBAL) return &global_system_variables.character_set_database; @@ -1360,6 +1373,7 @@ CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd, enum_var_type t return &thd->variables.character_set_database; } + void sys_var_character_set_database::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) @@ -1368,6 +1382,7 @@ void sys_var_character_set_database::set_default(THD *thd, enum_var_type type) thd->variables.character_set_database= thd->db_charset; } + bool sys_var_collation_connection::update(THD *thd, set_var *var) { if (var->type == OPT_GLOBAL) @@ -1377,7 +1392,9 @@ bool sys_var_collation_connection::update(THD *thd, set_var *var) return 0; } -byte *sys_var_collation_connection::value_ptr(THD *thd, enum_var_type type) + +byte *sys_var_collation_connection::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) { CHARSET_INFO *cs= ((type == OPT_GLOBAL) ? global_system_variables.collation_connection : @@ -1385,6 +1402,7 @@ byte *sys_var_collation_connection::value_ptr(THD *thd, enum_var_type type) return cs ? (byte*) cs->name : (byte*) "NULL"; } + void sys_var_collation_connection::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) @@ -1394,6 +1412,71 @@ void sys_var_collation_connection::set_default(THD *thd, enum_var_type type) } +bool sys_var_key_buffer_size::update(THD *thd, set_var *var) +{ + ulonglong tmp= var->value->val_int(); + if (!base_name.length) + { + base_name.str= (char*) "default"; + base_name.length= 7; + } + KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, base_name.str, + base_name.length); + if (!key_cache) + { + if (!tmp) // Tried to delete cache + return 0; // Ok, nothing to do + if (!(key_cache= create_key_cache(base_name.str, + base_name.length))) + return 1; + } + if (!tmp) + { + /* Delete not default key caches */ + if (base_name.length != 7 || memcpy(base_name.str, "default", 7)) + { + /* + QQ: Here we should move tables using this key cache to default + key cache + */ + delete key_cache; + return 0; + } + } + + key_cache->size= (ulonglong) getopt_ull_limit_value(tmp, option_limits); + + /* QQ: Needs to be updated when we have multiple key caches */ + keybuff_size= key_cache->size; + ha_resize_key_cache(); + return 0; +} + +static ulonglong zero=0; + +byte *sys_var_key_buffer_size::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) +{ + const char *name; + uint length; + + if (!base->str) + { + name= "default"; + length= 7; + } + else + { + name= base->str; + length= base->length; + } + KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, name, length); + if (!key_cache) + return (byte*) &zero; + return (byte*) &key_cache->size; +} + + /***************************************************************************** Functions to handle SET NAMES and SET CHARACTER SET @@ -1429,7 +1512,8 @@ void sys_var_timestamp::set_default(THD *thd, enum_var_type type) } -byte *sys_var_timestamp::value_ptr(THD *thd, enum_var_type type) +byte *sys_var_timestamp::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) { thd->sys_var_tmp.long_value= (long) thd->start_time; return (byte*) &thd->sys_var_tmp.long_value; @@ -1443,7 +1527,8 @@ bool sys_var_last_insert_id::update(THD *thd, set_var *var) } -byte *sys_var_last_insert_id::value_ptr(THD *thd, enum_var_type type) +byte *sys_var_last_insert_id::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) { thd->sys_var_tmp.long_value= (long) thd->insert_id(); return (byte*) &thd->last_insert_id; @@ -1457,7 +1542,8 @@ bool sys_var_insert_id::update(THD *thd, set_var *var) } -byte *sys_var_insert_id::value_ptr(THD *thd, enum_var_type type) +byte *sys_var_insert_id::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) { return (byte*) &thd->current_insert_id; } @@ -1848,7 +1934,8 @@ int set_var_password::update(THD *thd) Functions to handle sql_mode ****************************************************************************/ -byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type) +byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type, + LEX_STRING *base) { ulong val; char buff[256]; @@ -1945,6 +2032,68 @@ ulong fix_sql_mode(ulong sql_mode) } +/**************************************************************************** + Named list handling +****************************************************************************/ + +gptr find_named(I_List *list, const char *name, uint length) +{ + I_List_iterator it(*list); + NAMED_LIST *element; + while ((element= it++)) + { + if (element->cmp(name, length)) + return element->data; + } + return 0; +} + + +void delete_elements(I_List *list, void (*free_element)(gptr)) +{ + NAMED_LIST *element; + while ((element= list->get())) + { + (*free_element)(element->data); + delete element; + } +} + + +/* Key cache functions */ + +static KEY_CACHE *create_key_cache(const char *name, uint length) +{ + KEY_CACHE *key_cache; + DBUG_PRINT("info",("Creating key cache: %s", name)); + if ((key_cache= (KEY_CACHE*) my_malloc(sizeof(KEY_CACHE), + MYF(MY_ZEROFILL | MY_WME)))) + { + if (!new NAMED_LIST(&key_caches, name, length, (gptr) key_cache)) + { + my_free((char*) key_cache, MYF(0)); + key_cache= 0; + } + } + return key_cache; +} + + +KEY_CACHE *get_or_create_key_cache(const char *name, uint length) +{ + KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, name, + length); + if (!key_cache) + key_cache= create_key_cache(name, length); + return key_cache; +} + + +void free_key_cache(gptr key_cache) +{ + my_free(key_cache, MYF(0)); +} + /**************************************************************************** Used templates @@ -1953,4 +2102,5 @@ ulong fix_sql_mode(ulong sql_mode) #ifdef __GNUC__ template class List; template class List_iterator_fast; +template class I_List_iterator; #endif diff --git a/sql/set_var.h b/sql/set_var.h index 5a0fbd21809..978aba3384a 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -47,12 +47,18 @@ public: struct my_option *option_limits; /* Updated by by set_var_init() */ uint name_length; /* Updated by by set_var_init() */ const char *name; + LEX_STRING base_name; /* for structs */ + sys_after_update_func after_update; sys_var(const char *name_arg) :name(name_arg),after_update(0) - {} + { + base_name.length=0; + } sys_var(const char *name_arg,sys_after_update_func func) :name(name_arg),after_update(func) - {} + { + base_name.length=0; + } virtual ~sys_var() {} virtual bool check(THD *thd, set_var *var) { return 0; } bool check_enum(THD *thd, set_var *var, TYPELIB *enum_names); @@ -60,14 +66,16 @@ public: virtual bool update(THD *thd, set_var *var)=0; virtual void set_default(THD *thd, enum_var_type type) {} virtual SHOW_TYPE type() { return SHOW_UNDEF; } - virtual byte *value_ptr(THD *thd, enum_var_type type) { return 0; } + virtual byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) + { return 0; } virtual bool check_type(enum_var_type type) { return type != OPT_GLOBAL; } /* Error if not GLOBAL */ virtual bool check_update_type(Item_result type) { return type != INT_RESULT; } /* Assume INT */ virtual bool check_default(enum_var_type type) { return option_limits == 0; } - Item *item(THD *thd, enum_var_type type); + Item *item(THD *thd, enum_var_type type, LEX_STRING *base); + virtual bool is_struct() { return 0; } }; @@ -83,7 +91,8 @@ public: bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); SHOW_TYPE type() { return SHOW_LONG; } - byte *value_ptr(THD *thd, enum_var_type type) { return (byte*) value; } + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) + { return (byte*) value; } }; @@ -99,7 +108,8 @@ public: bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); SHOW_TYPE type() { return SHOW_LONGLONG; } - byte *value_ptr(THD *thd, enum_var_type type) { return (byte*) value; } + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) + { return (byte*) value; } }; @@ -117,7 +127,8 @@ public: bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); SHOW_TYPE type() { return SHOW_MY_BOOL; } - byte *value_ptr(THD *thd, enum_var_type type) { return (byte*) value; } + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) + { return (byte*) value; } bool check_update_type(Item_result type) { return 0; } }; @@ -149,7 +160,8 @@ public: (*set_default_func)(thd, type); } SHOW_TYPE type() { return SHOW_CHAR; } - byte *value_ptr(THD *thd, enum_var_type type) { return (byte*) value; } + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) + { return (byte*) value; } bool check_update_type(Item_result type) { return type != STRING_RESULT; /* Only accept strings */ @@ -173,7 +185,7 @@ public: } bool update(THD *thd, set_var *var); SHOW_TYPE type() { return SHOW_CHAR; } - byte *value_ptr(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); bool check_update_type(Item_result type) { return 0; } }; @@ -209,7 +221,7 @@ public: bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); SHOW_TYPE type() { return SHOW_LONG; } - byte *value_ptr(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; class sys_var_pseudo_thread_id :public sys_var_thd_ulong @@ -236,7 +248,7 @@ public: bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); SHOW_TYPE type() { return SHOW_HA_ROWS; } - byte *value_ptr(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -256,7 +268,7 @@ public: bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); SHOW_TYPE type() { return SHOW_LONGLONG; } - byte *value_ptr(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); bool check_default(enum_var_type type) { return type == OPT_GLOBAL && !option_limits; @@ -282,7 +294,7 @@ public: bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); SHOW_TYPE type() { return SHOW_MY_BOOL; } - byte *value_ptr(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); bool check(THD *thd, set_var *var) { return check_enum(thd, var, &bool_typelib); @@ -313,7 +325,7 @@ public: bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); SHOW_TYPE type() { return SHOW_CHAR; } - byte *value_ptr(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); bool check_update_type(Item_result type) { return 0; } }; @@ -332,7 +344,7 @@ public: return check_set(thd, var, enum_names); } void set_default(THD *thd, enum_var_type type); - byte *value_ptr(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -355,7 +367,7 @@ public: bool check_update_type(Item_result type) { return 0; } bool check_type(enum_var_type type) { return type == OPT_GLOBAL; } SHOW_TYPE type() { return SHOW_MY_BOOL; } - byte *value_ptr(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -370,7 +382,7 @@ public: bool check_type(enum_var_type type) { return type == OPT_GLOBAL; } bool check_default(enum_var_type type) { return 0; } SHOW_TYPE type() { return SHOW_LONG; } - byte *value_ptr(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -381,7 +393,7 @@ public: bool update(THD *thd, set_var *var); bool check_type(enum_var_type type) { return type == OPT_GLOBAL; } SHOW_TYPE type() { return SHOW_LONGLONG; } - byte *value_ptr(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -392,7 +404,7 @@ public: bool update(THD *thd, set_var *var); bool check_type(enum_var_type type) { return type == OPT_GLOBAL; } SHOW_TYPE type() { return SHOW_LONGLONG; } - byte *value_ptr(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; @@ -456,7 +468,7 @@ SHOW_TYPE type() { return SHOW_CHAR; } } bool check_default(enum_var_type type) { return 0; } bool update(THD *thd, set_var *var); - byte *value_ptr(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); virtual void set_default(THD *thd, enum_var_type type)= 0; virtual CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type)= 0; }; @@ -513,9 +525,24 @@ public: sys_var_collation_connection(const char *name_arg) :sys_var_collation(name_arg) {} bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); - byte *value_ptr(THD *thd, enum_var_type type); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); }; + +class sys_var_key_buffer_size :public sys_var +{ +public: + sys_var_key_buffer_size(const char *name_arg) + :sys_var(name_arg) + {} + bool update(THD *thd, set_var *var); + SHOW_TYPE type() { return SHOW_LONGLONG; } + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); + bool check_default(enum_var_type type) { return 1; } + bool is_struct() { return 1; } +}; + + /* Variable that you can only read from */ class sys_var_readonly: public sys_var @@ -534,7 +561,7 @@ public: bool check_default(enum_var_type type) { return 1; } bool check_type(enum_var_type type) { return type != var_type; } bool check_update_type(Item_result type) { return 1; } - byte *value_ptr(THD *thd, enum_var_type type) + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) { return (*value_ptr_func)(thd); } @@ -639,6 +666,33 @@ public: }; +/* Named lists (used for keycaches) */ + +class NAMED_LIST :public ilink +{ + const char *name; + uint name_length; +public: + gptr data; + + NAMED_LIST(I_List *links, const char *name_arg, + uint name_length_arg, gptr data_arg): + name_length(name_length_arg), data(data_arg) + { + name=my_strdup(name_arg,MYF(MY_WME)); + links->push_back(this); + } + inline bool cmp(const char *name_cmp, uint length) + { + return length == name_length && !memcmp(name, name_cmp, length); + } + ~NAMED_LIST() + { + my_free((char*) name, MYF(0)); + } +}; + + /* Prototypes for helper functions */ @@ -649,6 +703,11 @@ sys_var *find_sys_var(const char *str, uint length=0); int sql_set_variables(THD *thd, List *var_list); void fix_delay_key_write(THD *thd, enum_var_type type); ulong fix_sql_mode(ulong sql_mode); - extern sys_var_str sys_charset_system; CHARSET_INFO *get_old_charset_by_name(const char *old_name); +gptr find_named(I_List *list, const char *name, uint length); +void delete_elements(I_List *list, void (*free_element)(gptr)); + +/* key_cache functions */ +KEY_CACHE *get_or_create_key_cache(const char *name, uint length); +void free_key_cache(gptr key_cache); diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 641b1384e9a..0bd8b70a96f 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -275,3 +275,4 @@ v/* "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 574d26b7c1c..64ffdea0d71 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -269,3 +269,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index c6c975cb141..3a506c7ef69 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -277,3 +277,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index f39c415fa55..83b90089701 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -271,3 +271,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index de22d6fd111..f4107e91d5b 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -271,3 +271,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 6c1187cd0e4..9549e98326c 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -266,3 +266,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 78d53034a71..0c60685d520 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -275,3 +275,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 347370f1ac8..873f8385462 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -266,3 +266,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 313275b3cb6..93ab550b60f 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -268,3 +268,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 8af7e3ba9f7..d1a5b1b301f 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -266,3 +266,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 417a03978fb..b8bc6e1d761 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -268,3 +268,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 22395d0fb6a..9bbcaa16076 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -266,3 +266,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index de6db62cdce..53b46d3f943 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -268,3 +268,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 28db8caa8bc..26e6b39a77f 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -268,3 +268,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index fdf856c7e56..60b0779db99 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -270,3 +270,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 397784dc7dd..904d7107893 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -266,3 +266,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 8f1cdb7b259..28bb5750d41 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -270,3 +270,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index ec41a6acb34..e193eac6793 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -268,3 +268,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 77d35be2fc9..3fbd7635ce9 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -262,3 +262,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 33cabdfc752..b25935131d5 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -274,3 +274,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 35e26f35ff7..777ef612a76 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -267,3 +267,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 9cdcb20db35..2166d7fe143 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -266,3 +266,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 5a614714de2..2fc14372f54 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -271,3 +271,4 @@ "Can't revoke all privileges, grant for one or more of the requested users" "Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'", "Illegal mix of collations for operation '%s'", +"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 2eeb57f34a7..425890ab446 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -557,10 +557,12 @@ int yylex(void *arg, void *yythd) return(IDENT); case MY_LEX_IDENT_SEP: // Found ident and now '.' - lex->next_state=MY_LEX_IDENT_START;// Next is an ident (not a keyword) yylval->lex_str.str=(char*) lex->ptr; yylval->lex_str.length=1; c=yyGet(); // should be '.' + lex->next_state= MY_LEX_IDENT_START;// Next is an ident (not a keyword) + if (!ident_map[yyPeek()]) // Probably ` or " + lex->next_state= MY_LEX_START; return((int) c); case MY_LEX_NUMBER_IDENT: // number or ident which num-start @@ -601,7 +603,7 @@ int yylex(void *arg, void *yythd) yyUnget(); } // fall through - case MY_LEX_IDENT_START: // Incomplete ident + case MY_LEX_IDENT_START: // We come here after '.' #if defined(USE_MB) && defined(USE_MB_IDENT) if (use_mb(cs)) { @@ -689,6 +691,7 @@ int yylex(void *arg, void *yythd) } if (c == delim) yySkip(); // Skip end ` + lex->next_state= MY_LEX_START; return(IDENT); } case MY_LEX_SIGNED_NUMBER: // Incomplete signed number @@ -707,9 +710,9 @@ int yylex(void *arg, void *yythd) if (c != '.') { if (c == '-' && my_isspace(cs,yyPeek())) - state=MY_LEX_COMMENT; + state= MY_LEX_COMMENT; else - state = MY_LEX_CHAR; // Return sign as single char + state= MY_LEX_CHAR; // Return sign as single char break; } yyUnget(); // Fix for next loop @@ -868,7 +871,7 @@ int yylex(void *arg, void *yythd) else state=MY_LEX_CHAR; // Return '*' break; - case MY_LEX_SET_VAR: // Check if ':=' + case MY_LEX_SET_VAR: // Check if ':=' if (yyPeek() != '=') { state=MY_LEX_CHAR; // Return ':' @@ -904,8 +907,8 @@ int yylex(void *arg, void *yythd) state = MY_LEX_REAL; // Real else { - state = MY_LEX_CHAR; // return '.' - lex->next_state=MY_LEX_IDENT_START;// Next is an ident (not a keyword) + state= MY_LEX_IDENT_SEP; // return '.' + yyUnget(); // Put back '.' } break; case MY_LEX_USER_END: // end '@' of user@hostname @@ -933,8 +936,11 @@ int yylex(void *arg, void *yythd) case MY_LEX_SYSTEM_VAR: yylval->lex_str.str=(char*) lex->ptr; yylval->lex_str.length=1; - lex->next_state=MY_LEX_IDENT_OR_KEYWORD; yySkip(); // Skip '@' + lex->next_state= (state_map[yyPeek()] == + MY_LEX_USER_VARIABLE_DELIMITER ? + MY_LEX_OPERATOR_OR_IDENT : + MY_LEX_IDENT_OR_KEYWORD); return((int) '@'); case MY_LEX_IDENT_OR_KEYWORD: /* @@ -942,7 +948,6 @@ int yylex(void *arg, void *yythd) We should now be able to handle: [(global | local | session) .]variable_name */ - while (ident_map[c=yyGet()]) ; if (c == '.') lex->next_state=MY_LEX_IDENT_SEP; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0db6ce8a642..3593087d332 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3570,15 +3570,20 @@ mysql_new_select(LEX *lex, bool move_down) void create_select_for_variable(const char *var_name) { + THD *thd; LEX *lex; - LEX_STRING tmp; + LEX_STRING tmp, null_lex_string; DBUG_ENTER("create_select_for_variable"); - lex= current_lex; + + thd= current_thd; + lex= &thd->lex; mysql_init_select(lex); lex->sql_command= SQLCOM_SELECT; tmp.str= (char*) var_name; tmp.length=strlen(var_name); - add_item_to_list(lex->thd, get_system_var(OPT_SESSION, tmp)); + bzero((char*) &null_lex_string.str, sizeof(null_lex_string)); + add_item_to_list(thd, get_system_var(thd, OPT_SESSION, tmp, + null_lex_string)); DBUG_VOID_RETURN; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index fae01936357..e8cb59e387e 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1527,12 +1527,14 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, char buff[1024]; List field_list; Protocol *protocol= thd->protocol; + LEX_STRING null_lex_str; DBUG_ENTER("mysqld_show"); field_list.push_back(new Item_empty_string("Variable_name",30)); field_list.push_back(new Item_empty_string("Value",256)); if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); /* purecov: inspected */ + null_lex_str.str= 0; // For sys_var->value_ptr() /* pthread_mutex_lock(&THR_LOCK_keycache); */ pthread_mutex_lock(&LOCK_status); @@ -1551,7 +1553,8 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, if (show_type == SHOW_SYS) { show_type= ((sys_var*) value)->type(); - value= (char*) ((sys_var*) value)->value_ptr(thd, value_type); + value= (char*) ((sys_var*) value)->value_ptr(thd, value_type, + &null_lex_str); } pos= end= buff; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6072be28dca..0651672a305 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -561,7 +561,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); IDENT TEXT_STRING REAL_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 + NCHAR_STRING opt_component %type opt_table_alias @@ -1532,6 +1532,10 @@ opt_ident: /* empty */ { $$=(char*) 0; } /* Defaultlength */ | field_ident { $$=$1.str; }; +opt_component: + /* empty */ { $$.str= 0; $$.length= 0; } + | '.' ident { $$=$2; }; + string_list: text_string { Lex->interval_list.push_back($1); } | string_list ',' text_string { Lex->interval_list.push_back($3); }; @@ -2276,9 +2280,9 @@ simple_expr: $$= new Item_func_get_user_var($2); Lex->uncacheable(); } - | '@' '@' opt_var_ident_type ident_or_text + | '@' '@' opt_var_ident_type ident_or_text opt_component { - if (!($$= get_system_var((enum_var_type) $3, $4))) + if (!($$= get_system_var(YYTHD, (enum_var_type) $3, $4, $5))) YYABORT; } | sum_expr @@ -2440,7 +2444,7 @@ simple_expr: } | LAST_INSERT_ID '(' ')' { - $$= get_system_var(OPT_SESSION, "last_insert_id", 14, + $$= get_system_var(YYTHD, OPT_SESSION, "last_insert_id", 14, "last_insert_id()"); Lex->safe_to_cache_query= 0; } @@ -4590,6 +4594,27 @@ internal_variable_name: YYABORT; $$=tmp; } + | ident '.' ident + { + sys_var *tmp=find_sys_var($3.str, $3.length); + if (!tmp) + YYABORT; + if (!tmp->is_struct()) + net_printf(YYTHD, ER_VARIABLE_IS_NOT_STRUCT, $3.str); + tmp->base_name= $1; + $$=tmp; + } + | DEFAULT '.' ident + { + sys_var *tmp=find_sys_var($3.str, $3.length); + if (!tmp) + YYABORT; + if (!tmp->is_struct()) + net_printf(YYTHD, ER_VARIABLE_IS_NOT_STRUCT, $3.str); + tmp->base_name.str= (char*) "default"; + tmp->base_name.length= 7; + $$=tmp; + } ; isolation_types: From bfc70eb9c91a10ead4aa987da37ae2b0a457cf49 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Mon, 7 Jul 2003 00:45:51 +0300 Subject: [PATCH 34/54] fixed subselect with to temporary tables executing (now it return correct results. Test was commited before, but it is not pushed, BUG# is not registered, because bug was introduced after release) --- sql/sql_select.cc | 14 ++++++++++++++ sql/sql_select.h | 4 +++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0eead502f31..0aa7e67a12b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1137,6 +1137,20 @@ JOIN::exec() thd->proc_info="Copying to group table"; tmp_error= -1; + if (curr_join != this) + { + if (sum_funcs2) + { + curr_join->sum_funcs= sum_funcs2; + curr_join->sum_funcs_end= sum_funcs_end2; + } + else + { + curr_join->alloc_func_list(); + sum_funcs2= curr_join->sum_funcs; + sum_funcs_end2= curr_join->sum_funcs_end; + } + } if (curr_join->make_sum_func_list(*curr_all_fields, *curr_fields_list, 1) || (tmp_error= do_select(curr_join, (List *) 0, curr_tmp_table, diff --git a/sql/sql_select.h b/sql/sql_select.h index aa08c5c1725..7de9007369e 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -146,6 +146,8 @@ class JOIN :public Sql_alloc TABLE *exec_tmp_table1, *exec_tmp_table2; THD *thd; Item_sum **sum_funcs, ***sum_funcs_end; + /* second copy of sumfuncs (for queries with 2 temporary tables */ + Item_sum **sum_funcs2, ***sum_funcs_end2; Procedure *procedure; Item *having; Item *tmp_having; // To store Having when processed temporary table @@ -199,7 +201,7 @@ class JOIN :public Sql_alloc send_records(0), found_records(0), examined_rows(0), exec_tmp_table1(0), exec_tmp_table2(0), thd(thd_arg), - sum_funcs(0), + sum_funcs(0),sum_funcs2(0), procedure(0), having(0), tmp_having(0), select_options(select_options_arg), From bdfe922f85892c0ce492b5d74219cc82aee41d02 Mon Sep 17 00:00:00 2001 From: "paul@ice.snake.net" <> Date: Mon, 7 Jul 2003 23:35:24 -0500 Subject: [PATCH 35/54] Error message edits. (Change sentence ending with period + sentence not ending with period into single sentence.) --- sql/share/czech/errmsg.txt | 2 +- sql/share/danish/errmsg.txt | 4 ++-- sql/share/dutch/errmsg.txt | 4 ++-- sql/share/english/errmsg.txt | 4 ++-- sql/share/french/errmsg.txt | 4 ++-- sql/share/german/errmsg.txt | 4 ++-- sql/share/italian/errmsg.txt | 4 ++-- sql/share/norwegian-ny/errmsg.txt | 4 ++-- sql/share/norwegian/errmsg.txt | 4 ++-- sql/share/polish/errmsg.txt | 4 ++-- sql/share/portuguese/errmsg.txt | 4 ++-- sql/share/romanian/errmsg.txt | 4 ++-- sql/share/serbian/errmsg.txt | 4 ++-- sql/share/slovak/errmsg.txt | 4 ++-- sql/share/spanish/errmsg.txt | 4 ++-- sql/share/swedish/errmsg.txt | 2 +- 16 files changed, 30 insertions(+), 30 deletions(-) diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 641b1384e9a..f179b311c83 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -17,7 +17,7 @@ v/* "Nemohu vytvo-Bøit soubor '%-.64s' (chybový kód: %d)", "Nemohu vytvo-Bøit tabulku '%-.64s' (chybový kód: %d)", "Nemohu vytvo-Bøit databázi '%-.64s', chyba %d", -"Nemohu vytvo-Bøit databázi '%-.64s', databáze ji¾ existuje", +"Nemohu vytvo-Bøit databázi '%-.64s'; databáze ji¾ existuje", "Nemohu zru-B¹it databázi '%-.64s', databáze neexistuje", "Chyba p-Bøi ru¹ení databáze (nemohu vymazat '%-.64s', chyba %d)", "Chyba p-Bøi ru¹ení databáze (nemohu vymazat adresáø '%-.64s', chyba %d)", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 574d26b7c1c..58466ed32f7 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -11,8 +11,8 @@ "Kan ikke oprette filen '%-.64s' (Fejlkode: %d)", "Kan ikke oprette tabellen '%-.64s' (Fejlkode: %d)", "Kan ikke oprette databasen '%-.64s'. Fejl %d", -"Kan ikke oprette databasen '%-.64s'. Databasen eksisterer", -"Kan ikke slette (droppe) '%-.64s'. Databasen eksisterer ikke", +"Kan ikke oprette databasen '%-.64s'; databasen eksisterer", +"Kan ikke slette (droppe) '%-.64s'; databasen eksisterer ikke", "Fejl ved sletning (drop) af databasen (kan ikke slette '%-.64s', Fejl %d)", "Fejl ved sletting af database (kan ikke slette folderen '%-.64s', Fejl %d)", "Fejl ved sletning af '%-.64s' (Fejlkode: %d)", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index c6c975cb141..6296c39d232 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -19,8 +19,8 @@ "Kan file '%-.64s' niet aanmaken (Errcode: %d)", "Kan tabel '%-.64s' niet aanmaken (Errcode: %d)", "Kan database '%-.64s' niet aanmaken (Errcode: %d)", -"Kan database '%-.64s' niet aanmaken. Database bestaat reeds", -"Kan database '%-.64s' niet verwijderen. Database bestaat niet", +"Kan database '%-.64s' niet aanmaken; database bestaat reeds", +"Kan database '%-.64s' niet verwijderen; database bestaat niet", "Fout bij verwijderen database (kan '%-.64s' niet verwijderen, Errcode: %d)", "Fout bij verwijderen database (kan rmdir '%-.64s' niet uitvoeren, Errcode: %d)", "Fout bij het verwijderen van '%-.64s' (Errcode: %d)", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index f39c415fa55..5a9c44ef07e 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -8,8 +8,8 @@ "Can't create file '%-.64s' (errno: %d)", "Can't create table '%-.64s' (errno: %d)", "Can't create database '%-.64s'. (errno: %d)", -"Can't create database '%-.64s'. Database exists", -"Can't drop database '%-.64s'. Database doesn't exist", +"Can't create database '%-.64s'; database exists", +"Can't drop database '%-.64s'; database doesn't exist", "Error dropping database (can't delete '%-.64s', errno: %d)", "Error dropping database (can't rmdir '%-.64s', errno: %d)", "Error on delete of '%-.64s' (errno: %d)", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 6c1187cd0e4..e9a80c44f7f 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -8,8 +8,8 @@ "Ne peut créer le fichier '%-.64s' (Errcode: %d)", "Ne peut créer la table '%-.64s' (Errcode: %d)", "Ne peut créer la base '%-.64s'. Erreur %d", -"Ne peut créer la base '%-.64s'. Elle existe déjà", -"Ne peut effacer la base '%-.64s'. Elle n'existe pas", +"Ne peut créer la base '%-.64s'; elle existe déjà", +"Ne peut effacer la base '%-.64s'; elle n'existe pas", "Ne peut effacer la base '%-.64s' (erreur %d)", "Erreur en effaçant la base (rmdir '%-.64s', erreur %d)", "Erreur en effaçant '%-.64s' (Errcode: %d)", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 78d53034a71..00f0699445f 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -17,8 +17,8 @@ "Kann Datei '%-.64s' nicht erzeugen. (Fehler: %d)", "Kann Tabelle '%-.64s' nicht erzeugen. (Fehler: %d)", "Kann Datenbank '%-.64s' nicht erzeugen. (Fehler: %d)", -"Kann Datenbank '%-.64s' nicht erzeugen. Datenbank '%-.64s' existiert bereits.", -"Kann Datenbank '%-.64s' nicht löschen. Keine Datenbank '%-.64s' vorhanden.", +"Kann Datenbank '%-.64s' nicht erzeugen; datenbank '%-.64s' existiert bereits.", +"Kann Datenbank '%-.64s' nicht löschen; keine Datenbank '%-.64s' vorhanden.", "Fehler beim Löschen der Datenbank. ('%-.64s' kann nicht gelöscht werden, Fehlernuumer: %d)", "Fehler beim Löschen der Datenbank. (Verzeichnis '%-.64s' kann nicht gelöscht werden, Fehlernummer: %d)", "Fehler beim Löschen von '%-.64s'. (Fehler: %d)", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 8af7e3ba9f7..677d20a535b 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -8,8 +8,8 @@ "Impossibile creare il file '%-.64s' (errno: %d)", "Impossibile creare la tabella '%-.64s' (errno: %d)", "Impossibile creare il database '%-.64s'. (errno: %d)", -"Impossibile creare il database '%-.64s'. Il database esiste", -"Impossibile cancellare '%-.64s'. Il database non esiste", +"Impossibile creare il database '%-.64s'; il database esiste", +"Impossibile cancellare '%-.64s'; il database non esiste", "Errore durante la cancellazione del database (impossibile cancellare '%-.64s', errno: %d)", "Errore durante la cancellazione del database (impossibile rmdir '%-.64s', errno: %d)", "Errore durante la cancellazione di '%-.64s' (errno: %d)", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index de6db62cdce..6d9ac18be34 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -10,8 +10,8 @@ "Kan ikkje opprette fila '%-.64s' (Feilkode: %d)", "Kan ikkje opprette tabellen '%-.64s' (Feilkode: %d)", "Kan ikkje opprette databasen '%-.64s'. Feil %d", -"Kan ikkje opprette databasen '%-.64s'. Databasen eksisterer", -"Kan ikkje fjerne (drop) '%-.64s'. Databasen eksisterer ikkje", +"Kan ikkje opprette databasen '%-.64s'; databasen eksisterer", +"Kan ikkje fjerne (drop) '%-.64s'; databasen eksisterer ikkje", "Feil ved fjerning (drop) av databasen (kan ikkje slette '%-.64s', feil %d)", "Feil ved sletting av database (kan ikkje slette katalogen '%-.64s', feil %d)", "Feil ved sletting av '%-.64s' (Feilkode: %d)", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 28db8caa8bc..ba7c108f9ae 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -10,8 +10,8 @@ "Kan ikke opprette fila '%-.64s' (Feilkode: %d)", "Kan ikke opprette tabellen '%-.64s' (Feilkode: %d)", "Kan ikke opprette databasen '%-.64s'. Feil %d", -"Kan ikke opprette databasen '%-.64s'. Databasen eksisterer", -"Kan ikke fjerne (drop) '%-.64s'. Databasen eksisterer ikke", +"Kan ikke opprette databasen '%-.64s'; databasen eksisterer", +"Kan ikke fjerne (drop) '%-.64s'; databasen eksisterer ikke", "Feil ved fjerning (drop) av databasen (kan ikke slette '%-.64s', feil %d)", "Feil ved sletting av database (kan ikke slette katalogen '%-.64s', feil %d)", "Feil ved sletting av '%-.64s' (Feilkode: %d)", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index fdf856c7e56..04e60f5aa95 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -12,8 +12,8 @@ "Nie mo¿na stworzyæ pliku '%-.64s' (Kod b³êdu: %d)", "Nie mo¿na stworzyæ tabeli '%-.64s' (Kod b³êdu: %d)", "Nie mo¿na stworzyæ bazy danych '%-.64s'. B³?d %d", -"Nie mo¿na stworzyæ bazy danych '%-.64s'. Baza danych ju¿ istnieje", -"Nie mo¿na usun?æ bazy danych '%-.64s'. Baza danych nie istnieje", +"Nie mo¿na stworzyæ bazy danych '%-.64s'; baza danych ju¿ istnieje", +"Nie mo¿na usun?æ bazy danych '%-.64s'; baza danych nie istnieje", "B³?d podczas usuwania bazy danych (nie mo¿na usun?æ '%-.64s', b³?d %d)", "B³?d podczas usuwania bazy danych (nie mo¿na wykonaæ rmdir '%-.64s', b³?d %d)", "B³?d podczas usuwania '%-.64s' (Kod b³êdu: %d)", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 397784dc7dd..64d83c20aab 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -8,8 +8,8 @@ "Não pode criar o arquivo '%-.64s' (erro no. %d)", "Não pode criar a tabela '%-.64s' (erro no. %d)", "Não pode criar o banco de dados '%-.64s' (erro no. %d)", -"Não pode criar o banco de dados '%-.64s'. Este banco de dados já existe", -"Não pode eliminar o banco de dados '%-.64s'. Este banco de dados não existe", +"Não pode criar o banco de dados '%-.64s'; este banco de dados já existe", +"Não pode eliminar o banco de dados '%-.64s'; este banco de dados não existe", "Erro ao eliminar banco de dados (não pode eliminar '%-.64s' - erro no. %d)", "Erro ao eliminar banco de dados (não pode remover diretório '%-.64s' - erro no. %d)", "Erro na remoção de '%-.64s' (erro no. %d)", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 8f1cdb7b259..e62c857553b 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -12,8 +12,8 @@ "Nu pot sa creez fisierul '%-.64s' (Eroare: %d)", "Nu pot sa creez tabla '%-.64s' (Eroare: %d)", "Nu pot sa creez baza de date '%-.64s'. (Eroare: %d)", -"Nu pot sa creez baza de date '%-.64s'. Baza de date exista deja", -"Nu pot sa drop baza de date '%-.64s'. Baza da date este inexistenta", +"Nu pot sa creez baza de date '%-.64s'; baza de date exista deja", +"Nu pot sa drop baza de date '%-.64s'; baza da date este inexistenta", "Eroare dropuind baza de date (nu pot sa sterg '%-.64s', Eroare: %d)", "Eroare dropuind baza de date (nu pot sa rmdir '%-.64s', Eroare: %d)", "Eroare incercind sa delete '%-.64s' (Eroare: %d)", diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 77d35be2fc9..62e5519475f 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -14,8 +14,8 @@ "Ne mogu da kreiram file '%-.64s' (errno: %d)", "Ne mogu da kreiram tabelu '%-.64s' (errno: %d)", "Ne mogu da kreiram bazu '%-.64s'. (errno: %d)", -"Ne mogu da kreiram bazu '%-.64s'. Baza veæ postoji.", -"Ne mogu da izbrišem bazu '%-.64s'. Baza ne postoji.", +"Ne mogu da kreiram bazu '%-.64s'; baza veæ postoji.", +"Ne mogu da izbrišem bazu '%-.64s'; baza ne postoji.", "Ne mogu da izbrišem bazu (ne mogu da izbrišem '%-.64s', errno: %d)", "Ne mogu da izbrišem bazu (ne mogu da izbrišem direktorijum '%-.64s', errno: %d)", "Greška pri brisanju '%-.64s' (errno: %d)", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 33cabdfc752..7730a4220ba 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -16,8 +16,8 @@ "Nemô¾em vytvori» súbor '%-.64s' (chybový kód: %d)", "Nemô¾em vytvori» tabuµku '%-.64s' (chybový kód: %d)", "Nemô¾em vytvori» databázu '%-.64s'. (chybový kód: %d)", -"Nemô¾em vytvori» databázu '%-.64s'. Databáza existuje", -"Nemô¾em zmaza» databázu '%-.64s'. Databáza neexistuje", +"Nemô¾em vytvori» databázu '%-.64s'; databáza existuje", +"Nemô¾em zmaza» databázu '%-.64s'; databáza neexistuje", "Chyba pri mazaní databázy (nemô¾em zmaza» '%-.64s', chybový kód: %d)", "Chyba pri mazaní databázy (nemô¾em vymaza» adresár '%-.64s', chybový kód: %d)", "Chyba pri mazaní '%-.64s' (chybový kód: %d)", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 35e26f35ff7..8f923312969 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -9,8 +9,8 @@ "No puedo crear archivo '%-.64s' (Error: %d)", "No puedo crear tabla '%-.64s' (Error: %d)", "No puedo crear base de datos '%-.64s'. Error %d", -"No puedo crear base de datos '%-.64s'. La base de datos ya existe", -"No puedo eliminar base de datos '%-.64s'. La base de datos no existe", +"No puedo crear base de datos '%-.64s'; la base de datos ya existe", +"No puedo eliminar base de datos '%-.64s'; la base de datos no existe", "Error eliminando la base de datos(no puedo borrar '%-.64s', error %d)", "Error eliminando la base de datos (No puedo borrar directorio '%-.64s', error %d)", "Error en el borrado de '%-.64s' (Error: %d)", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 9cdcb20db35..ed60fc62387 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -9,7 +9,7 @@ "Kan inte skapa tabellen '%-.64s' (Felkod: %d)", "Kan inte skapa databasen '%-.64s'. (Felkod: %d)", "Databasen '%-.64s' existerar redan", -"Kan inte radera databasen '%-.64s'. Databasen finns inte", +"Kan inte radera databasen '%-.64s'; databasen finns inte", "Fel vid radering av databasen (Kan inte radera '%-.64s'. Felkod: %d)", "Fel vid radering av databasen (Kan inte radera biblioteket '%-.64s'. Felkod: %d)", "Kan inte radera filen '%-.64s' (Felkod: %d)", From bb718b31d0f6187a08f674026667c6d063b4b208 Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Tue, 8 Jul 2003 02:27:21 -0700 Subject: [PATCH 36/54] implementation of mysql_stmt_reset client end --- include/mysql.h | 1 + include/mysql_com.h | 1 + libmysql/libmysql.c | 23 +++++++++++++++++++++++ libmysql/libmysql.def | 1 + sql/mysql_priv.h | 1 + sql/sql_parse.cc | 5 +++++ sql/sql_prepare.cc | 2 +- 7 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/mysql.h b/include/mysql.h index bd63a10ba45..27d6b03bd0b 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -566,6 +566,7 @@ unsigned long STDCALL mysql_param_count(MYSQL_STMT * stmt); my_bool STDCALL mysql_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); my_bool STDCALL mysql_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); my_bool STDCALL mysql_stmt_close(MYSQL_STMT * stmt); +my_bool STDCALL mysql_stmt_reset(MYSQL_STMT * stmt); my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt); unsigned int STDCALL mysql_stmt_errno(MYSQL_STMT * stmt); const char *STDCALL mysql_stmt_error(MYSQL_STMT * stmt); diff --git a/include/mysql_com.h b/include/mysql_com.h index e87001ff27d..5eb59a1c7ab 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -44,6 +44,7 @@ enum enum_server_command COM_TIME, COM_DELAYED_INSERT, COM_CHANGE_USER, COM_BINLOG_DUMP, COM_TABLE_DUMP, COM_CONNECT_OUT, COM_REGISTER_SLAVE, COM_PREPARE, COM_EXECUTE, COM_LONG_DATA, COM_CLOSE_STMT, + COM_RESET_STMT, COM_END /* Must be last */ }; diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 771278c1dbb..1461d2fa128 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -3316,6 +3316,7 @@ mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong row) } else DBUG_PRINT("exit", ("stmt doesn't contain any resultset")); + DBUG_VOID_RETURN; } @@ -3421,6 +3422,28 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) return stmt_close(stmt, 0); } +/* + Reset the statement buffers in server +*/ + +my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt) +{ + char buff[MYSQL_STMT_HEADER]; + MYSQL *mysql; + DBUG_ENTER("mysql_stmt_reset"); + DBUG_ASSERT(stmt != 0); + + mysql= stmt->mysql->last_used_con; + int4store(buff, stmt->stmt_id); /* Send stmt id to server */ + if (advanced_command(mysql, COM_RESET_STMT,buff,MYSQL_STMT_HEADER,0,0,1)) + { + set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, + mysql->net.sqlstate); + DBUG_RETURN(1); + } + DBUG_RETURN(0); +} + /* Return statement error code */ diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index d641ca57274..51869eacc4b 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -98,6 +98,7 @@ EXPORTS mysql_stat mysql_stmt_affected_rows mysql_stmt_close + mysql_stmt_reset mysql_stmt_data_seek mysql_stmt_errno mysql_stmt_error diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 5ad2cc56b8c..6633912967e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -557,6 +557,7 @@ void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used); bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length); void mysql_stmt_execute(THD *thd, char *packet); void mysql_stmt_free(THD *thd, char *packet); +void mysql_stmt_reset(THD *thd, char *packet); void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length); int check_insert_fields(THD *thd,TABLE *table,List &fields, List &values, ulong counter); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0db6ce8a642..00917e296ca 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1290,6 +1290,11 @@ restore_user: mysql_stmt_free(thd, packet); break; } + case COM_RESET_STMT: + { + mysql_stmt_reset(thd, packet); + break; + } case COM_QUERY: { if (alloc_query(thd, packet, packet_length)) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index c38fb44db1c..550e4bbe086 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -965,7 +965,7 @@ void mysql_stmt_reset(THD *thd, char *packet) PREP_STMT *stmt; DBUG_ENTER("mysql_stmt_reset"); - if (!(stmt=find_prepared_statement(thd, stmt_id, "close"))) + if (!(stmt= find_prepared_statement(thd, stmt_id, "reset"))) { send_error(thd); DBUG_VOID_RETURN; From 5709ed20ab031e1ed2366e9c210d2da01c60cf14 Mon Sep 17 00:00:00 2001 From: "gluh@gluh.mysql.r18.ru" <> Date: Tue, 8 Jul 2003 15:06:05 +0500 Subject: [PATCH 37/54] SAPDB date/time finctions --- mysql-test/r/cast.result | 4 +- mysql-test/r/func_sapdb.result | 12 +- mysql-test/t/func_sapdb.test | 6 +- sql/item_create.cc | 4 +- sql/item_timefunc.cc | 322 +++++++++++++++++---------------- sql/item_timefunc.h | 82 ++------- sql/mysql_priv.h | 2 + sql/protocol.cc | 13 ++ sql/sql_string.cc | 17 ++ sql/sql_string.h | 2 + sql/sql_yacc.yy | 9 +- sql/time.cc | 1 + 12 files changed, 238 insertions(+), 236 deletions(-) diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index a14ea4d61a6..5d185bee005 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -44,10 +44,10 @@ t1 CREATE TABLE `t1` ( drop table t1; select cast("2001-1-1" as date) = "2001-01-01"; cast("2001-1-1" as date) = "2001-01-01" -0 +1 select cast("2001-1-1" as datetime) = "2001-01-01 00:00:00"; cast("2001-1-1" as datetime) = "2001-01-01 00:00:00" -0 +1 select cast("1:2:3" as TIME) = "1:02:03"; cast("1:2:3" as TIME) = "1:02:03" 0 diff --git a/mysql-test/r/func_sapdb.result b/mysql-test/r/func_sapdb.result index 5c044d00726..e330c73727b 100644 --- a/mysql-test/r/func_sapdb.result +++ b/mysql-test/r/func_sapdb.result @@ -101,8 +101,8 @@ timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") select timediff("1997-12-31 23:59:59.000001","23:59:59.000001"); timediff("1997-12-31 23:59:59.000001","23:59:59.000001") NULL -select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.1"); -timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.1") +select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001"); +timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001") -00:00:00.000001 select maketime(10,11,12); maketime(10,11,12) @@ -122,6 +122,12 @@ NULL select timestamp("2001-12-01", "25:01:01"); timestamp("2001-12-01", "25:01:01") 2001-12-02 01:01:01 +select timestamp("2001-12-01 01:01:01.000100"); +timestamp("2001-12-01 01:01:01.000100") +2001-12-01 01:01:01.000100 +select timestamp("2001-12-01"); +timestamp("2001-12-01") +2001-12-01 00:00:00 select day("1997-12-31 23:59:59.000001"); day("1997-12-31 23:59:59.000001") 31 @@ -147,7 +153,7 @@ addtime(cast("23:59:59.999999" as time) , "1 1:1:1.000002") as f3, timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") as f4, timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") as f5, maketime(10,11,12) as f6, -timestamp("2001-12-01", "01:01:01") as f7, +timestamp(cast("2001-12-01" as date), "01:01:01") as f7, date("1997-12-31 23:59:59.000001") as f8, time("1997-12-31 23:59:59.000001") as f9; describe t1; diff --git a/mysql-test/t/func_sapdb.test b/mysql-test/t/func_sapdb.test index 05e1f20fe1e..afd84fe9630 100644 --- a/mysql-test/t/func_sapdb.test +++ b/mysql-test/t/func_sapdb.test @@ -51,7 +51,7 @@ select timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002"); select timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002"); select timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002"); select timediff("1997-12-31 23:59:59.000001","23:59:59.000001"); -select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.1"); +select timediff("2000:01:01 00:00:00", "2000:01:01 00:00:00.000001"); select maketime(10,11,12); select maketime(25,11,12); @@ -61,6 +61,8 @@ select maketime(-25,11,12); select timestamp("2001-12-01", "01:01:01.999999"); select timestamp("2001-13-01", "01:01:01.000001"); select timestamp("2001-12-01", "25:01:01"); +select timestamp("2001-12-01 01:01:01.000100"); +select timestamp("2001-12-01"); select day("1997-12-31 23:59:59.000001"); select date("1997-12-31 23:59:59.000001"); select date("1997-13-31 23:59:59.000001"); @@ -75,7 +77,7 @@ select makedate(1997,1) as f1, timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") as f4, timediff("1997-12-30 23:59:59.000001","1997-12-31 23:59:59.000002") as f5, maketime(10,11,12) as f6, - timestamp("2001-12-01", "01:01:01") as f7, + timestamp(cast("2001-12-01" as date), "01:01:01") as f7, date("1997-12-31 23:59:59.000001") as f8, time("1997-12-31 23:59:59.000001") as f9; describe t1; diff --git a/sql/item_create.cc b/sql/item_create.cc index 402428d40cb..eaa27c1009d 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -709,12 +709,12 @@ Item *create_func_makedate(Item* a,Item* b) Item *create_func_addtime(Item* a,Item* b) { - return new Item_func_add_time(a, b, 0); + return new Item_func_add_time(a, b, 0, 0); } Item *create_func_subtime(Item* a,Item* b) { - return new Item_func_add_time(a, b, 1); + return new Item_func_add_time(a, b, 0, 1); } Item *create_func_timediff(Item* a,Item* b) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index fd2bca591a7..4fdb1b13d24 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -29,6 +29,8 @@ ** Todo: Move month and days to language files */ +#define MAX_DAY_NUMBER 3652424L + static String month_names[] = { String("January", &my_charset_latin1), @@ -55,10 +57,14 @@ static String day_names[] = String("Sunday", &my_charset_latin1) }; -enum date_time_format_types { TIME_ONLY= 0, TIME_MICROSECOND, - DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND}; +enum date_time_format_types +{ + TIME_ONLY= 0, TIME_MICROSECOND, + DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND +}; -typedef struct date_time_format { +typedef struct date_time_format +{ const char* format_str; uint length; }; @@ -73,6 +79,14 @@ static struct date_time_format date_time_formats[]= }; +/* + OPTIMIZATION TODO: + - Replace the switch with a function that should be called for each + date type. + - Remove sprintf and opencode the conversion, like we do in + Field_datetime. +*/ + String *make_datetime(String *str, TIME *ltime, enum date_time_format_types format) { @@ -898,8 +912,8 @@ String *Item_func_date_format::val_str(String *str) null_value=1; return 0; } - length= my_sprintf(intbuff, (intbuff,"%d",l_time.day)); - str->append(intbuff, length); + length= int10_to_str(l_time.day, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); if (l_time.day >= 10 && l_time.day <= 19) str->append("th"); else @@ -921,45 +935,45 @@ String *Item_func_date_format::val_str(String *str) } break; case 'Y': - sprintf(intbuff,"%04d",l_time.year); - str->append(intbuff,4); + length= int10_to_str(l_time.year, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 4, '0'); break; case 'y': - sprintf(intbuff,"%02d",l_time.year%100); - str->append(intbuff,2); + length= int10_to_str(l_time.year%100, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'm': - sprintf(intbuff,"%02d",l_time.month); - str->append(intbuff,2); + length= int10_to_str(l_time.month, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'c': - sprintf(intbuff,"%d",l_time.month); - str->append(intbuff); + length= int10_to_str(l_time.month, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); break; case 'd': - sprintf(intbuff,"%02d",l_time.day); - str->append(intbuff,2); + length= int10_to_str(l_time.day, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'e': - sprintf(intbuff,"%d",l_time.day); - str->append(intbuff); + length= int10_to_str(l_time.day, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); break; case 'f': - sprintf(intbuff,"%06ld",l_time.second_part); - str->append(intbuff); + length= int10_to_str(l_time.second_part, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 6, '0'); break; case 'H': - sprintf(intbuff,"%02d",l_time.hour); - str->append(intbuff,2); + length= int10_to_str(l_time.hour, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'h': case 'I': - sprintf(intbuff,"%02d", (l_time.hour+11)%12+1); - str->append(intbuff,2); + length= int10_to_str((l_time.hour+11)%12+1, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'i': /* minutes */ - sprintf(intbuff,"%02d",l_time.minute); - str->append(intbuff,2); + length= int10_to_str(l_time.minute, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'j': if (date_or_time) @@ -967,52 +981,60 @@ String *Item_func_date_format::val_str(String *str) null_value=1; return 0; } - sprintf(intbuff,"%03d", - (int) (calc_daynr(l_time.year,l_time.month,l_time.day) - - calc_daynr(l_time.year,1,1)) + 1); - str->append(intbuff,3); + length= int10_to_str(calc_daynr(l_time.year,l_time.month,l_time.day) - + calc_daynr(l_time.year,1,1) + 1, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 3, '0'); break; case 'k': - sprintf(intbuff,"%d",l_time.hour); - str->append(intbuff); + length= int10_to_str(l_time.hour, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); break; case 'l': - sprintf(intbuff,"%d", (l_time.hour+11)%12+1); - str->append(intbuff); + length= int10_to_str((l_time.hour+11)%12+1, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); break; case 'p': str->append(l_time.hour < 12 ? "AM" : "PM",2); break; case 'r': - sprintf(intbuff,(l_time.hour < 12) ? "%02d:%02d:%02d AM" : - "%02d:%02d:%02d PM",(l_time.hour+11)%12+1,l_time.minute, - l_time.second); - str->append(intbuff); + length= my_sprintf(intbuff, + (intbuff, + (l_time.hour < 12) ? "%02d:%02d:%02d AM" : "%02d:%02d:%02d PM", + (l_time.hour+11)%12+1, + l_time.minute, + l_time.second)); + str->append(intbuff, length); break; case 'S': case 's': - sprintf(intbuff,"%02d",l_time.second); - str->append(intbuff); + length= int10_to_str(l_time.second, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); break; case 'T': - sprintf(intbuff,"%02d:%02d:%02d", l_time.hour, l_time.minute, - l_time.second); - str->append(intbuff); + length= my_sprintf(intbuff, + (intbuff, + "%02d:%02d:%02d", + l_time.hour, + l_time.minute, + l_time.second)); + str->append(intbuff, length); break; case 'U': case 'u': { uint year; - sprintf(intbuff,"%02d",calc_week(&l_time, 0, (*ptr) == 'U', &year)); - str->append(intbuff,2); + length= int10_to_str(calc_week(&l_time, 0, (*ptr) == 'U', &year), + intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); } break; case 'v': case 'V': { uint year; - sprintf(intbuff,"%02d",calc_week(&l_time, 1, (*ptr) == 'V', &year)); - str->append(intbuff,2); + length= int10_to_str(calc_week(&l_time, 1, (*ptr) == 'V', &year), + intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); } break; case 'x': @@ -1020,14 +1042,15 @@ String *Item_func_date_format::val_str(String *str) { uint year; (void) calc_week(&l_time, 1, (*ptr) == 'X', &year); - sprintf(intbuff,"%04d",year); - str->append(intbuff,4); + length= int10_to_str(year, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 4, '0'); } break; case 'w': weekday=calc_weekday(calc_daynr(l_time.year,l_time.month,l_time.day),1); - sprintf(intbuff,"%d",weekday); - str->append(intbuff,1); + length= int10_to_str(weekday, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); + break; default: str->append(*ptr); @@ -1109,7 +1132,7 @@ void Item_date_add_interval::fix_length_and_dec() enum_field_types arg0_field_type; set_charset(default_charset()); maybe_null=1; - max_length=26*default_charset()->mbmaxlen; + max_length=26*MY_CHARSET_BIN_MB_MAXLEN; value.alloc(32); /* @@ -1197,13 +1220,13 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) ltime->hour=sec/3600; daynr= calc_daynr(ltime->year,ltime->month,1) + days; get_date_from_daynr(daynr,<ime->year,<ime->month,<ime->day); - if (daynr < 0 || daynr >= 3652424) // Day number from year 0 to 9999-12-31 + if (daynr < 0 || daynr >= MAX_DAY_NUMBER) // Day number from year 0 to 9999-12-31 goto null_date; break; case INTERVAL_DAY: period= calc_daynr(ltime->year,ltime->month,ltime->day) + sign*interval.day; - if (period < 0 || period >= 3652424) // Daynumber from year 0 to 9999-12-31 + if (period < 0 || period >= MAX_DAY_NUMBER) // Daynumber from year 0 to 9999-12-31 goto null_date; get_date_from_daynr((long) period,<ime->year,<ime->month,<ime->day); break; @@ -1375,6 +1398,63 @@ void Item_typecast::print(String *str) str->append(')'); } +String *Item_datetime_typecast::val_str(String *str) +{ + TIME ltime; + + if (!get_arg0_date(<ime,1) && + make_datetime(str, <ime, ltime.second_part ? + DATE_TIME_MICROSECOND : DATE_TIME)) + return str; + +null_date: + null_value=1; + return 0; +} + + +bool Item_time_typecast::get_time(TIME *ltime) +{ + bool res= get_arg0_time(ltime); + ltime->time_type= TIMESTAMP_TIME; + return res; +} + + +String *Item_time_typecast::val_str(String *str) +{ + TIME ltime; + + if (!get_arg0_time(<ime) && + make_datetime(str, <ime, ltime.second_part ? TIME_MICROSECOND : TIME_ONLY)) + return str; + + null_value=1; + return 0; +} + + +bool Item_date_typecast::get_date(TIME *ltime, bool fuzzy_date) +{ + bool res= get_arg0_date(ltime,1); + ltime->time_type= TIMESTAMP_DATE; + return res; +} + + +String *Item_date_typecast::val_str(String *str) +{ + TIME ltime; + + if (!get_arg0_date(<ime,1) && + make_datetime(str, <ime, DATE_ONLY)) + return str; + +null_date: + null_value=1; + return 0; +} + /* MAKEDATE(a,b) is a date function that creates a date value from a year and day value. @@ -1392,7 +1472,7 @@ String *Item_func_makedate::val_str(String *str) goto null_date; days= calc_daynr(yearnr,1,1) + daynr - 1; - if (days > 0 || days < 3652424L) // Day number from year 0 to 9999-12-31 + if (days > 0 || days < MAX_DAY_NUMBER) // Day number from year 0 to 9999-12-31 { null_value=0; get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day); @@ -1410,7 +1490,7 @@ void Item_func_add_time::fix_length_and_dec() { enum_field_types arg0_field_type; decimals=0; - max_length=26*my_charset_bin.mbmaxlen; + max_length=26*MY_CHARSET_BIN_MB_MAXLEN; /* The field type for the result of an Item_func_add_time function is defined as @@ -1424,7 +1504,8 @@ void Item_func_add_time::fix_length_and_dec() cached_field_type= MYSQL_TYPE_STRING; arg0_field_type= args[0]->field_type(); - if (arg0_field_type == MYSQL_TYPE_DATETIME || + if (arg0_field_type == MYSQL_TYPE_DATE || + arg0_field_type == MYSQL_TYPE_DATETIME || arg0_field_type == MYSQL_TYPE_TIMESTAMP) cached_field_type= MYSQL_TYPE_DATETIME; else if (arg0_field_type == MYSQL_TYPE_TIME) @@ -1443,20 +1524,28 @@ void Item_func_add_time::fix_length_and_dec() String *Item_func_add_time::val_str(String *str) { TIME l_time1, l_time2, l_time3; - bool is_time; + bool is_time= 0; long microseconds, seconds, days= 0; int l_sign= sign; null_value=0; - if (args[0]->get_time(&l_time1) || - args[1]->get_time(&l_time2) || - l_time2.time_type == TIMESTAMP_FULL) - goto null_date; - is_time= (l_time1.time_type == TIMESTAMP_TIME); l_time3.neg= 0; - if (is_time) + if (is_date) // TIMESTAMP function { - if ((l_time2.neg == l_time1.neg) && l_time1.neg) + if (get_arg0_date(&l_time1,1) || + args[1]->get_time(&l_time2) || + l_time1.time_type == TIMESTAMP_TIME || + l_time2.time_type != TIMESTAMP_TIME) + goto null_date; + } + else // ADDTIME function + { + if (args[0]->get_time(&l_time1) || + args[1]->get_time(&l_time2) || + l_time2.time_type == TIMESTAMP_FULL) + goto null_date; + is_time= (l_time1.time_type == TIMESTAMP_TIME); + if (is_time && (l_time2.neg == l_time1.neg && l_time1.neg)) l_time3.neg= 1; } if (l_time1.neg != l_time2.neg) @@ -1504,13 +1593,17 @@ String *Item_func_add_time::val_str(String *str) { get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day); if (l_time3.day && - make_datetime(str, &l_time3, DATE_TIME_MICROSECOND)) + make_datetime(str, &l_time3, + l_time1.second_part || l_time2.second_part ? + DATE_TIME_MICROSECOND : DATE_TIME)) return str; goto null_date; } l_time3.hour+= days*24; - if (make_datetime(str, &l_time3, TIME_MICROSECOND)) + if (make_datetime(str, &l_time3, + l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY)) return str; null_date: @@ -1578,7 +1671,9 @@ String *Item_func_timediff::val_str(String *str) l_time3.neg= l_time3.neg ? 0 : 1; calc_time_from_sec(&l_time3, seconds, microseconds); - if (make_datetime(str, &l_time3, TIME_MICROSECOND)) + if (make_datetime(str, &l_time3, + l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY)) return str; null_date: @@ -1623,99 +1718,6 @@ null_date: return 0; } -/* - TIMESTAMP(a,b) is a function ( extraction) that calculates a datetime value - comprising a date value, time value. - - a: Date_or_datetime value - b: Time value - Result: Datetime value -*/ - -String *Item_func_timestamp::val_str(String *str) -{ - TIME l_time1 ,l_time2, l_time3; - long seconds; - long microseconds; - long days; - int l_sign; - - if (get_arg0_date(&l_time1,1) || - args[1]->get_time(&l_time2) || - l_time1.time_type == TIMESTAMP_TIME || - l_time2.time_type != TIMESTAMP_TIME) - goto null_date; - - l_sign= l_time2.neg ? -1 : 1; - days= (calc_daynr((uint) l_time1.year,(uint) l_time1.month, - (uint) l_time1.day) + l_sign*l_time2.day); - - microseconds= l_time1.second_part + l_sign*l_time2.second_part; - seconds= (l_time1.hour*3600L + l_time1.minute*60L + l_time1.second + - (l_time2.day*86400L + l_time2.hour*3600L + - l_time2.minute*60L + l_time2.second)*l_sign); - days+= seconds/86400L; - seconds%= 86400L; - if (microseconds < 0) - { - microseconds+= 1000000L; - seconds--; - } - if (seconds < 0) - { - days--; - seconds+= 86400L; - } - if (days < 0) - goto null_date; - - calc_time_from_sec(&l_time3, seconds, microseconds); - get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day); - make_datetime(str, &l_time3, DATE_TIME_MICROSECOND); - return str; - -null_date: - null_value=1; - return 0; -} - -/* - DATE(a) is a function ( extraction) that calculates a date value. - - a: Datetime value - Result: Date value -*/ -String *Item_func_date::val_str(String *str) -{ - TIME ltime; - - if (!get_arg0_date(<ime,1) && - make_datetime(str, <ime, DATE_ONLY)) - return str; - -null_date: - null_value=1; - return 0; -} - -/* - TIME(a) is a function ( extraction) that calculates a time value. - - a: Datetime value - Result: Time value -*/ -String *Item_func_time::val_str(String *str) -{ - TIME ltime; - - if (!get_arg0_time(<ime) && - make_datetime(str, <ime, TIME_MICROSECOND)) - return str; - - null_value=1; - return 0; -} - /* MICROSECOND(a) is a function ( extraction) that extracts the microseconds from a. diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index ea29731fe35..20b95f8e22d 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -557,6 +557,8 @@ class Item_date_typecast :public Item_typecast { public: Item_date_typecast(Item *a) :Item_typecast(a) {} + String *val_str(String *str); + bool get_date(TIME *ltime, bool fuzzy_date); const char *func_name() const { return "date"; } enum_field_types field_type() const { return MYSQL_TYPE_DATE; } Field *tmp_table_field() { return result_field; } @@ -571,6 +573,8 @@ class Item_time_typecast :public Item_typecast { public: Item_time_typecast(Item *a) :Item_typecast(a) {} + String *val_str(String *str); + bool get_time(TIME *ltime); const char *func_name() const { return "time"; } enum_field_types field_type() const { return MYSQL_TYPE_TIME; } Field *tmp_table_field() { return result_field; } @@ -585,6 +589,7 @@ class Item_datetime_typecast :public Item_typecast { public: Item_datetime_typecast(Item *a) :Item_typecast(a) {} + String *val_str(String *str); const char *func_name() const { return "datetime"; } enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } Field *tmp_table_field() { return result_field; } @@ -604,7 +609,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=8*my_charset_bin.mbmaxlen; + max_length=8*MY_CHARSET_BIN_MB_MAXLEN; } Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) @@ -613,18 +618,26 @@ public: } }; + class Item_func_add_time :public Item_str_func { + const bool is_date; int sign; enum_field_types cached_field_type; public: - Item_func_add_time(Item *a, Item *b, bool neg_arg) - :Item_str_func(a, b) { sign= neg_arg ? -1 : 1; } + Item_func_add_time(Item *a, Item *b, bool type_arg, bool neg_arg) + :Item_str_func(a, b), is_date(type_arg) { sign= neg_arg ? -1 : 1; } String *val_str(String *str); const char *func_name() const { return "addtime"; } enum_field_types field_type() const { return cached_field_type; } void fix_length_and_dec(); + +/* + TODO: + Change this when we support + microseconds in TIME/DATETIME +*/ Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { @@ -647,7 +660,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=17*my_charset_bin.mbmaxlen; + max_length=17*MY_CHARSET_BIN_MB_MAXLEN; } Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) @@ -667,66 +680,7 @@ public: void fix_length_and_dec() { decimals=0; - max_length=8*my_charset_bin.mbmaxlen; - } - Field *tmp_table_field() { return result_field; } - Field *tmp_table_field(TABLE *t_arg) - { - return (new Field_time(maybe_null, name, t_arg, &my_charset_bin)); - } -}; - -class Item_func_timestamp :public Item_str_func -{ -public: - Item_func_timestamp(Item *a, Item *b) :Item_str_func(a, b) {} - String *val_str(String *str); - const char *func_name() const { return "timestamp"; } - enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } - void fix_length_and_dec() - { - decimals=0; - max_length=26*my_charset_bin.mbmaxlen; - } - Field *tmp_table_field() { return result_field; } - Field *tmp_table_field(TABLE *t_arg) - { - return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin)); - } -}; - -class Item_func_date :public Item_str_func -{ -public: - Item_func_date(Item *a) - :Item_str_func(a) {} - String *val_str(String *str); - const char *func_name() const { return "date"; } - enum_field_types field_type() const { return MYSQL_TYPE_DATE; } - void fix_length_and_dec() - { - decimals=0; - max_length=10*my_charset_bin.mbmaxlen; - } - Field *tmp_table_field() { return result_field; } - Field *tmp_table_field(TABLE *t_arg) - { - return (new Field_date(maybe_null, name, t_arg, &my_charset_bin)); - } -}; - -class Item_func_time :public Item_str_func -{ -public: - Item_func_time(Item *a) - :Item_str_func(a) {} - String *val_str(String *str); - const char *func_name() const { return "time"; } - enum_field_types field_type() const { return MYSQL_TYPE_TIME; } - void fix_length_and_dec() - { - decimals=0; - max_length=15*my_charset_bin.mbmaxlen; + max_length=8*MY_CHARSET_BIN_MB_MAXLEN; } Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 8aeb18dcf26..ea3c2d45333 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -224,6 +224,8 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define RAID_BLOCK_SIZE 1024 +#define MY_CHARSET_BIN_MB_MAXLEN 1 + #ifdef EXTRA_DEBUG /* Sync points allow us to force the server to reach a certain line of code diff --git a/sql/protocol.cc b/sql/protocol.cc index 3d214e6f86d..1b9256c7723 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -823,6 +823,13 @@ bool Protocol_simple::store(Field *field) } +/* + TODO: + Second_part format ("%06") needs to change when + we support 0-6 decimals for time. +*/ + + bool Protocol_simple::store(TIME *tm) { #ifndef DEBUG_OFF @@ -863,6 +870,12 @@ bool Protocol_simple::store_date(TIME *tm) } +/* + TODO: + Second_part format ("%06") needs to change when + we support 0-6 decimals for time. +*/ + bool Protocol_simple::store_time(TIME *tm) { #ifndef DEBUG_OFF diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 0a3e8d0db9f..e7d7b08c93c 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -390,6 +390,23 @@ bool String::append(IO_CACHE* file, uint32 arg_length) return FALSE; } +bool String::append_with_prefill(const char *s,uint32 arg_length, + uint32 full_length, char fill_char) +{ + int t_length= arg_length > full_length ? arg_length : full_length; + + if (realloc(str_length + t_length)) + return TRUE; + t_length= full_length - arg_length; + if (t_length > 0) + { + bfill(Ptr+str_length, t_length, fill_char); + str_length=str_length + t_length; + } + append(s, arg_length); + return FALSE; +} + uint32 String::numchars() { return str_charset->cset->numchars(str_charset, Ptr, Ptr+str_length); diff --git a/sql/sql_string.h b/sql/sql_string.h index e88c9389589..d446d26298b 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -189,6 +189,8 @@ public: bool append(const char *s,uint32 arg_length=0); bool append(const char *s,uint32 arg_length, CHARSET_INFO *cs); bool append(IO_CACHE* file, uint32 arg_length); + bool append_with_prefill(const char *s, uint32 arg_length, + uint32 full_length, char fill_char); int strstr(const String &search,uint32 offset=0); // Returns offset to substring or -1 int strstr_case(const String &s,uint32 offset=0); int strrstr(const String &search,uint32 offset=0); // Returns offset to substring or -1 diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 873257116b9..4aa5b70407e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2381,7 +2381,7 @@ simple_expr: Lex->safe_to_cache_query=0; } | DATE_SYM '(' expr ')' - { $$= new Item_func_date($3); } + { $$= new Item_date_typecast($3); } | DAY_SYM '(' expr ')' { $$= new Item_func_dayofmonth($3); } | ELT_FUNC '(' expr ',' expr_list ')' @@ -2580,9 +2580,11 @@ simple_expr: | SUBSTRING_INDEX '(' expr ',' expr ',' expr ')' { $$= new Item_func_substr_index($3,$5,$7); } | TIME_SYM '(' expr ')' - { $$= new Item_func_time($3); } + { $$= new Item_time_typecast($3); } + | TIMESTAMP '(' expr ')' + { $$= new Item_datetime_typecast($3); } | TIMESTAMP '(' expr ',' expr ')' - { $$= new Item_func_timestamp($3, $5); } + { $$= new Item_func_add_time($3, $5, 1, 0); } | TRIM '(' expr ')' { $$= new Item_func_trim($3); } | TRIM '(' LEADING expr FROM expr ')' @@ -4427,6 +4429,7 @@ keyword: | MEDIUM_SYM {} | MERGE_SYM {} | MEMORY_SYM {} + | MICROSECOND_SYM {} | MINUTE_SYM {} | MIN_ROWS {} | MODIFY_SYM {} diff --git a/sql/time.cc b/sql/time.cc index 056adf050ce..70ae8dcd8ed 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -432,6 +432,7 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) l_time->minute=date[4]; l_time->second=date[5]; l_time->second_part=date[6]; + l_time->neg= 0; DBUG_RETURN(l_time->time_type= (number_of_fields <= 3 ? TIMESTAMP_DATE : TIMESTAMP_FULL)); } From db22d366ce12c4dc6176121a6d0acf4befbe6211 Mon Sep 17 00:00:00 2001 From: "serg@sergbook.mylan" <> Date: Wed, 9 Jul 2003 13:00:44 +0200 Subject: [PATCH 38/54] comment clarified --- sql/net_serv.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/net_serv.cc b/sql/net_serv.cc index eb4d76bbf6e..fd5e4f1d71a 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -959,5 +959,5 @@ my_net_read(NET *net) return len; } -#endif /* EMBEDDED_LIBRARY */ +#endif /* #ifndef EMBEDDED_LIBRARY */ From e08e67ff9d256bc5a144ec6d24443c211b122c54 Mon Sep 17 00:00:00 2001 From: "paul@teton.kitebird.com" <> Date: Wed, 9 Jul 2003 18:42:54 -0500 Subject: [PATCH 39/54] Error message style consistency edits. --- sql/share/czech/errmsg.txt | 4 ++-- sql/share/danish/errmsg.txt | 4 ++-- sql/share/dutch/errmsg.txt | 2 +- sql/share/english/errmsg.txt | 4 ++-- sql/share/estonian/errmsg.txt | 2 +- sql/share/french/errmsg.txt | 4 ++-- sql/share/german/errmsg.txt | 8 ++++---- sql/share/greek/errmsg.txt | 6 +++--- sql/share/hungarian/errmsg.txt | 2 +- sql/share/italian/errmsg.txt | 2 +- sql/share/japanese/errmsg.txt | 2 +- sql/share/korean/errmsg.txt | 2 +- sql/share/norwegian-ny/errmsg.txt | 4 ++-- sql/share/norwegian/errmsg.txt | 4 ++-- sql/share/polish/errmsg.txt | 4 ++-- sql/share/romanian/errmsg.txt | 4 ++-- sql/share/russian/errmsg.txt | 2 +- sql/share/serbian/errmsg.txt | 4 ++-- sql/share/slovak/errmsg.txt | 4 ++-- sql/share/spanish/errmsg.txt | 4 ++-- sql/share/swedish/errmsg.txt | 4 ++-- sql/share/ukrainian/errmsg.txt | 4 ++-- 22 files changed, 40 insertions(+), 40 deletions(-) diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 30516e8dad1..5ed743962eb 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -16,7 +16,7 @@ v/* "ANO", "Nemohu vytvo-Bøit soubor '%-.64s' (chybový kód: %d)", "Nemohu vytvo-Bøit tabulku '%-.64s' (chybový kód: %d)", -"Nemohu vytvo-Bøit databázi '%-.64s', chyba %d", +"Nemohu vytvo-Bøit databázi '%-.64s' (chybový kód: %d)", "Nemohu vytvo-Bøit databázi '%-.64s'; databáze ji¾ existuje", "Nemohu zru-B¹it databázi '%-.64s', databáze neexistuje", "Chyba p-Bøi ru¹ení databáze (nemohu vymazat '%-.64s', chyba %d)", @@ -222,7 +222,7 @@ v/* "CREATE DATABASE not allowed while thread is holding global read lock", "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 289f70c79ed..224b168e15b 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -10,7 +10,7 @@ "JA", "Kan ikke oprette filen '%-.64s' (Fejlkode: %d)", "Kan ikke oprette tabellen '%-.64s' (Fejlkode: %d)", -"Kan ikke oprette databasen '%-.64s'. Fejl %d", +"Kan ikke oprette databasen '%-.64s' (Fejlkode: %d)", "Kan ikke oprette databasen '%-.64s'; databasen eksisterer", "Kan ikke slette (droppe) '%-.64s'; databasen eksisterer ikke", "Fejl ved sletning (drop) af databasen (kan ikke slette '%-.64s', Fejl %d)", @@ -216,7 +216,7 @@ "CREATE DATABASE er ikke tilladt mens en tråd holder på globalt read lock", "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 8cf926554a4..ad843ae2e4e 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -224,7 +224,7 @@ "CREATE DATABASE niet toegestaan terwijl thread een globale 'read lock' bezit", "Foutieve parameters voor %s", "%-.32s@%-.64s mag geen nieuwe gebruikers creeren", -"Incorrecte tabel definitie; Alle MERGE tabellen moeten tot dezelfde database behoren", +"Incorrecte tabel definitie; alle MERGE tabellen moeten tot dezelfde database behoren", "Deadlock gevonden tijdens lock-aanvraag poging; Probeer herstart van de transactie", "Het gebruikte tabel type ondersteund geen FULLTEXT indexen", "Kan foreign key beperking niet toevoegen", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 6f0de413a47..778854c820b 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -7,7 +7,7 @@ "YES", "Can't create file '%-.64s' (errno: %d)", "Can't create table '%-.64s' (errno: %d)", -"Can't create database '%-.64s'. (errno: %d)", +"Can't create database '%-.64s' (errno: %d)", "Can't create database '%-.64s'; database exists", "Can't drop database '%-.64s'; database doesn't exist", "Error dropping database (can't delete '%-.64s', errno: %d)", @@ -213,7 +213,7 @@ "CREATE DATABASE not allowed while thread is holding global read lock", "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index f4107e91d5b..0ac668ce01c 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -12,7 +12,7 @@ "JAH", "Ei suuda luua faili '%-.64s' (veakood: %d)", "Ei suuda luua tabelit '%-.64s' (veakood: %d)", -"Ei suuda luua andmebaasi '%-.64s'. (veakood: %d)", +"Ei suuda luua andmebaasi '%-.64s' (veakood: %d)", "Ei suuda luua andmebaasi '%-.64s': andmebaas juba eksisteerib", "Ei suuda kustutada andmebaasi '%-.64s': andmebaasi ei eksisteeri", "Viga andmebaasi kustutamisel (ei suuda kustutada faili '%-.64s', veakood: %d)", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 5d82eebefda..51053dc5632 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -7,7 +7,7 @@ "OUI", "Ne peut créer le fichier '%-.64s' (Errcode: %d)", "Ne peut créer la table '%-.64s' (Errcode: %d)", -"Ne peut créer la base '%-.64s'. Erreur %d", +"Ne peut créer la base '%-.64s' (Erreur %d)", "Ne peut créer la base '%-.64s'; elle existe déjà", "Ne peut effacer la base '%-.64s'; elle n'existe pas", "Ne peut effacer la base '%-.64s' (erreur %d)", @@ -213,7 +213,7 @@ "CREATE DATABASE n'est pas autorisée pendant qu'une tâche possède un verrou global en lecture", "Mauvais arguments à %s", "%-.32s@%-.64s n'est pas autorisé à créer de nouveaux utilisateurs", -"Définition de table incorrecte : toutes les tables MERGE doivent être dans la même base de donnée", +"Définition de table incorrecte; toutes les tables MERGE doivent être dans la même base de donnée", "Deadlock découvert en essayant d'obtenir les verrous : essayez de redémarrer la transaction", "Le type de table utilisé ne supporte pas les index FULLTEXT", "Impossible d'ajouter des contraintes d'index externe", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 4512cd1e0cb..49615c08223 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -14,9 +14,9 @@ "isamchk", "Nein", "Ja", -"Kann Datei '%-.64s' nicht erzeugen. (Fehler: %d)", -"Kann Tabelle '%-.64s' nicht erzeugen. (Fehler: %d)", -"Kann Datenbank '%-.64s' nicht erzeugen. (Fehler: %d)", +"Kann Datei '%-.64s' nicht erzeugen (Fehler: %d)", +"Kann Tabelle '%-.64s' nicht erzeugen (Fehler: %d)", +"Kann Datenbank '%-.64s' nicht erzeugen (Fehler: %d)", "Kann Datenbank '%-.64s' nicht erzeugen; datenbank '%-.64s' existiert bereits.", "Kann Datenbank '%-.64s' nicht löschen; keine Datenbank '%-.64s' vorhanden.", "Fehler beim Löschen der Datenbank. ('%-.64s' kann nicht gelöscht werden, Fehlernuumer: %d)", @@ -222,7 +222,7 @@ "Solange ein globaler Read LOCK gesetzt ist, ist CREATE DATABASE nicht zulässig.", "Falsche Argumente für %s", "%-.32s@%-.64s is nicht berechtigt neue Benutzer hinzuzufügen.", -"Falsche Tabellendefinition: Sämtliche MERGE-Tabellen müssen in derselben Datenbank sein.", +"Falsche Tabellendefinition; sämtliche MERGE-Tabellen müssen in derselben Datenbank sein.", "Beim Versuch einen Lock anzufordern ist ein Deadlock aufgetreten. Es wird versucht die Transaktion erneut zu starten.", "Der verwendete Tabellentyp unterstützt keinen FULLTEXT-Index.", "Foreign_Key Beschränkung konnte nicht hinzugefügt werden.", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 873f8385462..d49e80135e3 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -7,8 +7,8 @@ "ÍÁÉ", "Áäýíáôç ç äçìéïõñãßá ôïõ áñ÷åßïõ '%-.64s' (êùäéêüò ëÜèïõò: %d)", "Áäýíáôç ç äçìéïõñãßá ôïõ ðßíáêá '%-.64s' (êùäéêüò ëÜèïõò: %d)", -"Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.64s'. (êùäéêüò ëÜèïõò: %d)", -"Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.64s'. Ç âÜóç äåäïìÝíùí õðÜñ÷åé Þäç", +"Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.64s' (êùäéêüò ëÜèïõò: %d)", +"Áäýíáôç ç äçìéïõñãßá ôçò âÜóçò äåäïìÝíùí '%-.64s'; Ç âÜóç äåäïìÝíùí õðÜñ÷åé Þäç", "Áäýíáôç ç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí '%-.64s'. Ç âÜóç äåäïìÝíùí äåí õðÜñ÷åé", "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ '%-.64s', êùäéêüò ëÜèïõò: %d)", "ÐáñïõóéÜóôçêå ðñüâëçìá êáôÜ ôç äéáãñáöÞ ôçò âÜóçò äåäïìÝíùí (áäýíáôç ç äéáãñáöÞ ôïõ öáêÝëëïõ '%-.64s', êùäéêüò ëÜèïõò: %d)", @@ -213,7 +213,7 @@ "CREATE DATABASE not allowed while thread is holding global read lock", "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 93ab550b60f..8fc12da1f00 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -215,7 +215,7 @@ "CREATE DATABASE not allowed while thread is holding global read lock", "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index cc21f7cf42a..18ce664e7fd 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -7,7 +7,7 @@ "SI", "Impossibile creare il file '%-.64s' (errno: %d)", "Impossibile creare la tabella '%-.64s' (errno: %d)", -"Impossibile creare il database '%-.64s'. (errno: %d)", +"Impossibile creare il database '%-.64s' (errno: %d)", "Impossibile creare il database '%-.64s'; il database esiste", "Impossibile cancellare '%-.64s'; il database non esiste", "Errore durante la cancellazione del database (impossibile cancellare '%-.64s', errno: %d)", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index b8bc6e1d761..fedf0fd8e9c 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -215,7 +215,7 @@ "CREATE DATABASE not allowed while thread is holding global read lock", "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 9bbcaa16076..8c37b824342 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -213,7 +213,7 @@ "CREATE DATABASE not allowed while thread is holding global read lock", "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index f562553e40a..4e5bed92916 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -9,7 +9,7 @@ "JA", "Kan ikkje opprette fila '%-.64s' (Feilkode: %d)", "Kan ikkje opprette tabellen '%-.64s' (Feilkode: %d)", -"Kan ikkje opprette databasen '%-.64s'. Feil %d", +"Kan ikkje opprette databasen '%-.64s' (Feilkode: %d)", "Kan ikkje opprette databasen '%-.64s'; databasen eksisterer", "Kan ikkje fjerne (drop) '%-.64s'; databasen eksisterer ikkje", "Feil ved fjerning (drop) av databasen (kan ikkje slette '%-.64s', feil %d)", @@ -215,7 +215,7 @@ "CREATE DATABASE not allowed while thread is holding global read lock", "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index dcb7be9a053..4b4f4e6a1f3 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -9,7 +9,7 @@ "JA", "Kan ikke opprette fila '%-.64s' (Feilkode: %d)", "Kan ikke opprette tabellen '%-.64s' (Feilkode: %d)", -"Kan ikke opprette databasen '%-.64s'. Feil %d", +"Kan ikke opprette databasen '%-.64s' (Feilkode: %d)", "Kan ikke opprette databasen '%-.64s'; databasen eksisterer", "Kan ikke fjerne (drop) '%-.64s'; databasen eksisterer ikke", "Feil ved fjerning (drop) av databasen (kan ikke slette '%-.64s', feil %d)", @@ -215,7 +215,7 @@ "CREATE DATABASE not allowed while thread is holding global read lock", "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 9cd63dfc009..cc710376052 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -11,7 +11,7 @@ "TAK", "Nie mo¿na stworzyæ pliku '%-.64s' (Kod b³êdu: %d)", "Nie mo¿na stworzyæ tabeli '%-.64s' (Kod b³êdu: %d)", -"Nie mo¿na stworzyæ bazy danych '%-.64s'. B³?d %d", +"Nie mo¿na stworzyæ bazy danych '%-.64s' (Kod b³êdu: %d)", "Nie mo¿na stworzyæ bazy danych '%-.64s'; baza danych ju¿ istnieje", "Nie mo¿na usun?æ bazy danych '%-.64s'; baza danych nie istnieje", "B³?d podczas usuwania bazy danych (nie mo¿na usun?æ '%-.64s', b³?d %d)", @@ -217,7 +217,7 @@ "CREATE DATABASE not allowed while thread is holding global read lock", "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index c5be6e5df8d..f8bbba75a9f 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -11,7 +11,7 @@ "DA", "Nu pot sa creez fisierul '%-.64s' (Eroare: %d)", "Nu pot sa creez tabla '%-.64s' (Eroare: %d)", -"Nu pot sa creez baza de date '%-.64s'. (Eroare: %d)", +"Nu pot sa creez baza de date '%-.64s' (Eroare: %d)", "Nu pot sa creez baza de date '%-.64s'; baza de date exista deja", "Nu pot sa drop baza de date '%-.64s'; baza da date este inexistenta", "Eroare dropuind baza de date (nu pot sa sterg '%-.64s', Eroare: %d)", @@ -217,7 +217,7 @@ "CREATE DATABASE not allowed while thread is holding global read lock", "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index e193eac6793..1981e7e7a5a 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -9,7 +9,7 @@ "äá", "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÆÁÊÌ '%-.64s' (ÏÛÉÂËÁ: %d)", "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÔÁÂÌÉÃÕ '%-.64s' (ÏÛÉÂËÁ: %d)", -"îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.64s'. (ÏÛÉÂËÁ: %d)", +"îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.64s' (ÏÛÉÂËÁ: %d)", "îÅ×ÏÚÍÏÖÎÏ ÓÏÚÄÁÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.64s'. âÁÚÁ ÄÁÎÎÙÈ ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ", "îÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ ÂÁÚÕ ÄÁÎÎÙÈ '%-.64s'. ôÁËÏÊ ÂÁÚÙ ÄÁÎÎÙÈ ÎÅÔ", "ïÛÉÂËÁ ÐÒÉ ÕÄÁÌÅÎÉÉ ÂÁÚÙ ÄÁÎÎÙÈ (ÎÅ×ÏÚÍÏÖÎÏ ÕÄÁÌÉÔØ '%-.64s', ÏÛÉÂËÁ: %d)", diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index e413097a997..e1583bbb791 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -13,7 +13,7 @@ "DA", "Ne mogu da kreiram file '%-.64s' (errno: %d)", "Ne mogu da kreiram tabelu '%-.64s' (errno: %d)", -"Ne mogu da kreiram bazu '%-.64s'. (errno: %d)", +"Ne mogu da kreiram bazu '%-.64s' (errno: %d)", "Ne mogu da kreiram bazu '%-.64s'; baza veæ postoji.", "Ne mogu da izbrišem bazu '%-.64s'; baza ne postoji.", "Ne mogu da izbrišem bazu (ne mogu da izbrišem '%-.64s', errno: %d)", @@ -219,7 +219,7 @@ "Komanda 'CREATE DATABASE' nije dozvoljena dok thread globalno zakljuèava èitanje podataka", "Pogrešni argumenti prosleðeni na %s", "Korisniku %-.32s@%-.64s nije dozvoljeno da kreira nove korisnike", -"Pogrešna definicija tabele; Sve 'MERGE' tabele moraju biti u istoj bazi podataka", +"Pogrešna definicija tabele; sve 'MERGE' tabele moraju biti u istoj bazi podataka", "Unakrsno zakljuèavanje pronaðeno kada sam pokušao da dobijem pravo na zakljuèavanje; Probajte da restartujete transakciju", "Upotrebljeni tip tabele ne podržava 'FULLTEXT' indekse", "Ne mogu da dodam proveru spoljnog kljuèa", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index a3e34b8b41a..c6fad79e15a 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -15,7 +15,7 @@ "Áno", "Nemô¾em vytvori» súbor '%-.64s' (chybový kód: %d)", "Nemô¾em vytvori» tabuµku '%-.64s' (chybový kód: %d)", -"Nemô¾em vytvori» databázu '%-.64s'. (chybový kód: %d)", +"Nemô¾em vytvori» databázu '%-.64s' (chybový kód: %d)", "Nemô¾em vytvori» databázu '%-.64s'; databáza existuje", "Nemô¾em zmaza» databázu '%-.64s'; databáza neexistuje", "Chyba pri mazaní databázy (nemô¾em zmaza» '%-.64s', chybový kód: %d)", @@ -221,7 +221,7 @@ "CREATE DATABASE not allowed while thread is holding global read lock", "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index c1b3f19da4f..731e576fafd 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -8,7 +8,7 @@ "SI", "No puedo crear archivo '%-.64s' (Error: %d)", "No puedo crear tabla '%-.64s' (Error: %d)", -"No puedo crear base de datos '%-.64s'. Error %d", +"No puedo crear base de datos '%-.64s' (Error: %d)", "No puedo crear base de datos '%-.64s'; la base de datos ya existe", "No puedo eliminar base de datos '%-.64s'; la base de datos no existe", "Error eliminando la base de datos(no puedo borrar '%-.64s', error %d)", @@ -214,7 +214,7 @@ "CREATE DATABASE no permitido mientras un thread está ejerciendo un bloqueo de lectura global", "Wrong arguments to %s", "%-.32s@%-.64s is not allowed to create new users", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "The used table type doesn't support FULLTEXT indexes", "Cannot add foreign key constraint", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index b1153c83504..9e34dbb138a 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -7,7 +7,7 @@ "YES", "Kan inte skapa filen '%-.64s' (Felkod: %d)", "Kan inte skapa tabellen '%-.64s' (Felkod: %d)", -"Kan inte skapa databasen '%-.64s'. (Felkod: %d)", +"Kan inte skapa databasen '%-.64s' (Felkod: %d)", "Databasen '%-.64s' existerar redan", "Kan inte radera databasen '%-.64s'; databasen finns inte", "Fel vid radering av databasen (Kan inte radera '%-.64s'. Felkod: %d)", @@ -213,7 +213,7 @@ "CREATE DATABASE är inte tillåtet när man har ett globalt läslås", "Felaktiga argument till %s", "%-.32s@%-.64s har inte rättighet att skapa nya användare", -"Felaktig tabelldefinition. Alla tabeller i en MERGE-tabell måste vara i samma databas", +"Felaktig tabelldefinition; alla tabeller i en MERGE-tabell måste vara i samma databas", "Fick 'DEADLOCK' vid låsförsök av block/rad. Försök att starta om transaktionen", "Tabelltypen har inte hantering av FULLTEXT-index", "Kan inte lägga till 'FOREIGN KEY constraint'", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 2fc14372f54..adbb35dc7c0 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -12,7 +12,7 @@ "ôáë", "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÆÁÊÌ '%-.64s' (ÐÏÍÉÌËÁ: %d)", "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÔÁÂÌÉÃÀ '%-.64s' (ÐÏÍÉÌËÁ: %d)", -"îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.64s'. (ÐÏÍÉÌËÁ: %d)", +"îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.64s' (ÐÏÍÉÌËÁ: %d)", "îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.64s'. âÁÚÁ ÄÁÎÎÉÈ ¦ÓÎÕ¤", "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ '%-.64s'. âÁÚÁ ÄÁÎÎÉÈ ÎÅ ¦ÓÎÕ¤", "îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ ÂÁÚÕ ÄÁÎÎÉÈ (îÅ ÍÏÖÕ ×ÉÄÁÌÉÔÉ '%-.64s', ÐÏÍÉÌËÁ: %d)", @@ -218,7 +218,7 @@ "CREATE DATABASE ÎÅ ÄÏÚ×ÏÌÅÎÏ ÄÏËÉ Ç¦ÌËÁ ÐÅÒÅÂÕ×Á¤ Ð¦Ä ÚÁÇÁÌØÎÉÍ ÂÌÏËÕ×ÁÎÎÑÍ ÞÉÔÁÎÎÑ", "èÉÂÎÉÊ ÁÒÇÕÍÅÎÔ ÄÌÑ %s", "ëÏÒÉÓÔÕ×ÁÞÕ %-.32s@%-.64s ÎÅ ÄÏÚ×ÏÌÅÎÏ ÓÔ×ÏÒÀ×ÁÔÉ ÎÏ×ÉÈ ËÏÒÉÓÔÕ×ÁÞ¦×", -"Incorrect table definition; All MERGE tables must be in the same database", +"Incorrect table definition; all MERGE tables must be in the same database", "Deadlock found when trying to get lock; Try restarting transaction", "÷ÉËÏÒÉÓÔÁÎÉÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ FULLTEXT ¦ÎÄÅËÓ¦×", "Cannot add foreign key constraint", From 92b3a231d45928e7de64fa2e8936b877bf6049c4 Mon Sep 17 00:00:00 2001 From: "lenz@kallisto.local" <> Date: Thu, 10 Jul 2003 10:02:57 +0200 Subject: [PATCH 40/54] - Updated error message tests in several results of the test suite after the server error messages had been modified in errmsg.txt --- mysql-test/r/create.result | 4 ++-- mysql-test/r/drop.result | 6 +++--- mysql-test/r/rpl000009.result | 6 +++--- mysql-test/r/symlink.result | 2 +- mysql-test/r/warnings.result | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 70814aa899e..9a0eca52b84 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -50,7 +50,7 @@ create table t1 (t1.index int); drop table t1; drop database if exists test_$1; Warnings: -Note 1008 Can't drop database 'test_$1'. Database doesn't exist +Note 1008 Can't drop database 'test_$1'; database doesn't exist create database test_$1; create table test_$1.$test1 (a$1 int, $b int, c$ int); insert into test_$1.$test1 values (1,2,3); @@ -252,7 +252,7 @@ id name drop table t2, t3; drop database if exists test_$1; Warnings: -Note 1008 Can't drop database 'test_$1'. Database doesn't exist +Note 1008 Can't drop database 'test_$1'; database doesn't exist create database test_$1; create table test_$1.t3 like t1; create temporary table t3 like test_$1.t3; diff --git a/mysql-test/r/drop.result b/mysql-test/r/drop.result index 2b878455bea..9555ea452ca 100644 --- a/mysql-test/r/drop.result +++ b/mysql-test/r/drop.result @@ -13,7 +13,7 @@ n 1 drop database if exists mysqltest; Warnings: -Note 1008 Can't drop database 'mysqltest'. Database doesn't exist +Note 1008 Can't drop database 'mysqltest'; database doesn't exist create database mysqltest; drop database if exists mysqltest; create database mysqltest; @@ -27,7 +27,7 @@ create database mysqltest; drop database mysqltest; drop database if exists mysqltest; Warnings: -Note 1008 Can't drop database 'mysqltest'. Database doesn't exist +Note 1008 Can't drop database 'mysqltest'; database doesn't exist flush tables with read lock; create database mysqltest; Got one of the listed errors @@ -48,4 +48,4 @@ Database mysql test drop database mysqltest; -ERROR HY000: Can't drop database 'mysqltest'. Database doesn't exist +ERROR HY000: Can't drop database 'mysqltest'; database doesn't exist diff --git a/mysql-test/r/rpl000009.result b/mysql-test/r/rpl000009.result index dc1d8c4872e..d0faf0435e3 100644 --- a/mysql-test/r/rpl000009.result +++ b/mysql-test/r/rpl000009.result @@ -21,7 +21,7 @@ n m drop database mysqltest; drop database if exists mysqltest2; drop database mysqltest; -ERROR HY000: Can't drop database 'mysqltest'. Database doesn't exist +ERROR HY000: Can't drop database 'mysqltest'; database doesn't exist drop database mysqltest2; set sql_log_bin = 0; create database mysqltest2; @@ -48,8 +48,8 @@ mysql test load data from master; Warnings: -Note 1008 Can't drop database 'mysqltest'. Database doesn't exist -Note 1008 Can't drop database 'mysqltest2'. Database doesn't exist +Note 1008 Can't drop database 'mysqltest'; database doesn't exist +Note 1008 Can't drop database 'mysqltest2'; database doesn't exist show databases; Database mysql diff --git a/mysql-test/r/symlink.result b/mysql-test/r/symlink.result index 3efc69d2f64..f12b98ba041 100644 --- a/mysql-test/r/symlink.result +++ b/mysql-test/r/symlink.result @@ -46,7 +46,7 @@ rename table t7 to t9; drop table t1; Got one of the listed errors Warnings: -Note 1008 Can't drop database 'test_mysqltest'. Database doesn't exist +Note 1008 Can't drop database 'test_mysqltest'; database doesn't exist Got one of the listed errors Got one of the listed errors Got one of the listed errors diff --git a/mysql-test/r/warnings.result b/mysql-test/r/warnings.result index add9051ddfb..d84c284d7b4 100644 --- a/mysql-test/r/warnings.result +++ b/mysql-test/r/warnings.result @@ -32,7 +32,7 @@ Level Code Message Note 1051 Unknown table 'not_exists_table' drop database if exists not_exists_db; Warnings: -Note 1008 Can't drop database 'not_exists_db'. Database doesn't exist +Note 1008 Can't drop database 'not_exists_db'; database doesn't exist show count(*) warnings; @@session.warning_count 1 From c994482fadd709639073ad2414d6362fa9987adb Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Fri, 11 Jul 2003 16:11:17 +0500 Subject: [PATCH 41/54] field_conv.cc: Data was not converted when ALTER TABLE CHAGE changed a field character set. --- sql/field_conv.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql/field_conv.cc b/sql/field_conv.cc index ec2488f520a..144e6d7e74a 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -489,6 +489,8 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*) if (!to->eq_def(from)) return do_field_string; } + else if (to->charset() != from->charset()) + return do_field_string; else if (to->real_type() == FIELD_TYPE_VAR_STRING && to_length != from_length) return do_varstring; From 7d094db0018cb7da4fa34c18c11a9840fbc43e5b Mon Sep 17 00:00:00 2001 From: "venu@myvenu.com" <> Date: Fri, 11 Jul 2003 18:55:03 -0700 Subject: [PATCH 42/54] Add the support of 'SUBSTR' function compatible with Oracle and SAPDB (SCRUM #872) --- mysql-test/r/func_str.result | 21 +++++++++++++++++++++ mysql-test/t/func_str.test | 11 +++++++++++ sql/item_strfunc.cc | 3 ++- sql/lex.h | 1 + 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index c2a921e1a54..611660675c8 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -532,3 +532,24 @@ t1 CREATE TABLE `t1` ( `replace(_latin2'abcd',_latin2'b',_latin2'B')` char(4) character set latin2 NOT NULL default '' ) TYPE=MyISAM CHARSET=latin1 drop table t1; +select SUBSTR('abcdefg',3,2); +SUBSTR('abcdefg',3,2) +cd +select SUBSTRING('abcdefg',3,2); +SUBSTRING('abcdefg',3,2) +cd +select SUBSTR('abcdefg',-3,2) FROM DUAL; +SUBSTR('abcdefg',-3,2) +ef +select SUBSTR('abcdefg',-1,5) FROM DUAL; +SUBSTR('abcdefg',-1,5) +g +select SUBSTR('abcdefg',0,0) FROM DUAL; +SUBSTR('abcdefg',0,0) + +select SUBSTR('abcdefg',-1,-1) FROM DUAL; +SUBSTR('abcdefg',-1,-1) + +select SUBSTR('abcdefg',1,-1) FROM DUAL; +SUBSTR('abcdefg',1,-1) + diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index c9e7b1a529d..1fabd997366 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -294,3 +294,14 @@ select ; show create table t1; drop table t1; + +# +# test for SUBSTR +# +select SUBSTR('abcdefg',3,2); +select SUBSTRING('abcdefg',3,2); +select SUBSTR('abcdefg',-3,2) FROM DUAL; +select SUBSTR('abcdefg',-1,5) FROM DUAL; +select SUBSTR('abcdefg',0,0) FROM DUAL; +select SUBSTR('abcdefg',-1,-1) FROM DUAL; +select SUBSTR('abcdefg',1,-1) FROM DUAL; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 2d29f76c2d7..92a68002b9e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -979,13 +979,14 @@ void Item_func_right::fix_length_and_dec() String *Item_func_substr::val_str(String *str) { String *res = args[0]->val_str(str); - int32 start = (int32) args[1]->val_int()-1; + int32 start = (int32) args[1]->val_int(); int32 length = arg_count == 3 ? (int32) args[2]->val_int() : INT_MAX32; int32 tmp_length; if ((null_value=(args[0]->null_value || args[1]->null_value || (arg_count == 3 && args[2]->null_value)))) return 0; /* purecov: inspected */ + start= (int32)((start < 0) ? res->length() + start : start -1); start=res->charpos(start); length=res->charpos(length,start); if (start < 0 || (uint) start+1 > res->length() || length <= 0) diff --git a/sql/lex.h b/sql/lex.h index a148baad07f..c2860f4551a 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -627,6 +627,7 @@ static SYMBOL sql_functions[] = { { "STD", SYM(STD_SYM),0,0}, { "STDDEV", SYM(STD_SYM),0,0}, { "STRCMP", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_strcmp)}, + { "SUBSTR", SYM(SUBSTRING),0,0}, { "SUBSTRING", SYM(SUBSTRING),0,0}, { "SUBSTRING_INDEX", SYM(SUBSTRING_INDEX),0,0}, { "SUBTIME", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_subtime)}, From 3110561e5df13003d74da58b57e9babc42dbd450 Mon Sep 17 00:00:00 2001 From: "guilhem@gbichot2" <> Date: Sat, 12 Jul 2003 23:31:21 +0200 Subject: [PATCH 43/54] Added SHOW MASTER LOGS as synonym for SHOW BINARY LOGS. Added PURGE BINARY LOGS as synonym for PURGE MASTER LOGS. Removed PURGE LOGS (now PURGE MASTER LOGS). Added SHOW BDB LOGS as synonym for SHOW LOGS. Note: tests key_cache.test hanged, rpl_log_pos.test, rpl_rotate_logs.test failed for me. For the second and third one I guess this will disappear after merging 4.0. --- mysql-test/r/rpl_rotate_logs.result | 7 ++++++- mysql-test/t/rpl_rotate_logs.test | 5 ++++- sql/sql_yacc.yy | 11 ++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/rpl_rotate_logs.result b/mysql-test/r/rpl_rotate_logs.result index 66209d2b852..c3c83947578 100644 --- a/mysql-test/r/rpl_rotate_logs.result +++ b/mysql-test/r/rpl_rotate_logs.result @@ -41,11 +41,16 @@ insert into t2 values(NULL); set global sql_slave_skip_counter=1; start slave; purge master logs to 'master-bin.000002'; +show master logs; +Log_name +master-bin.000002 +master-bin.000003 +purge binary logs to 'master-bin.000002'; show binary logs; Log_name master-bin.000002 master-bin.000003 -purge logs before now(); +purge master logs before now(); show binary logs; Log_name master-bin.000003 diff --git a/mysql-test/t/rpl_rotate_logs.test b/mysql-test/t/rpl_rotate_logs.test index 8ad5109d2c6..df506c08e71 100644 --- a/mysql-test/t/rpl_rotate_logs.test +++ b/mysql-test/t/rpl_rotate_logs.test @@ -90,9 +90,12 @@ connection master; sync_slave_with_master; connection master; purge master logs to 'master-bin.000002'; +show master logs; +# we just tests if synonyms are accepted +purge binary logs to 'master-bin.000002'; show binary logs; --sleep 1; -purge logs before now(); +purge master logs before now(); show binary logs; insert into t2 values (65); sync_slave_with_master; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3098bd18b2d..c836cb414e0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3742,7 +3742,7 @@ show_param: Lex->mi.pos = $12; Lex->mi.server_id = $16; } - | BINARY LOGS_SYM + | master_or_binary LOGS_SYM { Lex->sql_command = SQLCOM_SHOW_BINLOGS; } @@ -3802,6 +3802,8 @@ show_param: { Lex->sql_command= SQLCOM_SHOW_CHARSETS; } | COLLATION_SYM wild { Lex->sql_command= SQLCOM_SHOW_COLLATIONS; } + | BERKELEY_DB_SYM LOGS_SYM + { Lex->sql_command= SQLCOM_SHOW_LOGS; } | LOGS_SYM { Lex->sql_command= SQLCOM_SHOW_LOGS; } | GRANTS FOR_SYM user @@ -3832,6 +3834,10 @@ show_param: Lex->sql_command = SQLCOM_SHOW_SLAVE_STAT; }; +master_or_binary: + MASTER_SYM + | BINARY; + opt_db: /* empty */ { $$= 0; } | from_or_in ident { $$= $2.str; }; @@ -3949,8 +3955,7 @@ purge: ; purge_options: - LOGS_SYM purge_option - | MASTER_SYM LOGS_SYM purge_option + master_or_binary LOGS_SYM purge_option ; purge_option: From 0d3a73efb338d92a9becdf98689c1cf04be5914d Mon Sep 17 00:00:00 2001 From: "miguel@hegel.local" <> Date: Sun, 13 Jul 2003 01:20:15 -0400 Subject: [PATCH 44/54] Removed unreferenced local variable --- sql/item_strfunc.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 2d29f76c2d7..f5cc88e2e4e 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2427,7 +2427,6 @@ String* Item_func_export_set::val_str(String* str) void Item_func_export_set::fix_length_and_dec() { - uint i; uint length=max(args[1]->max_length,args[2]->max_length); uint sep_length=(arg_count > 3 ? args[3]->max_length : 1); max_length=length*64+sep_length*63; From 0f47087e2217cbbb39bba2c8ceb0e9de38254dbf Mon Sep 17 00:00:00 2001 From: "ram@mysql.r18.ru" <> Date: Mon, 14 Jul 2003 15:32:31 +0500 Subject: [PATCH 45/54] Fix for the bug #841: wrong number of warnings --- sql/sql_insert.cc | 19 +++++++++---------- sql/sql_load.cc | 4 ++-- sql/sql_table.cc | 4 ++-- sql/sql_update.cc | 8 ++++---- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 091de9d406f..947205949f1 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -404,13 +404,12 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, { char buff[160]; if (duplic == DUP_IGNORE) - sprintf(buff,ER(ER_INSERT_INFO),info.records, - (lock_type == TL_WRITE_DELAYED) ? 0 : - info.records-info.copied, - thd->cuted_fields); + sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, + (lock_type == TL_WRITE_DELAYED) ? (ulong) 0 : + (ulong) (info.records - info.copied), (ulong) thd->cuted_fields); else - sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted, - thd->cuted_fields); + sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, + (ulong) info.deleted, (ulong) thd->cuted_fields); ::send_ok(thd,info.copied+info.deleted,(ulonglong)id,buff); } free_underlaid_joins(thd, &thd->lex.select_lex); @@ -1494,11 +1493,11 @@ bool select_insert::send_eof() { char buff[160]; if (info.handle_duplicates == DUP_IGNORE) - sprintf(buff,ER(ER_INSERT_INFO),info.records,info.records-info.copied, - thd->cuted_fields); + sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, + (ulong) (info.records - info.copied), (ulong) thd->cuted_fields); else - sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted, - thd->cuted_fields); + sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, + (ulong) info.deleted, (ulong) thd->cuted_fields); ::send_ok(thd,info.copied+info.deleted,last_insert_id,buff); return 0; } diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 12acfb9b5df..d030eaf617c 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -318,8 +318,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, error= -1; // Error on read goto err; } - sprintf(name,ER(ER_LOAD_INFO),info.records,info.deleted, - info.records-info.copied,thd->cuted_fields); + sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted, + (ulong) (info.records - info.copied), (ulong) thd->cuted_fields); send_ok(thd,info.copied+info.deleted,0L,name); // on the slave thd->query is never initialized if (!thd->slave_thread) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 33a59e540f8..2e6585583ba 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2416,8 +2416,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, query_cache_invalidate3(thd, table_list, 0); end_temporary: - sprintf(tmp_name,ER(ER_INSERT_INFO),(ulong) (copied+deleted), - (ulong) deleted, thd->cuted_fields); + sprintf(tmp_name, ER(ER_INSERT_INFO), (ulong) (copied + deleted), + (ulong) deleted, (ulong) thd->cuted_fields); send_ok(thd,copied+deleted,0L,tmp_name); thd->some_tables_deleted=0; DBUG_RETURN(0); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 989d17b006b..e1c28dd0e4d 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -373,8 +373,8 @@ int mysql_update(THD *thd, else { char buff[80]; - sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated, - (long) thd->cuted_fields); + sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated, + (ulong) thd->cuted_fields); send_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, thd->insert_id_used ? thd->insert_id() : 0L,buff); @@ -993,8 +993,8 @@ bool multi_update::send_eof() } - sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated, - (long) thd->cuted_fields); + sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated, + (ulong) thd->cuted_fields); ::send_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, thd->insert_id_used ? thd->insert_id() : 0L,buff); From 1472b156e2030f42203dc34d2b1e10186003ebe6 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Mon, 14 Jul 2003 18:00:27 +0500 Subject: [PATCH 46/54] A test for character conversion in ALTER TABLE was added --- mysql-test/r/alter_table.result | 39 +++++++++++++++++++++++++++++++++ mysql-test/t/alter_table.test | 27 +++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index cb11e680910..7fa5a0f601f 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -281,3 +281,42 @@ ALTER TABLE t1 DISABLE KEYS; INSERT DELAYED INTO t1 VALUES(1),(2),(3); ALTER TABLE t1 ENABLE KEYS; drop table t1; +set names koi8r; +create table t1 (a char(10) character set koi8r); +insert into t1 values ('ÔÅÓÔ'); +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ D4C5D3D4 +alter table t1 change a a char(10) character set cp1251; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ F2E5F1F2 +alter table t1 change a a char(10) binary; +select a,hex(a) from t1; +a hex(a) +òåñò F2E5F1F2 +alter table t1 change a a char(10) character set cp1251; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ F2E5F1F2 +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ D4C5D3D4 +alter table t1 change a a varchar(10) character set cp1251; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ F2E5F1F2 +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ D4C5D3D4 +alter table t1 change a a text character set cp1251; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ F2E5F1F2 +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +a hex(a) +ÔÅÓÔ D4C5D3D4 +drop table t1; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 04229bd1882..346ad8fe80e 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -144,3 +144,30 @@ ALTER TABLE t1 DISABLE KEYS; INSERT DELAYED INTO t1 VALUES(1),(2),(3); ALTER TABLE t1 ENABLE KEYS; drop table t1; + +# +# Test that data get converted when character set is changed +# Test that data doesn't get converted when src or dst is BINARY/BLOB +# +set names koi8r; +create table t1 (a char(10) character set koi8r); +insert into t1 values ('ÔÅÓÔ'); +select a,hex(a) from t1; +alter table t1 change a a char(10) character set cp1251; +select a,hex(a) from t1; +alter table t1 change a a char(10) binary; +select a,hex(a) from t1; +alter table t1 change a a char(10) character set cp1251; +select a,hex(a) from t1; +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +alter table t1 change a a varchar(10) character set cp1251; +select a,hex(a) from t1; +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; +alter table t1 change a a text character set cp1251; +select a,hex(a) from t1; +alter table t1 change a a char(10) character set koi8r; +select a,hex(a) from t1; + +drop table t1; From e26b90c2382a5828a96fb565a5a5829dcc6bd6b7 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Mon, 14 Jul 2003 19:28:36 +0500 Subject: [PATCH 47/54] COALESCE now aggregates its argument types in this way: if some of the arguments is STRING_RESULT the STRING_RESULT else if some of the arguments is REAL_RESULT then REAL_RESULT else INT_RESULT --- mysql-test/r/case.result | 21 +++++++++++++++++++++ mysql-test/t/case.test | 22 ++++++++++++++++++++++ sql/item_cmpfunc.cc | 6 ++++++ 3 files changed, 49 insertions(+) diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index 914e05efa7a..04627a7a493 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -71,3 +71,24 @@ orange yellow green drop table t1; +SET NAMES latin1; +CREATE TABLE t1 SELECT COALESCE(_latin1'a',_latin2'a'); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'coalesce' +CREATE TABLE t1 SELECT COALESCE('a' COLLATE latin1_swedish_ci,'b' COLLATE latin1_bin); +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation 'coalesce' +CREATE TABLE t1 SELECT +COALESCE(1), COALESCE(1.0),COALESCE('a'), +COALESCE(1,1.0), COALESCE(1,'1'),COALESCE(1.1,'1'), +COALESCE('a' COLLATE latin1_bin,'b'); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `COALESCE(1)` int(1) NOT NULL default '0', + `COALESCE(1.0)` double(3,1) NOT NULL default '0.0', + `COALESCE('a')` char(1) NOT NULL default '', + `COALESCE(1,1.0)` double(3,1) NOT NULL default '0.0', + `COALESCE(1,'1')` char(1) NOT NULL default '', + `COALESCE(1.1,'1')` char(3) NOT NULL default '', + `COALESCE('a' COLLATE latin1_bin,'b')` char(1) character set latin1 collate latin1_bin NOT NULL default '' +) TYPE=MyISAM CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/t/case.test b/mysql-test/t/case.test index 6131d1500de..0249a8eefba 100644 --- a/mysql-test/t/case.test +++ b/mysql-test/t/case.test @@ -41,3 +41,25 @@ create table t1 (row int not null, col int not null, val varchar(255) not null); insert into t1 values (1,1,'orange'),(1,2,'large'),(2,1,'yellow'),(2,2,'medium'),(3,1,'green'),(3,2,'small'); select max(case col when 1 then val else null end) as color from t1 group by row; drop table t1; + +# +# COALESCE is a CASE abbrevation: +# +# COALESCE(v1,v2) == CASE WHEN v1 IS NOT NULL THEN v1 ELSE v2 END +# +# COALESCE(V1, V2, . . . ,Vn ) = +# CASE WHEN V1 IS NOT NULL THEN V1 ELSE COALESCE (V2, . . . ,Vn) END +# +# Check COALESCE argument types aggregation + +SET NAMES latin1; +--error 1265 +CREATE TABLE t1 SELECT COALESCE(_latin1'a',_latin2'a'); +--error 1265 +CREATE TABLE t1 SELECT COALESCE('a' COLLATE latin1_swedish_ci,'b' COLLATE latin1_bin); +CREATE TABLE t1 SELECT + COALESCE(1), COALESCE(1.0),COALESCE('a'), + COALESCE(1,1.0), COALESCE(1,'1'),COALESCE(1.1,'1'), + COALESCE('a' COLLATE latin1_bin,'b'); +SHOW CREATE TABLE t1; +DROP TABLE t1; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 326138d798d..ff805e05346 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1149,7 +1149,13 @@ void Item_func_coalesce::fix_length_and_dec() { set_if_bigger(max_length,args[i]->max_length); set_if_bigger(decimals,args[i]->decimals); + cached_result_type=item_store_type(cached_result_type, + args[i]->result_type()); } + if (cached_result_type == STRING_RESULT) + agg_arg_collations(collation, args, arg_count); + else if (cached_result_type != REAL_RESULT) + decimals= 0; } /**************************************************************************** From 04ac36a4679fb3f1b816201c655912d88770c572 Mon Sep 17 00:00:00 2001 From: "gluh@gluh.mysql.r18.ru" <> Date: Tue, 15 Jul 2003 12:55:29 +0500 Subject: [PATCH 48/54] Fix bug: mysqld crashes on func_sapdb test. --- sql/item_timefunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 4fdb1b13d24..c2d1504e94a 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -380,7 +380,7 @@ longlong Item_func_time_to_sec::val_int() static bool get_interval_value(Item *args,interval_type int_type, String *str_value, INTERVAL *t) { - long array[4],value; + long array[5],value; const char *str; uint32 length; LINT_INIT(value); LINT_INIT(str); LINT_INIT(length); From e1aaa670cc2274b655d25e35e216644aa9d37645 Mon Sep 17 00:00:00 2001 From: "ram@mysql.r18.ru" <> Date: Tue, 15 Jul 2003 14:38:48 +0500 Subject: [PATCH 49/54] mysql should ignore ' " ` symbols inside comments (Bug #539). --- client/mysql.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 45b0e4bf2ea..4c07c1bbab7 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1085,7 +1085,7 @@ static bool add_line(String &buffer,char *line,char *in_string, out=line; } } - else if (*ml_comment && !*in_string && inchar == '*' && *(pos+1) == '/') + else if (*ml_comment && inchar == '*' && *(pos + 1) == '/') { pos++; *ml_comment= 0; @@ -1093,11 +1093,13 @@ static bool add_line(String &buffer,char *line,char *in_string, else { // Add found char to buffer if (inchar == *in_string) - *in_string=0; - else if (!*in_string && (inchar == '\'' || inchar == '"' || inchar == '`')) - *in_string=(char) inchar; - if (!(*ml_comment)) - *out++ = (char) inchar; + *in_string= 0; + else if (!*ml_comment) + { + if (!*in_string && (inchar == '\'' || inchar == '"' || inchar == '`')) + *in_string= (char) inchar; + *out++= (char) inchar; + } } } if (out != line || !buffer.is_empty()) From 4b9c7f8336358324079b5f5f5e83d84e559e4e1b Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Tue, 15 Jul 2003 17:33:00 +0500 Subject: [PATCH 50/54] Item_func_field doesn't have a separate Item to store the first argument. It's now passed as args[0]. This fix allowed to resuse a lot of code. --- mysql-test/r/func_str.result | 4 +-- mysql-test/t/func_str.test | 4 +-- sql/item_func.cc | 55 ++++++++---------------------------- sql/item_func.h | 21 +------------- sql/sql_yacc.yy | 2 +- 5 files changed, 18 insertions(+), 68 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 611660675c8..208efc51acb 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -297,9 +297,9 @@ select FIELD('b','A' COLLATE latin1_bin,'B'); FIELD('b','A' COLLATE latin1_bin,'B') 0 select FIELD(_latin2'b','A','B'); -ERROR HY000: Illegal mix of collations for operation 'field' +Illegal mix of collations (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'field' select FIELD('b',_latin2'A','B'); -ERROR HY000: Illegal mix of collations for operation 'field' +Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'field' select FIELD('b',_latin2'A','B',1); FIELD('b',_latin2'A','B',1) 1 diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 1fabd997366..7748694169f 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -167,9 +167,9 @@ select FIELD('b','A','B'); select FIELD('B','A','B'); select FIELD('b' COLLATE latin1_bin,'A','B'); select FIELD('b','A' COLLATE latin1_bin,'B'); ---error 1269 +--error 1265 select FIELD(_latin2'b','A','B'); ---error 1269 +--error 1265 select FIELD('b',_latin2'A','B'); select FIELD('b',_latin2'A','B',1); diff --git a/sql/item_func.cc b/sql/item_func.cc index 7264a3b5225..7e236225067 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1170,32 +1170,32 @@ longlong Item_func_field::val_int() if (cmp_type == STRING_RESULT) { String *field; - if (!(field=item->val_str(&value))) + if (!(field=args[0]->val_str(&value))) return 0; // -1 if null ? - for (uint i=0 ; i < arg_count ; i++) + for (uint i=1 ; i < arg_count ; i++) { String *tmp_value=args[i]->val_str(&tmp); if (tmp_value && field->length() == tmp_value->length() && !sortcmp(field,tmp_value,cmp_collation.collation)) - return (longlong) (i+1); + return (longlong) (i); } } else if (cmp_type == INT_RESULT) { - longlong val= item->val_int(); - for (uint i=0; i < arg_count ; i++) + longlong val= args[0]->val_int(); + for (uint i=1; i < arg_count ; i++) { if (val == args[i]->val_int()) - return (longlong) (i+1); + return (longlong) (i); } } else { - double val= item->val(); - for (uint i=0; i < arg_count ; i++) + double val= args[0]->val(); + for (uint i=1; i < arg_count ; i++) { if (val == args[i]->val()) - return (longlong) (i+1); + return (longlong) (i); } } return 0; @@ -1204,42 +1204,11 @@ longlong Item_func_field::val_int() void Item_func_field::fix_length_and_dec() { maybe_null=0; max_length=3; - used_tables_cache|= item->used_tables(); - const_item_cache&= item->const_item(); - with_sum_func= with_sum_func || item->with_sum_func; - - cmp_type= item->result_type(); - for (uint i=0; i < arg_count ; i++) + cmp_type= args[0]->result_type(); + for (uint i=1; i < arg_count ; i++) cmp_type= item_cmp_type(cmp_type, args[i]->result_type()); - if (cmp_type == STRING_RESULT) - { - cmp_collation.set(item->collation); - for (uint i=0 ; i < arg_count ; i++) - { - if (cmp_collation.aggregate(args[i]->collation)) - { - my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),func_name()); - return; - } - } - } -} - - -void Item_func_field::split_sum_func(Item **ref_pointer_array, - List &fields) -{ - if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) - item->split_sum_func(ref_pointer_array, fields); - else if (item->used_tables() || item->type() == SUM_FUNC_ITEM) - { - uint el= fields.elements; - fields.push_front(item); - ref_pointer_array[el]= item; - item= new Item_ref(ref_pointer_array + el, 0, item->name); - } - Item_func::split_sum_func(ref_pointer_array, fields); + agg_arg_collations_for_comparison(cmp_collation, args, arg_count); } diff --git a/sql/item_func.h b/sql/item_func.h index a5575a35851..a0969fc6b9a 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -625,33 +625,14 @@ public: class Item_func_field :public Item_int_func { - Item *item; String value,tmp; Item_result cmp_type; DTCollation cmp_collation; public: - Item_func_field(Item *a,List &list) :Item_int_func(list),item(a) {} - ~Item_func_field() { delete item; } + Item_func_field(List &list) :Item_int_func(list) {} longlong val_int(); - bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref) - { - return (item->fix_fields(thd, tlist, &item) || item->check_cols(1) || - Item_func::fix_fields(thd, tlist, ref)); - } - void split_sum_func(Item **ref_pointer_array, List &fields); - void update_used_tables() - { - item->update_used_tables() ; Item_func::update_used_tables(); - used_tables_cache|= item->used_tables(); - const_item_cache&= item->const_item(); - } const char *func_name() const { return "field"; } void fix_length_and_dec(); - void set_outer_resolving() - { - item->set_outer_resolving(); - Item_int_func::set_outer_resolving(); - } }; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c836cb414e0..c07876a18cc 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2427,7 +2427,7 @@ simple_expr: $$= new Item_func_date_format (new Item_func_from_unixtime($3),$5,0); } | FIELD_FUNC '(' expr ',' expr_list ')' - { $$= new Item_func_field($3, *$5); } + { $5->push_front($3); $$= new Item_func_field(*$5); } | GEOMFROMTEXT '(' expr ')' { $$= new Item_func_geometry_from_text($3); } | GEOMFROMTEXT '(' expr ',' expr ')' From bc753e138c0f9ced054200dbe5b8f7853b80b63e Mon Sep 17 00:00:00 2001 From: "ram@mysql.r18.ru" <> Date: Tue, 15 Jul 2003 17:38:01 +0500 Subject: [PATCH 51/54] bugfix for the bugfix for the bug #539 --- client/mysql.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 4c07c1bbab7..ed0c1bf102b 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1094,12 +1094,11 @@ static bool add_line(String &buffer,char *line,char *in_string, { // Add found char to buffer if (inchar == *in_string) *in_string= 0; - else if (!*ml_comment) - { - if (!*in_string && (inchar == '\'' || inchar == '"' || inchar == '`')) - *in_string= (char) inchar; + else if (!*ml_comment && !*in_string && + (inchar == '\'' || inchar == '"' || inchar == '`')) + *in_string= (char) inchar; + if (!*ml_comment) *out++= (char) inchar; - } } } if (out != line || !buffer.is_empty()) From 91d93f6f61d388251a0a637d2f09a6786fd4abd8 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Tue, 15 Jul 2003 18:11:49 +0500 Subject: [PATCH 52/54] ELT passes the first argument in args[0] instead of having a separate Item. --- mysql-test/r/func_str.result | 4 ++-- mysql-test/t/func_str.test | 4 ++-- sql/item_strfunc.cc | 44 +++++++----------------------------- sql/item_strfunc.h | 18 +-------------- sql/sql_yacc.yy | 2 +- 5 files changed, 14 insertions(+), 58 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 208efc51acb..12969449e3f 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -297,9 +297,9 @@ select FIELD('b','A' COLLATE latin1_bin,'B'); FIELD('b','A' COLLATE latin1_bin,'B') 0 select FIELD(_latin2'b','A','B'); -Illegal mix of collations (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'field' +ERROR HY000: Illegal mix of collations (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'field' select FIELD('b',_latin2'A','B'); -Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'field' +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'field' select FIELD('b',_latin2'A','B',1); FIELD('b',_latin2'A','B',1) 1 diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 7748694169f..38633e87c4b 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -167,9 +167,9 @@ select FIELD('b','A','B'); select FIELD('B','A','B'); select FIELD('b' COLLATE latin1_bin,'A','B'); select FIELD('b','A' COLLATE latin1_bin,'B'); ---error 1265 +--error 1268 select FIELD(_latin2'b','A','B'); ---error 1265 +--error 1268 select FIELD('b',_latin2'A','B'); select FIELD('b',_latin2'A','B',1); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index b25619d0bb1..4e35e90b429 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1660,81 +1660,53 @@ void Item_func_elt::fix_length_and_dec() max_length=0; decimals=0; - if (agg_arg_collations(collation, args, arg_count)) + if (agg_arg_collations(collation, args+1, arg_count-1)) return; - for (uint i=0 ; i < arg_count ; i++) + for (uint i=1 ; i < arg_count ; i++) { set_if_bigger(max_length,args[i]->max_length); set_if_bigger(decimals,args[i]->decimals); } maybe_null=1; // NULL if wrong first arg - with_sum_func= with_sum_func || item->with_sum_func; - used_tables_cache|=item->used_tables(); - const_item_cache&=item->const_item(); -} - - -void Item_func_elt::split_sum_func(Item **ref_pointer_array, - List &fields) -{ - if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) - item->split_sum_func(ref_pointer_array, fields); - else if (item->used_tables() || item->type() == SUM_FUNC_ITEM) - { - uint el= fields.elements; - fields.push_front(item); - ref_pointer_array[el]= item; - item= new Item_ref(ref_pointer_array + el, 0, item->name); - } - Item_str_func::split_sum_func(ref_pointer_array, fields); -} - - -void Item_func_elt::update_used_tables() -{ - Item_func::update_used_tables(); - item->update_used_tables(); - used_tables_cache|=item->used_tables(); - const_item_cache&=item->const_item(); } double Item_func_elt::val() { uint tmp; - if ((tmp=(uint) item->val_int()) == 0 || tmp > arg_count) + if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count) { null_value=1; return 0.0; } null_value=0; - return args[tmp-1]->val(); + return args[tmp]->val(); } longlong Item_func_elt::val_int() { uint tmp; - if ((tmp=(uint) item->val_int()) == 0 || tmp > arg_count) + if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count) { null_value=1; return 0; } null_value=0; - return args[tmp-1]->val_int(); + return args[tmp]->val_int(); } String *Item_func_elt::val_str(String *str) { uint tmp; String *res; - if ((tmp=(uint) item->val_int()) == 0 || tmp > arg_count) + if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count) { null_value=1; return NULL; } null_value=0; - res= args[tmp-1]->val_str(str); + res= args[tmp]->val_str(str); res->set_charset(charset()); return res; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 6cc6d730627..7f8d7ade67b 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -372,29 +372,13 @@ public: class Item_func_elt :public Item_str_func { - Item *item; - public: - Item_func_elt(Item *a,List &list) :Item_str_func(list),item(a) {} - ~Item_func_elt() { delete item; } + Item_func_elt(List &list) :Item_str_func(list) {} double val(); longlong val_int(); String *val_str(String *str); - bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) - { - return (item->fix_fields(thd, tlist, &item) || - item->check_cols(1) || - Item_func::fix_fields(thd, tlist, ref)); - } - void split_sum_func(Item **ref_pointer_array, List &fields); void fix_length_and_dec(); - void update_used_tables(); const char *func_name() const { return "elt"; } - void set_outer_resolving() - { - item->set_outer_resolving(); - Item_str_func::set_outer_resolving(); - } }; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c07876a18cc..45a647cd8ab 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2389,7 +2389,7 @@ simple_expr: | DAY_SYM '(' expr ')' { $$= new Item_func_dayofmonth($3); } | ELT_FUNC '(' expr ',' expr_list ')' - { $$= new Item_func_elt($3, *$5); } + { $5->push_front($3); $$= new Item_func_elt(*$5); } | MAKE_SET_SYM '(' expr ',' expr_list ')' { $$= new Item_func_make_set($3, *$5); } | ENCRYPT '(' expr ')' From 27a82c836c1c2ce271c9bf17a12be5dd1219a190 Mon Sep 17 00:00:00 2001 From: "paul@teton.kitebird.com" <> Date: Tue, 15 Jul 2003 14:37:22 -0500 Subject: [PATCH 53/54] Update openssl_1 test. --- mysql-test/r/openssl_1.result | 8 ++++---- mysql-test/t/openssl_1.test | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/openssl_1.result b/mysql-test/r/openssl_1.result index 65b882c0a9b..afc4b12a341 100644 --- a/mysql-test/r/openssl_1.result +++ b/mysql-test/r/openssl_1.result @@ -10,22 +10,22 @@ select * from t1; f1 5 delete from t1; -Access denied for user: 'ssl_user1@localhost' to database 'test' +ERROR 42000: Access denied for user: 'ssl_user1@localhost' to database 'test' select * from t1; f1 5 delete from t1; -Access denied for user: 'ssl_user2@localhost' to database 'test' +ERROR 42000: Access denied for user: 'ssl_user2@localhost' to database 'test' select * from t1; f1 5 delete from t1; -Access denied for user: 'ssl_user3@localhost' to database 'test' +ERROR 42000: Access denied for user: 'ssl_user3@localhost' to database 'test' select * from t1; f1 5 delete from t1; -Access denied for user: 'ssl_user4@localhost' to database 'test' +ERROR 42000: Access denied for user: 'ssl_user4@localhost' to database 'test' delete from mysql.user where user='ssl_user%'; delete from mysql.db where user='ssl_user%'; flush privileges; diff --git a/mysql-test/t/openssl_1.test b/mysql-test/t/openssl_1.test index 3af7406cef3..c1c818efb70 100644 --- a/mysql-test/t/openssl_1.test +++ b/mysql-test/t/openssl_1.test @@ -2,7 +2,9 @@ # Use mysql-test-run with --with-openssl option. -- source include/have_openssl_1.inc +--disable_warnings drop table if exists t1; +--enable_warnings create table t1(f1 int); insert into t1 values (5); From a35fff5bc38732d48472a64a4504bcead010a379 Mon Sep 17 00:00:00 2001 From: "bar@bar.mysql.r18.ru" <> Date: Wed, 16 Jul 2003 11:29:16 +0500 Subject: [PATCH 54/54] Item_func_null doesn't have a separate Item for the first argument anymore. args[0] is used instead. This allowed to resuse a lot of code. --- mysql-test/r/func_in.result | 32 +++++++++++++++ mysql-test/r/func_str.result | 10 ++--- mysql-test/t/func_in.test | 19 +++++++++ mysql-test/t/func_str.test | 10 ++--- sql/item_cmpfunc.cc | 78 +++++++++++++----------------------- sql/item_cmpfunc.h | 26 +++--------- sql/opt_range.cc | 4 +- sql/sql_yacc.yy | 8 ++-- 8 files changed, 100 insertions(+), 87 deletions(-) diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index 006dc8abef0..4b15c44fdb1 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -111,3 +111,35 @@ id 5 9 drop table t1; +create table t1 ( +a char(1) character set latin1 collate latin1_general_ci, +b char(1) character set latin1 collate latin1_swedish_ci, +c char(1) character set latin1 collate latin1_danish_ci +); +insert into t1 values ('A','B','C'); +insert into t1 values ('a','c','c'); +select * from t1 where a in (b); +ERROR HY000: Illegal mix of collations (latin1_general_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation ' IN ' +select * from t1 where a in (b,c); +ERROR HY000: Illegal mix of collations (latin1_general_ci,IMPLICIT), (latin1_swedish_ci,IMPLICIT), (latin1_danish_ci,IMPLICIT) for operation ' IN ' +select * from t1 where 'a' in (a,b,c); +ERROR HY000: Illegal mix of collations for operation ' IN ' +select * from t1 where 'a' in (a); +a b c +A B C +a c c +select * from t1 where a in ('a'); +a b c +A B C +a c c +select * from t1 where 'a' collate latin1_general_ci in (a,b,c); +a b c +A B C +a c c +select * from t1 where 'a' collate latin1_bin in (a,b,c); +a b c +a c c +select * from t1 where 'a' in (a,b,c collate latin1_bin); +a b c +a c c +drop table t1; diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 12969449e3f..37694ad2f0a 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -363,15 +363,15 @@ select _latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin); _latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin) 0 select _latin2'B' in (_latin1'a',_latin1'b'); -ERROR HY000: Illegal mix of collations for operation ' IN ' +ERROR HY000: Illegal mix of collations (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation ' IN ' select _latin1'B' in (_latin2'a',_latin1'b'); -ERROR HY000: Illegal mix of collations for operation ' IN ' +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation ' IN ' select _latin1'B' in (_latin1'a',_latin2'b'); -ERROR HY000: Illegal mix of collations for operation ' IN ' +ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE) for operation ' IN ' select _latin1'B' COLLATE latin1_general_ci in (_latin1'a' COLLATE latin1_bin,_latin1'b'); -ERROR HY000: Illegal mix of collations for operation ' IN ' +ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_bin,EXPLICIT), (latin1_swedish_ci,COERCIBLE) for operation ' IN ' select _latin1'B' COLLATE latin1_general_ci in (_latin1'a',_latin1'b' COLLATE latin1_bin); -ERROR HY000: Illegal mix of collations for operation ' IN ' +ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_swedish_ci,COERCIBLE), (latin1_bin,EXPLICIT) for operation ' IN ' select collation(bin(130)), coercibility(bin(130)); collation(bin(130)) coercibility(bin(130)) latin1_swedish_ci 3 diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index 723f1707a42..dca068f368a 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -54,3 +54,22 @@ insert into t1 values (1),(2),(3),(4),(5),(6),(7),(8),(9); select * from t1 where id in (2,5,9); drop table t1; +create table t1 ( +a char(1) character set latin1 collate latin1_general_ci, +b char(1) character set latin1 collate latin1_swedish_ci, +c char(1) character set latin1 collate latin1_danish_ci +); +insert into t1 values ('A','B','C'); +insert into t1 values ('a','c','c'); +--error 1265 +select * from t1 where a in (b); +--error 1268 +select * from t1 where a in (b,c); +--error 1269 +select * from t1 where 'a' in (a,b,c); +select * from t1 where 'a' in (a); +select * from t1 where a in ('a'); +select * from t1 where 'a' collate latin1_general_ci in (a,b,c); +select * from t1 where 'a' collate latin1_bin in (a,b,c); +select * from t1 where 'a' in (a,b,c collate latin1_bin); +drop table t1; diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 38633e87c4b..f158eaa3764 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -217,15 +217,15 @@ select _latin1'B' in (_latin1'a',_latin1'b'); select _latin1'B' collate latin1_bin in (_latin1'a',_latin1'b'); select _latin1'B' in (_latin1'a' collate latin1_bin,_latin1'b'); select _latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin); ---error 1269 +--error 1268 select _latin2'B' in (_latin1'a',_latin1'b'); ---error 1269 +--error 1268 select _latin1'B' in (_latin2'a',_latin1'b'); ---error 1269 +--error 1268 select _latin1'B' in (_latin1'a',_latin2'b'); ---error 1269 +--error 1268 select _latin1'B' COLLATE latin1_general_ci in (_latin1'a' COLLATE latin1_bin,_latin1'b'); ---error 1269 +--error 1268 select _latin1'B' COLLATE latin1_general_ci in (_latin1'a',_latin1'b' COLLATE latin1_bin); select collation(bin(130)), coercibility(bin(130)); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index ff805e05346..758733aaa2c 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1420,7 +1420,7 @@ int cmp_item_row::compare(cmp_item *c) bool Item_func_in::nulls_in_row() { Item **arg,**arg_end; - for (arg= args, arg_end= args+arg_count; arg != arg_end ; arg++) + for (arg= args+1, arg_end= args+arg_count; arg != arg_end ; arg++) { if ((*arg)->null_inside()) return 1; @@ -1437,42 +1437,43 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) void Item_func_in::fix_length_and_dec() { + Item **arg, **arg_end; + uint const_itm= 1; + + if ((args[0]->result_type() == STRING_RESULT) && + (agg_arg_collations_for_comparison(cmp_collation, args, arg_count))) + return; + + for (arg=args+1, arg_end=args+arg_count; arg != arg_end ; arg++) + const_itm&= arg[0]->const_item(); + /* Row item with NULLs inside can return NULL or FALSE => they can't be processed as static */ - if (const_item() && !nulls_in_row()) + if (const_itm && !nulls_in_row()) { - switch (item->result_type()) { + switch (args[0]->result_type()) { case STRING_RESULT: uint i; - cmp_collation.set(item->collation); - for (i=0 ; icollation)) - break; - if (cmp_collation.derivation == DERIVATION_NONE) - { - my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),func_name()); - return; - } - array=new in_string(arg_count,(qsort2_cmp) srtcmp_in, + array=new in_string(arg_count-1,(qsort2_cmp) srtcmp_in, cmp_collation.collation); break; case INT_RESULT: - array= new in_longlong(arg_count); + array= new in_longlong(arg_count-1); break; case REAL_RESULT: - array= new in_double(arg_count); + array= new in_double(arg_count-1); break; case ROW_RESULT: - array= new in_row(arg_count, item); + array= new in_row(arg_count-1, args[0]); break; default: DBUG_ASSERT(0); return; } uint j=0; - for (uint i=0 ; i < arg_count ; i++) + for (uint i=1 ; i < arg_count ; i++) { array->set(j,args[i]); if (!args[i]->null_value) // Skip NULL values @@ -1485,19 +1486,19 @@ void Item_func_in::fix_length_and_dec() } else { - in_item= cmp_item::get_comparator(item); + in_item= cmp_item::get_comparator(args[0]); + if (args[0]->result_type() == STRING_RESULT) + in_item->cmp_charset= cmp_collation.collation; } - maybe_null= item->maybe_null; + maybe_null= args[0]->maybe_null; max_length= 1; - used_tables_cache|=item->used_tables(); - const_item_cache&=item->const_item(); + const_item_cache&=args[0]->const_item(); } void Item_func_in::print(String *str) { str->append('('); - item->print(str); Item_func::print(str); str->append(')'); } @@ -1507,15 +1508,15 @@ longlong Item_func_in::val_int() { if (array) { - int tmp=array->find(item); - null_value=item->null_value || (!tmp && have_null); + int tmp=array->find(args[0]); + null_value=args[0]->null_value || (!tmp && have_null); return tmp; } - in_item->store_value(item); - if ((null_value=item->null_value)) + in_item->store_value(args[0]); + if ((null_value=args[0]->null_value)) return 0; have_null= 0; - for (uint i=0 ; i < arg_count ; i++) + for (uint i=1 ; i < arg_count ; i++) { if (!in_item->cmp(args[i]) && !args[i]->null_value) return 1; // Would maybe be nice with i ? @@ -1526,29 +1527,6 @@ longlong Item_func_in::val_int() } -void Item_func_in::update_used_tables() -{ - Item_func::update_used_tables(); - item->update_used_tables(); - used_tables_cache|=item->used_tables(); - const_item_cache&=item->const_item(); -} - -void Item_func_in::split_sum_func(Item **ref_pointer_array, List &fields) -{ - if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) - item->split_sum_func(ref_pointer_array, fields); - else if (item->used_tables() || item->type() == SUM_FUNC_ITEM) - { - uint el= fields.elements; - fields.push_front(item); - ref_pointer_array[el]= item; - item= new Item_ref(ref_pointer_array + el, 0, item->name); - } - Item_func::split_sum_func(ref_pointer_array, fields); -} - - longlong Item_func_bit_or::val_int() { ulonglong arg1= (ulonglong) args[0]->val_int(); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 8309cd25a72..9de222aafaf 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -600,42 +600,26 @@ public: class Item_func_in :public Item_int_func { - Item *item; in_vector *array; cmp_item *in_item; bool have_null; DTCollation cmp_collation; public: - Item_func_in(Item *a,List &list) - :Item_int_func(list), item(a), array(0), in_item(0), have_null(0) + Item_func_in(List &list) + :Item_int_func(list), array(0), in_item(0), have_null(0) { - allowed_arg_cols= item->cols(); + allowed_arg_cols= args[0]->cols(); } longlong val_int(); - bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) - { - // We do not check item->cols(), because allowed_arg_cols assigned from it - bool res=(item->fix_fields(thd, tlist, &item) || - Item_func::fix_fields(thd, tlist, ref)); - with_sum_func= with_sum_func || item->with_sum_func; - return res; - } void fix_length_and_dec(); - ~Item_func_in() { delete item; delete array; delete in_item; } + ~Item_func_in() { delete array; delete in_item; } optimize_type select_optimize() const { return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; } - Item *key_item() const { return item; } + Item *key_item() const { return args[0]; } void print(String *str); enum Functype functype() const { return IN_FUNC; } const char *func_name() const { return " IN "; } - void update_used_tables(); - void split_sum_func(Item **ref_pointer_array, List &fields); bool nulls_in_row(); - void set_outer_resolving() - { - item->set_outer_resolving(); - Item_int_func::set_outer_resolving(); - } }; /* Functions used by where clause */ diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7eb66c4e30f..18c465ffde3 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -832,10 +832,10 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) Field *field=((Item_field*) (func->key_item()))->field; Item_result cmp_type=field->cmp_type(); tree= get_mm_parts(param,field,Item_func::EQ_FUNC, - func->arguments()[0],cmp_type); + func->arguments()[1],cmp_type); if (!tree) DBUG_RETURN(tree); // Not key field - for (uint i=1 ; i < func->argument_count(); i++) + for (uint i=2 ; i < func->argument_count(); i++) { SEL_TREE *new_tree=get_mm_parts(param,field,Item_func::EQ_FUNC, func->arguments()[i],cmp_type); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 45a647cd8ab..0bb20b74016 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2109,9 +2109,9 @@ all_or_any: ALL { $$ = 1; } /* expressions that begin with 'expr' */ expr_expr: expr IN_SYM '(' expr_list ')' - { $$= new Item_func_in($1,*$4); } + { $4->push_front($1); $$= new Item_func_in(*$4); } | expr NOT IN_SYM '(' expr_list ')' - { $$= new Item_func_not(new Item_func_in($1,*$5)); } + { $5->push_front($1); $$= new Item_func_not(new Item_func_in(*$5)); } | expr IN_SYM in_subselect { $$= new Item_in_subselect(YYTHD, $1, $3); } | expr NOT IN_SYM in_subselect @@ -2211,9 +2211,9 @@ no_in_expr: /* expressions that begin with 'expr' that does NOT follow AND */ no_and_expr: no_and_expr IN_SYM '(' expr_list ')' - { $$= new Item_func_in($1,*$4); } + { $4->push_front($1); $$= new Item_func_in(*$4); } | no_and_expr NOT IN_SYM '(' expr_list ')' - { $$= new Item_func_not(new Item_func_in($1,*$5)); } + { $5->push_front($1); $$= new Item_func_not(new Item_func_in(*$5)); } | no_and_expr IN_SYM in_subselect { $$= new Item_in_subselect(YYTHD, $1, $3); } | no_and_expr NOT IN_SYM in_subselect