diff options
76 files changed, 3260 insertions, 1907 deletions
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index ad97d5b1442..d73b28863ba 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -4502,8 +4502,8 @@ stmt_fetch_row(MYSQL_STMT *stmt, uchar **row) MYSQL_BIND *bind, *end; uchar *null_ptr= (uchar*) *row, bit; - *row+= (stmt->field_count+7)/8; - bit=1; + row+= (stmt->field_count+9)/8; + bit= 4; /* First 2 bits are reserved */ /* Copy complete row to application buffers */ for (bind= stmt->bind, end= (MYSQL_BIND *) bind + stmt->field_count; diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index ea47126a4d5..daf65cb2f80 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -44,7 +44,7 @@ sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \ item_func.cc item_strfunc.cc item_sum.cc item_timefunc.cc \ item_uniq.cc item_subselect.cc item_row.cc\ key.cc lock.cc log.cc log_event.cc mf_iocache.cc\ - mini_client.cc net_pkg.cc net_serv.cc opt_ft.cc opt_range.cc \ + mini_client.cc protocol.cc net_serv.cc opt_ft.cc opt_range.cc \ opt_sum.cc procedure.cc records.cc sql_acl.cc \ repl_failsafe.cc slave.cc sql_load.cc sql_olap.cc \ sql_analyse.cc sql_base.cc sql_cache.cc sql_class.cc \ diff --git a/mysql-test/r/case.result b/mysql-test/r/case.result index ec37c9a5763..18241a8fcc1 100644 --- a/mysql-test/r/case.result +++ b/mysql-test/r/case.result @@ -10,10 +10,10 @@ CASE "c" when "a" then 1 when "b" then 2 ELSE 3 END 3 select CASE BINARY "b" when "a" then 1 when "B" then 2 WHEN "b" then "ok" END; CASE BINARY "b" when "a" then 1 when "B" then 2 WHEN "b" then "ok" END -ok +0 select CASE "b" when "a" then 1 when binary "B" then 2 WHEN "b" then "ok" END; CASE "b" when "a" then 1 when binary "B" then 2 WHEN "b" then "ok" END -ok +0 select CASE concat("a","b") when concat("ab","") then "a" when "b" then "b" end; CASE concat("a","b") when concat("ab","") then "a" when "b" then "b" end a diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result index 572b32c171c..db28038526b 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -24,10 +24,10 @@ cast("A" as binary) = "a" cast(BINARY "a" as CHAR) = "A" 0 1 select cast("2001-1-1" as DATE), cast("2001-1-1" as DATETIME); cast("2001-1-1" as DATE) cast("2001-1-1" as DATETIME) -2001-1-1 2001-1-1 +2001-01-01 2001-01-01 00:00:00 select cast("1:2:3" as TIME); cast("1:2:3" as TIME) -1:2:3 +01:02:03 select cast("2001-1-1" as date) = "2001-01-01"; cast("2001-1-1" as date) = "2001-01-01" 0 diff --git a/mysql-test/r/delayed.result b/mysql-test/r/delayed.result index 9e375203e49..8e4b52a8366 100644 --- a/mysql-test/r/delayed.result +++ b/mysql-test/r/delayed.result @@ -12,9 +12,9 @@ select * from t1 where tmsp=0; a tmsp select * from t1 where tmsp=19711006010203; a tmsp -5 19711006010203 -6 19711006010203 -8 19711006010203 +5 1971-10-06 01:02:03 +6 1971-10-06 01:02:03 +8 1971-10-06 01:02:03 drop table t1; create table t1 (a int not null auto_increment primary key, b char(10)); insert delayed into t1 values (1,"b"); diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index 94977b4f2f0..03e00b206b2 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -114,7 +114,7 @@ a t 20 20 explain select count(*) from t1 as tt1, (select * from t1) as tt2; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY Select tables optimized away +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away 2 DERIVED tt1 index NULL a 4 NULL 10000 Using index drop table if exists t1; SELECT * FROM (SELECT (SELECT * FROM (SELECT 1 as a) as a )) as b; diff --git a/mysql-test/r/explain.result b/mysql-test/r/explain.result index dafed9a7d41..2892c2ea587 100644 --- a/mysql-test/r/explain.result +++ b/mysql-test/r/explain.result @@ -27,4 +27,4 @@ Key column 'foo' doesn't exist in table drop table t1; explain select 1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE No tables used +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used diff --git a/mysql-test/r/func_date_add.result b/mysql-test/r/func_date_add.result index acdf2c5d7be..234fded9a68 100644 --- a/mysql-test/r/func_date_add.result +++ b/mysql-test/r/func_date_add.result @@ -31,17 +31,17 @@ INSERT INTO t1 VALUES (357917728,7,2,2,20000319145027); select visitor_id,max(ts) as mts from t1 group by visitor_id having mts < DATE_SUB(NOW(),INTERVAL 3 MONTH); visitor_id mts -48985536 20000319013932 -173865424 20000318233615 -357917728 20000319145027 -465931136 20000318160953 -1092858576 20000319013445 +48985536 2000-03-19 01:39:32 +173865424 2000-03-18 23:36:15 +357917728 2000-03-19 14:50:27 +465931136 2000-03-18 16:09:53 +1092858576 2000-03-19 01:34:45 select visitor_id,max(ts) as mts from t1 group by visitor_id having DATE_ADD(mts,INTERVAL 3 MONTH) < NOW(); visitor_id mts -48985536 20000319013932 -173865424 20000318233615 -357917728 20000319145027 -465931136 20000318160953 -1092858576 20000319013445 +48985536 2000-03-19 01:39:32 +173865424 2000-03-18 23:36:15 +357917728 2000-03-19 14:50:27 +465931136 2000-03-18 16:09:53 +1092858576 2000-03-19 01:34:45 drop table t1; diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index cee1d91d64d..d0358aad6ba 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -228,14 +228,14 @@ bugstatus int(10) unsigned default NULL, submitter int(10) unsigned default NULL ) TYPE=MyISAM; INSERT INTO t1 VALUES (1,'Link',1,1,1,'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','2001-02-28 08:40:16',20010228084016,0,4); -SELECT CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified,bugstatus,submitter), '"') FROM t1; -CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified,bugstatus,submitter), '"') +SELECT CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified+0,bugstatus,submitter), '"') FROM t1; +CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified+0,bugstatus,submitter), '"') "Link";"1";"1";"1";"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";"2001-02-28 08:40:16";"20010228084016";"0";"4" SELECT CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugstatus,submitter), '"') FROM t1; CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugstatus,submitter), '"') "Link";"1";"1";"1";"0";"4" -SELECT CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified,bugstatus,submitter) FROM t1; -CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified,bugstatus,submitter) +SELECT CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified+0,bugstatus,submitter) FROM t1; +CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified+0,bugstatus,submitter) Link";"1";"1";"1";"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";"2001-02-28 08:40:16";"20010228084016";"0";"4 drop table t1; CREATE TABLE t1 (id int(11) NOT NULL auto_increment, tmp text NOT NULL, KEY id (id)) TYPE=MyISAM; diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 2941352c776..d8491035f0b 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -392,11 +392,71 @@ CREATE TABLE t3 (ctime1 char(19) NOT NULL, ctime2 char(19) NOT NULL); INSERT INTO t3 VALUES ("2002-10-29 16:51:06","2002-11-05 16:47:31"); select * from t1, t2 where t1.start between t2.ctime1 and t2.ctime2; start ctime1 ctime2 -2002-11-04 00:00:00 20021029165106 20021105164731 +2002-11-04 00:00:00 2002-10-29 16:51:06 2002-11-05 16:47:31 select * from t1, t2 where t1.start >= t2.ctime1 and t1.start <= t2.ctime2; start ctime1 ctime2 -2002-11-04 00:00:00 20021029165106 20021105164731 +2002-11-04 00:00:00 2002-10-29 16:51:06 2002-11-05 16:47:31 select * from t1, t3 where t1.start between t3.ctime1 and t3.ctime2; start ctime1 ctime2 2002-11-04 00:00:00 2002-10-29 16:51:06 2002-11-05 16:47:31 drop table t1,t2,t3; +CREATE TABLE t1 (datetime datetime, timestamp timestamp, date date, time time); +INSERT INTO t1 values ("2001-01-02 03:04:05", "2002-01-02 03:04:05", "2003-01-02", "06:07:08"); +SELECT * from t1; +datetime timestamp date time +2001-01-02 03:04:05 2002-01-02 03:04:05 2003-01-02 06:07:08 +select date_add("1997-12-31",INTERVAL 1 SECOND); +date_add("1997-12-31",INTERVAL 1 SECOND) +1997-12-31 00:00:01 +select date_add("1997-12-31",INTERVAL "1 1" YEAR_MONTH); +date_add("1997-12-31",INTERVAL "1 1" YEAR_MONTH) +1999-01-31 +select date_add(datetime, INTERVAL 1 SECOND) from t1; +date_add(datetime, INTERVAL 1 SECOND) +2001-01-02 03:04:06 +select date_add(datetime, INTERVAL 1 YEAR) from t1; +date_add(datetime, INTERVAL 1 YEAR) +2002-01-02 03:04:05 +select date_add(date,INTERVAL 1 SECOND) from t1; +date_add(date,INTERVAL 1 SECOND) +2003-01-02 00:00:01 +select date_add(date,INTERVAL 1 MINUTE) from t1; +date_add(date,INTERVAL 1 MINUTE) +2003-01-02 00:01:00 +select date_add(date,INTERVAL 1 HOUR) from t1; +date_add(date,INTERVAL 1 HOUR) +2003-01-02 01:00:00 +select date_add(date,INTERVAL 1 DAY) from t1; +date_add(date,INTERVAL 1 DAY) +2003-01-03 +select date_add(date,INTERVAL 1 MONTH) from t1; +date_add(date,INTERVAL 1 MONTH) +2003-02-02 +select date_add(date,INTERVAL 1 YEAR) from t1; +date_add(date,INTERVAL 1 YEAR) +2004-01-02 +select date_add(date,INTERVAL "1:1" MINUTE_SECOND) from t1; +date_add(date,INTERVAL "1:1" MINUTE_SECOND) +2003-01-02 00:01:01 +select date_add(date,INTERVAL "1:1" HOUR_MINUTE) from t1; +date_add(date,INTERVAL "1:1" HOUR_MINUTE) +2003-01-02 01:01:00 +select date_add(date,INTERVAL "1:1" DAY_HOUR) from t1; +date_add(date,INTERVAL "1:1" DAY_HOUR) +2003-01-03 01:00:00 +select date_add(date,INTERVAL "1 1" YEAR_MONTH) from t1; +date_add(date,INTERVAL "1 1" YEAR_MONTH) +2004-02-02 +select date_add(date,INTERVAL "1:1:1" HOUR_SECOND) from t1; +date_add(date,INTERVAL "1:1:1" HOUR_SECOND) +2003-01-02 01:01:01 +select date_add(date,INTERVAL "1 1:1" DAY_MINUTE) from t1; +date_add(date,INTERVAL "1 1:1" DAY_MINUTE) +2003-01-03 01:01:00 +select date_add(date,INTERVAL "1 1:1:1" DAY_SECOND) from t1; +date_add(date,INTERVAL "1 1:1:1" DAY_SECOND) +2003-01-03 01:01:01 +select date_add(time,INTERVAL 1 SECOND) from t1; +date_add(time,INTERVAL 1 SECOND) +2006-07-08 00:00:01 +drop table t1; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 467436a2f85..82e678416ad 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -959,29 +959,29 @@ INSERT INTO t2 VALUES (650,'San Francisco',90,0,20020109113158,342,0000000000000 INSERT INTO t2 VALUES (333,'tubs',99,2,20020109113453,501,20020109113453,500,3,10,0); select * from t1; number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status -4077711111 SeanWheeler 90 2 20020111112846 500 00000000000000 -1 2 3 1 -9197722223 berry 90 3 20020111112809 500 20020102114532 501 4 10 0 -650 San Francisco 0 0 20011227111336 342 00000000000000 -1 1 24 1 -302467 Sue's Subshop 90 3 20020109113241 500 20020102115111 501 7 24 0 -6014911113 SudzCarwash 520 1 20020102115234 500 20020102115259 501 33 32768 0 -333 tubs 99 2 20020109113440 501 20020109113440 500 3 10 0 +4077711111 SeanWheeler 90 2 2002-01-11 11:28:46 500 0000-00-00 00:00:00 -1 2 3 1 +9197722223 berry 90 3 2002-01-11 11:28:09 500 2002-01-02 11:45:32 501 4 10 0 +650 San Francisco 0 0 2001-12-27 11:13:36 342 0000-00-00 00:00:00 -1 1 24 1 +302467 Sue's Subshop 90 3 2002-01-09 11:32:41 500 2002-01-02 11:51:11 501 7 24 0 +6014911113 SudzCarwash 520 1 2002-01-02 11:52:34 500 2002-01-02 11:52:59 501 33 32768 0 +333 tubs 99 2 2002-01-09 11:34:40 501 2002-01-09 11:34:40 500 3 10 0 select * from t2; number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status -4077711111 SeanWheeler 0 2 20020111112853 500 00000000000000 -1 2 3 1 -9197722223 berry 90 3 20020111112818 500 20020102114532 501 4 10 0 -650 San Francisco 90 0 20020109113158 342 00000000000000 -1 1 24 1 -333 tubs 99 2 20020109113453 501 20020109113453 500 3 10 0 +4077711111 SeanWheeler 0 2 2002-01-11 11:28:53 500 0000-00-00 00:00:00 -1 2 3 1 +9197722223 berry 90 3 2002-01-11 11:28:18 500 2002-01-02 11:45:32 501 4 10 0 +650 San Francisco 90 0 2002-01-09 11:31:58 342 0000-00-00 00:00:00 -1 1 24 1 +333 tubs 99 2 2002-01-09 11:34:53 501 2002-01-09 11:34:53 500 3 10 0 delete t1, t2 from t1 left join t2 on t1.number=t2.number where (t1.carrier_id=90 and t1.number=t2.number) or (t2.carrier_id=90 and t1.number=t2.number) or (t1.carrier_id=90 and t2.number is null); select * from t1; number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status -6014911113 SudzCarwash 520 1 20020102115234 500 20020102115259 501 33 32768 0 -333 tubs 99 2 20020109113440 501 20020109113440 500 3 10 0 +6014911113 SudzCarwash 520 1 2002-01-02 11:52:34 500 2002-01-02 11:52:59 501 33 32768 0 +333 tubs 99 2 2002-01-09 11:34:40 501 2002-01-09 11:34:40 500 3 10 0 select * from t2; number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status -333 tubs 99 2 20020109113453 501 20020109113453 500 3 10 0 +333 tubs 99 2 2002-01-09 11:34:53 501 2002-01-09 11:34:53 500 3 10 0 select * from t2; number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status -333 tubs 99 2 20020109113453 501 20020109113453 500 3 10 0 +333 tubs 99 2 2002-01-09 11:34:53 501 2002-01-09 11:34:53 500 3 10 0 drop table t1,t2; create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) type=innodb; BEGIN; diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index 700b73d3eca..b89a6696727 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -91,7 +91,7 @@ grp a c id a c d NULL NULL NULL NULL NULL NULL explain select t1.*,t2.* from t1,t2 where t1.a=t2.a and isnull(t2.a)=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE Impossible WHERE noticed after reading const tables +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables explain select t1.*,t2.* from t1 left join t2 on t1.a=t2.a where isnull(t2.a)=1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 7 diff --git a/mysql-test/r/key_primary.result b/mysql-test/r/key_primary.result index e148548b721..14ca90b3dd2 100644 --- a/mysql-test/r/key_primary.result +++ b/mysql-test/r/key_primary.result @@ -16,5 +16,5 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 const PRIMARY PRIMARY 3 const 1 describe select * from t1 where t1="ABCD"; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE Impossible WHERE noticed after reading const tables +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables drop table t1; diff --git a/mysql-test/r/keywords.result b/mysql-test/r/keywords.result index 2ca36425841..c218379110f 100644 --- a/mysql-test/r/keywords.result +++ b/mysql-test/r/keywords.result @@ -3,7 +3,7 @@ create table t1 (time time, date date, timestamp timestamp); insert into t1 values ("12:22:22","97:02:03","1997-01-02"); select * from t1; time date timestamp -12:22:22 1997-02-03 19970102000000 +12:22:22 1997-02-03 1997-01-02 00:00:00 select t1.time+0,t1.date+0,t1.timestamp+0,concat(date," ",time) from t1; t1.time+0 t1.date+0 t1.timestamp+0 concat(date," ",time) 122222 19970203 19970102000000 1997-02-03 12:22:22 diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index cd78ac791c4..d0e595d6551 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -560,7 +560,7 @@ select * from t6; a 1 2 -drop table if exists t1, t2, t3, t4, t5, t6; +drop table if exists t6, t3, t1, t2, t4, t5; DROP TABLE IF EXISTS t1, t2; CREATE TABLE t1 ( fileset_id tinyint(3) unsigned NOT NULL default '0', @@ -595,4 +595,4 @@ EXPLAIN SELECT * FROM t2 WHERE fileset_id = 2 AND file_code = '0000000115' LIMIT 1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 const PRIMARY,files PRIMARY 33 const,const 1 -DROP TABLE IF EXISTS t1, t2; +DROP TABLE IF EXISTS t2, t1; diff --git a/mysql-test/r/odbc.result b/mysql-test/r/odbc.result index 498147704a3..30366762cd0 100644 --- a/mysql-test/r/odbc.result +++ b/mysql-test/r/odbc.result @@ -12,5 +12,5 @@ select * from t1 where a is null; a b explain select * from t1 where b is null; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE Impossible WHERE noticed after reading const tables +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables drop table t1; diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index a3663416bc8..86a93398a9f 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -16,7 +16,7 @@ event_date type event_id 1999-07-14 100600 10 explain select event_date,type,event_id from t1 WHERE type = 100601 and event_date >= "1999-07-01" AND event_date < "1999-07-15" AND (type=100600 OR type=100100) ORDER BY event_date; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE Impossible WHERE +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE select event_date,type,event_id from t1 WHERE event_date >= "1999-07-01" AND event_date <= "1999-07-15" AND (type=100600 OR type=100100) or event_date >= "1999-07-01" AND event_date <= "1999-07-15" AND type=100099; event_date type event_id 1999-07-10 100100 24 diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 37943ec1189..80aa6046e8d 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3097,7 +3097,7 @@ fld1 sum(price) 038008 234298 explain select fld3 from t2 where 1>2 or 2>3; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE Impossible WHERE +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE explain select fld3 from t2 where fld1=fld1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 1199 @@ -3152,7 +3152,7 @@ count(*) 4181 explain select min(fld1),max(fld1),count(*) from t2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE Select tables optimized away +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away select min(fld1),max(fld1),count(*) from t2; min(fld1) max(fld1) count(*) 0 1232609 1199 diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 8f3914fe493..6073ebb933f 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -20,8 +20,8 @@ Reference 'a' not supported (forward reference in item list) EXPLAIN SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived2> system NULL NULL NULL NULL 1 -3 DEPENDENT SUBSELECT No tables used -2 DERIVED No tables used +3 DEPENDENT SUBSELECT NULL NULL NULL NULL NULL NULL NULL No tables used +2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; 1 1 @@ -280,7 +280,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL PRIMARY 41 NULL 2 Using where; Using index EXPLAIN SELECT (SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY No tables used +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used 2 SUBSELECT t1 index NULL PRIMARY 41 NULL 2 Using where; Using index SELECT DISTINCT date FROM t1 WHERE date='2002-08-03'; date @@ -298,8 +298,8 @@ Subselect returns more than 1 record EXPLAIN SELECT 1 FROM t1 WHERE 1=(SELECT 1 UNION SELECT 1); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 index NULL topic 3 NULL 2 Using index -2 SUBSELECT No tables used -3 UNION No tables used +2 SUBSELECT NULL NULL NULL NULL NULL NULL NULL No tables used +3 UNION NULL NULL NULL NULL NULL NULL NULL No tables used drop table t1; CREATE TABLE `t1` ( `numeropost` mediumint(8) unsigned NOT NULL auto_increment, @@ -394,11 +394,11 @@ EXPLAIN SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT 1 Subselect returns more than 1 record EXPLAIN SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE Select tables optimized away +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away EXPLAIN SELECT numreponse FROM t1 WHERE numeropost='1' AND numreponse=(SELECT MAX(numreponse) FROM t1 WHERE numeropost='1'); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 const PRIMARY,numreponse PRIMARY 7 const,const 1 -2 SUBSELECT Select tables optimized away +2 SUBSELECT NULL NULL NULL NULL NULL NULL NULL Select tables optimized away drop table t1; CREATE TABLE t1 (a int(1)); INSERT INTO t1 VALUES (1); @@ -574,14 +574,14 @@ id EXPLAIN SELECT * FROM t WHERE id IN (SELECT 1+(select 1)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t ref id id 5 const 1 Using where; Using index -3 SUBSELECT No tables used +3 SUBSELECT NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: Note 1247 Select 2 was reduced during optimisation EXPLAIN SELECT * FROM t WHERE id IN (SELECT 1 UNION SELECT 3); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t index NULL id 5 NULL 2 Using where; Using index -2 DEPENDENT SUBSELECT No tables used -3 UNION No tables used +2 DEPENDENT SUBSELECT NULL NULL NULL NULL NULL NULL NULL No tables used +3 UNION NULL NULL NULL NULL NULL NULL NULL No tables used SELECT * FROM t WHERE id IN (SELECT 5 UNION SELECT 3); id SELECT * FROM t WHERE id IN (SELECT 5 UNION SELECT 2); diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 1e58b8da42e..cac8cd3d71e 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -41,8 +41,8 @@ t drop table t1; CREATE TABLE t1 (a timestamp, b date, c time, d datetime); insert into t1 (b,c,d) values(now(),curtime(),now()); -select date_format(a,"%Y-%m-%d")=b,right(a,6)=c+0,a=d+0 from t1; -date_format(a,"%Y-%m-%d")=b right(a,6)=c+0 a=d+0 +select date_format(a,"%Y-%m-%d")=b,right(a+0,6)=c+0,a=d+0 from t1; +date_format(a,"%Y-%m-%d")=b right(a+0,6)=c+0 a=d+0 1 1 1 drop table t1; CREATE TABLE t1 (a datetime not null); diff --git a/mysql-test/r/type_ranges.result b/mysql-test/r/type_ranges.result index d0f964e4641..ea2863aefce 100644 --- a/mysql-test/r/type_ranges.result +++ b/mysql-test/r/type_ranges.result @@ -53,7 +53,7 @@ ushort smallint(5) unsigned zerofill MUL 00000 select,insert,update,references umedium mediumint(8) unsigned MUL 0 select,insert,update,references ulong int(11) unsigned MUL 0 select,insert,update,references ulonglong bigint(13) unsigned MUL 0 select,insert,update,references -time_stamp timestamp(14) YES NULL select,insert,update,references +time_stamp timestamp YES NULL select,insert,update,references date_field date YES NULL select,insert,update,references time_field time YES NULL select,insert,update,references date_time datetime YES NULL select,insert,update,references @@ -183,7 +183,7 @@ ushort smallint(5) unsigned zerofill 00000 select,insert,update,references umedium mediumint(8) unsigned MUL 0 select,insert,update,references ulong int(11) unsigned MUL 0 select,insert,update,references ulonglong bigint(13) unsigned MUL 0 select,insert,update,references -time_stamp timestamp(14) YES NULL select,insert,update,references +time_stamp timestamp YES NULL select,insert,update,references date_field varchar(10) character set latin1 YES NULL select,insert,update,references time_field time YES NULL select,insert,update,references date_time datetime YES NULL select,insert,update,references @@ -209,7 +209,7 @@ ushort smallint(5) unsigned zerofill 00000 select,insert,update,references umedium mediumint(8) unsigned 0 select,insert,update,references ulong int(11) unsigned 0 select,insert,update,references ulonglong bigint(13) unsigned 0 select,insert,update,references -time_stamp timestamp(14) YES NULL select,insert,update,references +time_stamp timestamp YES NULL select,insert,update,references date_field varchar(10) character set latin1 YES NULL select,insert,update,references time_field time YES NULL select,insert,update,references date_time datetime YES NULL select,insert,update,references diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index 088f3b205b9..26dedf544c4 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -15,26 +15,26 @@ SET TIMESTAMP=1238; insert into t1 (a) select a+1 from t2 where a=8; select * from t1; a t -1 19700101032034 -2 20020303000000 -3 19700101032035 -4 19700101032036 -5 20020304000000 -6 19700101032037 -7 20020305000000 -8 00000000000000 -9 19700101032038 +1 1970-01-01 03:20:34 +2 2002-03-03 00:00:00 +3 1970-01-01 03:20:35 +4 1970-01-01 03:20:36 +5 2002-03-04 00:00:00 +6 1970-01-01 03:20:37 +7 2002-03-05 00:00:00 +8 0000-00-00 00:00:00 +9 1970-01-01 03:20:38 drop table t1,t2; SET TIMESTAMP=1234; CREATE TABLE t1 (value TEXT NOT NULL, id VARCHAR(32) NOT NULL, stamp timestamp, PRIMARY KEY (id)); INSERT INTO t1 VALUES ("my value", "myKey","1999-04-02 00:00:00"); SELECT stamp FROM t1 WHERE id="myKey"; stamp -19990402000000 +1999-04-02 00:00:00 UPDATE t1 SET value="my value" WHERE id="myKey"; SELECT stamp FROM t1 WHERE id="myKey"; stamp -19990402000000 +1999-04-02 00:00:00 drop table t1; create table t1 (a timestamp); insert into t1 values (now()); @@ -44,8 +44,8 @@ date_format(a,"%Y %y") year(a) year(now()) drop table t1; create table t1 (ix timestamp); insert into t1 values (19991101000000),(19990102030405),(19990630232922),(19990601000000),(19990930232922),(19990531232922),(19990501000000),(19991101000000),(19990501000000); -select * from t1; -ix +select ix+0 from t1; +ix+0 19991101000000 19990102030405 19990630232922 @@ -71,16 +71,16 @@ INSERT INTO t1 VALUES ("2005-01-01","2005-01-01 00:00:00",20050101000000); INSERT INTO t1 VALUES ("2030-01-01","2030-01-01 00:00:00",20300101000000); SELECT * FROM t1; date date_time time_stamp -1998-12-31 1998-12-31 23:59:59 19981231235959 -1999-01-01 1999-01-01 00:00:00 19990101000000 -1999-09-09 1999-09-09 23:59:59 19990909235959 -2000-01-01 2000-01-01 00:00:00 20000101000000 -2000-02-28 2000-02-28 00:00:00 20000228000000 -2000-02-29 2000-02-29 00:00:00 20000229000000 -2000-03-01 2000-03-01 00:00:00 20000301000000 -2000-12-31 2000-12-31 23:59:59 20001231235959 -2001-01-01 2001-01-01 00:00:00 20010101000000 -2004-12-31 2004-12-31 23:59:59 20041231235959 -2005-01-01 2005-01-01 00:00:00 20050101000000 -2030-01-01 2030-01-01 00:00:00 20300101000000 +1998-12-31 1998-12-31 23:59:59 1998-12-31 23:59:59 +1999-01-01 1999-01-01 00:00:00 1999-01-01 00:00:00 +1999-09-09 1999-09-09 23:59:59 1999-09-09 23:59:59 +2000-01-01 2000-01-01 00:00:00 2000-01-01 00:00:00 +2000-02-28 2000-02-28 00:00:00 2000-02-28 00:00:00 +2000-02-29 2000-02-29 00:00:00 2000-02-29 00:00:00 +2000-03-01 2000-03-01 00:00:00 2000-03-01 00:00:00 +2000-12-31 2000-12-31 23:59:59 2000-12-31 23:59:59 +2001-01-01 2001-01-01 00:00:00 2001-01-01 00:00:00 +2004-12-31 2004-12-31 23:59:59 2004-12-31 23:59:59 +2005-01-01 2005-01-01 00:00:00 2005-01-01 00:00:00 +2030-01-01 2030-01-01 00:00:00 2030-01-01 00:00:00 drop table t1; diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 9f62ffe5c40..3930e5e25c1 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -102,16 +102,16 @@ Unknown column 'xx' in 'field list' explain select a,b from t1 union select 1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 4 -2 UNION No tables used +2 UNION NULL NULL NULL NULL NULL NULL NULL No tables used explain select 1 union select a,b from t1 union select 1; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY No tables used +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used 2 UNION t1 ALL NULL NULL NULL NULL 4 -3 UNION No tables used +3 UNION NULL NULL NULL NULL NULL NULL NULL No tables used explain select a,b from t1 union select 1 limit 0; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY Impossible WHERE -2 UNION Impossible WHERE +1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE +2 UNION NULL NULL NULL NULL NULL NULL NULL Impossible WHERE select a,b from t1 into outfile 'skr' union select a,b from t2; Wrong usage of UNION and INTO select a,b from t1 order by a union select a,b from t2; diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index bd92182b101..d355cc95317 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -115,9 +115,9 @@ CREATE TABLE t1 ( ) TYPE=MyISAM; INSERT INTO t1 VALUES (1,'Link',1,1,1,'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa','2001-02-28 08:40:16',20010228084016,0,4); -SELECT CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified,bugstatus,submitter), '"') FROM t1; +SELECT CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified+0,bugstatus,submitter), '"') FROM t1; SELECT CONCAT('"',CONCAT_WS('";"',title,prio,category,program,bugstatus,submitter), '"') FROM t1; -SELECT CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified,bugstatus,submitter) FROM t1; +SELECT CONCAT_WS('";"',title,prio,category,program,bugdesc,created,modified+0,bugstatus,submitter) FROM t1; drop table t1; # diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index dd589ff2e66..2e913bdf943 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -183,3 +183,34 @@ select * from t1, t2 where t1.start between t2.ctime1 and t2.ctime2; select * from t1, t2 where t1.start >= t2.ctime1 and t1.start <= t2.ctime2; select * from t1, t3 where t1.start between t3.ctime1 and t3.ctime2; drop table t1,t2,t3; + +# +# Test types from + INTERVAL +# + +CREATE TABLE t1 (datetime datetime, timestamp timestamp, date date, time time); +INSERT INTO t1 values ("2001-01-02 03:04:05", "2002-01-02 03:04:05", "2003-01-02", "06:07:08"); +SELECT * from t1; +select date_add("1997-12-31",INTERVAL 1 SECOND); +select date_add("1997-12-31",INTERVAL "1 1" YEAR_MONTH); + +select date_add(datetime, INTERVAL 1 SECOND) from t1; +select date_add(datetime, INTERVAL 1 YEAR) from t1; + +select date_add(date,INTERVAL 1 SECOND) from t1; +select date_add(date,INTERVAL 1 MINUTE) from t1; +select date_add(date,INTERVAL 1 HOUR) from t1; +select date_add(date,INTERVAL 1 DAY) from t1; +select date_add(date,INTERVAL 1 MONTH) from t1; +select date_add(date,INTERVAL 1 YEAR) from t1; +select date_add(date,INTERVAL "1:1" MINUTE_SECOND) from t1; +select date_add(date,INTERVAL "1:1" HOUR_MINUTE) from t1; +select date_add(date,INTERVAL "1:1" DAY_HOUR) from t1; +select date_add(date,INTERVAL "1 1" YEAR_MONTH) from t1; +select date_add(date,INTERVAL "1:1:1" HOUR_SECOND) from t1; +select date_add(date,INTERVAL "1 1:1" DAY_MINUTE) from t1; +select date_add(date,INTERVAL "1 1:1:1" DAY_SECOND) from t1; + +# The following is not as one would expect... +select date_add(time,INTERVAL 1 SECOND) from t1; +drop table t1; diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index 2199f50fb16..39c33ef8684 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -202,7 +202,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 t1, t2, t3, t4, t5, t6; +drop table if exists t6, t3, t1, t2, t4, t5; # # testing merge::records_in_range and optimizer @@ -235,5 +235,5 @@ EXPLAIN SELECT * FROM t1 WHERE fileset_id = 2 AND file_code BETWEEN '0000000115' AND '0000000120' LIMIT 1; EXPLAIN SELECT * FROM t2 WHERE fileset_id = 2 AND file_code = '0000000115' LIMIT 1; -DROP TABLE IF EXISTS t1, t2; +DROP TABLE IF EXISTS t2, t1; diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index a516bc89f99..991f11e86ea 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -19,7 +19,7 @@ drop table t1; CREATE TABLE t1 (a timestamp, b date, c time, d datetime); insert into t1 (b,c,d) values(now(),curtime(),now()); -select date_format(a,"%Y-%m-%d")=b,right(a,6)=c+0,a=d+0 from t1; +select date_format(a,"%Y-%m-%d")=b,right(a+0,6)=c+0,a=d+0 from t1; drop table t1; # diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index 2929184df93..c51d439fde4 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -35,7 +35,7 @@ drop table t1; create table t1 (ix timestamp); insert into t1 values (19991101000000),(19990102030405),(19990630232922),(19990601000000),(19990930232922),(19990531232922),(19990501000000),(19991101000000),(19990501000000); -select * from t1; +select ix+0 from t1; drop table t1; CREATE TABLE t1 (date date, date_time datetime, time_stamp timestamp); diff --git a/sql/Makefile.am b/sql/Makefile.am index c5af51e8397..245e4c5d258 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -64,7 +64,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ thr_malloc.cc item_create.cc item_subselect.cc \ item_row.cc \ field.cc key.cc sql_class.cc sql_list.cc \ - net_serv.cc net_pkg.cc lock.cc my_lock.c \ + net_serv.cc protocol.cc lock.cc my_lock.c \ sql_string.cc sql_manager.cc sql_map.cc \ mysqld.cc password.c hash_filo.cc hostname.cc \ convert.cc set_var.cc sql_parse.cc sql_yacc.yy \ diff --git a/sql/field.cc b/sql/field.cc index 3cb51757b4e..e3db572eb57 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -196,17 +196,12 @@ void Field::copy_from_tmp(int row_offset) } -bool Field::send(THD *thd, String *packet) +bool Field::send_binary(Protocol *protocol) { - if (is_null()) - return net_store_null(packet); char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),default_charset_info); val_str(&tmp,&tmp); - CONVERT *convert; - if ((convert=thd->variables.convert_set)) - return convert->store(packet,tmp.ptr(),tmp.length()); - return net_store_data(packet,tmp.ptr(),tmp.length()); + return protocol->store(tmp.ptr(), tmp.length()); } @@ -1074,6 +1069,10 @@ String *Field_tiny::val_str(String *val_buffer, return val_buffer; } +bool Field_tiny::send_binary(Protocol *protocol) +{ + return protocol->store_tiny((longlong) (int8) ptr[0]); +} int Field_tiny::cmp(const char *a_ptr, const char *b_ptr) { @@ -1285,6 +1284,7 @@ longlong Field_short::val_int(void) return unsigned_flag ? (longlong) (unsigned short) j : (longlong) j; } + String *Field_short::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { @@ -1312,6 +1312,12 @@ String *Field_short::val_str(String *val_buffer, } +bool Field_short::send_binary(Protocol *protocol) +{ + return protocol->store_short(Field_short::val_int()); +} + + int Field_short::cmp(const char *a_ptr, const char *b_ptr) { short a,b; @@ -1538,6 +1544,12 @@ String *Field_medium::val_str(String *val_buffer, } +bool Field_medium::send_binary(Protocol *protocol) +{ + return protocol->store_long(Field_medium::val_int()); +} + + int Field_medium::cmp(const char *a_ptr, const char *b_ptr) { long a,b; @@ -1774,6 +1786,11 @@ String *Field_long::val_str(String *val_buffer, } +bool Field_long::send_binary(Protocol *protocol) +{ + return protocol->store_long(Field_long::val_int()); +} + int Field_long::cmp(const char *a_ptr, const char *b_ptr) { int32 a,b; @@ -1988,6 +2005,12 @@ String *Field_longlong::val_str(String *val_buffer, } +bool Field_longlong::send_binary(Protocol *protocol) +{ + return protocol->store_longlong(Field_longlong::val_int(), unsigned_flag); +} + + int Field_longlong::cmp(const char *a_ptr, const char *b_ptr) { longlong a,b; @@ -2302,6 +2325,12 @@ void Field_float::sort_string(char *to,uint length __attribute__((unused))) } +bool Field_float::send_binary(Protocol *protocol) +{ + return protocol->store((float) Field_float::val_real(), dec, (String*) 0); +} + + void Field_float::sql_type(String &res) const { if (dec == NOT_FIXED_DEC) @@ -2499,6 +2528,11 @@ String *Field_double::val_str(String *val_buffer, return val_buffer; } +bool Field_double::send_binary(Protocol *protocol) +{ + return protocol->store((float) Field_double::val_real(), dec, (String*) 0); +} + int Field_double::cmp(const char *a_ptr, const char *b_ptr) { @@ -2568,10 +2602,10 @@ void Field_double::sql_type(String &res) const Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, enum utype unireg_check_arg, const char *field_name_arg, - struct st_table *table_arg) - :Field_num(ptr_arg, len_arg, (uchar*) 0,0, - unireg_check_arg, field_name_arg, table_arg, - 0, 1, 1) + struct st_table *table_arg, + CHARSET_INFO *cs) + :Field_str(ptr_arg, 19, (uchar*) 0,0, + unireg_check_arg, field_name_arg, table_arg, cs) { if (table && !table->timestamp_field) { @@ -2596,35 +2630,6 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) return 0; } -void Field_timestamp::fill_and_store(char *from,uint len) -{ - uint res_length; - if (len <= field_length) - res_length=field_length; - else if (len <= 12) - res_length=12; /* purecov: inspected */ - else if (len <= 14) - res_length=14; /* purecov: inspected */ - else - res_length=(len+1)/2*2; // must be even - if (res_length != len) - { - bmove_upp(from+res_length,from+len,len); - bfill(from,res_length-len,'0'); - len=res_length; - } - long tmp=(long) str_to_timestamp(from,len); -#ifdef WORDS_BIGENDIAN - if (table->db_low_byte_first) - { - int4store(ptr,tmp); - } - else -#endif - longstore(ptr,tmp); -} - - int Field_timestamp::store(double nr) { int error= 0; @@ -2735,44 +2740,34 @@ longlong Field_timestamp::val_int(void) time_arg=(time_t) temp; localtime_r(&time_arg,&tm_tmp); l_time=&tm_tmp; - res=(longlong) 0; - for (pos=len=0; len+1 < (uint) field_length ; len+=2,pos++) - { - bool year_flag=0; - switch (dayord.pos[pos]) { - case 0: part_time=l_time->tm_year % 100; year_flag=1 ; break; - case 1: part_time=l_time->tm_mon+1; break; - case 2: part_time=l_time->tm_mday; break; - case 3: part_time=l_time->tm_hour; break; - case 4: part_time=l_time->tm_min; break; - case 5: part_time=l_time->tm_sec; break; - default: part_time=0; break; /* purecov: deadcode */ - } - if (year_flag && (field_length == 8 || field_length == 14)) - { - res=res*(longlong) 10000+(part_time+ - ((part_time < YY_PART_YEAR) ? 2000 : 1900)); - len+=2; - } - else - res=res*(longlong) 100+part_time; - } - return (longlong) res; + + part_time= l_time->tm_year % 100; + res= ((longlong) (part_time+ ((part_time < YY_PART_YEAR) ? 2000 : 1900))* + LL(10000000000)); + part_time= l_time->tm_mon+1; + res+= (longlong) part_time * LL(100000000); + part_time=l_time->tm_mday; + res+= (longlong) ((long) part_time * 1000000L); + part_time=l_time->tm_hour; + res+= (longlong) (part_time * 10000L); + part_time=l_time->tm_min; + res+= (longlong) (part_time * 100); + part_time=l_time->tm_sec; + return res+part_time; } String *Field_timestamp::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { - uint pos; - int part_time; - uint32 temp; + uint32 temp, temp2; time_t time_arg; struct tm *l_time; struct tm tm_tmp; val_buffer->alloc(field_length+1); char *to=(char*) val_buffer->ptr(),*end=to+field_length; + val_buffer->length(field_length); #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -2783,44 +2778,57 @@ String *Field_timestamp::val_str(String *val_buffer, if (temp == 0L) { /* Zero time is "000000" */ - VOID(strfill(to,field_length,'0')); - val_buffer->length(field_length); + strmov(to, "0000-00-00 00:00:00"); return val_buffer; } time_arg=(time_t) temp; localtime_r(&time_arg,&tm_tmp); l_time=&tm_tmp; - for (pos=0; to < end ; pos++) - { - bool year_flag=0; - switch (dayord.pos[pos]) { - case 0: part_time=l_time->tm_year % 100; year_flag=1; break; - case 1: part_time=l_time->tm_mon+1; break; - case 2: part_time=l_time->tm_mday; break; - case 3: part_time=l_time->tm_hour; break; - case 4: part_time=l_time->tm_min; break; - case 5: part_time=l_time->tm_sec; break; - default: part_time=0; break; /* purecov: deadcode */ - } - if (year_flag && (field_length == 8 || field_length == 14)) - { - if (part_time < YY_PART_YEAR) - { - *to++='2'; *to++='0'; /* purecov: inspected */ - } - else - { - *to++='1'; *to++='9'; - } - } - *to++=(char) ('0'+((uint) part_time/10)); - *to++=(char) ('0'+((uint) part_time % 10)); - } - *to=0; // Safeguard - val_buffer->length((uint) (to-val_buffer->ptr())); + + temp= l_time->tm_year % 100; + if (temp < YY_PART_YEAR) + { + *to++= '2'; + *to++= '0'; + } + else + { + *to++= '1'; + *to++= '9'; + } + temp2=temp/10; temp=temp-temp2*10; + *to++= (char) ('0'+(char) (temp2)); + *to++= (char) ('0'+(char) (temp)); + *to++= '-'; + temp=l_time->tm_mon+1; + temp2=temp/10; temp=temp-temp2*10; + *to++= (char) ('0'+(char) (temp2)); + *to++= (char) ('0'+(char) (temp)); + *to++= '-'; + temp=l_time->tm_mday; + temp2=temp/10; temp=temp-temp2*10; + *to++= (char) ('0'+(char) (temp2)); + *to++= (char) ('0'+(char) (temp)); + *to++= ' '; + temp=l_time->tm_hour; + temp2=temp/10; temp=temp-temp2*10; + *to++= (char) ('0'+(char) (temp2)); + *to++= (char) ('0'+(char) (temp)); + *to++= ':'; + temp=l_time->tm_min; + temp2=temp/10; temp=temp-temp2*10; + *to++= (char) ('0'+(char) (temp2)); + *to++= (char) ('0'+(char) (temp)); + *to++= ':'; + temp=l_time->tm_sec; + temp2=temp/10; temp=temp-temp2*10; + *to++= (char) ('0'+(char) (temp2)); + *to++= (char) ('0'+(char) (temp)); + *to= 0; return val_buffer; } + bool Field_timestamp::get_date(TIME *ltime, bool fuzzydate) { long temp; @@ -2860,6 +2868,15 @@ bool Field_timestamp::get_time(TIME *ltime) return Field_timestamp::get_date(ltime,0); } + +bool Field_timestamp::send_binary(Protocol *protocol) +{ + TIME tm; + Field_timestamp::get_date(&tm, 1); + return protocol->store(&tm); +} + + int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr) { int32 a,b; @@ -2878,6 +2895,7 @@ int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr) return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0; } + void Field_timestamp::sort_string(char *to,uint length __attribute__((unused))) { #ifdef WORDS_BIGENDIAN @@ -2901,10 +2919,7 @@ void Field_timestamp::sort_string(char *to,uint length __attribute__((unused))) void Field_timestamp::sql_type(String &res) const { - ulong length= my_sprintf((char*) res.ptr(), - ((char*) res.ptr(),"timestamp(%d)", - (int) field_length)); - res.length(length); + res.set("timestamp", 9, default_charset_info); } @@ -3068,6 +3083,17 @@ bool Field_time::get_time(TIME *ltime) return 0; } + +bool Field_time::send_binary(Protocol *protocol) +{ + TIME tm; + Field_time::get_time(&tm); + tm.day= tm.hour/3600; // Move hours to days + tm.hour-= tm.day*3600; + return protocol->store(&tm); +} + + int Field_time::cmp(const char *a_ptr, const char *b_ptr) { int32 a,b; @@ -3965,19 +3991,15 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) ThNormalize((uchar *) ptr+2, field_length, (uchar *) from, length); } #else - if (length <= field_length) - { - memcpy(ptr+2,from,length); - } - else + if (length > field_length) { length=field_length; - memcpy(ptr+2,from,field_length); current_thd->cuted_fields++; error= 1; } + memcpy(ptr+2,from,length); #endif /* USE_TIS620 */ - int2store(ptr,length); + int2store(ptr, length); return error; } @@ -4176,6 +4198,28 @@ uint Field_varstring::max_packed_col_length(uint max_length) return (max_length > 255 ? 2 : 1)+max_length; } +void Field_varstring::get_key_image(char *buff, uint length, imagetype type) +{ + length-= HA_KEY_BLOB_LENGTH; + uint f_length=uint2korr(ptr); + if (f_length > length) + f_length= length; + int2store(buff,length); + memcpy(buff+2,ptr+2,length); +#ifdef HAVE_purify + if (f_length < length) + bzero(buff+2+f_length, (length-f_length)); +#endif +} + +void Field_varstring::set_key_image(char *buff,uint length) +{ + length=uint2korr(buff); // Real length is here + (void) Field_varstring::store(buff+2, length, default_charset_info); +} + + + /**************************************************************************** ** blob type ** A blob is saved as a length and a pointer. The length is stored in the @@ -4443,7 +4487,6 @@ void Field_blob::get_key_image(char *buff,uint length, imagetype type) return; } - length-=HA_KEY_BLOB_LENGTH; if ((uint32) length > blob_length) { #ifdef HAVE_purify @@ -5258,7 +5301,7 @@ Field *make_field(char *ptr, uint32 field_length, f_is_dec(pack_flag) == 0); case FIELD_TYPE_TIMESTAMP: return new Field_timestamp(ptr,field_length, - unireg_check, field_name, table); + unireg_check, field_name, table, field_charset); case FIELD_TYPE_YEAR: return new Field_year(ptr,field_length,null_pos,null_bit, unireg_check, field_name, table); diff --git a/sql/field.h b/sql/field.h index c3f107ebb46..4c0af6e807b 100644 --- a/sql/field.h +++ b/sql/field.h @@ -27,10 +27,12 @@ #define NOT_FIXED_DEC 31 class Send_field; +class Protocol; struct st_cache_field; void field_conv(Field *to,Field *from); -class Field { +class Field +{ Field(const Item &); /* Prevent use of these */ void operator=(Field &); public: @@ -164,7 +166,7 @@ public: ptr-=row_offset; return tmp; } - bool send(THD *thd, String *packet); + bool send_binary(Protocol *protocol); virtual char *pack(char* to, const char *from, uint max_length=~(uint) 0) { uint32 length=pack_length(); @@ -268,11 +270,11 @@ public: void set_charset(CHARSET_INFO *charset) { field_charset=charset; } bool binary() const { return field_charset->state & MY_CS_BINSORT ? 1 : 0; } inline int cmp_image(char *buff,uint length) - { - if (binary()) - return memcmp(ptr,buff,length); - else - return my_strncasecmp(field_charset,ptr,buff,length); + { + if (binary()) + return memcmp(ptr,buff,length); + else + return my_strncasecmp(field_charset,ptr,buff,length); } friend class create_field; }; @@ -291,7 +293,7 @@ public: {} enum_field_types type() const { return FIELD_TYPE_DECIMAL;} enum ha_base_keytype key_type() const - { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } + { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } void reset(void); int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); @@ -329,6 +331,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 1; } @@ -358,6 +361,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 2; } @@ -387,6 +391,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 3; } @@ -420,6 +425,7 @@ public: void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; } double val_real(void); longlong val_int(void); + bool send_binary(Protocol *protocol); String *val_str(String*,String *); int cmp(const char *,const char*); void sort_string(char *buff,uint length); @@ -457,6 +463,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 8; } @@ -485,6 +492,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return sizeof(float); } @@ -517,6 +525,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return sizeof(double); } @@ -552,14 +561,15 @@ public: }; -class Field_timestamp :public Field_num { +class Field_timestamp :public Field_str { public: Field_timestamp(char *ptr_arg, uint32 len_arg, enum utype unireg_check_arg, const char *field_name_arg, - struct st_table *table_arg); - enum Item_result result_type () const { return field_length == 8 || field_length == 14 ? INT_RESULT : STRING_RESULT; } + struct st_table *table_arg, + CHARSET_INFO *cs); enum_field_types type() const { return FIELD_TYPE_TIMESTAMP;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } + enum Item_result cmp_type () const { return INT_RESULT; } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); int store(longlong nr); @@ -567,6 +577,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 4; } @@ -588,7 +599,6 @@ public: longget(tmp,ptr); return tmp; } - void fill_and_store(char *from,uint len); bool get_date(TIME *ltime,bool fuzzydate); bool get_time(TIME *ltime); }; @@ -610,6 +620,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); void sql_type(String &str) const; }; @@ -636,6 +647,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 4; } @@ -664,6 +676,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 3; } @@ -697,6 +710,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); bool get_time(TIME *ltime); int cmp(const char *,const char*); void sort_string(char *buff,uint length); @@ -732,6 +746,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return 8; } @@ -772,6 +787,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); void sql_type(String &str) const; @@ -812,8 +828,11 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); + void get_key_image(char *buff,uint length, imagetype type); + void set_key_image(char *buff,uint length); void sql_type(String &str) const; char *pack(char *to, const char *from, uint max_length=~(uint) 0); const char *unpack(char* to, const char *from); @@ -852,6 +871,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); int cmp(const char *a, uint32 a_length, const char *b, uint32 b_length); int cmp_offset(uint offset); @@ -957,6 +977,7 @@ public: double val_real(void); longlong val_int(void); String *val_str(String*,String *); + bool send_binary(Protocol *protocol); int cmp(const char *,const char*); void sort_string(char *buff,uint length); uint32 pack_length() const { return (uint32) packlength; } diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 8edb63b23d6..1b8a2d9b3f8 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -231,10 +231,9 @@ int berkeley_rollback(THD *thd, void *trans) } -int berkeley_show_logs(THD *thd) +int berkeley_show_logs(Protocol *protocol) { char **all_logs, **free_logs, **a, **f; - String *packet= &thd->packet; int error=1; MEM_ROOT show_logs_root; MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); @@ -243,8 +242,9 @@ int berkeley_show_logs(THD *thd) init_alloc_root(&show_logs_root, 1024, 1024); my_pthread_setspecific_ptr(THR_MALLOC,&show_logs_root); - if ((error= db_env->log_archive(db_env, &all_logs, DB_ARCH_ABS | DB_ARCH_LOG)) - || (error= db_env->log_archive(db_env, &free_logs, DB_ARCH_ABS))) + if ((error= db_env->log_archive(db_env, &all_logs, + DB_ARCH_ABS | DB_ARCH_LOG)) || + (error= db_env->log_archive(db_env, &free_logs, DB_ARCH_ABS))) { DBUG_PRINT("error", ("log_archive failed (error %d)", error)); db_env->err(db_env, error, "log_archive: DB_ARCH_ABS"); @@ -257,18 +257,18 @@ int berkeley_show_logs(THD *thd) { for (a = all_logs, f = free_logs; *a; ++a) { - packet->length(0); - net_store_data(packet,*a); - net_store_data(packet,"BDB"); + protocol->prepare_for_resend(); + protocol->store(*a); + protocol->store("BDB", 3); if (f && *f && strcmp(*a, *f) == 0) { - ++f; - net_store_data(packet, SHOW_LOG_STATUS_FREE); + f++; + protocol->store(SHOW_LOG_STATUS_FREE); } else - net_store_data(packet, SHOW_LOG_STATUS_INUSE); + protocol->store(SHOW_LOG_STATUS_INUSE); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + if (protocol->write()) { error=1; goto err; @@ -2065,8 +2065,7 @@ void ha_berkeley::print_error(int error, myf errflag) static void print_msg(THD *thd, const char *table_name, const char *op_name, const char *msg_type, const char *fmt, ...) { - String* packet = &thd->packet; - packet->length(0); + Protocol *protocol= thd->protocol; char msgbuf[256]; msgbuf[0] = 0; va_list args; @@ -2074,15 +2073,14 @@ static void print_msg(THD *thd, const char *table_name, const char *op_name, my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia - DBUG_PRINT(msg_type,("message: %s",msgbuf)); - net_store_data(packet, table_name); - net_store_data(packet, op_name); - net_store_data(packet, msg_type); - net_store_data(packet, msgbuf); - if (my_net_write(&thd->net, (char*)thd->packet.ptr(), - thd->packet.length())) + protocol->prepare_for_resend(); + protocol->store(table_name); + protocol->store(op_name); + protocol->store(msg_type); + protocol->store(msgbuf); + if (protocol->write()) thd->killed=1; } #endif diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index f2a81d123f1..dfdd12470d6 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -180,4 +180,4 @@ bool berkeley_end(void); bool berkeley_flush_logs(void); int berkeley_commit(THD *thd, void *trans); int berkeley_rollback(THD *thd, void *trans); -int berkeley_show_logs(THD *thd); +int berkeley_show_logs(Protocol *protocol); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 14810bada31..8f933085066 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -3922,9 +3922,8 @@ innodb_show_status( /*===============*/ THD* thd) /* in: the MySQL query thread of the caller */ { - String* packet = &thd->packet; char* buf; - + Protocol *protocol= thd->protocol; DBUG_ENTER("innodb_show_status"); if (innodb_skip) { @@ -3945,22 +3944,17 @@ innodb_show_status( field_list.push_back(new Item_empty_string("Status", strlen(buf))); - if(send_fields(thd, field_list, 1)) { + if (protocol->send_fields(&field_list, 1)) + { DBUG_RETURN(-1); } - packet->length(0); - - net_store_data(packet, buf); - - if (my_net_write(&thd->net, (char*)thd->packet.ptr(), - packet->length())) { - ut_free(buf); - - DBUG_RETURN(-1); - } - + protocol->prepare_for_resend(); + protocol->store(buf, strlen(buf)); ut_free(buf); + + if (protocol->write()) + DBUG_RETURN(-1); send_eof(thd); diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index ae71e362875..67fddf34d5c 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -50,14 +50,12 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type, const char *fmt, va_list args) { THD* thd = (THD*)param->thd; - String* packet = &thd->packet; - uint length; + Protocol *protocol= thd->protocol; + uint length, msg_length; char msgbuf[MI_MAX_MSG_BUF]; char name[NAME_LEN*2+2]; - packet->length(0); - msgbuf[0] = 0; // healthy paranoia ? - my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); + msg_length= my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args); msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia DBUG_PRINT(msg_type,("message: %s",msgbuf)); @@ -67,19 +65,20 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type, sql_print_error(msgbuf); return; } - if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR | T_AUTO_REPAIR)) + if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR | + T_AUTO_REPAIR)) { my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME)); return; } length=(uint) (strxmov(name, param->db_name,".",param->table_name,NullS) - name); - net_store_data(packet, name, length); - net_store_data(packet, param->op_name); - net_store_data(packet, msg_type); - - net_store_data(packet, msgbuf); - if (my_net_write(&thd->net, (char*)thd->packet.ptr(), thd->packet.length())) + protocol->prepare_for_resend(); + protocol->store(name, length); + protocol->store(param->op_name); + protocol->store(msg_type); + protocol->store(msgbuf, msg_length); + if (protocol->write()) sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n", msgbuf); return; diff --git a/sql/item.cc b/sql/item.cc index 4fbbfdd4772..d05578c800a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -22,6 +22,7 @@ #include "mysql_priv.h" #include <m_ctype.h> #include "my_dir.h" +#include <assert.h> /***************************************************************************** ** Item functions @@ -378,12 +379,6 @@ int Item_param::save_in_field(Field *field, bool no_conversions) } -void Item_param::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_STRING); -} - - double Item_param::val() { switch (item_result_type) { @@ -671,65 +666,24 @@ void Item::init_make_field(Send_field *tmp_field, tmp_field->flags |= UNSIGNED_FLAG; } -/* ARGSUSED */ -void Item_field::make_field(Send_field *tmp_field) -{ - field->make_field(tmp_field); - if (name) - tmp_field->col_name=name; // Use user supplied name -} - -void Item_int::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_LONGLONG); -} - -void Item_uint::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_LONGLONG); - tmp_field->flags|= UNSIGNED_FLAG; - unsigned_flag=1; -} - -void Item_real::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_DOUBLE); -} - -void Item_string::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_STRING); -} - -void Item_datetime::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_DATETIME); -} - - -void Item_null::make_field(Send_field *tmp_field) -{ - init_make_field(tmp_field,FIELD_TYPE_NULL); - tmp_field->length=4; -} - - -void Item_func::make_field(Send_field *tmp_field) +void Item::make_field(Send_field *tmp_field) { - init_make_field(tmp_field, ((result_type() == STRING_RESULT) ? - FIELD_TYPE_VAR_STRING : - (result_type() == INT_RESULT) ? - FIELD_TYPE_LONGLONG : FIELD_TYPE_DOUBLE)); + init_make_field(tmp_field, field_type()); } -void Item_avg_field::make_field(Send_field *tmp_field) +enum_field_types Item::field_type() const { - init_make_field(tmp_field,FIELD_TYPE_DOUBLE); + return ((result_type() == STRING_RESULT) ? FIELD_TYPE_VAR_STRING : + (result_type() == INT_RESULT) ? FIELD_TYPE_LONGLONG : + FIELD_TYPE_DOUBLE); } -void Item_variance_field::make_field(Send_field *tmp_field) +/* ARGSUSED */ +void Item_field::make_field(Send_field *tmp_field) { - init_make_field(tmp_field,FIELD_TYPE_DOUBLE); + field->make_field(tmp_field); + if (name) + tmp_field->col_name=name; // Use user supplied name } /* @@ -938,30 +892,118 @@ int Item_varbinary::save_in_field(Field *field, bool no_conversions) } -void Item_varbinary::make_field(Send_field *tmp_field) +/* + Pack data in buffer for sending +*/ + +bool Item_null::send(Protocol *protocol, String *packet) { - init_make_field(tmp_field,FIELD_TYPE_STRING); + return protocol->store_null(); } /* -** pack data in buffer for sending + This is only called from items that is not of type item_field */ -bool Item::send(THD *thd, String *packet) +bool Item::send(Protocol *protocol, String *buffer) { - char buff[MAX_FIELD_WIDTH]; - CONVERT *convert; - String s(buff,sizeof(buff),packet->charset()),*res; - if (!(res=val_str(&s))) - return net_store_null(packet); - if ((convert=thd->variables.convert_set)) - return convert->store(packet,res->ptr(),res->length()); - return net_store_data(packet,res->ptr(),res->length()); + bool result; + enum_field_types type; + LINT_INIT(result); + + switch ((type=field_type())) { + default: + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_GEOMETRY: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_VAR_STRING: + { + String *res; + if ((res=val_str(buffer))) + result= protocol->store(res->ptr(),res->length()); + break; + } + case MYSQL_TYPE_TINY: + { + longlong nr; + nr= val_int(); + if (!null_value) + result= protocol->store_tiny(nr); + break; + } + case MYSQL_TYPE_SHORT: + { + longlong nr; + nr= val_int(); + if (!null_value) + result= protocol->store_short(nr); + break; + } + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + { + longlong nr; + nr= val_int(); + if (!null_value) + result= protocol->store_long(nr); + break; + } + case MYSQL_TYPE_LONGLONG: + { + longlong nr; + nr= val_int(); + if (!null_value) + result= protocol->store_longlong(nr, unsigned_flag); + break; + } + case MYSQL_TYPE_DOUBLE: + { + double nr; + nr= val(); + if (!null_value) + result= protocol->store(nr, decimals, buffer); + break; + } + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_TIMESTAMP: + { + TIME tm; + get_date(&tm, 1); + if (!null_value) + { + if (type == MYSQL_TYPE_DATE) + return protocol->store_date(&tm); + else + result= protocol->store(&tm); + } + break; + } + case MYSQL_TYPE_TIME: + { + TIME tm; + get_time(&tm); + if (!null_value) + result= protocol->store_time(&tm); + break; + } + } + if (null_value) + result= protocol->store_null(); + return result; } -bool Item_null::send(THD *thd, String *packet) + +bool Item_field::send(Protocol *protocol, String *buffer) { - return net_store_null(packet); + return protocol->store(result_field); } /* diff --git a/sql/item.h b/sql/item.h index c4cf534e16c..ed1a5fdf6a1 100644 --- a/sql/item.h +++ b/sql/item.h @@ -19,6 +19,7 @@ #pragma interface /* gcc class implementation */ #endif +class Protocol; struct st_table_list; void item_init(void); /* Init item functions */ @@ -54,20 +55,21 @@ public: virtual ~Item() { name=0; } /*lint -e1509 */ void set_name(const char *str,uint length=0); void init_make_field(Send_field *tmp_field,enum enum_field_types type); + virtual void make_field(Send_field *field); virtual bool fix_fields(THD *, struct st_table_list *, Item **); virtual int save_in_field(Field *field, bool no_conversions); virtual void save_org_in_field(Field *field) { (void) save_in_field(field, 1); } virtual int save_safe_in_field(Field *field) { return save_in_field(field, 1); } - virtual bool send(THD *thd, String *str); + virtual bool send(Protocol *protocol, String *str); virtual bool eq(const Item *, bool binary_cmp) const; virtual Item_result result_type () const { return REAL_RESULT; } + virtual enum_field_types field_type() const; virtual enum Type type() const =0; virtual double val()=0; virtual longlong val_int()=0; virtual String *val_str(String*)=0; - virtual void make_field(Send_field *field)=0; virtual Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return 0; } virtual const char *full_name() const { return name ? name : "???"; } virtual double val_result() { return val(); } @@ -119,10 +121,10 @@ public: item (it assign '*ref' with field 'item' in derived classes) */ enum Type type() const { return item->type(); } + enum_field_types field_type() const { return item->field_type(); } double val() { return item->val(); } longlong val_int() { return item->val_int(); } String* val_str(String* s) { return item->val_str(s); } - void make_field(Send_field* f) { item->make_field(f); } bool check_cols(uint col) { return item->check_cols(col); } bool eq(const Item *item, bool binary_cmp) const { return item->eq(item, binary_cmp); } @@ -196,12 +198,9 @@ public: double val_result(); longlong val_int_result(); String *str_result(String* tmp); - bool send(THD *thd, String *str_arg) - { - return result_field->send(thd,str_arg); - } - void make_field(Send_field *field); + bool send(Protocol *protocol, String *str_arg); bool fix_fields(THD *, struct st_table_list *, Item **); + void make_field(Send_field *tmp_field); int save_in_field(Field *field,bool no_conversions); void save_org_in_field(Field *field); table_map used_tables() const; @@ -209,6 +208,10 @@ public: { return field->result_type(); } + enum_field_types field_type() + { + return field->type(); + } Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; } bool get_date(TIME *ltime,bool fuzzydate); bool get_time(TIME *ltime); @@ -226,12 +229,17 @@ public: double val(); longlong val_int(); String *val_str(String *str); - void make_field(Send_field *field); int save_in_field(Field *field, bool no_conversions); int save_safe_in_field(Field *field); - enum Item_result result_type () const - { return STRING_RESULT; } - bool send(THD *thd, String *str); + enum Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_NULL; } + bool fix_fields(THD *thd, struct st_table_list *list, Item **item) + { + bool res= Item::fix_fields(thd, list, item); + max_length=0; + return res; + } + bool send(Protocol *protocol, String *str); bool basic_const_item() const { return 1; } Item *new_item() { return new Item_null(name); } bool is_null() { return 1; } @@ -258,7 +266,6 @@ public: double val(); longlong val_int(); String *val_str(String*); - void make_field(Send_field *field); int save_in_field(Field *field, bool no_conversions); void set_null(); void set_int(longlong i); @@ -272,6 +279,7 @@ public: void (*setup_param_func)(Item_param *param, uchar **pos); enum Item_result result_type () const { return item_result_type; } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } Item *new_item() { return new Item_param(name); } }; @@ -292,11 +300,11 @@ public: (longlong) strtoull(str_arg,(char**) 0,10)) { max_length= (uint) strlen(str_arg); name=(char*) str_arg;} enum Type type() const { return INT_ITEM; } - virtual enum Item_result result_type () const { return INT_RESULT; } + enum Item_result result_type () const { return INT_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } longlong val_int() { return value; } double val() { return (double) value; } String *val_str(String*); - void make_field(Send_field *field); int save_in_field(Field *field, bool no_conversions); bool basic_const_item() const { return 1; } Item *new_item() { return new Item_int(name,value,max_length); } @@ -312,8 +320,13 @@ public: Item_uint(uint32 i) :Item_int((longlong) i, 10) {} double val() { return ulonglong2double(value); } String *val_str(String*); - void make_field(Send_field *field); Item *new_item() { return new Item_uint(name,max_length); } + bool fix_fields(THD *thd, struct st_table_list *list, Item **item) + { + bool res= Item::fix_fields(thd, list, item); + unsigned_flag= 1; + return res; + } void print(String *str); }; @@ -339,10 +352,10 @@ public: Item_real(double value_par) :value(value_par) {} int save_in_field(Field *field, bool no_conversions); enum Type type() const { return REAL_ITEM; } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } double val() { return value; } longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5));} String *val_str(String*); - void make_field(Send_field *field); bool basic_const_item() const { return 1; } Item *new_item() { return new Item_real(name,value,decimals,max_length); } }; @@ -387,8 +400,8 @@ public: } String *val_str(String*) { return (String*) &str_value; } int save_in_field(Field *field, bool no_conversions); - void make_field(Send_field *field); enum Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } bool basic_const_item() const { return 1; } bool eq(const Item *item, bool binary_cmp) const; Item *new_item() @@ -409,7 +422,6 @@ class Item_default :public Item public: Item_default() { name= (char*) "DEFAULT"; } enum Type type() const { return DEFAULT_ITEM; } - void make_field(Send_field *field) {} int save_in_field(Field *field, bool no_conversions) { field->set_default(); @@ -429,7 +441,7 @@ class Item_datetime :public Item_string public: Item_datetime(const char *item_name): Item_string(item_name,"",0,default_charset_info) { max_length=19;} - void make_field(Send_field *field); + enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } }; class Item_empty_string :public Item_string @@ -439,6 +451,20 @@ public: { name=(char*) header; max_length=length;} }; +class Item_return_int :public Item_int +{ + enum_field_types int_field_type; +public: + Item_return_int(const char *name, uint length, + enum_field_types field_type_arg) + :Item_int(name, 0, length), int_field_type(field_type_arg) + { + unsigned_flag=1; + } + enum_field_types field_type() const { return int_field_type; } +}; + + class Item_varbinary :public Item { public: @@ -449,8 +475,8 @@ public: longlong val_int(); String *val_str(String*) { return &str_value; } int save_in_field(Field *field, bool no_conversions); - void make_field(Send_field *field); enum Item_result result_type () const { return INT_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } }; @@ -505,13 +531,14 @@ public: { return (null_value=(*ref)->get_date(ltime,fuzzydate)); } - bool send(THD *thd, String *tmp) { return (*ref)->send(thd, tmp); } + bool send(Protocol *prot, String *tmp){ return (*ref)->send(prot, tmp); } void make_field(Send_field *field) { (*ref)->make_field(field); } bool fix_fields(THD *, struct st_table_list *, Item **); int save_in_field(Field *field, bool no_conversions) { return (*ref)->save_in_field(field, no_conversions); } void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } enum Item_result result_type () const { return (*ref)->result_type(); } + enum_field_types field_type() const { return (*ref)->field_type(); } table_map used_tables() const { return (*ref)->used_tables(); } bool check_loop(uint id); }; @@ -597,6 +624,7 @@ public: class Item_copy_string :public Item { + enum enum_field_types cached_field_type; public: Item *item; Item_copy_string(Item *i) :item(i) @@ -605,10 +633,12 @@ public: decimals=item->decimals; max_length=item->max_length; name=item->name; + cached_field_type= item->field_type(); } ~Item_copy_string() { delete item; } enum Type type() const { return COPY_STR_ITEM; } enum Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const { return cached_field_type; } double val() { return null_value ? 0.0 : my_strntod(str_value.charset(),str_value.ptr(),str_value.length(),NULL); } longlong val_int() diff --git a/sql/item_func.cc b/sql/item_func.cc index c84b554b522..c0b6a872831 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1945,8 +1945,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { - if (!thd) - thd=current_thd; // Should never happen + /* fix_fields will call Item_func_set_user_var::fix_length_and_dec */ if (Item_func::fix_fields(thd, tables, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) return 1; diff --git a/sql/item_func.h b/sql/item_func.h index 98e56af368c..36d6dcbe002 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -106,7 +106,6 @@ public: Item_func(List<Item> &list); ~Item_func() {} /* Nothing to do; Items are freed automaticly */ bool fix_fields(THD *,struct st_table_list *, Item **ref); - void make_field(Send_field *field); table_map used_tables() const; void update_used_tables(); bool eq(const Item *item, bool binary_cmp) const; @@ -909,7 +908,9 @@ class Item_func_set_user_var :public Item_func user_var_entry *entry; public: - Item_func_set_user_var(LEX_STRING a,Item *b): Item_func(b), name(a) {} + Item_func_set_user_var(LEX_STRING a,Item *b) + :Item_func(b), cached_result_type(INT_RESULT), name(a) + {} double val(); longlong val_int(); String *val_str(String *str); @@ -939,6 +940,11 @@ public: void fix_length_and_dec(); void print(String *str); enum Item_result result_type() const; + /* + We must always return variables as strings to guard against selects of type + select @t1:=1,@t1,@t:="hello",@t from foo where (@t1:= t2.b) + */ + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } const char *func_name() const { return "get_user_var"; } bool const_item() const { return const_var_flag; } table_map used_tables() const diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 7dd57ef228e..a8bbc433b7a 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -74,20 +74,6 @@ void Item_subselect::select_transformer(st_select_lex *select_lex) } -void Item_subselect::make_field (Send_field *tmp_field) -{ - if (null_value) - { - init_make_field(tmp_field,FIELD_TYPE_NULL); - tmp_field->length=4; - } else { - init_make_field(tmp_field, ((result_type() == STRING_RESULT) ? - FIELD_TYPE_VAR_STRING : - (result_type() == INT_RESULT) ? - FIELD_TYPE_LONGLONG : FIELD_TYPE_DOUBLE)); - } -} - bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { if (substitution) diff --git a/sql/item_subselect.h b/sql/item_subselect.h index adae0831c22..7e46af09e2a 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -76,7 +76,6 @@ public: void assigned(bool a) { value_assigned= a; } enum Type type() const; bool is_null() { return null_value; } - void make_field (Send_field *); bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); virtual void fix_length_and_dec(); table_map used_tables() const; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 7bed3541777..f54ab87b81d 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -47,28 +47,21 @@ void Item_sum::mark_as_sum_func() with_sum_func= 1; } + void Item_sum::make_field(Send_field *tmp_field) { if (args[0]->type() == Item::FIELD_ITEM && keep_field_type()) - ((Item_field*) args[0])->field->make_field(tmp_field); - else { - tmp_field->flags=0; - if (!maybe_null) - tmp_field->flags|= NOT_NULL_FLAG; - if (unsigned_flag) - tmp_field->flags |= UNSIGNED_FLAG; - tmp_field->length=max_length; - tmp_field->decimals=decimals; - tmp_field->type=(result_type() == INT_RESULT ? FIELD_TYPE_LONG : - result_type() == REAL_RESULT ? FIELD_TYPE_DOUBLE : - FIELD_TYPE_VAR_STRING); + ((Item_field*) args[0])->field->make_field(tmp_field); + tmp_field->db_name=(char*)""; + tmp_field->org_table_name=tmp_field->table_name=(char*)""; + tmp_field->org_col_name=tmp_field->col_name=name; } - tmp_field->db_name=(char*)""; - tmp_field->org_table_name=tmp_field->table_name=(char*)""; - tmp_field->org_col_name=tmp_field->col_name=name; + else + init_make_field(tmp_field, field_type()); } + void Item_sum::print(String *str) { str->append(func_name()); @@ -168,6 +161,10 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) null_value=1; fix_length_and_dec(); thd->allow_sum_func=1; // Allow group functions + if (item->type() == Item::FIELD_ITEM) + hybrid_field_type= ((Item_field*) item)->field->type(); + else + hybrid_field_type= Item::field_type(); fixed= 1; return 0; } diff --git a/sql/item_sum.h b/sql/item_sum.h index b5665c3cf8c..50375fbf77c 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -210,7 +210,7 @@ public: longlong val_int() { return (longlong) val(); } bool is_null() { (void) val_int(); return null_value; } String *val_str(String*); - void make_field(Send_field *field); + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } void fix_length_and_dec() {} }; @@ -247,7 +247,7 @@ public: longlong val_int() { return (longlong) val(); } String *val_str(String*); bool is_null() { (void) val_int(); return null_value; } - void make_field(Send_field *field); + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } void fix_length_and_dec() {} }; @@ -318,6 +318,7 @@ class Item_sum_hybrid :public Item_sum double sum; longlong sum_int; Item_result hybrid_type; + enum_field_types hybrid_field_type; int cmp_sign; table_map used_table_cache; @@ -344,6 +345,7 @@ class Item_sum_hybrid :public Item_sum void make_const() { used_table_cache=0; } bool keep_field_type(void) const { return 1; } enum Item_result result_type () const { return hybrid_type; } + enum enum_field_types field_type() const { return hybrid_field_type; } void update_field(int offset); void min_max_update_str_field(int offset); void min_max_update_real_field(int offset); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 7e2e8f7cfbd..7b58fbe8404 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -295,8 +295,8 @@ longlong Item_func_time_to_sec::val_int() /* -** Convert a string to a interval value -** To make code easy, allow interval objects without separators. + Convert a string to a interval value + To make code easy, allow interval objects without separators. */ static bool get_interval_value(Item *args,interval_type int_type, @@ -516,12 +516,14 @@ void Item_func_curtime::fix_length_and_dec() (int) start->tm_sec); } + String *Item_func_now::val_str(String *str) { str_value.set(buff,buff_length,thd_charset()); return &str_value; } + void Item_func_now::fix_length_and_dec() { struct tm tm_tmp,*start; @@ -540,13 +542,14 @@ void Item_func_now::fix_length_and_dec() (ulong) (((uint) start->tm_min)*100L+ (uint) start->tm_sec))); - buff_length= (uint) cs->snprintf(cs,buff, sizeof(buff),"%04d-%02d-%02d %02d:%02d:%02d", - ((int) (start->tm_year+1900)) % 10000, - (int) start->tm_mon+1, - (int) start->tm_mday, - (int) start->tm_hour, - (int) start->tm_min, - (int) start->tm_sec); + buff_length= (uint) cs->snprintf(cs,buff, sizeof(buff), + "%04d-%02d-%02d %02d:%02d:%02d", + ((int) (start->tm_year+1900)) % 10000, + (int) start->tm_mon+1, + (int) start->tm_mday, + (int) start->tm_hour, + (int) start->tm_min, + (int) start->tm_sec); /* For getdate */ ltime.year= start->tm_year+1900; ltime.month= start->tm_mon+1; @@ -995,7 +998,42 @@ bool Item_func_from_unixtime::get_date(TIME *ltime, return 0; } - /* Here arg[1] is a Item_interval object */ + +void Item_date_add_interval::fix_length_and_dec() +{ + enum_field_types arg0_field_type; + set_charset(thd_charset()); + maybe_null=1; + max_length=19*thd_charset()->mbmaxlen; + value.alloc(32); + + /* + The field type for the result of an Item_date function is defined as + follows: + + - If first arg is a MYSQL_TYPE_DATETIME result is MYSQL_TYPE_DATETIME + - If first arg is a MYSQL_TYPE_DATE and the interval type uses hours, + minutes or seconds then type is MYSQL_TYPE_DATETIME. + - Otherwise the result is MYSQL_TYPE_STRING + (This is because you can't know if the string contains a DATE, TIME or + DATETIME argument) + */ + 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_DATE) + { + if (int_type <= INTERVAL_MONTH || int_type == INTERVAL_YEAR_MONTH) + cached_field_type= arg0_field_type; + else + cached_field_type= MYSQL_TYPE_DATETIME; + } +} + + +/* Here arg[1] is a Item_interval object */ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) { diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 40397351c18..aa075e1a91d 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -316,6 +316,7 @@ public: Item_date() :Item_func() {} Item_date(Item *a) :Item_func(a) {} enum Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_DATE; } String *val_str(String *str); double val() { return (double) val_int(); } const char *func_name() const { return "date"; } @@ -326,10 +327,6 @@ public: max_length=10*thd_charset()->mbmaxlen; } int save_in_field(Field *to, bool no_conversions); - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_DATE); - } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg, thd_charset()); @@ -343,10 +340,7 @@ public: Item_date_func() :Item_str_func() {} Item_date_func(Item *a) :Item_str_func(a) {} Item_date_func(Item *a,Item *b) :Item_str_func(a,b) {} - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_DATETIME); - } + enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : new Field_datetime(maybe_null, name, @@ -364,15 +358,12 @@ public: Item_func_curtime() :Item_func() {} Item_func_curtime(Item *a) :Item_func(a) {} enum Item_result result_type () const { return STRING_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_TIME; } double val() { return (double) value; } longlong val_int() { return value; } String *val_str(String *str); const char *func_name() const { return "curtime"; } void fix_length_and_dec(); - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_TIME); - } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : @@ -452,7 +443,6 @@ class Item_func_from_unixtime :public Item_date_func decimals=0; max_length=19*thd_charset()->mbmaxlen; } -// enum Item_result result_type () const { return STRING_RESULT; } bool get_date(TIME *res,bool fuzzy_date); }; @@ -470,11 +460,8 @@ public: maybe_null=1; max_length=13*thd_charset()->mbmaxlen; } + enum_field_types field_type() const { return MYSQL_TYPE_TIME; } const char *func_name() const { return "sec_to_time"; } - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_TIME); - } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : @@ -482,32 +469,34 @@ public: } }; +/* + The following must be sorted so that simple intervals comes first. + (get_interval_value() depends on this) +*/ + +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 +}; -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}; class Item_date_add_interval :public Item_date_func { const interval_type int_type; String value; const bool date_sub_interval; + enum_field_types cached_field_type; public: Item_date_add_interval(Item *a,Item *b,interval_type type_arg,bool neg_arg) :Item_date_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {} String *val_str(String *); const char *func_name() const { return "date_add_interval"; } - void fix_length_and_dec() - { - set_charset(thd_charset()); - maybe_null=1; - max_length=19*thd_charset()->mbmaxlen; - value.alloc(32); - } + void fix_length_and_dec(); + enum_field_types field_type() const { return cached_field_type; } double val() { return (double) val_int(); } longlong val_int(); bool get_date(TIME *res,bool fuzzy_date); @@ -566,10 +555,7 @@ class Item_date_typecast :public Item_typecast public: Item_date_typecast(Item *a) :Item_typecast(a) {} const char *func_name() const { return "date"; } - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_DATE); - } + enum_field_types field_type() const { return MYSQL_TYPE_DATE; } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : @@ -583,10 +569,7 @@ class Item_time_typecast :public Item_typecast public: Item_time_typecast(Item *a) :Item_typecast(a) {} const char *func_name() const { return "time"; } - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_TIME); - } + enum_field_types field_type() const { return MYSQL_TYPE_TIME; } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : @@ -600,10 +583,7 @@ class Item_datetime_typecast :public Item_typecast public: Item_datetime_typecast(Item *a) :Item_typecast(a) {} const char *func_name() const { return "datetime"; } - void make_field(Send_field *tmp_field) - { - init_make_field(tmp_field,FIELD_TYPE_DATETIME); - } + enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : new Field_datetime(maybe_null, name, diff --git a/sql/log_event.cc b/sql/log_event.cc index 5050bba9965..1f4371d5919 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -306,9 +306,9 @@ int Log_event::exec_event(struct st_relay_log_info* rli) Log_event::pack_info() ****************************************************************************/ -void Log_event::pack_info(String* packet) +void Log_event::pack_info(Protocol *protocol) { - net_store_data(packet, "", 0); + protocol->store("",0); } /***************************************************************************** @@ -319,10 +319,13 @@ void Log_event::pack_info(String* packet) void Log_event::init_show_field_list(List<Item>* field_list) { field_list->push_back(new Item_empty_string("Log_name", 20)); - field_list->push_back(new Item_empty_string("Pos", 20)); + field_list->push_back(new Item_return_int("Pos", 11, + MYSQL_TYPE_LONGLONG)); field_list->push_back(new Item_empty_string("Event_type", 20)); - field_list->push_back(new Item_empty_string("Server_id", 20)); - field_list->push_back(new Item_empty_string("Orig_log_pos", 20)); + field_list->push_back(new Item_return_int("Server_id", 10, + MYSQL_TYPE_LONG)); + field_list->push_back(new Item_return_int("Orig_log_pos", 11, + MYSQL_TYPE_LONGLONG)); field_list->push_back(new Item_empty_string("Info", 20)); } @@ -333,23 +336,22 @@ void Log_event::init_show_field_list(List<Item>* field_list) Only called by SHOW BINLOG EVENTS ****************************************************************************/ -int Log_event::net_send(THD* thd_arg, const char* log_name, my_off_t pos) +int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos) { - String* packet = &thd_arg->packet; const char *p= strrchr(log_name, FN_LIBCHAR); const char *event_type; if (p) log_name = p + 1; - packet->length(0); - net_store_data(packet, log_name, strlen(log_name)); - net_store_data(packet, (longlong) pos); + protocol->prepare_for_resend(); + protocol->store(log_name); + protocol->store((ulonglong) pos); event_type = get_type_str(); - net_store_data(packet, event_type, strlen(event_type)); - net_store_data(packet, server_id); - net_store_data(packet, (longlong) log_pos); - pack_info(packet); - return my_net_write(&thd_arg->net, (char*) packet->ptr(), packet->length()); + protocol->store(event_type, strlen(event_type)); + protocol->store((uint32) server_id); + protocol->store((ulonglong) log_pos); + pack_info(protocol); + return protocol->write(); } #endif // !MYSQL_CLIENT @@ -671,7 +673,7 @@ void Log_event::set_log_pos(MYSQL_LOG* log) Query_log_event::pack_info() ****************************************************************************/ -void Query_log_event::pack_info(String* packet) +void Query_log_event::pack_info(Protocol *protocol) { char buf[256]; String tmp(buf, sizeof(buf), system_charset_info); @@ -685,7 +687,7 @@ void Query_log_event::pack_info(String* packet) if (query && q_len) tmp.append(query, q_len); - net_store_data(packet, (char*)tmp.ptr(), tmp.length()); + protocol->store((char*) tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -925,7 +927,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) ****************************************************************************/ #ifndef MYSQL_CLIENT -void Start_log_event::pack_info(String* packet) +void Start_log_event::pack_info(Protocol *protocol) { char buf1[256]; String tmp(buf1, sizeof(buf1), system_charset_info); @@ -936,7 +938,7 @@ void Start_log_event::pack_info(String* packet) tmp.append(server_version); tmp.append(", Binlog ver: "); tmp.append(llstr(binlog_version, buf)); - net_store_data(packet, tmp.ptr(), tmp.length()); + protocol->store(tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -1036,7 +1038,7 @@ int Start_log_event::exec_event(struct st_relay_log_info* rli) ****************************************************************************/ #ifndef MYSQL_CLIENT -void Load_log_event::pack_info(String* packet) +void Load_log_event::pack_info(Protocol *protocol) { char buf[256]; String tmp(buf, sizeof(buf), system_charset_info); @@ -1109,7 +1111,7 @@ void Load_log_event::pack_info(String* packet) tmp.append(')'); } - net_store_data(packet, tmp.ptr(), tmp.length()); + protocol->store(tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -1542,7 +1544,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) ****************************************************************************/ #ifndef MYSQL_CLIENT -void Rotate_log_event::pack_info(String* packet) +void Rotate_log_event::pack_info(Protocol *protocol) { char buf1[256], buf[22]; String tmp(buf1, sizeof(buf1), system_charset_info); @@ -1552,7 +1554,7 @@ void Rotate_log_event::pack_info(String* packet) tmp.append(llstr(pos,buf)); if (flags & LOG_EVENT_FORCED_ROTATE_F) tmp.append("; forced by master"); - net_store_data(packet, tmp.ptr(), tmp.length()); + protocol->store(tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -1680,7 +1682,7 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) ****************************************************************************/ #ifndef MYSQL_CLIENT -void Intvar_log_event::pack_info(String* packet) +void Intvar_log_event::pack_info(Protocol *protocol) { char buf1[256], buf[22]; String tmp(buf1, sizeof(buf1), system_charset_info); @@ -1688,7 +1690,7 @@ void Intvar_log_event::pack_info(String* packet) tmp.append(get_var_type_name()); tmp.append('='); tmp.append(llstr(val, buf)); - net_store_data(packet, tmp.ptr(), tmp.length()); + protocol->store(tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -1801,14 +1803,14 @@ int Intvar_log_event::exec_event(struct st_relay_log_info* rli) ****************************************************************************/ #ifndef MYSQL_CLIENT -void Rand_log_event::pack_info(String* packet) +void Rand_log_event::pack_info(Protocol *protocol) { char buf1[256], *pos; pos= strmov(buf1,"rand_seed1="); pos= int10_to_str((long) seed1, pos, 10); pos= strmov(pos, ",rand_seed2="); pos= int10_to_str((long) seed2, pos, 10); - net_store_data(packet, buf1, (uint) (pos-buf1)); + protocol->store(buf1, (uint) (pos-buf1)); } #endif // !MYSQL_CLIENT @@ -1888,7 +1890,7 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli) ****************************************************************************/ #ifndef MYSQL_CLIENT -void Slave_log_event::pack_info(String* packet) +void Slave_log_event::pack_info(Protocol *protocol) { char buf1[256], buf[22], *end; String tmp(buf1, sizeof(buf1), system_charset_info); @@ -1902,7 +1904,7 @@ void Slave_log_event::pack_info(String* packet) tmp.append(master_log); tmp.append(",pos="); tmp.append(llstr(master_pos,buf)); - net_store_data(packet, tmp.ptr(), tmp.length()); + protocol->store(tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -2236,7 +2238,7 @@ void Create_file_log_event::print(FILE* file, bool short_form, ****************************************************************************/ #ifndef MYSQL_CLIENT -void Create_file_log_event::pack_info(String* packet) +void Create_file_log_event::pack_info(Protocol *protocol) { char buf1[256],buf[22], *end; String tmp(buf1, sizeof(buf1), system_charset_info); @@ -2251,7 +2253,7 @@ void Create_file_log_event::pack_info(String* packet) tmp.append(";block_len="); end= int10_to_str((long) block_len, buf, 10); tmp.append(buf, (uint32) (end-buf)); - net_store_data(packet, (char*) tmp.ptr(), tmp.length()); + protocol->store((char*) tmp.ptr(), tmp.length()); } #endif // !MYSQL_CLIENT @@ -2395,14 +2397,14 @@ void Append_block_log_event::print(FILE* file, bool short_form, ****************************************************************************/ #ifndef MYSQL_CLIENT -void Append_block_log_event::pack_info(String* packet) +void Append_block_log_event::pack_info(Protocol *protocol) { char buf[256]; uint length; length= (uint) my_sprintf(buf, (buf, ";file_id=%u;block_len=%u", file_id, block_len)); - net_store_data(packet, buf, (int32) length); + protocol->store(buf, (int32) length); } #endif // !MYSQL_CLIENT @@ -2510,12 +2512,12 @@ void Delete_file_log_event::print(FILE* file, bool short_form, ****************************************************************************/ #ifndef MYSQL_CLIENT -void Delete_file_log_event::pack_info(String* packet) +void Delete_file_log_event::pack_info(Protocol *protocol) { char buf[64]; uint length; length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id)); - net_store_data(packet, buf, (int32) length); + protocol->store(buf, (int32) length); } #endif // !MYSQL_CLIENT @@ -2609,12 +2611,12 @@ void Execute_load_log_event::print(FILE* file, bool short_form, ****************************************************************************/ #ifndef MYSQL_CLIENT -void Execute_load_log_event::pack_info(String* packet) +void Execute_load_log_event::pack_info(Protocol *protocol) { char buf[64]; uint length; length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id)); - net_store_data(packet, buf, (int32) length); + protocol->store(buf, (int32) length); } #endif // !MYSQL_CLIENT diff --git a/sql/log_event.h b/sql/log_event.h index 20a134ab3cc..c4f93c7a9b6 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -267,8 +267,8 @@ public: static int read_log_event(IO_CACHE* file, String* packet, pthread_mutex_t* log_lock); void set_log_pos(MYSQL_LOG* log); - virtual void pack_info(String* packet); - int net_send(THD* thd, const char* log_name, my_off_t pos); + virtual void pack_info(Protocol *protocol); + int net_send(Protocol *protocol, const char* log_name, my_off_t pos); static void init_show_field_list(List<Item>* field_list); virtual int exec_event(struct st_relay_log_info* rli); virtual const char* get_db() @@ -355,7 +355,7 @@ public: Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, bool using_trans); const char* get_db() { return db; } - void pack_info(String* packet); + void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); #else void print(FILE* file, bool short_form = 0, char* last_db = 0); @@ -404,7 +404,7 @@ public: #ifndef MYSQL_CLIENT Slave_log_event(THD* thd_arg, struct st_relay_log_info* rli); - void pack_info(String* packet); + void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); #else void print(FILE* file, bool short_form = 0, char* last_db = 0); @@ -454,7 +454,7 @@ public: List<Item>& fields_arg, enum enum_duplicates handle_dup, bool using_trans); void set_fields(List<Item> &fields_arg); - void pack_info(String* packet); + void pack_info(Protocol* protocol); const char* get_db() { return db; } int exec_event(struct st_relay_log_info* rli) { @@ -507,7 +507,7 @@ public: created = (uint32) when; memcpy(server_version, ::server_version, ST_SERVER_VER_LEN); } - void pack_info(String* packet); + void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); #else void print(FILE* file, bool short_form = 0, char* last_db = 0); @@ -542,7 +542,7 @@ public: Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg) :Log_event(),val(val_arg),type(type_arg) {} - void pack_info(String* packet); + void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); #else void print(FILE* file, bool short_form = 0, char* last_db = 0); @@ -574,7 +574,7 @@ class Rand_log_event: public Log_event Rand_log_event(THD* thd_arg, ulonglong seed1_arg, ulonglong seed2_arg) :Log_event(thd_arg,0,0),seed1(seed1_arg),seed2(seed2_arg) {} - void pack_info(String* packet); + void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); #else void print(FILE* file, bool short_form = 0, char* last_db = 0); @@ -636,7 +636,7 @@ public: pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg : (uint) strlen(new_log_ident_arg)), alloced(0) {} - void pack_info(String* packet); + void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); #else void print(FILE* file, bool short_form = 0, char* last_db = 0); @@ -683,7 +683,7 @@ public: enum enum_duplicates handle_dup, char* block_arg, uint block_len_arg, bool using_trans); - void pack_info(String* packet); + void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); #else void print(FILE* file, bool short_form = 0, char* last_db = 0); @@ -734,7 +734,7 @@ public: Append_block_log_event(THD* thd, char* block_arg, uint block_len_arg, bool using_trans); int exec_event(struct st_relay_log_info* rli); - void pack_info(String* packet); + void pack_info(Protocol* protocol); #else void print(FILE* file, bool short_form = 0, char* last_db = 0); #endif @@ -759,7 +759,7 @@ public: #ifndef MYSQL_CLIENT Delete_file_log_event(THD* thd, bool using_trans); - void pack_info(String* packet); + void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); #else void print(FILE* file, bool short_form = 0, char* last_db = 0); @@ -785,7 +785,7 @@ public: #ifndef MYSQL_CLIENT Execute_load_log_event(THD* thd, bool using_trans); - void pack_info(String* packet); + void pack_info(Protocol* protocol); int exec_event(struct st_relay_log_info* rli); #else void print(FILE* file, bool short_form = 0, char* last_db = 0); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3c67dfe4a3d..cf0cefd76da 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -283,6 +283,7 @@ inline THD *_current_thd(void) #include "handler.h" #include "table.h" #include "field.h" /* Field definitions */ +#include "protocol.h" #include "sql_udf.h" #include "item.h" typedef compare_func_creator (*chooser_compare_func_creator)(bool invert); @@ -377,30 +378,6 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* table_list, HA_CHECK_OPT* check_opt); bool check_simple_select(); -/* net_pkg.c */ -void send_warning(THD *thd, uint sql_errno, const char *err=0); -void net_printf(THD *thd,uint sql_errno, ...); -void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, - const char *info=0); -void send_eof(THD *thd, bool no_flush=0); -void net_send_error(NET *net, uint sql_errno, const char *err); -char *net_store_length(char *packet,ulonglong length); -char *net_store_length(char *packet,uint length); -char *net_store_data(char *to,const char *from); -char *net_store_data(char *to,int32 from); -char *net_store_data(char *to,longlong from); - -bool net_store_null(String *packet); -bool net_store_data(String *packet,uint32 from); -bool net_store_data(String *packet,longlong from); -bool net_store_data(String *packet,const char *from); -bool net_store_data(String *packet,const char *from,uint length); -bool net_store_data(String *packet,struct tm *tmp); -bool net_store_data(String* packet, I_List<i_string>* str_list); -bool net_store_data(String *packet,CONVERT *convert, const char *from, - uint length); -bool net_store_data(String *packet, CONVERT *convert, const char *from); - SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length); int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields, List <Item> &all_fields, ORDER *order); @@ -594,7 +571,6 @@ int lock_tables(THD *thd,TABLE_LIST *tables); TABLE *open_temporary_table(THD *thd, const char *path, const char *db, const char *table_name, bool link_in_list); bool rm_temporary_table(enum db_type base, char *path); -bool send_fields(THD *thd,List<Item> &item,uint send_field_count); void free_io_cache(TABLE *entry); void intern_close_table(TABLE *entry); bool close_thread_table(THD *thd, TABLE **table_ptr); @@ -818,6 +794,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time); 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); int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(byte *,uint,char,char); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9de04ac3454..943af7b44be 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1536,7 +1536,7 @@ static void start_signal_handler(void) (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_attr_setprio(&thr_attr,INTERRUPT_PRIOR); - pthread_attr_setstacksize(&thr_attr,32768); + pthread_attr_setstacksize(&thr_attr, 129*1024); #endif (void) pthread_mutex_lock(&LOCK_thread_count); diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc deleted file mode 100644 index 1da625e776f..00000000000 --- a/sql/net_pkg.cc +++ /dev/null @@ -1,492 +0,0 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - - -#include "mysql_priv.h" -#include <stdarg.h> - - /* Send a error string to client */ - -void send_error(THD *thd, uint sql_errno, const char *err) -{ - uint length; - char buff[MYSQL_ERRMSG_SIZE+2]; - NET *net= &thd->net; - DBUG_ENTER("send_error"); - DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno, - err ? err : net->last_error[0] ? - net->last_error : "NULL")); - - query_cache_abort(net); - thd->query_error= 1; // needed to catch query errors during replication - if (!err) - { - if (sql_errno) - err=ER(sql_errno); - else - { - if ((err=net->last_error)[0]) - sql_errno=net->last_errno; - else - { - sql_errno=ER_UNKNOWN_ERROR; - err=ER(sql_errno); /* purecov: inspected */ - } - } - } - if (net->vio == 0) - { - if (thd->bootstrap) - { - /* In bootstrap it's ok to print on stderr */ - fprintf(stderr,"ERROR: %d %s\n",sql_errno,err); - } - DBUG_VOID_RETURN; - } - - if (net->return_errno) - { // new client code; Add errno before message - int2store(buff,sql_errno); - length= (uint) (strmake(buff+2,err,MYSQL_ERRMSG_SIZE-1) - buff); - err=buff; - } - else - { - length=(uint) strlen(err); - set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); - } - VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length)); - thd->fatal_error=0; // Error message is given - thd->net.report_error= 0; - DBUG_VOID_RETURN; -} - -/* - Send an error to the client when a connection is forced close - This is used by mysqld.cc, which doesn't have a THD -*/ - -void net_send_error(NET *net, uint sql_errno, const char *err) -{ - char buff[2]; - uint length; - DBUG_ENTER("send_net_error"); - - int2store(buff,sql_errno); - length=(uint) strlen(err); - set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); - net_write_command(net,(uchar) 255, buff, 2, err, length); - DBUG_VOID_RETURN; -} - - -/* - Send a warning to the end user - - SYNOPSIS - send_warning() - thd Thread handler - sql_errno Warning number (error message) - err Error string. If not set, use ER(sql_errno) - - DESCRIPTION - Register the warning so that the user can get it with mysql_warnings() - Send an ok (+ warning count) to the end user. -*/ - -void send_warning(THD *thd, uint sql_errno, const char *err) -{ - DBUG_ENTER("send_warning"); - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno, - err ? err : ER(sql_errno)); - send_ok(thd); - DBUG_VOID_RETURN; -} - - -/* - Write error package and flush to client - It's a little too low level, but I don't want to use another buffer for - this -*/ - -void -net_printf(THD *thd, uint errcode, ...) -{ - va_list args; - uint length,offset; - const char *format,*text_pos; - int head_length= NET_HEADER_SIZE; - NET *net= &thd->net; - DBUG_ENTER("net_printf"); - DBUG_PRINT("enter",("message: %u",errcode)); - - thd->query_error= 1; // needed to catch query errors during replication - query_cache_abort(net); // Safety - va_start(args,errcode); - /* - The following is needed to make net_printf() work with 0 argument for - errorcode and use the argument after that as the format string. This - is useful for rare errors that are not worth the hassle to put in - errmsg.sys, but at the same time, the message is not fixed text - */ - if (errcode) - format= ER(errcode); - else - { - format=va_arg(args,char*); - errcode= ER_UNKNOWN_ERROR; - } - offset= net->return_errno ? 2 : 0; - text_pos=(char*) net->buff+head_length+offset+1; - (void) vsprintf(my_const_cast(char*) (text_pos),format,args); - length=(uint) strlen((char*) text_pos); - if (length >= sizeof(net->last_error)) - length=sizeof(net->last_error)-1; /* purecov: inspected */ - va_end(args); - - if (net->vio == 0) - { - if (thd->bootstrap) - { - /* In bootstrap it's ok to print on stderr */ - fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos); - thd->fatal_error=1; - } - DBUG_VOID_RETURN; - } - - int3store(net->buff,length+1+offset); - net->buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); - net->buff[head_length]=(uchar) 255; // Error package - if (offset) - int2store(text_pos-2, errcode); - VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset)); - thd->fatal_error=0; // Error message is given - DBUG_VOID_RETURN; -} - - -/* - Return ok to the client. - - SYNOPSIS - send_ok() - thd Thread handler - affected_rows Number of rows changed by statement - id Auto_increment id for first row (if used) - message Message to send to the client (Used by mysql_status) - - DESCRIPTION - The ok packet has the following structure - - 0 Marker (1 byte) - affected_rows Stored in 1-9 bytes - id Stored in 1-9 bytes - server_status Copy of thd->server_status; Can be used by client - to check if we are inside an transaction - New in 4.0 protocol - warning_count Stored in 2 bytes; New in 4.1 protocol - message Stored as packed length (1-9 bytes) + message - Is not stored if no message - - If net->no_send_ok return without sending packet -*/ - -void -send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) -{ - NET *net= &thd->net; - if (net->no_send_ok || !net->vio) // hack for re-parsing queries - return; - - char buff[MYSQL_ERRMSG_SIZE+10],*pos; - DBUG_ENTER("send_ok"); - buff[0]=0; // No fields - pos=net_store_length(buff+1,(ulonglong) affected_rows); - pos=net_store_length(pos, (ulonglong) id); - if (thd->client_capabilities & CLIENT_PROTOCOL_41) - { - int2store(pos,thd->server_status); - pos+=2; - - /* We can only return up to 65535 warnings in two bytes */ - uint tmp= min(thd->total_warn_count, 65535); - int2store(pos, tmp); - pos+= 2; - } - else if (net->return_status) // For 4.0 protocol - { - int2store(pos,thd->server_status); - pos+=2; - } - if (message) - pos=net_store_data((char*) pos,message); - VOID(my_net_write(net,buff,(uint) (pos-buff))); - VOID(net_flush(net)); - DBUG_VOID_RETURN; -} - - -/* - Send eof (= end of result set) to the client - - SYNOPSIS - send_eof() - thd Thread handler - no_flush Set to 1 if there will be more data to the client, - like in send_fields(). - - DESCRIPTION - The eof packet has the following structure - - 254 Marker (1 byte) - warning_count Stored in 2 bytes; New in 4.1 protocol - status_flag Stored in 2 bytes; - For flags like SERVER_STATUS_MORE_RESULTS - - Note that the warning count will not be sent if 'no_flush' is set as - we don't want to report the warning count until all data is sent to the - client. -*/ - -void -send_eof(THD *thd, bool no_flush) -{ - static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ - NET *net= &thd->net; - DBUG_ENTER("send_eof"); - if (net->vio != 0) - { - if (!no_flush && (thd->client_capabilities & CLIENT_PROTOCOL_41)) - { - uchar buff[5]; - uint tmp= min(thd->total_warn_count, 65535); - buff[0]=254; - int2store(buff+1, tmp); - int2store(buff+3, 0); // No flags yet - VOID(my_net_write(net,(char*) buff,5)); - VOID(net_flush(net)); - } - else - { - VOID(my_net_write(net,eof_buff,1)); - if (!no_flush) - VOID(net_flush(net)); - } - } - DBUG_VOID_RETURN; -} - - -/**************************************************************************** -** Store a field length in logical packet -****************************************************************************/ - -char * -net_store_length(char *pkg, ulonglong length) -{ - uchar *packet=(uchar*) pkg; - if (length < LL(251)) - { - *packet=(uchar) length; - return (char*) packet+1; - } - /* 251 is reserved for NULL */ - if (length < LL(65536)) - { - *packet++=252; - int2store(packet,(uint) length); - return (char*) packet+2; - } - if (length < LL(16777216)) - { - *packet++=253; - int3store(packet,(ulong) length); - return (char*) packet+3; - } - *packet++=254; - int8store(packet,length); - return (char*) packet+9; -} - -char * -net_store_length(char *pkg, uint length) -{ - uchar *packet=(uchar*) pkg; - if (length < 251) - { - *packet=(uchar) length; - return (char*) packet+1; - } - *packet++=252; - int2store(packet,(uint) length); - return (char*) packet+2; -} - -/* The following will only be used for short strings < 65K */ -char * -net_store_data(char *to,const char *from) -{ - uint length=(uint) strlen(from); - to=net_store_length(to,length); - memcpy(to,from,length); - return to+length; -} - - -char * -net_store_data(char *to,int32 from) -{ - char buff[20]; - uint length=(uint) (int10_to_str(from,buff,10)-buff); - to=net_store_length(to,length); - memcpy(to,buff,length); - return to+length; -} - -char * -net_store_data(char *to,longlong from) -{ - char buff[22]; - uint length=(uint) (longlong10_to_str(from,buff,10)-buff); - to=net_store_length(to,length); - memcpy(to,buff,length); - return to+length; -} - - -bool net_store_null(String *packet) -{ - return packet->append((char) 251); -} - -bool -net_store_data(String *packet,const char *from,uint length) -{ - ulong packet_length=packet->length(); - if (packet_length+5+length > packet->alloced_length() && - packet->realloc(packet_length+5+length)) - return 1; - char *to=(char*) net_store_length((char*) packet->ptr()+packet_length, - (ulonglong) length); - memcpy(to,from,length); - packet->length((uint) (to+length-packet->ptr())); - return 0; -} - -/* The following is only used at short, null terminated data */ - -bool -net_store_data(String *packet,const char *from) -{ - uint length=(uint) strlen(from); - uint packet_length=packet->length(); - if (packet_length+5+length > packet->alloced_length() && - packet->realloc(packet_length+5+length)) - return 1; - char *to=(char*) net_store_length((char*) packet->ptr()+packet_length, - length); - memcpy(to,from,length); - packet->length((uint) (to+length-packet->ptr())); - return 0; -} - - -bool -net_store_data(String *packet,uint32 from) -{ - char buff[20]; - return net_store_data(packet,(char*) buff, - (uint) (int10_to_str(from,buff,10)-buff)); -} - -bool -net_store_data(String *packet, longlong from) -{ - char buff[22]; - return net_store_data(packet,(char*) buff, - (uint) (longlong10_to_str(from,buff,10)-buff)); -} - -bool -net_store_data(String *packet,struct tm *tmp) -{ - char buff[20]; - sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d", - ((int) (tmp->tm_year+1900)) % 10000, - (int) tmp->tm_mon+1, - (int) tmp->tm_mday, - (int) tmp->tm_hour, - (int) tmp->tm_min, - (int) tmp->tm_sec); - return net_store_data(packet,(char*) buff,19); -} - -bool net_store_data(String* packet, I_List<i_string>* str_list) -{ - char buf[256]; - String tmp(buf, sizeof(buf), default_charset_info); - tmp.length(0); - I_List_iterator<i_string> it(*str_list); - i_string* s; - - while ((s=it++)) - { - if (tmp.length()) - tmp.append(','); - tmp.append(s->ptr); - } - - return net_store_data(packet, (char*)tmp.ptr(), tmp.length()); -} - -/* -** translate and store data; These are mainly used by the SHOW functions -*/ - -bool -net_store_data(String *packet,CONVERT *convert, const char *from,uint length) -{ - if (convert) - return convert->store(packet, from, length); - return net_store_data(packet,from,length); -} - -bool -net_store_data(String *packet, CONVERT *convert, const char *from) -{ - uint length=(uint) strlen(from); - if (convert) - return convert->store(packet, from, length); - return net_store_data(packet,from,length); -} - -/* - Function called by my_net_init() to set some check variables -*/ - -extern "C" { -void my_net_local_init(NET *net) -{ - net->max_packet= (uint) global_system_variables.net_buffer_length; - net->read_timeout= (uint) global_system_variables.net_read_timeout; - net->write_timeout=(uint) global_system_variables.net_write_timeout; - net->retry_count= (uint) global_system_variables.net_retry_count; - net->max_packet_size= max(global_system_variables.net_buffer_length, - global_system_variables.max_allowed_packet); -} -} diff --git a/sql/opt_range.cc b/sql/opt_range.cc index d76737e8e31..bcea522cb6d 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1042,7 +1042,8 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, DBUG_RETURN(0); if (maybe_null) *str= (char) field->is_real_null(); // Set to 1 if null - field->get_key_image(str+maybe_null,key_part->part_length, key_part->image_type); + field->get_key_image(str+maybe_null,key_part->part_length, + key_part->image_type); if (!(tree=new SEL_ARG(field,str,str))) DBUG_RETURN(0); @@ -2284,9 +2285,11 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key, key_tree->min_flag : key_tree->min_flag | key_tree->max_flag; } - /* Ensure that some part of min_key and max_key are used. If not, - regard this as no lower/upper range */ - if((flag & GEOM_FLAG) == 0) + /* + Ensure that some part of min_key and max_key are used. If not, + regard this as no lower/upper range + */ + if ((flag & GEOM_FLAG) == 0) { if (tmp_min_key != param->min_key) flag&= ~NO_MIN_RANGE; @@ -2451,17 +2454,17 @@ int QUICK_SELECT::get_next() if (!(range=it++)) DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used - if(range->flag & GEOM_FLAG) + if (range->flag & GEOM_FLAG) { if ((result = file->index_read(record, - (byte*) (range->min_key + ((range->flag & GEOM_FLAG) > 0)), - range->min_length, - (ha_rkey_function)(range->flag ^ GEOM_FLAG)))) - + (byte*) (range->min_key +1), + range->min_length, + (ha_rkey_function)(range->flag ^ + GEOM_FLAG)))) { if (result != HA_ERR_KEY_NOT_FOUND) DBUG_RETURN(result); - range=0; // Not found, to next range + range=0; // Not found, to next range continue; } DBUG_RETURN(0); @@ -2478,13 +2481,14 @@ int QUICK_SELECT::get_next() continue; } if ((result = file->index_read(record, - (byte*) (range->min_key + ((range->flag & GEOM_FLAG) > 0)), - range->min_length, - (range->flag & NEAR_MIN) ? - HA_READ_AFTER_KEY: - (range->flag & EQ_RANGE) ? - HA_READ_KEY_EXACT : - HA_READ_KEY_OR_NEXT))) + (byte*) (range->min_key + + test(range->flag & GEOM_FLAG)), + range->min_length, + (range->flag & NEAR_MIN) ? + HA_READ_AFTER_KEY: + (range->flag & EQ_RANGE) ? + HA_READ_KEY_EXACT : + HA_READ_KEY_OR_NEXT))) { if (result != HA_ERR_KEY_NOT_FOUND) @@ -2502,8 +2506,11 @@ int QUICK_SELECT::get_next() } } - /* compare if found key is over max-value */ - /* Returns 0 if key <= range->max_key */ + +/* + Compare if found key is over max-value + Returns 0 if key <= range->max_key +*/ int QUICK_SELECT::cmp_next(QUICK_RANGE *range_arg) { diff --git a/sql/procedure.h b/sql/procedure.h index b72c5cb559f..bc1b6062e1d 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -55,7 +55,7 @@ public: decimals=dec; max_length=float_length(dec); } enum Item_result result_type () const { return REAL_RESULT; } - enum_field_types field_type() const { return FIELD_TYPE_DOUBLE; } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } void set(double nr) { value=nr; } void set(longlong nr) { value=(double) nr; } void set(const char *str,uint length,CHARSET_INFO *cs) @@ -73,7 +73,7 @@ public: Item_proc_int(const char *name_par) :Item_proc(name_par) { max_length=11; } enum Item_result result_type () const { return INT_RESULT; } - enum_field_types field_type() const { return FIELD_TYPE_LONG; } + enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } void set(double nr) { value=(longlong) nr; } void set(longlong nr) { value=nr; } void set(const char *str,uint length, CHARSET_INFO *cs) @@ -91,7 +91,7 @@ public: Item_proc_string(const char *name_par,uint length) :Item_proc(name_par) { this->max_length=length; } enum Item_result result_type () const { return STRING_RESULT; } - enum_field_types field_type() const { return FIELD_TYPE_STRING; } + enum_field_types field_type() const { return MYSQL_TYPE_STRING; } void set(double nr) { str_value.set(nr, 2, thd_charset()); } void set(longlong nr) { str_value.set(nr, thd_charset()); } void set(const char *str, uint length, CHARSET_INFO *cs) diff --git a/sql/protocol.cc b/sql/protocol.cc new file mode 100644 index 00000000000..88bfe6831c4 --- /dev/null +++ b/sql/protocol.cc @@ -0,0 +1,989 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Low level functions for storing data to be send to the MySQL client + The actual communction is handled by the net_xxx functions in net_serv.cc +*/ + +#ifdef __GNUC__ +#pragma implementation // gcc: Class implementation +#endif + +#include "mysql_priv.h" +#include <stdarg.h> +#include <assert.h> + + /* Send a error string to client */ + +void send_error(THD *thd, uint sql_errno, const char *err) +{ + uint length; + char buff[MYSQL_ERRMSG_SIZE+2]; + NET *net= &thd->net; + DBUG_ENTER("send_error"); + DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno, + err ? err : net->last_error[0] ? + net->last_error : "NULL")); + + query_cache_abort(net); + thd->query_error= 1; // needed to catch query errors during replication + if (!err) + { + if (sql_errno) + err=ER(sql_errno); + else + { + if ((err=net->last_error)[0]) + sql_errno=net->last_errno; + else + { + sql_errno=ER_UNKNOWN_ERROR; + err=ER(sql_errno); /* purecov: inspected */ + } + } + } + if (net->vio == 0) + { + if (thd->bootstrap) + { + /* In bootstrap it's ok to print on stderr */ + fprintf(stderr,"ERROR: %d %s\n",sql_errno,err); + } + DBUG_VOID_RETURN; + } + + if (net->return_errno) + { // new client code; Add errno before message + int2store(buff,sql_errno); + length= (uint) (strmake(buff+2,err,MYSQL_ERRMSG_SIZE-1) - buff); + err=buff; + } + else + { + length=(uint) strlen(err); + set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); + } + VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length)); + thd->fatal_error=0; // Error message is given + thd->net.report_error= 0; + DBUG_VOID_RETURN; +} + +/* + Send an error to the client when a connection is forced close + This is used by mysqld.cc, which doesn't have a THD +*/ + +void net_send_error(NET *net, uint sql_errno, const char *err) +{ + char buff[2]; + uint length; + DBUG_ENTER("send_net_error"); + + int2store(buff,sql_errno); + length=(uint) strlen(err); + set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); + net_write_command(net,(uchar) 255, buff, 2, err, length); + DBUG_VOID_RETURN; +} + + +/* + Send a warning to the end user + + SYNOPSIS + send_warning() + thd Thread handler + sql_errno Warning number (error message) + err Error string. If not set, use ER(sql_errno) + + DESCRIPTION + Register the warning so that the user can get it with mysql_warnings() + Send an ok (+ warning count) to the end user. +*/ + +void send_warning(THD *thd, uint sql_errno, const char *err) +{ + DBUG_ENTER("send_warning"); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno, + err ? err : ER(sql_errno)); + send_ok(thd); + DBUG_VOID_RETURN; +} + + +/* + Write error package and flush to client + It's a little too low level, but I don't want to use another buffer for + this +*/ + +void +net_printf(THD *thd, uint errcode, ...) +{ + va_list args; + uint length,offset; + const char *format,*text_pos; + int head_length= NET_HEADER_SIZE; + NET *net= &thd->net; + DBUG_ENTER("net_printf"); + DBUG_PRINT("enter",("message: %u",errcode)); + + thd->query_error= 1; // needed to catch query errors during replication + query_cache_abort(net); // Safety + va_start(args,errcode); + /* + The following is needed to make net_printf() work with 0 argument for + errorcode and use the argument after that as the format string. This + is useful for rare errors that are not worth the hassle to put in + errmsg.sys, but at the same time, the message is not fixed text + */ + if (errcode) + format= ER(errcode); + else + { + format=va_arg(args,char*); + errcode= ER_UNKNOWN_ERROR; + } + offset= net->return_errno ? 2 : 0; + text_pos=(char*) net->buff+head_length+offset+1; + (void) vsprintf(my_const_cast(char*) (text_pos),format,args); + length=(uint) strlen((char*) text_pos); + if (length >= sizeof(net->last_error)) + length=sizeof(net->last_error)-1; /* purecov: inspected */ + va_end(args); + + if (net->vio == 0) + { + if (thd->bootstrap) + { + /* In bootstrap it's ok to print on stderr */ + fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos); + thd->fatal_error=1; + } + DBUG_VOID_RETURN; + } + + int3store(net->buff,length+1+offset); + net->buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++); + net->buff[head_length]=(uchar) 255; // Error package + if (offset) + int2store(text_pos-2, errcode); + VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset)); + thd->fatal_error=0; // Error message is given + DBUG_VOID_RETURN; +} + + +/* + Return ok to the client. + + SYNOPSIS + send_ok() + thd Thread handler + affected_rows Number of rows changed by statement + id Auto_increment id for first row (if used) + message Message to send to the client (Used by mysql_status) + + DESCRIPTION + The ok packet has the following structure + + 0 Marker (1 byte) + affected_rows Stored in 1-9 bytes + id Stored in 1-9 bytes + server_status Copy of thd->server_status; Can be used by client + to check if we are inside an transaction + New in 4.0 protocol + warning_count Stored in 2 bytes; New in 4.1 protocol + message Stored as packed length (1-9 bytes) + message + Is not stored if no message + + If net->no_send_ok return without sending packet +*/ + +void +send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) +{ + NET *net= &thd->net; + if (net->no_send_ok || !net->vio) // hack for re-parsing queries + return; + + char buff[MYSQL_ERRMSG_SIZE+10],*pos; + DBUG_ENTER("send_ok"); + buff[0]=0; // No fields + pos=net_store_length(buff+1,(ulonglong) affected_rows); + pos=net_store_length(pos, (ulonglong) id); + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + int2store(pos,thd->server_status); + pos+=2; + + /* We can only return up to 65535 warnings in two bytes */ + uint tmp= min(thd->total_warn_count, 65535); + int2store(pos, tmp); + pos+= 2; + } + else if (net->return_status) // For 4.0 protocol + { + int2store(pos,thd->server_status); + pos+=2; + } + if (message) + pos=net_store_data((char*) pos, message, strlen(message)); + VOID(my_net_write(net,buff,(uint) (pos-buff))); + VOID(net_flush(net)); + DBUG_VOID_RETURN; +} + + +/* + Send eof (= end of result set) to the client + + SYNOPSIS + send_eof() + thd Thread handler + no_flush Set to 1 if there will be more data to the client, + like in send_fields(). + + DESCRIPTION + The eof packet has the following structure + + 254 Marker (1 byte) + warning_count Stored in 2 bytes; New in 4.1 protocol + status_flag Stored in 2 bytes; + For flags like SERVER_STATUS_MORE_RESULTS + + Note that the warning count will not be sent if 'no_flush' is set as + we don't want to report the warning count until all data is sent to the + client. +*/ + +void +send_eof(THD *thd, bool no_flush) +{ + static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ + NET *net= &thd->net; + DBUG_ENTER("send_eof"); + if (net->vio != 0) + { + if (!no_flush && (thd->client_capabilities & CLIENT_PROTOCOL_41)) + { + uchar buff[5]; + uint tmp= min(thd->total_warn_count, 65535); + buff[0]=254; + int2store(buff+1, tmp); + int2store(buff+3, 0); // No flags yet + VOID(my_net_write(net,(char*) buff,5)); + VOID(net_flush(net)); + } + else + { + VOID(my_net_write(net,eof_buff,1)); + if (!no_flush) + VOID(net_flush(net)); + } + } + DBUG_VOID_RETURN; +} + + +/**************************************************************************** + Store a field length in logical packet + + This is used to code the string length for normal protocol +****************************************************************************/ + +char * +net_store_length(char *pkg, ulonglong length) +{ + uchar *packet=(uchar*) pkg; + if (length < LL(251)) + { + *packet=(uchar) length; + return (char*) packet+1; + } + /* 251 is reserved for NULL */ + if (length < LL(65536)) + { + *packet++=252; + int2store(packet,(uint) length); + return (char*) packet+2; + } + if (length < LL(16777216)) + { + *packet++=253; + int3store(packet,(ulong) length); + return (char*) packet+3; + } + *packet++=254; + int8store(packet,length); + return (char*) packet+9; +} + + +/* + Faster net_store_length when we know length is a 32 bit integer +*/ + +char *net_store_length(char *pkg, uint length) +{ + uchar *packet=(uchar*) pkg; + if (length < 251) + { + *packet=(uchar) length; + return (char*) packet+1; + } + *packet++=252; + int2store(packet,(uint) length); + return (char*) packet+2; +} + + +/* + Used internally for storing strings in packet +*/ + +static bool net_store_data(String *packet, const char *from, uint length) +{ + ulong packet_length=packet->length(); + if (packet_length+5+length > packet->alloced_length() && + packet->realloc(packet_length+5+length)) + return 1; + char *to=(char*) net_store_length((char*) packet->ptr()+packet_length, + (ulonglong) length); + memcpy(to,from,length); + packet->length((uint) (to+length-packet->ptr())); + return 0; +} + +/**************************************************************************** + Functions used by the protocol functions (like send_ok) to store strings + and numbers in the header result packet. +****************************************************************************/ + +/* The following will only be used for short strings < 65K */ + +char *net_store_data(char *to,const char *from, uint length) +{ + to=net_store_length(to,length); + memcpy(to,from,length); + return to+length; +} + +char *net_store_data(char *to,int32 from) +{ + char buff[20]; + uint length=(uint) (int10_to_str(from,buff,10)-buff); + to=net_store_length(to,length); + memcpy(to,buff,length); + return to+length; +} + +char *net_store_data(char *to,longlong from) +{ + char buff[22]; + uint length=(uint) (longlong10_to_str(from,buff,10)-buff); + to=net_store_length(to,length); + memcpy(to,buff,length); + return to+length; +} + +/* + Function called by my_net_init() to set some check variables +*/ + +extern "C" { +void my_net_local_init(NET *net) +{ + net->max_packet= (uint) global_system_variables.net_buffer_length; + net->read_timeout= (uint) global_system_variables.net_read_timeout; + net->write_timeout=(uint) global_system_variables.net_write_timeout; + net->retry_count= (uint) global_system_variables.net_retry_count; + net->max_packet_size= max(global_system_variables.net_buffer_length, + global_system_variables.max_allowed_packet); +} +} + + +/***************************************************************************** + Default Protocol functions +*****************************************************************************/ + +void Protocol::init(THD *thd_arg) +{ + thd=thd_arg; + convert=thd->variables.convert_set; + packet= &thd->packet; +#ifndef DEBUG_OFF + field_types= 0; +#endif +} + +/* + Send name and type of result to client. + + SYNOPSIS + send_fields() + THD Thread data object + list List of items to send to client + convert object used to convertation to another character set + flag Bit mask with the following functions: + 1 send number of rows + 2 send default values + + DESCRIPTION + Sum fields has table name empty and field_name. + Uses send_fields_convert() and send_fields() depending on + if we have an active character set convert or not. + + RETURN VALUES + 0 ok + 1 Error (Note that in this case the error is not sent to the client) +*/ + +bool Protocol::send_fields(List<Item> *list, uint flag) +{ + List_iterator_fast<Item> it(*list); + Item *item; + char buff[80]; + String tmp((char*) buff,sizeof(buff),default_charset_info); + Protocol_simple prot(thd); + String *packet= prot.storage_packet(); + DBUG_ENTER("send_fields"); + + if (flag & 1) + { // Packet with number of elements + char *pos=net_store_length(buff, (uint) list->elements); + (void) my_net_write(&thd->net, buff,(uint) (pos-buff)); + } + +#ifndef DEBUG_OFF + field_types= (enum_field_types*) thd->alloc(sizeof(field_types) * + list->elements); + uint count= 0; +#endif + + while ((item=it++)) + { + char *pos; + Send_field field; + item->make_field(&field); + prot.prepare_for_resend(); + + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + if (prot.store(field.db_name, (uint) strlen(field.db_name)) || + prot.store(field.table_name, (uint) strlen(field.table_name)) || + prot.store(field.org_table_name, + (uint) strlen(field.org_table_name)) || + prot.store(field.col_name, (uint) strlen(field.col_name)) || + prot.store(field.org_col_name, (uint) strlen(field.org_col_name))) + goto err; + } + else + { + if (prot.store(field.table_name, (uint) strlen(field.table_name)) || + prot.store(field.col_name, (uint) strlen(field.col_name))) + goto err; + } + if (packet->realloc(packet->length()+10)) + goto err; + pos= (char*) packet->ptr()+packet->length(); + +#ifdef TO_BE_DELETED_IN_6 + if (!(thd->client_capabilities & CLIENT_LONG_FLAG)) + { + packet->length(packet->length()+9); + pos[0]=3; int3store(pos+1,field.length); + pos[4]=1; pos[5]=field.type; + pos[6]=2; pos[7]=(char) field.flags; pos[8]= (char) field.decimals; + } + else +#endif + { + packet->length(packet->length()+10); + pos[0]=3; int3store(pos+1,field.length); + pos[4]=1; pos[5]=field.type; + pos[6]=3; int2store(pos+7,field.flags); pos[9]= (char) field.decimals; + } + if (flag & 2) + item->send(&prot, &tmp); // Send default value + if (prot.write()) + break; /* purecov: inspected */ +#ifndef DEBUG_OFF + field_types[count++]= field.type; +#endif + } + + send_eof(thd); + DBUG_RETURN(prepare_for_send(list)); + +err: + send_error(thd,ER_OUT_OF_RESOURCES); /* purecov: inspected */ + DBUG_RETURN(1); /* purecov: inspected */ +} + + +bool Protocol::write() +{ + DBUG_ENTER("Protocol::write"); + DBUG_RETURN(my_net_write(&thd->net, packet->ptr(), packet->length())); +} + + +/* + Send \0 end terminated string + + SYNOPSIS + store() + from NullS or \0 terminated string + + NOTES + In most cases one should use store(from, length) instead of this function + + RETURN VALUES + 0 ok + 1 error +*/ + +bool Protocol::store(const char *from) +{ + if (!from) + return store_null(); + uint length= strlen(from); + return store(from, length); +} + + +/* + Send a set of strings as one long string with ',' in between +*/ + +bool Protocol::store(I_List<i_string>* str_list) +{ + char buf[256]; + String tmp(buf, sizeof(buf), default_charset_info); + uint32 len; + I_List_iterator<i_string> it(*str_list); + i_string* s; + + tmp.length(0); + while ((s=it++)) + { + tmp.append(s->ptr); + tmp.append(','); + } + if ((len= tmp.length())) + len--; // Remove last ',' + return store((char*) tmp.ptr(), len); +} + + +/**************************************************************************** + Functions to handle the simple (default) protocol where everything is + This protocol is the one that is used by default between the MySQL server + and client when you are not using prepared statements. + + All data are sent as 'packed-string-length' followed by 'string-data' + +****************************************************************************/ + +void Protocol_simple::prepare_for_resend() +{ + packet->length(0); +#ifndef DEBUG_OFF + field_pos= 0; +#endif +} + +bool Protocol_simple::store_null() +{ +#ifndef DEBUG_OFF + field_pos++; +#endif + char buff[1]; + buff[0]= 251; + return packet->append(buff, sizeof(buff), PACKET_BUFFET_EXTRA_ALLOC); +} + +bool Protocol_simple::store(const char *from, uint length) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_DECIMAL || + (field_types[field_pos] >= MYSQL_TYPE_ENUM && + field_types[field_pos] <= MYSQL_TYPE_GEOMETRY)); + field_pos++; +#endif + if (convert) + return convert->store(packet, from, length); + return net_store_data(packet, from, length); +} + + +bool Protocol_simple::store_tiny(longlong from) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || field_types[field_pos++] == MYSQL_TYPE_TINY); +#endif + char buff[20]; + return net_store_data(packet,(char*) buff, + (uint) (int10_to_str((int) from,buff, -10)-buff)); +} + +bool Protocol_simple::store_short(longlong from) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos++] == MYSQL_TYPE_SHORT); +#endif + char buff[20]; + return net_store_data(packet,(char*) buff, + (uint) (int10_to_str((int) from,buff, -10)-buff)); +} + +bool Protocol_simple::store_long(longlong from) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || field_types[field_pos++] == MYSQL_TYPE_LONG); +#endif + char buff[20]; + return net_store_data(packet,(char*) buff, + (uint) (int10_to_str((int) from,buff, -10)-buff)); +} + + +bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos++] == MYSQL_TYPE_LONGLONG); +#endif + char buff[22]; + return net_store_data(packet,(char*) buff, + (uint) (longlong10_to_str(from,buff, + unsigned_flag ? 10 : -10)- + buff)); +} + + +bool Protocol_simple::store(float from, uint32 decimals, String *buffer) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos++] == MYSQL_TYPE_FLOAT); +#endif + buffer->set((double) from, decimals, thd->thd_charset); + return net_store_data(packet,(char*) buffer->ptr(), buffer->length()); +} + +bool Protocol_simple::store(double from, uint32 decimals, String *buffer) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos++] == MYSQL_TYPE_DOUBLE); +#endif + buffer->set(from, decimals, thd->thd_charset); + return net_store_data(packet,(char*) buffer->ptr(), buffer->length()); +} + + +bool Protocol_simple::store(Field *field) +{ + if (field->is_null()) + return store_null(); +#ifndef DEBUG_OFF + field_pos++; +#endif + char buff[MAX_FIELD_WIDTH]; + String tmp(buff,sizeof(buff),default_charset_info); + field->val_str(&tmp,&tmp); + if (convert) + return convert->store(packet, tmp.ptr(), tmp.length()); + return net_store_data(packet, tmp.ptr(), tmp.length()); +} + + +bool Protocol_simple::store(TIME *tm) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_DATETIME || + field_types[field_pos] == MYSQL_TYPE_TIMESTAMP); + field_pos++; +#endif + char buff[40]; + uint length; + length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d", + (int) tm->year, + (int) tm->month, + (int) tm->day, + (int) tm->hour, + (int) tm->minute, + (int) tm->second)); + return net_store_data(packet, (char*) buff, length); +} + + +bool Protocol_simple::store_date(TIME *tm) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos++] == MYSQL_TYPE_DATE); +#endif + char buff[40]; + uint length; + length= my_sprintf(buff,(buff, "%04d-%02d-%02d", + (int) tm->year, + (int) tm->month, + (int) tm->day)); + return net_store_data(packet, (char*) buff, length); +} + + +bool Protocol_simple::store_time(TIME *tm) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos++] == MYSQL_TYPE_TIME); +#endif + char buff[40]; + uint length; + length= my_sprintf(buff,(buff, "%s%02ld:%02d:%02d", + tm->neg ? "-" : "", + (long) tm->day*3600L+(long) tm->hour, + (int) tm->minute, + (int) tm->second)); + return net_store_data(packet, (char*) buff, length); +} + + +/**************************************************************************** + Functions to handle the binary protocol used with prepared statements +****************************************************************************/ + +bool Protocol_prep::prepare_for_send(List<Item> *item_list) +{ + field_count=item_list->elements; + bit_fields= (field_count+3)/8; + if (packet->alloc(bit_fields)) + return 1; + /* prepare_for_resend will be called after this one */ + return 0; +} + + +void Protocol_prep::prepare_for_resend() +{ + packet->length(bit_fields); + bzero((char*) packet->ptr()+1, bit_fields-1); + packet[0]=1; // Marker for ok packet + field_pos=0; +} + + +bool Protocol_prep::store(const char *from,uint length) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_DECIMAL || + (field_types[field_pos] >= MYSQL_TYPE_ENUM && + field_types[field_pos] <= MYSQL_TYPE_GEOMETRY)); +#endif + field_pos++; + if (convert) + return convert->store(packet, from, length); + return net_store_data(packet, from, length); +} + + +bool Protocol_prep::store_null() +{ + uint offset=(field_pos+2)/8, bit= (1 << ((field_pos+2) & 7)); + /* Room for this as it's allocated in prepare_for_send */ + char *to= (char*) packet->ptr()+offset; + *to= (char) ((uchar) *to | (uchar) bit); + field_pos++; + return 0; +} + + +bool Protocol_prep::store_tiny(longlong from) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_TINY); +#endif + char buff[1]; + field_pos++; + buff[0]= (uchar) from; + return packet->append(buff, sizeof(buff), PACKET_BUFFET_EXTRA_ALLOC); +} + + +bool Protocol_prep::store_short(longlong from) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_SHORT); +#endif + field_pos++; + char *to= packet->prep_append(2, PACKET_BUFFET_EXTRA_ALLOC); + if (!to) + return 1; + int2store(to, (int) from); + return 0; +} + + +bool Protocol_prep::store_long(longlong from) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_LONG); +#endif + field_pos++; + char *to= packet->prep_append(4, PACKET_BUFFET_EXTRA_ALLOC); + if (!to) + return 1; + int4store(to, from); + return 0; +} + + +bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_LONGLONG); +#endif + field_pos++; + char *to= packet->prep_append(8, PACKET_BUFFET_EXTRA_ALLOC); + if (!to) + return 1; + int8store(to, from); + return 0; +} + + +bool Protocol_prep::store(float from, uint32 decimals, String *buffer) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_FLOAT); +#endif + field_pos++; + char *to= packet->prep_append(4, PACKET_BUFFET_EXTRA_ALLOC); + if (!to) + return 1; + float4store(to, from); + return 0; +} + + +bool Protocol_prep::store(double from, uint32 decimals, String *buffer) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_DOUBLE); +#endif + field_pos++; + char *to= packet->prep_append(8, PACKET_BUFFET_EXTRA_ALLOC); + if (!to) + return 1; + float8store(to, from); + return 0; +} + + +bool Protocol_prep::store(Field *field) +{ + /* + We should not count up field_pos here as send_binary() will call another + protocol function to do this for us + */ + if (field->is_null()) + return store_null(); + return field->send_binary(this); +} + + +bool Protocol_prep::store(TIME *tm) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_DATETIME || + field_types[field_pos] == MYSQL_TYPE_DATE || + field_types[field_pos] == MYSQL_TYPE_TIMESTAMP); +#endif + char buff[12],*pos; + uint length; + field_pos++; + pos= buff+1; + + int2store(pos, tm->year); + int2store(pos+2, tm->month); + int2store(pos+3, tm->day); + int2store(pos+4, tm->hour); + int2store(pos+5, tm->minute); + int2store(pos+6, tm->second); + int4store(pos+7, tm->second_part); + if (tm->second_part) + length=11; + else if (tm->hour || tm->minute || tm->second) + length=7; + else if (tm->year || tm->month || tm->day) + length=4; + else + length=0; + buff[0]=(char) length; // Length is stored first + return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC); +} + +bool Protocol_prep::store_date(TIME *tm) +{ + tm->hour= tm->minute= tm->second=0; + tm->second_part= 0; + return Protocol_prep::store(tm); +} + + +bool Protocol_prep::store_time(TIME *tm) +{ +#ifndef DEBUG_OFF + DBUG_ASSERT(field_types == 0 || + field_types[field_pos] == MYSQL_TYPE_TIME); +#endif + char buff[15],*pos; + uint length; + field_pos++; + pos= buff+1; + pos[0]= tm->neg ? 1 : 0; + int4store(pos+1, tm->day); + int2store(pos+5, tm->hour); + int2store(pos+7, tm->minute); + int2store(pos+9, tm->second); + int4store(pos+11, tm->second_part); + if (tm->second_part) + length=14; + else if (tm->hour || tm->minute || tm->second || tm->day) + length=10; + else + length=0; + buff[0]=(char) length; // Length is stored first + return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC); +} diff --git a/sql/protocol.h b/sql/protocol.h new file mode 100644 index 00000000000..b3ab0a2b31d --- /dev/null +++ b/sql/protocol.h @@ -0,0 +1,131 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifdef __GNUC__ +#pragma interface /* gcc class implementation */ +#endif + +#define PACKET_BUFFET_EXTRA_ALLOC 1024 + +class CONVERT; +class i_string; +class THD; + +class Protocol +{ +protected: + THD *thd; + String *packet; + uint field_pos; +#ifndef DEBUG_OFF + enum enum_field_types *field_types; +#endif + +public: + CONVERT *convert; + + Protocol() {} + Protocol(THD *thd) { init(thd); } + void init(THD* thd); + bool send_fields(List<Item> *list, uint flag); + bool store(I_List<i_string> *str_list); + bool store(const char *from); + String *storage_packet() { return packet; } + inline void free() { packet->free(); } + bool write(); + inline bool store(uint32 from) + { return store_long((longlong) from); } + inline bool store(longlong from) + { return store_longlong((longlong) from, 0); } + inline bool store(ulonglong from) + { return store_longlong((longlong) from, 1); } + + virtual bool prepare_for_send(List<Item> *item_list) { return 0;} + virtual void prepare_for_resend()=0; + + virtual bool store_null()=0; + virtual bool store_tiny(longlong from)=0; + virtual bool store_short(longlong from)=0; + virtual bool store_long(longlong from)=0; + virtual bool store_longlong(longlong from, bool unsigned_flag)=0; + virtual bool store(const char *from, uint length)=0; + virtual bool store(float from, uint32 decimals, String *buffer)=0; + virtual bool store(double from, uint32 decimals, String *buffer)=0; + virtual bool store(TIME *time)=0; + virtual bool store_date(TIME *time)=0; + virtual bool store_time(TIME *time)=0; + virtual bool store(Field *field)=0; +}; + + +/* Class used for the old (MySQL 4.0 protocol) */ + +class Protocol_simple :public Protocol +{ +public: + Protocol_simple() {} + Protocol_simple(THD *thd) :Protocol(thd) {} + virtual void prepare_for_resend(); + virtual bool store_null(); + virtual bool store_tiny(longlong from); + virtual bool store_short(longlong from); + virtual bool store_long(longlong from); + virtual bool store_longlong(longlong from, bool unsigned_flag); + virtual bool store(const char *from, uint length); + virtual bool store(TIME *time); + virtual bool store_date(TIME *time); + virtual bool store_time(TIME *time); + virtual bool store(float nr, uint32 decimals, String *buffer); + virtual bool store(double from, uint32 decimals, String *buffer); + virtual bool store(Field *field); +}; + + +class Protocol_prep :public Protocol +{ +private: + uint field_count, bit_fields; +public: + Protocol_prep() {} + Protocol_prep(THD *thd) :Protocol(thd) {} + virtual bool prepare_for_send(List<Item> *item_list); + virtual void prepare_for_resend(); + virtual bool store_null(); + virtual bool store_tiny(longlong from); + virtual bool store_short(longlong from); + virtual bool store_long(longlong from); + virtual bool store_longlong(longlong from, bool unsigned_flag); + virtual bool store(const char *from,uint length); + virtual bool store(TIME *time); + virtual bool store_date(TIME *time); + virtual bool store_time(TIME *time); + virtual bool store(float nr, uint32 decimals, String *buffer); + virtual bool store(double from, uint32 decimals, String *buffer); + virtual bool store(Field *field); +}; + + +void send_warning(THD *thd, uint sql_errno, const char *err=0); +void net_printf(THD *thd,uint sql_errno, ...); +void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, + const char *info=0); +void send_eof(THD *thd, bool no_flush=0); +void net_send_error(NET *net, uint sql_errno, const char *err); +char *net_store_length(char *packet,ulonglong length); +char *net_store_length(char *packet,uint length); +char *net_store_data(char *to,const char *from, uint length); +char *net_store_data(char *to,int32 from); +char *net_store_data(char *to,longlong from); diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 785a253b1ac..16b2eedd3b2 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -416,6 +416,7 @@ static Slave_log_event* find_slave_event(IO_CACHE* log, int show_new_master(THD* thd) { + Protocol *protocol= thd->protocol; DBUG_ENTER("show_new_master"); List<Item> field_list; char errmsg[SLAVE_ERRMSG_SIZE]; @@ -431,15 +432,15 @@ int show_new_master(THD* thd) } else { - String* packet = &thd->packet; field_list.push_back(new Item_empty_string("Log_name", 20)); - field_list.push_back(new Item_empty_string("Log_pos", 20)); - if (send_fields(thd, field_list, 1)) + field_list.push_back(new Item_return_int("Log_pos", 10, + MYSQL_TYPE_LONGLONG)); + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); - packet->length(0); - net_store_data(packet, lex_mi->log_file_name); - net_store_data(packet, (longlong)lex_mi->pos); - if (my_net_write(&thd->net, packet->ptr(), packet->length())) + protocol->prepare_for_resend(); + protocol->store(lex_mi->log_file_name); + protocol->store((ulonglong) lex_mi->pos); + if (protocol->write()) DBUG_RETURN(-1); send_eof(thd); DBUG_RETURN(0); @@ -580,21 +581,24 @@ int show_slave_hosts(THD* thd) { List<Item> field_list; NET* net = &thd->net; - String* packet = &thd->packet; + Protocol *protocol= thd->protocol; DBUG_ENTER("show_slave_hosts"); - field_list.push_back(new Item_empty_string("Server_id", 20)); + field_list.push_back(new Item_return_int("Server_id", 10, + MYSQL_TYPE_LONG)); field_list.push_back(new Item_empty_string("Host", 20)); if (opt_show_slave_auth_info) { field_list.push_back(new Item_empty_string("User",20)); field_list.push_back(new Item_empty_string("Password",20)); } - field_list.push_back(new Item_empty_string("Port",20)); - field_list.push_back(new Item_empty_string("Rpl_recovery_rank", 20)); - field_list.push_back(new Item_empty_string("Master_id", 20)); + field_list.push_back(new Item_return_int("Port", 7, MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Rpl_recovery_rank", 7, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Master_id", 10, + MYSQL_TYPE_LONG)); - if (send_fields(thd, field_list, 1)) + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); pthread_mutex_lock(&LOCK_slave_list); @@ -602,18 +606,18 @@ int show_slave_hosts(THD* thd) for (uint i = 0; i < slave_list.records; ++i) { SLAVE_INFO* si = (SLAVE_INFO*) hash_element(&slave_list, i); - packet->length(0); - net_store_data(packet, si->server_id); - net_store_data(packet, si->host); + protocol->prepare_for_resend(); + protocol->store((uint32) si->server_id); + protocol->store(si->host); if (opt_show_slave_auth_info) { - net_store_data(packet, si->user); - net_store_data(packet, si->password); + protocol->store(si->user); + protocol->store(si->password); } - net_store_data(packet, (uint32) si->port); - net_store_data(packet, si->rpl_recovery_rank); - net_store_data(packet, si->master_id); - if (my_net_write(net, (char*)packet->ptr(), packet->length())) + protocol->store((uint32) si->port); + protocol->store((uint32) si->rpl_recovery_rank); + protocol->store((uint32) si->master_id); + if (protocol->write()) { pthread_mutex_unlock(&LOCK_slave_list); DBUG_RETURN(-1); diff --git a/sql/set_var.cc b/sql/set_var.cc index 691add191b2..3404df1c56a 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -992,8 +992,12 @@ bool sys_var_thd_conv_charset::update(THD *thd, set_var *var) if (var->type == OPT_GLOBAL) global_system_variables.convert_set= var->save_result.convert; else + { thd->lex.convert_set= thd->variables.convert_set= var->save_result.convert; + thd->protocol_simple.init(thd); + thd->protocol_prep.init(thd); + } return 0; } diff --git a/sql/slave.cc b/sql/slave.cc index f8acc592afa..7d3ec8d3dce 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1513,42 +1513,38 @@ err: *****************************************************************************/ int register_slave_on_master(MYSQL* mysql) { - String packet; - char buf[4]; + char buf[1024], *pos= buf; + uint report_host_len, report_user_len=0, report_password_len=0; if (!report_host) return 0; - - int4store(buf, server_id); - packet.append(buf, 4); - - net_store_data(&packet, report_host); + report_host_len= strlen(report_host); if (report_user) - net_store_data(&packet, report_user); - else - packet.append((char)0); - + report_user_len= strlen(report_user); if (report_password) - net_store_data(&packet, report_user); - else - packet.append((char)0); - - int2store(buf, (uint16)report_port); - packet.append(buf, 2); - int4store(buf, rpl_recovery_rank); - packet.append(buf, 4); - int4store(buf, 0); /* tell the master will fill in master_id */ - packet.append(buf, 4); - - if (mc_simple_command(mysql, COM_REGISTER_SLAVE, (char*)packet.ptr(), - packet.length(), 0)) + report_password_len= strlen(report_password); + /* 30 is a good safety margin */ + if (report_host_len + report_user_len + report_password_len + 30 > + sizeof(buf)) + return 0; // safety + + int4store(pos, server_id); pos+= 4; + pos= net_store_data(pos, report_host, report_host_len); + pos= net_store_data(pos, report_user, report_user_len); + pos= net_store_data(pos, report_password, report_password_len); + int2store(pos, (uint16) report_port); pos+= 2; + int4store(pos, rpl_recovery_rank); pos+= 4; + /* The master will fill in master_id */ + int4store(pos, 0); pos+= 4; + + if (mc_simple_command(mysql, COM_REGISTER_SLAVE, (char*) buf, + (uint) (pos- buf), 0)) { sql_print_error("Error on COM_REGISTER_SLAVE: %d '%s'", mc_mysql_errno(mysql), mc_mysql_error(mysql)); return 1; } - return 0; } @@ -1560,60 +1556,69 @@ int register_slave_on_master(MYSQL* mysql) int show_master_info(THD* thd, MASTER_INFO* mi) { // TODO: fix this for multi-master - DBUG_ENTER("show_master_info"); List<Item> field_list; + Protocol *protocol= thd->protocol; + DBUG_ENTER("show_master_info"); + field_list.push_back(new Item_empty_string("Master_Host", sizeof(mi->host))); field_list.push_back(new Item_empty_string("Master_User", sizeof(mi->user))); - field_list.push_back(new Item_empty_string("Master_Port", 6)); - field_list.push_back(new Item_empty_string("Connect_retry", 6)); + field_list.push_back(new Item_return_int("Master_Port", 7, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Connect_retry", 10, + MYSQL_TYPE_LONG)); field_list.push_back(new Item_empty_string("Master_Log_File", - FN_REFLEN)); - field_list.push_back(new Item_empty_string("Read_Master_Log_Pos", 12)); + FN_REFLEN)); + field_list.push_back(new Item_return_int("Read_Master_Log_Pos", 10, + MYSQL_TYPE_LONGLONG)); field_list.push_back(new Item_empty_string("Relay_Log_File", - FN_REFLEN)); - field_list.push_back(new Item_empty_string("Relay_Log_Pos", 12)); + FN_REFLEN)); + field_list.push_back(new Item_return_int("Relay_Log_Pos", 10, + MYSQL_TYPE_LONGLONG)); field_list.push_back(new Item_empty_string("Relay_Master_Log_File", - FN_REFLEN)); + FN_REFLEN)); field_list.push_back(new Item_empty_string("Slave_IO_Running", 3)); field_list.push_back(new Item_empty_string("Slave_SQL_Running", 3)); field_list.push_back(new Item_empty_string("Replicate_do_db", 20)); field_list.push_back(new Item_empty_string("Replicate_ignore_db", 20)); - field_list.push_back(new Item_empty_string("Last_errno", 4)); + field_list.push_back(new Item_return_int("Last_errno", 4, MYSQL_TYPE_LONG)); field_list.push_back(new Item_empty_string("Last_error", 20)); - field_list.push_back(new Item_empty_string("Skip_counter", 12)); - field_list.push_back(new Item_empty_string("Exec_master_log_pos", 12)); - field_list.push_back(new Item_empty_string("Relay_log_space", 12)); - if (send_fields(thd, field_list, 1)) + field_list.push_back(new Item_return_int("Skip_counter", 10, + MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("Exec_master_log_pos", 10, + MYSQL_TYPE_LONGLONG)); + field_list.push_back(new Item_return_int("Relay_log_space", 10, + MYSQL_TYPE_LONGLONG)); + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); if (mi->host[0]) { String *packet= &thd->packet; - packet->length(0); + protocol->prepare_for_resend(); pthread_mutex_lock(&mi->data_lock); pthread_mutex_lock(&mi->rli.data_lock); - net_store_data(packet, mi->host); - net_store_data(packet, mi->user); - net_store_data(packet, (uint32) mi->port); - net_store_data(packet, (uint32) mi->connect_retry); - net_store_data(packet, mi->master_log_name); - net_store_data(packet, (longlong) mi->master_log_pos); - net_store_data(packet, mi->rli.relay_log_name + + protocol->store(mi->host); + protocol->store(mi->user); + protocol->store((uint32) mi->port); + protocol->store((uint32) mi->connect_retry); + protocol->store(mi->master_log_name); + protocol->store((ulonglong) mi->master_log_pos); + protocol->store(mi->rli.relay_log_name + dirname_length(mi->rli.relay_log_name)); - net_store_data(packet, (longlong) mi->rli.relay_log_pos); - net_store_data(packet, mi->rli.master_log_name); - net_store_data(packet, mi->slave_running ? "Yes":"No"); - net_store_data(packet, mi->rli.slave_running ? "Yes":"No"); - net_store_data(packet, &replicate_do_db); - net_store_data(packet, &replicate_ignore_db); - net_store_data(packet, (uint32)mi->rli.last_slave_errno); - net_store_data(packet, mi->rli.last_slave_error); - net_store_data(packet, mi->rli.slave_skip_counter); - net_store_data(packet, (longlong) mi->rli.master_log_pos); - net_store_data(packet, (longlong) mi->rli.log_space_total); + protocol->store((ulonglong) mi->rli.relay_log_pos); + protocol->store(mi->rli.master_log_name); + protocol->store(mi->slave_running ? "Yes":"No"); + protocol->store(mi->rli.slave_running ? "Yes":"No"); + protocol->store(&replicate_do_db); + protocol->store(&replicate_ignore_db); + protocol->store((uint32) mi->rli.last_slave_errno); + protocol->store(mi->rli.last_slave_error); + protocol->store((uint32) mi->rli.slave_skip_counter); + protocol->store((ulonglong) mi->rli.master_log_pos); + protocol->store((ulonglong) mi->rli.log_space_total); pthread_mutex_unlock(&mi->rli.data_lock); pthread_mutex_unlock(&mi->data_lock); @@ -1640,8 +1645,7 @@ bool flush_master_info(MASTER_INFO* mi) my_b_printf(file, "%s\n%s\n%s\n%s\n%s\n%d\n%d\n", mi->master_log_name, llstr(mi->master_log_pos, lbuf), mi->host, mi->user, - mi->password, mi->port, mi->connect_retry - ); + mi->password, mi->port, mi->connect_retry); flush_io_cache(file); DBUG_RETURN(0); } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index cde6ace1470..310ac16e927 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2776,6 +2776,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) int error = 0; ACL_USER *acl_user; ACL_DB *acl_db; char buff[1024]; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysql_show_grants"); LINT_INIT(acl_user); @@ -2822,7 +2823,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) strxmov(buff,"Grants for ",lex_user->user.str,"@", lex_user->host.str,NullS); field_list.push_back(field); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(-1); rw_wrlock(&LOCK_grant); @@ -2931,12 +2932,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append(buff,p-buff); } } - thd->packet.length(0); - net_store_data(&thd->packet,global.ptr(),global.length()); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(), - thd->packet.length())) + protocol->prepare_for_resend(); + protocol->store(global.ptr(),global.length()); + if (protocol->write()) { - error=-1; goto end; + error=-1; + goto end; } } @@ -2987,10 +2988,9 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) db.append ('\''); if (want_access & GRANT_ACL) db.append(" WITH GRANT OPTION",18); - thd->packet.length(0); - net_store_data(&thd->packet,db.ptr(),db.length()); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(), - thd->packet.length())) + protocol->prepare_for_resend(); + protocol->store(db.ptr(),db.length()); + if (protocol->write()) { error=-1; goto end; @@ -3075,10 +3075,9 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) global.append('\''); if (want_access & GRANT_ACL) global.append(" WITH GRANT OPTION",18); - thd->packet.length(0); - net_store_data(&thd->packet,global.ptr(),global.length()); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(), - thd->packet.length())) + protocol->prepare_for_resend(); + protocol->store(global.ptr(),global.length()); + if (protocol->write()) { error= -1; break; diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index ecd9f635060..acd67ad66d7 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -310,30 +310,7 @@ void field_str::add() was_maybe_zerofill = num_info.maybe_zerofill; } - if (room_in_tree) - { - if (res != &s) - s.copy(*res); - if (!tree_search(&tree, (void*) &s, tree.custom_arg)) // If not in tree - { - s.copy(); // slow, when SAFE_MALLOC is in use - if (!tree_insert(&tree, (void*) &s, 0, tree.custom_arg)) - { - room_in_tree = 0; // Remove tree, out of RAM ? - delete_tree(&tree); - } - else - { - bzero((char*) &s, sizeof(s)); // Let tree handle free of this - if ((treemem += length) > pc->max_treemem) - { - room_in_tree = 0; // Remove tree, too big tree - delete_tree(&tree); - } - } - } - } - + /* Update min and max arguments */ if (!found) { found = 1; @@ -364,6 +341,31 @@ void field_str::add() max_arg.copy(*res); } } + + if (room_in_tree) + { + if (res != &s) + s.copy(*res); + if (!tree_search(&tree, (void*) &s, tree.custom_arg)) // If not in tree + { + s.copy(); // slow, when SAFE_MALLOC is in use + if (!tree_insert(&tree, (void*) &s, 0, tree.custom_arg)) + { + room_in_tree = 0; // Remove tree, out of RAM ? + delete_tree(&tree); + } + else + { + bzero((char*) &s, sizeof(s)); // Let tree handle free of this + if ((treemem += length) > pc->max_treemem) + { + room_in_tree = 0; // Remove tree, too big tree + delete_tree(&tree); + } + } + } + } + if ((num_info.zerofill && (max_length != min_length)) || (was_zero_fill && (max_length != min_length))) can_be_still_num = 0; // zerofilled numbers must be of same length diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e2b36106fb0..87cc0d616a9 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -196,250 +196,6 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild) } -/* - Send name and type of result to client converted to a given char set - - SYNOPSIS - send_convert_fields() - THD Thread data object - list List of items to send to client - convert object used to convertation to another character set - flag Bit mask with the following functions: - 2 send default values - 4 Don't convert field names - - DESCRIPTION - Sum fields has table name empty and field_name. - - RETURN VALUES - 0 ok - 1 Error (Note that in this case the error is not sent to the client) -*/ - -bool -send_convert_fields(THD *thd,List<Item> &list,CONVERT *convert,uint flag) -{ - List_iterator_fast<Item> it(list); - Item *item; - char buff[80]; - String tmp((char*) buff,sizeof(buff),default_charset_info); - String *res,*packet= &thd->packet; - DBUG_ENTER("send_convert_fields"); - - while ((item=it++)) - { - char *pos; - Send_field field; - item->make_field(&field); - packet->length(0); - - if (thd->client_capabilities & CLIENT_PROTOCOL_41) - { - if (convert->store(packet,field.db_name, - (uint) strlen(field.db_name)) || - convert->store(packet,field.table_name, - (uint) strlen(field.table_name)) || - convert->store(packet,field.org_table_name, - (uint) strlen(field.org_table_name)) || - convert->store(packet,field.col_name, - (uint) strlen(field.col_name)) || - convert->store(packet,field.org_col_name, - (uint) strlen(field.org_col_name)) || - packet->realloc(packet->length()+10)) - goto err; - } - else - { - if (convert->store(packet,field.table_name, - (uint) strlen(field.table_name)) || - convert->store(packet,field.col_name, - (uint) strlen(field.col_name)) || - packet->realloc(packet->length()+10)) - goto err; - } - pos= (char*) packet->ptr()+packet->length(); - - if (!(thd->client_capabilities & CLIENT_LONG_FLAG)) - { - packet->length(packet->length()+9); - pos[0]=3; int3store(pos+1,field.length); - pos[4]=1; pos[5]=field.type; - pos[6]=2; pos[7]=(char) field.flags; pos[8]= (char) field.decimals; - } - else - { - packet->length(packet->length()+10); - pos[0]=3; int3store(pos+1,field.length); - pos[4]=1; pos[5]=field.type; - pos[6]=3; int2store(pos+7,field.flags); pos[9]= (char) field.decimals; - } - if (flag & 2) - { // Send default value - if (!(res=item->val_str(&tmp))) - { - if (net_store_null(packet)) - goto err; - } - else if (convert->store(packet,res->ptr(),res->length())) - goto err; - } - if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length())) - break; /* purecov: inspected */ - } - DBUG_RETURN(0); - -err: - DBUG_RETURN(1); -} - - -/* - Send name and type of result to client. - - SYNOPSIS - send_non_convert_fields() - THD Thread data object - list List of items to send to client - flag Bit mask with the following functions: - 2 send default values - 4 Don't convert field names - - DESCRIPTION - Sum fields has table name empty and field_name. - - RETURN VALUES - 0 ok - 1 Error -*/ - -bool -send_non_convert_fields(THD *thd,List<Item> &list,uint flag) -{ - List_iterator_fast<Item> it(list); - Item *item; - char buff[80]; - - String tmp((char*) buff,sizeof(buff),default_charset_info); - String *res,*packet= &thd->packet; - - while ((item=it++)) - { - char *pos; - Send_field field; - item->make_field(&field); - packet->length(0); - - if (thd->client_capabilities & CLIENT_PROTOCOL_41) - { - if (net_store_data(packet,field.db_name) || - net_store_data(packet,field.table_name) || - net_store_data(packet,field.org_table_name) || - net_store_data(packet,field.col_name) || - net_store_data(packet,field.org_col_name) || - packet->realloc(packet->length()+10)) - return 1; - } - else - { - if (net_store_data(packet,field.table_name) || - net_store_data(packet,field.col_name) || - packet->realloc(packet->length()+10)) - return 1; - } - - pos= (char*) packet->ptr()+packet->length(); - - if (!(thd->client_capabilities & CLIENT_LONG_FLAG)) - { - packet->length(packet->length()+9); - pos[0]=3; int3store(pos+1,field.length); - pos[4]=1; pos[5]=field.type; - pos[6]=2; pos[7]=(char) field.flags; pos[8]= (char) field.decimals; - } - else - { - packet->length(packet->length()+10); - pos[0]=3; int3store(pos+1,field.length); - pos[4]=1; pos[5]=field.type; - pos[6]=3; int2store(pos+7,field.flags); pos[9]= (char) field.decimals; - } - if (flag & 2) - { // Send default value - if (!(res=item->val_str(&tmp))) - { - if (net_store_null(packet)) - return 1; - } - else if (net_store_data(packet,res->ptr(),res->length())) - return 1; - } - if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length())) - break; - } - return 0; -} - - -/* - Send name and type of result to client. - - SYNOPSIS - send_fields() - THD Thread data object - list List of items to send to client - convert object used to convertation to another character set - flag Bit mask with the following functions: - 1 send number of rows - 2 send default values - 4 Don't convert field names - - DESCRIPTION - Sum fields has table name empty and field_name. - Uses send_fields_convert() and send_fields() depending on - if we have an active character set convert or not. - - RETURN VALUES - 0 ok - 1 Error (Note that in this case the error is not sent to the client) -*/ - -bool -send_fields(THD *thd, List<Item> &list, uint flag) -{ - char buff[9]; // Big enough for store_length - CONVERT *convert= (flag & 4) ? (CONVERT*) 0 : thd->variables.convert_set; - DBUG_ENTER("send_fields"); - - if (thd->fatal_error) // We have got an error - goto err; - - if (flag & 1) - { // Packet with number of elements - char *pos=net_store_length(buff, (uint) list.elements); - (void) my_net_write(&thd->net, buff,(uint) (pos-buff)); - } - - /* - Avoid check conditions on convert() for each field - by having two different functions - */ - if (convert) - { - if (send_convert_fields(thd, list, convert, flag)) - goto err; - } - else if (send_non_convert_fields(thd, list, flag)) - goto err; - - send_eof(thd); - DBUG_RETURN(0); - -err: - send_error(thd,ER_OUT_OF_RESOURCES); /* purecov: inspected */ - DBUG_RETURN(1); /* purecov: inspected */ -} - - /***************************************************************************** * Functions to free open table cache ****************************************************************************/ diff --git a/sql/sql_class.cc b/sql/sql_class.cc index ba6369b0022..345a2e6f34d 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -152,6 +152,11 @@ THD::THD():user_time(0), fatal_error(0), (qsort_cmp2) compare_prep_stmt, 1, (tree_element_free) free_prep_stmt, 0); + /* Protocol */ + protocol= &protocol_simple; // Default protocol + protocol_simple.init(this); + protocol_prep.init(this); + #ifdef USING_TRANSACTIONS bzero((char*) &transaction,sizeof(transaction)); if (opt_using_transactions) @@ -438,7 +443,7 @@ int THD::send_explain_fields(select_result *result) { List<Item> field_list; Item *item; - field_list.push_back(new Item_int("id",0,3)); + field_list.push_back(new Item_return_int("id",3, MYSQL_TYPE_LONGLONG)); field_list.push_back(new Item_empty_string("select_type",19)); field_list.push_back(new Item_empty_string("table",NAME_LEN)); field_list.push_back(new Item_empty_string("type",10)); @@ -447,12 +452,13 @@ int THD::send_explain_fields(select_result *result) item->maybe_null=1; field_list.push_back(item=new Item_empty_string("key",NAME_LEN)); item->maybe_null=1; - field_list.push_back(item=new Item_int("key_len",0,3)); + field_list.push_back(item=new Item_return_int("key_len",3, + MYSQL_TYPE_LONGLONG)); item->maybe_null=1; field_list.push_back(item=new Item_empty_string("ref", NAME_LEN*MAX_REF_PARTS)); item->maybe_null=1; - field_list.push_back(new Item_real("rows",0.0,0,10)); + field_list.push_back(new Item_return_int("rows",10, MYSQL_TYPE_LONGLONG)); field_list.push_back(new Item_empty_string("Extra",255)); return (result->send_fields(field_list,1)); } @@ -503,7 +509,7 @@ sql_exchange::sql_exchange(char *name,bool flag) bool select_send::send_fields(List<Item> &list,uint flag) { - return ::send_fields(thd,list,flag); + return thd->protocol->send_fields(&list,flag); } @@ -511,35 +517,33 @@ bool select_send::send_fields(List<Item> &list,uint flag) bool select_send::send_data(List<Item> &items) { - List_iterator_fast<Item> li(items); - String *packet= &thd->packet; - DBUG_ENTER("send_data"); - if (unit->offset_limit_cnt) { // using limit offset,count unit->offset_limit_cnt--; - DBUG_RETURN(0); + return 0; } - packet->length(0); // Reset packet + + List_iterator_fast<Item> li(items); + Protocol *protocol= thd->protocol; + char buff[MAX_FIELD_WIDTH]; + String buffer(buff, sizeof(buff), system_charset_info); + DBUG_ENTER("send_data"); + + protocol->prepare_for_resend(); Item *item; while ((item=li++)) { - if (item->send(thd, packet)) + if (item->send(protocol, &buffer)) { - packet->free(); // Free used + protocol->free(); // Free used buffer my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - DBUG_RETURN(1); + break; } } thd->sent_row_count++; if (!thd->net.report_error) - { - DBUG_RETURN(my_net_write(&thd->net, - (char*) packet->ptr(), - packet->length())); - } - else - DBUG_RETURN(1); + DBUG_RETURN(protocol->write()); + DBUG_RETURN(1); } bool select_send::send_eof() diff --git a/sql/sql_class.h b/sql/sql_class.h index ca56d2dcdf5..50ab7919998 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -389,6 +389,9 @@ public: MEM_ROOT mem_root; // 1 command-life memory pool MEM_ROOT con_root; // connection-life memory MEM_ROOT warn_root; // For warnings and errors + Protocol *protocol; // Current protocol + Protocol_simple protocol_simple; // Normal protocol + Protocol_prep protocol_prep; // Binary protocol HASH user_vars; // hash for user variables TREE prepared_statements; String packet; // dynamic buffer for network I/O diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 85dfb38fa48..bca133bd63a 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -604,7 +604,8 @@ bool mysql_change_db(THD *thd, const char *name) } -int mysqld_show_create_db(THD *thd, const char *dbname, HA_CREATE_INFO *create_info) +int mysqld_show_create_db(THD *thd, const char *dbname, + HA_CREATE_INFO *create_info) { int length; char path[FN_REFLEN], *to; @@ -613,7 +614,7 @@ int mysqld_show_create_db(THD *thd, const char *dbname, HA_CREATE_INFO *create_i HA_CREATE_INFO create; CONVERT *convert=thd->variables.convert_set; uint create_options = create_info ? create_info->options : 0; - + Protocol *protocol=thd->protocol; DBUG_ENTER("mysql_show_create_db"); if (check_db_name(dbname)) @@ -663,12 +664,11 @@ int mysqld_show_create_db(THD *thd, const char *dbname, HA_CREATE_INFO *create_i field_list.push_back(new Item_empty_string("Database",NAME_LEN)); field_list.push_back(new Item_empty_string("Create Database",1024)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); - String *packet = &thd->packet; - packet->length(0); - net_store_data(packet, convert, dbname); + protocol->prepare_for_resend(); + protocol->store(dbname, strlen(dbname)); to= strxmov(path, "CREATE DATABASE ", NullS); if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS) to= strxmov(to,"/*!32312 IF NOT EXISTS*/ ", NullS); @@ -678,11 +678,10 @@ int mysqld_show_create_db(THD *thd, const char *dbname, HA_CREATE_INFO *create_i to= strxmov(to," /*!40100 DEFAULT CHARACTER SET ", create.table_charset->name,"*/",NullS); - net_store_data(packet, convert, path, (uint) (to-path)); + protocol->store(path, (uint) (to-path)); - if (my_net_write(&thd->net,(char*) packet->ptr(), packet->length())) + if (protocol->write()) DBUG_RETURN(1); - send_eof(thd); DBUG_RETURN(0); } diff --git a/sql/sql_error.cc b/sql/sql_error.cc index bba49cf818b..c9684855b86 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -150,7 +150,7 @@ void store_warning(THD *thd, uint errcode, ...) */ static const char *warning_level_names[]= {"Note", "Warning", "Error", "?"}; - +static int warning_level_length[]= { 4, 7, 5, 1 }; my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show) { @@ -158,15 +158,16 @@ my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show) DBUG_ENTER("mysqld_show_warnings"); field_list.push_back(new Item_empty_string("Level", 7)); - field_list.push_back(new Item_int("Code",0,4)); + field_list.push_back(new Item_return_int("Code",4, MYSQL_TYPE_LONG)); field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE)); - if (send_fields(thd,field_list,1)) + if (thd->protocol->send_fields(&field_list,1)) DBUG_RETURN(1); MYSQL_ERROR *err; SELECT_LEX *sel= &thd->lex.select_lex; ha_rows offset= sel->offset_limit, limit= sel->select_limit; + Protocol *protocol=thd->protocol; List_iterator_fast<MYSQL_ERROR> it(thd->warn_list); while ((err= it++)) @@ -179,11 +180,12 @@ my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show) offset--; continue; } - thd->packet.length(0); - net_store_data(&thd->packet,warning_level_names[err->level]); - net_store_data(&thd->packet,(uint32) err->code); - net_store_data(&thd->packet,err->msg); - if (my_net_write(&thd->net,(char*)thd->packet.ptr(),thd->packet.length())) + protocol->prepare_for_resend(); + protocol->store(warning_level_names[err->level], + warning_level_length[err->level]); + protocol->store((uint32) err->code); + protocol->store(err->msg, strlen(err->msg)); + if (protocol->write()) DBUG_RETURN(1); if (!--limit) break; diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 6ea319a72e4..97703cd6b20 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -123,6 +123,9 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, List<Item> list; list.push_front(new Item_field(NULL,NULL,"*")); List_iterator<Item> it(list); + Protocol *protocol= thd->protocol; + char buff[MAX_FIELD_WIDTH]; + String buffer(buff, sizeof(buff), system_charset_info); uint num_rows; it++; @@ -131,7 +134,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it select_limit+=offset_limit; - send_fields(thd,list,1); + protocol->send_fields(&list,1); HANDLER_TABLES_HACK(thd); MYSQL_LOCK *lock=mysql_lock_tables(thd,&tables->table,1); @@ -141,7 +144,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, for (num_rows=0; num_rows < select_limit; ) { - switch(mode) { + switch (mode) { case RFIRST: err=keyname ? table->file->index_first(table->record[0]) : @@ -216,24 +219,24 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, if (!cond->val_int()) continue; } - if (num_rows>=offset_limit) + if (num_rows >= offset_limit) { if (!err) { String *packet = &thd->packet; Item *item; - packet->length(0); + protocol->prepare_for_resend(); it.rewind(); while ((item=it++)) { - if (item->send(thd,packet)) + if (item->send(thd->protocol, &buffer)) { - packet->free(); // Free used + protocol->free(); // Free used my_error(ER_OUT_OF_RESOURCES,MYF(0)); goto err; } } - my_net_write(&thd->net, (char*)packet->ptr(), packet->length()); + protocol->write(); } } num_rows++; @@ -249,26 +252,26 @@ err0: } /************************************************************************** - 2Monty: It could easily happen, that the following service functions are + Monty: It could easily happen, that the following service functions are already defined somewhere in the code, but I failed to find them. If this is the case, just say a word and I'll use old functions here. **************************************************************************/ -/* Note: this function differs from find_locked_table() because we're looking - here for alias, not real table name - */ +/* + Note: this function differs from find_locked_table() because we're looking + here for alias, not real table name +*/ + static TABLE **find_table_ptr_by_name(THD *thd, const char *db, const char *alias) { int dblen; TABLE **ptr; - if (!db || ! *db) - db= thd->db ? thd->db : ""; dblen=strlen(db)+1; - ptr=&(thd->handler_tables); + ptr= &(thd->handler_tables); - for (TABLE *table=*ptr; table ; table=*ptr) + for (TABLE *table= *ptr; table ; table= *ptr) { if (!memcmp(table->table_cache_key, db, dblen) && !my_strcasecmp(system_charset_info,table->table_name,alias)) diff --git a/sql/sql_help.cc b/sql/sql_help.cc index d2bea9ba44b..db28823a43d 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -219,22 +219,21 @@ int search_categories(THD *thd, DBUG_RETURN(count); } -int send_variant_2_list(THD *thd, List<String> *names, my_bool is_category) +int send_variant_2_list(Protocol *protocol, List<String> *names, + my_bool is_category) { DBUG_ENTER("send_names"); List_iterator<String> it(*names); String *cur_name; - String *packet= &thd->packet; while ((cur_name = it++)) { - packet->length(0); - net_store_data(packet, cur_name->ptr()); - net_store_data(packet, is_category ? "Y" : "N"); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->prepare_for_resend(); + protocol->store(cur_name->ptr()); + protocol->store(is_category ? "Y" : "N"); + if (protocol->write()) DBUG_RETURN(-1); } - DBUG_RETURN(0); } @@ -296,43 +295,44 @@ int get_all_names_for_category(THD *thd,MI_INFO *file_leafs, DBUG_RETURN(0); } -int send_answer_1(THD *thd, const char *s1, const char *s2, +int send_answer_1(Protocol *protocol, const char *s1, const char *s2, const char *s3, const char *s4) { DBUG_ENTER("send_answer_1"); List<Item> field_list; - field_list.push_back(new Item_empty_string("name",64)); - field_list.push_back(new Item_empty_string("is_category",1)); - field_list.push_back(new Item_empty_string("description",1000)); - field_list.push_back(new Item_empty_string("example",1000)); + field_list.push_back(new Item_empty_string("Name",64)); + field_list.push_back(new Item_empty_string("Category",1)); + field_list.push_back(new Item_empty_string("Description",1000)); + field_list.push_back(new Item_empty_string("Example",1000)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); - String *packet= &thd->packet; - packet->length(0); - net_store_data(packet, s1); - net_store_data(packet, s2); - net_store_data(packet, s3); - net_store_data(packet, s4); - - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->prepare_for_resend(); + protocol->store(s1); + protocol->store(s2); + protocol->store(s3); + protocol->store(s4); + if (protocol->write()) DBUG_RETURN(-1); DBUG_RETURN(0); } -int send_header_2(THD *thd) + +int send_header_2(Protocol *protocol) { DBUG_ENTER("send_header2"); List<Item> field_list; - field_list.push_back(new Item_empty_string("name",64)); - field_list.push_back(new Item_empty_string("is_category",1)); - DBUG_RETURN(send_fields(thd,field_list,1)); + field_list.push_back(new Item_empty_string("Name",64)); + field_list.push_back(new Item_empty_string("Category",1)); + DBUG_RETURN(protocol->send_fields(&field_list,1)); } -int mysqld_help (THD *thd, const char *mask) + +int mysqld_help(THD *thd, const char *mask) { + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_help"); MI_INFO *file_leafs= 0; @@ -345,7 +345,7 @@ int mysqld_help (THD *thd, const char *mask) int count= search_functions(file_leafs, mask, &function_list,&name,&description,&example); - if (count<0) + if (count < 0) { res= 1; goto end; @@ -371,31 +371,31 @@ int mysqld_help (THD *thd, const char *mask) example.append(*cur_leaf); example.append("\n",1); } - if ((res= send_answer_1(thd, categories_list.head()->ptr(), - "Y","",example.ptr()))) + if ((res= send_answer_1(protocol, categories_list.head()->ptr(), + "Y","",example.ptr()))) goto end; } else { - if ((res= send_header_2(thd)) || + if ((res= send_header_2(protocol)) || (count==0 && (search_categories(thd, 0, &categories_list, 0)<0 && (res= 1))) || - (res= send_variant_2_list(thd,&categories_list,true))) + (res= send_variant_2_list(protocol,&categories_list,true))) goto end; } } else if (count==1) { - if ((res= send_answer_1(thd,name->ptr(),"N", - description->ptr(), example->ptr()))) + if ((res= send_answer_1(protocol,name->ptr(),"N", + description->ptr(), example->ptr()))) goto end; } - else if((res= send_header_2(thd)) || - (res= send_variant_2_list(thd,&function_list,false)) || + else if((res= send_header_2(protocol)) || + (res= send_variant_2_list(protocol,&function_list,false)) || (search_categories(thd, mask, &categories_list, 0)<0 && (res=1)) || - (res= send_variant_2_list(thd,&categories_list,true))) + (res= send_variant_2_list(protocol,&categories_list,true))) { goto end; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 90568bfcc5e..f8c46c7cd41 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3010,11 +3010,11 @@ mysql_init_query(THD *thd) DBUG_VOID_RETURN; } + void mysql_init_select(LEX *lex) { SELECT_LEX *select_lex= lex->current_select->select_lex(); - DBUG_ASSERT(select_lex->linkage != GLOBAL_OPTIONS_TYPE); select_lex->init_select(); select_lex->master_unit()->select_limit= select_lex->select_limit= lex->thd->variables.select_limit; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 9d6e6d75ade..704acc9c1c2 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -512,7 +512,8 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, sending any info on where clause. */ if (send_prep_stmt(stmt, fields.elements) || - send_fields(thd,fields,0) || send_item_params(stmt)) + thd->protocol_prep.send_fields(&fields,0) || + send_item_params(stmt)) DBUG_RETURN(1); DBUG_RETURN(0); } @@ -726,7 +727,9 @@ void mysql_stmt_execute(THD *thd, char *packet) mysql_delete(), mysql_update() and mysql_select() to not to have re-check on setup_* and other things .. */ + thd->protocol= &thd->protocol_prep; // Switch to binary protocol mysql_execute_command(stmt->thd); + thd->protocol= &thd->protocol_simple; // Use normal protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 23951cec29f..375a7478377 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -928,14 +928,15 @@ int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1, int show_binlog_events(THD* thd) { + Protocol *protocol= thd->protocol; DBUG_ENTER("show_binlog_events"); List<Item> field_list; - const char* errmsg = 0; + const char *errmsg = 0; IO_CACHE log; File file = -1; Log_event::init_show_field_list(&field_list); - if (send_fields(thd, field_list, 1)) + if (protocol-> send_fields(&field_list, 1)) DBUG_RETURN(-1); if (mysql_bin_log.is_open()) @@ -983,7 +984,7 @@ int show_binlog_events(THD* thd) (ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,0)); ) { if (event_count >= limit_start && - ev->net_send(thd, linfo.log_file_name, pos)) + ev->net_send(protocol, linfo.log_file_name, pos)) { errmsg = "Net error"; delete ev; @@ -1029,28 +1030,29 @@ err: int show_binlog_info(THD* thd) { + Protocol *protocol= thd->protocol; DBUG_ENTER("show_binlog_info"); List<Item> field_list; field_list.push_back(new Item_empty_string("File", FN_REFLEN)); - field_list.push_back(new Item_empty_string("Position",20)); - field_list.push_back(new Item_empty_string("Binlog_do_db",20)); - field_list.push_back(new Item_empty_string("Binlog_ignore_db",20)); + field_list.push_back(new Item_return_int("Position",20, + MYSQL_TYPE_LONGLONG)); + field_list.push_back(new Item_empty_string("Binlog_do_db",255)); + field_list.push_back(new Item_empty_string("Binlog_ignore_db",255)); - if (send_fields(thd, field_list, 1)) + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); - String* packet = &thd->packet; - packet->length(0); + protocol->prepare_for_resend(); if (mysql_bin_log.is_open()) { LOG_INFO li; mysql_bin_log.get_current_log(&li); int dir_len = dirname_length(li.log_file_name); - net_store_data(packet, li.log_file_name + dir_len); - net_store_data(packet, (longlong)li.pos); - net_store_data(packet, &binlog_do_db); - net_store_data(packet, &binlog_ignore_db); - if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length())) + protocol->store(li.log_file_name + dir_len); + protocol->store((ulonglong) li.pos); + protocol->store(&binlog_do_db); + protocol->store(&binlog_ignore_db); + if (protocol->write()) DBUG_RETURN(-1); } send_eof(thd); @@ -1079,6 +1081,8 @@ int show_binlogs(THD* thd) List<Item> field_list; String *packet = &thd->packet; uint length; + Protocol *protocol= thd->protocol; + DBUG_ENTER("show_binlogs"); if (!mysql_bin_log.is_open()) { @@ -1088,8 +1092,8 @@ int show_binlogs(THD* thd) } field_list.push_back(new Item_empty_string("Log_name", 255)); - if (send_fields(thd, field_list, 1)) - return 1; + if (protocol->send_fields(&field_list, 1)) + DBUG_RETURN(1); mysql_bin_log.lock_index(); index_file=mysql_bin_log.get_index_file(); @@ -1098,22 +1102,22 @@ int show_binlogs(THD* thd) /* The file ends with EOF or empty line */ while ((length=my_b_gets(index_file, fname, sizeof(fname))) > 1) { + protocol->prepare_for_resend(); int dir_len = dirname_length(fname); - packet->length(0); /* The -1 is for removing newline from fname */ - net_store_data(packet, fname + dir_len, length-1-dir_len); - if (my_net_write(net, (char*) packet->ptr(), packet->length())) + protocol->store(fname + dir_len, length-1-dir_len); + if (protocol->write()) goto err; } mysql_bin_log.unlock_index(); send_eof(thd); - return 0; + DBUG_RETURN(0); err_with_msg: send_error(thd, ER_UNKNOWN_ERROR, errmsg); err: mysql_bin_log.unlock_index(); - return 1; + DBUG_RETURN(1); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index fe0cd02d056..602a4b494b6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3059,6 +3059,7 @@ join_free(JOIN *join, bool full) if (join->tables > join->const_tables) // Test for not-const tables free_io_cache(join->table[join->const_tables]); if (join->select_lex->dependent && !full) + { for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++) { if (tab->table) @@ -3073,6 +3074,7 @@ join_free(JOIN *join, bool full) tab->table->file->index_end(); } } + } else { for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++) @@ -3090,6 +3092,11 @@ join_free(JOIN *join, bool full) /* Don't free index if we are using read_record */ if (!tab->read_record.table) tab->table->file->index_end(); + /* + We need to reset this for next select + (Tested in part_of_refkey) + */ + tab->table->reginfo.join_tab= 0; } end_read_record(&tab->read_record); } @@ -7500,9 +7507,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, item_list.push_back(new Item_string(join->select_lex->type, strlen(join->select_lex->type), default_charset_info)); - Item *empty= new Item_empty_string("",0); for (uint i=0 ; i < 7; i++) - item_list.push_back(empty); + item_list.push_back(item_null); item_list.push_back(new Item_string(message,strlen(message), default_charset_info)); if (result->send_data(item_list)) @@ -7542,7 +7548,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, item_list.push_back(new Item_string(table->table_name, strlen(table->table_name), default_charset_info)); - item_list.push_back(new Item_string(join_type_str[tab->type],strlen(join_type_str[tab->type]),default_charset_info)); + item_list.push_back(new Item_string(join_type_str[tab->type], + strlen(join_type_str[tab->type]), + default_charset_info)); key_map bits; uint j; for (j=0,bits=tab->keys ; bits ; j++,bits>>=1) @@ -7600,9 +7608,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, item_list.push_back(item_null); item_list.push_back(item_null); } - sprintf(buff3,"%.0f",join->best_positions[i].records_read); - item_list.push_back(new Item_string(buff3,strlen(buff3), - default_charset_info)); + item_list.push_back(new Item_int((longlong) (ulonglong) + join->best_positions[i]. records_read, + 21)); my_bool key_read=table->key_read; if (tab->type == JT_NEXT && ((table->used_keys & ((key_map) 1 << tab->index)))) @@ -7658,6 +7666,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, DBUG_VOID_RETURN; } + int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) { DBUG_ENTER("mysql_explain_union"); @@ -7688,6 +7697,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) DBUG_RETURN(res); } + int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type, select_result *result) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index ebf5b210d6c..f60cba54e84 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -62,6 +62,7 @@ mysqld_show_dbs(THD *thd,const char *wild) char *end; List<char> files; char *file_name; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_dbs"); field->name=(char*) thd->alloc(20+ (wild ? (uint) strlen(wild)+4: 0)); @@ -71,13 +72,12 @@ mysqld_show_dbs(THD *thd,const char *wild) strxmov(end," (",wild,")",NullS); field_list.push_back(field); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1)) DBUG_RETURN(1); List_iterator_fast<char> it(files); - String *packet= &thd->packet; while ((file_name=it++)) { if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) || @@ -85,10 +85,9 @@ mysqld_show_dbs(THD *thd,const char *wild) thd->priv_user, file_name) || (grant_option && !check_grant_db(thd, file_name))) { - packet->length(0); - net_store_data(packet, thd->variables.convert_set, file_name); - if (my_net_write(&thd->net, (char*) packet->ptr(), - packet->length())) + protocol->prepare_for_resend(); + protocol->store(file_name); + if (protocol->write()) DBUG_RETURN(-1); } } @@ -105,29 +104,28 @@ int mysqld_show_open_tables(THD *thd,const char *wild) { List<Item> field_list; OPEN_TABLE_LIST *open_list; - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_open_tables"); field_list.push_back(new Item_empty_string("Database",NAME_LEN)); field_list.push_back(new Item_empty_string("Table",NAME_LEN)); - field_list.push_back(new Item_int("In_use",0, 4)); - field_list.push_back(new Item_int("Name_locked",0, 4)); + field_list.push_back(new Item_return_int("In_use", 1, MYSQL_TYPE_TINY)); + field_list.push_back(new Item_return_int("Name_locked", 4, MYSQL_TYPE_TINY)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); if (!(open_list=list_open_tables(thd,wild)) && thd->fatal_error) DBUG_RETURN(-1); - String *packet= &thd->packet; for (; open_list ; open_list=open_list->next) { - packet->length(0); - net_store_data(packet,convert, open_list->db); - net_store_data(packet,convert, open_list->table); - net_store_data(packet,open_list->in_use); - net_store_data(packet,open_list->locked); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->prepare_for_resend(); + protocol->store(open_list->db); + protocol->store(open_list->table); + protocol->store_tiny((longlong) open_list->in_use); + protocol->store_tiny((longlong) open_list->locked); + if (protocol->write()) { DBUG_RETURN(-1); } @@ -149,9 +147,11 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild) char path[FN_LEN],*end; List<char> files; char *file_name; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_tables"); - field->name=(char*) thd->alloc(20+(uint) strlen(db)+(wild ? (uint) strlen(wild)+4:0)); + field->name=(char*) thd->alloc(20+(uint) strlen(db)+ + (wild ? (uint) strlen(wild)+4:0)); end=strxmov(field->name,"Tables_in_",db,NullS); if (wild && wild[0]) strxmov(end," (",wild,")",NullS); @@ -159,17 +159,16 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild) (void) sprintf(path,"%s/%s",mysql_data_home,db); (void) unpack_dirname(path,path); field_list.push_back(field); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); if (mysql_find_files(thd,&files,db,path,wild,0)) DBUG_RETURN(-1); List_iterator_fast<char> it(files); - String *packet= &thd->packet; while ((file_name=it++)) { - packet->length(0); - net_store_data(packet, thd->variables.convert_set, file_name); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->prepare_for_resend(); + protocol->store(file_name); + if (protocol->write()) DBUG_RETURN(-1); } send_eof(thd); @@ -210,31 +209,32 @@ static struct show_table_type_st sys_table_types[]= int mysqld_show_table_types(THD *thd) { List<Item> field_list; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_table_types"); field_list.push_back(new Item_empty_string("Type",10)); field_list.push_back(new Item_empty_string("Support",10)); field_list.push_back(new Item_empty_string("Comment",80)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); - const char *default_type_name= ha_table_typelib.type_names[thd->variables.table_type]; + const char *default_type_name= + ha_table_typelib.type_names[thd->variables.table_type]; show_table_type_st *types; - String *packet= &thd->packet; for (types= sys_table_types; types->type; types++) { - packet->length(0); - net_store_data(packet, types->type); + protocol->prepare_for_resend(); + protocol->store(types->type); const char *option_name= show_comp_option_name[(int) *types->value]; if (*types->value == SHOW_OPTION_YES && !my_strcasecmp(system_charset_info, default_type_name, types->type)) option_name= "DEFAULT"; - net_store_data(packet, option_name); - net_store_data(packet, types->comment); - if (my_net_write(&thd->net, (char*) packet->ptr(), packet->length())) + protocol->store(option_name); + protocol->store(types->comment); + if (protocol->write()) DBUG_RETURN(-1); } send_eof(thd); @@ -279,24 +279,24 @@ static struct show_privileges_st sys_privileges[]= int mysqld_show_privileges(THD *thd) { List<Item> field_list; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_privileges"); field_list.push_back(new Item_empty_string("Privilege",10)); field_list.push_back(new Item_empty_string("Context",15)); field_list.push_back(new Item_empty_string("Comment",NAME_LEN)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); show_privileges_st *privilege= sys_privileges; - String *packet= &thd->packet; for (privilege= sys_privileges; privilege->privilege ; privilege++) { - packet->length(0); - net_store_data(packet,privilege->privilege); - net_store_data(packet,privilege->context); - net_store_data(packet,privilege->comment); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->prepare_for_resend(); + protocol->store(privilege->privilege); + protocol->store(privilege->context); + protocol->store(privilege->comment); + if (protocol->write()) DBUG_RETURN(-1); } send_eof(thd); @@ -343,14 +343,15 @@ static struct show_column_type_st sys_column_types[]= int mysqld_show_column_types(THD *thd) { List<Item> field_list; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_column_types"); field_list.push_back(new Item_empty_string("Type",30)); field_list.push_back(new Item_int("Size",(longlong) 1,21)); field_list.push_back(new Item_empty_string("Min_Value",20)); field_list.push_back(new Item_empty_string("Max_Value",20)); - field_list.push_back(new Item_int("Prec", 0,4)); - field_list.push_back(new Item_int("Scale", 0,4)); + field_list.push_back(new Item_return_int("Prec", 4, MYSQL_TYPE_SHORT)); + field_list.push_back(new Item_return_int("Scale", 4, MYSQL_TYPE_SHORT)); field_list.push_back(new Item_empty_string("Nullable",4)); field_list.push_back(new Item_empty_string("Auto_Increment",4)); field_list.push_back(new Item_empty_string("Unsigned",4)); @@ -360,29 +361,28 @@ int mysqld_show_column_types(THD *thd) field_list.push_back(new Item_empty_string("Default",NAME_LEN)); field_list.push_back(new Item_empty_string("Comment",NAME_LEN)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); /* TODO: Change the loop to not use 'i' */ - String *packet= &thd->packet; for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++) { - packet->length(0); - net_store_data(packet,sys_column_types[i].type); - net_store_data(packet,(longlong)sys_column_types[i].size); - net_store_data(packet,sys_column_types[i].min_value); - net_store_data(packet,sys_column_types[i].max_value); - net_store_data(packet,(uint32)sys_column_types[i].precision); - net_store_data(packet,(uint32)sys_column_types[i].scale); - net_store_data(packet,sys_column_types[i].nullable); - net_store_data(packet,sys_column_types[i].auto_increment); - net_store_data(packet,sys_column_types[i].unsigned_attr); - net_store_data(packet,sys_column_types[i].zerofill); - net_store_data(packet,sys_column_types[i].searchable); - net_store_data(packet,sys_column_types[i].case_sensitivity); - net_store_data(packet,sys_column_types[i].default_value); - net_store_data(packet,sys_column_types[i].comment); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->prepare_for_resend(); + protocol->store(sys_column_types[i].type); + protocol->store((ulonglong) sys_column_types[i].size); + protocol->store(sys_column_types[i].min_value); + protocol->store(sys_column_types[i].max_value); + protocol->store_short((longlong) sys_column_types[i].precision); + protocol->store_short((longlong) sys_column_types[i].scale); + protocol->store(sys_column_types[i].nullable); + protocol->store(sys_column_types[i].auto_increment); + protocol->store(sys_column_types[i].unsigned_attr); + protocol->store(sys_column_types[i].zerofill); + protocol->store(sys_column_types[i].searchable); + protocol->store(sys_column_types[i].case_sensitivity); + protocol->store(sys_column_types[i].default_value); + protocol->store(sys_column_types[i].comment); + if (protocol->write()) DBUG_RETURN(-1); } send_eof(thd); @@ -477,8 +477,8 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) char path[FN_LEN]; char *file_name; TABLE *table; - String *packet= &thd->packet; - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; + TIME time; DBUG_ENTER("mysqld_extend_show_tables"); (void) sprintf(path,"%s/%s",mysql_data_home,db); @@ -514,7 +514,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) field_list.push_back(item=new Item_empty_string("Create_options",255)); item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Comment",80)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); if (mysql_find_files(thd,&files,db,path,wild,0)) @@ -524,70 +524,74 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) { TABLE_LIST table_list; bzero((char*) &table_list,sizeof(table_list)); - packet->length(0); - net_store_data(packet,convert, file_name); + protocol->prepare_for_resend(); + protocol->store(file_name); table_list.db=(char*) db; table_list.real_name= table_list.alias= file_name; if (!(table = open_ltable(thd, &table_list, TL_READ))) { for (uint i=0 ; i < field_list.elements ; i++) - net_store_null(packet); - net_store_data(packet,convert, thd->net.last_error); + protocol->store_null(); + protocol->store(thd->net.last_error); thd->net.last_error[0]=0; } else { struct tm tm_tmp; + const char *str; handler *file=table->file; file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK); - net_store_data(packet, convert, file->table_type()); - net_store_data(packet, convert, - (table->db_options_in_use & HA_OPTION_COMPRESS_RECORD) ? - "Compressed" : - (table->db_options_in_use & HA_OPTION_PACK_RECORD) ? - "Dynamic" : "Fixed"); - net_store_data(packet, (longlong) file->records); - net_store_data(packet, (uint32) file->mean_rec_length); - net_store_data(packet, (longlong) file->data_file_length); + protocol->store(file->table_type()); + str= ((table->db_options_in_use & HA_OPTION_COMPRESS_RECORD) ? + "Compressed" : + (table->db_options_in_use & HA_OPTION_PACK_RECORD) ? + "Dynamic" : "Fixed"); + protocol->store(str); + protocol->store((ulonglong) file->records); + protocol->store((ulonglong) file->mean_rec_length); + protocol->store((ulonglong) file->data_file_length); if (file->max_data_file_length) - net_store_data(packet, (longlong) file->max_data_file_length); + protocol->store((ulonglong) file->max_data_file_length); else - net_store_null(packet); - net_store_data(packet, (longlong) file->index_file_length); - net_store_data(packet, (longlong) file->delete_length); + protocol->store_null(); + protocol->store((ulonglong) file->index_file_length); + protocol->store((ulonglong) file->delete_length); if (table->found_next_number_field) { table->next_number_field=table->found_next_number_field; table->next_number_field->reset(); file->update_auto_increment(); - net_store_data(packet, table->next_number_field->val_int()); + protocol->store(table->next_number_field->val_int()); table->next_number_field=0; } else - net_store_null(packet); + protocol->store_null(); if (!file->create_time) - net_store_null(packet); + protocol->store_null(); else { localtime_r(&file->create_time,&tm_tmp); - net_store_data(packet, &tm_tmp); + localtime_to_TIME(&time, &tm_tmp); + protocol->store(&time); } if (!file->update_time) - net_store_null(packet); + protocol->store_null(); else { localtime_r(&file->update_time,&tm_tmp); - net_store_data(packet, &tm_tmp); + localtime_to_TIME(&time, &tm_tmp); + protocol->store(&time); } if (!file->check_time) - net_store_null(packet); + protocol->store_null(); else { localtime_r(&file->check_time,&tm_tmp); - net_store_data(packet, &tm_tmp); + localtime_to_TIME(&time, &tm_tmp); + protocol->store(&time); } - net_store_data(packet, convert, table->table_charset ? - table->table_charset->name : "default"); + str= (table->table_charset ? table->table_charset->name : "default"); + protocol->store(str); { char option_buff[350],*ptr; ptr=option_buff; @@ -624,19 +628,18 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE); ptr=strmov(ptr,buff); } - net_store_data(packet, convert, option_buff+1, - (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1)); + protocol->store(option_buff+1, + (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1)); } { char *comment=table->file->update_table_comment(table->comment); - net_store_data(packet, comment); + protocol->store(comment); if (comment != table->comment) my_free(comment,MYF(0)); } close_thread_tables(thd,0); } - if (my_net_write(&thd->net,(char*) packet->ptr(), - packet->length())) + if (protocol->write()) DBUG_RETURN(-1); } send_eof(thd); @@ -656,7 +659,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, handler *file; char tmp[MAX_FIELD_WIDTH]; Item *item; - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_fields"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->real_name)); @@ -691,7 +694,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, (void) my_net_write(&thd->net,tmp,(uint) (pos-tmp)); } - if (send_fields(thd,field_list,0)) + if (protocol->send_fields(&field_list,0)) DBUG_RETURN(1); restore_record(table,2); // Get empty record @@ -714,19 +717,19 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, uint col_access; bool null_default_value=0; - packet->length(0); - net_store_data(packet,convert,field->field_name); + protocol->prepare_for_resend(); + protocol->store(field->field_name); field->sql_type(type); - net_store_data(packet,convert,type.ptr(),type.length()); + protocol->store(type.ptr(), type.length()); pos=(byte*) ((flags & NOT_NULL_FLAG) && field->type() != FIELD_TYPE_TIMESTAMP ? "" : "YES"); - net_store_data(packet,convert,(const char*) pos); + protocol->store((const char*) pos); pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" : (field->flags & UNIQUE_KEY_FLAG) ? "UNI" : (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":""); - net_store_data(packet,convert,(char*) pos); + protocol->store((char*) pos); if (field->type() == FIELD_TYPE_TIMESTAMP || field->unireg_check == Field::NEXT_NUMBER) @@ -735,17 +738,17 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, { // Not null by default type.set(tmp,sizeof(tmp),default_charset_info); field->val_str(&type,&type); - net_store_data(packet,convert,type.ptr(),type.length()); + protocol->store(type.ptr(),type.length()); } else if (field->maybe_null() || null_default_value) - net_store_null(packet); // Null as default + protocol->store_null(); // Null as default else - net_store_data(packet,convert,tmp,0); + protocol->store("",0); // empty string char *end=tmp; if (field->unireg_check == Field::NEXT_NUMBER) end=strmov(tmp,"auto_increment"); - net_store_data(packet,convert,tmp,(uint) (end-tmp)); + protocol->store(tmp,(uint) (end-tmp)); if (verbose) { @@ -760,10 +763,10 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, end=strmov(end,grant_types.type_names[bitnr]); } } - net_store_data(packet,convert, tmp+1,end == tmp ? 0 : (uint) (end-tmp-1)); - net_store_data(packet, field->comment.str,field->comment.length); + protocol->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1)); + protocol->store(field->comment.str, field->comment.length); } - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + if (protocol->write()) DBUG_RETURN(1); } } @@ -777,7 +780,9 @@ int mysqld_show_create(THD *thd, TABLE_LIST *table_list) { TABLE *table; - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; + char buff[2048]; + String buffer(buff, sizeof(buff), system_charset_info); DBUG_ENTER("mysqld_show_create"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->real_name)); @@ -791,51 +796,18 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) List<Item> field_list; field_list.push_back(new Item_empty_string("Table",NAME_LEN)); - field_list.push_back(new Item_empty_string("Create Table",1024)); + field_list.push_back(new Item_empty_string("Create Table", MAX_BLOB_WIDTH)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list, 1)) + DBUG_RETURN(1); + protocol->prepare_for_resend(); + protocol->store(table->table_name); + buffer.length(0); + if (store_create_info(thd, table, &buffer)) + DBUG_RETURN(-1); + protocol->store(buffer.ptr(), buffer.length()); + if (protocol->write()) DBUG_RETURN(1); - - String *packet = &thd->packet; - { - packet->length(0); - net_store_data(packet,convert, table->table_name); - /* - A hack - we need to reserve some space for the length before - we know what it is - let's assume that the length of create table - statement will fit into 3 bytes ( 16 MB max :-) ) - */ - ulong store_len_offset = packet->length(); - packet->length(store_len_offset + 4); - if (store_create_info(thd, table, packet)) - DBUG_RETURN(-1); - ulong create_len = packet->length() - store_len_offset - 4; - /* - Just in case somebody manages to create a table - with *that* much stuff in the definition - */ - if (create_len > 0x00ffffff) // better readable in HEX ... - { - /* - Just in case somebody manages to create a table - with *that* much stuff in the definition - */ - DBUG_RETURN(1); - } - - /* - Now we have to store the length in three bytes, even if it would fit - into fewer bytes, so we cannot use net_store_data() anymore, - and do it ourselves - */ - char* p = (char*)packet->ptr() + store_len_offset; - *p++ = (char) 253; // The client the length is stored using 3-bytes - int3store(p, create_len); - - // now we are in business :-) - if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length())) - DBUG_RETURN(1); - } send_eof(thd); DBUG_RETURN(0); } @@ -844,18 +816,19 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) int mysqld_show_logs(THD *thd) { + List<Item> field_list; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_logs"); - List<Item> field_list; field_list.push_back(new Item_empty_string("File",FN_REFLEN)); field_list.push_back(new Item_empty_string("Type",10)); field_list.push_back(new Item_empty_string("Status",10)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); #ifdef HAVE_BERKELEY_DB - if (!berkeley_skip && berkeley_show_logs(thd)) + if (!berkeley_skip && berkeley_show_logs(protocol)) DBUG_RETURN(-1); #endif @@ -869,7 +842,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) { TABLE *table; char buff[256]; - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_keys"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->real_name)); @@ -883,15 +856,16 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) List<Item> field_list; Item *item; field_list.push_back(new Item_empty_string("Table",NAME_LEN)); - field_list.push_back(new Item_int("Non_unique",0,1)); + field_list.push_back(new Item_return_int("Non_unique",1, MYSQL_TYPE_TINY)); field_list.push_back(new Item_empty_string("Key_name",NAME_LEN)); - field_list.push_back(new Item_int("Seq_in_index",0,2)); + field_list.push_back(new Item_return_int("Seq_in_index",2, MYSQL_TYPE_TINY)); field_list.push_back(new Item_empty_string("Column_name",NAME_LEN)); field_list.push_back(item=new Item_empty_string("Collation",1)); item->maybe_null=1; field_list.push_back(item=new Item_int("Cardinality",0,21)); item->maybe_null=1; - field_list.push_back(item=new Item_int("Sub_part",0,3)); + field_list.push_back(item=new Item_return_int("Sub_part",3, + MYSQL_TYPE_TINY)); item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Packed",10)); item->maybe_null=1; @@ -900,7 +874,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) field_list.push_back(new Item_empty_string("Comment",255)); item->maybe_null=1; - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); String *packet= &thd->packet; @@ -909,54 +883,48 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) for (uint i=0 ; i < table->keys ; i++,key_info++) { KEY_PART_INFO *key_part= key_info->key_part; - char *end; + const char *str; for (uint j=0 ; j < key_info->key_parts ; j++,key_part++) { - packet->length(0); - net_store_data(packet,convert,table->table_name); - net_store_data(packet,convert,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1); - net_store_data(packet,convert,key_info->name); - end=int10_to_str((long) (j+1),(char*) buff,10); - net_store_data(packet,convert,buff,(uint) (end-buff)); - net_store_data(packet,convert, - key_part->field ? key_part->field->field_name : - "?unknown field?"); + protocol->prepare_for_resend(); + protocol->store(table->table_name); + protocol->store_tiny((longlong) ((key_info->flags & HA_NOSAME) ? 0 :1)); + protocol->store(key_info->name); + protocol->store_tiny((longlong) (j+1)); + str=(key_part->field ? key_part->field->field_name : + "?unknown field?"); + protocol->store(str); if (table->file->index_flags(i) & HA_READ_ORDER) - net_store_data(packet,convert, - ((key_part->key_part_flag & HA_REVERSE_SORT) ? - "D" : "A"), 1); + protocol->store(((key_part->key_part_flag & HA_REVERSE_SORT) ? + "D" : "A"), 1); else - net_store_null(packet); /* purecov: inspected */ + protocol->store_null(); /* purecov: inspected */ KEY *key=table->key_info+i; if (key->rec_per_key[j]) { ha_rows records=(table->file->records / key->rec_per_key[j]); - end=longlong10_to_str((longlong) records, buff, 10); - net_store_data(packet,convert,buff,(uint) (end-buff)); + protocol->store((ulonglong) records); } else - net_store_null(packet); + protocol->store_null(); /* Check if we have a key part that only uses part of the field */ if (!key_part->field || key_part->length != table->field[key_part->fieldnr-1]->key_length()) - { - end=int10_to_str((long) key_part->length, buff,10); /* purecov: inspected */ - net_store_data(packet,convert,buff,(uint) (end-buff)); /* purecov: inspected */ - } + protocol->store_tiny((longlong) key_part->length); else - net_store_null(packet); - net_store_null(packet); // No pack_information yet + protocol->store_null(); + protocol->store_null(); // No pack_information yet /* Null flag */ uint flags= key_part->field ? key_part->field->flags : 0; char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES"); - net_store_data(packet,convert,(const char*) pos); - net_store_data(packet,convert,table->file->index_type(i)); + protocol->store((const char*) pos); + protocol->store(table->file->index_type(i)); /* Comment */ - net_store_data(packet,convert,""); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->store("", 0); + if (protocol->write()) DBUG_RETURN(1); /* purecov: inspected */ } } @@ -992,7 +960,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) field_list.push_back(new Item_field(field)); } restore_record(table,2); // Get empty record - if (send_fields(thd,field_list,2)) + if (thd->protocol->send_fields(&field_list,2)) DBUG_VOID_RETURN; VOID(net_flush(&thd->net)); DBUG_VOID_RETURN; @@ -1002,20 +970,20 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) int mysqld_dump_create_info(THD *thd, TABLE *table, int fd) { - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; + String *packet= protocol->storage_packet(); DBUG_ENTER("mysqld_dump_create_info"); DBUG_PRINT("enter",("table: %s",table->real_name)); - String *packet = &thd->packet; - packet->length(0); - if (store_create_info(thd,table,packet)) + protocol->prepare_for_resend(); + if (store_create_info(thd, table, packet)) DBUG_RETURN(-1); - if (convert) - convert->convert((char*) packet->ptr(), packet->length()); + if (protocol->convert) + protocol->convert->convert((char*) packet->ptr(), packet->length()); if (fd < 0) { - if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length())) + if (protocol->write()) DBUG_RETURN(-1); VOID(net_flush(&thd->net)); } @@ -1278,21 +1246,21 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) I_List<thread_info> thread_infos; ulong max_query_length= (verbose ? thd->variables.max_allowed_packet : PROCESS_LIST_WIDTH); - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_list_processes"); - field_list.push_back(new Item_int("Id",0,7)); + field_list.push_back(new Item_int("Id",0,11)); field_list.push_back(new Item_empty_string("User",16)); field_list.push_back(new Item_empty_string("Host",64)); field_list.push_back(field=new Item_empty_string("db",NAME_LEN)); field->maybe_null=1; field_list.push_back(new Item_empty_string("Command",16)); - field_list.push_back(new Item_empty_string("Time",7)); + field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG)); field_list.push_back(field=new Item_empty_string("State",30)); field->maybe_null=1; field_list.push_back(field=new Item_empty_string("Info",max_query_length)); field->maybe_null=1; - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_VOID_RETURN; VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list @@ -1358,37 +1326,26 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) VOID(pthread_mutex_unlock(&LOCK_thread_count)); thread_info *thd_info; - String *packet= &thd->packet; + time_t now= time(0); while ((thd_info=thread_infos.get())) { char buff[20],*end; - packet->length(0); - end=int10_to_str((long) thd_info->thread_id, buff,10); - net_store_data(packet,convert,buff,(uint) (end-buff)); - net_store_data(packet,convert,thd_info->user); - net_store_data(packet,convert,thd_info->host); - if (thd_info->db) - net_store_data(packet,convert,thd_info->db); - else - net_store_null(packet); + protocol->prepare_for_resend(); + protocol->store((ulonglong) thd_info->thread_id); + protocol->store(thd_info->user); + protocol->store(thd_info->host); + protocol->store(thd_info->db); if (thd_info->proc_info) - net_store_data(packet,convert,thd_info->proc_info); + protocol->store(thd_info->proc_info); else - net_store_data(packet,convert,command_name[thd_info->command]); + protocol->store(command_name[thd_info->command]); if (thd_info->start_time) - net_store_data(packet, - (uint32) (time((time_t*) 0) - thd_info->start_time)); - else - net_store_null(packet); - if (thd_info->state_info) - net_store_data(packet,convert,thd_info->state_info); - else - net_store_null(packet); - if (thd_info->query) - net_store_data(packet,convert,thd_info->query); + protocol->store((uint32) (now - thd_info->start_time)); else - net_store_null(packet); - if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + protocol->store_null(); + protocol->store(thd_info->state_info); + protocol->store(thd_info->query); + if (protocol->write()) break; /* purecov: inspected */ } send_eof(thd); @@ -1405,16 +1362,16 @@ int mysqld_show_charsets(THD *thd, const char *wild) char buff[8192]; String packet2(buff,sizeof(buff),default_charset_info); List<Item> field_list; - CONVERT *convert=thd->variables.convert_set; CHARSET_INFO **cs; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysqld_show_charsets"); field_list.push_back(new Item_empty_string("Name",30)); - field_list.push_back(new Item_int("Id",0,7)); - field_list.push_back(new Item_int("strx_maxlen",0,7)); - field_list.push_back(new Item_int("mb_maxlen",0,7)); + field_list.push_back(new Item_return_int("Id",11, FIELD_TYPE_SHORT)); + field_list.push_back(new Item_return_int("strx_maxlen",3, FIELD_TYPE_TINY)); + field_list.push_back(new Item_return_int("mb_maxlen",3, FIELD_TYPE_TINY)); - if (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(1); for (cs=all_charsets ; cs < all_charsets+255 ; cs++ ) @@ -1424,14 +1381,13 @@ int mysqld_show_charsets(THD *thd, const char *wild) if (!(wild && wild[0] && wild_case_compare(system_charset_info,cs[0]->name,wild))) { - packet2.length(0); - net_store_data(&packet2,convert,cs[0]->name); - net_store_data(&packet2,(uint32) cs[0]->number); - net_store_data(&packet2,(uint32) cs[0]->strxfrm_multiply); - net_store_data(&packet2,(uint32) (cs[0]->mbmaxlen)); - - if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length())) - goto err; + protocol->prepare_for_resend(); + protocol->store(cs[0]->name); + protocol->store_short((longlong) cs[0]->number); + protocol->store_tiny((longlong) cs[0]->strxfrm_multiply); + protocol->store_tiny((longlong) cs[0]->mbmaxlen); + if (protocol->write()) + goto err; } } send_eof(thd); @@ -1445,15 +1401,14 @@ err: int mysqld_show(THD *thd, const char *wild, show_var_st *variables, enum enum_var_type value_type) { - char buff[8192]; - String packet2(buff,sizeof(buff), system_charset_info); + char buff[1024]; List<Item> field_list; - CONVERT *convert=thd->variables.convert_set; + Protocol *protocol= thd->protocol; 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 (send_fields(thd,field_list,1)) + if (protocol->send_fields(&field_list,1)) DBUG_RETURN(1); /* purecov: inspected */ /* pthread_mutex_lock(&THR_LOCK_keycache); */ @@ -1463,232 +1418,248 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, if (!(wild && wild[0] && wild_case_compare(system_charset_info, variables->name,wild))) { - packet2.length(0); - net_store_data(&packet2,convert,variables->name); + protocol->prepare_for_resend(); + protocol->store(variables->name); SHOW_TYPE show_type=variables->type; char *value=variables->value; + const char *pos, *end; + long nr; + if (show_type == SHOW_SYS) { show_type= ((sys_var*) value)->type(); value= (char*) ((sys_var*) value)->value_ptr(thd, value_type); } + pos= end= buff; switch (show_type) { case SHOW_LONG: case SHOW_LONG_CONST: - net_store_data(&packet2,(uint32) *(ulong*) value); + end= int10_to_str(*(long*) value, buff, 10); break; case SHOW_LONGLONG: - net_store_data(&packet2,(longlong) *(longlong*) value); + end= longlong10_to_str(*(longlong*) value, buff, 10); break; case SHOW_BOOL: - net_store_data(&packet2,(ulong) *(bool*) value ? "ON" : "OFF"); + end= strmov(buff, *(bool*) value ? "ON" : "OFF"); break; case SHOW_MY_BOOL: - net_store_data(&packet2,(ulong) *(my_bool*) value ? "ON" : "OFF"); + end= strmov(buff, *(my_bool*) value ? "ON" : "OFF"); break; case SHOW_INT_CONST: case SHOW_INT: - net_store_data(&packet2,(uint32) *(int*) value); + end= int10_to_str((long) *(uint32*) value, buff, 10); break; case SHOW_HAVE: { SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value; - net_store_data(&packet2, show_comp_option_name[(int) tmp]); + pos= show_comp_option_name[(int) tmp]; + end= strend(pos); break; } case SHOW_CHAR: - net_store_data(&packet2,convert, value); + pos= value; + end= strend(pos); break; case SHOW_STARTTIME: - net_store_data(&packet2,(uint32) (thd->query_start() - start_time)); + nr= (long) (thd->query_start() - start_time); + end= int10_to_str(nr, buff, 10); break; case SHOW_QUESTION: - net_store_data(&packet2,(uint32) thd->query_id); + end= int10_to_str((long) thd->query_id, buff, 10); break; case SHOW_RPL_STATUS: - net_store_data(&packet2, rpl_status_type[(int)rpl_status]); + end= int10_to_str((long) rpl_status_type[(int)rpl_status], buff, 10); break; case SHOW_SLAVE_RUNNING: { LOCK_ACTIVE_MI; - net_store_data(&packet2, (active_mi->slave_running && - active_mi->rli.slave_running) - ? "ON" : "OFF"); + end= strmov(buff, (active_mi->slave_running && + active_mi->rli.slave_running) ? "ON" : "OFF"); UNLOCK_ACTIVE_MI; break; } case SHOW_OPENTABLES: - net_store_data(&packet2,(uint32) cached_tables()); + end= int10_to_str((long) cached_tables(), buff, 10); break; case SHOW_CHAR_PTR: { - value= *(char**) value; - net_store_data(&packet2,convert, value ? value : ""); + if (!(pos= *(char**) value)) + pos= ""; + end= strend(pos); break; } #ifdef HAVE_OPENSSL /* First group - functions relying on CTX */ case SHOW_SSL_CTX_SESS_ACCEPT: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_accept(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_accept(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_ACCEPT_GOOD: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_accept_good(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_accept_good(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_CONNECT_GOOD: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect_good(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_connect_good(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_CB_HITS: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_cb_hits(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_cb_hits(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_HITS: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_hits(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_hits(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_CACHE_FULL: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_cache_full(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_cache_full(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_MISSES: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_misses(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_misses(ssl_acceptor_fd-> + ssl_context_)), + buff, 10); break; case SHOW_SSL_CTX_SESS_TIMEOUTS: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_)), + buff,10); break; case SHOW_SSL_CTX_SESS_NUMBER: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_)), + buff,10); break; case SHOW_SSL_CTX_SESS_CONNECT: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_)), + buff,10); break; case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_)), + buff,10); break; case SHOW_SSL_CTX_GET_VERIFY_MODE: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_)), + buff,10); break; case SHOW_SSL_CTX_GET_VERIFY_DEPTH: - net_store_data(&packet2,(uint32) - (!ssl_acceptor_fd ? 0 : - SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_))); + end= int10_to_str((long) (!ssl_acceptor_fd ? 0 : + SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_)), + buff,10); break; case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE: if (!ssl_acceptor_fd) { - net_store_data(&packet2,"NONE" ); + pos= "NONE"; + end= pos+4; break; } switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context_)) { case SSL_SESS_CACHE_OFF: - net_store_data(&packet2,"OFF" ); + pos= "OFF"; break; case SSL_SESS_CACHE_CLIENT: - net_store_data(&packet2,"CLIENT" ); + pos= "CLIENT"; break; case SSL_SESS_CACHE_SERVER: - net_store_data(&packet2,"SERVER" ); + pos= "SERVER"; break; case SSL_SESS_CACHE_BOTH: - net_store_data(&packet2,"BOTH" ); + pos= "BOTH"; break; case SSL_SESS_CACHE_NO_AUTO_CLEAR: - net_store_data(&packet2,"NO_AUTO_CLEAR" ); + pos= "NO_AUTO_CLEAR"; break; case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP: - net_store_data(&packet2,"NO_INTERNAL_LOOKUP" ); + pos= "NO_INTERNAL_LOOKUP"; break; default: - net_store_data(&packet2,"Unknown"); + pos= "Unknown"; break; } + pos= strend(pos); break; /* First group - functions relying on SSL */ case SHOW_SSL_GET_VERSION: - net_store_data(&packet2, thd->net.vio->ssl_ ? - SSL_get_version(thd->net.vio->ssl_) : ""); + pos= thd->net.vio->ssl_ ? SSL_get_version(thd->net.vio->ssl_) : ""; + end= strend(pos); break; case SHOW_SSL_SESSION_REUSED: - net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ? - SSL_session_reused(thd->net.vio->ssl_) : 0)); + end= int10_to_str((long) (thd->net.vio->ssl_ ? + SSL_session_reused(thd->net.vio->ssl_): + 0), buff, 10); break; case SHOW_SSL_GET_DEFAULT_TIMEOUT: - net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ? - SSL_get_default_timeout(thd->net.vio->ssl_):0)); + end= int10_to_str((long) (thd->net.vio->ssl_ ? + SSL_get_default_timeout(thd->net.vio->ssl_): + 0), buff, 10); break; case SHOW_SSL_GET_VERIFY_MODE: - net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ? - SSL_get_verify_mode(thd->net.vio->ssl_):0)); + end= int10_to_str((long) (thd->net.vio->ssl_ ? + SSL_get_verify_mode(thd->net.vio->ssl_): + 0), buff, 10); break; case SHOW_SSL_GET_VERIFY_DEPTH: - net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ? - SSL_get_verify_depth(thd->net.vio->ssl_):0)); + end= int10_to_str((long) (thd->net.vio->ssl_ ? + SSL_get_verify_depth(thd->net.vio->ssl_): + 0), buff, 10); break; case SHOW_SSL_GET_CIPHER: - net_store_data(&packet2, thd->net.vio->ssl_ ? - SSL_get_cipher(thd->net.vio->ssl_) : ""); + pos= thd->net.vio->ssl_ ? SSL_get_cipher(thd->net.vio->ssl_) : ""; + end= strend(pos); break; case SHOW_SSL_GET_CIPHER_LIST: if (thd->net.vio->ssl_) { - char buf[1024], *pos; - pos=buf; + char *to= buff; for (int i=0 ; i++ ;) { - const char *p=SSL_get_cipher_list(thd->net.vio->ssl_,i); + const char *p= SSL_get_cipher_list(thd->net.vio->ssl_,i); if (p == NULL) break; - pos=strmov(pos, p); - *pos++= ':'; + to= strmov(to, p); + *to++= ':'; } - if (pos != buf) - pos--; // Remove last ':' - *pos=0; - net_store_data(&packet2, buf); + if (to != buff) + to--; // Remove last ':' + end= to; } - else - net_store_data(&packet2, ""); break; #endif /* HAVE_OPENSSL */ case SHOW_UNDEF: // Show never happen case SHOW_SYS: - net_store_data(&packet2, ""); // Safety - break; + break; // Return empty string } - if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length())) + if (protocol->store(pos, (uint32) (end - pos)) || + protocol->write()) goto err; /* purecov: inspected */ } } diff --git a/sql/sql_string.h b/sql/sql_string.h index dde67b11d50..d7447dd6ed6 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -255,4 +255,29 @@ public: void qs_append(double d); void qs_append(double *d); void qs_append(const char &c); + + /* Inline (general) functions used by the protocol functions */ + + inline char *prep_append(uint32 arg_length, uint32 step_alloc) + { + uint32 new_length= arg_length + str_length; + if (new_length > Alloced_length) + { + if (realloc(new_length + step_alloc)) + return 0; + } + uint32 old_length= str_length; + str_length+= arg_length; + return Ptr+ old_length; /* Area to use */ + } + + inline bool append(const char *s, uint32 arg_length, uint32 step_alloc) + { + uint32 new_length= arg_length + str_length; + if (new_length > Alloced_length && realloc(new_length + step_alloc)) + return TRUE; + memcpy(Ptr+str_length, s, arg_length); + str_length+= arg_length; + return FALSE; + } }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index d343ccd39f5..1ab84531e40 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1017,20 +1017,18 @@ bool close_cached_table(THD *thd,TABLE *table) DBUG_RETURN(result); } -static int send_check_errmsg(THD* thd, TABLE_LIST* table, +static int send_check_errmsg(THD *thd, TABLE_LIST* table, const char* operator_name, const char* errmsg) { - - String* packet = &thd->packet; - packet->length(0); - net_store_data(packet, table->alias); - net_store_data(packet, (char*)operator_name); - net_store_data(packet, "error"); - net_store_data(packet, errmsg); + Protocol *protocol= thd->protocol; + protocol->prepare_for_resend(); + protocol->store(table->alias); + protocol->store((char*) operator_name); + protocol->store("error", 5); + protocol->store(errmsg); thd->net.last_error[0]=0; - if (my_net_write(&thd->net, (char*) thd->packet.ptr(), - packet->length())) + if (protocol->write()) return -1; return 1; } @@ -1176,8 +1174,8 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, { TABLE_LIST *table; List<Item> field_list; - Item* item; - String* packet = &thd->packet; + Item *item; + Protocol *protocol= thd->protocol; DBUG_ENTER("mysql_admin_table"); field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2)); @@ -1188,7 +1186,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, item->maybe_null = 1; field_list.push_back(item = new Item_empty_string("Msg_text", 255)); item->maybe_null = 1; - if (send_fields(thd, field_list, 1)) + if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); for (table = tables; table; table = table->next) @@ -1201,7 +1199,8 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, thd->open_options|= extra_open_options; table->table = open_ltable(thd, table, lock_type); thd->open_options&= ~extra_open_options; - packet->length(0); + protocol->prepare_for_resend(); + if (prepare_func) { switch ((*prepare_func)(thd, table, check_opt)) { @@ -1214,30 +1213,30 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, if (!table->table) { const char *err_msg; - net_store_data(packet, table_name); - net_store_data(packet, operator_name); - net_store_data(packet, "error"); + protocol->prepare_for_resend(); + protocol->store(table_name); + protocol->store(operator_name); + protocol->store("error",5); if (!(err_msg=thd->net.last_error)) err_msg=ER(ER_CHECK_NO_SUCH_TABLE); - net_store_data(packet, err_msg); + protocol->store(err_msg); thd->net.last_error[0]=0; - if (my_net_write(&thd->net, (char*) thd->packet.ptr(), - packet->length())) + if (protocol->write()) goto err; continue; } if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify) { char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE]; - net_store_data(packet, table_name); - net_store_data(packet, operator_name); - net_store_data(packet, "error"); + protocol->prepare_for_resend(); + protocol->store(table_name); + protocol->store(operator_name); + protocol->store("error", 5); sprintf(buff, ER(ER_OPEN_AS_READONLY), table_name); - net_store_data(packet, buff); + protocol->store(buff); close_thread_tables(thd); table->table=0; // For query cache - if (my_net_write(&thd->net, (char*) thd->packet.ptr(), - packet->length())) + if (protocol->write()) goto err; continue; } @@ -1265,50 +1264,50 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, } int result_code = (table->table->file->*operator_func)(thd, check_opt); - packet->length(0); - net_store_data(packet, table_name); - net_store_data(packet, operator_name); + protocol->prepare_for_resend(); + protocol->store(table_name); + protocol->store(operator_name); switch (result_code) { case HA_ADMIN_NOT_IMPLEMENTED: { char buf[ERRMSGSIZE+20]; - my_snprintf(buf, ERRMSGSIZE, - ER(ER_CHECK_NOT_IMPLEMENTED), operator_name); - net_store_data(packet, "error"); - net_store_data(packet, buf); + uint length=my_snprintf(buf, ERRMSGSIZE, + ER(ER_CHECK_NOT_IMPLEMENTED), operator_name); + protocol->store("error", 5); + protocol->store(buf, length); } break; case HA_ADMIN_OK: - net_store_data(packet, "status"); - net_store_data(packet, "OK"); + protocol->store("status", 6); + protocol->store("OK",2); break; case HA_ADMIN_FAILED: - net_store_data(packet, "status"); - net_store_data(packet, "Operation failed"); + protocol->store("status", 6); + protocol->store("Operation failed",16); break; case HA_ADMIN_ALREADY_DONE: - net_store_data(packet, "status"); - net_store_data(packet, "Table is already up to date"); + protocol->store("status", 6); + protocol->store("Table is already up to date", 27); break; case HA_ADMIN_CORRUPT: - net_store_data(packet, "error"); - net_store_data(packet, "Corrupt"); + protocol->store("error", 5); + protocol->store("Corrupt", 8); fatal_error=1; break; case HA_ADMIN_INVALID: - net_store_data(packet, "error"); - net_store_data(packet, "Invalid argument"); + protocol->store("error", 5); + protocol->store("Invalid argument",16); break; default: // Probably HA_ADMIN_INTERNAL_ERROR - net_store_data(packet, "error"); - net_store_data(packet, "Unknown - internal error during operation"); + protocol->store("error", 5); + protocol->store("Unknown - internal error during operation", 41); fatal_error=1; break; } @@ -1325,8 +1324,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, } close_thread_tables(thd); table->table=0; // For query cache - if (my_net_write(&thd->net, (char*) packet->ptr(), - packet->length())) + if (protocol->write()) goto err; } diff --git a/sql/structs.h b/sql/structs.h index 7873de4db63..604be6fcc6e 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -113,7 +113,8 @@ enum timestamp_type { TIMESTAMP_NONE, TIMESTAMP_DATE, TIMESTAMP_FULL, TIMESTAMP_TIME }; typedef struct st_time { - uint year,month,day,hour,minute,second,second_part; + uint year,month,day,hour,minute,second; + ulong second_part; bool neg; timestamp_type time_type; } TIME; diff --git a/sql/time.cc b/sql/time.cc index 0811b896bfc..282075df9eb 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -724,3 +724,20 @@ bool str_to_time(const char *str,uint length,TIME *l_time) } return 0; } + + +/* + Convert a system time structure to TIME +*/ + +void localtime_to_TIME(TIME *to, struct tm *from) +{ + to->neg=0; + to->second_part=0; + to->year= (int) ((from->tm_year+1900) % 10000); + to->month= (int) from->tm_mon+1; + to->day= (int) from->tm_mday; + to->hour= (int) from->tm_hour; + to->minute= (int) from->tm_min; + to->second= (int) from->tm_sec; +} diff --git a/tests/fork_big2.pl b/tests/fork_big2.pl new file mode 100644 index 00000000000..b552b95ba6b --- /dev/null +++ b/tests/fork_big2.pl @@ -0,0 +1,705 @@ +#!/usr/bin/perl -w +# +# This is a test with uses many processes to test a MySQL server. +# +# Tested a lot with: --threads=30 + +$opt_loop_count=500000; # Change this to make test harder/easier + +##################### Standard benchmark inits ############################## + +use DBI; +use Getopt::Long; +use Benchmark; + +package main; + +$opt_skip_create=$opt_skip_in=$opt_verbose=$opt_fast_insert= +$opt_lock_tables=$opt_debug=$opt_skip_drop=$opt_fast=$opt_force=0; +$opt_thread_factor=1;
+$opt_insert=1;
+$opt_select=6;$opt_join=4;
+$opt_select_count=$opt_join_count=0;
+$opt_update=1;$opt_delete=0;
+$opt_flush=$opt_check=$opt_repair=$opt_alter=0;
+$opt_join_range=100;
+$opt_time=0; +$opt_host=$opt_user=$opt_password=""; $opt_db="test"; + +GetOptions("host=s","db=s","user=s","password=s","loop-count=i","skip-create","skip-in","skip-drop",
+ "verbose","fast-insert","lock-tables","debug","fast","force","thread-factor=i",
+ "insert=i", "select=i", "join=i", "select-count=i", "join-count=i", "update=i", "delete=i",
+ "flush=i", "check=i", "repair=i", "alter=i", "max-join_range=i", "time=i") || die "Aborted"; +$opt_verbose=$opt_debug=$opt_lock_tables=$opt_fast_insert=$opt_fast=$opt_skip_in=$opt_force=undef; # Ignore warnings from these + +print "Test of multiple connections that test the following things:\n"; +print "insert, select, delete, update, alter, check, repair and flush\n"; + +@testtables = ( ["bench_f31", ""], + ["bench_f32", "row_format=fixed"], + ["bench_f33", "delay_key_write=1"], + ["bench_f34", "checksum=1"], + ["bench_f35", "delay_key_write=1"]); +$abort_table="bench_f39"; + +$numtables = $#testtables+1; +srand 100; # Make random numbers repeatable + +#### +#### Start timeing and start test +####
+
+$opt_insert*=$opt_thread_factor; +$opt_select*=$opt_thread_factor;
+$opt_join*=$opt_thread_factor;
+$opt_select_count*=$opt_thread_factor;
+$opt_join_count*=$opt_thread_factor;
+$opt_update*=$opt_thread_factor;
+$opt_delete*=$opt_thread_factor;
+
+if ($opt_time == 0 && $opt_insert == 0)
+{
+ $opt_insert=1;
+}
+ +$start_time=new Benchmark; +$dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; +if (!$opt_skip_create) +{ + my $table_def; + foreach $table_def (@testtables) + { + my ($table,$extra)= ($table_def->[0], $table_def->[1]); + print "Creating table $table in database $opt_db\n"; + $dbh->do("drop table if exists $table"); + $dbh->do("create table $table". + " (id int(6) not null auto_increment,". + " info varchar(32)," . + " marker timestamp," . + " flag int not null," . + " primary key(id)) $extra") + + or die $DBI::errstr; + # One row in the table will make future tests easier + $dbh->do("insert into $table (id) values (null)") + or die $DBI::errstr; + } + # Create the table we use to signal that we should end the test + $dbh->do("drop table if exists $abort_table"); + $dbh->do("create table $abort_table (id int(6) not null) type=heap") || + die $DBI::errstr; +} + +$dbh->do("delete from $abort_table"); +$dbh->disconnect; $dbh=0; # Close handler +$|= 1; # Autoflush + +#### +#### Start the tests +#### +if ($opt_time != 0)
+{
+ test_abort() if (($pid=fork()) == 0); $work{$pid}="abort";
+} +for ($i=0 ; $i < $opt_insert ; $i ++) +{ + test_insert() if (($pid=fork()) == 0); $work{$pid}="insert"; +}
+$threads=$i; +for ($i=0 ; $i < $opt_select ; $i ++)
+{
+ test_select() if (($pid=fork()) == 0); $work{$pid}="select";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_join ; $i ++)
+{
+ test_join() if (($pid=fork()) == 0); $work{$pid}="join";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_select_count ; $i ++) +{ + test_select_count() if (($pid=fork()) == 0); $work{$pid}="select_count"; +} +$threads+=$i;
+for ($i=0 ; $i < $opt_join_count ; $i ++)
+{
+ test_join_count() if (($pid=fork()) == 0); $work{$pid}="join_count";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_update ; $i ++)
+{
+ test_update() if (($pid=fork()) == 0); $work{$pid}="update";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_delete ; $i ++)
+{
+ test_delete() if (($pid=fork()) == 0); $work{$pid}="delete";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_flush ; $i ++)
+{
+ test_flush() if (($pid=fork()) == 0); $work{$pid}="flush";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_check ; $i ++)
+{
+ test_check() if (($pid=fork()) == 0); $work{$pid}="check";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_repair ; $i ++)
+{
+ test_repair() if (($pid=fork()) == 0); $work{$pid}="repair";
+}
+$threads+=$i;
+for ($i=0 ; $i < $opt_alter ; $i ++)
+{
+ test_alter() if (($pid=fork()) == 0); $work{$pid}="alter";
+}
+$threads+=$i;
+
+print "Started $threads threads\n"; + +$errors=0; +$running_insert_threads=$opt_insert; +while (($pid=wait()) != -1) +{ + $ret=$?/256; + print "thread '" . $work{$pid} . "' finished with exit code $ret\n";
+ if ($opt_time == 0)
+ { + if ($work{$pid} =~ /^insert/) + { + if (!--$running_insert_threads) + {
+
+ # Time to stop other threads + signal_abort(); + }
+ } + } + $errors++ if ($ret != 0); +} + +# +# Cleanup +# + +if (!$opt_skip_drop && !$errors) +{ + my $table_def; + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $dbh->do("drop table $abort_table"); + foreach $table_def (@testtables) + { + $dbh->do("drop table " . $table_def->[0]); + } + $dbh->disconnect; $dbh=0; # Close handler +} + +print ($errors ? "Test failed\n" :"Test ok\n"); +$end_time=new Benchmark; +print "Total time: " . + timestr(timediff($end_time, $start_time),"noc") . "\n"; + +exit(0); + +#
+# Sleep and then abort other threads
+#
+
+sub test_abort
+{
+ sleep($opt_time);
+ signal_abort();
+ exit(0);
+}
+
+ +# +# Insert records in the table +# + +sub test_insert +{ + my ($from_table,$to_table)= @_; + my ($dbh,$i,$j,$count,$table_def,$table); + + if (!defined($from_table)) + { + $from_table=0; $to_table=$numtables-1; + } + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + for ($i=$count=0 ; $i < $opt_loop_count; $i++) + { + for ($j= $from_table ; $j <= $to_table ; $j++) + { + my ($table)= ($testtables[$j]->[0]); + $dbh->do("insert into $table values (NULL,'This is entry $i','',0)") || die "Got error on insert: $DBI::errstr\n"; + $count++; + } + } + $dbh->disconnect; $dbh=0; + print "Test_insert: Inserted $count rows\n"; + exit(0); +} + + +# +# select records +# Do continously select over all tables as long as there is changed +# rows in the table +# + +sub test_select +{ + my ($dbh, $i, $j, $count, $loop); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $count_query=make_count_query($numtables); + $count=0; + $loop=9999; + + $i=0; + while (($i++ % 100) || !test_if_abort($dbh)) + { + if ($loop++ >= 100) + { + $loop=0; + $row_counts=simple_query($dbh, $count_query); + } + for ($j=0 ; $j < $numtables ; $j++) + { + my ($id)= int rand $row_counts->[$j]; + my ($table)= $testtables[$j]->[0]; + simple_query($dbh, "select id,info from $table where id=$id"); + $count++; + } + } + $dbh->disconnect; $dbh=0; + print "Test_select: Executed $count selects\n"; + exit(0); +} + +# +# Do big select count(distinct..) over the table +# + +sub test_select_count +{ + my ($dbh, $i, $j, $count, $loop); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $count=0; + $i=0; + while (!test_if_abort($dbh)) + { + for ($j=0 ; $j < $numtables ; $j++) + { + my ($table)= $testtables[$j]->[0]; + simple_query($dbh, "select count(distinct marker),count(distinct id),count(distinct info) from $table"); + $count++; + } + sleep(20); # This query is quite slow + } + $dbh->disconnect; $dbh=0; + print "Test_select: Executed $count select count(distinct) queries\n"; + exit(0); +} + +# +# select records +# Do continously joins between the first and second table +# + +sub test_join +{ + my ($dbh, $i, $j, $count, $loop); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $count_query=make_count_query($numtables); + $count=0; + $loop=9999; + + $i=0; + while (($i++ % 100) || !test_if_abort($dbh)) + { + if ($loop++ >= 100) + { + $loop=0; + $row_counts=simple_query($dbh, $count_query); + } + for ($j=0 ; $j < $numtables-1 ; $j++) + { + my ($id)= int rand $row_counts->[$j]; + my ($t1,$t2)= ($testtables[$j]->[0],$testtables[$j+1]->[0]); + simple_query($dbh, "select $t1.id,$t2.info from $t1, $t2 where $t1.id=$t2.id and $t1.id=$id"); + $count++; + } + } + $dbh->disconnect; $dbh=0; + print "Test_join: Executed $count joins\n"; + exit(0); +}
+
+#
+# select records
+# Do continously joins between the first and second for range and count selected rows
+#
+
+sub test_join_count
+{
+ my ($dbh, $i, $j, $count, $loop);
+
+ $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host",
+ $opt_user, $opt_password,
+ { PrintError => 0}) || die $DBI::errstr;
+
+ $count_query=make_count_query($numtables);
+ $count=0;
+ $loop=9999;
+ $sum=0;
+
+ srand();
+
+ $i=0;
+ while (($i++ % 10) || !test_if_abort($dbh))
+ {
+ if ($loop++ >= 10)
+ {
+ $loop=0;
+ $row_counts=simple_query($dbh, $count_query);
+ }
+ for ($j=0 ; $j < $numtables-1 ; $j++)
+ {
+ my ($id1)= int rand $row_counts->[$j];
+ my ($id2)= int rand $row_counts->[$j];
+ if ($id1 > $id2)
+ {
+ my $id0=$id1; $id1=$id2; $id2=$id0;
+ if ($id2-$id1 > $opt_join_range)
+ {
+ $id2=$id1+$opt_join_range;
+ }
+ }
+ my ($t1,$t2)= ($testtables[$j]->[0],$testtables[$j+1]->[0]);
+ $row=simple_query($dbh, "select count(*) from $t1, $t2 where $t1.id=$t2.id and $t1.id between $id1 and $id2");
+ $sum+=$row->[0];
+ $count++;
+ }
+ }
+ $dbh->disconnect; $dbh=0;
+ print "Test_join_count: Executed $count joins: total $sum rows\n";
+ exit(0);
+}
+ + +# +# Delete 1-5 rows from the first 2 tables. +# Test ends when the number of rows for table 3 didn't change during +# one loop +# + +sub test_delete +{ + my ($dbh, $i,$j, $row_counts, $count_query, $table_count, $count); + + $table_count=2; + $count=0; + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $count_query=make_count_query($table_count+1); + + sleep(5); # Give time to insert some rows + $i=0; + while (($i++ % 10) || !test_if_abort($dbh)) + { + sleep(1); + $row_counts=simple_query($dbh, $count_query); + + for ($j=0 ; $j < $table_count ; $j++) + { + my ($id)= int rand $row_counts->[$j]; + my ($table)= $testtables[$j]->[0]; + $dbh->do("delete from $table where id >= $id-2 and id <= $id +2") || die "Got error on delete from $table: $DBI::errstr\n"; + $count++; + } + } + $dbh->disconnect; $dbh=0; + print "Test_delete: Executed $count deletes\n"; + exit(0); +} + +# +# Update the flag for table 2 and 3 +# Will abort after a while when table1 doesn't change max value +# + +sub test_update +{ + my ($dbh, $i, $j, $row_counts, $count_query, $count, $loop); + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $count_query=make_count_query(3); + $loop=9999; + $count=0; + + sleep(5); # Give time to insert some rows + $i=0; + while (($i++ % 100) || !test_if_abort($dbh)) + { + if ($loop++ >= 100) + { + $loop=0; + $row_counts=simple_query($dbh, $count_query); + } + + for ($j=1 ; $j <= 2 ; $j++) + { + my ($id)= int rand $row_counts->[$j]; + my ($table)= $testtables[$j]->[0]; + # Fix to not change the same rows as the above delete + $id= ($id + $count) % $row_counts->[$j]; + + $dbh->do("update $table set flag=flag+1 where id >= $id-2 and id <= $id +2") || die "Got error on update of $table: $DBI::errstr\n"; + $count++; + } + } + $dbh->disconnect; $dbh=0; + print "Test_update: Executed $count updates\n"; + exit(0); +} + + +# +# Run a check on all tables except the last one +# (The last one is not checked to put pressure on the key cache) +# + +sub test_check +{ + my ($dbh, $row, $i, $j, $type, $table); + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $type= "check"; + for ($i=$j=0 ; !test_if_abort($dbh) ; $i++) + { + sleep(1000); + $table=$testtables[$j]->[0]; + $sth=$dbh->prepare("$type table $table") || die "Got error on prepare: $DBI::errstr\n"; + $sth->execute || die $DBI::errstr; + + while (($row=$sth->fetchrow_arrayref)) + { + if ($row->[3] ne "OK") + { + print "Got error " . $row->[3] . " when doing $type on $table\n"; + exit(1); + } + } + if (++$j == $numtables-1) + { + $j=0; + } + } + $dbh->disconnect; $dbh=0; + print "test_check: Executed $i checks\n"; + exit(0); +} + +# +# Do a repair on the first table once in a while +# + +sub test_repair +{ + my ($dbh, $row, $i, $type, $table); + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $type= "repair"; + for ($i=0 ; !test_if_abort($dbh) ; $i++) + { + sleep(2000); + $table=$testtables[0]->[0]; + $sth=$dbh->prepare("$type table $table") || die "Got error on prepare: $DBI::errstr\n"; + $sth->execute || die $DBI::errstr; + + while (($row=$sth->fetchrow_arrayref)) + { + if ($row->[3] ne "OK") + { + print "Got error " . $row->[3] . " when doing $type on $table\n"; + exit(1); + } + } + } + $dbh->disconnect; $dbh=0; + print "test_repair: Executed $i repairs\n"; + exit(0); +} + +# +# Do a flush tables on table 3 and 4 once in a while +# + +sub test_flush +{ + my ($dbh,$count,$tables); + + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $tables=$testtables[2]->[0] . "," . $testtables[3]->[0]; + + $count=0; + while (!test_if_abort($dbh)) + { + sleep(3000); + $dbh->do("flush tables $tables") || + die "Got error on flush $DBI::errstr\n"; + $count++; + } + $dbh->disconnect; $dbh=0; + print "flush: Executed $count flushs\n"; + exit(0); +} + + +# +# Test all tables in a database +# + +sub test_database +{ + my ($database) = @_; + my ($dbh, $row, $i, $type, $tables); + $dbh = DBI->connect("DBI:mysql:$database:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $tables= join(',',$dbh->func('_ListTables')); + $type= "check"; + for ($i=0 ; !test_if_abort($dbh) ; $i++) + { + sleep(120); + $sth=$dbh->prepare("$type table $tables") || die "Got error on prepare: $DBI::errstr\n"; + $sth->execute || die $DBI::errstr; + + while (($row=$sth->fetchrow_arrayref)) + { + if ($row->[3] ne "OK") + { + print "Got error " . $row->[2] . " " . $row->[3] . " when doing $type on " . $row->[0] . "\n"; + exit(1); + } + } + } + $dbh->disconnect; $dbh=0; + print "test_check: Executed $i checks\n"; + exit(0); +} + +# +# Test ALTER TABLE on the second table +# + +sub test_alter +{ + my ($dbh, $row, $i, $type, $table); + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + for ($i=0 ; !test_if_abort($dbh) ; $i++) + { + sleep(100); + $table=$testtables[1]->[0]; + $sth=$dbh->prepare("ALTER table $table modify info char(32)") || die "Got error on prepare: $DBI::errstr\n"; + $sth->execute || die $DBI::errstr; + } + $dbh->disconnect; $dbh=0; + print "test_alter: Executed $i ALTER TABLE\n"; + exit(0); +} + + +# +# Help functions +# + +sub signal_abort +{ + my ($dbh); + $dbh = DBI->connect("DBI:mysql:$opt_db:$opt_host", + $opt_user, $opt_password, + { PrintError => 0}) || die $DBI::errstr; + + $dbh->do("insert into $abort_table values(1)") || die $DBI::errstr; + $dbh->disconnect; $dbh=0; +} + + +sub test_if_abort() +{ + my ($dbh)=@_; + $row=simple_query($dbh,"select * from $opt_db.$abort_table"); + return (defined($row) && defined($row->[0]) != 0) ? 1 : 0; +} + + +sub make_count_query +{ + my ($table_count)= @_; + my ($tables, $count_query, $i, $tables_def); + $tables=""; + $count_query="select high_priority "; + $table_count--; + for ($i=0 ; $i < $table_count ; $i++) + { + my ($table_def)= $testtables[$i]; + $tables.=$table_def->[0] . ","; + $count_query.= "max(" . $table_def->[0] . ".id),"; + } + $table_def=$testtables[$table_count]; + $tables.=$table_def->[0]; + $count_query.= "max(" . $table_def->[0] . ".id) from $tables"; + return $count_query; +} + +sub simple_query() +{ + my ($dbh, $query)= @_; + my ($sth,$row); + + $sth=$dbh->prepare($query) || die "Got error on '$query': " . $dbh->errstr . "\n"; + $sth->execute || die "Got error on '$query': " . $dbh->errstr . "\n"; + $row= $sth->fetchrow_arrayref(); + $sth=0; + return $row; +} |