diff options
Diffstat (limited to 'sql/sp.cc')
-rw-r--r-- | sql/sp.cc | 245 |
1 files changed, 105 insertions, 140 deletions
diff --git a/sql/sp.cc b/sql/sp.cc index 4fc9ea1f602..49b8b304e76 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -13,7 +13,6 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - #include "mysql_priv.h" #include "sp.h" #include "sp_head.h" @@ -48,7 +47,7 @@ enum { MYSQL_PROC_FIELD_DB = 0, MYSQL_PROC_FIELD_NAME, - MYSQL_PROC_FIELD_TYPE, + MYSQL_PROC_MYSQL_TYPE, MYSQL_PROC_FIELD_SPECIFIC_NAME, MYSQL_PROC_FIELD_LANGUAGE, MYSQL_PROC_FIELD_ACCESS, @@ -70,24 +69,6 @@ enum /* - Close mysql.proc, opened with open_proc_table_for_read(). - - SYNOPSIS - close_proc_table() - thd Thread context - backup Pointer to Open_tables_state instance which holds - information about tables which were open before we - decided to access mysql.proc. -*/ - -void close_proc_table(THD *thd, Open_tables_state *backup) -{ - close_thread_tables(thd); - thd->restore_backup_open_tables_state(backup); -} - - -/* Open the mysql.proc table for read. SYNOPSIS @@ -97,13 +78,6 @@ void close_proc_table(THD *thd, Open_tables_state *backup) currently open tables will be saved, and from which will be restored when we will end work with mysql.proc. - NOTES - Thanks to restrictions which we put on opening and locking of - this table for writing, we can open and lock it for reading - even when we already have some other tables open and locked. - One must call close_proc_table() to close table opened with - this call. - RETURN 0 Error # Pointer to TABLE object of mysql.proc @@ -111,37 +85,18 @@ void close_proc_table(THD *thd, Open_tables_state *backup) TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) { - TABLE_LIST tables; - TABLE *table; - bool not_used; - DBUG_ENTER("open_proc_table"); + DBUG_ENTER("open_proc_table_for_read"); - thd->reset_n_backup_open_tables_state(backup); + TABLE_LIST table; + bzero((char*) &table, sizeof(table)); + table.db= (char*) "mysql"; + table.table_name= table.alias= (char*)"proc"; + table.lock_type= TL_READ; - bzero((char*) &tables, sizeof(tables)); - tables.db= (char*) "mysql"; - tables.table_name= tables.alias= (char*)"proc"; - if (!(table= open_table(thd, &tables, thd->mem_root, ¬_used, - MYSQL_LOCK_IGNORE_FLUSH))) - { - thd->restore_backup_open_tables_state(backup); - DBUG_RETURN(0); - } - - DBUG_ASSERT(table->s->system_table); - - table->reginfo.lock_type= TL_READ; - /* - We have to ensure we are not blocked by a flush tables, as this - could lead to a deadlock if we have other tables opened. - */ - if (!(thd->lock= mysql_lock_tables(thd, &table, 1, - MYSQL_LOCK_IGNORE_FLUSH, ¬_used))) - { - close_proc_table(thd, backup); + if (!open_system_tables_for_read(thd, &table, backup)) + DBUG_RETURN(table.table); + else DBUG_RETURN(0); - } - DBUG_RETURN(table); } @@ -162,18 +117,15 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) static TABLE *open_proc_table_for_update(THD *thd) { - TABLE_LIST tables; - TABLE *table; - DBUG_ENTER("open_proc_table"); + DBUG_ENTER("open_proc_table_for_update"); - bzero((char*) &tables, sizeof(tables)); - tables.db= (char*) "mysql"; - tables.table_name= tables.alias= (char*)"proc"; - tables.lock_type= TL_WRITE; - - table= open_ltable(thd, &tables, TL_WRITE); + TABLE_LIST table; + bzero((char*) &table, sizeof(table)); + table.db= (char*) "mysql"; + table.table_name= table.alias= (char*)"proc"; + table.lock_type= TL_WRITE; - DBUG_RETURN(table); + DBUG_RETURN(open_system_table_for_update(thd, &table)); } @@ -216,8 +168,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table) key_copy(key, table->record[0], table->key_info, table->key_info->key_length); - if (table->file->index_read_idx(table->record[0], 0, - key, table->key_info->key_length, + if (table->file->index_read_idx(table->record[0], 0, key, HA_WHOLE_KEY, HA_READ_KEY_EXACT)) DBUG_RETURN(SP_KEY_NOT_FOUND); @@ -362,7 +313,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) chistics.comment.str= ptr; chistics.comment.length= length; - close_proc_table(thd, &open_tables_state_backup); + close_system_tables(thd, &open_tables_state_backup); table= 0; ret= db_load_routine(thd, type, name, sphp, @@ -371,7 +322,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) done: if (table) - close_proc_table(thd, &open_tables_state_backup); + close_system_tables(thd, &open_tables_state_backup); DBUG_RETURN(ret); } @@ -392,13 +343,12 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, sp_rcontext *old_spcont= thd->spcont; char definer_user_name_holder[USERNAME_LENGTH + 1]; - LEX_STRING_WITH_INIT definer_user_name(definer_user_name_holder, - USERNAME_LENGTH); + LEX_STRING definer_user_name= { definer_user_name_holder, + USERNAME_LENGTH }; char definer_host_name_holder[HOSTNAME_LENGTH + 1]; - LEX_STRING_WITH_INIT definer_host_name(definer_host_name_holder, - HOSTNAME_LENGTH); - + LEX_STRING definer_host_name= { definer_host_name_holder, HOSTNAME_LENGTH }; + int ret; thd->variables.sql_mode= sql_mode; @@ -434,7 +384,7 @@ 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; - lex_start(thd, (uchar*)defstr.c_ptr(), defstr.length()); + lex_start(thd, defstr.c_ptr(), defstr.length()); thd->spcont= 0; if (MYSQLparse(thd) || thd->is_fatal_error || newlex.sphead == NULL) @@ -469,10 +419,12 @@ static void sp_returns_type(THD *thd, String &result, sp_head *sp) { TABLE table; + TABLE_SHARE share; Field *field; - bzero(&table, sizeof(table)); + bzero((char*) &table, sizeof(table)); + bzero((char*) &share, sizeof(share)); table.in_use= thd; - table.s = &table.share_not_to_be_used; + table.s = &share; field= sp->create_result_field(0, 0, &table); field->sql_type(result); @@ -495,6 +447,13 @@ db_create_routine(THD *thd, int type, sp_head *sp) DBUG_PRINT("enter", ("type: %d name: %.*s",type,sp->m_name.length, sp->m_name.str)); + /* + This statement will be replicated as a statement, even when using + row-based replication. The flag will be reset at the end of the + statement. + */ + thd->clear_current_stmt_binlog_row_based(); + if (!(table= open_proc_table_for_update(thd))) ret= SP_OPEN_TABLE_FAILED; else @@ -502,7 +461,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) restore_record(table, s->default_values); // Get default values for fields /* NOTE: all needed privilege checks have been already done. */ - strxmov(definer, thd->lex->definer->user.str, "@", + strxnmov(definer, sizeof(definer)-1, thd->lex->definer->user.str, "@", thd->lex->definer->host.str, NullS); if (table->s->fields != MYSQL_PROC_FIELD_COUNT) @@ -528,18 +487,18 @@ db_create_routine(THD *thd, int type, sp_head *sp) store(sp->m_db.str, sp->m_db.length, system_charset_info); table->field[MYSQL_PROC_FIELD_NAME]-> store(sp->m_name.str, sp->m_name.length, system_charset_info); - table->field[MYSQL_PROC_FIELD_TYPE]-> - store((longlong)type, 1); + table->field[MYSQL_PROC_MYSQL_TYPE]-> + store((longlong)type, TRUE); table->field[MYSQL_PROC_FIELD_SPECIFIC_NAME]-> store(sp->m_name.str, sp->m_name.length, system_charset_info); if (sp->m_chistics->daccess != SP_DEFAULT_ACCESS) table->field[MYSQL_PROC_FIELD_ACCESS]-> - store((longlong)sp->m_chistics->daccess, 1); + store((longlong)sp->m_chistics->daccess, TRUE); table->field[MYSQL_PROC_FIELD_DETERMINISTIC]-> - store((longlong)(sp->m_chistics->detistic ? 1 : 2), 1); + store((longlong)(sp->m_chistics->detistic ? 1 : 2), TRUE); if (sp->m_chistics->suid != SP_IS_DEFAULT_SUID) table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]-> - store((longlong)sp->m_chistics->suid, 1); + store((longlong)sp->m_chistics->suid, TRUE); table->field[MYSQL_PROC_FIELD_PARAM_LIST]-> store(sp->m_params.str, sp->m_params.length, system_charset_info); if (sp->m_type == TYPE_ENUM_FUNCTION) @@ -556,7 +515,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_CREATED])->set_time(); ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time(); table->field[MYSQL_PROC_FIELD_SQL_MODE]-> - store((longlong)thd->variables.sql_mode, 1); + store((longlong)thd->variables.sql_mode, TRUE); if (sp->m_chistics->comment.str) table->field[MYSQL_PROC_FIELD_COMMENT]-> store(sp->m_chistics->comment.str, sp->m_chistics->comment.length, @@ -593,7 +552,7 @@ db_create_routine(THD *thd, int type, sp_head *sp) } ret= SP_OK; - if (table->file->write_row(table->record[0])) + if (table->file->ha_write_row(table->record[0])) ret= SP_WRITE_ROW_FAILED; else if (mysql_bin_log.is_open()) { @@ -610,9 +569,8 @@ db_create_routine(THD *thd, int type, sp_head *sp) sp->m_body.length); /* Such a statement can always go directly to binlog, no trans cache */ - Query_log_event qinfo(thd, log_query.c_ptr(), log_query.length(), 0, - FALSE); - mysql_bin_log.write(&qinfo); + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + log_query.c_ptr(), log_query.length(), FALSE, FALSE); } } @@ -632,11 +590,18 @@ db_drop_routine(THD *thd, int type, sp_name *name) DBUG_PRINT("enter", ("type: %d name: %.*s", type, name->m_name.length, name->m_name.str)); + /* + This statement will be replicated as a statement, even when using + row-based replication. The flag will be reset at the end of the + statement. + */ + thd->clear_current_stmt_binlog_row_based(); + if (!(table= open_proc_table_for_update(thd))) DBUG_RETURN(SP_OPEN_TABLE_FAILED); if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK) { - if (table->file->delete_row(table->record[0])) + if (table->file->ha_delete_row(table->record[0])) ret= SP_DELETE_ROW_FAILED; } @@ -645,8 +610,8 @@ db_drop_routine(THD *thd, int type, sp_name *name) if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); - mysql_bin_log.write(&qinfo); + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + thd->query, thd->query_length, FALSE, FALSE); } } @@ -664,6 +629,13 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) DBUG_PRINT("enter", ("type: %d name: %.*s", type, name->m_name.length, name->m_name.str)); + /* + This statement will be replicated as a statement, even when using + row-based replication. The flag will be reset at the end of the + statement. + */ + thd->clear_current_stmt_binlog_row_based(); + if (!(table= open_proc_table_for_update(thd))) DBUG_RETURN(SP_OPEN_TABLE_FAILED); if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK) @@ -673,15 +645,15 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) ((Field_timestamp *)table->field[MYSQL_PROC_FIELD_MODIFIED])->set_time(); if (chistics->suid != SP_IS_DEFAULT_SUID) table->field[MYSQL_PROC_FIELD_SECURITY_TYPE]-> - store((longlong)chistics->suid, 1); + store((longlong)chistics->suid, TRUE); if (chistics->daccess != SP_DEFAULT_ACCESS) table->field[MYSQL_PROC_FIELD_ACCESS]-> - store((longlong)chistics->daccess, 1); + store((longlong)chistics->daccess, TRUE); if (chistics->comment.str) table->field[MYSQL_PROC_FIELD_COMMENT]->store(chistics->comment.str, chistics->comment.length, system_charset_info); - if ((table->file->update_row(table->record[1],table->record[0]))) + if ((table->file->ha_update_row(table->record[1],table->record[0]))) ret= SP_WRITE_ROW_FAILED; } @@ -690,8 +662,8 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); - mysql_bin_log.write(&qinfo); + thd->binlog_query(THD::MYSQL_QUERY_TYPE, + thd->query, thd->query_length, FALSE, FALSE); } } @@ -710,15 +682,15 @@ struct st_used_field static struct st_used_field init_fields[]= { - { "Db", NAME_LEN, MYSQL_TYPE_STRING, 0}, - { "Name", NAME_LEN, MYSQL_TYPE_STRING, 0}, - { "Type", 9, MYSQL_TYPE_STRING, 0}, - { "Definer", 77, MYSQL_TYPE_STRING, 0}, - { "Modified", 0, MYSQL_TYPE_TIMESTAMP, 0}, - { "Created", 0, MYSQL_TYPE_TIMESTAMP, 0}, - { "Security_type", 1, MYSQL_TYPE_STRING, 0}, - { "Comment", NAME_LEN, MYSQL_TYPE_STRING, 0}, - { 0, 0, MYSQL_TYPE_STRING, 0} + { "Db", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0}, + { "Name", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0}, + { "Type", 9, MYSQL_TYPE_STRING, 0}, + { "Definer", 77, MYSQL_TYPE_STRING, 0}, + { "Modified", 0, MYSQL_TYPE_TIMESTAMP, 0}, + { "Created", 0, MYSQL_TYPE_TIMESTAMP, 0}, + { "Security_type", 1, MYSQL_TYPE_STRING, 0}, + { "Comment", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0}, + { 0, 0, MYSQL_TYPE_STRING, 0} }; @@ -729,7 +701,7 @@ print_field_values(THD *thd, TABLE *table, { Protocol *protocol= thd->protocol; - if (table->field[MYSQL_PROC_FIELD_TYPE]->val_int() == type) + if (table->field[MYSQL_PROC_MYSQL_TYPE]->val_int() == type) { String db_string; String name_string; @@ -752,7 +724,7 @@ print_field_values(THD *thd, TABLE *table, switch (used_field->field_type) { case MYSQL_TYPE_TIMESTAMP: { - TIME tmp_time; + MYSQL_TIME tmp_time; bzero((char *)&tmp_time, sizeof(tmp_time)); ((Field_timestamp *) used_field->field)->get_time(&tmp_time); @@ -803,6 +775,7 @@ db_show_routine_status(THD *thd, int type, const char *wild) TABLE_LIST *leaves= 0; st_used_field used_fields[array_elements(init_fields)]; + table->use_all_columns(); memcpy((char*) used_fields, (char*) init_fields, sizeof(used_fields)); /* Init header */ for (used_field= &used_fields[0]; @@ -836,7 +809,7 @@ db_show_routine_status(THD *thd, int type, const char *wild) thd->lex->select_lex.context.resolve_in_table_list_only(&tables); setup_tables(thd, &thd->lex->select_lex.context, &thd->lex->select_lex.top_join_list, - &tables, 0, &leaves, FALSE); + &tables, &leaves, FALSE); for (used_field= &used_fields[0]; used_field->field_name; used_field++) @@ -854,7 +827,7 @@ db_show_routine_status(THD *thd, int type, const char *wild) } } - table->file->ha_index_init(0); + table->file->ha_index_init(0, 1); if ((res= table->file->index_first(table->record[0]))) { res= (res == HA_ERR_END_OF_FILE) ? 0 : SP_INTERNAL_ERROR; @@ -898,17 +871,17 @@ sp_drop_db_routines(THD *thd, char *db) key_len= table->key_info->key_part[0].store_length; ret= SP_OK; - table->file->ha_index_init(0); + table->file->ha_index_init(0, 1); if (! table->file->index_read(table->record[0], (byte *)table->field[MYSQL_PROC_FIELD_DB]->ptr, - key_len, HA_READ_KEY_EXACT)) + (key_part_map)1, HA_READ_KEY_EXACT)) { int nxtres; bool deleted= FALSE; do { - if (! table->file->delete_row(table->record[0])) + if (! table->file->ha_delete_row(table->record[0])) deleted= TRUE; /* We deleted something */ else { @@ -985,7 +958,7 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp)); if (sp->m_first_free_instance) { - DBUG_PRINT("info", ("first free: 0x%lx, level: %lu, flags %x", + DBUG_PRINT("info", ("first free: 0x%lx level: %lu flags %x", (ulong)sp->m_first_free_instance, sp->m_first_free_instance->m_recursion_level, sp->m_first_free_instance->m_flags)); @@ -1123,7 +1096,7 @@ sp_routine_exists_in_table(THD *thd, int type, sp_name *name) { if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK) ret= SP_KEY_NOT_FOUND; - close_proc_table(thd, &open_tables_state_backup); + close_system_tables(thd, &open_tables_state_backup); } return ret; } @@ -1555,7 +1528,6 @@ static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src, first_no_prelock - If true, don't add tables or cache routines used by the body of the first routine (i.e. *start) will be executed in non-prelocked mode. - tabs_changed - Set to TRUE some tables were added, FALSE otherwise NOTE If some function is missing this won't be reported here. Instead this fact will be discovered during query execution. @@ -1568,10 +1540,9 @@ static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src, static int sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, Sroutine_hash_entry *start, - bool first_no_prelock, bool *tabs_changed) + bool first_no_prelock) { int ret= 0; - bool tabschnd= 0; /* Set if tables changed */ bool first= TRUE; DBUG_ENTER("sp_cache_routines_and_add_tables_aux"); @@ -1627,10 +1598,8 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, rest of the server checks agains NAME_LEN bytes and not chars. Hence, the overrun happens only if the name is in length > 32 and uses multibyte (cyrillic, greek, etc.) - - !! Change 3 with SYSTEM_CHARSET_MBMAXLEN when it's defined. */ - char n[NAME_LEN*3*2+2]; + char n[NAME_LEN*2+2]; /* m_qname.str is not always \0 terminated */ memcpy(n, name.m_qname.str, name.m_qname.length); @@ -1646,15 +1615,13 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, { sp_update_stmt_used_routines(thd, lex, &sp->m_sroutines, rt->belong_to_view); - tabschnd|= - sp->add_used_tables_to_table_list(thd, &lex->query_tables_last, - rt->belong_to_view); + (void)sp->add_used_tables_to_table_list(thd, &lex->query_tables_last, + rt->belong_to_view); } + sp->propagate_attributes(lex); } first= FALSE; } - if (tabs_changed) /* it can be NULL */ - *tabs_changed= tabschnd; DBUG_RETURN(ret); } @@ -1670,20 +1637,18 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, lex - LEX representing statement first_no_prelock - If true, don't add tables or cache routines used by the body of the first routine (i.e. *start) - tabs_changed - Set to TRUE some tables were added, FALSE otherwise - + RETURN VALUE 0 - success non-0 - failure */ int -sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock, - bool *tabs_changed) +sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock) { return sp_cache_routines_and_add_tables_aux(thd, lex, (Sroutine_hash_entry *)lex->sroutines_list.first, - first_no_prelock, tabs_changed); + first_no_prelock); } @@ -1710,9 +1675,8 @@ sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, TABLE_LIST *view) (Sroutine_hash_entry **)lex->sroutines_list.next; sp_update_stmt_used_routines(thd, lex, &view->view->sroutines_list, view->top_table()); - return sp_cache_routines_and_add_tables_aux(thd, lex, - *last_cached_routine_ptr, FALSE, - NULL); + return sp_cache_routines_and_add_tables_aux(thd, lex, + *last_cached_routine_ptr, FALSE); } @@ -1747,20 +1711,21 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, { for (int j= 0; j < (int)TRG_ACTION_MAX; j++) { - if (triggers->bodies[i][j]) + sp_head *trigger_body= triggers->bodies[i][j]; + if (trigger_body) { - (void)triggers->bodies[i][j]-> - add_used_tables_to_table_list(thd, &lex->query_tables_last, - table->belong_to_view); + (void)trigger_body-> + add_used_tables_to_table_list(thd, &lex->query_tables_last, + table->belong_to_view); sp_update_stmt_used_routines(thd, lex, - &triggers->bodies[i][j]->m_sroutines, + &trigger_body->m_sroutines, table->belong_to_view); + trigger_body->propagate_attributes(lex); } } } ret= sp_cache_routines_and_add_tables_aux(thd, lex, - *last_cached_routine_ptr, - FALSE, NULL); + *last_cached_routine_ptr, FALSE); } return ret; } |