From: Joerg Bruehe Date: July 25 2008 10:59am Subject: bzr push into mysql-5.0 branch (joerg:2646) List-Archive: http://lists.mysql.com/commits/50492 Message-Id: <20080725105922.D2B6B7AC57@trift2.fambruehe> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 2646 Kristofer Pettersson 2008-07-22 [merge] merge 5.0->5.0-bugteam modified: configure.in include/my_sys.h mysys/default.c mysys/mf_pack.c scripts/make_binary_distribution.sh === modified file 'client/mysql.cc' --- a/client/mysql.cc 2008-06-24 16:05:56 +0000 +++ b/client/mysql.cc 2008-07-18 10:24:59 +0000 @@ -2081,6 +2081,37 @@ static bool add_line(String &buffer,char continue; } } + else if (!*ml_comment && !*in_string && + (end_of_line - pos) >= 10 && + !my_strnncoll(charset_info, (uchar*) pos, 10, + (const uchar*) "delimiter ", 10)) + { + // Flush previously accepted characters + if (out != line) + { + buffer.append(line, (uint32) (out - line)); + out= line; + } + + // Flush possible comments in the buffer + if (!buffer.is_empty()) + { + if (com_go(&buffer, 0) > 0) // < 0 is not fatal + DBUG_RETURN(1); + buffer.length(0); + } + + /* + Delimiter wants the get rest of the given line as argument to + allow one to change ';' to ';;' and back + */ + buffer.append(pos); + if (com_delimiter(&buffer, pos) > 0) + DBUG_RETURN(1); + + buffer.length(0); + break; + } else if (!*ml_comment && !*in_string && is_prefix(pos, delimiter)) { // Found a statement. Continue parsing after the delimiter === modified file 'mysql-test/r/client_xml.result' --- a/mysql-test/r/client_xml.result 2007-04-09 12:53:10 +0000 +++ b/mysql-test/r/client_xml.result 2008-07-18 09:07:16 +0000 @@ -1,3 +1,4 @@ +drop table if exists t1; create table t1 ( `a&b` int, `a 0) THEN +IF ( t_done > 0) THEN +IF (t_done = 'a') THEN +SET t_done = 'a'; +ELSEIF (t_done = 'a') THEN +SET t_done = 'a'; +ELSEIF(t_done = 'a') THEN +SET t_done = 'a'; +ELSEIF(t_done = 'a') THEN +SET t_done = 'a'; +ELSEIF(t_done = 'a') THEN +SET t_done = 'a'; +ELSEIF(t_done = 'a') THEN +SET t_done = 'a'; +ELSEIF(t_done = 'a') THEN +SET t_done = 'a'; +ELSEIF(t_done = 'a') THEN +SET t_done = 'a'; +END IF; +END IF; +END IF; +END IF; +END LOOP inner_loop; +END inner_block; +END LOOP outer_loop; +END $$ +drop procedure proc_35577; +drop procedure if exists p_37269; +create procedure p_37269() +begin +declare done int default 0; +declare varb int default 0; +declare vara int default 0; +repeat +select now(); +until done end repeat; +while varb do +select now(); +begin +select now(); +repeat +select now(); +until done end repeat; +if vara then +select now(); +repeat +select now(); +loop +select now(); +end loop; +repeat +select now(); +label1: while varb do +select now(); +end while label1; +if vara then +select now(); +repeat +select now(); +until done end repeat; +begin +select now(); +while varb do +select now(); +label1: while varb do +select now(); +end while label1; +if vara then +select now(); +while varb do +select now(); +loop +select now(); +end loop; +repeat +select now(); +loop +select now(); +while varb do +select now(); +end while; +repeat +select now(); +label1: loop +select now(); +if vara then +select now(); +end if; +end loop label1; +until done end repeat; +end loop; +until done end repeat; +end while; +end if; +end while; +end; +end if; +until done end repeat; +until done end repeat; +end if; +end; +end while; +end $$ +drop procedure p_37269; +drop procedure if exists p_37228; +create procedure p_37228 () +BEGIN +DECLARE v INT DEFAULT 123; +IF (v > 1) THEN SET v = 1; +ELSEIF (v < 10) THEN SET v = 10; +ELSEIF (v < 11) THEN SET v = 11; +ELSEIF (v < 12) THEN SET v = 12; +ELSEIF (v < 13) THEN SET v = 13; +ELSEIF (v < 14) THEN SET v = 14; +ELSEIF (v < 15) THEN SET v = 15; +ELSEIF (v < 16) THEN SET v = 16; +ELSEIF (v < 17) THEN SET v = 17; +ELSEIF (v < 18) THEN SET v = 18; +ELSEIF (v < 19) THEN SET v = 19; +ELSEIF (v < 20) THEN SET v = 20; +ELSEIF (v < 21) THEN SET v = 21; +ELSEIF (v < 22) THEN SET v = 22; +ELSEIF (v < 23) THEN SET v = 23; +ELSEIF (v < 24) THEN SET v = 24; +ELSEIF (v < 25) THEN SET v = 25; +ELSEIF (v < 26) THEN SET v = 26; +ELSEIF (v < 27) THEN SET v = 27; +ELSEIF (v < 28) THEN SET v = 28; +ELSEIF (v < 29) THEN SET v = 29; +ELSEIF (v < 30) THEN SET v = 30; +ELSEIF (v < 31) THEN SET v = 31; +ELSEIF (v < 32) THEN SET v = 32; +ELSEIF (v < 33) THEN SET v = 33; +ELSEIF (v < 34) THEN SET v = 34; +ELSEIF (v < 35) THEN SET v = 35; +ELSEIF (v < 36) THEN SET v = 36; +ELSEIF (v < 37) THEN SET v = 37; +ELSEIF (v < 38) THEN SET v = 38; +ELSEIF (v < 39) THEN SET v = 39; +END IF; +END $$ +drop procedure p_37228; === modified file 'mysql-test/t/client_xml.test' --- a/mysql-test/t/client_xml.test 2007-04-09 12:53:10 +0000 +++ b/mysql-test/t/client_xml.test 2008-07-18 09:07:16 +0000 @@ -1,6 +1,10 @@ # Can't run with embedded server -- source include/not_embedded.inc +--disable_warnings +drop table if exists t1; +--enable_warnings + # Test of the xml output of the 'mysql' and 'mysqldump' clients -- makes # sure that basic encoding issues are handled properly create table t1 ( === modified file 'mysql-test/t/mysql_delimiter.sql' --- a/mysql-test/t/mysql_delimiter.sql 2008-06-24 16:03:17 +0000 +++ b/mysql-test/t/mysql_delimiter.sql 2008-07-18 10:24:59 +0000 @@ -61,12 +61,6 @@ show tables// delimiter ; # Reset delimiter # -# Bug #33812: mysql client incorrectly parsing DELIMITER -# -select a as delimiter from t1 -delimiter ; # Reset delimiter - -# # Bug #36244: MySQL CLI doesn't recognize standalone -- as comment # before DELIMITER statement # === added file 'mysql-test/t/parser_stack.test' --- a/mysql-test/t/parser_stack.test 1970-01-01 00:00:00 +0000 +++ b/mysql-test/t/parser_stack.test 2008-07-14 21:41:30 +0000 @@ -0,0 +1,402 @@ +# Copyright (C) 2008 Sun Microsystems, Inc +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +# +# These tests are designed to cause an internal parser stack overflow, +# and trigger my_yyoverflow(). +# + +use test; + +SELECT +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +1 +)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +; + +prepare stmt from +" +SELECT +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +1 +)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +" +; + +execute stmt; + +--disable_warnings +drop view if exists view_overflow; +--enable_warnings + +CREATE VIEW view_overflow AS +SELECT +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( +1 +)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) +; + +SELECT * from view_overflow; + +drop view view_overflow; + +--disable_warnings +drop procedure if exists proc_overflow; +--enable_warnings + +delimiter $$; + +CREATE PROCEDURE proc_overflow() +BEGIN + + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + + select 1; + select 2; + select 3; + + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + +END $$ + +delimiter ;$$ + +call proc_overflow(); + +drop procedure proc_overflow; + +--disable_warnings +drop function if exists func_overflow; +--enable_warnings + +delimiter $$; + +create function func_overflow() returns int +BEGIN + DECLARE x int default 0; + + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + + SET x=x+1; + SET x=x+2; + SET x=x+3; + + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + + return x; +END $$ + +delimiter ;$$ + +select func_overflow(); + +drop function func_overflow; + +--disable_warnings +drop table if exists table_overflow; +--enable_warnings + +create table table_overflow(a int, b int); + +delimiter $$; + +create trigger trigger_overflow before insert on table_overflow +for each row +BEGIN + + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN BEGIN + + SET NEW.b := NEW.a; + SET NEW.b := NEW.b + 1; + SET NEW.b := NEW.b + 2; + SET NEW.b := NEW.b + 3; + + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + END; END; END; END; END; END; END; END; END; END; END; END; + +END $$ + +delimiter ;$$ + +insert into table_overflow set a=10; +insert into table_overflow set a=20; +select * from table_overflow; + +drop table table_overflow; + +--disable_warnings +drop procedure if exists proc_35577; +--enable_warnings + +delimiter $$; + +CREATE PROCEDURE proc_35577() +BEGIN + DECLARE z_done INT DEFAULT 0; + DECLARE t_done VARCHAR(5000); + outer_loop: LOOP + IF t_done=1 THEN + LEAVE outer_loop; + END IF; + + inner_block:BEGIN + DECLARE z_done INT DEFAULT 0; + SET z_done = 0; + inner_loop: LOOP + IF z_done=1 THEN + LEAVE inner_loop; + END IF; + IF (t_done = 'a') THEN + IF (t_done <> 0) THEN + IF ( t_done > 0) THEN + IF (t_done = 'a') THEN + SET t_done = 'a'; + ELSEIF (t_done = 'a') THEN + SET t_done = 'a'; + ELSEIF(t_done = 'a') THEN + SET t_done = 'a'; + ELSEIF(t_done = 'a') THEN + SET t_done = 'a'; + ELSEIF(t_done = 'a') THEN + SET t_done = 'a'; + ELSEIF(t_done = 'a') THEN + SET t_done = 'a'; + ELSEIF(t_done = 'a') THEN + SET t_done = 'a'; + ELSEIF(t_done = 'a') THEN + SET t_done = 'a'; + END IF; + END IF; + END IF; + END IF; + END LOOP inner_loop; + END inner_block; + END LOOP outer_loop; +END $$ + +delimiter ;$$ + +drop procedure proc_35577; + +# +# Bug#37269 (parser crash when creating stored procedure) +# + +--disable_warnings +drop procedure if exists p_37269; +--enable_warnings + +delimiter $$; + +create procedure p_37269() +begin + declare done int default 0; + declare varb int default 0; + declare vara int default 0; + + repeat + select now(); + until done end repeat; + while varb do + select now(); + begin + select now(); + repeat + select now(); + until done end repeat; + if vara then + select now(); + repeat + select now(); + loop + select now(); + end loop; + repeat + select now(); + label1: while varb do + select now(); + end while label1; + if vara then + select now(); + repeat + select now(); + until done end repeat; + begin + select now(); + while varb do + select now(); + label1: while varb do + select now(); + end while label1; + if vara then + select now(); + while varb do + select now(); + loop + select now(); + end loop; + repeat + select now(); + loop + select now(); + while varb do + select now(); + end while; + repeat + select now(); + label1: loop + select now(); + if vara then + select now(); + end if; + end loop label1; + until done end repeat; + end loop; + until done end repeat; + end while; + end if; + end while; + end; + end if; + until done end repeat; + until done end repeat; + end if; + end; + end while; +end $$ + +delimiter ;$$ + +drop procedure p_37269; + +# +# Bug#37228 (Sever crashes when creating stored procedure with more than +# 10 IF/ELSEIF) +# + +--disable_warnings +drop procedure if exists p_37228; +--enable_warnings + +delimiter $$; + +create procedure p_37228 () +BEGIN + DECLARE v INT DEFAULT 123; + + IF (v > 1) THEN SET v = 1; + ELSEIF (v < 10) THEN SET v = 10; + ELSEIF (v < 11) THEN SET v = 11; + ELSEIF (v < 12) THEN SET v = 12; + ELSEIF (v < 13) THEN SET v = 13; + ELSEIF (v < 14) THEN SET v = 14; + ELSEIF (v < 15) THEN SET v = 15; + ELSEIF (v < 16) THEN SET v = 16; + ELSEIF (v < 17) THEN SET v = 17; + ELSEIF (v < 18) THEN SET v = 18; + ELSEIF (v < 19) THEN SET v = 19; + ELSEIF (v < 20) THEN SET v = 20; + ELSEIF (v < 21) THEN SET v = 21; + ELSEIF (v < 22) THEN SET v = 22; + ELSEIF (v < 23) THEN SET v = 23; + ELSEIF (v < 24) THEN SET v = 24; + ELSEIF (v < 25) THEN SET v = 25; + ELSEIF (v < 26) THEN SET v = 26; + ELSEIF (v < 27) THEN SET v = 27; + ELSEIF (v < 28) THEN SET v = 28; + ELSEIF (v < 29) THEN SET v = 29; + ELSEIF (v < 30) THEN SET v = 30; + ELSEIF (v < 31) THEN SET v = 31; + ELSEIF (v < 32) THEN SET v = 32; + ELSEIF (v < 33) THEN SET v = 33; + ELSEIF (v < 34) THEN SET v = 34; + ELSEIF (v < 35) THEN SET v = 35; + ELSEIF (v < 36) THEN SET v = 36; + ELSEIF (v < 37) THEN SET v = 37; + ELSEIF (v < 38) THEN SET v = 38; + ELSEIF (v < 39) THEN SET v = 39; + END IF; +END $$ + +delimiter ;$$ + +drop procedure p_37228; + + === modified file 'sql/filesort.cc' --- a/sql/filesort.cc 2008-03-12 07:59:15 +0000 +++ b/sql/filesort.cc 2008-07-15 14:13:21 +0000 @@ -402,6 +402,56 @@ static byte *read_buffpek_from_file(IO_C DBUG_RETURN(tmp); } +#ifndef DBUG_OFF +/* + Print a text, SQL-like record representation into dbug trace. + + Note: this function is a work in progress: at the moment + - column read bitmap is ignored (can print garbage for unused columns) + - there is no quoting +*/ +static void dbug_print_record(TABLE *table, bool print_rowid) +{ + char buff[1024]; + Field **pfield; + String tmp(buff,sizeof(buff),&my_charset_bin); + DBUG_LOCK_FILE; + + fprintf(DBUG_FILE, "record ("); + for (pfield= table->field; *pfield ; pfield++) + fprintf(DBUG_FILE, "%s%s", (*pfield)->field_name, (pfield[1])? ", ":""); + fprintf(DBUG_FILE, ") = "); + + fprintf(DBUG_FILE, "("); + for (pfield= table->field; *pfield ; pfield++) + { + Field *field= *pfield; + + if (field->is_null()) + fwrite("NULL", sizeof(char), 4, DBUG_FILE); + + if (field->type() == MYSQL_TYPE_BIT) + (void) field->val_int_as_str(&tmp, 1); + else + field->val_str(&tmp); + + fwrite(tmp.ptr(),sizeof(char),tmp.length(),DBUG_FILE); + if (pfield[1]) + fwrite(", ", sizeof(char), 2, DBUG_FILE); + } + fprintf(DBUG_FILE, ")"); + if (print_rowid) + { + fprintf(DBUG_FILE, " rowid "); + for (uint i=0; i < table->file->ref_length; i++) + { + fprintf(DBUG_FILE, "%x", (uchar)table->file->ref[i]); + } + } + fprintf(DBUG_FILE, "\n"); + DBUG_UNLOCK_FILE; +} +#endif /* Search after sort_keys and write them into tempfile. @@ -475,25 +525,23 @@ static ha_rows find_all_keys(SORTPARAM * current_thd->variables.read_buff_size); } - READ_RECORD read_record_info; if (quick_select) { if (select->quick->reset()) DBUG_RETURN(HA_POS_ERROR); - init_read_record(&read_record_info, current_thd, select->quick->head, - select, 1, 1); } for (;;) { if (quick_select) { - if ((error= read_record_info.read_record(&read_record_info))) + if ((error= select->quick->get_next())) { error= HA_ERR_END_OF_FILE; break; } file->position(sort_form->record[0]); + DBUG_EXECUTE_IF("debug_filesort", dbug_print_record(sort_form, TRUE);); } else /* Not quick-select */ { @@ -550,15 +598,7 @@ static ha_rows find_all_keys(SORTPARAM * if (thd->net.report_error) break; } - if (quick_select) - { - /* - index_merge quick select uses table->sort when retrieving rows, so free - resoures it has allocated. - */ - end_read_record(&read_record_info); - } - else + if (!quick_select) { (void) file->extra(HA_EXTRA_NO_CACHE); /* End cacheing of records */ if (!next_pos) === modified file 'sql/ha_federated.cc' --- a/sql/ha_federated.cc 2008-03-29 07:52:16 +0000 +++ b/sql/ha_federated.cc 2008-07-17 14:33:41 +0000 @@ -405,6 +405,9 @@ static byte *federated_get_key(FEDERATED bool federated_db_init() { DBUG_ENTER("federated_db_init"); + /* the federated engine can be disabled by a command line option */ + if (have_federated_db == SHOW_OPTION_DISABLED) + DBUG_RETURN(TRUE); if (pthread_mutex_init(&federated_mutex, MY_MUTEX_INIT_FAST)) goto error; if (hash_init(&federated_open_tables, &my_charset_bin, 32, 0, 0, === modified file 'sql/log.cc' --- a/sql/log.cc 2008-03-21 14:10:15 +0000 +++ b/sql/log.cc 2008-07-24 12:28:21 +0000 @@ -1193,6 +1193,7 @@ int MYSQL_LOG::purge_logs(const char *to int error; bool exit_loop= 0; LOG_INFO log_info; + THD *thd= current_thd; DBUG_ENTER("purge_logs"); DBUG_PRINT("info",("to_log= %s",to_log)); @@ -1218,10 +1219,13 @@ int MYSQL_LOG::purge_logs(const char *to /* It's not fatal if we can't stat a log file that does not exist; If we could not stat, we won't delete. - */ - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), - log_info.log_file_name); + */ + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + } sql_print_information("Failed to execute my_stat on file '%s'", log_info.log_file_name); my_errno= 0; @@ -1231,13 +1235,24 @@ int MYSQL_LOG::purge_logs(const char *to /* Other than ENOENT are fatal */ - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, - ER_BINLOG_PURGE_FATAL_ERR, - "a problem with getting info on being purged %s; " - "consider examining correspondence " - "of your binlog index file " - "to the actual binlog files", - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with getting info on being purged %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } + else + { + sql_print_information("Failed to delete log file '%s'; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } error= LOG_INFO_FATAL; goto err; } @@ -1254,22 +1269,36 @@ int MYSQL_LOG::purge_logs(const char *to { if (my_errno == ENOENT) { - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + } sql_print_information("Failed to delete file '%s'", log_info.log_file_name); my_errno= 0; } else { - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, - ER_BINLOG_PURGE_FATAL_ERR, - "a problem with deleting %s; " - "consider examining correspondence " - "of your binlog index file " - "to the actual binlog files", - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } + else + { + sql_print_information("Failed to delete file '%s'; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } error= LOG_INFO_FATAL; goto err; } @@ -1316,7 +1345,8 @@ int MYSQL_LOG::purge_logs_before_date(ti int error; LOG_INFO log_info; MY_STAT stat_area; - + THD *thd= current_thd; + DBUG_ENTER("purge_logs_before_date"); pthread_mutex_lock(&LOCK_index); @@ -1338,12 +1368,15 @@ int MYSQL_LOG::purge_logs_before_date(ti { /* It's not fatal if we can't stat a log file that does not exist. - */ - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), - log_info.log_file_name); - sql_print_information("Failed to execute my_stat on file '%s'", - log_info.log_file_name); + */ + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + } + sql_print_information("Failed to execute my_stat on file '%s'", + log_info.log_file_name); my_errno= 0; } else @@ -1351,13 +1384,21 @@ int MYSQL_LOG::purge_logs_before_date(ti /* Other than ENOENT are fatal */ - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, - ER_BINLOG_PURGE_FATAL_ERR, - "a problem with getting info on being purged %s; " - "consider examining correspondence " - "of your binlog index file " - "to the actual binlog files", - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with getting info on being purged %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } + else + { + sql_print_information("Failed to delete log file '%s'", + log_info.log_file_name); + } error= LOG_INFO_FATAL; goto err; } @@ -1371,22 +1412,33 @@ int MYSQL_LOG::purge_logs_before_date(ti if (my_errno == ENOENT) { /* It's not fatal even if we can't delete a log file */ - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + } sql_print_information("Failed to delete file '%s'", log_info.log_file_name); my_errno= 0; } else { - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, - ER_BINLOG_PURGE_FATAL_ERR, - "a problem with deleting %s; " - "consider examining correspondence " - "of your binlog index file " - "to the actual binlog files", - log_info.log_file_name); + if (thd) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + } + else + { + sql_print_information("Failed to delete log file '%s'", + log_info.log_file_name); + } error= LOG_INFO_FATAL; goto err; } === modified file 'sql/mysql_priv.h' --- a/sql/mysql_priv.h 2008-03-28 11:31:52 +0000 +++ b/sql/mysql_priv.h 2008-07-15 14:13:21 +0000 @@ -1557,8 +1557,8 @@ ulonglong get_datetime_value(THD *thd, I int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(byte *,uint,char,char); void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, - SQL_SELECT *select, - int use_record_cache, bool print_errors); + SQL_SELECT *select, int use_record_cache, + bool print_errors, bool disable_rr_cache); void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, bool print_error, uint idx); void end_read_record(READ_RECORD *info); === modified file 'sql/opt_range.cc' --- a/sql/opt_range.cc 2008-03-28 18:02:27 +0000 +++ b/sql/opt_range.cc 2008-07-15 14:13:21 +0000 @@ -6494,7 +6494,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_ QUICK_RANGE_SELECT* cur_quick; int result; Unique *unique; - DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::prepare_unique"); + DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::read_keys_and_merge"); /* We're going to just read rowids. */ if (head->file->extra(HA_EXTRA_KEYREAD)) @@ -6565,13 +6565,17 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_ } - /* ok, all row ids are in Unique */ + /* + Ok all rowids are in the Unique now. The next call will initialize + head->sort structure so it can be used to iterate through the rowids + sequence. + */ result= unique->get(head); delete unique; doing_pk_scan= FALSE; - /* start table scan */ - init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1, 1); - /* index_merge currently doesn't support "using index" at all */ + + /* Start the rnd_pos() scan. */ + init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1 , 1, TRUE); head->file->extra(HA_EXTRA_NO_KEYREAD); DBUG_RETURN(result); @@ -6601,6 +6605,7 @@ int QUICK_INDEX_MERGE_SELECT::get_next() { result= HA_ERR_END_OF_FILE; end_read_record(&read_record); + free_io_cache(head); /* All rows from Unique have been retrieved, do a clustered PK scan */ if (pk_quick_select) { === modified file 'sql/records.cc' --- a/sql/records.cc 2007-10-17 16:08:58 +0000 +++ b/sql/records.cc 2008-07-15 14:13:21 +0000 @@ -72,11 +72,47 @@ void init_read_record_idx(READ_RECORD *i } -/* init struct for read with info->read_record */ +/* + init struct for read with info->read_record + + SYNOPSIS + init_read_record() + info OUT read structure + thd Thread handle + table Table the data [originally] comes from. + select SQL_SELECT structure. We may select->quick or + select->file as data source + use_record_cache Call file->extra_opt(HA_EXTRA_CACHE,...) + if we're going to do sequential read and some + additional conditions are satisfied. + print_error Copy this to info->print_error + disable_rr_cache Don't use rr_from_cache (used by sort-union + index-merge which produces rowid sequences that + are already ordered) + + DESCRIPTION + This function sets up reading data via one of the methods: + + rr_unpack_from_tempfile Unpack full records from sequential file + rr_unpack_from_buffer ... or from buffer + + rr_from_tempfile Read rowids from tempfile and get full records + with handler->rnd_pos() calls. + rr_from_pointers ... or get rowids from buffer + + rr_from_cache Read a bunch of rowids from file, sort them, + get records in rowid order, return, repeat. + + rr_quick Get data from QUICK_*_SELECT + + rr_sequential Sequentially scan the table using + handler->rnd_next() calls +*/ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, SQL_SELECT *select, - int use_record_cache, bool print_error) + int use_record_cache, bool print_error, + bool disable_rr_cache) { IO_CACHE *tempfile; DBUG_ENTER("init_read_record"); @@ -121,7 +157,8 @@ void init_read_record(READ_RECORD *info, it doesn't make sense to use cache - we don't read from the table and table->sort.io_cache is read sequentially */ - if (!table->sort.addon_field && + if (!disable_rr_cache && + !table->sort.addon_field && ! (specialflag & SPECIAL_SAFE_MODE) && thd->variables.read_rnd_buff_size && !(table->file->table_flags() & HA_FAST_KEY_READ) && === modified file 'sql/sp.cc' --- a/sql/sp.cc 2008-05-15 23:13:24 +0000 +++ b/sql/sp.cc 2008-07-14 21:41:30 +0000 @@ -443,11 +443,12 @@ db_load_routine(THD *thd, int type, sp_n goto end; { - Lex_input_stream lip(thd, defstr.c_ptr(), defstr.length()); - thd->m_lip= &lip; + Parser_state parser_state(thd, defstr.c_ptr(), defstr.length()); + thd->m_parser_state= &parser_state; lex_start(thd); thd->spcont= NULL; ret= MYSQLparse(thd); + thd->m_parser_state= NULL; if (ret == 0) { === modified file 'sql/sp_head.cc' --- a/sql/sp_head.cc 2008-05-15 23:13:24 +0000 +++ b/sql/sp_head.cc 2008-07-14 21:41:30 +0000 @@ -591,7 +591,7 @@ sp_head::init_strings(THD *thd, LEX *lex const char *endp; /* Used to trim the end */ /* During parsing, we must use thd->mem_root */ MEM_ROOT *root= thd->mem_root; - Lex_input_stream *lip=thd->m_lip; + Lex_input_stream *lip= & thd->m_parser_state->m_lip; if (m_param_begin && m_param_end) { === modified file 'sql/sql_acl.cc' --- a/sql/sql_acl.cc 2008-03-28 09:26:40 +0000 +++ b/sql/sql_acl.cc 2008-07-15 14:13:21 +0000 @@ -205,7 +205,8 @@ static my_bool acl_load(THD *thd, TABLE_ acl_cache->clear(1); // Clear locked hostname cache init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0); - init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0); + init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0, + FALSE); VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50)); while (!(read_record_info.read_record(&read_record_info))) { @@ -253,7 +254,7 @@ static my_bool acl_load(THD *thd, TABLE_ end_read_record(&read_record_info); freeze_size(&acl_hosts); - init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0); + init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0,FALSE); VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100)); password_length= table->field[2]->field_length / table->field[2]->charset()->mbmaxlen; @@ -426,7 +427,7 @@ static my_bool acl_load(THD *thd, TABLE_ end_read_record(&read_record_info); freeze_size(&acl_users); - init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0); + init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0,FALSE); VOID(my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100)); while (!(read_record_info.read_record(&read_record_info))) { === modified file 'sql/sql_class.cc' --- a/sql/sql_class.cc 2008-03-14 02:03:01 +0000 +++ b/sql/sql_class.cc 2008-07-14 21:41:30 +0000 @@ -177,7 +177,8 @@ THD::THD() rand_used(0), time_zone_used(0), last_insert_id_used(0), last_insert_id_used_bin_log(0), insert_id_used(0), clear_next_insert_id(0), in_lock_tables(0), bootstrap(0), - derived_tables_processing(FALSE), spcont(NULL), m_lip(NULL) + derived_tables_processing(FALSE), spcont(NULL), + m_parser_state(NULL) { ulong tmp; === modified file 'sql/sql_class.h' --- a/sql/sql_class.h 2008-02-28 14:34:08 +0000 +++ b/sql/sql_class.h 2008-07-14 21:41:30 +0000 @@ -28,7 +28,7 @@ class Slave_log_event; class Format_description_log_event; class sp_rcontext; class sp_cache; -class Lex_input_stream; +class Parser_state; enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE }; enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY, RNEXT_SAME }; @@ -1575,13 +1575,11 @@ public: } binlog_evt_union; /** - Character input stream consumed by the lexical analyser, - used during parsing. - Note that since the parser is not re-entrant, we keep only one input - stream here. This member is valid only when executing code during parsing, - and may point to invalid memory after that. + Internal parser state. + Note that since the parser is not re-entrant, we keep only one parser + state here. This member is valid only when executing code during parsing. */ - Lex_input_stream *m_lip; + Parser_state *m_parser_state; THD(); ~THD(); === modified file 'sql/sql_delete.cc' --- a/sql/sql_delete.cc 2008-03-27 11:52:55 +0000 +++ b/sql/sql_delete.cc 2008-07-15 14:13:21 +0000 @@ -214,7 +214,7 @@ bool mysql_delete(THD *thd, TABLE_LIST * DBUG_RETURN(TRUE); } if (usable_index==MAX_KEY) - init_read_record(&info,thd,table,select,1,1); + init_read_record(&info, thd, table, select, 1, 1, FALSE); else init_read_record_idx(&info, thd, table, 1, usable_index); @@ -772,7 +772,7 @@ int multi_delete::do_deletes() } READ_RECORD info; - init_read_record(&info,thd,table,NULL,0,1); + init_read_record(&info, thd, table, NULL, 0, 1, FALSE); /* Ignore any rows not found in reference tables as they may already have been deleted by foreign key handling === modified file 'sql/sql_help.cc' --- a/sql/sql_help.cc 2007-10-17 16:08:58 +0000 +++ b/sql/sql_help.cc 2008-07-15 14:13:21 +0000 @@ -181,7 +181,7 @@ int search_topics(THD *thd, TABLE *topic int count= 0; READ_RECORD read_record_info; - init_read_record(&read_record_info, thd, topics, select,1,0); + init_read_record(&read_record_info, thd, topics, select, 1, 0, FALSE); while (!read_record_info.read_record(&read_record_info)) { if (!select->cond->val_int()) // Doesn't match like @@ -221,7 +221,7 @@ int search_keyword(THD *thd, TABLE *keyw int count= 0; READ_RECORD read_record_info; - init_read_record(&read_record_info, thd, keywords, select,1,0); + init_read_record(&read_record_info, thd, keywords, select, 1, 0, FALSE); while (!read_record_info.read_record(&read_record_info) && count<2) { if (!select->cond->val_int()) // Dosn't match like @@ -346,7 +346,7 @@ int search_categories(THD *thd, TABLE *c DBUG_ENTER("search_categories"); - init_read_record(&read_record_info, thd, categories, select,1,0); + init_read_record(&read_record_info, thd, categories, select,1,0,FALSE); while (!read_record_info.read_record(&read_record_info)) { if (select && !select->cond->val_int()) @@ -380,7 +380,7 @@ void get_all_items_for_category(THD *thd DBUG_ENTER("get_all_items_for_category"); READ_RECORD read_record_info; - init_read_record(&read_record_info, thd, items, select,1,0); + init_read_record(&read_record_info, thd, items, select,1,0,FALSE); while (!read_record_info.read_record(&read_record_info)) { if (!select->cond->val_int()) === modified file 'sql/sql_lex.cc' --- a/sql/sql_lex.cc 2008-07-07 16:00:08 +0000 +++ b/sql/sql_lex.cc 2008-07-14 21:41:30 +0000 @@ -192,7 +192,6 @@ void lex_start(THD *thd) lex->select_lex.order_list.empty(); lex->select_lex.udf_list.empty(); lex->current_select= &lex->select_lex; - lex->yacc_yyss=lex->yacc_yyvs=0; lex->sql_command= lex->orig_sql_command= SQLCOM_END; lex->duplicates= DUP_ERROR; lex->ignore= 0; @@ -210,11 +209,16 @@ void lex_start(THD *thd) void lex_end(LEX *lex) { - DBUG_ENTER("lex_end"); - DBUG_PRINT("enter", ("lex: 0x%lx", (long) lex)); - x_free(lex->yacc_yyss); - x_free(lex->yacc_yyvs); - DBUG_VOID_RETURN; + /* Empty in 5.0, non empty in 5.1 */ +} + +Yacc_state::~Yacc_state() +{ + if (yacc_yyss) + { + x_free(yacc_yyss); + x_free(yacc_yyvs); + } } @@ -531,7 +535,7 @@ int MYSQLlex(void *arg, void *yythd) uint length; enum my_lex_states state; THD *thd= (THD *)yythd; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= & thd->m_parser_state->m_lip; LEX *lex= thd->lex; YYSTYPE *yylval=(YYSTYPE*) arg; CHARSET_INFO *cs= thd->charset(); @@ -1781,7 +1785,7 @@ void Query_tables_list::destroy_query_ta */ st_lex::st_lex() - :result(0), yacc_yyss(0), yacc_yyvs(0), + :result(0), sql_command(SQLCOM_END) { reset_query_tables_list(TRUE); === modified file 'sql/sql_lex.h' --- a/sql/sql_lex.h 2008-03-27 16:49:32 +0000 +++ b/sql/sql_lex.h 2008-07-14 21:41:30 +0000 @@ -1004,7 +1004,6 @@ typedef struct st_lex : public Query_tab LEX_STRING comment, ident; LEX_USER *grant_user; XID *xid; - gptr yacc_yyss,yacc_yyvs; THD *thd; CHARSET_INFO *charset, *underscore_charset; bool text_string_is_7bit; @@ -1290,6 +1289,59 @@ typedef struct st_lex : public Query_tab } } LEX; + +/** + The internal state of the syntax parser. + This object is only available during parsing, + and is private to the syntax parser implementation (sql_yacc.yy). +*/ +class Yacc_state +{ +public: + Yacc_state() + : yacc_yyss(NULL), yacc_yyvs(NULL) + {} + + ~Yacc_state(); + + /** + Bison internal state stack, yyss, when dynamically allocated using + my_yyoverflow(). + */ + gptr yacc_yyss; + + /** + Bison internal semantic value stack, yyvs, when dynamically allocated using + my_yyoverflow(). + */ + gptr yacc_yyvs; + + /* + TODO: move more attributes from the LEX structure here. + */ +}; + +/** + Internal state of the parser. + The complete state consist of: + - state data used during lexical parsing, + - state data used during syntactic parsing. +*/ +class Parser_state +{ +public: + Parser_state(THD *thd, const char* buff, unsigned int length) + : m_lip(thd, buff, length), m_yacc() + {} + + ~Parser_state() + {} + + Lex_input_stream m_lip; + Yacc_state m_yacc; +}; + + struct st_lex_local: public st_lex { static void *operator new(size_t size) throw() === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2008-07-07 16:00:08 +0000 +++ b/sql/sql_parse.cc 2008-07-14 21:41:30 +0000 @@ -5875,29 +5875,35 @@ bool check_stack_overrun(THD *thd, long bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, ulong *yystacksize) { - LEX *lex= current_thd->lex; + Yacc_state *state= & current_thd->m_parser_state->m_yacc; ulong old_info=0; + DBUG_ASSERT(state); if ((uint) *yystacksize >= MY_YACC_MAX) return 1; - if (!lex->yacc_yyvs) + if (!state->yacc_yyvs) old_info= *yystacksize; *yystacksize= set_zone((*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX); - if (!(lex->yacc_yyvs= (char*) - my_realloc((gptr) lex->yacc_yyvs, + if (!(state->yacc_yyvs= (char*) + my_realloc(state->yacc_yyvs, *yystacksize*sizeof(**yyvs), MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) || - !(lex->yacc_yyss= (char*) - my_realloc((gptr) lex->yacc_yyss, + !(state->yacc_yyss= (char*) + my_realloc(state->yacc_yyss, *yystacksize*sizeof(**yyss), MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR)))) return 1; if (old_info) - { // Copy old info from stack - memcpy(lex->yacc_yyss, (gptr) *yyss, old_info*sizeof(**yyss)); - memcpy(lex->yacc_yyvs, (gptr) *yyvs, old_info*sizeof(**yyvs)); + { + /* + Only copy the old stack on the first call to my_yyoverflow(), + when replacing a static stack (YYINITDEPTH) by a dynamic stack. + For subsequent calls, my_realloc already did preserve the old stack. + */ + memcpy(state->yacc_yyss, *yyss, old_info*sizeof(**yyss)); + memcpy(state->yacc_yyvs, *yyvs, old_info*sizeof(**yyvs)); } - *yyss=(short*) lex->yacc_yyss; - *yyvs=(YYSTYPE*) lex->yacc_yyvs; + *yyss= (short*) state->yacc_yyss; + *yyvs= (YYSTYPE*) state->yacc_yyvs; return 0; } @@ -6136,11 +6142,12 @@ void mysql_parse(THD *thd, const char *i sp_cache_flush_obsolete(&thd->sp_proc_cache); sp_cache_flush_obsolete(&thd->sp_func_cache); - Lex_input_stream lip(thd, inBuf, length); - thd->m_lip= &lip; + Parser_state parser_state(thd, inBuf, length); + thd->m_parser_state= &parser_state; int err= MYSQLparse(thd); - *found_semicolon= lip.found_semicolon; + *found_semicolon= parser_state.m_lip.found_semicolon; + thd->m_parser_state= NULL; if (!err && ! thd->is_fatal_error) { @@ -6165,8 +6172,9 @@ void mysql_parse(THD *thd, const char *i 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 (parser_state.m_lip.found_semicolon && + (thd->query_length= (ulong)(parser_state.m_lip.found_semicolon + - thd->query))) thd->query_length--; /* Actually execute the query */ if (*found_semicolon) @@ -6225,11 +6233,13 @@ bool mysql_test_parse_for_slave(THD *thd bool error= 0; DBUG_ENTER("mysql_test_parse_for_slave"); - Lex_input_stream lip(thd, inBuf, length); - thd->m_lip= &lip; + Parser_state parser_state(thd, inBuf, length); + thd->m_parser_state= &parser_state; + lex_start(thd); mysql_reset_thd_for_next_command(thd); int err= MYSQLparse((void*) thd); + thd->m_parser_state= NULL; if (!err && ! thd->is_fatal_error && all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first)) @@ -7295,7 +7305,7 @@ bool check_simple_select() if (lex->current_select != &lex->select_lex) { char command[80]; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= & thd->m_parser_state->m_lip; strmake(command, lip->yylval->symbol.str, min(lip->yylval->symbol.length, sizeof(command)-1)); my_error(ER_CANT_USE_OPTION_HERE, MYF(0), command); === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2008-03-27 11:52:55 +0000 +++ b/sql/sql_prepare.cc 2008-07-14 21:41:30 +0000 @@ -2849,12 +2849,13 @@ bool Prepared_statement::prepare(const c old_stmt_arena= thd->stmt_arena; thd->stmt_arena= this; - Lex_input_stream lip(thd, thd->query, thd->query_length); - lip.stmt_prepare_mode= TRUE; - thd->m_lip= &lip; + Parser_state parser_state(thd, thd->query, thd->query_length); + parser_state.m_lip.stmt_prepare_mode= TRUE; + thd->m_parser_state= &parser_state; lex_start(thd); lex->safe_to_cache_query= FALSE; int err= MYSQLparse((void *)thd); + thd->m_parser_state= NULL; lex->set_trg_event_type_for_tables(); error= err || thd->is_fatal_error || === modified file 'sql/sql_select.cc' --- a/sql/sql_select.cc 2008-05-16 14:05:55 +0000 +++ b/sql/sql_select.cc 2008-07-15 14:13:21 +0000 @@ -11309,7 +11309,7 @@ join_init_read_record(JOIN_TAB *tab) if (tab->select && tab->select->quick && tab->select->quick->reset()) return 1; init_read_record(&tab->read_record, tab->join->thd, tab->table, - tab->select,1,1); + tab->select,1,1, FALSE); return (*tab->read_record.read_record)(&tab->read_record); } === modified file 'sql/sql_table.cc' --- a/sql/sql_table.cc 2008-05-12 16:01:13 +0000 +++ b/sql/sql_table.cc 2008-07-15 14:13:21 +0000 @@ -4177,7 +4177,7 @@ copy_data_between_tables(TABLE *from,TAB current query id */ from->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); - init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1,1); + init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE); if (ignore) to->file->extra(HA_EXTRA_IGNORE_DUP_KEY); thd->row_count= 0; === modified file 'sql/sql_trigger.cc' --- a/sql/sql_trigger.cc 2007-09-04 22:40:27 +0000 +++ b/sql/sql_trigger.cc 2008-07-14 21:41:30 +0000 @@ -968,11 +968,13 @@ bool Table_triggers_list::check_n_load(T 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; + Parser_state parser_state(thd, trg_create_str->str, + trg_create_str->length); + thd->m_parser_state= &parser_state; lex_start(thd); thd->spcont= NULL; int err= MYSQLparse((void *)thd); + thd->m_parser_state= NULL; if (err || thd->is_fatal_error) { === modified file 'sql/sql_udf.cc' --- a/sql/sql_udf.cc 2007-11-09 10:41:50 +0000 +++ b/sql/sql_udf.cc 2008-07-15 14:13:21 +0000 @@ -176,7 +176,7 @@ void udf_init() } table= tables.table; - init_read_record(&read_record_info, new_thd, table, NULL,1,0); + init_read_record(&read_record_info, new_thd, table, NULL,1,0,FALSE); while (!(error = read_record_info.read_record(&read_record_info))) { DBUG_PRINT("info",("init udf record")); === modified file 'sql/sql_update.cc' --- a/sql/sql_update.cc 2008-05-18 09:21:25 +0000 +++ b/sql/sql_update.cc 2008-07-15 14:13:21 +0000 @@ -358,7 +358,7 @@ int mysql_update(THD *thd, Full index scan must be started with init_read_record_idx */ if (used_index == MAX_KEY || (select && select->quick)) - init_read_record(&info,thd,table,select,0,1); + init_read_record(&info, thd, table, select, 0, 1, FALSE); else init_read_record_idx(&info, thd, table, 1, used_index); @@ -422,7 +422,7 @@ int mysql_update(THD *thd, if (select && select->quick && select->quick->reset()) goto err; - init_read_record(&info,thd,table,select,0,1); + init_read_record(&info, thd, table, select, 0, 1, FALSE); updated= found= 0; thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */ === modified file 'sql/sql_view.cc' --- a/sql/sql_view.cc 2008-05-08 07:41:22 +0000 +++ b/sql/sql_view.cc 2008-07-14 21:41:30 +0000 @@ -1081,8 +1081,7 @@ bool mysql_make_view(THD *thd, File_pars char old_db_buf[NAME_LEN+1]; LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) }; bool dbchanged; - Lex_input_stream lip(thd, table->query.str, table->query.length); - thd->m_lip= &lip; + Parser_state parser_state(thd, table->query.str, table->query.length); /* Use view db name as thread default database, in order to ensure @@ -1091,6 +1090,7 @@ bool mysql_make_view(THD *thd, File_pars if ((result= sp_use_new_db(thd, table->view_db, &old_db, 1, &dbchanged))) goto end; + thd->m_parser_state= &parser_state; lex_start(thd); view_select= &lex->select_lex; view_select->select_number= ++thd->select_number; @@ -1125,6 +1125,7 @@ bool mysql_make_view(THD *thd, File_pars CHARSET_INFO *save_cs= thd->variables.character_set_client; thd->variables.character_set_client= system_charset_info; res= MYSQLparse((void *)thd); + thd->m_parser_state= NULL; if ((old_lex->sql_command == SQLCOM_SHOW_FIELDS) || (old_lex->sql_command == SQLCOM_SHOW_CREATE)) === modified file 'sql/sql_yacc.yy' --- a/sql/sql_yacc.yy 2008-07-07 16:00:08 +0000 +++ b/sql/sql_yacc.yy 2008-07-14 21:41:30 +0000 @@ -23,6 +23,7 @@ #define YYPARSE_PARAM yythd #define YYLEX_PARAM yythd #define YYTHD ((THD *)yythd) +#define YYLIP (& YYTHD->m_parser_state->m_lip) #define MYSQL_YACC #define YYINITDEPTH 100 @@ -86,7 +87,7 @@ const LEX_STRING null_lex_str={0,0}; void my_parse_error(const char *s) { THD *thd= current_thd; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= & thd->m_parser_state->m_lip; const char *yytext= lip->tok_start; /* Push an error into the error stack */ @@ -1213,11 +1214,11 @@ query: MYSQL_YYABORT; } thd->lex->sql_command= SQLCOM_EMPTY_QUERY; - thd->m_lip->found_semicolon= NULL; + YYLIP->found_semicolon= NULL; } | verb_clause { - Lex_input_stream *lip = YYTHD->m_lip; + Lex_input_stream *lip = YYLIP; if ((YYTHD->client_capabilities & CLIENT_MULTI_QUERIES) && ! lip->stmt_prepare_mode && @@ -1243,7 +1244,7 @@ query: | verb_clause END_OF_INPUT { /* Single query, not terminated. */ - YYTHD->m_lip->found_semicolon= NULL; + YYLIP->found_semicolon= NULL; } ; @@ -2155,7 +2156,7 @@ sp_proc_stmt: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; if (lex->sphead->reset_lex(thd)) MYSQL_YYABORT; @@ -2165,7 +2166,7 @@ sp_proc_stmt: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; sp_head *sp= lex->sphead; sp->m_flags|= sp_get_flags_for_command(lex); @@ -4503,16 +4504,12 @@ select_item: remember_name: { - THD *thd= YYTHD; - Lex_input_stream *lip= thd->m_lip; - $$= (char*) lip->tok_start; + $$= (char*) YYLIP->tok_start; }; remember_end: { - THD *thd= YYTHD; - Lex_input_stream *lip= thd->m_lip; - $$=(char*) lip->tok_end; + $$=(char*) YYLIP->tok_end; }; select_item2: @@ -6452,7 +6449,7 @@ procedure_item: remember_name expr { THD *thd= YYTHD; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; if (add_proc_to_list(thd, $2)) MYSQL_YYABORT; @@ -7524,7 +7521,7 @@ load: LOAD DATA_SYM { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; if (lex->sphead) { @@ -7566,10 +7563,7 @@ load_data: } opt_duplicate INTO { - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - lex->fname_end= lip->ptr; + Lex->fname_end= YYLIP->ptr; } TABLE_SYM table_ident { @@ -7787,7 +7781,7 @@ param_marker: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; Item_param *item; if (! lex->parsing_options.allows_variable) { @@ -7820,7 +7814,7 @@ literal: | NULL_SYM { $$ = new Item_null(); - YYTHD->m_lip->next_state=MY_LEX_OPERATOR_OR_IDENT; + YYLIP->next_state= MY_LEX_OPERATOR_OR_IDENT; } | FALSE_SYM { $$= new Item_int((char*) "FALSE",0,1); } | TRUE_SYM { $$= new Item_int((char*) "TRUE",1,1); } @@ -7924,7 +7918,7 @@ simple_ident: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; sp_variable_t *spv; sp_pcontext *spc = lex->spcont; if (spc && (spv = spc->find_variable(&$1))) @@ -8537,7 +8531,7 @@ option_type_value: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; if (lex->sphead) { @@ -8568,7 +8562,7 @@ option_type_value: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; if (lex->sphead) { @@ -9878,7 +9872,7 @@ trigger_tail: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; sp_head *sp; if (lex->sphead) @@ -9971,7 +9965,7 @@ sf_tail: { /* $5 */ THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; sp_head *sp; lex->stmt_definition_begin= $1; @@ -9996,11 +9990,7 @@ sf_tail: sp_fdparam_list /* $6 */ ')' /* $7 */ { /* $8 */ - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - - lex->sphead->m_param_end= lip->tok_start; + Lex->sphead->m_param_end= YYLIP->tok_start; } RETURNS_SYM /* $9 */ { /* $10 */ @@ -10026,7 +10016,7 @@ sf_tail: { /* $14 */ THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; lex->sphead->m_chistics= &lex->sp_chistics; lex->sphead->m_body_begin= lip->tok_start; @@ -10078,18 +10068,14 @@ sp_tail: } '(' { - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - - lex->sphead->m_param_begin= lip->tok_start+1; + Lex->sphead->m_param_begin= YYLIP->tok_start+1; } sp_pdparam_list ')' { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; lex->sphead->m_param_end= lip->tok_start; bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); @@ -10098,7 +10084,7 @@ sp_tail: { THD *thd= YYTHD; LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; + Lex_input_stream *lip= YYLIP; lex->sphead->m_chistics= &lex->sp_chistics; lex->sphead->m_body_begin= lip->tok_start;