summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortsmith@maint1.mysql.com <>2007-06-21 18:58:31 +0200
committertsmith@maint1.mysql.com <>2007-06-21 18:58:31 +0200
commit3ae37d30deddcae0deb34120350801f8a2c43d5e (patch)
treef2b8dc257630c43d5656c14d2fc4a352f295fc34
parent8e65f663788cd923b6a0dbd3b6537413c8e48d53 (diff)
parent7758a5de33727ce71f29903e62d3826570b3b842 (diff)
downloadmariadb-git-3ae37d30deddcae0deb34120350801f8a2c43d5e.tar.gz
Merge maint1.mysql.com:/data/localhome/tsmith/bk/51
into maint1.mysql.com:/data/localhome/tsmith/bk/maint/51
-rw-r--r--include/my_sys.h8
-rw-r--r--mysql-test/r/comments.result12
-rw-r--r--mysql-test/r/log_tables.result68
-rw-r--r--mysql-test/r/query_cache.result48
-rw-r--r--mysql-test/r/sp.result128
-rw-r--r--mysql-test/r/trigger.result16
-rw-r--r--mysql-test/r/varbinary.result16
-rw-r--r--mysql-test/t/comments.test15
-rw-r--r--mysql-test/t/disabled.def3
-rw-r--r--mysql-test/t/events_restart_phase3.test1
-rw-r--r--mysql-test/t/greedy_optimizer.test4
-rw-r--r--mysql-test/t/join.test6
-rw-r--r--mysql-test/t/log_tables.test70
-rw-r--r--mysql-test/t/query_cache.test45
-rw-r--r--mysql-test/t/sp.test81
-rw-r--r--mysql-test/t/trigger.test27
-rw-r--r--mysql-test/t/varbinary.test19
-rw-r--r--mysys/charset.c64
-rw-r--r--sql/event_data_objects.cc214
-rw-r--r--sql/event_data_objects.h14
-rw-r--r--sql/event_db_repository.cc28
-rw-r--r--sql/event_scheduler.cc2
-rw-r--r--sql/field.cc62
-rw-r--r--sql/field.h32
-rw-r--r--sql/handler.cc4
-rw-r--r--sql/item.h2
-rw-r--r--sql/item_sum.cc4
-rw-r--r--sql/item_timefunc.cc32
-rw-r--r--sql/log.cc11
-rw-r--r--sql/mysql_priv.h28
-rw-r--r--sql/sp.cc52
-rw-r--r--sql/sp_head.cc118
-rw-r--r--sql/sp_head.h15
-rw-r--r--sql/sp_pcontext.cc2
-rw-r--r--sql/sp_pcontext.h4
-rw-r--r--sql/sp_rcontext.cc2
-rw-r--r--sql/sql_cache.cc79
-rw-r--r--sql/sql_class.cc17
-rw-r--r--sql/sql_class.h36
-rw-r--r--sql/sql_db.cc49
-rw-r--r--sql/sql_insert.cc6
-rw-r--r--sql/sql_lex.cc560
-rw-r--r--sql/sql_lex.h344
-rw-r--r--sql/sql_parse.cc52
-rw-r--r--sql/sql_partition.cc3
-rw-r--r--sql/sql_prepare.cc7
-rw-r--r--sql/sql_select.cc6
-rw-r--r--sql/sql_table.cc60
-rw-r--r--sql/sql_trigger.cc332
-rw-r--r--sql/sql_trigger.h19
-rw-r--r--sql/sql_view.cc18
-rw-r--r--sql/sql_yacc.yy160
-rw-r--r--sql/unireg.cc54
-rw-r--r--sql/unireg.h1
-rw-r--r--tests/mysql_client_test.c67
55 files changed, 2176 insertions, 951 deletions
diff --git a/include/my_sys.h b/include/my_sys.h
index a8633982f84..d1a253e4a7f 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -904,6 +904,14 @@ extern CHARSET_INFO *get_charset(uint cs_number, myf flags);
extern CHARSET_INFO *get_charset_by_name(const char *cs_name, myf flags);
extern CHARSET_INFO *get_charset_by_csname(const char *cs_name,
uint cs_flags, myf my_flags);
+
+extern bool resolve_charset(CHARSET_INFO **cs,
+ const char *cs_name,
+ CHARSET_INFO *default_cs);
+extern bool resolve_collation(CHARSET_INFO **cl,
+ const char *cl_name,
+ CHARSET_INFO *default_cl);
+
extern void free_charsets(void);
extern char *get_charsets_dir(char *buf);
extern my_bool my_charset_same(CHARSET_INFO *cs1, CHARSET_INFO *cs2);
diff --git a/mysql-test/r/comments.result b/mysql-test/r/comments.result
index a9106ce0538..98921c561d1 100644
--- a/mysql-test/r/comments.result
+++ b/mysql-test/r/comments.result
@@ -8,7 +8,7 @@ multi line comment */;
;
ERROR 42000: Query was empty
select 1 /*!32301 +1 */;
-1 /*!32301 +1
+1 +1
2
select 1 /*!52301 +1 */;
1
@@ -26,3 +26,13 @@ select 1 # The rest of the row will be ignored
1
1
/* line with only comment */;
+select 1/*!2*/;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '2*/' at line 1
+select 1/*!000002*/;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '2*/' at line 1
+select 1/*!999992*/;
+1
+1
+select 1 + /*!00000 2 */ + 3 /*!99999 noise*/ + 4;
+1 + 2 + 3 + 4
+10
diff --git a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result
index 5a90c22fa06..ce3dabe3a56 100644
--- a/mysql-test/r/log_tables.result
+++ b/mysql-test/r/log_tables.result
@@ -287,3 +287,71 @@ slow_log
slow_log_new
drop table slow_log_new, general_log_new;
use test;
+SET GLOBAL LOG_OUTPUT = 'TABLE';
+SET GLOBAL general_log = 0;
+FLUSH LOGS;
+TRUNCATE TABLE mysql.general_log;
+ALTER TABLE mysql.general_log ENGINE = MyISAM;
+ALTER TABLE mysql.general_log
+ADD COLUMN seq BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY;
+SET GLOBAL general_log = 1;
+FLUSH LOGS;
+SELECT * FROM mysql.general_log;
+event_time user_host thread_id server_id command_type argument seq
+EVENT_TIME USER_HOST THREAD_ID SERVER_ID Query FLUSH LOGS 1
+EVENT_TIME USER_HOST THREAD_ID SERVER_ID Query SELECT * FROM mysql.general_log 2
+SELECT * FROM mysql.general_log;
+event_time user_host thread_id server_id command_type argument seq
+EVENT_TIME USER_HOST THREAD_ID SERVER_ID Query FLUSH LOGS 1
+EVENT_TIME USER_HOST THREAD_ID SERVER_ID Query SELECT * FROM mysql.general_log 2
+EVENT_TIME USER_HOST THREAD_ID SERVER_ID Query SELECT * FROM mysql.general_log 3
+SELECT "My own query 1";
+My own query 1
+My own query 1
+SELECT "My own query 2";
+My own query 2
+My own query 2
+SELECT * FROM mysql.general_log;
+event_time user_host thread_id server_id command_type argument seq
+EVENT_TIME USER_HOST THREAD_ID SERVER_ID Query FLUSH LOGS 1
+EVENT_TIME USER_HOST THREAD_ID SERVER_ID Query SELECT * FROM mysql.general_log 2
+EVENT_TIME USER_HOST THREAD_ID SERVER_ID Query SELECT * FROM mysql.general_log 3
+EVENT_TIME USER_HOST THREAD_ID SERVER_ID Query SELECT "My own query 1" 4
+EVENT_TIME USER_HOST THREAD_ID SERVER_ID Query SELECT "My own query 2" 5
+EVENT_TIME USER_HOST THREAD_ID SERVER_ID Query SELECT * FROM mysql.general_log 6
+SET GLOBAL general_log = 0;
+FLUSH LOGS;
+ALTER TABLE mysql.general_log DROP COLUMN seq;
+ALTER TABLE mysql.general_log ENGINE = CSV;
+SET @old_long_query_time:=@@long_query_time;
+SET GLOBAL slow_query_log = 0;
+FLUSH LOGS;
+TRUNCATE TABLE mysql.slow_log;
+ALTER TABLE mysql.slow_log ENGINE = MyISAM;
+ALTER TABLE mysql.slow_log
+ADD COLUMN seq BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY;
+SET SESSION long_query_time = 1;
+SET GLOBAL slow_query_log = 1;
+FLUSH LOGS;
+SELECT "My own slow query", sleep(2);
+My own slow query sleep(2)
+My own slow query 0
+SELECT "My own slow query", sleep(2);
+My own slow query sleep(2)
+My own slow query 0
+SELECT "My own slow query", sleep(2);
+My own slow query sleep(2)
+My own slow query 0
+SELECT "My own slow query", sleep(2);
+My own slow query sleep(2)
+My own slow query 0
+SELECT * FROM mysql.slow_log WHERE seq >= 2 LIMIT 3;
+start_time user_host query_time lock_time rows_sent rows_examined db last_insert_id insert_id server_id sql_text seq
+START_TIME USER_HOST QUERY_TIME 00:00:00 1 0 test NULL NULL 1 SELECT "My own slow query", sleep(2) 2
+START_TIME USER_HOST QUERY_TIME 00:00:00 1 0 test NULL NULL 1 SELECT "My own slow query", sleep(2) 3
+START_TIME USER_HOST QUERY_TIME 00:00:00 1 0 test NULL NULL 1 SELECT "My own slow query", sleep(2) 4
+SET GLOBAL slow_query_log = 0;
+SET SESSION long_query_time =@old_long_query_time;
+FLUSH LOGS;
+ALTER TABLE mysql.slow_log DROP COLUMN seq;
+ALTER TABLE mysql.slow_log ENGINE = CSV;
diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result
index fadd99ab27c..680577c495e 100644
--- a/mysql-test/r/query_cache.result
+++ b/mysql-test/r/query_cache.result
@@ -1495,3 +1495,51 @@ insert into t1 values ('c');
a
drop table t1;
set GLOBAL query_cache_size= default;
+drop database if exists db1;
+drop database if exists db2;
+set GLOBAL query_cache_size=15*1024*1024;
+create database db1;
+use db1;
+create table t1(c1 int)engine=myisam;
+insert into t1(c1) values (1);
+select * from db1.t1 f;
+c1
+1
+show status like 'Qcache_queries_in_cache';
+Variable_name Value
+Qcache_queries_in_cache 1
+rename schema db1 to db2;
+show status like 'Qcache_queries_in_cache';
+Variable_name Value
+Qcache_queries_in_cache 0
+drop database db2;
+set global query_cache_size=default;
+drop database if exists db1;
+drop database if exists db3;
+set GLOBAL query_cache_size=15*1024*1024;
+create database db1;
+create database db3;
+use db1;
+create table t1(c1 int) engine=myisam;
+use db3;
+create table t1(c1 int) engine=myisam;
+use db1;
+insert into t1(c1) values (1);
+use mysql;
+select * from db1.t1;
+c1
+1
+select c1+1 from db1.t1;
+c1+1
+2
+select * from db3.t1;
+c1
+show status like 'Qcache_queries_in_cache';
+Variable_name Value
+Qcache_queries_in_cache 3
+rename schema db1 to db2;
+show status like 'Qcache_queries_in_cache';
+Variable_name Value
+Qcache_queries_in_cache 1
+drop database db2;
+drop database db3;
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 1c3fd53b0b2..98d73f7536c 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -6281,4 +6281,130 @@ v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VI
DROP VIEW v1;
DROP FUNCTION metered;
DROP TABLE t1;
-End of 5.0 tests
+drop procedure if exists proc_25411_a;
+drop procedure if exists proc_25411_b;
+drop procedure if exists proc_25411_c;
+create procedure proc_25411_a()
+begin
+/* real comment */
+select 1;
+/*! select 2; */
+select 3;
+/*!00000 select 4; */
+/*!99999 select 5; */
+end
+$$
+create procedure proc_25411_b(
+/* real comment */
+/*! p1 int, */
+/*!00000 p2 int */
+/*!99999 ,p3 int */
+)
+begin
+select p1, p2;
+end
+$$
+create procedure proc_25411_c()
+begin
+select 1/*!,2*//*!00000,3*//*!99999,4*/;
+select 1/*! ,2*//*!00000 ,3*//*!99999 ,4*/;
+select 1/*!,2 *//*!00000,3 *//*!99999,4 */;
+select 1/*! ,2 *//*!00000 ,3 *//*!99999 ,4 */;
+select 1 /*!,2*/ /*!00000,3*/ /*!99999,4*/ ;
+end
+$$
+show create procedure proc_25411_a;
+Procedure sql_mode Create Procedure
+proc_25411_a CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_25411_a`()
+begin
+/* real comment */
+select 1;
+ select 2;
+select 3;
+ select 4;
+
+end
+call proc_25411_a();
+1
+1
+2
+2
+3
+3
+4
+4
+show create procedure proc_25411_b;
+Procedure sql_mode Create Procedure
+proc_25411_b CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_25411_b`(
+/* real comment */
+ p1 int,
+ p2 int
+
+)
+begin
+select p1, p2;
+end
+select name, param_list, body from mysql.proc where name like "%25411%";
+name param_list body
+proc_25411_a begin
+/* real comment */
+select 1;
+ select 2;
+select 3;
+ select 4;
+
+end
+proc_25411_b
+/* real comment */
+ p1 int,
+ p2 int
+
+ begin
+select p1, p2;
+end
+proc_25411_c begin
+select 1,2,3;
+select 1 ,2 ,3;
+select 1,2 ,3 ;
+select 1 ,2 ,3 ;
+select 1 ,2 ,3 ;
+end
+call proc_25411_b(10, 20);
+p1 p2
+10 20
+show create procedure proc_25411_c;
+Procedure sql_mode Create Procedure
+proc_25411_c CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_25411_c`()
+begin
+select 1,2,3;
+select 1 ,2 ,3;
+select 1,2 ,3 ;
+select 1 ,2 ,3 ;
+select 1 ,2 ,3 ;
+end
+call proc_25411_c();
+1 2 3
+1 2 3
+1 2 3
+1 2 3
+1 2 3
+1 2 3
+1 2 3
+1 2 3
+1 2 3
+1 2 3
+drop procedure proc_25411_a;
+drop procedure proc_25411_b;
+drop procedure proc_25411_c;
+drop procedure if exists proc_26302;
+create procedure proc_26302()
+select 1 /* testing */;
+show create procedure proc_26302;
+Procedure sql_mode Create Procedure
+proc_26302 CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_26302`()
+select 1 /* testing */
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES
+where ROUTINE_NAME = "proc_26302";
+ROUTINE_NAME ROUTINE_DEFINITION
+proc_26302 select 1 /* testing */
+drop procedure proc_26302;
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
index 59ed4511aed..ecaef458e92 100644
--- a/mysql-test/r/trigger.result
+++ b/mysql-test/r/trigger.result
@@ -1477,3 +1477,19 @@ DROP TABLE t1,t2;
SET SESSION LOW_PRIORITY_UPDATES=DEFAULT;
SET GLOBAL LOW_PRIORITY_UPDATES=DEFAULT;
End of 5.0 tests
+drop table if exists table_25411_a;
+drop table if exists table_25411_b;
+create table table_25411_a(a int);
+create table table_25411_b(b int);
+create trigger trg_25411a_ai after insert on table_25411_a
+for each row
+insert into table_25411_b select new.*;
+select * from table_25411_a;
+a
+insert into table_25411_a values (1);
+ERROR 42S02: Unknown table 'new'
+select * from table_25411_a;
+a
+1
+drop table table_25411_a;
+drop table table_25411_b;
diff --git a/mysql-test/r/varbinary.result b/mysql-test/r/varbinary.result
index f30af2ea1a3..6d39d8301c5 100644
--- a/mysql-test/r/varbinary.result
+++ b/mysql-test/r/varbinary.result
@@ -79,3 +79,19 @@ select length(a) from t1;
length(a)
6
drop table t1;
+drop table if exists table_28127_a;
+drop table if exists table_28127_b;
+create table table_28127_a(0b02 int);
+show create table table_28127_a;
+Table Create Table
+table_28127_a CREATE TABLE `table_28127_a` (
+ `0b02` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+create table table_28127_b(0b2 int);
+show create table table_28127_b;
+Table Create Table
+table_28127_b CREATE TABLE `table_28127_b` (
+ `0b2` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table table_28127_a;
+drop table table_28127_b;
diff --git a/mysql-test/t/comments.test b/mysql-test/t/comments.test
index 52273ec9523..8ae6ba5779e 100644
--- a/mysql-test/t/comments.test
+++ b/mysql-test/t/comments.test
@@ -19,3 +19,18 @@ select 1 # The rest of the row will be ignored
/* line with only comment */;
# End of 4.1 tests
+
+#
+# Bug#25411 (trigger code truncated)
+#
+
+--error ER_PARSE_ERROR
+select 1/*!2*/;
+
+--error ER_PARSE_ERROR
+select 1/*!000002*/;
+
+select 1/*!999992*/;
+
+select 1 + /*!00000 2 */ + 3 /*!99999 noise*/ + 4;
+
diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def
index 27e3b9bc614..29336e1050d 100644
--- a/mysql-test/t/disabled.def
+++ b/mysql-test/t/disabled.def
@@ -48,3 +48,6 @@ ndb_partition_error2 : HF is not sure if the test can work as internded on all
im_options_set : Bug#20294: Instance manager tests fail randomly
im_options_unset : Bug#20294: Instance manager tests fail randomly
mysql_upgrade : Bug#28560 test links to /usr/local/mysql/lib libraries, causes non-determinism and failures on ABI breakage
+rpl_udf : Bug#28993 rpl_udf test causes server crash and valgrind warning in pushbuild
+rpl_ndb_circular : Bug#29233 rpl_ndb_circular fails randomly
+ndb_dd_sql_features : Bug#29102 ndb_dd_sql_features fails in pushbuild
diff --git a/mysql-test/t/events_restart_phase3.test b/mysql-test/t/events_restart_phase3.test
index f5eeb1af2d9..04d879e50ec 100644
--- a/mysql-test/t/events_restart_phase3.test
+++ b/mysql-test/t/events_restart_phase3.test
@@ -18,3 +18,4 @@ drop database events_test;
let $wait_condition=
select count(*) = 0 from information_schema.processlist
where db='events_test' and command = 'Connect' and user=current_user();
+--source include/wait_condition.inc
diff --git a/mysql-test/t/greedy_optimizer.test b/mysql-test/t/greedy_optimizer.test
index 4feca43ae1a..b73f70c6a3e 100644
--- a/mysql-test/t/greedy_optimizer.test
+++ b/mysql-test/t/greedy_optimizer.test
@@ -145,11 +145,11 @@ select @@optimizer_prune_level;
#
# These are the values for the parameters that control the greedy optimizer
# (total 6 combinations - 3 for optimizer_search_depth, 2 for optimizer_prune_level):
-#
+# 3:
# set optimizer_search_depth=0; - automatic
# set optimizer_search_depth=1; - min
# set optimizer_search_depth=62; - max (default)
-#
+# 2:
# set optimizer_prune_level=0 - exhaustive;
# set optimizer_prune_level=1 - heuristic; # default
diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test
index 4d35989aa9a..14c98431970 100644
--- a/mysql-test/t/join.test
+++ b/mysql-test/t/join.test
@@ -512,10 +512,12 @@ select * from v1a join (t3 natural join t4) on a = y;
#--------------------------------------------------------------------
# Negative tests (tests for errors)
#--------------------------------------------------------------------
+# works in Oracle - bug
-- error 1052
-select * from t1 natural join (t3 cross join t4); # works in Oracle - bug
+select * from t1 natural join (t3 cross join t4);
+# works in Oracle - bug
-- error 1052
-select * from (t3 cross join t4) natural join t1; # works in Oracle - bug
+select * from (t3 cross join t4) natural join t1;
-- error 1052
select * from t1 join (t2, t3) using (b);
-- error 1052
diff --git a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test
index b02a47dde6b..e8eff7cba0a 100644
--- a/mysql-test/t/log_tables.test
+++ b/mysql-test/t/log_tables.test
@@ -400,6 +400,76 @@ show tables like "%log%";
drop table slow_log_new, general_log_new;
use test;
+#
+# Bug#27857 (Log tables supplies the wrong value for generating
+# AUTO_INCREMENT numbers)
+#
+
+SET GLOBAL LOG_OUTPUT = 'TABLE';
+
+## test the general log
+
+SET GLOBAL general_log = 0;
+FLUSH LOGS;
+
+TRUNCATE TABLE mysql.general_log;
+ALTER TABLE mysql.general_log ENGINE = MyISAM;
+ALTER TABLE mysql.general_log
+ ADD COLUMN seq BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY;
+
+SET GLOBAL general_log = 1;
+FLUSH LOGS;
+
+--replace_column 1 EVENT_TIME 2 USER_HOST 3 THREAD_ID 4 SERVER_ID
+SELECT * FROM mysql.general_log;
+--replace_column 1 EVENT_TIME 2 USER_HOST 3 THREAD_ID 4 SERVER_ID
+SELECT * FROM mysql.general_log;
+SELECT "My own query 1";
+SELECT "My own query 2";
+--replace_column 1 EVENT_TIME 2 USER_HOST 3 THREAD_ID 4 SERVER_ID
+SELECT * FROM mysql.general_log;
+
+SET GLOBAL general_log = 0;
+FLUSH LOGS;
+
+ALTER TABLE mysql.general_log DROP COLUMN seq;
+ALTER TABLE mysql.general_log ENGINE = CSV;
+
+## test the slow query log
+
+SET @old_long_query_time:=@@long_query_time;
+
+SET GLOBAL slow_query_log = 0;
+FLUSH LOGS;
+
+TRUNCATE TABLE mysql.slow_log;
+ALTER TABLE mysql.slow_log ENGINE = MyISAM;
+
+ALTER TABLE mysql.slow_log
+ ADD COLUMN seq BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY;
+
+SET SESSION long_query_time = 1;
+SET GLOBAL slow_query_log = 1;
+FLUSH LOGS;
+
+## FLUSH LOGS above might be slow, so the following is
+## logged as either seq 1-4 or seq 2-5
+SELECT "My own slow query", sleep(2);
+SELECT "My own slow query", sleep(2);
+SELECT "My own slow query", sleep(2);
+SELECT "My own slow query", sleep(2);
+
+## So we look for seq 2-4
+--replace_column 1 START_TIME 2 USER_HOST 3 QUERY_TIME
+SELECT * FROM mysql.slow_log WHERE seq >= 2 LIMIT 3;
+
+SET GLOBAL slow_query_log = 0;
+SET SESSION long_query_time =@old_long_query_time;
+FLUSH LOGS;
+
+ALTER TABLE mysql.slow_log DROP COLUMN seq;
+ALTER TABLE mysql.slow_log ENGINE = CSV;
+
# kill all connections
disconnect con1;
disconnect con2;
diff --git a/mysql-test/t/query_cache.test b/mysql-test/t/query_cache.test
index e046f21815a..14ccea0fdc8 100644
--- a/mysql-test/t/query_cache.test
+++ b/mysql-test/t/query_cache.test
@@ -1058,3 +1058,48 @@ drop table t1;
set GLOBAL query_cache_size= default;
# End of 5.0 tests
+
+
+#
+# Bug #28211 RENAME DATABASE and query cache don't play nicely together
+#
+--disable_warnings
+drop database if exists db1;
+drop database if exists db2;
+--enable_warnings
+set GLOBAL query_cache_size=15*1024*1024;
+create database db1;
+use db1;
+create table t1(c1 int)engine=myisam;
+insert into t1(c1) values (1);
+select * from db1.t1 f;
+show status like 'Qcache_queries_in_cache';
+rename schema db1 to db2;
+show status like 'Qcache_queries_in_cache';
+drop database db2;
+set global query_cache_size=default;
+
+--disable_warnings
+drop database if exists db1;
+drop database if exists db3;
+--enable_warnings
+set GLOBAL query_cache_size=15*1024*1024;
+create database db1;
+create database db3;
+use db1;
+create table t1(c1 int) engine=myisam;
+use db3;
+create table t1(c1 int) engine=myisam;
+use db1;
+insert into t1(c1) values (1);
+use mysql;
+select * from db1.t1;
+select c1+1 from db1.t1;
+select * from db3.t1;
+show status like 'Qcache_queries_in_cache';
+rename schema db1 to db2;
+show status like 'Qcache_queries_in_cache';
+drop database db2;
+drop database db3;
+
+# End of 5.1 tests
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 8972e8bae4a..29e759d7881 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -7251,4 +7251,83 @@ DROP FUNCTION metered;
DROP TABLE t1;
---echo End of 5.0 tests
+#
+# Bug#25411 (trigger code truncated)
+#
+
+--disable_warnings
+drop procedure if exists proc_25411_a;
+drop procedure if exists proc_25411_b;
+drop procedure if exists proc_25411_c;
+--enable_warnings
+
+delimiter $$;
+
+create procedure proc_25411_a()
+begin
+ /* real comment */
+ select 1;
+ /*! select 2; */
+ select 3;
+ /*!00000 select 4; */
+ /*!99999 select 5; */
+end
+$$
+
+create procedure proc_25411_b(
+/* real comment */
+/*! p1 int, */
+/*!00000 p2 int */
+/*!99999 ,p3 int */
+)
+begin
+ select p1, p2;
+end
+$$
+
+create procedure proc_25411_c()
+begin
+ select 1/*!,2*//*!00000,3*//*!99999,4*/;
+ select 1/*! ,2*//*!00000 ,3*//*!99999 ,4*/;
+ select 1/*!,2 *//*!00000,3 *//*!99999,4 */;
+ select 1/*! ,2 *//*!00000 ,3 *//*!99999 ,4 */;
+ select 1 /*!,2*/ /*!00000,3*/ /*!99999,4*/ ;
+end
+$$
+
+delimiter ;$$
+
+show create procedure proc_25411_a;
+call proc_25411_a();
+
+show create procedure proc_25411_b;
+select name, param_list, body from mysql.proc where name like "%25411%";
+call proc_25411_b(10, 20);
+
+show create procedure proc_25411_c;
+call proc_25411_c();
+
+drop procedure proc_25411_a;
+drop procedure proc_25411_b;
+drop procedure proc_25411_c;
+
+
+#
+# Bug#26302 (MySQL server cuts off trailing "*/" from comments in SP/func)
+#
+
+--disable_warnings
+drop procedure if exists proc_26302;
+--enable_warnings
+
+create procedure proc_26302()
+select 1 /* testing */;
+
+show create procedure proc_26302;
+
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES
+where ROUTINE_NAME = "proc_26302";
+
+drop procedure proc_26302;
+
+
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
index 6dc8c71176b..3df88f60a33 100644
--- a/mysql-test/t/trigger.test
+++ b/mysql-test/t/trigger.test
@@ -1830,3 +1830,30 @@ SET SESSION LOW_PRIORITY_UPDATES=DEFAULT;
SET GLOBAL LOW_PRIORITY_UPDATES=DEFAULT;
--echo End of 5.0 tests
+
+#
+# Bug#25411 (trigger code truncated)
+#
+
+--disable_warnings
+drop table if exists table_25411_a;
+drop table if exists table_25411_b;
+--enable_warnings
+
+create table table_25411_a(a int);
+create table table_25411_b(b int);
+
+create trigger trg_25411a_ai after insert on table_25411_a
+for each row
+ insert into table_25411_b select new.*;
+
+select * from table_25411_a;
+
+--error ER_BAD_TABLE_ERROR
+insert into table_25411_a values (1);
+
+select * from table_25411_a;
+
+drop table table_25411_a;
+drop table table_25411_b;
+
diff --git a/mysql-test/t/varbinary.test b/mysql-test/t/varbinary.test
index 2d055920c22..9ccbac7cdda 100644
--- a/mysql-test/t/varbinary.test
+++ b/mysql-test/t/varbinary.test
@@ -85,3 +85,22 @@ alter table t1 modify a varchar(255);
select length(a) from t1;
drop table t1;
+
+#
+# Bug#28127 (Some valid identifiers names are not parsed correctly)
+#
+
+--disable_warnings
+drop table if exists table_28127_a;
+drop table if exists table_28127_b;
+--enable_warnings
+
+create table table_28127_a(0b02 int);
+show create table table_28127_a;
+
+create table table_28127_b(0b2 int);
+show create table table_28127_b;
+
+drop table table_28127_a;
+drop table table_28127_b;
+
diff --git a/mysys/charset.c b/mysys/charset.c
index c6065f87df3..5f9521eeab8 100644
--- a/mysys/charset.c
+++ b/mysys/charset.c
@@ -573,6 +573,70 @@ CHARSET_INFO *get_charset_by_csname(const char *cs_name,
}
+/**
+ Resolve character set by the character set name (utf8, latin1, ...).
+
+ The function tries to resolve character set by the specified name. If
+ there is character set with the given name, it is assigned to the "cs"
+ parameter and FALSE is returned. If there is no such character set,
+ "default_cs" is assigned to the "cs" and TRUE is returned.
+
+ @param[out] cs Variable to store character set.
+ @param[in] cs_name Character set name.
+ @param[in] default_cs Default character set.
+
+ @return FALSE if character set was resolved successfully; TRUE if there
+ is no character set with given name.
+*/
+
+bool resolve_charset(CHARSET_INFO **cs,
+ const char *cs_name,
+ CHARSET_INFO *default_cs)
+{
+ *cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0));
+
+ if (*cs == NULL)
+ {
+ *cs= default_cs;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Resolve collation by the collation name (utf8_general_ci, ...).
+
+ The function tries to resolve collation by the specified name. If there
+ is collation with the given name, it is assigned to the "cl" parameter
+ and FALSE is returned. If there is no such collation, "default_cl" is
+ assigned to the "cl" and TRUE is returned.
+
+ @param[out] cl Variable to store collation.
+ @param[in] cl_name Collation name.
+ @param[in] default_cl Default collation.
+
+ @return FALSE if collation was resolved successfully; TRUE if there is no
+ collation with given name.
+*/
+
+bool resolve_collation(CHARSET_INFO **cl,
+ const char *cl_name,
+ CHARSET_INFO *default_cl)
+{
+ *cl= get_charset_by_name(cl_name, MYF(0));
+
+ if (*cl == NULL)
+ {
+ *cl= default_cl;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
/*
Escape string with backslashes (\)
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index 138752d5ce5..77dc33e6265 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -94,17 +94,18 @@ Event_parse_data::Event_parse_data()
:on_completion(Event_basic::ON_COMPLETION_DROP),
status(Event_basic::ENABLED),
do_not_create(FALSE),
- item_starts(NULL), item_ends(NULL), item_execute_at(NULL),
- starts_null(TRUE), ends_null(TRUE), execute_at_null(TRUE),
- item_expression(NULL), expression(0)
+ body_changed(FALSE),
+ item_starts(NULL), item_ends(NULL), item_execute_at(NULL),
+ starts_null(TRUE), ends_null(TRUE), execute_at_null(TRUE),
+ item_expression(NULL), expression(0)
{
DBUG_ENTER("Event_parse_data::Event_parse_data");
/* Actually in the parser STARTS is always set */
starts= ends= execute_at= 0;
- body.str= comment.str= NULL;
- body.length= comment.length= 0;
+ comment.str= NULL;
+ comment.length= 0;
DBUG_VOID_RETURN;
}
@@ -138,86 +139,6 @@ Event_parse_data::init_name(THD *thd, sp_name *spn)
/*
- Set body of the event - what should be executed.
-
- SYNOPSIS
- Event_parse_data::init_body()
- thd THD
-
- NOTE
- The body is extracted by copying all data between the
- start of the body set by another method and the current pointer in Lex.
-
- Some questionable removal of characters is done in here, and that part
- should be refactored when the parser is smarter.
-*/
-
-void
-Event_parse_data::init_body(THD *thd)
-{
- DBUG_ENTER("Event_parse_data::init_body");
-
- /* This method is called from within the parser, from sql_yacc.yy */
- DBUG_ASSERT(thd->m_lip != NULL);
-
- DBUG_PRINT("info", ("body: '%s' body_begin: 0x%lx end: 0x%lx", body_begin,
- (long) body_begin, (long) thd->m_lip->ptr));
-
- body.length= thd->m_lip->ptr - body_begin;
- const char *body_end= body_begin + body.length - 1;
-
- /* Trim nuls or close-comments ('*'+'/') or spaces at the end */
- while (body_begin < body_end)
- {
-
- if ((*body_end == '\0') ||
- (my_isspace(thd->variables.character_set_client, *body_end)))
- { /* consume NULs and meaningless whitespace */
- --body.length;
- --body_end;
- continue;
- }
-
- /*
- consume closing comments
-
- This is arguably wrong, but it's the best we have until the parser is
- changed to be smarter. FIXME PARSER
-
- See also the sp_head code, where something like this is done also.
-
- One idea is to keep in the lexer structure the count of the number of
- open-comments we've entered, and scan left-to-right looking for a
- closing comment IFF the count is greater than zero.
-
- Another idea is to remove the closing comment-characters wholly in the
- parser, since that's where it "removes" the opening characters.
- */
- if ((*(body_end - 1) == '*') && (*body_end == '/'))
- {
- DBUG_PRINT("info", ("consumend one '*" "/' comment in the query '%s'",
- body_begin));
- body.length-= 2;
- body_end-= 2;
- continue;
- }
-
- break; /* none were found, so we have excised all we can. */
- }
-
- /* the first is always whitespace which I cannot skip in the parser */
- while (my_isspace(thd->variables.character_set_client, *body_begin))
- {
- ++body_begin;
- --body.length;
- }
- body.str= thd->strmake(body_begin, body.length);
-
- DBUG_VOID_RETURN;
-}
-
-
-/*
This function is called on CREATE EVENT or ALTER EVENT. When either
ENDS or AT is in the past, we are trying to create an event that
will never be executed. If it has ON COMPLETION NOT PRESERVE
@@ -838,36 +759,32 @@ Event_timed::init()
}
-/*
- Loads an event's body from a row from mysql.event
-
- SYNOPSIS
- Event_job_data::load_from_row(THD *thd, TABLE *table)
-
- RETURN VALUE
- 0 OK
- EVEX_GET_FIELD_FAILED Error
-
- NOTES
- This method is silent on errors and should behave like that. Callers
- should handle throwing of error messages. The reason is that the class
- should not know about how to deal with communication.
+/**
+ Load an event's body from a row from mysql.event.
+ @details This method is silent on errors and should behave like that.
+ Callers should handle throwing of error messages. The reason is that the
+ class should not know about how to deal with communication.
+
+ @return Operation status
+ @retval FALSE OK
+ @retval TRUE Error
*/
-int
+bool
Event_job_data::load_from_row(THD *thd, TABLE *table)
{
char *ptr;
uint len;
+ LEX_STRING tz_name;
+
DBUG_ENTER("Event_job_data::load_from_row");
if (!table)
- goto error;
+ DBUG_RETURN(TRUE);
if (table->s->fields < ET_FIELD_COUNT)
- goto error;
+ DBUG_RETURN(TRUE);
- LEX_STRING tz_name;
if (load_string_fields(table->field,
ET_FIELD_DB, &dbname,
ET_FIELD_NAME, &name,
@@ -875,10 +792,10 @@ Event_job_data::load_from_row(THD *thd, TABLE *table)
ET_FIELD_DEFINER, &definer,
ET_FIELD_TIME_ZONE, &tz_name,
ET_FIELD_COUNT))
- goto error;
+ DBUG_RETURN(TRUE);
if (load_time_zone(thd, tz_name))
- goto error;
+ DBUG_RETURN(TRUE);
ptr= strchr(definer.str, '@');
@@ -895,29 +812,23 @@ Event_job_data::load_from_row(THD *thd, TABLE *table)
sql_mode= (ulong) table->field[ET_FIELD_SQL_MODE]->val_int();
- DBUG_RETURN(0);
-error:
- DBUG_RETURN(EVEX_GET_FIELD_FAILED);
+ DBUG_RETURN(FALSE);
}
-/*
- Loads an event from a row from mysql.event
+/**
+ Load an event's body from a row from mysql.event.
- SYNOPSIS
- Event_queue_element::load_from_row(THD *thd, TABLE *table)
+ @details This method is silent on errors and should behave like that.
+ Callers should handle throwing of error messages. The reason is that the
+ class should not know about how to deal with communication.
- RETURN VALUE
- 0 OK
- EVEX_GET_FIELD_FAILED Error
-
- NOTES
- This method is silent on errors and should behave like that. Callers
- should handle throwing of error messages. The reason is that the class
- should not know about how to deal with communication.
+ @return Operation status
+ @retval FALSE OK
+ @retval TRUE Error
*/
-int
+bool
Event_queue_element::load_from_row(THD *thd, TABLE *table)
{
char *ptr;
@@ -927,10 +838,10 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table)
DBUG_ENTER("Event_queue_element::load_from_row");
if (!table)
- goto error;
+ DBUG_RETURN(TRUE);
if (table->s->fields < ET_FIELD_COUNT)
- goto error;
+ DBUG_RETURN(TRUE);
if (load_string_fields(table->field,
ET_FIELD_DB, &dbname,
@@ -938,10 +849,10 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table)
ET_FIELD_DEFINER, &definer,
ET_FIELD_TIME_ZONE, &tz_name,
ET_FIELD_COUNT))
- goto error;
+ DBUG_RETURN(TRUE);
if (load_time_zone(thd, tz_name))
- goto error;
+ DBUG_RETURN(TRUE);
starts_null= table->field[ET_FIELD_STARTS]->is_null();
if (!starts_null)
@@ -971,7 +882,7 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table)
{
if (table->field[ET_FIELD_EXECUTE_AT]->get_date(&time,
TIME_NO_ZERO_DATE))
- goto error;
+ DBUG_RETURN(TRUE);
execute_at= sec_since_epoch_TIME(&time);
}
@@ -990,13 +901,13 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table)
table->field[ET_FIELD_TRANSIENT_INTERVAL]->val_str(&str);
if (!(tmp.length= str.length()))
- goto error;
+ DBUG_RETURN(TRUE);
tmp.str= str.c_ptr_safe();
i= find_string_in_array(interval_type_to_name, &tmp, system_charset_info);
if (i < 0)
- goto error;
+ DBUG_RETURN(TRUE);
interval= (interval_type) i;
}
@@ -1009,7 +920,7 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table)
last_executed_changed= FALSE;
if ((ptr= get_field(&mem_root, table->field[ET_FIELD_STATUS])) == NullS)
- goto error;
+ DBUG_RETURN(TRUE);
DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", name.str, ptr));
@@ -1028,40 +939,34 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table)
break;
}
if ((ptr= get_field(&mem_root, table->field[ET_FIELD_ORIGINATOR])) == NullS)
- goto error;
+ DBUG_RETURN(TRUE);
originator = table->field[ET_FIELD_ORIGINATOR]->val_int();
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
if ((ptr= get_field(&mem_root,
table->field[ET_FIELD_ON_COMPLETION])) == NullS)
- goto error;
+ DBUG_RETURN(TRUE);
on_completion= (ptr[0]=='D'? Event_queue_element::ON_COMPLETION_DROP:
Event_queue_element::ON_COMPLETION_PRESERVE);
- DBUG_RETURN(0);
-error:
- DBUG_RETURN(EVEX_GET_FIELD_FAILED);
+ DBUG_RETURN(FALSE);
}
-/*
- Loads an event from a row from mysql.event
-
- SYNOPSIS
- Event_timed::load_from_row(THD *thd, TABLE *table)
+/**
+ Load an event's body from a row from mysql.event.
- RETURN VALUE
- 0 OK
- EVEX_GET_FIELD_FAILED Error
+ @details This method is silent on errors and should behave like that.
+ Callers should handle throwing of error messages. The reason is that the
+ class should not know about how to deal with communication.
- NOTES
- This method is silent on errors and should behave like that. Callers
- should handle throwing of error messages. The reason is that the class
- should not know about how to deal with communication.
+ @return Operation status
+ @retval FALSE OK
+ @retval TRUE Error
*/
-int
+bool
Event_timed::load_from_row(THD *thd, TABLE *table)
{
char *ptr;
@@ -1070,12 +975,12 @@ Event_timed::load_from_row(THD *thd, TABLE *table)
DBUG_ENTER("Event_timed::load_from_row");
if (Event_queue_element::load_from_row(thd, table))
- goto error;
+ DBUG_RETURN(TRUE);
if (load_string_fields(table->field,
ET_FIELD_BODY, &body,
ET_FIELD_COUNT))
- goto error;
+ DBUG_RETURN(TRUE);
ptr= strchr(definer.str, '@');
@@ -1102,9 +1007,7 @@ Event_timed::load_from_row(THD *thd, TABLE *table)
sql_mode= (ulong) table->field[ET_FIELD_SQL_MODE]->val_int();
- DBUG_RETURN(0);
-error:
- DBUG_RETURN(EVEX_GET_FIELD_FAILED);
+ DBUG_RETURN(FALSE);
}
@@ -1925,11 +1828,9 @@ Event_job_data::execute(THD *thd, bool drop)
{
Lex_input_stream lip(thd, thd->query, thd->query_length);
- thd->m_lip= &lip;
lex_start(thd);
- int err= MYSQLparse(thd);
- if (err || thd->is_fatal_error)
+ if (parse_sql(thd, &lip))
{
sql_print_error("Event Scheduler: "
"%serror during compilation of %s.%s",
@@ -1999,6 +1900,9 @@ end:
thd->lex->unit.cleanup();
thd->end_statement();
thd->cleanup_after_query();
+ /* Avoid races with SHOW PROCESSLIST */
+ thd->query_length= 0;
+ thd->query= NULL;
DBUG_PRINT("info", ("EXECUTED %s.%s ret: %d", dbname.str, name.str, ret));
diff --git a/sql/event_data_objects.h b/sql/event_data_objects.h
index 8e03ab19602..d79732780ff 100644
--- a/sql/event_data_objects.h
+++ b/sql/event_data_objects.h
@@ -77,7 +77,7 @@ public:
Event_basic();
virtual ~Event_basic();
- virtual int
+ virtual bool
load_from_row(THD *thd, TABLE *table) = 0;
protected:
@@ -119,7 +119,7 @@ public:
Event_queue_element();
virtual ~Event_queue_element();
- virtual int
+ virtual bool
load_from_row(THD *thd, TABLE *table);
bool
@@ -157,7 +157,7 @@ public:
void
init();
- virtual int
+ virtual bool
load_from_row(THD *thd, TABLE *table);
int
@@ -176,7 +176,7 @@ public:
Event_job_data();
- virtual int
+ virtual bool
load_from_row(THD *thd, TABLE *table);
bool
@@ -205,12 +205,11 @@ public:
*/
bool do_not_create;
- const char *body_begin;
+ bool body_changed;
LEX_STRING dbname;
LEX_STRING name;
LEX_STRING definer;// combination of user and host
- LEX_STRING body;
LEX_STRING comment;
Item* item_starts;
@@ -235,9 +234,6 @@ public:
bool
check_parse_data(THD *thd);
- void
- init_body(THD *thd);
-
private:
void
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index fa17ee8a380..703c4160216 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -15,6 +15,7 @@
#include "mysql_priv.h"
#include "event_db_repository.h"
+#include "sp_head.h"
#include "event_data_objects.h"
#include "events.h"
#include "sql_show.h"
@@ -141,7 +142,10 @@ const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] =
*/
static bool
-mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
+mysql_event_fill_row(THD *thd,
+ TABLE *table,
+ Event_parse_data *et,
+ sp_head *sp,
my_bool is_update)
{
CHARSET_INFO *scs= system_charset_info;
@@ -152,7 +156,6 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));
DBUG_PRINT("info", ("name =[%s]", et->name.str));
- DBUG_PRINT("info", ("body =[%s]", et->body.str));
if (table->s->fields < ET_FIELD_COUNT)
{
@@ -187,11 +190,18 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
Change the SQL_MODE only if body was present in an ALTER EVENT and of course
always during CREATE EVENT.
*/
- if (et->body.str)
+ if (et->body_changed)
{
+ DBUG_ASSERT(sp->m_body.str);
+
fields[ET_FIELD_SQL_MODE]->store((longlong)thd->variables.sql_mode, TRUE);
- if (fields[f_num= ET_FIELD_BODY]->store(et->body.str, et->body.length, scs))
+
+ if (fields[f_num= ET_FIELD_BODY]->store(sp->m_body.str,
+ sp->m_body.length,
+ scs))
+ {
goto err_truncate;
+ }
}
if (et->expression)
@@ -513,10 +523,12 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
{
int ret= 1;
TABLE *table= NULL;
+ sp_head *sp= thd->lex->sphead;
DBUG_ENTER("Event_db_repository::create_event");
DBUG_PRINT("info", ("open mysql.event for update"));
+ DBUG_ASSERT(sp);
if (open_event_table(thd, TL_WRITE, &table))
goto end;
@@ -561,7 +573,7 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
goto end;
}
- if (parse_data->body.length > table->field[ET_FIELD_BODY]->field_length)
+ if (sp->m_body.length > table->field[ET_FIELD_BODY]->field_length)
{
my_error(ER_TOO_LONG_BODY, MYF(0), parse_data->name.str);
goto end;
@@ -573,7 +585,7 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
mysql_event_fill_row() calls my_error() in case of error so no need to
handle it here
*/
- if (mysql_event_fill_row(thd, table, parse_data, FALSE))
+ if (mysql_event_fill_row(thd, table, parse_data, sp, FALSE))
goto end;
table->field[ET_FIELD_STATUS]->store((longlong)parse_data->status, TRUE);
@@ -617,7 +629,9 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
{
CHARSET_INFO *scs= system_charset_info;
TABLE *table= NULL;
+ sp_head *sp= thd->lex->sphead;
int ret= 1;
+
DBUG_ENTER("Event_db_repository::update_event");
/* None or both must be set */
@@ -661,7 +675,7 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
mysql_event_fill_row() calls my_error() in case of error so no need to
handle it here
*/
- if (mysql_event_fill_row(thd, table, parse_data, TRUE))
+ if (mysql_event_fill_row(thd, table, parse_data, sp, TRUE))
goto end;
if (new_dbname)
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
index 478ae0098da..c552b22e942 100644
--- a/sql/event_scheduler.cc
+++ b/sql/event_scheduler.cc
@@ -326,6 +326,8 @@ end:
delete event;
deinit_event_thread(thd);
+
+ DBUG_VOID_RETURN;
}
diff --git a/sql/field.cc b/sql/field.cc
index e6713e548ab..242d1351bbd 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -38,8 +38,8 @@
*****************************************************************************/
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
-template class List<create_field>;
-template class List_iterator<create_field>;
+template class List<Create_field>;
+template class List_iterator<Create_field>;
#endif
uchar Field_null::null[1]={1};
@@ -2631,7 +2631,7 @@ void Field_new_decimal::sql_type(String &str) const
}
-uint Field_new_decimal::is_equal(create_field *new_field)
+uint Field_new_decimal::is_equal(Create_field *new_field)
{
return ((new_field->sql_type == real_type()) &&
((new_field->flags & UNSIGNED_FLAG) ==
@@ -4366,7 +4366,7 @@ Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
const char *field_name_arg,
TABLE_SHARE *share,
CHARSET_INFO *cs)
- :Field_str(ptr_arg, 19, null_ptr_arg, null_bit_arg,
+ :Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, cs)
{
/* For 4.0 MYD and 4.0 InnoDB compatibility */
@@ -4383,7 +4383,8 @@ Field_timestamp::Field_timestamp(uchar *ptr_arg, uint32 len_arg,
Field_timestamp::Field_timestamp(bool maybe_null_arg,
const char *field_name_arg,
CHARSET_INFO *cs)
- :Field_str((uchar*) 0, 19, maybe_null_arg ? (uchar*) "": 0, 0,
+ :Field_str((uchar*) 0, MAX_DATETIME_WIDTH,
+ maybe_null_arg ? (uchar*) "": 0, 0,
NONE, field_name_arg, cs)
{
/* For 4.0 MYD and 4.0 InnoDB compatibility */
@@ -4916,7 +4917,7 @@ String *Field_time::val_str(String *val_buffer,
{
ASSERT_COLUMN_MARKED_FOR_READ;
MYSQL_TIME ltime;
- val_buffer->alloc(19);
+ val_buffer->alloc(MAX_DATE_STRING_REP_LENGTH);
long tmp=(long) sint3korr(ptr);
ltime.neg= 0;
if (tmp < 0)
@@ -5464,7 +5465,7 @@ int Field_newdate::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
MODE_INVALID_DATES))), &error))
{
- char buff[12];
+ char buff[MAX_DATE_STRING_REP_LENGTH];
String str(buff, sizeof(buff), &my_charset_latin1);
make_date((DATE_TIME_FORMAT *) 0, ltime, &str);
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
@@ -5695,7 +5696,7 @@ int Field_datetime::store_time(MYSQL_TIME *ltime,timestamp_type time_type)
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
MODE_INVALID_DATES))), &error))
{
- char buff[19];
+ char buff[MAX_DATE_STRING_REP_LENGTH];
String str(buff, sizeof(buff), &my_charset_latin1);
make_datetime((DATE_TIME_FORMAT *) 0, ltime, &str);
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
@@ -5771,7 +5772,7 @@ String *Field_datetime::val_str(String *val_buffer,
part1=(long) (tmp/LL(1000000));
part2=(long) (tmp - (ulonglong) part1*LL(1000000));
- pos=(char*) val_buffer->ptr()+19;
+ pos=(char*) val_buffer->ptr() + MAX_DATETIME_WIDTH;
*pos--=0;
*pos--= (char) ('0'+(char) (part2%10)); part2/=10;
*pos--= (char) ('0'+(char) (part2%10)); part3= (int) (part2 / 10);
@@ -6069,7 +6070,7 @@ int Field_str::store(double nr)
}
-uint Field::is_equal(create_field *new_field)
+uint Field::is_equal(Create_field *new_field)
{
return (new_field->sql_type == real_type());
}
@@ -6077,7 +6078,7 @@ uint Field::is_equal(create_field *new_field)
/* If one of the fields is binary and the other one isn't return 1 else 0 */
-bool Field_str::compare_str_field_flags(create_field *new_field, uint32 flags)
+bool Field_str::compare_str_field_flags(Create_field *new_field, uint32 flags)
{
return (((new_field->flags & (BINCMP_FLAG | BINARY_FLAG)) &&
!(flags & (BINCMP_FLAG | BINARY_FLAG))) ||
@@ -6086,7 +6087,7 @@ bool Field_str::compare_str_field_flags(create_field *new_field, uint32 flags)
}
-uint Field_str::is_equal(create_field *new_field)
+uint Field_str::is_equal(Create_field *new_field)
{
if (compare_str_field_flags(new_field, flags))
return 0;
@@ -6939,7 +6940,7 @@ Field *Field_varstring::new_key_field(MEM_ROOT *root,
}
-uint Field_varstring::is_equal(create_field *new_field)
+uint Field_varstring::is_equal(Create_field *new_field)
{
if (new_field->sql_type == real_type() &&
new_field->charset == field_charset)
@@ -7621,7 +7622,7 @@ uint Field_blob::max_packed_col_length(uint max_length)
}
-uint Field_blob::is_equal(create_field *new_field)
+uint Field_blob::is_equal(Create_field *new_field)
{
if (compare_str_field_flags(new_field, flags))
return 0;
@@ -8159,7 +8160,7 @@ bool Field_num::eq_def(Field *field)
}
-uint Field_num::is_equal(create_field *new_field)
+uint Field_num::is_equal(Create_field *new_field)
{
return ((new_field->sql_type == real_type()) &&
((new_field->flags & UNSIGNED_FLAG) == (uint) (flags &
@@ -8264,7 +8265,7 @@ Field *Field_bit::new_key_field(MEM_ROOT *root,
}
-uint Field_bit::is_equal(create_field *new_field)
+uint Field_bit::is_equal(Create_field *new_field)
{
return (new_field->sql_type == real_type() &&
new_field->length == max_display_length());
@@ -8595,20 +8596,20 @@ void Field_bit_as_char::sql_type(String &res) const
/*****************************************************************************
- Handling of field and create_field
+ Handling of field and Create_field
*****************************************************************************/
/*
- Convert create_field::length from number of characters to number of bytes
+ Convert Create_field::length from number of characters to number of bytes
SYNOPSIS
- create_field::create_length_to_internal_length()
+ Create_field::create_length_to_internal_length()
DESCRIPTION
- Convert create_field::length from number of characters to number of bytes.
+ Convert Create_field::length from number of characters to number of bytes.
*/
-void create_field::create_length_to_internal_length(void)
+void Create_field::create_length_to_internal_length(void)
{
switch (sql_type) {
case MYSQL_TYPE_TINY_BLOB:
@@ -8655,7 +8656,7 @@ void create_field::create_length_to_internal_length(void)
}
-void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
+void Create_field::init_for_tmp_table(enum_field_types sql_type_arg,
uint32 length_arg, uint32 decimals_arg,
bool maybe_null, bool is_unsigned)
{
@@ -8696,7 +8697,7 @@ void create_field::init_for_tmp_table(enum_field_types sql_type_arg,
TRUE on error
*/
-bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
+bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
char *fld_length, char *fld_decimals,
uint fld_type_modifier, Item *fld_default_value,
Item *fld_on_update_value, LEX_STRING *fld_comment,
@@ -8706,7 +8707,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
uint sign_len, allowed_type_modifier= 0;
ulong max_field_charlength= MAX_FIELD_CHARLENGTH;
- DBUG_ENTER("create_field::init()");
+ DBUG_ENTER("Create_field::init()");
field= 0;
field_name= fld_name;
@@ -8890,15 +8891,18 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
break;
case MYSQL_TYPE_TIMESTAMP:
if (!fld_length)
- length= 14; /* Full date YYYYMMDDHHMMSS */
- else if (length != 19)
+ {
+ /* Compressed date YYYYMMDDHHMMSS */
+ length= MAX_DATETIME_COMPRESSED_WIDTH;
+ }
+ else if (length != MAX_DATETIME_WIDTH)
{
/*
We support only even TIMESTAMP lengths less or equal than 14
and 19 as length of 4.1 compatible representation.
*/
length= ((length+1)/2)*2; /* purecov: inspected */
- length= min(length,14); /* purecov: inspected */
+ length= min(length, MAX_DATETIME_COMPRESSED_WIDTH); /* purecov: inspected */
}
flags|= ZEROFILL_FLAG | UNSIGNED_FLAG;
if (fld_default_value)
@@ -8951,7 +8955,7 @@ bool create_field::init(THD *thd, char *fld_name, enum_field_types fld_type,
length= 10;
break;
case MYSQL_TYPE_DATETIME:
- length= 19;
+ length= MAX_DATETIME_WIDTH;
break;
case MYSQL_TYPE_SET:
{
@@ -9279,7 +9283,7 @@ Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length,
/* Create a field suitable for create of table */
-create_field::create_field(Field *old_field,Field *orig_field)
+Create_field::Create_field(Field *old_field,Field *orig_field)
{
field= old_field;
field_name=change=old_field->field_name;
diff --git a/sql/field.h b/sql/field.h
index 3b4784adb2b..a0fe0f2e57e 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -28,7 +28,7 @@
class Send_field;
class Protocol;
-class create_field;
+class Create_field;
struct st_cache_field;
int field_conv(Field *to,Field *from);
@@ -413,7 +413,7 @@ public:
/* maximum possible display length */
virtual uint32 max_display_length()= 0;
- virtual uint is_equal(create_field *new_field);
+ virtual uint is_equal(Create_field *new_field);
/* convert decimal to longlong with overflow check */
longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag,
int *err);
@@ -474,14 +474,14 @@ public:
Item_result result_type () const { return REAL_RESULT; }
void prepend_zeros(String *value);
void add_zerofill_and_unsigned(String &res) const;
- friend class create_field;
+ friend class Create_field;
void make_field(Send_field *);
uint decimals() const { return (uint) dec; }
uint size_of() const { return sizeof(*this); }
bool eq_def(Field *field);
int store_decimal(const my_decimal *);
my_decimal *val_decimal(my_decimal *);
- uint is_equal(create_field *new_field);
+ uint is_equal(Create_field *new_field);
int check_int(CHARSET_INFO *cs, const char *str, int length,
const char *int_end, int error);
bool get_int(CHARSET_INFO *cs, const char *from, uint len,
@@ -512,11 +512,11 @@ public:
{ field_derivation= derivation_arg; }
bool binary() const { return field_charset == &my_charset_bin; }
uint32 max_display_length() { return field_length; }
- friend class create_field;
+ friend class Create_field;
my_decimal *val_decimal(my_decimal *);
virtual bool str_needs_quotes() { return TRUE; }
- bool compare_str_field_flags(create_field *new_field, uint32 flags);
- uint is_equal(create_field *new_field);
+ bool compare_str_field_flags(Create_field *new_field, uint32 flags);
+ uint is_equal(Create_field *new_field);
};
@@ -625,7 +625,7 @@ public:
uint32 max_display_length() { return field_length; }
uint size_of() const { return sizeof(*this); }
uint32 pack_length() const { return (uint32) bin_size; }
- uint is_equal(create_field *new_field);
+ uint is_equal(Create_field *new_field);
};
@@ -1257,7 +1257,7 @@ public:
Field *new_key_field(MEM_ROOT *root, struct st_table *new_table,
uchar *new_ptr, uchar *new_null_ptr,
uint new_null_bit);
- uint is_equal(create_field *new_field);
+ uint is_equal(Create_field *new_field);
void hash(ulong *nr, ulong *nr2);
};
@@ -1391,7 +1391,7 @@ public:
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
uint32 max_display_length();
- uint is_equal(create_field *new_field);
+ uint is_equal(Create_field *new_field);
};
@@ -1570,7 +1570,7 @@ public:
bit_ptr == ((Field_bit *)field)->bit_ptr &&
bit_ofs == ((Field_bit *)field)->bit_ofs);
}
- uint is_equal(create_field *new_field);
+ uint is_equal(Create_field *new_field);
void move_field_offset(my_ptrdiff_t ptr_diff)
{
Field::move_field_offset(ptr_diff);
@@ -1608,7 +1608,7 @@ public:
Create field class for CREATE TABLE
*/
-class create_field :public Sql_alloc
+class Create_field :public Sql_alloc
{
public:
const char *field_name;
@@ -1639,11 +1639,11 @@ public:
uint8 row,col,sc_length,interval_id; // For rea_create_table
uint offset,pack_flag;
- create_field() :after(0) {}
- create_field(Field *field, Field *orig_field);
+ Create_field() :after(0) {}
+ Create_field(Field *field, Field *orig_field);
/* Used to make a clone of this object for ALTER/CREATE TABLE */
- create_field *clone(MEM_ROOT *mem_root) const
- { return new (mem_root) create_field(*this); }
+ Create_field *clone(MEM_ROOT *mem_root) const
+ { return new (mem_root) Create_field(*this); }
void create_length_to_internal_length(void);
/* Init for a tmp table field. To be extended if need be. */
diff --git a/sql/handler.cc b/sql/handler.cc
index 1a468f306e3..a0f27824533 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -3376,8 +3376,8 @@ TYPELIB *ha_known_exts(void)
const char **ext, *old_ext;
known_extensions_id= mysys_usage_id;
- found_exts.push_back((char*) triggers_file_ext);
- found_exts.push_back((char*) trigname_file_ext);
+ found_exts.push_back((char*) TRG_EXT);
+ found_exts.push_back((char*) TRN_EXT);
plugin_foreach(NULL, exts_handlerton,
MYSQL_STORAGE_ENGINE_PLUGIN, &found_exts);
diff --git a/sql/item.h b/sql/item.h
index 91f116b985e..c79107e04bd 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1768,7 +1768,7 @@ public:
We have to have a different max_length than 'length' here to
ensure that we get the right length if we do use the item
to create a new table. In this case max_length must be the maximum
- number of chars for a string of this type because we in create_field::
+ number of chars for a string of this type because we in Create_field::
divide the max_length with mbmaxlen).
*/
max_length= str_value.numchars()*cs->mbmaxlen;
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 08ce47573e7..10bd24dbb66 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -912,8 +912,8 @@ void Item_sum_distinct::fix_length_and_dec()
bool Item_sum_distinct::setup(THD *thd)
{
- List<create_field> field_list;
- create_field field_def; /* field definition */
+ List<Create_field> field_list;
+ Create_field field_def; /* field definition */
DBUG_ENTER("Item_sum_distinct::setup");
DBUG_ASSERT(tree == 0);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 6f38a1acc67..95ff7dfd336 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -51,7 +51,7 @@ static bool make_datetime(date_time_format_types format, MYSQL_TIME *ltime,
{
char *buff;
CHARSET_INFO *cs= &my_charset_bin;
- uint length= 30;
+ uint length= MAX_DATE_STRING_REP_LENGTH;
if (str->alloc(length))
return 1;
@@ -1379,7 +1379,7 @@ String *Item_date::val_str(String *str)
MYSQL_TIME ltime;
if (get_date(&ltime, TIME_FUZZY_DATE))
return (String *) 0;
- if (str->alloc(11))
+ if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
{
null_value= 1;
return (String *) 0;
@@ -1428,7 +1428,7 @@ void Item_func_curdate::fix_length_and_dec()
String *Item_func_curdate::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
- if (str->alloc(11))
+ if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
{
null_value= 1;
return (String *) 0;
@@ -1657,7 +1657,8 @@ String *Item_func_sec_to_time::val_str(String *str)
MYSQL_TIME ltime;
longlong arg_val= args[0]->val_int();
- if ((null_value=args[0]->null_value) || str->alloc(19))
+ if ((null_value=args[0]->null_value) ||
+ str->alloc(MAX_DATE_STRING_REP_LENGTH))
{
null_value= 1;
return (String*) 0;
@@ -1842,6 +1843,10 @@ String *Item_func_date_format::val_str(String *str)
size=max_length;
else
size=format_length(format);
+
+ if (size < MAX_DATE_STRING_REP_LENGTH)
+ size= MAX_DATE_STRING_REP_LENGTH;
+
if (format == str)
str= &value; // Save result here
if (str->alloc(size))
@@ -1885,13 +1890,14 @@ String *Item_func_from_unixtime::val_str(String *str)
if (get_date(&time_tmp, 0))
return 0;
- if (str->alloc(20*MY_CHARSET_BIN_MB_MAXLEN))
+ if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
{
null_value= 1;
return 0;
}
make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str);
+
return str;
}
@@ -1940,14 +1946,15 @@ String *Item_func_convert_tz::val_str(String *str)
if (get_date(&time_tmp, 0))
return 0;
-
- if (str->alloc(20*MY_CHARSET_BIN_MB_MAXLEN))
+
+ if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
{
null_value= 1;
return 0;
}
-
+
make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str);
+
return str;
}
@@ -2433,6 +2440,7 @@ String *Item_datetime_typecast::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
+
if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
!make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME,
&ltime, str))
@@ -2511,7 +2519,8 @@ String *Item_date_typecast::val_str(String *str)
DBUG_ASSERT(fixed == 1);
MYSQL_TIME ltime;
- if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) && !str->alloc(11))
+ if (!get_arg0_date(&ltime, TIME_FUZZY_DATE) &&
+ !str->alloc(MAX_DATE_STRING_REP_LENGTH))
{
make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
return str;
@@ -2564,7 +2573,7 @@ String *Item_func_makedate::val_str(String *str)
{
null_value=0;
get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day);
- if (str->alloc(11))
+ if (str->alloc(MAX_DATE_STRING_REP_LENGTH))
goto err;
make_date((DATE_TIME_FORMAT *) 0, &l_time, str);
return str;
@@ -2700,6 +2709,7 @@ String *Item_func_add_time::val_str(String *str)
days= (long)(seconds/86400L);
calc_time_from_sec(&l_time3, (long)(seconds%86400L), microseconds);
+
if (!is_time)
{
get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day);
@@ -2815,7 +2825,7 @@ String *Item_func_maketime::val_str(String *str)
args[2]->null_value ||
minute < 0 || minute > 59 ||
second < 0 || second > 59 ||
- str->alloc(19))))
+ str->alloc(MAX_DATE_STRING_REP_LENGTH))))
return 0;
bzero((char *)&ltime, sizeof(ltime));
diff --git a/sql/log.cc b/sql/log.cc
index ac6ea92c61a..6dc204265b0 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -307,6 +307,9 @@ bool Log_to_csv_event_handler::open_log_table(uint log_table_type)
table->table->use_all_columns();
table->table->locked_by_logger= TRUE;
table->table->no_replicate= TRUE;
+
+ /* Honor next number columns if present */
+ table->table->next_number_field= table->table->found_next_number_field;
}
/* restore thread settings */
if (curr)
@@ -440,6 +443,7 @@ bool Log_to_csv_event_handler::
CHARSET_INFO *client_cs)
{
TABLE *table= general_log.table;
+ uint field_index;
/*
"INSERT INTO general_log" can generate warning sometimes.
@@ -490,6 +494,12 @@ bool Log_to_csv_event_handler::
table->field[4]->set_notnull();
table->field[5]->set_notnull();
+ /* Set any extra columns to their default values */
+ for (field_index= 6 ; field_index < table->s->fields ; field_index++)
+ {
+ table->field[field_index]->set_default();
+ }
+
/* log table entries are not replicated at the moment */
tmp_disable_binlog(current_thd);
@@ -1331,6 +1341,7 @@ void Log_to_csv_event_handler::
/* close the table */
log_thd->store_globals();
table->table->file->ha_rnd_end();
+ table->table->file->ha_release_auto_increment();
/* discard logger mark before unlock*/
table->table->locked_by_logger= FALSE;
close_thread_tables(log_thd, lock_in_use);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 83244d3aeff..2b427e62c8b 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -101,7 +101,7 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
ER_WARN_DEPRECATED_SYNTAX, ER(ER_WARN_DEPRECATED_SYNTAX), \
(Old), (Ver), (New)); \
else \
- sql_print_warning("The syntax %s is deprecated and will be removed " \
+ sql_print_warning("The syntax '%s' is deprecated and will be removed " \
"in MySQL %s. Please use %s instead.", (Old), (Ver), (New)); \
} while(0)
@@ -618,6 +618,8 @@ bool check_string_char_length(LEX_STRING *str, const char *err_msg,
uint max_char_length, CHARSET_INFO *cs,
bool no_error);
+bool parse_sql(THD *thd, class Lex_input_stream *lip);
+
enum enum_mysql_completiontype {
ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7,
COMMIT_RELEASE=-1, COMMIT=0, COMMIT_AND_CHAIN=6
@@ -908,7 +910,7 @@ bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* table_list,
bool mysql_preload_keys(THD* thd, TABLE_LIST* table_list);
int reassign_keycache_tables(THD* thd, KEY_CACHE *src_cache,
KEY_CACHE *dst_cache);
-TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list);
+TABLE *create_virtual_tmp_table(THD *thd, List<Create_field> &field_list);
bool mysql_xa_recover(THD *thd);
@@ -952,8 +954,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
bool table_cant_handle_bit_fields,
bool make_copy_field,
uint convert_blob_length);
-void sp_prepare_create_field(THD *thd, create_field *sql_field);
-int prepare_create_field(create_field *sql_field,
+void sp_prepare_create_field(THD *thd, Create_field *sql_field);
+int prepare_create_field(Create_field *sql_field,
uint *blob_columns,
int *timestamps, int *timestamps_with_niladic,
longlong table_flags);
@@ -1178,7 +1180,7 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum enum_field_types t
char *change, List<String> *interval_list,
CHARSET_INFO *cs,
uint uint_geom_type);
-create_field * new_create_field(THD *thd, char *field_name, enum_field_types type,
+Create_field * new_create_field(THD *thd, char *field_name, enum_field_types type,
char *length, char *decimals,
uint type_modifier,
Item *default_value, Item *on_update_value,
@@ -1588,6 +1590,7 @@ bool check_db_dir_existence(const char *db_name);
bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
bool load_db_opt_by_name(THD *thd, const char *db_name,
HA_CREATE_INFO *db_create_info);
+CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name);
bool my_dbopt_init(void);
void my_dbopt_cleanup(void);
extern int creating_database; // How many database locks are made
@@ -1609,8 +1612,8 @@ extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword;
extern const char **errmesg; /* Error messages */
extern const char *myisam_recover_options_str;
extern const char *in_left_expr_name, *in_additional_cond, *in_having_cond;
-extern const char * const triggers_file_ext;
-extern const char * const trigname_file_ext;
+extern const char * const TRG_EXT;
+extern const char * const TRN_EXT;
extern Eq_creator eq_creator;
extern Ne_creator ne_creator;
extern Gt_creator gt_creator;
@@ -1805,12 +1808,12 @@ void unireg_end(void) __attribute__((noreturn));
bool mysql_create_frm(THD *thd, const char *file_name,
const char *db, const char *table,
HA_CREATE_INFO *create_info,
- List<create_field> &create_field,
+ List<Create_field> &create_field,
uint key_count,KEY *key_info,handler *db_type);
int rea_create_table(THD *thd, const char *path,
const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
- List<create_field> &create_field,
+ List<Create_field> &create_field,
uint key_count,KEY *key_info,
handler *file);
int format_number(uint inputflag,uint max_length,char * pos,uint length,
@@ -1961,7 +1964,6 @@ void free_list(I_List <i_string_pair> *list);
void free_list(I_List <i_string> *list);
/* sql_yacc.cc */
-extern int MYSQLparse(void *thd);
#ifndef DBUG_OFF
extern void turn_parser_debug_on();
#endif
@@ -2153,6 +2155,12 @@ bool schema_table_store_record(THD *thd, TABLE *table);
int item_create_init();
void item_create_cleanup();
+inline void lex_string_set(LEX_STRING *lex_str, const char *c_str)
+{
+ lex_str->str= (char *) c_str;
+ lex_str->length= strlen(c_str);
+}
+
#endif /* MYSQL_SERVER */
#endif /* MYSQL_CLIENT */
diff --git a/sql/sp.cc b/sql/sp.cc
index 49e86f9d07e..a8e6c2844a2 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -384,32 +384,32 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
if ((ret= sp_use_new_db(thd, name->m_db, &old_db, 1, &dbchanged)))
goto end;
+ thd->spcont= NULL;
+
{
Lex_input_stream lip(thd, defstr.c_ptr(), defstr.length());
- thd->m_lip= &lip;
lex_start(thd);
- ret= MYSQLparse(thd);
- }
- thd->spcont= 0;
- if (ret || thd->is_fatal_error || newlex.sphead == NULL)
- {
- sp_head *sp= newlex.sphead;
+ if (parse_sql(thd, &lip) || newlex.sphead == NULL)
+ {
+ sp_head *sp= newlex.sphead;
- if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
- goto end;
- delete sp;
- ret= SP_PARSE_ERROR;
- }
- else
- {
- if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
- goto end;
- *sphp= newlex.sphead;
- (*sphp)->set_definer(&definer_user_name, &definer_host_name);
- (*sphp)->set_info(created, modified, &chistics, sql_mode);
- (*sphp)->optimize();
+ if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
+ goto end;
+ delete sp;
+ ret= SP_PARSE_ERROR;
+ }
+ else
+ {
+ if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
+ goto end;
+ *sphp= newlex.sphead;
+ (*sphp)->set_definer(&definer_user_name, &definer_host_name);
+ (*sphp)->set_info(created, modified, &chistics, sql_mode);
+ (*sphp)->optimize();
+ }
}
+
end:
lex_end(thd->lex);
thd->spcont= old_spcont;
@@ -588,10 +588,14 @@ sp_create_routine(THD *thd, int type, sp_head *sp)
log_query.append(STRING_WITH_LEN("CREATE "));
append_definer(thd, &log_query, &thd->lex->definer->user,
&thd->lex->definer->host);
- log_query.append(thd->lex->stmt_definition_begin,
- (char *)sp->m_body_begin -
- thd->lex->stmt_definition_begin +
- sp->m_body.length);
+
+ LEX_STRING stmt_definition;
+ stmt_definition.str= (char*) thd->lex->stmt_definition_begin;
+ stmt_definition.length= thd->lex->stmt_definition_end
+ - thd->lex->stmt_definition_begin;
+ trim_whitespace(thd->charset(), & stmt_definition);
+
+ log_query.append(stmt_definition.str, stmt_definition.length);
/* Such a statement can always go directly to binlog, no trans cache */
thd->binlog_query(THD::MYSQL_QUERY_TYPE,
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index bbf281caee0..feceb2fb960 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -564,24 +564,23 @@ sp_head::init_strings(THD *thd, LEX *lex)
m_params.str= strmake_root(root, m_param_begin, m_params.length);
}
- /* If ptr has overrun end_of_query then end_of_query is the end */
- endp= (lip->ptr > lip->end_of_query ? lip->end_of_query : lip->ptr);
- /*
- Trim "garbage" at the end. This is sometimes needed with the
- "/ * ! VERSION... * /" wrapper in dump files.
- */
- endp= skip_rear_comments(thd->charset(), m_body_begin, endp);
+ endp= lip->get_cpp_ptr();
+ lex->stmt_definition_end= endp;
m_body.length= endp - m_body_begin;
m_body.str= strmake_root(root, m_body_begin, m_body.length);
- m_defstr.length= endp - lip->buf;
- m_defstr.str= strmake_root(root, lip->buf, m_defstr.length);
+ trim_whitespace(thd->charset(), & m_body);
+
+ m_defstr.length= endp - lip->get_cpp_buf();
+ m_defstr.str= strmake_root(root, lip->get_cpp_buf(), m_defstr.length);
+ trim_whitespace(thd->charset(), & m_defstr);
+
DBUG_VOID_RETURN;
}
static TYPELIB *
-create_typelib(MEM_ROOT *mem_root, create_field *field_def, List<String> *src)
+create_typelib(MEM_ROOT *mem_root, Create_field *field_def, List<String> *src)
{
TYPELIB *result= NULL;
CHARSET_INFO *cs= field_def->charset;
@@ -1269,30 +1268,31 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
#endif // ! NO_EMBEDDED_ACCESS_CHECKS
-/*
+/**
+ Execute trigger stored program.
+
Execute a trigger:
- - changes security context for triggers
- - switch to new memroot
- - call sp_head::execute
- - restore old memroot
- - restores security context
+ - changes security context for triggers;
+ - switch to new memroot;
+ - call sp_head::execute;
+ - restore old memroot;
+ - restores security context.
+
+ @param thd Thread context.
+ @param db_name Database name.
+ @param table_name Table name.
+ @param grant_info GRANT_INFO structure to be filled with information
+ about definer's privileges on subject table.
- SYNOPSIS
- sp_head::execute_trigger()
- thd Thread handle
- db database name
- table table name
- grant_info GRANT_INFO structure to be filled with
- information about definer's privileges
- on subject table
-
- RETURN
- FALSE on success
- TRUE on error
+ @return Error status.
+ @retval FALSE on success.
+ @retval TRUE on error.
*/
bool
-sp_head::execute_trigger(THD *thd, const char *db, const char *table,
+sp_head::execute_trigger(THD *thd,
+ const LEX_STRING *db_name,
+ const LEX_STRING *table_name,
GRANT_INFO *grant_info)
{
sp_rcontext *octx = thd->spcont;
@@ -1305,6 +1305,46 @@ sp_head::execute_trigger(THD *thd, const char *db, const char *table,
DBUG_ENTER("sp_head::execute_trigger");
DBUG_PRINT("info", ("trigger %s", m_name.str));
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ Security_context *save_ctx= NULL;
+
+
+ if (m_chistics->suid != SP_IS_NOT_SUID &&
+ m_security_ctx.change_security_context(thd,
+ &m_definer_user,
+ &m_definer_host,
+ &m_db,
+ &save_ctx))
+ DBUG_RETURN(TRUE);
+
+ /*
+ Fetch information about table-level privileges for subject table into
+ GRANT_INFO instance. The access check itself will happen in
+ Item_trigger_field, where this information will be used along with
+ information about column-level privileges.
+ */
+
+ fill_effective_table_privileges(thd,
+ grant_info,
+ db_name->str,
+ table_name->str);
+
+ /* Check that the definer has TRIGGER privilege on the subject table. */
+
+ if (!(grant_info->privilege & TRIGGER_ACL))
+ {
+ char priv_desc[128];
+ get_privilege_desc(priv_desc, sizeof(priv_desc), TRIGGER_ACL);
+
+ my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), priv_desc,
+ thd->security_ctx->priv_user, thd->security_ctx->host_or_ip,
+ table_name->str);
+
+ m_security_ctx.restore_security_context(thd, save_ctx);
+ DBUG_RETURN(TRUE);
+ }
+#endif // NO_EMBEDDED_ACCESS_CHECKS
+
/*
Prepare arena and memroot for objects which lifetime is whole
duration of trigger call (sp_rcontext, it's tables and items,
@@ -1337,6 +1377,11 @@ sp_head::execute_trigger(THD *thd, const char *db, const char *table,
err_with_cleanup:
thd->restore_active_arena(&call_arena, &backup_arena);
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ m_security_ctx.restore_security_context(thd, save_ctx);
+#endif // NO_EMBEDDED_ACCESS_CHECKS
+
delete nctx;
call_arena.free_items();
free_root(&call_mem_root, MYF(0));
@@ -1827,8 +1872,6 @@ sp_head::reset_lex(THD *thd)
sublex->trg_table_fields.empty();
sublex->sp_lex_in_use= FALSE;
- sublex->in_comment= oldlex->in_comment;
-
/* Reset type info. */
sublex->charset= NULL;
@@ -1908,7 +1951,7 @@ sp_head::backpatch(sp_label_t *lab)
}
/*
- Prepare an instance of create_field for field creation (fill all necessary
+ Prepare an instance of Create_field for field creation (fill all necessary
attributes).
SYNOPSIS
@@ -1916,7 +1959,7 @@ sp_head::backpatch(sp_label_t *lab)
thd [IN] Thread handle
lex [IN] Yacc parsing context
field_type [IN] Field type
- field_def [OUT] An instance of create_field to be filled
+ field_def [OUT] An instance of Create_field to be filled
RETURN
FALSE on success
@@ -1926,7 +1969,7 @@ sp_head::backpatch(sp_label_t *lab)
bool
sp_head::fill_field_definition(THD *thd, LEX *lex,
enum enum_field_types field_type,
- create_field *field_def)
+ Create_field *field_def)
{
HA_CREATE_INFO sp_db_info;
LEX_STRING cmt = { 0, 0 };
@@ -2011,6 +2054,13 @@ sp_head::set_info(longlong created, longlong modified,
void
+sp_head::set_body_begin_ptr(Lex_input_stream *lip, const char *begin_ptr)
+{
+ m_body_begin= begin_ptr;
+}
+
+
+void
sp_head::set_definer(const char *definer, uint definerlen)
{
char user_name_holder[USERNAME_LENGTH + 1];
diff --git a/sql/sp_head.h b/sql/sp_head.h
index eacc2ccdcf6..2d3bc1307d9 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -126,7 +126,7 @@ public:
int m_type;
uint m_flags; // Boolean attributes of a stored routine
- create_field m_return_field_def; /* This is used for FUNCTIONs only. */
+ Create_field m_return_field_def; /* This is used for FUNCTIONs only. */
const char *m_tmp_query; // Temporary pointer to sub query string
st_sp_chistics *m_chistics;
@@ -178,8 +178,11 @@ public:
// Pointers set during parsing
const char *m_param_begin;
const char *m_param_end;
+
+private:
const char *m_body_begin;
+public:
/*
Security context for stored routine which should be run under
definer privileges.
@@ -216,8 +219,10 @@ public:
destroy();
bool
- execute_trigger(THD *thd, const char *db, const char *table,
- GRANT_INFO *grant_onfo);
+ execute_trigger(THD *thd,
+ const LEX_STRING *db_name,
+ const LEX_STRING *table_name,
+ GRANT_INFO *grant_info);
bool
execute_function(THD *thd, Item **args, uint argcount, Field *return_fld);
@@ -290,11 +295,13 @@ public:
bool fill_field_definition(THD *thd, LEX *lex,
enum enum_field_types field_type,
- create_field *field_def);
+ Create_field *field_def);
void set_info(longlong created, longlong modified,
st_sp_chistics *chistics, ulong sql_mode);
+ void set_body_begin_ptr(Lex_input_stream *lip, const char *begin_ptr);
+
void set_definer(const char *definer, uint definerlen);
void set_definer(const LEX_STRING *user_name, const LEX_STRING *host_name);
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index 9c96485b8ec..8babbd52ff6 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -422,7 +422,7 @@ sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped)
void
-sp_pcontext::retrieve_field_definitions(List<create_field> *field_def_lst)
+sp_pcontext::retrieve_field_definitions(List<Create_field> *field_def_lst)
{
/* Put local/context fields in the result list. */
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index 3b8b165a6e0..aefc501b3b0 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -43,7 +43,7 @@ typedef struct sp_variable
uint offset;
Item *dflt;
- create_field field_def;
+ Create_field field_def;
} sp_variable_t;
@@ -234,7 +234,7 @@ public:
children.
*/
void
- retrieve_field_definitions(List<create_field> *field_def_lst);
+ retrieve_field_definitions(List<Create_field> *field_def_lst);
// Find by name
sp_variable_t *
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index e49c4eb1240..b94c733cb0a 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -102,7 +102,7 @@ bool sp_rcontext::init(THD *thd)
bool
sp_rcontext::init_var_table(THD *thd)
{
- List<create_field> field_def_lst;
+ List<Create_field> field_def_lst;
if (!m_root_parsing_ctx->max_var_index())
return FALSE;
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 04f142c5dfb..719c67aff6a 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -1459,40 +1459,62 @@ void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length,
DBUG_VOID_RETURN;
}
-/*
- Remove all cached queries that uses the given database
+/**
+ @brief Remove all cached queries that uses the given database
*/
-
void Query_cache::invalidate(char *db)
{
+ bool restart= FALSE;
DBUG_ENTER("Query_cache::invalidate (db)");
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0 && !flush_in_progress)
{
- DUMP(this);
- restart_search:
if (tables_blocks)
{
- Query_cache_block *curr= tables_blocks;
- Query_cache_block *next;
- do
- {
- next= curr->next;
- if (strcmp(db, (char*)(curr->table()->db())) == 0)
- invalidate_table(curr);
+ Query_cache_block *table_block = tables_blocks;
+ do {
+ restart= FALSE;
+ do
+ {
+ Query_cache_block *next= table_block->next;
+ Query_cache_table *table = table_block->table();
+ if (strcmp(table->db(),db) == 0)
+ invalidate_table(table_block);
+
+ table_block= next;
+
+ /*
+ If our root node to used tables became null then the last element
+ in the table list was removed when a query was invalidated;
+ Terminate the search.
+ */
+ if (tables_blocks == 0)
+ {
+ table_block= tables_blocks;
+ }
+ /*
+ If the iterated list has changed underlying structure;
+ we need to restart the search.
+ */
+ else if (table_block->type == Query_cache_block::FREE)
+ {
+ restart= TRUE;
+ table_block= tables_blocks;
+ }
+ /*
+ The used tables are linked in a circular list;
+ loop until we return to the begining.
+ */
+ } while (table_block != tables_blocks);
/*
- invalidate_table can freed block on which point 'next' (if
- table of this block used only in queries which was deleted
- by invalidate_table). As far as we do not allocate new blocks
- and mark all headers of freed blocks as 'FREE' (even if they are
- merged with other blocks) we can just test type of block
- to be sure that block is not deleted
+ Invalidating a table will also mean that all cached queries using
+ this table also will be invalidated. This will in turn change the
+ list of tables associated with these queries and the linked list of
+ used table will be changed. Because of this we might need to restart
+ the search when a table has been invalidated.
*/
- if (next->type == Query_cache_block::FREE)
- goto restart_search;
- curr= next;
- } while (curr != tables_blocks);
- }
+ } while (restart);
+ } // end if( tables_blocks )
}
STRUCT_UNLOCK(&structure_guard_mutex);
@@ -2395,6 +2417,7 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used,
(ulong) tables_used->table,
(ulong) tables_used->table->s->table_cache_key.length,
(ulong) tables_used->table->s->table_cache_key.str));
+
if (!insert_table(tables_used->table->s->table_cache_key.length,
tables_used->table->s->table_cache_key.str,
block_table,
@@ -2461,9 +2484,8 @@ my_bool Query_cache::register_all_tables(Query_cache_block *block,
n= register_tables_from_list(tables_used, 0, block_table);
- if (n)
+ if (n==0)
{
- DBUG_PRINT("qcache", ("failed at table %d", (int) n));
/* Unlink the tables we allocated above */
for (Query_cache_block_table *tmp = block->table(0) ;
tmp != block_table;
@@ -2953,8 +2975,11 @@ Query_cache::double_linked_list_exclude(Query_cache_block *point,
{
point->next->prev = point->prev;
point->prev->next = point->next;
+ /*
+ If the root is removed; select a new root
+ */
if (point == *list_pointer)
- *list_pointer = point->next;
+ *list_pointer= point->next;
}
DBUG_VOID_RETURN;
}
@@ -3752,7 +3777,7 @@ void Query_cache::tables_dump()
Query_cache_table *table = table_block->table();
DBUG_PRINT("qcache", ("'%s' '%s'", table->db(), table->table()));
table_block = table_block->next;
- } while ( table_block != tables_blocks);
+ } while (table_block != tables_blocks);
}
else
DBUG_PRINT("qcache", ("no tables in list"));
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 9dbc79344a9..62f6706d717 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -59,8 +59,8 @@ const char * const THD::DEFAULT_WHERE= "field list";
/* Used templates */
template class List<Key>;
template class List_iterator<Key>;
-template class List<key_part_spec>;
-template class List_iterator<key_part_spec>;
+template class List<Key_part_spec>;
+template class List_iterator<Key_part_spec>;
template class List<Alter_drop>;
template class List_iterator<Alter_drop>;
template class List<Alter_column>;
@@ -86,7 +86,7 @@ extern "C" void free_user_var(user_var_entry *entry)
my_free((char*) entry,MYF(0));
}
-bool key_part_spec::operator==(const key_part_spec& other) const
+bool Key_part_spec::operator==(const Key_part_spec& other) const
{
return length == other.length && !strcmp(field_name, other.field_name);
}
@@ -115,7 +115,7 @@ Key::Key(const Key &rhs, MEM_ROOT *mem_root)
in THD.
*/
-foreign_key::foreign_key(const foreign_key &rhs, MEM_ROOT *mem_root)
+Foreign_key::Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root)
:Key(rhs),
ref_table(rhs.ref_table),
ref_columns(rhs.ref_columns),
@@ -160,9 +160,9 @@ bool foreign_key_prefix(Key *a, Key *b)
if (a->columns.elements > b->columns.elements)
return TRUE; // Can't be prefix
- List_iterator<key_part_spec> col_it1(a->columns);
- List_iterator<key_part_spec> col_it2(b->columns);
- const key_part_spec *col1, *col2;
+ List_iterator<Key_part_spec> col_it1(a->columns);
+ List_iterator<Key_part_spec> col_it2(b->columns);
+ const Key_part_spec *col1, *col2;
#ifdef ENABLE_WHEN_INNODB_CAN_HANDLE_SWAPED_FOREIGN_KEY_COLUMNS
while ((col1= col_it1++))
@@ -342,7 +342,8 @@ THD::THD()
in_lock_tables(0),
bootstrap(0),
derived_tables_processing(FALSE),
- spcont(NULL)
+ spcont(NULL),
+ m_lip(NULL)
{
ulong tmp;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index de7aaafbe3b..dd03225b501 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -85,14 +85,14 @@ typedef struct st_copy_info {
} COPY_INFO;
-class key_part_spec :public Sql_alloc {
+class Key_part_spec :public Sql_alloc {
public:
const char *field_name;
uint length;
- key_part_spec(const char *name,uint len=0) :field_name(name), length(len) {}
- bool operator==(const key_part_spec& other) const;
+ Key_part_spec(const char *name,uint len=0) :field_name(name), length(len) {}
+ bool operator==(const Key_part_spec& other) const;
/**
- Construct a copy of this key_part_spec. field_name is copied
+ Construct a copy of this Key_part_spec. field_name is copied
by-pointer as it is known to never change. At the same time
'length' may be reset in mysql_prepare_create_table, and this
is why we supply it with a copy.
@@ -100,8 +100,8 @@ public:
@return If out of memory, 0 is returned and an error is set in
THD.
*/
- key_part_spec *clone(MEM_ROOT *mem_root) const
- { return new (mem_root) key_part_spec(*this); }
+ Key_part_spec *clone(MEM_ROOT *mem_root) const
+ { return new (mem_root) Key_part_spec(*this); }
};
@@ -114,7 +114,7 @@ public:
:name(par_name), type(par_type) {}
/**
Used to make a clone of this object for ALTER/CREATE TABLE
- @sa comment for key_part_spec::clone
+ @sa comment for Key_part_spec::clone
*/
Alter_drop *clone(MEM_ROOT *mem_root) const
{ return new (mem_root) Alter_drop(*this); }
@@ -129,7 +129,7 @@ public:
:name(par_name), def(literal) {}
/**
Used to make a clone of this object for ALTER/CREATE TABLE
- @sa comment for key_part_spec::clone
+ @sa comment for Key_part_spec::clone
*/
Alter_column *clone(MEM_ROOT *mem_root) const
{ return new (mem_root) Alter_column(*this); }
@@ -141,13 +141,13 @@ public:
enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT, SPATIAL, FOREIGN_KEY};
enum Keytype type;
KEY_CREATE_INFO key_create_info;
- List<key_part_spec> columns;
+ List<Key_part_spec> columns;
const char *name;
bool generated;
Key(enum Keytype type_par, const char *name_arg,
KEY_CREATE_INFO *key_info_arg,
- bool generated_arg, List<key_part_spec> &cols)
+ bool generated_arg, List<Key_part_spec> &cols)
:type(type_par), key_create_info(*key_info_arg), columns(cols),
name(name_arg), generated(generated_arg)
{}
@@ -157,7 +157,7 @@ public:
friend bool foreign_key_prefix(Key *a, Key *b);
/**
Used to make a clone of this object for ALTER/CREATE TABLE
- @sa comment for key_part_spec::clone
+ @sa comment for Key_part_spec::clone
*/
virtual Key *clone(MEM_ROOT *mem_root) const
{ return new (mem_root) Key(*this, mem_root); }
@@ -165,7 +165,7 @@ public:
class Table_ident;
-class foreign_key: public Key {
+class Foreign_key: public Key {
public:
enum fk_match_opt { FK_MATCH_UNDEF, FK_MATCH_FULL,
FK_MATCH_PARTIAL, FK_MATCH_SIMPLE};
@@ -173,23 +173,23 @@ public:
FK_OPTION_SET_NULL, FK_OPTION_NO_ACTION, FK_OPTION_DEFAULT};
Table_ident *ref_table;
- List<key_part_spec> ref_columns;
+ List<Key_part_spec> ref_columns;
uint delete_opt, update_opt, match_opt;
- foreign_key(const char *name_arg, List<key_part_spec> &cols,
- Table_ident *table, List<key_part_spec> &ref_cols,
+ Foreign_key(const char *name_arg, List<Key_part_spec> &cols,
+ Table_ident *table, List<Key_part_spec> &ref_cols,
uint delete_opt_arg, uint update_opt_arg, uint match_opt_arg)
:Key(FOREIGN_KEY, name_arg, &default_key_create_info, 0, cols),
ref_table(table), ref_columns(cols),
delete_opt(delete_opt_arg), update_opt(update_opt_arg),
match_opt(match_opt_arg)
{}
- foreign_key(const foreign_key &rhs, MEM_ROOT *mem_root);
+ Foreign_key(const Foreign_key &rhs, MEM_ROOT *mem_root);
/**
Used to make a clone of this object for ALTER/CREATE TABLE
- @sa comment for key_part_spec::clone
+ @sa comment for Key_part_spec::clone
*/
virtual Key *clone(MEM_ROOT *mem_root) const
- { return new (mem_root) foreign_key(*this, mem_root); }
+ { return new (mem_root) Foreign_key(*this, mem_root); }
};
typedef struct st_mysql_lock
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 82938184245..43d84740f0b 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -538,6 +538,37 @@ bool load_db_opt_by_name(THD *thd, const char *db_name,
}
+/**
+ Return default database collation.
+
+ @param thd Thread context.
+ @param db_name Database name.
+
+ @return CHARSET_INFO object. The operation always return valid character
+ set, even if the database does not exist.
+*/
+
+CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name)
+{
+ HA_CREATE_INFO db_info;
+
+ if (thd->db != NULL && strcmp(db_name, thd->db) == 0)
+ return thd->db_charset;
+
+ load_db_opt_by_name(thd, db_name, &db_info);
+
+ /*
+ NOTE: even if load_db_opt_by_name() fails,
+ db_info.default_table_charset contains valid character set
+ (collation_server). We should not fail if load_db_opt_by_name() fails,
+ because it is valid case. If a database has been created just by
+ "mkdir", it does not contain db.opt file, but it is valid database.
+ */
+
+ return db_info.default_table_charset;
+}
+
+
/*
Create a database
@@ -751,10 +782,8 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
if ((error=write_db_opt(thd, path, create_info)))
goto exit;
- /*
- Change options if current database is being altered
- TODO: Delete this code
- */
+ /* Change options if current database is being altered. */
+
if (thd->db && !strcmp(thd->db,db))
{
thd->db_charset= create_info->default_table_charset ?
@@ -1358,6 +1387,7 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
Security_context *sctx= thd->security_ctx;
ulong db_access= sctx->db_access;
+ CHARSET_INFO *db_default_cl;
DBUG_ENTER("mysql_change_db");
DBUG_PRINT("enter",("name: '%s'", new_db_name->str));
@@ -1487,16 +1517,9 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
attributes and will be freed in THD::~THD().
*/
- {
- HA_CREATE_INFO db_options;
+ db_default_cl= get_default_db_collation(thd, new_db_file_name.str);
- load_db_opt_by_name(thd, new_db_name->str, &db_options);
-
- mysql_change_db_impl(thd, &new_db_file_name, db_access,
- db_options.default_table_charset ?
- db_options.default_table_charset :
- thd->variables.collation_server);
- }
+ mysql_change_db_impl(thd, &new_db_file_name, db_access, db_default_cl);
DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 0ce52779ce1..a498a88ce4b 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -3213,7 +3213,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
MYSQL_LOCK **lock,
TABLEOP_HOOKS *hooks)
{
- TABLE tmp_table; // Used during 'create_field()'
+ TABLE tmp_table; // Used during 'Create_field()'
TABLE_SHARE share;
TABLE *table= 0;
uint select_field_count= items->elements;
@@ -3257,7 +3257,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
while ((item=it++))
{
- create_field *cr_field;
+ Create_field *cr_field;
Field *field, *def_field;
if (item->type() == Item::FUNC_ITEM)
field= item->tmp_table_field(&tmp_table);
@@ -3266,7 +3266,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
(Item ***) 0, &tmp_field, &def_field, 0, 0, 0, 0,
0);
if (!field ||
- !(cr_field=new create_field(field,(item->type() == Item::FIELD_ITEM ?
+ !(cr_field=new Create_field(field,(item->type() == Item::FIELD_ITEM ?
((Item_field *)item)->field :
(Field*) 0))))
DBUG_RETURN(0);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 44768dd6d79..1b8d90d51b6 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -31,16 +31,6 @@
sys_var *trg_new_row_fake_var= (sys_var*) 0x01;
-/* Macros to look like lex */
-
-#define yyGet() ((uchar) *(lip->ptr++))
-#define yyGetLast() ((uchar) lip->ptr[-1])
-#define yyPeek() ((uchar) lip->ptr[0])
-#define yyPeek2() ((uchar) lip->ptr[1])
-#define yyUnget() lip->ptr--
-#define yySkip() lip->ptr++
-#define yyLength() ((uint) (lip->ptr - lip->tok_start)-1)
-
/* Longest standard keyword name */
#define TOCK_NAME_LENGTH 24
@@ -127,17 +117,24 @@ Lex_input_stream::Lex_input_stream(THD *thd,
yylineno(1),
yytoklen(0),
yylval(NULL),
- ptr(buffer),
- tok_start(NULL),
- tok_end(NULL),
- end_of_query(buffer + length),
- tok_start_prev(NULL),
- buf(buffer),
+ m_ptr(buffer),
+ m_tok_start(NULL),
+ m_tok_end(NULL),
+ m_end_of_query(buffer + length),
+ m_tok_start_prev(NULL),
+ m_buf(buffer),
+ m_echo(true),
+ m_cpp_tok_start(NULL),
+ m_cpp_tok_start_prev(NULL),
+ m_cpp_tok_end(NULL),
next_state(MY_LEX_START),
found_semicolon(NULL),
ignore_space(test(thd->variables.sql_mode & MODE_IGNORE_SPACE)),
- stmt_prepare_mode(FALSE)
+ stmt_prepare_mode(FALSE),
+ in_comment(NO_COMMENT)
{
+ m_cpp_buf= (char*) thd->alloc(length + 1);
+ m_cpp_ptr= m_cpp_buf;
}
Lex_input_stream::~Lex_input_stream()
@@ -192,7 +189,6 @@ void lex_start(THD *thd)
lex->parsing_options.reset();
lex->empty_field_list_on_rset= 0;
lex->select_lex.select_number= 1;
- lex->in_comment=0;
lex->length=0;
lex->part_info= 0;
lex->select_lex.in_sum_expr=0;
@@ -261,7 +257,7 @@ void lex_end(LEX *lex)
static int find_keyword(Lex_input_stream *lip, uint len, bool function)
{
- const char *tok= lip->tok_start;
+ const char *tok= lip->get_tok_start();
SYMBOL *symbol= get_hash_symbol(tok, len, function);
if (symbol)
@@ -312,9 +308,9 @@ bool is_lex_native_function(const LEX_STRING *name)
static LEX_STRING get_token(Lex_input_stream *lip, uint skip, uint length)
{
LEX_STRING tmp;
- yyUnget(); // ptr points now after last token char
+ lip->yyUnget(); // ptr points now after last token char
tmp.length=lip->yytoklen=length;
- tmp.str= lip->m_thd->strmake(lip->tok_start + skip, tmp.length);
+ tmp.str= lip->m_thd->strmake(lip->get_tok_start() + skip, tmp.length);
return tmp;
}
@@ -332,10 +328,10 @@ static LEX_STRING get_quoted_token(Lex_input_stream *lip,
LEX_STRING tmp;
const char *from, *end;
char *to;
- yyUnget(); // ptr points now after last token char
+ lip->yyUnget(); // ptr points now after last token char
tmp.length= lip->yytoklen=length;
tmp.str=(char*) lip->m_thd->alloc(tmp.length+1);
- from= lip->tok_start + skip;
+ from= lip->get_tok_start() + skip;
to= tmp.str;
end= to+length;
for ( ; to != end; )
@@ -353,23 +349,25 @@ static LEX_STRING get_quoted_token(Lex_input_stream *lip,
Fix sometimes to do only one scan of the string
*/
-static char *get_text(Lex_input_stream *lip)
+static char *get_text(Lex_input_stream *lip, int pre_skip, int post_skip)
{
reg1 uchar c,sep;
uint found_escape=0;
CHARSET_INFO *cs= lip->m_thd->charset();
- sep= yyGetLast(); // String should end with this
- while (lip->ptr != lip->end_of_query)
+ sep= lip->yyGetLast(); // String should end with this
+ while (! lip->eof())
{
- c = yyGet();
+ c= lip->yyGet();
#ifdef USE_MB
{
int l;
if (use_mb(cs) &&
- (l = my_ismbchar(cs, lip->ptr-1, lip->end_of_query))) {
- lip->ptr += l-1;
- continue;
+ (l = my_ismbchar(cs,
+ lip->get_ptr() -1,
+ lip->get_end_of_query()))) {
+ lip->skip_binary(l-1);
+ continue;
}
}
#endif
@@ -377,26 +375,31 @@ static char *get_text(Lex_input_stream *lip)
!(lip->m_thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES))
{ // Escaped character
found_escape=1;
- if (lip->ptr == lip->end_of_query)
+ if (lip->eof())
return 0;
- yySkip();
+ lip->yySkip();
}
else if (c == sep)
{
- if (c == yyGet()) // Check if two separators in a row
+ if (c == lip->yyGet()) // Check if two separators in a row
{
- found_escape=1; // dupplicate. Remember for delete
+ found_escape=1; // duplicate. Remember for delete
continue;
}
else
- yyUnget();
+ lip->yyUnget();
/* Found end. Unescape and return string */
const char *str, *end;
char *start;
- str=lip->tok_start+1;
- end=lip->ptr-1;
+ str= lip->get_tok_start();
+ end= lip->get_ptr();
+ /* Extract the text from the token */
+ str += pre_skip;
+ end -= post_skip;
+ DBUG_ASSERT(end >= str);
+
if (!(start= (char*) lip->m_thd->alloc((uint) (end-str)+1)))
return (char*) ""; // Sql_alloc has set error flag
if (!found_escape)
@@ -581,9 +584,7 @@ int MYSQLlex(void *arg, void *yythd)
lip->yylval=yylval; // The global state
- lip->tok_start_prev= lip->tok_start;
-
- lip->tok_start=lip->tok_end=lip->ptr;
+ lip->start_token();
state=lip->next_state;
lip->next_state=MY_LEX_OPERATOR_OR_IDENT;
LINT_INIT(c);
@@ -592,17 +593,22 @@ int MYSQLlex(void *arg, void *yythd)
switch (state) {
case MY_LEX_OPERATOR_OR_IDENT: // Next is operator or keyword
case MY_LEX_START: // Start of token
- // Skip startspace
- for (c=yyGet() ; (state_map[c] == MY_LEX_SKIP) ; c= yyGet())
+ // Skip starting whitespace
+ while(state_map[c= lip->yyPeek()] == MY_LEX_SKIP)
{
if (c == '\n')
lip->yylineno++;
+
+ lip->yySkip();
}
- lip->tok_start=lip->ptr-1; // Start of real token
+
+ /* Start of real token */
+ lip->restart_token();
+ c= lip->yyGet();
state= (enum my_lex_states) state_map[c];
break;
case MY_LEX_ESCAPE:
- if (yyGet() == 'N')
+ if (lip->yyGet() == 'N')
{ // Allow \N as shortcut for NULL
yylval->lex_str.str=(char*) "\\N";
yylval->lex_str.length=2;
@@ -610,40 +616,53 @@ int MYSQLlex(void *arg, void *yythd)
}
case MY_LEX_CHAR: // Unknown or single char token
case MY_LEX_SKIP: // This should not happen
- if (c == '-' && yyPeek() == '-' &&
- (my_isspace(cs,yyPeek2()) ||
- my_iscntrl(cs,yyPeek2())))
+ if (c == '-' && lip->yyPeek() == '-' &&
+ (my_isspace(cs,lip->yyPeekn(1)) ||
+ my_iscntrl(cs,lip->yyPeekn(1))))
{
state=MY_LEX_COMMENT;
break;
}
- yylval->lex_str.str=(char*) (lip->ptr=lip->tok_start);// Set to first chr
- yylval->lex_str.length=1;
- c=yyGet();
+
if (c != ')')
lip->next_state= MY_LEX_START; // Allow signed numbers
+
if (c == ',')
- lip->tok_start=lip->ptr; // Let tok_start point at next item
- /*
- Check for a placeholder: it should not precede a possible identifier
- because of binlogging: when a placeholder is replaced with
- its value in a query for the binlog, the query must stay
- grammatically correct.
- */
- else if (c == '?' && lip->stmt_prepare_mode && !ident_map[yyPeek()])
+ {
+ /*
+ Warning:
+ This is a work around, to make the "remember_name" rule in
+ sql/sql_yacc.yy work properly.
+ The problem is that, when parsing "select expr1, expr2",
+ the code generated by bison executes the *pre* action
+ remember_name (see select_item) *before* actually parsing the
+ first token of expr2.
+ */
+ lip->restart_token();
+ }
+ else
+ {
+ /*
+ Check for a placeholder: it should not precede a possible identifier
+ because of binlogging: when a placeholder is replaced with
+ its value in a query for the binlog, the query must stay
+ grammatically correct.
+ */
+ if (c == '?' && lip->stmt_prepare_mode && !ident_map[lip->yyPeek()])
return(PARAM_MARKER);
+ }
+
return((int) c);
case MY_LEX_IDENT_OR_NCHAR:
- if (yyPeek() != '\'')
- {
+ if (lip->yyPeek() != '\'')
+ {
state= MY_LEX_IDENT;
break;
}
/* Found N'string' */
- lip->tok_start++; // Skip N
- yySkip(); // Skip '
- if (!(yylval->lex_str.str = get_text(lip)))
+ lip->yySkip(); // Skip '
+ if (!(yylval->lex_str.str = get_text(lip, 2, 1)))
{
state= MY_LEX_CHAR; // Read char by char
break;
@@ -652,13 +671,13 @@ int MYSQLlex(void *arg, void *yythd)
return(NCHAR_STRING);
case MY_LEX_IDENT_OR_HEX:
- if (yyPeek() == '\'')
+ if (lip->yyPeek() == '\'')
{ // Found x'hex-number'
state= MY_LEX_HEX_NUMBER;
break;
}
case MY_LEX_IDENT_OR_BIN:
- if (yyPeek() == '\'')
+ if (lip->yyPeek() == '\'')
{ // Found b'bin-number'
state= MY_LEX_BIN_NUMBER;
break;
@@ -669,54 +688,58 @@ int MYSQLlex(void *arg, void *yythd)
if (use_mb(cs))
{
result_state= IDENT_QUOTED;
- if (my_mbcharlen(cs, yyGetLast()) > 1)
+ if (my_mbcharlen(cs, lip->yyGetLast()) > 1)
{
- int l = my_ismbchar(cs, lip->ptr-1, lip->end_of_query);
+ int l = my_ismbchar(cs,
+ lip->get_ptr() -1,
+ lip->get_end_of_query());
if (l == 0) {
state = MY_LEX_CHAR;
continue;
}
- lip->ptr += l - 1;
+ lip->skip_binary(l - 1);
}
- while (ident_map[c=yyGet()])
+ while (ident_map[c=lip->yyGet()])
{
if (my_mbcharlen(cs, c) > 1)
{
int l;
- if ((l = my_ismbchar(cs, lip->ptr-1, lip->end_of_query)) == 0)
+ if ((l = my_ismbchar(cs,
+ lip->get_ptr() -1,
+ lip->get_end_of_query())) == 0)
break;
- lip->ptr += l-1;
+ lip->skip_binary(l-1);
}
}
}
else
#endif
{
- for (result_state= c; ident_map[c= yyGet()]; result_state|= c);
+ for (result_state= c; ident_map[c= lip->yyGet()]; result_state|= c);
/* If there were non-ASCII characters, mark that we must convert */
result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
}
- length= (uint) (lip->ptr - lip->tok_start)-1;
- start= lip->ptr;
+ length= lip->yyLength();
+ start= lip->get_ptr();
if (lip->ignore_space)
{
/*
If we find a space then this can't be an identifier. We notice this
below by checking start != lex->ptr.
*/
- for (; state_map[c] == MY_LEX_SKIP ; c= yyGet());
+ for (; state_map[c] == MY_LEX_SKIP ; c= lip->yyGet());
}
- if (start == lip->ptr && c == '.' && ident_map[yyPeek()])
+ if (start == lip->get_ptr() && c == '.' && ident_map[lip->yyPeek()])
lip->next_state=MY_LEX_IDENT_SEP;
else
{ // '(' must follow directly if function
- yyUnget();
- if ((tokval = find_keyword(lip, length,c == '(')))
+ lip->yyUnget();
+ if ((tokval = find_keyword(lip, length, c == '(')))
{
lip->next_state= MY_LEX_START; // Allow signed numbers
return(tokval); // Was keyword
}
- yySkip(); // next state does a unget
+ lip->yySkip(); // next state does a unget
}
yylval->lex_str=get_token(lip, 0, length);
@@ -735,16 +758,48 @@ int MYSQLlex(void *arg, void *yythd)
return(result_state); // IDENT or IDENT_QUOTED
case MY_LEX_IDENT_SEP: // Found ident and now '.'
- yylval->lex_str.str=(char*) lip->ptr;
- yylval->lex_str.length=1;
- c=yyGet(); // should be '.'
+ yylval->lex_str.str= (char*) lip->get_ptr();
+ yylval->lex_str.length= 1;
+ c= lip->yyGet(); // should be '.'
lip->next_state= MY_LEX_IDENT_START;// Next is an ident (not a keyword)
- if (!ident_map[yyPeek()]) // Probably ` or "
+ if (!ident_map[lip->yyPeek()]) // Probably ` or "
lip->next_state= MY_LEX_START;
return((int) c);
case MY_LEX_NUMBER_IDENT: // number or ident which num-start
- while (my_isdigit(cs,(c = yyGet()))) ;
+ if (lip->yyGetLast() == '0')
+ {
+ c= lip->yyGet();
+ if (c == 'x')
+ {
+ while (my_isxdigit(cs,(c = lip->yyGet()))) ;
+ if ((lip->yyLength() >= 3) && !ident_map[c])
+ {
+ /* skip '0x' */
+ yylval->lex_str=get_token(lip, 2, lip->yyLength()-2);
+ return (HEX_NUM);
+ }
+ lip->yyUnget();
+ state= MY_LEX_IDENT_START;
+ break;
+ }
+ else if (c == 'b')
+ {
+ while ((c= lip->yyGet()) == '0' || c == '1');
+ if ((lip->yyLength() >= 3) && !ident_map[c])
+ {
+ /* Skip '0b' */
+ yylval->lex_str= get_token(lip, 2, lip->yyLength()-2);
+ return (BIN_NUM);
+ }
+ lip->yyUnget();
+ state= MY_LEX_IDENT_START;
+ break;
+ }
+ lip->yyUnget();
+ }
+
+ while (my_isdigit(cs, (c = lip->yyGet()))) ;
if (!ident_map[c])
{ // Can't be identifier
state=MY_LEX_INT_OR_REAL;
@@ -753,42 +808,18 @@ int MYSQLlex(void *arg, void *yythd)
if (c == 'e' || c == 'E')
{
// The following test is written this way to allow numbers of type 1e1
- if (my_isdigit(cs,yyPeek()) ||
- (c=(yyGet())) == '+' || c == '-')
+ if (my_isdigit(cs,lip->yyPeek()) ||
+ (c=(lip->yyGet())) == '+' || c == '-')
{ // Allow 1E+10
- if (my_isdigit(cs,yyPeek())) // Number must have digit after sign
+ if (my_isdigit(cs,lip->yyPeek())) // Number must have digit after sign
{
- yySkip();
- while (my_isdigit(cs,yyGet())) ;
- yylval->lex_str=get_token(lip, 0, yyLength());
+ lip->yySkip();
+ while (my_isdigit(cs,lip->yyGet())) ;
+ yylval->lex_str=get_token(lip, 0, lip->yyLength());
return(FLOAT_NUM);
}
}
- yyUnget(); /* purecov: inspected */
- }
- else if (c == 'x' && (lip->ptr - lip->tok_start) == 2 &&
- lip->tok_start[0] == '0' )
- { // Varbinary
- while (my_isxdigit(cs,(c = yyGet()))) ;
- if ((lip->ptr - lip->tok_start) >= 4 && !ident_map[c])
- {
- /* skip '0x' */
- yylval->lex_str=get_token(lip, 2, yyLength()-2);
- return (HEX_NUM);
- }
- yyUnget();
- }
- else if (c == 'b' && (lip->ptr - lip->tok_start) == 2 &&
- lip->tok_start[0] == '0' )
- { // b'bin-number'
- while (my_isxdigit(cs,(c = yyGet()))) ;
- if ((lip->ptr - lip->tok_start) >= 4 && !ident_map[c])
- {
- /* Skip '0b' */
- yylval->lex_str= get_token(lip, 2, yyLength()-2);
- return (BIN_NUM);
- }
- yyUnget();
+ lip->yyUnget();
}
// fall through
case MY_LEX_IDENT_START: // We come here after '.'
@@ -797,44 +828,46 @@ int MYSQLlex(void *arg, void *yythd)
if (use_mb(cs))
{
result_state= IDENT_QUOTED;
- while (ident_map[c=yyGet()])
+ while (ident_map[c=lip->yyGet()])
{
if (my_mbcharlen(cs, c) > 1)
{
int l;
- if ((l = my_ismbchar(cs, lip->ptr-1, lip->end_of_query)) == 0)
+ if ((l = my_ismbchar(cs,
+ lip->get_ptr() -1,
+ lip->get_end_of_query())) == 0)
break;
- lip->ptr += l-1;
+ lip->skip_binary(l-1);
}
}
}
else
#endif
{
- for (result_state=0; ident_map[c= yyGet()]; result_state|= c);
+ for (result_state=0; ident_map[c= lip->yyGet()]; result_state|= c);
/* If there were non-ASCII characters, mark that we must convert */
result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
}
- if (c == '.' && ident_map[yyPeek()])
+ if (c == '.' && ident_map[lip->yyPeek()])
lip->next_state=MY_LEX_IDENT_SEP;// Next is '.'
- yylval->lex_str= get_token(lip, 0, yyLength());
+ yylval->lex_str= get_token(lip, 0, lip->yyLength());
return(result_state);
case MY_LEX_USER_VARIABLE_DELIMITER: // Found quote char
{
uint double_quotes= 0;
char quote_char= c; // Used char
- while ((c=yyGet()))
+ while ((c=lip->yyGet()))
{
int var_length;
if ((var_length= my_mbcharlen(cs, c)) == 1)
{
if (c == quote_char)
{
- if (yyPeek() != quote_char)
+ if (lip->yyPeek() != quote_char)
break;
- c=yyGet();
+ c=lip->yyGet();
double_quotes++;
continue;
}
@@ -842,78 +875,78 @@ int MYSQLlex(void *arg, void *yythd)
#ifdef USE_MB
else if (var_length < 1)
break; // Error
- lip->ptr+= var_length-1;
+ lip->skip_binary(var_length-1);
#endif
}
if (double_quotes)
yylval->lex_str=get_quoted_token(lip, 1,
- yyLength() - double_quotes -1,
+ lip->yyLength() - double_quotes -1,
quote_char);
else
- yylval->lex_str=get_token(lip, 1, yyLength() -1);
+ yylval->lex_str=get_token(lip, 1, lip->yyLength() -1);
if (c == quote_char)
- yySkip(); // Skip end `
+ lip->yySkip(); // Skip end `
lip->next_state= MY_LEX_START;
return(IDENT_QUOTED);
}
case MY_LEX_INT_OR_REAL: // Complete int or incomplete real
if (c != '.')
{ // Found complete integer number.
- yylval->lex_str=get_token(lip, 0, yyLength());
+ yylval->lex_str=get_token(lip, 0, lip->yyLength());
return int_token(yylval->lex_str.str,yylval->lex_str.length);
}
// fall through
case MY_LEX_REAL: // Incomplete real number
- while (my_isdigit(cs,c = yyGet())) ;
+ while (my_isdigit(cs,c = lip->yyGet())) ;
if (c == 'e' || c == 'E')
{
- c = yyGet();
+ c = lip->yyGet();
if (c == '-' || c == '+')
- c = yyGet(); // Skip sign
+ c = lip->yyGet(); // Skip sign
if (!my_isdigit(cs,c))
{ // No digit after sign
state= MY_LEX_CHAR;
break;
}
- while (my_isdigit(cs,yyGet())) ;
- yylval->lex_str=get_token(lip, 0, yyLength());
+ while (my_isdigit(cs,lip->yyGet())) ;
+ yylval->lex_str=get_token(lip, 0, lip->yyLength());
return(FLOAT_NUM);
}
- yylval->lex_str=get_token(lip, 0, yyLength());
+ yylval->lex_str=get_token(lip, 0, lip->yyLength());
return(DECIMAL_NUM);
case MY_LEX_HEX_NUMBER: // Found x'hexstring'
- yyGet(); // Skip '
- while (my_isxdigit(cs,(c = yyGet()))) ;
- length=(lip->ptr - lip->tok_start); // Length of hexnum+3
- if (!(length & 1) || c != '\'')
- {
- return(ABORT_SYM); // Illegal hex constant
- }
- yyGet(); // get_token makes an unget
+ lip->yySkip(); // Accept opening '
+ while (my_isxdigit(cs, (c= lip->yyGet()))) ;
+ if (c != '\'')
+ return(ABORT_SYM); // Illegal hex constant
+ lip->yySkip(); // Accept closing '
+ length= lip->yyLength(); // Length of hexnum+3
+ if ((length % 2) == 0)
+ return(ABORT_SYM); // odd number of hex digits
yylval->lex_str=get_token(lip,
2, // skip x'
length-3); // don't count x' and last '
return (HEX_NUM);
case MY_LEX_BIN_NUMBER: // Found b'bin-string'
- yyGet(); // Skip '
- while ((c= yyGet()) == '0' || c == '1');
- length= (lip->ptr - lip->tok_start); // Length of bin-num + 3
+ lip->yySkip(); // Accept opening '
+ while ((c= lip->yyGet()) == '0' || c == '1');
if (c != '\'')
- return(ABORT_SYM); // Illegal hex constant
- yyGet(); // get_token makes an unget
+ return(ABORT_SYM); // Illegal hex constant
+ lip->yySkip(); // Accept closing '
+ length= lip->yyLength(); // Length of bin-num + 3
yylval->lex_str= get_token(lip,
2, // skip b'
length-3); // don't count b' and last '
return (BIN_NUM);
case MY_LEX_CMP_OP: // Incomplete comparison operator
- if (state_map[yyPeek()] == MY_LEX_CMP_OP ||
- state_map[yyPeek()] == MY_LEX_LONG_CMP_OP)
- yySkip();
- if ((tokval = find_keyword(lip, (uint) (lip->ptr - lip->tok_start),0)))
+ if (state_map[lip->yyPeek()] == MY_LEX_CMP_OP ||
+ state_map[lip->yyPeek()] == MY_LEX_LONG_CMP_OP)
+ lip->yySkip();
+ if ((tokval = find_keyword(lip, lip->yyLength() + 1, 0)))
{
lip->next_state= MY_LEX_START; // Allow signed numbers
return(tokval);
@@ -922,14 +955,14 @@ int MYSQLlex(void *arg, void *yythd)
break;
case MY_LEX_LONG_CMP_OP: // Incomplete comparison operator
- if (state_map[yyPeek()] == MY_LEX_CMP_OP ||
- state_map[yyPeek()] == MY_LEX_LONG_CMP_OP)
+ if (state_map[lip->yyPeek()] == MY_LEX_CMP_OP ||
+ state_map[lip->yyPeek()] == MY_LEX_LONG_CMP_OP)
{
- yySkip();
- if (state_map[yyPeek()] == MY_LEX_CMP_OP)
- yySkip();
+ lip->yySkip();
+ if (state_map[lip->yyPeek()] == MY_LEX_CMP_OP)
+ lip->yySkip();
}
- if ((tokval = find_keyword(lip, (uint) (lip->ptr - lip->tok_start),0)))
+ if ((tokval = find_keyword(lip, lip->yyLength() + 1, 0)))
{
lip->next_state= MY_LEX_START; // Found long op
return(tokval);
@@ -938,12 +971,12 @@ int MYSQLlex(void *arg, void *yythd)
break;
case MY_LEX_BOOL:
- if (c != yyPeek())
+ if (c != lip->yyPeek())
{
state=MY_LEX_CHAR;
break;
}
- yySkip();
+ lip->yySkip();
tokval = find_keyword(lip,2,0); // Is a bool operator
lip->next_state= MY_LEX_START; // Allow signed numbers
return(tokval);
@@ -956,7 +989,7 @@ int MYSQLlex(void *arg, void *yythd)
}
/* " used for strings */
case MY_LEX_STRING: // Incomplete text string
- if (!(yylval->lex_str.str = get_text(lip)))
+ if (!(yylval->lex_str.str = get_text(lip, 1, 1)))
{
state= MY_LEX_CHAR; // Read char by char
break;
@@ -966,82 +999,138 @@ int MYSQLlex(void *arg, void *yythd)
case MY_LEX_COMMENT: // Comment
lex->select_lex.options|= OPTION_FOUND_COMMENT;
- while ((c = yyGet()) != '\n' && c) ;
- yyUnget(); // Safety against eof
+ while ((c = lip->yyGet()) != '\n' && c) ;
+ lip->yyUnget(); // Safety against eof
state = MY_LEX_START; // Try again
break;
case MY_LEX_LONG_COMMENT: /* Long C comment? */
- if (yyPeek() != '*')
+ if (lip->yyPeek() != '*')
{
state=MY_LEX_CHAR; // Probable division
break;
}
- yySkip(); // Skip '*'
lex->select_lex.options|= OPTION_FOUND_COMMENT;
- if (yyPeek() == '!') // MySQL command in comment
+ /* Reject '/' '*', since we might need to turn off the echo */
+ lip->yyUnget();
+
+ if (lip->yyPeekn(2) == '!')
{
- ulong version=MYSQL_VERSION_ID;
- yySkip();
- state=MY_LEX_START;
- if (my_isdigit(cs,yyPeek()))
- { // Version number
- version=strtol((char*) lip->ptr,(char**) &lip->ptr,10);
- }
- if (version <= MYSQL_VERSION_ID)
- {
- lex->in_comment=1;
- break;
- }
+ lip->in_comment= DISCARD_COMMENT;
+ /* Accept '/' '*' '!', but do not keep this marker. */
+ lip->set_echo(false);
+ lip->yySkip();
+ lip->yySkip();
+ lip->yySkip();
+
+ /*
+ The special comment format is very strict:
+ '/' '*' '!', followed by exactly
+ 2 digits (major), then 3 digits (minor).
+ */
+ char version_str[6];
+ version_str[0]= lip->yyPeekn(0);
+ version_str[1]= lip->yyPeekn(1);
+ version_str[2]= lip->yyPeekn(2);
+ version_str[3]= lip->yyPeekn(3);
+ version_str[4]= lip->yyPeekn(4);
+ version_str[5]= 0;
+ if ( my_isdigit(cs, version_str[0])
+ && my_isdigit(cs, version_str[1])
+ && my_isdigit(cs, version_str[2])
+ && my_isdigit(cs, version_str[3])
+ && my_isdigit(cs, version_str[4])
+ )
+ {
+ ulong version;
+ version=strtol(version_str, NULL, 10);
+
+ /* Accept 'M' 'M' 'm' 'm' 'm' */
+ lip->yySkipn(5);
+
+ if (version <= MYSQL_VERSION_ID)
+ {
+ /* Expand the content of the special comment as real code */
+ lip->set_echo(true);
+ state=MY_LEX_START;
+ break;
+ }
+ }
+ else
+ {
+ state=MY_LEX_START;
+ lip->set_echo(true);
+ break;
+ }
}
- while (lip->ptr != lip->end_of_query &&
- ((c=yyGet()) != '*' || yyPeek() != '/'))
+ else
{
- if (c == '\n')
- lip->yylineno++;
+ lip->in_comment= PRESERVE_COMMENT;
+ lip->yySkip(); // Accept /
+ lip->yySkip(); // Accept *
}
- if (lip->ptr != lip->end_of_query)
- yySkip(); // remove last '/'
- state = MY_LEX_START; // Try again
+
+ while (! lip->eof() &&
+ ((c=lip->yyGet()) != '*' || lip->yyPeek() != '/'))
+ {
+ if (c == '\n')
+ lip->yylineno++;
+ }
+ if (! lip->eof())
+ lip->yySkip(); // remove last '/'
+ state = MY_LEX_START; // Try again
+ lip->set_echo(true);
break;
case MY_LEX_END_LONG_COMMENT:
- if (lex->in_comment && yyPeek() == '/')
+ if ((lip->in_comment != NO_COMMENT) && lip->yyPeek() == '/')
{
- yySkip();
- lex->in_comment=0;
- state=MY_LEX_START;
+ /* Reject '*' '/' */
+ lip->yyUnget();
+ /* Accept '*' '/', with the proper echo */
+ lip->set_echo(lip->in_comment == PRESERVE_COMMENT);
+ lip->yySkipn(2);
+ /* And start recording the tokens again */
+ lip->set_echo(true);
+ lip->in_comment=NO_COMMENT;
+ state=MY_LEX_START;
}
else
state=MY_LEX_CHAR; // Return '*'
break;
case MY_LEX_SET_VAR: // Check if ':='
- if (yyPeek() != '=')
+ if (lip->yyPeek() != '=')
{
state=MY_LEX_CHAR; // Return ':'
break;
}
- yySkip();
+ lip->yySkip();
return (SET_VAR);
case MY_LEX_SEMICOLON: // optional line terminator
- if (yyPeek())
+ if (lip->yyPeek())
{
if ((thd->client_capabilities & CLIENT_MULTI_STATEMENTS) &&
!lip->stmt_prepare_mode)
{
lex->safe_to_cache_query= 0;
- lip->found_semicolon= lip->ptr;
+ lip->found_semicolon= lip->get_ptr();
thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
lip->next_state= MY_LEX_END;
+ lip->set_echo(true);
return (END_OF_INPUT);
}
state= MY_LEX_CHAR; // Return ';'
break;
}
- /* fall true */
+ lip->next_state=MY_LEX_END; // Mark for next loop
+ return(END_OF_INPUT);
case MY_LEX_EOL:
- if (lip->ptr >= lip->end_of_query)
+ if (lip->eof())
{
- lip->next_state=MY_LEX_END; // Mark for next loop
- return(END_OF_INPUT);
+ lip->yyUnget(); // Reject the last '\0'
+ lip->set_echo(false);
+ lip->yySkip();
+ lip->set_echo(true);
+ lip->next_state=MY_LEX_END; // Mark for next loop
+ return(END_OF_INPUT);
}
state=MY_LEX_CHAR;
break;
@@ -1051,16 +1140,16 @@ int MYSQLlex(void *arg, void *yythd)
/* Actually real shouldn't start with . but allow them anyhow */
case MY_LEX_REAL_OR_POINT:
- if (my_isdigit(cs,yyPeek()))
+ if (my_isdigit(cs,lip->yyPeek()))
state = MY_LEX_REAL; // Real
else
{
state= MY_LEX_IDENT_SEP; // return '.'
- yyUnget(); // Put back '.'
+ lip->yyUnget(); // Put back '.'
}
break;
case MY_LEX_USER_END: // end '@' of user@hostname
- switch (state_map[yyPeek()]) {
+ switch (state_map[lip->yyPeek()]) {
case MY_LEX_STRING:
case MY_LEX_USER_VARIABLE_DELIMITER:
case MY_LEX_STRING_OR_DELIMITER:
@@ -1072,20 +1161,20 @@ int MYSQLlex(void *arg, void *yythd)
lip->next_state=MY_LEX_HOSTNAME;
break;
}
- yylval->lex_str.str=(char*) lip->ptr;
+ yylval->lex_str.str=(char*) lip->get_ptr();
yylval->lex_str.length=1;
return((int) '@');
case MY_LEX_HOSTNAME: // end '@' of user@hostname
- for (c=yyGet() ;
+ for (c=lip->yyGet() ;
my_isalnum(cs,c) || c == '.' || c == '_' || c == '$';
- c= yyGet()) ;
- yylval->lex_str=get_token(lip, 0, yyLength());
+ c= lip->yyGet()) ;
+ yylval->lex_str=get_token(lip, 0, lip->yyLength());
return(LEX_HOSTNAME);
case MY_LEX_SYSTEM_VAR:
- yylval->lex_str.str=(char*) lip->ptr;
+ yylval->lex_str.str=(char*) lip->get_ptr();
yylval->lex_str.length=1;
- yySkip(); // Skip '@'
- lip->next_state= (state_map[yyPeek()] ==
+ lip->yySkip(); // Skip '@'
+ lip->next_state= (state_map[lip->yyPeek()] ==
MY_LEX_USER_VARIABLE_DELIMITER ?
MY_LEX_OPERATOR_OR_IDENT :
MY_LEX_IDENT_OR_KEYWORD);
@@ -1096,19 +1185,19 @@ int MYSQLlex(void *arg, void *yythd)
We should now be able to handle:
[(global | local | session) .]variable_name
*/
-
- for (result_state= 0; ident_map[c= yyGet()]; result_state|= c);
+
+ for (result_state= 0; ident_map[c= lip->yyGet()]; result_state|= c);
/* If there were non-ASCII characters, mark that we must convert */
result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
-
+
if (c == '.')
lip->next_state=MY_LEX_IDENT_SEP;
- length= (uint) (lip->ptr - lip->tok_start)-1;
- if (length == 0)
+ length= lip->yyLength();
+ if (length == 0)
return(ABORT_SYM); // Names must be nonempty.
if ((tokval= find_keyword(lip, length,0)))
{
- yyUnget(); // Put back 'c'
+ lip->yyUnget(); // Put back 'c'
return(tokval); // Was keyword
}
yylval->lex_str=get_token(lip, 0, length);
@@ -1135,7 +1224,7 @@ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
/*
Make deep copies of used objects.
This is not a fully deep copy - clone() implementations
- of Alter_drop, Alter_column, Key, foreign_key, key_part_spec
+ of Alter_drop, Alter_column, Key, foreign_key, Key_part_spec
do not copy string constants. At the same length the only
reason we make a copy currently is that ALTER/CREATE TABLE
code changes input Alter_info definitions, but string
@@ -1149,32 +1238,31 @@ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
}
-/*
- Skip comment in the end of statement.
-
- SYNOPSIS
- skip_rear_comments()
- cs character set
- begin pointer to the beginning of statement
- end pointer to the end of statement
-
- DESCRIPTION
- The function is intended to trim comments at the end of the statement.
+void trim_whitespace(CHARSET_INFO *cs, LEX_STRING *str)
+{
+ /*
+ TODO:
+ This code assumes that there are no multi-bytes characters
+ that can be considered white-space.
+ */
- RETURN
- Pointer to the last non-comment symbol of the statement.
-*/
+ while ((str->length > 0) && (my_isspace(cs, str->str[0])))
+ {
+ str->length --;
+ str->str ++;
+ }
-const char *skip_rear_comments(CHARSET_INFO *cs, const char *begin,
- const char *end)
-{
- while (begin < end && (end[-1] == '*' ||
- end[-1] == '/' || end[-1] == ';' ||
- my_isspace(cs, end[-1])))
- end-= 1;
- return end;
+ /*
+ FIXME:
+ Also, parsing backward is not safe with multi bytes characters
+ */
+ while ((str->length > 0) && (my_isspace(cs, str->str[str->length-1])))
+ {
+ str->length --;
+ }
}
+
/*
st_select_lex structures initialisations
*/
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index f798fb535b3..7057bf4b5ef 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -850,14 +850,14 @@ public:
List<Alter_drop> drop_list;
List<Alter_column> alter_list;
List<Key> key_list;
- List<create_field> create_list;
+ List<Create_field> create_list;
uint flags;
enum enum_enable_or_disable keys_onoff;
enum tablespace_op_type tablespace_op;
List<char> partition_names;
uint no_parts;
enum_alter_table_change_level change_level;
- create_field *datetime_field;
+ Create_field *datetime_field;
bool error_if_not_empty;
@@ -1049,8 +1049,40 @@ struct st_parsing_options
/**
+ The state of the lexical parser, when parsing comments.
+*/
+enum enum_comment_state
+{
+ /**
+ Not parsing comments.
+ */
+ NO_COMMENT,
+ /**
+ Parsing comments that need to be preserved.
+ Typically, these are user comments '/' '*' ... '*' '/'.
+ */
+ PRESERVE_COMMENT,
+ /**
+ Parsing comments that need to be discarded.
+ Typically, these are special comments '/' '*' '!' ... '*' '/',
+ or '/' '*' '!' 'M' 'M' 'm' 'm' 'm' ... '*' '/', where the comment
+ markers should not be expanded.
+ */
+ DISCARD_COMMENT
+};
+
+
+/**
This class represents the character input stream consumed during
lexical analysis.
+ In addition to consuming the input stream, this class performs some
+ comment pre processing, by filtering out out of bound special text
+ from the query input stream.
+ Two buffers, with pointers inside each buffers, are maintained in
+ parallel. The 'raw' buffer is the original query text, which may
+ contain out-of-bound comments. The 'cpp' (for comments pre processor)
+ is the pre-processed buffer that contains only the query text that
+ should be seen once out-of-bound data is removed.
*/
class Lex_input_stream
{
@@ -1058,6 +1090,218 @@ public:
Lex_input_stream(THD *thd, const char* buff, unsigned int length);
~Lex_input_stream();
+ /**
+ Set the echo mode.
+ When echo is true, characters parsed from the raw input stream are
+ preserved. When false, characters parsed are silently ignored.
+ @param echo the echo mode.
+ */
+ void set_echo(bool echo)
+ {
+ m_echo= echo;
+ }
+
+ /**
+ Skip binary from the input stream.
+ @param n number of bytes to accept.
+ */
+ void skip_binary(int n)
+ {
+ if (m_echo)
+ {
+ memcpy(m_cpp_ptr, m_ptr, n);
+ m_cpp_ptr += n;
+ }
+ m_ptr += n;
+ }
+
+ /**
+ Get a character, and advance in the stream.
+ @return the next character to parse.
+ */
+ char yyGet()
+ {
+ char c= *m_ptr++;
+ if (m_echo)
+ *m_cpp_ptr++ = c;
+ return c;
+ }
+
+ /**
+ Get the last character accepted.
+ @return the last character accepted.
+ */
+ char yyGetLast()
+ {
+ return m_ptr[-1];
+ }
+
+ /**
+ Look at the next character to parse, but do not accept it.
+ */
+ char yyPeek()
+ {
+ return m_ptr[0];
+ }
+
+ /**
+ Look ahead at some character to parse.
+ @param n offset of the character to look up
+ */
+ char yyPeekn(int n)
+ {
+ return m_ptr[n];
+ }
+
+ /**
+ Cancel the effect of the last yyGet() or yySkip().
+ Note that the echo mode should not change between calls to yyGet / yySkip
+ and yyUnget. The caller is responsible for ensuring that.
+ */
+ void yyUnget()
+ {
+ m_ptr--;
+ if (m_echo)
+ m_cpp_ptr--;
+ }
+
+ /**
+ Accept a character, by advancing the input stream.
+ */
+ void yySkip()
+ {
+ if (m_echo)
+ *m_cpp_ptr++ = *m_ptr++;
+ else
+ m_ptr++;
+ }
+
+ /**
+ Accept multiple characters at once.
+ @param n the number of characters to accept.
+ */
+ void yySkipn(int n)
+ {
+ if (m_echo)
+ {
+ memcpy(m_cpp_ptr, m_ptr, n);
+ m_cpp_ptr += n;
+ }
+ m_ptr += n;
+ }
+
+ /**
+ End of file indicator for the query text to parse.
+ @return true if there are no more characters to parse
+ */
+ bool eof()
+ {
+ return (m_ptr >= m_end_of_query);
+ }
+
+ /**
+ End of file indicator for the query text to parse.
+ @param n number of characters expected
+ @return true if there are less than n characters to parse
+ */
+ bool eof(int n)
+ {
+ return ((m_ptr + n) >= m_end_of_query);
+ }
+
+ /** Get the raw query buffer. */
+ const char* get_buf()
+ {
+ return m_buf;
+ }
+
+ /** Get the pre-processed query buffer. */
+ const char* get_cpp_buf()
+ {
+ return m_cpp_buf;
+ }
+
+ /** Get the end of the raw query buffer. */
+ const char* get_end_of_query()
+ {
+ return m_end_of_query;
+ }
+
+ /** Mark the stream position as the start of a new token. */
+ void start_token()
+ {
+ m_tok_start_prev= m_tok_start;
+ m_tok_start= m_ptr;
+ m_tok_end= m_ptr;
+
+ m_cpp_tok_start_prev= m_cpp_tok_start;
+ m_cpp_tok_start= m_cpp_ptr;
+ m_cpp_tok_end= m_cpp_ptr;
+ }
+
+ /**
+ Adjust the starting position of the current token.
+ This is used to compensate for starting whitespace.
+ */
+ void restart_token()
+ {
+ m_tok_start= m_ptr;
+ m_cpp_tok_start= m_cpp_ptr;
+ }
+
+ /** Get the token start position, in the raw buffer. */
+ const char* get_tok_start()
+ {
+ return m_tok_start;
+ }
+
+ /** Get the token start position, in the pre-processed buffer. */
+ const char* get_cpp_tok_start()
+ {
+ return m_cpp_tok_start;
+ }
+
+ /** Get the token end position, in the raw buffer. */
+ const char* get_tok_end()
+ {
+ return m_tok_end;
+ }
+
+ /** Get the token end position, in the pre-processed buffer. */
+ const char* get_cpp_tok_end()
+ {
+ return m_cpp_tok_end;
+ }
+
+ /** Get the previous token start position, in the raw buffer. */
+ const char* get_tok_start_prev()
+ {
+ return m_tok_start_prev;
+ }
+
+ /** Get the current stream pointer, in the raw buffer. */
+ const char* get_ptr()
+ {
+ return m_ptr;
+ }
+
+ /** Get the current stream pointer, in the pre-processed buffer. */
+ const char* get_cpp_ptr()
+ {
+ return m_cpp_ptr;
+ }
+
+ /** Get the length of the current token, in the raw buffer. */
+ uint yyLength()
+ {
+ /*
+ The assumption is that the lexical analyser is always 1 character ahead,
+ which the -1 account for.
+ */
+ DBUG_ASSERT(m_ptr > m_tok_start);
+ return (uint) ((m_ptr - m_tok_start) - 1);
+ }
+
/** Current thread. */
THD *m_thd;
@@ -1070,37 +1314,74 @@ public:
/** Interface with bison, value of the last token parsed. */
LEX_YYSTYPE yylval;
- /** Pointer to the current position in the input stream. */
- const char* ptr;
+private:
+ /** Pointer to the current position in the raw input stream. */
+ const char* m_ptr;
+
+ /** Starting position of the last token parsed, in the raw buffer. */
+ const char* m_tok_start;
- /** Starting position of the last token parsed. */
- const char* tok_start;
+ /** Ending position of the previous token parsed, in the raw buffer. */
+ const char* m_tok_end;
- /** Ending position of the last token parsed. */
- const char* tok_end;
+ /** End of the query text in the input stream, in the raw buffer. */
+ const char* m_end_of_query;
- /** End of the query text in the input stream. */
- const char* end_of_query;
+ /** Starting position of the previous token parsed, in the raw buffer. */
+ const char* m_tok_start_prev;
- /** Starting position of the previous token parsed. */
- const char* tok_start_prev;
+ /** Begining of the query text in the input stream, in the raw buffer. */
+ const char* m_buf;
- /** Begining of the query text in the input stream. */
- const char* buf;
+ /** Echo the parsed stream to the pre-processed buffer. */
+ bool m_echo;
+
+ /** Pre-processed buffer. */
+ char* m_cpp_buf;
+
+ /** Pointer to the current position in the pre-processed input stream. */
+ char* m_cpp_ptr;
+
+ /**
+ Starting position of the last token parsed,
+ in the pre-processed buffer.
+ */
+ const char* m_cpp_tok_start;
+
+ /**
+ Starting position of the previous token parsed,
+ in the pre-procedded buffer.
+ */
+ const char* m_cpp_tok_start_prev;
+
+ /**
+ Ending position of the previous token parsed,
+ in the pre-processed buffer.
+ */
+ const char* m_cpp_tok_end;
+
+public:
/** Current state of the lexical analyser. */
enum my_lex_states next_state;
- /** Position of ';' in the stream, to delimit multiple queries. */
+ /**
+ Position of ';' in the stream, to delimit multiple queries.
+ This delimiter is in the raw buffer.
+ */
const char* found_semicolon;
/** SQL_MODE = IGNORE_SPACE. */
bool ignore_space;
- /*
+
+ /**
TRUE if we're parsing a prepared statement: in this mode
we should allow placeholders and disallow multi-statements.
*/
bool stmt_prepare_mode;
+
+ /** State of the lexical analyser for comments. */
+ enum_comment_state in_comment;
};
@@ -1138,8 +1419,17 @@ typedef struct st_lex : public Query_tables_list
CHARSET_INFO *charset, *underscore_charset;
/* store original leaf_tables for INSERT SELECT and PS/SP */
TABLE_LIST *leaf_tables_insert;
- /* Position (first character index) of SELECT of CREATE VIEW statement */
- uint create_view_select_start;
+
+ /** Start of SELECT of CREATE VIEW statement */
+ const char* create_view_select_start;
+ /** End of SELECT of CREATE VIEW statement */
+ const char* create_view_select_end;
+
+ /** Start of 'ON <table>', in trigger statements. */
+ const char* raw_trg_on_table_name_begin;
+ /** End of 'ON <table>', in trigger statements. */
+ const char* raw_trg_on_table_name_end;
+
/* Partition info structure filled in by PARTITION BY parse part */
partition_info *part_info;
@@ -1149,8 +1439,8 @@ typedef struct st_lex : public Query_tables_list
*/
LEX_USER *definer;
- List<key_part_spec> col_list;
- List<key_part_spec> ref_list;
+ List<Key_part_spec> col_list;
+ List<Key_part_spec> ref_list;
List<String> interval_list;
List<LEX_USER> users_list;
List<LEX_COLUMN> columns;
@@ -1176,7 +1466,7 @@ typedef struct st_lex : public Query_tables_list
List<LEX_STRING> db_list;
SQL_LIST proc_list, auxiliary_table_list, save_list;
- create_field *last_field;
+ Create_field *last_field;
Item_sum *in_sum_func;
udf_func udf;
HA_CHECK_OPT check_opt; // check/repair options
@@ -1238,7 +1528,9 @@ typedef struct st_lex : public Query_tables_list
uint8 create_view_algorithm;
uint8 create_view_check;
bool drop_if_exists, drop_temporary, local_file, one_shot_set;
- bool in_comment, verbose, no_write_to_binlog;
+
+ bool verbose, no_write_to_binlog;
+
bool tx_chain, tx_release;
/*
Special JOIN::prepare mode: changing of query is prohibited.
@@ -1302,10 +1594,12 @@ typedef struct st_lex : public Query_tables_list
- CREATE FUNCTION (points to "FUNCTION" or "AGGREGATE");
This pointer is required to add possibly omitted DEFINER-clause to the
- DDL-statement before dumping it to the binlog.
+ DDL-statement before dumping it to the binlog.
*/
const char *stmt_definition_begin;
+ const char *stmt_definition_end;
+
/*
Pointers to part of LOAD DATA statement that should be rewritten
during replication ("LOCAL 'filename' REPLACE INTO" part).
@@ -1434,8 +1728,8 @@ extern void lex_free(void);
extern void lex_start(THD *thd);
extern void lex_end(LEX *lex);
extern int MYSQLlex(void *arg, void *yythd);
-extern const char *skip_rear_comments(CHARSET_INFO *cs, const char *ubegin,
- const char *uend);
+
+extern void trim_whitespace(CHARSET_INFO *cs, LEX_STRING *str);
extern bool is_lex_native_function(const LEX_STRING *name);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index e7ed02f333e..66296377100 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -5353,12 +5353,11 @@ void mysql_parse(THD *thd, const char *inBuf, uint length,
sp_cache_flush_obsolete(&thd->sp_func_cache);
Lex_input_stream lip(thd, inBuf, length);
- thd->m_lip= &lip;
- int err= MYSQLparse(thd);
+ bool err= parse_sql(thd, &lip);
*found_semicolon= lip.found_semicolon;
- if (!err && ! thd->is_fatal_error)
+ if (!err)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (mqh_used && thd->user_connect &&
@@ -5381,8 +5380,8 @@ void mysql_parse(THD *thd, const char *inBuf, uint length,
PROCESSLIST.
Note that we don't need LOCK_thread_count to modify query_length.
*/
- if (lip.found_semicolon &&
- (thd->query_length= (ulong)(lip.found_semicolon - thd->query)))
+ if (*found_semicolon &&
+ (thd->query_length= (ulong)(*found_semicolon - thd->query)))
thd->query_length--;
/* Actually execute the query */
mysql_execute_command(thd);
@@ -5436,12 +5435,10 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
DBUG_ENTER("mysql_test_parse_for_slave");
Lex_input_stream lip(thd, inBuf, length);
- thd->m_lip= &lip;
lex_start(thd);
mysql_reset_thd_for_next_command(thd);
- int err= MYSQLparse((void*) thd);
- if (!err && ! thd->is_fatal_error &&
+ if (!parse_sql(thd, &lip) &&
all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
error= 1; /* Ignore question */
thd->end_statement();
@@ -5466,7 +5463,7 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
List<String> *interval_list, CHARSET_INFO *cs,
uint uint_geom_type)
{
- register create_field *new_field;
+ register Create_field *new_field;
LEX *lex= thd->lex;
DBUG_ENTER("add_field_to_list");
@@ -5479,7 +5476,7 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
if (type_modifier & PRI_KEY_FLAG)
{
Key *key;
- lex->col_list.push_back(new key_part_spec(field_name->str, 0));
+ lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
key= new Key(Key::PRIMARY, NullS,
&default_key_create_info,
0, lex->col_list);
@@ -5489,7 +5486,7 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
{
Key *key;
- lex->col_list.push_back(new key_part_spec(field_name->str, 0));
+ lex->col_list.push_back(new Key_part_spec(field_name->str, 0));
key= new Key(Key::UNIQUE, NullS,
&default_key_create_info, 0,
lex->col_list);
@@ -5547,7 +5544,7 @@ bool add_field_to_list(THD *thd, LEX_STRING *field_name, enum_field_types type,
WARN_DEPRECATED(thd, "5.2", buf, "'TIMESTAMP'");
}
- if (!(new_field= new create_field()) ||
+ if (!(new_field= new Create_field()) ||
new_field->init(thd, field_name->str, type, length, decimals, type_modifier,
default_value, on_update_value, comment, change,
interval_list, cs, uint_geom_type))
@@ -7133,3 +7130,34 @@ bool check_string_char_length(LEX_STRING *str, const char *err_msg,
my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_char_length);
return TRUE;
}
+
+
+extern int MYSQLparse(void *thd); // from sql_yacc.cc
+
+
+/**
+ This is a wrapper of MYSQLparse(). All the code should call parse_sql()
+ instead of MYSQLparse().
+
+ @param thd Thread context.
+ @param lip Lexer context.
+
+ @return Error status.
+ @retval FALSE on success.
+ @retval TRUE on parsing error.
+*/
+
+bool parse_sql(THD *thd, Lex_input_stream *lip)
+{
+ bool err_status;
+
+ DBUG_ASSERT(thd->m_lip == NULL);
+
+ thd->m_lip= lip;
+
+ err_status= MYSQLparse(thd) != 0 || thd->is_fatal_error;
+
+ thd->m_lip= NULL;
+
+ return err_status;
+}
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 04e7645a8aa..407a0b3dcf2 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -3696,7 +3696,6 @@ bool mysql_unpack_partition(THD *thd,
thd->variables.character_set_client= system_charset_info;
Lex_input_stream lip(thd, part_buf, part_info_len);
- thd->m_lip= &lip;
lex_start(thd);
/*
@@ -3725,7 +3724,7 @@ bool mysql_unpack_partition(THD *thd,
lex.part_info->part_state= part_state;
lex.part_info->part_state_len= part_state_len;
DBUG_PRINT("info", ("Parse: %s", part_buf));
- if (MYSQLparse((void*)thd) || thd->is_fatal_error)
+ if (parse_sql(thd, &lip))
{
thd->free_items();
goto end;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 9d739102b6f..7badccd55d9 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2868,12 +2868,11 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
Lex_input_stream lip(thd, thd->query, thd->query_length);
lip.stmt_prepare_mode= TRUE;
- thd->m_lip= &lip;
lex_start(thd);
- int err= MYSQLparse((void *)thd);
- error= err || thd->is_fatal_error ||
- thd->net.report_error || init_param_array(this);
+ error= parse_sql(thd, &lip) ||
+ thd->net.report_error ||
+ init_param_array(this);
/*
While doing context analysis of the query (in check_prepared_statement)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index dc5e33518d2..98620800434 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -10083,12 +10083,12 @@ err:
0 if out of memory, TABLE object in case of success
*/
-TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
+TABLE *create_virtual_tmp_table(THD *thd, List<Create_field> &field_list)
{
uint field_count= field_list.elements;
uint blob_count= 0;
Field **field;
- create_field *cdef; /* column definition */
+ Create_field *cdef; /* column definition */
uint record_length= 0;
uint null_count= 0; /* number of columns which may be null */
uint null_pack_length; /* NULL representation array length */
@@ -10116,7 +10116,7 @@ TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list)
setup_tmp_table_column_bitmaps(table, bitmaps);
/* Create all fields and calculate the total length of record */
- List_iterator_fast<create_field> it(field_list);
+ List_iterator_fast<Create_field> it(field_list);
while ((cdef= it++))
{
*field= make_field(share, 0, cdef->length,
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 9527bd57922..047c210d6a5 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -34,13 +34,13 @@ const char *primary_key_name="PRIMARY";
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
static int copy_data_between_tables(TABLE *from,TABLE *to,
- List<create_field> &create, bool ignore,
+ List<Create_field> &create, bool ignore,
uint order_num, ORDER *order,
ha_rows *copied,ha_rows *deleted,
enum enum_enable_or_disable keys_onoff,
bool error_if_not_empty);
-static bool prepare_blob_field(THD *thd, create_field *sql_field);
+static bool prepare_blob_field(THD *thd, Create_field *sql_field);
static bool check_engine(THD *, const char *, HA_CREATE_INFO *);
static bool
mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
@@ -1939,7 +1939,7 @@ void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
table_flags table flags
DESCRIPTION
- This function prepares a create_field instance.
+ This function prepares a Create_field instance.
Fields such as pack_flag are valid after this call.
RETURN VALUES
@@ -1947,7 +1947,7 @@ void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
1 Error
*/
-int prepare_create_field(create_field *sql_field,
+int prepare_create_field(Create_field *sql_field,
uint *blob_columns,
int *timestamps, int *timestamps_with_niladic,
longlong table_flags)
@@ -2138,7 +2138,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
uint *key_count, int select_field_count)
{
const char *key_name;
- create_field *sql_field,*dup_field;
+ Create_field *sql_field,*dup_field;
uint field,null_fields,blob_columns,max_key_length;
ulong record_offset= 0;
KEY *key_info;
@@ -2146,8 +2146,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
int timestamps= 0, timestamps_with_niladic= 0;
int field_no,dup_no;
int select_field_pos,auto_increment=0;
- List_iterator<create_field> it(alter_info->create_list);
- List_iterator<create_field> it2(alter_info->create_list);
+ List_iterator<Create_field> it(alter_info->create_list);
+ List_iterator<Create_field> it2(alter_info->create_list);
uint total_uneven_bit_length= 0;
DBUG_ENTER("mysql_prepare_create_table");
@@ -2201,7 +2201,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
sql_field->sql_type == MYSQL_TYPE_ENUM))
{
/*
- Starting from 5.1 we work here with a copy of create_field
+ Starting from 5.1 we work here with a copy of Create_field
created by the caller, not with the instance that was
originally created during parsing. It's OK to create
a temporary item and initialize with it a member of the
@@ -2492,7 +2492,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (key->type == Key::FOREIGN_KEY)
{
fk_key_count++;
- foreign_key *fk_key= (foreign_key*) key;
+ Foreign_key *fk_key= (Foreign_key*) key;
if (fk_key->ref_columns.elements &&
fk_key->ref_columns.elements != fk_key->columns.elements)
{
@@ -2576,7 +2576,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
for (; (key=key_iterator++) ; key_number++)
{
uint key_length=0;
- key_part_spec *column;
+ Key_part_spec *column;
if (key->name == ignore_key)
{
@@ -2685,12 +2685,12 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
if (key_info->block_size)
key_info->flags|= HA_USES_BLOCK_SIZE;
- List_iterator<key_part_spec> cols(key->columns), cols2(key->columns);
+ List_iterator<Key_part_spec> cols(key->columns), cols2(key->columns);
CHARSET_INFO *ft_key_charset=0; // for FULLTEXT
for (uint column_nr=0 ; (column=cols++) ; column_nr++)
{
uint length;
- key_part_spec *dup_column;
+ Key_part_spec *dup_column;
it.rewind();
field=0;
@@ -3000,7 +3000,7 @@ static void set_table_default_charset(THD *thd,
In this case the error is given
*/
-static bool prepare_blob_field(THD *thd, create_field *sql_field)
+static bool prepare_blob_field(THD *thd, Create_field *sql_field)
{
DBUG_ENTER("prepare_blob_field");
@@ -3041,7 +3041,7 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field)
/*
- Preparation of create_field for SP function return values.
+ Preparation of Create_field for SP function return values.
Based on code used in the inner loop of mysql_prepare_create_table()
above.
@@ -3055,7 +3055,7 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field)
*/
-void sp_prepare_create_field(THD *thd, create_field *sql_field)
+void sp_prepare_create_field(THD *thd, Create_field *sql_field)
{
if (sql_field->sql_type == MYSQL_TYPE_SET ||
sql_field->sql_type == MYSQL_TYPE_ENUM)
@@ -4950,8 +4950,8 @@ compare_tables(TABLE *table,
Field **f_ptr, *field;
uint changes= 0, tmp;
uint key_count;
- List_iterator_fast<create_field> new_field_it(alter_info->create_list);
- create_field *new_field;
+ List_iterator_fast<Create_field> new_field_it(alter_info->create_list);
+ Create_field *new_field;
KEY_PART_INFO *key_part;
KEY_PART_INFO *end;
/*
@@ -5298,16 +5298,16 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
Alter_info *alter_info)
{
/* New column definitions are added here */
- List<create_field> new_create_list;
+ List<Create_field> new_create_list;
/* New key definitions are added here */
List<Key> new_key_list;
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
- List_iterator<create_field> def_it(alter_info->create_list);
+ List_iterator<Create_field> def_it(alter_info->create_list);
List_iterator<Alter_column> alter_it(alter_info->alter_list);
List_iterator<Key> key_it(alter_info->key_list);
- List_iterator<create_field> find_it(new_create_list);
- List_iterator<create_field> field_it(new_create_list);
- List<key_part_spec> key_parts;
+ List_iterator<Create_field> find_it(new_create_list);
+ List_iterator<Create_field> field_it(new_create_list);
+ List<Key_part_spec> key_parts;
uint db_create_options= (table->s->db_create_options
& ~(HA_OPTION_PACK_RECORD));
uint used_fields= create_info->used_fields;
@@ -5347,7 +5347,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
create_info->tablespace= tablespace;
}
restore_record(table, s->default_values); // Empty record for DEFAULT
- create_field *def;
+ Create_field *def;
/*
First collect all fields from table which isn't in drop_list
@@ -5403,7 +5403,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
This field was not dropped and not changed, add it to the list
for the new table.
*/
- def= new create_field(field, field);
+ def= new Create_field(field, field);
new_create_list.push_back(def);
alter_it.rewind(); // Change default if ALTER
Alter_column *alter;
@@ -5458,7 +5458,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
new_create_list.push_front(def);
else
{
- create_field *find;
+ Create_field *find;
find_it.rewind();
while ((find=find_it++)) // Add new columns
{
@@ -5516,7 +5516,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
if (!key_part->field)
continue; // Wrong field (from UNIREG)
const char *key_part_name=key_part->field->field_name;
- create_field *cfield;
+ Create_field *cfield;
field_it.rewind();
while ((cfield=field_it++))
{
@@ -5558,7 +5558,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
key_part_length= 0; // Use whole field
}
key_part_length /= key_part->field->charset()->mbmaxlen;
- key_parts.push_back(new key_part_spec(cfield->field_name,
+ key_parts.push_back(new Key_part_spec(cfield->field_name,
key_part_length));
}
if (key_parts.elements)
@@ -6763,7 +6763,7 @@ err_with_placeholders:
static int
copy_data_between_tables(TABLE *from,TABLE *to,
- List<create_field> &create,
+ List<Create_field> &create,
bool ignore,
uint order_num, ORDER *order,
ha_rows *copied,
@@ -6817,8 +6817,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
save_sql_mode= thd->variables.sql_mode;
- List_iterator<create_field> it(create);
- create_field *def;
+ List_iterator<Create_field> it(create);
+ Create_field *def;
copy_end=copy;
for (Field **ptr=to->field ; *ptr ; ptr++)
{
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index e15003ab243..7433a3f45cd 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -23,7 +23,7 @@
static const LEX_STRING triggers_file_type=
{ C_STRING_WITH_LEN("TRIGGERS") };
-const char * const triggers_file_ext= ".TRG";
+const char * const TRG_EXT= ".TRG";
/*
Table of .TRG file field descriptors.
@@ -79,7 +79,7 @@ struct st_trigname
static const LEX_STRING trigname_file_type=
{ C_STRING_WITH_LEN("TRIGGERNAME") };
-const char * const trigname_file_ext= ".TRN";
+const char * const TRN_EXT= ".TRN";
static File_option trigname_file_parameters[]=
{
@@ -132,6 +132,7 @@ private:
LEX_STRING *trigger_table_value;
};
+
/*
Create or drop trigger for table.
@@ -463,14 +464,14 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
sql_create_definition_file() files handles renaming and backup of older
versions
*/
- file.length= build_table_filename(file_buff, FN_REFLEN-1,
+ file.length= build_table_filename(file_buff, FN_REFLEN - 1,
tables->db, tables->table_name,
- triggers_file_ext, 0);
+ TRG_EXT, 0);
file.str= file_buff;
trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1,
tables->db,
lex->spname->m_name.str,
- trigname_file_ext, 0);
+ TRN_EXT, 0);
trigname_file.str= trigname_buff;
/* Use the filesystem to enforce trigger namespace constraints. */
@@ -563,10 +564,13 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
append_definer(thd, stmt_query, &definer_user, &definer_host);
}
- stmt_query->append(thd->lex->stmt_definition_begin,
- (char *) thd->lex->sphead->m_body_begin -
- thd->lex->stmt_definition_begin +
- thd->lex->sphead->m_body.length);
+ LEX_STRING stmt_definition;
+ stmt_definition.str= (char*) thd->lex->stmt_definition_begin;
+ stmt_definition.length= thd->lex->stmt_definition_end
+ - thd->lex->stmt_definition_begin;
+ trim_whitespace(thd->charset(), & stmt_definition);
+
+ stmt_query->append(stmt_definition.str, stmt_definition.length);
trg_def->str= stmt_query->c_ptr();
trg_def->length= stmt_query->length();
@@ -601,7 +605,7 @@ err_with_cleanup:
static bool rm_trigger_file(char *path, const char *db,
const char *table_name)
{
- build_table_filename(path, FN_REFLEN-1, db, table_name, triggers_file_ext, 0);
+ build_table_filename(path, FN_REFLEN-1, db, table_name, TRG_EXT, 0);
return my_delete(path, MYF(MY_WME));
}
@@ -624,8 +628,7 @@ static bool rm_trigger_file(char *path, const char *db,
static bool rm_trigname_file(char *path, const char *db,
const char *trigger_name)
{
- build_table_filename(path, FN_REFLEN-1,
- db, trigger_name, trigname_file_ext, 0);
+ build_table_filename(path, FN_REFLEN - 1, db, trigger_name, TRN_EXT, 0);
return my_delete(path, MYF(MY_WME));
}
@@ -650,8 +653,8 @@ static bool save_trigger_file(Table_triggers_list *triggers, const char *db,
char file_buff[FN_REFLEN];
LEX_STRING file;
- file.length= build_table_filename(file_buff, FN_REFLEN-1, db, table_name,
- triggers_file_ext, 0);
+ file.length= build_table_filename(file_buff, FN_REFLEN - 1, db, table_name,
+ TRG_EXT, 0);
file.str= file_buff;
return sql_create_definition_file(NULL, &file, &triggers_file_type,
(uchar*)triggers, triggers_file_parameters,
@@ -831,8 +834,8 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
DBUG_ENTER("Table_triggers_list::check_n_load");
- path.length= build_table_filename(path_buff, FN_REFLEN-1,
- db, table_name, triggers_file_ext, 0);
+ path.length= build_table_filename(path_buff, FN_REFLEN - 1,
+ db, table_name, TRG_EXT, 0);
path.str= path_buff;
// QQ: should we analyze errno somehow ?
@@ -978,12 +981,10 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
thd->variables.sql_mode= (ulong)*trg_sql_mode;
Lex_input_stream lip(thd, trg_create_str->str, trg_create_str->length);
- thd->m_lip= &lip;
lex_start(thd);
thd->spcont= 0;
- int err= MYSQLparse((void *)thd);
- if (err || thd->is_fatal_error)
+ if (parse_sql(thd, &lip))
{
/* Currently sphead is always deleted in case of a parse error */
DBUG_ASSERT(lex.sphead == 0);
@@ -1032,7 +1033,11 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
if (!(on_table_name= (LEX_STRING*) alloc_root(&table->mem_root,
sizeof(LEX_STRING))))
goto err_with_lex_cleanup;
- *on_table_name= lex.ident;
+
+ on_table_name->str= (char*) lex.raw_trg_on_table_name_begin;
+ on_table_name->length= lex.raw_trg_on_table_name_end
+ - lex.raw_trg_on_table_name_begin;
+
if (triggers->on_table_names_list.push_back(on_table_name, &table->mem_root))
goto err_with_lex_cleanup;
@@ -1101,7 +1106,7 @@ err_with_lex_cleanup:
be merged into .FRM anyway.
*/
my_error(ER_WRONG_OBJECT, MYF(0),
- table_name, triggers_file_ext+1, "TRIGGER");
+ table_name, TRG_EXT + 1, "TRIGGER");
DBUG_RETURN(1);
}
@@ -1161,83 +1166,66 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
}
-/*
+/**
Find trigger's table from trigger identifier and add it to
the statement table list.
- SYNOPSIS
- mysql_table_for_trigger()
- thd - current thread context
- trig - identifier for trigger
- if_exists - treat a not existing trigger as a warning if TRUE
- table - pointer to TABLE_LIST object for the table trigger (output)
-
- RETURN VALUE
- 0 Success
- 1 Error
+ @param[in] thd Thread context.
+ @param[in] trg_name Trigger name.
+ @param[in] if_exists TRUE if SQL statement contains "IF EXISTS" clause.
+ That means a warning instead of error should be
+ thrown if trigger with given name does not exist.
+ @param[out] table Pointer to TABLE_LIST object for the
+ table trigger.
+
+ @return Operation status
+ @retval FALSE On success.
+ @retval TRUE Otherwise.
*/
-int
-add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
- TABLE_LIST **table)
+bool add_table_for_trigger(THD *thd,
+ sp_name *trg_name,
+ bool if_exists,
+ TABLE_LIST **table)
{
LEX *lex= thd->lex;
- char path_buff[FN_REFLEN];
- LEX_STRING path;
- File_parser *parser;
- struct st_trigname trigname;
- Handle_old_incorrect_trigger_table_hook trigger_table_hook(
- path_buff, &trigname.trigger_table);
-
+ char trn_path_buff[FN_REFLEN];
+ LEX_STRING trn_path= { trn_path_buff, 0 };
+ LEX_STRING tbl_name;
+
DBUG_ENTER("add_table_for_trigger");
- DBUG_ASSERT(table != NULL);
- path.length= build_table_filename(path_buff, FN_REFLEN-1,
- trig->m_db.str, trig->m_name.str,
- trigname_file_ext, 0);
- path.str= path_buff;
+ build_trn_path(thd, trg_name, &trn_path);
- if (access(path_buff, F_OK))
+ if (check_trn_exists(&trn_path))
{
if (if_exists)
{
push_warning_printf(thd,
- MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_TRG_DOES_NOT_EXIST,
- ER(ER_TRG_DOES_NOT_EXIST));
+ MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_TRG_DOES_NOT_EXIST,
+ ER(ER_TRG_DOES_NOT_EXIST));
+
*table= NULL;
- DBUG_RETURN(0);
+
+ DBUG_RETURN(FALSE);
}
my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
- DBUG_RETURN(1);
- }
-
- if (!(parser= sql_parse_prepare(&path, thd->mem_root, 1)))
- DBUG_RETURN(1);
-
- if (!is_equal(&trigname_file_type, parser->type()))
- {
- my_error(ER_WRONG_OBJECT, MYF(0), trig->m_name.str, trigname_file_ext+1,
- "TRIGGERNAME");
- DBUG_RETURN(1);
+ DBUG_RETURN(TRUE);
}
- if (parser->parse((uchar*)&trigname, thd->mem_root,
- trigname_file_parameters, 1,
- &trigger_table_hook))
- DBUG_RETURN(1);
+ if (load_table_name_for_trigger(thd, trg_name, &trn_path, &tbl_name))
+ DBUG_RETURN(TRUE);
/* We need to reset statement table list to be PS/SP friendly. */
lex->query_tables= 0;
lex->query_tables_last= &lex->query_tables;
- *table= sp_add_to_query_tables(thd, lex, trig->m_db.str,
- trigname.trigger_table.str, TL_IGNORE);
- if (! *table)
- DBUG_RETURN(1);
+ *table= sp_add_to_query_tables(thd, lex, trg_name->m_db.str,
+ tbl_name.str, TL_IGNORE);
- DBUG_RETURN(0);
+ DBUG_RETURN(*table ? FALSE : TRUE);
}
@@ -1348,7 +1336,12 @@ Table_triggers_list::change_table_name_in_triggers(THD *thd,
/* Construct CREATE TRIGGER statement with new table name. */
buff.length(0);
+
+ /* WARNING: 'on_table_name' is supposed to point inside 'def' */
+ DBUG_ASSERT(on_table_name->str > def->str);
+ DBUG_ASSERT(on_table_name->str < (def->str + def->length));
before_on_len= on_table_name->str - def->str;
+
buff.append(def->str, before_on_len);
buff.append(STRING_WITH_LEN("ON "));
append_identifier(thd, &buff, new_table_name->str, new_table_name->length);
@@ -1416,7 +1409,7 @@ Table_triggers_list::change_table_name_in_trignames(const char *db_name,
{
trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1,
db_name, trigger->str,
- trigname_file_ext, 0);
+ TRN_EXT, 0);
trigname_file.str= trigname_buff;
trigname.trigger_table= *new_table_name;
@@ -1525,77 +1518,54 @@ end:
}
-bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
- trg_action_time_type time_type,
- bool old_row_is_record1)
-{
- bool err_status= FALSE;
- sp_head *sp_trigger= bodies[event][time_type];
-
- if (sp_trigger)
- {
- Sub_statement_state statement_state;
-
- if (old_row_is_record1)
- {
- old_field= record1_field;
- new_field= trigger_table->field;
- }
- else
- {
- new_field= record1_field;
- old_field= trigger_table->field;
- }
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- Security_context *sctx= &sp_trigger->m_security_ctx;
- Security_context *save_ctx= NULL;
-
+/**
+ Execute trigger for given (event, time) pair.
- if (sp_trigger->m_chistics->suid != SP_IS_NOT_SUID &&
- sctx->change_security_context(thd,
- &sp_trigger->m_definer_user,
- &sp_trigger->m_definer_host,
- &sp_trigger->m_db,
- &save_ctx))
- return TRUE;
+ The operation executes trigger for the specified event (insert, update,
+ delete) and time (after, before) if it is set.
- /*
- Fetch information about table-level privileges to GRANT_INFO structure for
- subject table. Check of privileges that will use it and information about
- column-level privileges will happen in Item_trigger_field::fix_fields().
- */
+ @param thd
+ @param event
+ @param time_type,
+ @param old_row_is_record1
- fill_effective_table_privileges(thd,
- &subject_table_grants[event][time_type],
- trigger_table->s->db.str,
- trigger_table->s->table_name.str);
+ @return Error status.
+ @retval FALSE on success.
+ @retval TRUE on error.
+*/
- /* Check that the definer has TRIGGER privilege on the subject table. */
+bool Table_triggers_list::process_triggers(THD *thd,
+ trg_event_type event,
+ trg_action_time_type time_type,
+ bool old_row_is_record1)
+{
+ bool err_status;
+ Sub_statement_state statement_state;
- if (!(subject_table_grants[event][time_type].privilege & TRIGGER_ACL))
- {
- char priv_desc[128];
- get_privilege_desc(priv_desc, sizeof(priv_desc), TRIGGER_ACL);
+ if (!bodies[event][time_type])
+ return FALSE;
- my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), priv_desc,
- thd->security_ctx->priv_user, thd->security_ctx->host_or_ip,
- trigger_table->s->table_name.str);
+ if (old_row_is_record1)
+ {
+ old_field= record1_field;
+ new_field= trigger_table->field;
+ }
+ else
+ {
+ new_field= record1_field;
+ old_field= trigger_table->field;
+ }
- sctx->restore_security_context(thd, save_ctx);
- return TRUE;
- }
-#endif // NO_EMBEDDED_ACCESS_CHECKS
+ thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
- thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
- err_status= sp_trigger->execute_trigger
- (thd, trigger_table->s->db.str, trigger_table->s->table_name.str,
- &subject_table_grants[event][time_type]);
- thd->restore_sub_statement_state(&statement_state);
+ err_status=
+ bodies[event][time_type]->execute_trigger(
+ thd,
+ &trigger_table->s->db,
+ &trigger_table->s->table_name,
+ &subject_table_grants[event][time_type]);
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- sctx->restore_security_context(thd, save_ctx);
-#endif // NO_EMBEDDED_ACCESS_CHECKS
- }
+ thd->restore_sub_statement_state(&statement_state);
return err_status;
}
@@ -1737,3 +1707,95 @@ process_unknown_string(char *&unknown_key, uchar* base, MEM_ROOT *mem_root,
}
DBUG_RETURN(FALSE);
}
+
+
+/**
+ Contruct path to TRN-file.
+
+ @param thd[in] Thread context.
+ @param trg_name[in] Trigger name.
+ @param trn_path[out] Variable to store constructed path
+*/
+
+void build_trn_path(THD *thd, const sp_name *trg_name, LEX_STRING *trn_path)
+{
+ /* Construct path to the TRN-file. */
+
+ trn_path->length= build_table_filename(trn_path->str,
+ FN_REFLEN - 1,
+ trg_name->m_db.str,
+ trg_name->m_name.str,
+ TRN_EXT,
+ 0);
+}
+
+
+/**
+ Check if TRN-file exists.
+
+ @return
+ @retval TRUE if TRN-file does not exist.
+ @retval FALSE if TRN-file exists.
+*/
+
+bool check_trn_exists(const LEX_STRING *trn_path)
+{
+ return access(trn_path->str, F_OK) != 0;
+}
+
+
+/**
+ Retrieve table name for given trigger.
+
+ @param thd[in] Thread context.
+ @param trg_name[in] Trigger name.
+ @param trn_path[in] Path to the corresponding TRN-file.
+ @param tbl_name[out] Variable to store retrieved table name.
+
+ @return Error status.
+ @retval FALSE on success.
+ @retval TRUE if table name could not be retrieved.
+*/
+
+bool load_table_name_for_trigger(THD *thd,
+ const sp_name *trg_name,
+ const LEX_STRING *trn_path,
+ LEX_STRING *tbl_name)
+{
+ File_parser *parser;
+ struct st_trigname trn_data;
+
+ Handle_old_incorrect_trigger_table_hook trigger_table_hook(
+ trn_path->str,
+ &trn_data.trigger_table);
+
+ DBUG_ENTER("load_table_name_for_trigger");
+
+ /* Parse the TRN-file. */
+
+ if (!(parser= sql_parse_prepare(trn_path, thd->mem_root, TRUE)))
+ DBUG_RETURN(TRUE);
+
+ if (!is_equal(&trigname_file_type, parser->type()))
+ {
+ my_error(ER_WRONG_OBJECT, MYF(0),
+ trg_name->m_name.str,
+ TRN_EXT + 1,
+ "TRIGGERNAME");
+
+ DBUG_RETURN(TRUE);
+ }
+
+ if (parser->parse((uchar*) &trn_data, thd->mem_root,
+ trigname_file_parameters, 1,
+ &trigger_table_hook))
+ DBUG_RETURN(TRUE);
+
+ /* Copy trigger table name. */
+
+ *tbl_name= trn_data.trigger_table;
+
+ /* That's all. */
+
+ DBUG_RETURN(FALSE);
+}
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index 7d99dd811cd..c305efb5029 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -17,7 +17,7 @@
/*
This class holds all information about triggers of table.
- QQ: Will it be merged into TABLE in future ?
+ QQ: Will it be merged into TABLE in the future ?
*/
class Table_triggers_list: public Sql_alloc
@@ -143,6 +143,17 @@ private:
extern const LEX_STRING trg_action_time_type_names[];
extern const LEX_STRING trg_event_type_names[];
-int
-add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
- TABLE_LIST **table);
+bool add_table_for_trigger(THD *thd,
+ sp_name *trg_name,
+ bool continue_if_not_exist,
+ TABLE_LIST **table);
+
+void build_trn_path(THD *thd, const sp_name *trg_name, LEX_STRING *trn_path);
+
+bool check_trn_exists(const LEX_STRING *trn_path);
+
+bool load_table_name_for_trigger(THD *thd,
+ const sp_name *trg_name,
+ const LEX_STRING *trn_path,
+ LEX_STRING *tbl_name);
+
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index c1e4006555f..dd17024aee0 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -690,7 +690,6 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
char md5[MD5_BUFF_LENGTH];
bool can_be_merged;
char dir_buff[FN_REFLEN], path_buff[FN_REFLEN];
- const char *endp;
LEX_STRING dir, file, path;
int error= 0;
DBUG_ENTER("mysql_register_view");
@@ -708,10 +707,12 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
/* fill structure */
view->query.str= str.c_ptr_safe();
view->query.length= str.length();
- view->source.str= thd->query + thd->lex->create_view_select_start;
- endp= view->source.str;
- endp= skip_rear_comments(thd->charset(), endp, thd->query + thd->query_length);
- view->source.length= endp - view->source.str;
+
+ view->source.str= (char*) thd->lex->create_view_select_start;
+ view->source.length= (thd->lex->create_view_select_end
+ - thd->lex->create_view_select_start);
+ trim_whitespace(thd->charset(), & view->source);
+
view->file_version= 1;
view->calc_md5(md5);
view->md5.str= md5;
@@ -892,7 +893,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
LEX *old_lex, *lex;
Query_arena *arena, backup;
TABLE_LIST *top_view= table->top_table();
- int res;
+ bool res;
bool result, view_is_mergeable;
TABLE_LIST *view_main_select_tables;
DBUG_ENTER("mysql_make_view");
@@ -1004,7 +1005,6 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
{
Lex_input_stream lip(thd, table->query.str, table->query.length);
- thd->m_lip= &lip;
lex_start(thd);
view_select= &lex->select_lex;
view_select->select_number= ++thd->select_number;
@@ -1038,7 +1038,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
MODE_IGNORE_SPACE | MODE_NO_BACKSLASH_ESCAPES);
CHARSET_INFO *save_cs= thd->variables.character_set_client;
thd->variables.character_set_client= system_charset_info;
- res= MYSQLparse((void *)thd);
+ res= parse_sql(thd, &lip);
if ((old_lex->sql_command == SQLCOM_SHOW_FIELDS) ||
(old_lex->sql_command == SQLCOM_SHOW_CREATE))
@@ -1047,7 +1047,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
thd->variables.character_set_client= save_cs;
thd->variables.sql_mode= save_mode;
}
- if (!res && !thd->is_fatal_error)
+ if (!res)
{
TABLE_LIST *view_tables= lex->query_tables;
TABLE_LIST *view_tables_tail= 0;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 1c00ac98c03..3babaa2aa7a 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -106,7 +106,7 @@ void my_parse_error(const char *s)
THD *thd= current_thd;
Lex_input_stream *lip= thd->m_lip;
- const char *yytext= lip->tok_start;
+ const char *yytext= lip->get_tok_start();
/* Push an error into the error stack */
my_printf_error(ER_PARSE_ERROR, ER(ER_PARSE_ERROR), MYF(0), s,
(yytext ? yytext : ""),
@@ -456,7 +456,7 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal,
List<Item> *item_list;
List<String> *string_list;
String *string;
- key_part_spec *key_part;
+ Key_part_spec *key_part;
TABLE_LIST *table_list;
udf_func *udf;
LEX_USER *lex_user;
@@ -1872,10 +1872,7 @@ ev_sql_stmt:
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
lex->sphead->m_chistics= &lex->sp_chistics;
- lex->sphead->m_body_begin= lip->ptr;
-
- lex->event_parse_data->body_begin= lip->ptr;
-
+ lex->sphead->set_body_begin_ptr(lip, lip->get_cpp_ptr());
}
ev_sql_stmt_inner
{
@@ -1888,7 +1885,7 @@ ev_sql_stmt:
lex->sp_chistics.suid= SP_IS_SUID; //always the definer!
- lex->event_parse_data->init_body(thd);
+ lex->event_parse_data->body_changed= TRUE;
}
;
@@ -1986,6 +1983,7 @@ create_function_tail:
LEX *lex= thd->lex;
Lex_input_stream *lip= thd->m_lip;
sp_head *sp;
+ const char* tmp_param_begin;
/*
First check if AGGREGATE was used, in that case it's a
@@ -2017,7 +2015,10 @@ create_function_tail:
*/
$<ulong_num>$= thd->client_capabilities & CLIENT_MULTI_QUERIES;
thd->client_capabilities &= ~CLIENT_MULTI_QUERIES;
- lex->sphead->m_param_begin= lip->tok_start+1;
+
+ tmp_param_begin= lip->get_cpp_tok_start();
+ tmp_param_begin++;
+ lex->sphead->m_param_begin= tmp_param_begin;
}
sp_fdparam_list ')'
{
@@ -2025,7 +2026,7 @@ create_function_tail:
LEX *lex= thd->lex;
Lex_input_stream *lip= thd->m_lip;
- lex->sphead->m_param_end= lip->tok_start;
+ lex->sphead->m_param_end= lip->get_cpp_tok_start();
}
RETURNS_SYM
{
@@ -2065,7 +2066,7 @@ create_function_tail:
Lex_input_stream *lip= thd->m_lip;
lex->sphead->m_chistics= &lex->sp_chistics;
- lex->sphead->m_body_begin= lip->tok_start;
+ lex->sphead->set_body_begin_ptr(lip, lip->get_cpp_tok_start());
}
sp_proc_stmt
{
@@ -2676,7 +2677,7 @@ sp_proc_stmt_statement:
Lex_input_stream *lip= thd->m_lip;
lex->sphead->reset_lex(thd);
- lex->sphead->m_tmp_query= lip->tok_start;
+ lex->sphead->m_tmp_query= lip->get_tok_start();
}
statement
{
@@ -2709,9 +2710,9 @@ sp_proc_stmt_statement:
lex->tok_end otherwise.
*/
if (yychar == YYEMPTY)
- i->m_query.length= lip->ptr - sp->m_tmp_query;
+ i->m_query.length= lip->get_ptr() - sp->m_tmp_query;
else
- i->m_query.length= lip->tok_end - sp->m_tmp_query;
+ i->m_query.length= lip->get_tok_end() - sp->m_tmp_query;
i->m_query.str= strmake_root(thd->mem_root,
sp->m_tmp_query,
i->m_query.length);
@@ -4498,7 +4499,7 @@ key_def:
{
LEX *lex=Lex;
const char *key_name= $4 ? $4 : $1;
- Key *key= new foreign_key(key_name, lex->col_list,
+ Key *key= new Foreign_key(key_name, lex->col_list,
$8,
lex->ref_list,
lex->fk_delete_opt,
@@ -4925,8 +4926,8 @@ opt_ref_list:
| '(' ref_list ')' opt_on_delete {};
ref_list:
- ref_list ',' ident { Lex->ref_list.push_back(new key_part_spec($3.str)); }
- | ident { Lex->ref_list.push_back(new key_part_spec($1.str)); };
+ ref_list ',' ident { Lex->ref_list.push_back(new Key_part_spec($3.str)); }
+ | ident { Lex->ref_list.push_back(new Key_part_spec($1.str)); };
opt_on_delete:
@@ -4940,16 +4941,16 @@ opt_on_delete_list:
opt_on_delete_item:
ON DELETE_SYM delete_option { Lex->fk_delete_opt= $3; }
| ON UPDATE_SYM delete_option { Lex->fk_update_opt= $3; }
- | MATCH FULL { Lex->fk_match_option= foreign_key::FK_MATCH_FULL; }
- | MATCH PARTIAL { Lex->fk_match_option= foreign_key::FK_MATCH_PARTIAL; }
- | MATCH SIMPLE_SYM { Lex->fk_match_option= foreign_key::FK_MATCH_SIMPLE; };
+ | MATCH FULL { Lex->fk_match_option= Foreign_key::FK_MATCH_FULL; }
+ | MATCH PARTIAL { Lex->fk_match_option= Foreign_key::FK_MATCH_PARTIAL; }
+ | MATCH SIMPLE_SYM { Lex->fk_match_option= Foreign_key::FK_MATCH_SIMPLE; };
delete_option:
- RESTRICT { $$= (int) foreign_key::FK_OPTION_RESTRICT; }
- | CASCADE { $$= (int) foreign_key::FK_OPTION_CASCADE; }
- | SET NULL_SYM { $$= (int) foreign_key::FK_OPTION_SET_NULL; }
- | NO_SYM ACTION { $$= (int) foreign_key::FK_OPTION_NO_ACTION; }
- | SET DEFAULT { $$= (int) foreign_key::FK_OPTION_DEFAULT; };
+ RESTRICT { $$= (int) Foreign_key::FK_OPTION_RESTRICT; }
+ | CASCADE { $$= (int) Foreign_key::FK_OPTION_CASCADE; }
+ | SET NULL_SYM { $$= (int) Foreign_key::FK_OPTION_SET_NULL; }
+ | NO_SYM ACTION { $$= (int) Foreign_key::FK_OPTION_NO_ACTION; }
+ | SET DEFAULT { $$= (int) Foreign_key::FK_OPTION_DEFAULT; };
key_type:
key_or_index { $$= Key::MULTIPLE; }
@@ -5061,7 +5062,7 @@ key_list:
| key_part order_dir { Lex->col_list.push_back($1); };
key_part:
- ident { $$=new key_part_spec($1.str); }
+ ident { $$=new Key_part_spec($1.str); }
| ident '(' NUM ')'
{
int key_part_len= atoi($3.str);
@@ -5069,7 +5070,7 @@ key_part:
{
my_error(ER_KEY_PART_0, MYF(0), $1.str);
}
- $$=new key_part_spec($1.str,(uint) key_part_len);
+ $$=new Key_part_spec($1.str,(uint) key_part_len);
};
opt_ident:
@@ -6229,14 +6230,14 @@ remember_name:
{
THD *thd= YYTHD;
Lex_input_stream *lip= thd->m_lip;
- $$= (char*) lip->tok_start;
+ $$= (char*) lip->get_cpp_tok_start();
};
remember_end:
{
THD *thd= YYTHD;
Lex_input_stream *lip= thd->m_lip;
- $$=(char*) lip->tok_end;
+ $$= (char*) lip->get_cpp_tok_end();
};
select_item2:
@@ -8003,16 +8004,14 @@ procedure_list2:
| procedure_item;
procedure_item:
- remember_name expr
+ remember_name expr remember_end
{
THD *thd= YYTHD;
- Lex_input_stream *lip= thd->m_lip;
if (add_proc_to_list(thd, $2))
MYSQL_YYABORT;
if (!$2->name)
- $2->set_name($1,(uint) ((char*) lip->tok_end - $1),
- thd->charset());
+ $2->set_name($1, (uint) ($3 - $1), thd->charset());
}
;
@@ -9112,7 +9111,7 @@ load: LOAD DATA_SYM
my_error(ER_SP_BADSTATEMENT, MYF(0), "LOAD DATA");
MYSQL_YYABORT;
}
- lex->fname_start= lip->ptr;
+ lex->fname_start= lip->get_ptr();
}
load_data
{}
@@ -9149,7 +9148,7 @@ load_data:
THD *thd= YYTHD;
LEX *lex= thd->lex;
Lex_input_stream *lip= thd->m_lip;
- lex->fname_end= lip->ptr;
+ lex->fname_end= lip->get_ptr();
}
TABLE_SYM table_ident
{
@@ -9338,7 +9337,7 @@ param_marker:
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
MYSQL_YYABORT;
}
- item= new Item_param((uint) (lip->tok_start - thd->query));
+ item= new Item_param((uint) (lip->get_tok_start() - thd->query));
if (!($$= item) || lex->param_list.push_back(item))
{
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
@@ -9471,7 +9470,7 @@ simple_ident:
Item_splocal *splocal;
splocal= new Item_splocal($1, spv->offset, spv->type,
- lip->tok_start_prev -
+ lip->get_tok_start_prev() -
lex->sphead->m_tmp_query);
#ifndef DBUG_OFF
if (splocal)
@@ -10147,7 +10146,7 @@ option_type_value:
lex->option_type=OPT_SESSION;
lex->var_list.empty();
lex->one_shot_set= 0;
- lex->sphead->m_tmp_query= lip->tok_start;
+ lex->sphead->m_tmp_query= lip->get_tok_start();
}
}
ext_option_value
@@ -10180,9 +10179,9 @@ option_type_value:
lip->tok_end otherwise.
*/
if (yychar == YYEMPTY)
- qbuff.length= lip->ptr - sp->m_tmp_query;
+ qbuff.length= lip->get_ptr() - sp->m_tmp_query;
else
- qbuff.length= lip->tok_end - sp->m_tmp_query;
+ qbuff.length= lip->get_tok_end() - sp->m_tmp_query;
if (!(qbuff.str= (char*) alloc_root(thd->mem_root,
qbuff.length + 5)))
@@ -11364,7 +11363,7 @@ view_tail:
if (!lex->select_lex.add_table_to_list(thd, $3, NULL, TL_OPTION_UPDATING))
MYSQL_YYABORT;
}
- view_list_opt AS view_select view_check_option
+ view_list_opt AS view_select
{}
;
@@ -11389,40 +11388,32 @@ view_list:
view_select:
{
+ THD *thd= YYTHD;
LEX *lex= Lex;
+ Lex_input_stream *lip= thd->m_lip;
lex->parsing_options.allows_variable= FALSE;
lex->parsing_options.allows_select_into= FALSE;
lex->parsing_options.allows_select_procedure= FALSE;
lex->parsing_options.allows_derived= FALSE;
- }
- view_select_aux
+ lex->create_view_select_start= lip->get_cpp_ptr();
+ }
+ view_select_aux view_check_option
{
+ THD *thd= YYTHD;
LEX *lex= Lex;
+ Lex_input_stream *lip= thd->m_lip;
lex->parsing_options.allows_variable= TRUE;
lex->parsing_options.allows_select_into= TRUE;
lex->parsing_options.allows_select_procedure= TRUE;
lex->parsing_options.allows_derived= TRUE;
+ lex->create_view_select_end= lip->get_cpp_ptr();
}
;
view_select_aux:
- SELECT_SYM remember_name select_init2
- {
- THD *thd= YYTHD;
- LEX *lex= thd->lex;
- const char *stmt_beg= (lex->sphead ?
- lex->sphead->m_tmp_query : thd->query);
- lex->create_view_select_start= $2 - stmt_beg;
- }
- | '(' remember_name select_paren ')' union_opt
- {
- THD *thd= YYTHD;
- LEX *lex= thd->lex;
- const char *stmt_beg= (lex->sphead ?
- lex->sphead->m_tmp_query : thd->query);
- lex->create_view_select_start= $2 - stmt_beg;
- }
- ;
+ SELECT_SYM select_init2
+ | '(' select_paren ')' union_opt
+ ;
view_check_option:
/* empty */
@@ -11442,9 +11433,31 @@ view_check_option:
**************************************************************************/
trigger_tail:
- TRIGGER_SYM remember_name sp_name trg_action_time trg_event
- ON remember_name table_ident FOR_SYM remember_name EACH_SYM ROW_SYM
- {
+ TRIGGER_SYM
+ remember_name
+ sp_name
+ trg_action_time
+ trg_event
+ ON
+ remember_name /* $7 */
+ { /* $8 */
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
+ lex->raw_trg_on_table_name_begin= lip->get_tok_start();
+ }
+ table_ident /* $9 */
+ FOR_SYM
+ remember_name /* $11 */
+ { /* $12 */
+ THD *thd= YYTHD;
+ LEX *lex= thd->lex;
+ Lex_input_stream *lip= thd->m_lip;
+ lex->raw_trg_on_table_name_end= lip->get_tok_start();
+ }
+ EACH_SYM
+ ROW_SYM
+ { /* $15 */
THD *thd= YYTHD;
LEX *lex= thd->lex;
Lex_input_stream *lip= thd->m_lip;
@@ -11463,7 +11476,7 @@ trigger_tail:
sp->init_sp_name(thd, $3);
lex->stmt_definition_begin= $2;
lex->ident.str= $7;
- lex->ident.length= $10 - $7;
+ lex->ident.length= $11 - $7;
sp->m_type= TYPE_ENUM_TRIGGER;
lex->sphead= sp;
@@ -11478,12 +11491,10 @@ trigger_tail:
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
lex->sphead->m_chistics= &lex->sp_chistics;
- lex->sphead->m_body_begin= lip->ptr;
- while (my_isspace(system_charset_info, lex->sphead->m_body_begin[0]))
- ++lex->sphead->m_body_begin;
+ lex->sphead->set_body_begin_ptr(lip, lip->get_cpp_ptr());
}
- sp_proc_stmt
- {
+ sp_proc_stmt /* $16 */
+ { /* $17 */
LEX *lex= Lex;
sp_head *sp= lex->sphead;
@@ -11491,7 +11502,7 @@ trigger_tail:
sp->init_strings(YYTHD, lex);
/* Restore flag if it was cleared above */
- YYTHD->client_capabilities |= $<ulong_num>13;
+ YYTHD->client_capabilities |= $<ulong_num>15;
sp->restore_thd_mem_root(YYTHD);
if (sp->is_not_allowed_in_function("trigger"))
@@ -11502,7 +11513,7 @@ trigger_tail:
sp_proc_stmt alternatives are not saving/restoring LEX, so
lex->query_tables can be wiped out.
*/
- if (!lex->select_lex.add_table_to_list(YYTHD, $8,
+ if (!lex->select_lex.add_table_to_list(YYTHD, $9,
(LEX_STRING*) 0,
TL_OPTION_UPDATING,
TL_IGNORE))
@@ -11560,8 +11571,11 @@ sp_tail:
THD *thd= YYTHD;
LEX *lex= thd->lex;
Lex_input_stream *lip= thd->m_lip;
+ const char* tmp_param_begin;
- lex->sphead->m_param_begin= lip->tok_start+1;
+ tmp_param_begin= lip->get_cpp_tok_start();
+ tmp_param_begin++;
+ lex->sphead->m_param_begin= tmp_param_begin;
}
sp_pdparam_list
')'
@@ -11570,7 +11584,7 @@ sp_tail:
LEX *lex= thd->lex;
Lex_input_stream *lip= thd->m_lip;
- lex->sphead->m_param_end= lip->tok_start;
+ lex->sphead->m_param_end= lip->get_cpp_tok_start();
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
}
sp_c_chistics
@@ -11580,7 +11594,7 @@ sp_tail:
Lex_input_stream *lip= thd->m_lip;
lex->sphead->m_chistics= &lex->sp_chistics;
- lex->sphead->m_body_begin= lip->tok_start;
+ lex->sphead->set_body_begin_ptr(lip, lip->get_cpp_tok_start());
}
sp_proc_stmt
{
diff --git a/sql/unireg.cc b/sql/unireg.cc
index a02d24d8ae5..57847bc70c6 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -29,21 +29,21 @@
#define FCOMP 17 /* Bytes for a packed field */
-static uchar * pack_screens(List<create_field> &create_fields,
+static uchar * pack_screens(List<Create_field> &create_fields,
uint *info_length, uint *screens, bool small_file);
static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info,
ulong data_offset);
static bool pack_header(uchar *forminfo,enum legacy_db_type table_type,
- List<create_field> &create_fields,
+ List<Create_field> &create_fields,
uint info_length, uint screens, uint table_options,
ulong data_offset, handler *file);
-static uint get_interval_id(uint *int_count,List<create_field> &create_fields,
- create_field *last_field);
-static bool pack_fields(File file, List<create_field> &create_fields,
+static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
+ Create_field *last_field);
+static bool pack_fields(File file, List<Create_field> &create_fields,
ulong data_offset);
static bool make_empty_rec(THD *thd, int file, enum legacy_db_type table_type,
uint table_options,
- List<create_field> &create_fields,
+ List<Create_field> &create_fields,
uint reclength, ulong data_offset,
handler *handler);
@@ -70,7 +70,7 @@ static bool make_empty_rec(THD *thd, int file, enum legacy_db_type table_type,
bool mysql_create_frm(THD *thd, const char *file_name,
const char *db, const char *table,
HA_CREATE_INFO *create_info,
- List<create_field> &create_fields,
+ List<Create_field> &create_fields,
uint keys, KEY *key_info,
handler *db_file)
{
@@ -294,8 +294,8 @@ bool mysql_create_frm(THD *thd, const char *file_name,
Restore all UCS2 intervals.
HEX representation of them is not needed anymore.
*/
- List_iterator<create_field> it(create_fields);
- create_field *field;
+ List_iterator<Create_field> it(create_fields);
+ Create_field *field;
while ((field=it++))
{
if (field->save_interval)
@@ -341,7 +341,7 @@ err3:
int rea_create_table(THD *thd, const char *path,
const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
- List<create_field> &create_fields,
+ List<Create_field> &create_fields,
uint keys, KEY *key_info, handler *file)
{
DBUG_ENTER("rea_create_table");
@@ -371,7 +371,7 @@ err_handler:
/* Pack screens to a screen for save in a form-file */
-static uchar *pack_screens(List<create_field> &create_fields,
+static uchar *pack_screens(List<Create_field> &create_fields,
uint *info_length, uint *screens,
bool small_file)
{
@@ -380,7 +380,7 @@ static uchar *pack_screens(List<create_field> &create_fields,
uint length,cols;
uchar *info,*pos,*start_screen;
uint fields=create_fields.elements;
- List_iterator<create_field> it(create_fields);
+ List_iterator<Create_field> it(create_fields);
DBUG_ENTER("pack_screens");
start_row=4; end_row=22; cols=80; fields_on_screen=end_row+1-start_row;
@@ -388,7 +388,7 @@ static uchar *pack_screens(List<create_field> &create_fields,
*screens=(fields-1)/fields_on_screen+1;
length= (*screens) * (SC_INFO_LENGTH+ (cols>> 1)+4);
- create_field *field;
+ Create_field *field;
while ((field=it++))
length+=(uint) strlen(field->field_name)+1+TE_INFO_LENGTH+cols/2;
@@ -401,7 +401,7 @@ static uchar *pack_screens(List<create_field> &create_fields,
it.rewind();
for (i=0 ; i < fields ; i++)
{
- create_field *cfield=it++;
+ Create_field *cfield=it++;
if (row++ == end_row)
{
if (i)
@@ -521,7 +521,7 @@ static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
/* Make formheader */
static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
- List<create_field> &create_fields,
+ List<Create_field> &create_fields,
uint info_length, uint screens, uint table_options,
ulong data_offset, handler *file)
{
@@ -544,8 +544,8 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
/* Check fields */
- List_iterator<create_field> it(create_fields);
- create_field *field;
+ List_iterator<Create_field> it(create_fields);
+ Create_field *field;
while ((field=it++))
{
uint tmp_len= system_charset_info->cset->charpos(system_charset_info,
@@ -687,11 +687,11 @@ static bool pack_header(uchar *forminfo, enum legacy_db_type table_type,
/* get each unique interval each own id */
-static uint get_interval_id(uint *int_count,List<create_field> &create_fields,
- create_field *last_field)
+static uint get_interval_id(uint *int_count,List<Create_field> &create_fields,
+ Create_field *last_field)
{
- List_iterator<create_field> it(create_fields);
- create_field *field;
+ List_iterator<Create_field> it(create_fields);
+ Create_field *field;
TYPELIB *interval=last_field->interval;
while ((field=it++) != last_field)
@@ -715,18 +715,18 @@ static uint get_interval_id(uint *int_count,List<create_field> &create_fields,
/* Save fields, fieldnames and intervals */
-static bool pack_fields(File file, List<create_field> &create_fields,
+static bool pack_fields(File file, List<Create_field> &create_fields,
ulong data_offset)
{
reg2 uint i;
uint int_count, comment_length=0;
uchar buff[MAX_FIELD_WIDTH];
- create_field *field;
+ Create_field *field;
DBUG_ENTER("pack_fields");
/* Write field info */
- List_iterator<create_field> it(create_fields);
+ List_iterator<Create_field> it(create_fields);
int_count=0;
while ((field=it++))
@@ -856,7 +856,7 @@ static bool pack_fields(File file, List<create_field> &create_fields,
static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
uint table_options,
- List<create_field> &create_fields,
+ List<Create_field> &create_fields,
uint reclength,
ulong data_offset,
handler *handler)
@@ -867,7 +867,7 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
uchar *buff,*null_pos;
TABLE table;
TABLE_SHARE share;
- create_field *field;
+ Create_field *field;
enum_check_fields old_count_cuted_fields= thd->count_cuted_fields;
DBUG_ENTER("make_empty_rec");
@@ -893,7 +893,7 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type,
}
null_pos= buff;
- List_iterator<create_field> it(create_fields);
+ List_iterator<Create_field> it(create_fields);
thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong default values
while ((field=it++))
{
diff --git a/sql/unireg.h b/sql/unireg.h
index d67fa372083..5b73c6e9caa 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -74,6 +74,7 @@
#define MAX_TIME_WIDTH 23 /* -DDDDDD HH:MM:SS.###### */
#define MAX_DATETIME_FULL_WIDTH 29 /* YYYY-MM-DD HH:MM:SS.###### AM */
#define MAX_DATETIME_WIDTH 19 /* YYYY-MM-DD HH:MM:SS */
+#define MAX_DATETIME_COMPRESSED_WIDTH 14 /* YYYYMMDDHHMMSS */
#define MAX_TABLES (sizeof(table_map)*8-3) /* Max tables in join */
#define PARAM_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-3))
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 3f0cb1bf4fe..eefaa6ce071 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -16079,7 +16079,7 @@ static void test_bug24179()
Bug#28075 "COM_DEBUG crashes mysqld"
Note: Test disabled because of failure in PushBuild.
*/
-#ifdef fix_bug_in_pb_first
+
static void test_bug28075()
{
int rc;
@@ -16089,18 +16089,18 @@ static void test_bug28075()
rc= mysql_dump_debug_info(mysql);
DIE_UNLESS(rc == 0);
-
+
rc= mysql_ping(mysql);
DIE_UNLESS(rc == 0);
DBUG_VOID_RETURN;
}
-#endif
/*
Bug#27876 (SF with cyrillic variable name fails during execution (regression))
*/
+
static void test_bug27876()
{
int rc;
@@ -16165,6 +16165,7 @@ static void test_bug27876()
Bug#28505: mysql_affected_rows() returns wrong value if CLIENT_FOUND_ROWS
flag is set.
*/
+
static void test_bug28505()
{
my_ulonglong res;
@@ -16218,6 +16219,59 @@ static void test_bug28934()
/*
+ Bug#27592 (stack overrun when storing datetime value using prepared statements)
+*/
+
+static void test_bug27592()
+{
+ const int NUM_ITERATIONS= 40;
+ int i;
+ int rc;
+ MYSQL_STMT *stmt= NULL;
+ MYSQL_BIND bind[1];
+ MYSQL_TIME time_val;
+
+ DBUG_ENTER("test_bug27592");
+ myheader("test_bug27592");
+
+ mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+ mysql_query(mysql, "CREATE TABLE t1(c2 DATETIME)");
+
+ stmt= mysql_simple_prepare(mysql, "INSERT INTO t1 VALUES (?)");
+ DIE_UNLESS(stmt);
+
+ memset(bind, 0, sizeof(bind));
+
+ bind[0].buffer_type= MYSQL_TYPE_DATETIME;
+ bind[0].buffer= (char *) &time_val;
+ bind[0].length= NULL;
+
+ for (i= 0; i < NUM_ITERATIONS; i++)
+ {
+ time_val.year= 2007;
+ time_val.month= 6;
+ time_val.day= 7;
+ time_val.hour= 18;
+ time_val.minute= 41;
+ time_val.second= 3;
+
+ time_val.second_part=0;
+ time_val.neg=0;
+
+ rc= mysql_stmt_bind_param(stmt, bind);
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ }
+
+ mysql_stmt_close(stmt);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -16498,15 +16552,14 @@ static struct my_tests_st my_tests[]= {
{ "test_bug15518", test_bug15518 },
{ "test_bug23383", test_bug23383 },
{ "test_bug21635", test_bug21635 },
- { "test_bug28505", test_bug28505 },
{ "test_status", test_status },
{ "test_bug24179", test_bug24179 },
{ "test_ps_query_cache", test_ps_query_cache },
-#ifdef fix_bug_in_pb_first
{ "test_bug28075", test_bug28075 },
-#endif
- { "test_bug28934", test_bug28934 },
{ "test_bug27876", test_bug27876 },
+ { "test_bug28505", test_bug28505 },
+ { "test_bug28934", test_bug28934 },
+ { "test_bug27592", test_bug27592 },
{ 0, 0 }
};