From 1b6b7010a6b1bd6e7f79632c2738d7a1654078e4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Feb 2008 08:47:39 -0200 Subject: Bug#32633 Can not create any routine if SQL_MODE=no_engine_substitution The problem is that one can not create a stored routine if sql_mode contains NO_ENGINE_SUBSTITUTION or PAD_CHAR_TO_FULL_LENGTH. Also when a event is created, the mode is silently lost if sql_mode contains one of the aforementioned. This was happening because the table definitions which stored sql_mode values weren't being updated to accept new values of sql_mode. The solution is to update, in a backwards compatible manner, the various table definitions (columns) that store the sql_mode value to take into account the new possible values. One incompatible change is that if a event that is being created can't be stored to the mysql.event table, an error will be raised. The tests case also ensure that new SQL modes will be added to the mysql.proc and mysql.event tables, otherwise the tests will fail. mysql-test/r/events_bugs.result: Add test case result for Bug#32633 mysql-test/r/information_schema.result: Update the sql_mode column definition. mysql-test/r/sp.result: Add test case result for Bug#32633 mysql-test/r/system_mysql_db.result: Update the sql_mode column definition. mysql-test/t/events_bugs.test: Add test case for Bug#32633 mysql-test/t/sp.test: Add test case for Bug#32633 mysql-test/t/system_mysql_db_fix50117.test: Update the sql_mode column definition. scripts/mysql_system_tables.sql: Update the sql_mode column definition. scripts/mysql_system_tables_fix.sql: Update the sql_mode column definition. sql/event_db_repository.cc: Reset and restore SQL modes when storing and loading a event from the data dictionary. Also throw out a error if a store fails. sql/mysqld.cc: Add warning to avoid this problem in the future. sql-common/my_user.c: Truncate length if user name or host name does not fit in the buffer. sql/sp.cc: SQL mode of the thread must not effect data dictionary operations. --- sql/event_db_repository.cc | 69 ++++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 24 deletions(-) (limited to 'sql/event_db_repository.cc') diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 9a33b33d8c9..401f76f5d26 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -111,7 +111,7 @@ const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = "'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES'," "'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES'," "'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER'," - "'HIGH_NOT_PRECEDENCE')") }, + "'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH')") }, {NULL, 0} }, { @@ -172,11 +172,13 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et, sp_head *sp, + ulong sql_mode, my_bool is_update) { CHARSET_INFO *scs= system_charset_info; enum enum_events_table_field f_num; Field **fields= table->field; + int rs= FALSE; DBUG_ENTER("mysql_event_fill_row"); @@ -205,12 +207,9 @@ mysql_event_fill_row(THD *thd, goto err_truncate; /* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/ - fields[ET_FIELD_ON_COMPLETION]->store((longlong)et->on_completion, TRUE); - - fields[ET_FIELD_STATUS]->store((longlong)et->status, TRUE); - - fields[ET_FIELD_ORIGINATOR]->store((longlong)et->originator, TRUE); - + rs|= fields[ET_FIELD_ON_COMPLETION]->store((longlong)et->on_completion, TRUE); + rs|= fields[ET_FIELD_STATUS]->store((longlong)et->status, TRUE); + rs|= fields[ET_FIELD_ORIGINATOR]->store((longlong)et->originator, TRUE); /* Change the SQL_MODE only if body was present in an ALTER EVENT and of course @@ -220,7 +219,7 @@ mysql_event_fill_row(THD *thd, { DBUG_ASSERT(sp->m_body.str); - fields[ET_FIELD_SQL_MODE]->store((longlong)thd->variables.sql_mode, TRUE); + rs|= fields[ET_FIELD_SQL_MODE]->store((longlong)sql_mode, TRUE); if (fields[f_num= ET_FIELD_BODY]->store(sp->m_body.str, sp->m_body.length, @@ -236,16 +235,16 @@ mysql_event_fill_row(THD *thd, if (!is_update || !et->starts_null) { fields[ET_FIELD_TIME_ZONE]->set_notnull(); - fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(), - tz_name->charset()); + rs|= fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(), + tz_name->charset()); } fields[ET_FIELD_INTERVAL_EXPR]->set_notnull(); - fields[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, TRUE); + rs|= fields[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, TRUE); fields[ET_FIELD_TRANSIENT_INTERVAL]->set_notnull(); - fields[ET_FIELD_TRANSIENT_INTERVAL]-> + rs|= fields[ET_FIELD_TRANSIENT_INTERVAL]-> store(interval_type_to_name[et->interval].str, interval_type_to_name[et->interval].length, scs); @@ -274,8 +273,8 @@ mysql_event_fill_row(THD *thd, { const String *tz_name= thd->variables.time_zone->get_name(); fields[ET_FIELD_TIME_ZONE]->set_notnull(); - fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(), - tz_name->charset()); + rs|= fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(), + tz_name->charset()); fields[ET_FIELD_INTERVAL_EXPR]->set_null(); fields[ET_FIELD_TRANSIENT_INTERVAL]->set_null(); @@ -308,13 +307,13 @@ mysql_event_fill_row(THD *thd, } fields[ET_FIELD_CHARACTER_SET_CLIENT]->set_notnull(); - fields[ET_FIELD_CHARACTER_SET_CLIENT]->store( + rs|= fields[ET_FIELD_CHARACTER_SET_CLIENT]->store( thd->variables.character_set_client->csname, strlen(thd->variables.character_set_client->csname), system_charset_info); fields[ET_FIELD_COLLATION_CONNECTION]->set_notnull(); - fields[ET_FIELD_COLLATION_CONNECTION]->store( + rs|= fields[ET_FIELD_COLLATION_CONNECTION]->store( thd->variables.collation_connection->name, strlen(thd->variables.collation_connection->name), system_charset_info); @@ -323,15 +322,23 @@ mysql_event_fill_row(THD *thd, CHARSET_INFO *db_cl= get_default_db_collation(thd, et->dbname.str); fields[ET_FIELD_DB_COLLATION]->set_notnull(); - fields[ET_FIELD_DB_COLLATION]->store( - db_cl->name, strlen(db_cl->name), system_charset_info); + rs|= fields[ET_FIELD_DB_COLLATION]->store(db_cl->name, + strlen(db_cl->name), + system_charset_info); } if (et->body_changed) { fields[ET_FIELD_BODY_UTF8]->set_notnull(); - fields[ET_FIELD_BODY_UTF8]->store( - sp->m_body_utf8.str, sp->m_body_utf8.length, system_charset_info); + rs|= fields[ET_FIELD_BODY_UTF8]->store(sp->m_body_utf8.str, + sp->m_body_utf8.length, + system_charset_info); + } + + if (rs) + { + my_error(ER_EVENT_STORE_FAILED, MYF(0), fields[f_num]->field_name, rs); + DBUG_RETURN(TRUE); } DBUG_RETURN(FALSE); @@ -585,12 +592,16 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data, int ret= 1; TABLE *table= NULL; sp_head *sp= thd->lex->sphead; + ulong saved_mode= thd->variables.sql_mode; DBUG_ENTER("Event_db_repository::create_event"); DBUG_PRINT("info", ("open mysql.event for update")); DBUG_ASSERT(sp); + /* Reset sql_mode during data dictionary operations. */ + thd->variables.sql_mode= 0; + if (open_event_table(thd, TL_WRITE, &table)) goto end; @@ -646,7 +657,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, sp, FALSE)) + if (mysql_event_fill_row(thd, table, parse_data, sp, saved_mode, FALSE)) goto end; table->field[ET_FIELD_STATUS]->store((longlong)parse_data->status, TRUE); @@ -661,6 +672,7 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data, end: if (table) close_thread_tables(thd); + thd->variables.sql_mode= saved_mode; DBUG_RETURN(test(ret)); } @@ -691,6 +703,7 @@ 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; + ulong saved_mode= thd->variables.sql_mode; int ret= 1; DBUG_ENTER("Event_db_repository::update_event"); @@ -698,6 +711,9 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data, /* None or both must be set */ DBUG_ASSERT(new_dbname && new_name || new_dbname == new_name); + /* Reset sql_mode during data dictionary operations. */ + thd->variables.sql_mode= 0; + if (open_event_table(thd, TL_WRITE, &table)) goto end; @@ -736,7 +752,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, sp, TRUE)) + if (mysql_event_fill_row(thd, table, parse_data, sp, saved_mode, TRUE)) goto end; if (new_dbname) @@ -755,6 +771,7 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data, end: if (table) close_thread_tables(thd); + thd->variables.sql_mode= saved_mode; DBUG_RETURN(test(ret)); } @@ -950,13 +967,17 @@ bool Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *etn) { - TABLE *table= NULL; bool ret; + TABLE *table= NULL; + ulong saved_mode= thd->variables.sql_mode; DBUG_ENTER("Event_db_repository::load_named_event"); DBUG_PRINT("enter",("thd: 0x%lx name: %*s", (long) thd, (int) name.length, name.str)); + /* Reset sql_mode during data dictionary operations. */ + thd->variables.sql_mode= 0; + if (!(ret= open_event_table(thd, TL_READ, &table))) { if ((ret= find_named_event(dbname, name, table))) @@ -967,7 +988,7 @@ Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname, close_thread_tables(thd); } - + thd->variables.sql_mode= saved_mode; DBUG_RETURN(ret); } -- cgit v1.2.1