diff options
Diffstat (limited to 'sql/sp.cc')
-rw-r--r-- | sql/sp.cc | 237 |
1 files changed, 216 insertions, 21 deletions
diff --git a/sql/sp.cc b/sql/sp.cc index e281285b2e0..f81e52f40ab 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -70,6 +70,122 @@ enum MYSQL_PROC_FIELD_COUNT }; +static const +TABLE_FIELD_TYPE proc_table_fields[MYSQL_PROC_FIELD_COUNT] = +{ + { + { C_STRING_WITH_LEN("db") }, + { C_STRING_WITH_LEN("char(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("name") }, + { C_STRING_WITH_LEN("char(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("type") }, + { C_STRING_WITH_LEN("enum('FUNCTION','PROCEDURE')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("specific_name") }, + { C_STRING_WITH_LEN("char(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("language") }, + { C_STRING_WITH_LEN("enum('SQL')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("sql_data_access") }, + { C_STRING_WITH_LEN("enum('CONTAINS_SQL','NO_SQL','READS_SQL_DATA','MODIFIES_SQL_DATA')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("is_deterministic") }, + { C_STRING_WITH_LEN("enum('YES','NO')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("security_type") }, + { C_STRING_WITH_LEN("enum('INVOKER','DEFINER')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("param_list") }, + { C_STRING_WITH_LEN("blob") }, + { NULL, 0 } + }, + + { + { C_STRING_WITH_LEN("returns") }, + { C_STRING_WITH_LEN("longblob") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("body") }, + { C_STRING_WITH_LEN("longblob") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("definer") }, + { C_STRING_WITH_LEN("char(77)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("created") }, + { C_STRING_WITH_LEN("timestamp") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("modified") }, + { C_STRING_WITH_LEN("timestamp") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("sql_mode") }, + { C_STRING_WITH_LEN("set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES'," + "'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION'," + "'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB'," + "'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40'," + "'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','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH')") }, + { NULL, 0 } + }, + { + { C_STRING_WITH_LEN("comment") }, + { C_STRING_WITH_LEN("char(64)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("character_set_client") }, + { C_STRING_WITH_LEN("char(32)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("collation_connection") }, + { C_STRING_WITH_LEN("char(32)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("db_collation") }, + { C_STRING_WITH_LEN("char(32)") }, + { C_STRING_WITH_LEN("utf8") } + }, + { + { C_STRING_WITH_LEN("body_utf8") }, + { C_STRING_WITH_LEN("longblob") }, + { NULL, 0 } + } +}; + +static const TABLE_FIELD_DEF + proc_table_def= {MYSQL_PROC_FIELD_COUNT, proc_table_fields}; + /*************************************************************************/ /** @@ -247,6 +363,50 @@ Stored_routine_creation_ctx::load_from_db(THD *thd, /*************************************************************************/ +class Proc_table_intact : public Table_check_intact +{ +private: + bool m_print_once; + +public: + Proc_table_intact() : m_print_once(TRUE) {} + +protected: + void report_error(uint code, const char *fmt, ...); +}; + + +/** + Report failure to validate the mysql.proc table definition. + Print a message to the error log only once. +*/ + +void Proc_table_intact::report_error(uint code, const char *fmt, ...) +{ + va_list args; + char buf[512]; + + va_start(args, fmt); + my_vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + if (code) + my_message(code, buf, MYF(0)); + else + my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "proc"); + + if (m_print_once) + { + m_print_once= FALSE; + sql_print_error("%s", buf); + } +}; + + +/** Single instance used to control printing to the error log. */ +static Proc_table_intact proc_table_intact; + + /** Open the mysql.proc table for read. @@ -266,15 +426,17 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) DBUG_ENTER("open_proc_table_for_read"); TABLE_LIST table; - bzero((char*) &table, sizeof(table)); - table.db= (char*) "mysql"; - table.table_name= table.alias= (char*)"proc"; - table.lock_type= TL_READ; + table.init_one_table("mysql", "proc", TL_READ); + + if (open_system_tables_for_read(thd, &table, backup)) + DBUG_RETURN(NULL); - if (!open_system_tables_for_read(thd, &table, backup)) + if (!proc_table_intact.check(table.table, &proc_table_def)) DBUG_RETURN(table.table); - else - DBUG_RETURN(0); + + close_system_tables(thd, backup); + + DBUG_RETURN(NULL); } @@ -296,13 +458,19 @@ static TABLE *open_proc_table_for_update(THD *thd) { DBUG_ENTER("open_proc_table_for_update"); - TABLE_LIST table; - bzero((char*) &table, sizeof(table)); - table.db= (char*) "mysql"; - table.table_name= table.alias= (char*)"proc"; - table.lock_type= TL_WRITE; + TABLE *table; + TABLE_LIST table_list; + table_list.init_one_table("mysql", "proc", TL_WRITE); + + if (!(table= open_system_table_for_update(thd, &table_list))) + DBUG_RETURN(NULL); + + if (!proc_table_intact.check(table, &proc_table_def)) + DBUG_RETURN(table); + + close_thread_tables(thd); - DBUG_RETURN(open_system_table_for_update(thd, &table)); + DBUG_RETURN(NULL); } @@ -729,10 +897,13 @@ sp_create_routine(THD *thd, int type, sp_head *sp) bool store_failed= FALSE; + bool save_binlog_row_based; + DBUG_ENTER("sp_create_routine"); DBUG_PRINT("enter", ("type: %d name: %.*s",type, (int) sp->m_name.length, sp->m_name.str)); String retstr(64); + retstr.set_charset(system_charset_info); DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE || type == TYPE_ENUM_FUNCTION); @@ -745,6 +916,7 @@ sp_create_routine(THD *thd, int type, sp_head *sp) row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->current_stmt_binlog_row_based; thd->clear_current_stmt_binlog_row_based(); saved_count_cuted_fields= thd->count_cuted_fields; @@ -937,9 +1109,10 @@ sp_create_routine(THD *thd, int type, sp_head *sp) /* restore sql_mode when binloging */ thd->variables.sql_mode= saved_mode; /* Such a statement can always go directly to binlog, no trans cache */ - thd->binlog_query(THD::MYSQL_QUERY_TYPE, - log_query.c_ptr(), log_query.length(), - FALSE, FALSE, 0); + if (thd->binlog_query(THD::MYSQL_QUERY_TYPE, + log_query.c_ptr(), log_query.length(), + FALSE, FALSE, 0)) + ret= SP_INTERNAL_ERROR; thd->variables.sql_mode= 0; } @@ -950,6 +1123,8 @@ done: thd->variables.sql_mode= saved_mode; close_thread_tables(thd); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(ret); } @@ -974,6 +1149,7 @@ sp_drop_routine(THD *thd, int type, sp_name *name) { TABLE *table; int ret; + bool save_binlog_row_based; DBUG_ENTER("sp_drop_routine"); DBUG_PRINT("enter", ("type: %d name: %.*s", type, (int) name->m_name.length, name->m_name.str)); @@ -986,6 +1162,7 @@ sp_drop_routine(THD *thd, int type, sp_name *name) row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->current_stmt_binlog_row_based; thd->clear_current_stmt_binlog_row_based(); if (!(table= open_proc_table_for_update(thd))) @@ -998,11 +1175,14 @@ sp_drop_routine(THD *thd, int type, sp_name *name) if (ret == SP_OK) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + if (write_bin_log(thd, TRUE, thd->query(), thd->query_length())) + ret= SP_INTERNAL_ERROR; sp_cache_invalidate(); } close_thread_tables(thd); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(ret); } @@ -1029,6 +1209,7 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) { TABLE *table; int ret; + bool save_binlog_row_based; DBUG_ENTER("sp_update_routine"); DBUG_PRINT("enter", ("type: %d name: %.*s", type, (int) name->m_name.length, name->m_name.str)); @@ -1040,6 +1221,7 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) row-based replication. The flag will be reset at the end of the statement. */ + save_binlog_row_based= thd->current_stmt_binlog_row_based; thd->clear_current_stmt_binlog_row_based(); if (!(table= open_proc_table_for_update(thd))) @@ -1068,11 +1250,14 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) if (ret == SP_OK) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + if (write_bin_log(thd, TRUE, thd->query(), thd->query_length())) + ret= SP_INTERNAL_ERROR; sp_cache_invalidate(); } close_thread_tables(thd); + /* Restore the state of binlog format */ + thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(ret); } @@ -1238,6 +1423,7 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, 64 -- size of "returns" column of mysql.proc. */ String retstr(64); + retstr.set_charset(sp->get_creation_ctx()->get_client_cs()); DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp)); if (sp->m_first_free_instance) @@ -1509,7 +1695,8 @@ static bool add_used_routine(LEX *lex, Query_arena *arena, rn->key.length= key->length; rn->key.str= (char *)rn + sizeof(Sroutine_hash_entry); memcpy(rn->key.str, key->str, key->length + 1); - my_hash_insert(&lex->sroutines, (uchar *)rn); + if (my_hash_insert(&lex->sroutines, (uchar *)rn)) + return FALSE; lex->sroutines_list.link_in_list((uchar *)rn, (uchar **)&rn->next); rn->belong_to_view= belong_to_view; return TRUE; @@ -1587,16 +1774,24 @@ void sp_remove_not_own_routines(LEX *lex) dependant on time of life of elements from source hash. It also won't touch lists linking elements in source and destination hashes. + + @returns + @return TRUE Failure + @return FALSE Success */ -void sp_update_sp_used_routines(HASH *dst, HASH *src) +bool sp_update_sp_used_routines(HASH *dst, HASH *src) { for (uint i=0 ; i < src->records ; i++) { Sroutine_hash_entry *rt= (Sroutine_hash_entry *)hash_element(src, i); if (!hash_search(dst, (uchar *)rt->key.str, rt->key.length)) - my_hash_insert(dst, (uchar *)rt); + { + if (my_hash_insert(dst, (uchar *)rt)) + return TRUE; + } } + return FALSE; } |