From 03e7620d3f80bbeda3f409801d3af3676abe8ec7 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Mon, 28 Feb 2005 16:20:02 +0200 Subject: [PATCH 1/3] Fix for BUG#8532. The problem was in that the code that analyses the applicability of the QUICK_GROUP_MIN_MAX access method for DISTINC queries assumed that there are no duplicate column references in the DISTINCT clause, and it added non-exiting key parts for the duplicate column references. The solution adds a test to check whether the select list already contained a field with the same name. If such field was already present, then it was already decided to use its key part for index access. In this such case we must skip the duplicate field instead of counting it as a new field. --- mysql-test/r/group_min_max.result | 38 +++++++++++++++++++++++++++++++ mysql-test/t/group_min_max.test | 6 ++++- sql/opt_range.cc | 11 ++++++++- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index c7be93b0fd7..766e43b2299 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -1657,6 +1657,44 @@ a b c d +select distinct a1,a1 from t1; +a1 a1 +a a +b b +c c +d d +select distinct a2,a1,a2,a1 from t1; +a2 a1 a2 a1 +a a a a +b a b a +a b a b +b b b b +a c a c +b c b c +a d a d +b d b d +select distinct t1.a1,t2.a1 from t1,t2; +a1 a1 +a a +b a +c a +d a +a b +b b +c b +d b +a c +b c +c c +d c +a d +b d +c d +d d +a e +b e +c e +d e explain select distinct a1,a2,b from t1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using index for group-by diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index b42125566d5..d85b3395853 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -475,11 +475,15 @@ select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121 select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); select distinct b from t2 where (a2 >= 'b') and (b = 'a'); --- BUG 6303 +-- BUG #6303 select distinct t_00.a1 from t1 t_00 where exists ( select * from t2 where a1 = t_00.a1 ); +-- BUG #8532 - SELECT DISTINCT a, a causes server to crash +select distinct a1,a1 from t1; +select distinct a2,a1,a2,a1 from t1; +select distinct t1.a1,t2.a1 from t1,t2; -- -- DISTINCT queries with GROUP-BY diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 12e5c60312b..812d5a41cbc 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -6878,6 +6878,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) SEL_ARG *cur_index_tree= NULL; ha_rows cur_quick_prefix_records= 0; uint cur_param_idx; + key_map cur_used_key_parts; for (uint cur_index= 0 ; cur_index_info != cur_index_info_end ; cur_index_info++, cur_index++) @@ -6925,17 +6926,25 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) else if (join->select_distinct) { select_items_it.rewind(); + cur_used_key_parts.clear_all(); while ((item= select_items_it++)) { item_field= (Item_field*) item; /* (SA5) already checked above. */ /* Find the order of the key part in the index. */ key_part_nr= get_field_keypart(cur_index_info, item_field->field); + /* + Check if this attribute was already present in the select list. + If it was present, then its corresponding key part was alredy used. + */ + if (cur_used_key_parts.is_set(key_part_nr)) + continue; if (key_part_nr < 1 || key_part_nr > join->fields_list.elements) goto next_index; cur_part= cur_index_info->key_part + key_part_nr - 1; cur_group_prefix_len+= cur_part->store_length; + cur_used_key_parts.set_bit(key_part_nr); + ++cur_group_key_parts; } - cur_group_key_parts= join->fields_list.elements; } else DBUG_ASSERT(FALSE); From 07a87c9887740f2e59944ff017357b00a5cc1919 Mon Sep 17 00:00:00 2001 From: "pem@mysql.comhem.se" <> Date: Mon, 28 Feb 2005 16:34:02 +0100 Subject: [PATCH 2/3] Fixed BUG#7646: Stored procedure hang if show binlog events Return false from show_binlog_events() if successful, otherwise stored procedures will think it failed. --- sql/sql_repl.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 3b4e822a3df..80c7dba8f13 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -1274,6 +1274,7 @@ bool mysql_show_binlog_events(THD* thd) DBUG_ENTER("show_binlog_events"); List field_list; const char *errmsg = 0; + bool ret = TRUE; IO_CACHE log; File file = -1; Format_description_log_event *description_event= new @@ -1376,6 +1377,8 @@ bool mysql_show_binlog_events(THD* thd) pthread_mutex_unlock(log_lock); } + ret= FALSE; + err: delete description_event; if (file >= 0) @@ -1395,7 +1398,7 @@ err: pthread_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; pthread_mutex_unlock(&LOCK_thread_count); - DBUG_RETURN(TRUE); + DBUG_RETURN(ret); } From 54a2448bce10cbe222e3d17957a67cf9658d15c7 Mon Sep 17 00:00:00 2001 From: "pem@mysql.comhem.se" <> Date: Mon, 28 Feb 2005 18:07:06 +0100 Subject: [PATCH 3/3] Fixed BUG#8760: Stored Procedures: Invalid SQLSTATE is allowed in a DECLARE ? HANDLER FOR stmt. --- mysql-test/r/sp-error.result | 28 ++++++++++++++++++++++++++ mysql-test/t/sp-error.test | 38 ++++++++++++++++++++++++++++++++++++ sql/share/errmsg.txt | 2 ++ sql/sp_pcontext.cc | 24 +++++++++++++++++++++++ sql/sp_pcontext.h | 6 ++++++ sql/sql_yacc.yy | 12 +++++++----- 6 files changed, 105 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 1c2f4662ef1..1182c3d3569 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -466,4 +466,32 @@ ERROR 70100: Query execution was interrupted call bug6807()| ERROR 70100: Query execution was interrupted drop procedure bug6807| +drop procedure if exists bug8776_1| +drop procedure if exists bug8776_2| +drop procedure if exists bug8776_3| +drop procedure if exists bug8776_4| +create procedure bug8776_1() +begin +declare continue handler for sqlstate '42S0200test' begin end; +begin end; +end| +ERROR 42000: Bad SQLSTATE: '42S0200test' +create procedure bug8776_2() +begin +declare continue handler for sqlstate '4200' begin end; +begin end; +end| +ERROR 42000: Bad SQLSTATE: '4200' +create procedure bug8776_3() +begin +declare continue handler for sqlstate '420000' begin end; +begin end; +end| +ERROR 42000: Bad SQLSTATE: '420000' +create procedure bug8776_4() +begin +declare continue handler for sqlstate '42x00' begin end; +begin end; +end| +ERROR 42000: Bad SQLSTATE: '42x00' drop table t1| diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 594daf66fcb..0f775958d7a 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -641,6 +641,44 @@ call bug6807()| drop procedure bug6807| +# +# BUG#876: Stored Procedures: Invalid SQLSTATE is allowed in +# a DECLARE ? HANDLER FOR stmt. +# +--disable_warnings +drop procedure if exists bug8776_1| +drop procedure if exists bug8776_2| +drop procedure if exists bug8776_3| +drop procedure if exists bug8776_4| +--enable_warnings +--error ER_SP_BAD_SQLSTATE +create procedure bug8776_1() +begin + declare continue handler for sqlstate '42S0200test' begin end; + begin end; +end| + +--error ER_SP_BAD_SQLSTATE +create procedure bug8776_2() +begin + declare continue handler for sqlstate '4200' begin end; + begin end; +end| + +--error ER_SP_BAD_SQLSTATE +create procedure bug8776_3() +begin + declare continue handler for sqlstate '420000' begin end; + begin end; +end| + +--error ER_SP_BAD_SQLSTATE +create procedure bug8776_4() +begin + declare continue handler for sqlstate '42x00' begin end; + begin end; +end| + drop table t1| diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 5757510bfb4..ba4ef70486b 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5326,3 +5326,5 @@ ER_PROC_AUTO_REVOKE_FAIL eng "Failed to revoke all privileges to dropped routine" ER_DATA_TOO_LONG 22001 eng "Data too long for column '%s' at row %ld" +ER_SP_BAD_SQLSTATE 42000 + eng "Bad SQLSTATE: '%s'" diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index 7176498f276..15d3f87ff29 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -26,6 +26,30 @@ #include "sp_pcontext.h" #include "sp_head.h" +/* + * Sanity check for SQLSTATEs. Will not check if it's really an existing + * state (there are just too many), but will check length and bad characters. + * Returns TRUE if it's ok, FALSE if it's bad. + */ +bool +sp_cond_check(LEX_STRING *sqlstate) +{ + int i; + const char *p; + + if (sqlstate->length != 5) + return FALSE; + for (p= sqlstate->str, i= 0 ; i < 5 ; i++) + { + char c = p[i]; + + if ((c < '0' || '9' < c) && + (c < 'A' || 'Z' < c)) + return FALSE; + } + return TRUE; +} + sp_pcontext::sp_pcontext(sp_pcontext *prev) : Sql_alloc(), m_psubsize(0), m_csubsize(0), m_hsubsize(0), m_handlers(0), m_parent(prev) diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index 66f631f4938..42d8140b78c 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -60,6 +60,12 @@ typedef struct sp_cond_type uint mysqlerr; } sp_cond_type_t; +/* Sanity check for SQLSTATEs. Will not check if it's really an existing + * state (there are just too many), but will check length bad characters. + */ +extern bool +sp_cond_check(LEX_STRING *sqlstate); + typedef struct sp_cond { LEX_STRING name; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 45c3e94f0ff..a69b6a96982 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1760,13 +1760,15 @@ sp_cond: } | SQLSTATE_SYM opt_value TEXT_STRING_literal { /* SQLSTATE */ - uint len= ($3.length < sizeof($$->sqlstate)-1 ? - $3.length : sizeof($$->sqlstate)-1); - + if (!sp_cond_check(&$3)) + { + my_error(ER_SP_BAD_SQLSTATE, MYF(0), $3.str); + YYABORT; + } $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t)); $$->type= sp_cond_type_t::state; - memcpy($$->sqlstate, $3.str, len); - $$->sqlstate[len]= '\0'; + memcpy($$->sqlstate, $3.str, 5); + $$->sqlstate[5]= '\0'; } ;