From 89fa5f13d9d26f5232c3068ab67878a02804b91a Mon Sep 17 00:00:00 2001 From: "monty@hundin.mysql.fi" <> Date: Fri, 18 Jan 2002 00:43:50 +0200 Subject: Fixed bug when making a range join based on information from a const table. --- sql/sql_select.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9ff64780bdd..57053b87fa6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1026,14 +1026,13 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, { ha_rows records; if (!select) - select=make_select(s->table,const_table_map, + select=make_select(s->table,0, 0, and_conds(conds,s->on_expr),&error); records=get_quick_record_count(select,s->table, s->const_keys); s->quick=select->quick; s->needed_reg=select->needed_reg; select->quick=0; - select->read_tables=const_table_map; if (records != HA_POS_ERROR) { s->found_records=records; -- cgit v1.2.1 From d927ff75dc34f0c8b684d381339670a2c2819bc9 Mon Sep 17 00:00:00 2001 From: "heikki@donna.mysql.fi" <> Date: Tue, 22 Jan 2002 22:57:56 +0200 Subject: ha_innobase.cc, ha_innobase.h, handler.h, handler.cc, sql_class.h, log.cc: Tell table handlers where a binlog segment for a trx ends --- sql/ha_innobase.cc | 21 +++++++++++++++++++++ sql/ha_innobase.h | 5 +++++ sql/handler.cc | 40 +++++++++++++++++++++++++++++++++++++++- sql/handler.h | 4 ++++ sql/log.cc | 21 ++++++++++++++++++++- sql/sql_class.h | 2 +- 6 files changed, 90 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index 62c721de13f..ccb41880fc5 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -730,6 +730,27 @@ innobase_commit( DBUG_RETURN(error); } +/********************************************************************* +This is called when MySQL writes the binlog entry for the current +transaction. Writes to the InnoDB tablespace info which tells where the +MySQL binlog entry for the current transaction ended. Also commits the +transaction inside InnoDB. */ + +int +innobase_report_binlog_offset_and_commit( +/*=====================================*/ + /* out: 0 or error code */ + THD* thd, /* in: user thread */ + void* trx_handle, /* in: InnoDB trx handle */ + char* log_file_name, /* in: latest binlog file name */ + my_off_t end_offset) /* in: the offset in the binlog file + up to which we wrote */ +{ + /* Currently does nothing ! */ + + return(0); +} + /********************************************************************* Rolls back a transaction in an InnoDB database. */ diff --git a/sql/ha_innobase.h b/sql/ha_innobase.h index 3f4bd5144eb..54449a1ef2b 100644 --- a/sql/ha_innobase.h +++ b/sql/ha_innobase.h @@ -185,6 +185,11 @@ bool innobase_flush_logs(void); uint innobase_get_free_space(void); int innobase_commit(THD *thd, void* trx_handle); +int innobase_report_binlog_offset_and_commit( + THD* thd, + void* trx_handle, + char* log_file_name, + my_off_t end_offset); int innobase_rollback(THD *thd, void* trx_handle); int innobase_close_connection(THD *thd); int innobase_drop_database(char *path); diff --git a/sql/handler.cc b/sql/handler.cc index 0b493219674..c1e28b0058e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -257,6 +257,44 @@ int ha_autocommit_or_rollback(THD *thd, int error) DBUG_RETURN(error); } +/* This function is called when MySQL writes the log segment of a transaction +to the binlog. It is called when the LOCK_log mutex is reserved. Here we +communicate to transactional table handlers whta binlog position corresponds +to the current transaction. The handler can store it and in recovery print +to the user, so that the user knows from what position in the binlog to +start possible roll-forward, for example, if the crashed server was a slave +in replication. This function also calls the commit of the table handler, +because the order of trasnactions in the log of the table handler must be +the same as in the binlog. */ + +int ha_report_binlog_offset_and_commit( + THD *thd, /* in: user thread */ + char *log_file_name, /* in: latest binlog file name */ + my_off_t end_offset) /* in: the offset in the binlog file + up to which we wrote */ +{ + THD_TRANS *trans; + int error = 0; + + trans = &thd->transaction.all; + +#ifdef HAVE_INNOBASE_DB + if (trans->innobase_tid) + { + if ((error=innobase_report_binlog_offset_and_commit(thd, + trans->innobase_tid, + log_file_name, + end_offset))) + { + my_error(ER_ERROR_DURING_COMMIT, MYF(0), error); + error=1; + } + trans->innodb_active_trans=0; + } +#endif + + return error; +} int ha_commit_trans(THD *thd, THD_TRANS* trans) { @@ -269,7 +307,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans) if (trans == &thd->transaction.all && mysql_bin_log.is_open() && my_b_tell(&thd->transaction.trans_log)) { - mysql_bin_log.write(&thd->transaction.trans_log); + mysql_bin_log.write(thd, &thd->transaction.trans_log); reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE, (my_off_t) 0, 0, 1); thd->transaction.trans_log.end_of_file= max_binlog_cache_size; diff --git a/sql/handler.h b/sql/handler.h index 560420a480d..e4cac60ed67 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -353,6 +353,10 @@ int ha_delete_table(enum db_type db_type, const char *path); void ha_drop_database(char* path); void ha_key_cache(void); int ha_start_stmt(THD *thd); +int ha_report_binlog_offset_and_commit( + THD *thd, + char *log_file_name, + my_off_t end_offset); int ha_commit_trans(THD *thd, THD_TRANS *trans); int ha_rollback_trans(THD *thd, THD_TRANS *trans); int ha_autocommit_or_rollback(THD *thd, int error); diff --git a/sql/log.cc b/sql/log.cc index 1b236d342f5..bc2b19d921f 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -658,6 +658,7 @@ bool MYSQL_LOG::write(Query_log_event* event_info) VOID(pthread_mutex_unlock(&LOCK_log)); return 0; } + error=1; if (thd->last_insert_id_used) @@ -694,6 +695,20 @@ bool MYSQL_LOG::write(Query_log_event* event_info) goto err; error=0; should_rotate = (file == &log_file && my_b_tell(file) >= max_binlog_size); + + /* Tell for transactional table handlers up to which position in the + binlog file we wrote. The table handler can store this info, and + after crash recovery print for the user the offset of the last + transactions which were recovered. Actually, we must also call + the table handler commit here, protected by the LOCK_log mutex, + because otherwise the transactions may end up in a different order + in the table handler log! */ + + if (file == &log_file) { + error = ha_report_binlog_offset_and_commit(thd, log_file_name, + file->pos_in_file); + } + err: if (error) { @@ -718,7 +733,7 @@ err: 'cache' needs to be reinitialized after this functions returns. */ -bool MYSQL_LOG::write(IO_CACHE *cache) +bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache) { VOID(pthread_mutex_lock(&LOCK_log)); bool error=1; @@ -754,6 +769,10 @@ bool MYSQL_LOG::write(IO_CACHE *cache) sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno); goto err; } + error = ha_report_binlog_offset_and_commit(thd, log_file_name, + log_file.pos_in_file); + if (error) + goto err; } error=0; diff --git a/sql/sql_class.h b/sql/sql_class.h index 3d218a06d0c..d9497907926 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -82,7 +82,7 @@ public: time_t query_start=0); bool write(Query_log_event* event_info); // binary log write bool write(Load_log_event* event_info); - bool write(IO_CACHE *cache); + bool write(THD *thd, IO_CACHE *cache); int generate_new_name(char *new_name,const char *old_name); void make_log_name(char* buf, const char* log_ident); bool is_active(const char* log_file_name); -- cgit v1.2.1 From 0c87ad9f8a23a9f36aa21aef4bd852b325245fc3 Mon Sep 17 00:00:00 2001 From: "heikki@donna.mysql.fi" <> Date: Mon, 28 Jan 2002 22:18:49 +0200 Subject: Many files: Merge InnoDB-.48 --- sql/ha_innobase.cc | 243 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 139 insertions(+), 104 deletions(-) (limited to 'sql') diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index ccb41880fc5..a923a259ebd 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -21,7 +21,7 @@ InnoDB */ - Ask Monty if strings of different languages can exist in the same database. Answer: in near future yes, but not yet. */ - + #ifdef __GNUC__ #pragma implementation // gcc: Class implementation #endif @@ -112,6 +112,36 @@ static void innobase_print_error(const char* db_errpfx, char* buffer); /* General functions */ +/********************************************************************** +Releases possible search latch, auto inc lock, and InnoDB thread FIFO ticket. +These should be released at each SQL statement end. */ +static +void +innobase_release_stat_resources( +/*============================*/ + trx_t* trx) /* in: transaction object */ +{ + if (trx->has_search_latch) { + trx_search_latch_release_if_reserved(trx); + } + + if (trx->auto_inc_lock) { + + /* If we had reserved the auto-inc lock for + some table in this SQL statement, we release it now */ + + srv_conc_enter_innodb(trx); + row_unlock_table_autoinc_for_mysql(trx); + srv_conc_exit_innodb(trx); + } + + if (trx->declared_to_be_inside_innodb) { + /* Release our possible ticket in the FIFO */ + + srv_conc_force_exit_innodb(trx); + } +} + /************************************************************************ Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth time calls srv_active_wake_master_thread. This function should be used @@ -708,13 +738,13 @@ innobase_commit( trx = check_trx_exists(thd); if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) { - srv_conc_enter_innodb(trx); trx_commit_for_mysql(trx); - - srv_conc_exit_innodb(); } + /* Release possible statement level resources */ + innobase_release_stat_resources(trx); + trx_mark_sql_stat_end(trx); #ifndef DBUG_OFF @@ -739,16 +769,21 @@ transaction inside InnoDB. */ int innobase_report_binlog_offset_and_commit( /*=====================================*/ - /* out: 0 or error code */ + /* out: 0 or error code */ THD* thd, /* in: user thread */ - void* trx_handle, /* in: InnoDB trx handle */ + void* trx_handle, /* in: InnoDB trx handle */ char* log_file_name, /* in: latest binlog file name */ my_off_t end_offset) /* in: the offset in the binlog file - up to which we wrote */ + up to which we wrote */ { - /* Currently does nothing ! */ + trx_t* trx; + + trx = (trx_t*)trx_handle; - return(0); + trx->mysql_log_file_name = log_file_name; + trx->mysql_log_offset = (ib_longlong)end_offset; + + return(innobase_commit(thd, trx_handle)); } /********************************************************************* @@ -778,8 +813,11 @@ innobase_rollback( error = trx_rollback_last_sql_stat_for_mysql(trx); } - srv_conc_exit_innodb(); - + srv_conc_exit_innodb(trx); + + /* Release possible statement level resources */ + innobase_release_stat_resources(trx); + trx_mark_sql_stat_end(trx); DBUG_RETURN(convert_error_code_to_mysql(error)); @@ -1451,6 +1489,8 @@ ha_innobase::write_row( if (last_query_id != user_thd->query_id) { prebuilt->sql_stat_start = TRUE; last_query_id = user_thd->query_id; + + innobase_release_stat_resources(prebuilt->trx); } if (table->next_number_field && record == table->record[0]) { @@ -1501,7 +1541,7 @@ ha_innobase::write_row( srv_conc_enter_innodb(prebuilt->trx); error = row_lock_table_autoinc_for_mysql(prebuilt); - srv_conc_exit_innodb(); + srv_conc_exit_innodb(prebuilt->trx); if (error != DB_SUCCESS) { @@ -1518,7 +1558,7 @@ ha_innobase::write_row( error = row_lock_table_autoinc_for_mysql( prebuilt); if (error != DB_SUCCESS) { - srv_conc_exit_innodb(); + srv_conc_exit_innodb(prebuilt->trx); error = convert_error_code_to_mysql( error); @@ -1527,7 +1567,7 @@ ha_innobase::write_row( } auto_inc = dict_table_autoinc_get(prebuilt->table); - srv_conc_exit_innodb(); + srv_conc_exit_innodb(prebuilt->trx); /* If auto_inc is now != 0 the autoinc counter was already initialized for the table: we can give @@ -1554,7 +1594,7 @@ ha_innobase::write_row( srv_conc_enter_innodb(prebuilt->trx); error = row_lock_table_autoinc_for_mysql(prebuilt); - srv_conc_exit_innodb(); + srv_conc_exit_innodb(prebuilt->trx); if (error != DB_SUCCESS) { @@ -1594,7 +1634,7 @@ ha_innobase::write_row( error = row_insert_for_mysql((byte*) record, prebuilt); - srv_conc_exit_innodb(); + srv_conc_exit_innodb(prebuilt->trx); prebuilt->trx->ignore_duplicates_in_insert = FALSE; @@ -1789,6 +1829,8 @@ ha_innobase::update_row( if (last_query_id != user_thd->query_id) { prebuilt->sql_stat_start = TRUE; last_query_id = user_thd->query_id; + + innobase_release_stat_resources(prebuilt->trx); } if (prebuilt->upd_node) { @@ -1813,7 +1855,7 @@ ha_innobase::update_row( error = row_update_for_mysql((byte*) old_row, prebuilt); - srv_conc_exit_innodb(); + srv_conc_exit_innodb(prebuilt->trx); error = convert_error_code_to_mysql(error); @@ -1842,6 +1884,8 @@ ha_innobase::delete_row( if (last_query_id != user_thd->query_id) { prebuilt->sql_stat_start = TRUE; last_query_id = user_thd->query_id; + + innobase_release_stat_resources(prebuilt->trx); } if (!prebuilt->upd_node) { @@ -1857,7 +1901,7 @@ ha_innobase::delete_row( error = row_update_for_mysql((byte*) record, prebuilt); - srv_conc_exit_innodb(); + srv_conc_exit_innodb(prebuilt->trx); error = convert_error_code_to_mysql(error); @@ -1956,6 +2000,8 @@ ha_innobase::index_read( if (last_query_id != user_thd->query_id) { prebuilt->sql_stat_start = TRUE; last_query_id = user_thd->query_id; + + innobase_release_stat_resources(prebuilt->trx); } index = prebuilt->index; @@ -2001,7 +2047,7 @@ ha_innobase::index_read( ret = row_search_for_mysql((byte*) buf, mode, prebuilt, match_mode, 0); - srv_conc_exit_innodb(); + srv_conc_exit_innodb(prebuilt->trx); if (ret == DB_SUCCESS) { error = 0; @@ -2127,7 +2173,7 @@ ha_innobase::general_fetch( ret = row_search_for_mysql((byte*)buf, 0, prebuilt, match_mode, direction); - srv_conc_exit_innodb(); + srv_conc_exit_innodb(prebuilt->trx); if (ret == DB_SUCCESS) { error = 0; @@ -2427,89 +2473,6 @@ int ha_innobase::reset(void) return(0); } -/********************************************************************** -As MySQL will execute an external lock for every new table it uses when it -starts to process an SQL statement, we can use this function to store the -pointer to the THD in the handle. We will also use this function to communicate -to InnoDB that a new SQL statement has started and that we must store a -savepoint to our transaction handle, so that we are able to roll back -the SQL statement in case of an error. */ - -int -ha_innobase::external_lock( -/*=======================*/ - THD* thd, /* in: handle to the user thread */ - int lock_type) /* in: lock type */ -{ - row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; - int error = 0; - trx_t* trx; - - DBUG_ENTER("ha_innobase::external_lock"); - - update_thd(thd); - - trx = prebuilt->trx; - - prebuilt->sql_stat_start = TRUE; - prebuilt->in_update_remember_pos = TRUE; - - prebuilt->read_just_key = 0; - - if (lock_type == F_WRLCK) { - - /* If this is a SELECT, then it is in UPDATE TABLE ... - or SELECT ... FOR UPDATE */ - prebuilt->select_lock_type = LOCK_X; - } - - if (lock_type != F_UNLCK) { - if (trx->n_mysql_tables_in_use == 0) { - trx_mark_sql_stat_end(trx); - } - - thd->transaction.all.innodb_active_trans = 1; - trx->n_mysql_tables_in_use++; - - if (prebuilt->select_lock_type != LOCK_NONE) { - - trx->mysql_n_tables_locked++; - } - } else { - trx->n_mysql_tables_in_use--; - auto_inc_counter_for_this_stat = 0; - - if (trx->n_mysql_tables_in_use == 0) { - - trx->mysql_n_tables_locked = 0; - - if (trx->has_search_latch) { - - trx_search_latch_release_if_reserved(trx); - } - - if (trx->auto_inc_lock) { - - /* If we had reserved the auto-inc lock for - some table in this SQL statement, we release - it now */ - - srv_conc_enter_innodb(trx); - row_unlock_table_autoinc_for_mysql(trx); - srv_conc_exit_innodb(); - } - - if (!(thd->options - & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))) { - - innobase_commit(thd, trx); - } - } - } - - DBUG_RETURN(error); -} - /********************************************************************* Creates a table definition to an InnoDB database. */ static @@ -2685,7 +2648,7 @@ ha_innobase::create( /* Create the table definition in InnoDB */ - if ((error = create_table_def(trx, form, norm_name))) { + if (error = create_table_def(trx, form, norm_name)) { trx_commit_for_mysql(trx); @@ -3265,6 +3228,78 @@ ha_innobase::update_table_comment( return(str); } +/********************************************************************** +As MySQL will execute an external lock for every new table it uses when it +starts to process an SQL statement, we can use this function to store the +pointer to the THD in the handle. We will also use this function to communicate +to InnoDB that a new SQL statement has started and that we must store a +savepoint to our transaction handle, so that we are able to roll back +the SQL statement in case of an error. */ + +int +ha_innobase::external_lock( +/*=======================*/ + THD* thd, /* in: handle to the user thread */ + int lock_type) /* in: lock type */ +{ + row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; + int error = 0; + trx_t* trx; + + DBUG_ENTER("ha_innobase::external_lock"); + + update_thd(thd); + + trx = prebuilt->trx; + + prebuilt->sql_stat_start = TRUE; + prebuilt->in_update_remember_pos = TRUE; + + prebuilt->read_just_key = 0; + + if (lock_type == F_WRLCK) { + + /* If this is a SELECT, then it is in UPDATE TABLE ... + or SELECT ... FOR UPDATE */ + prebuilt->select_lock_type = LOCK_X; + } + + if (lock_type != F_UNLCK) { + if (trx->n_mysql_tables_in_use == 0) { + trx_mark_sql_stat_end(trx); + } + + thd->transaction.all.innodb_active_trans = 1; + trx->n_mysql_tables_in_use++; + + if (prebuilt->select_lock_type != LOCK_NONE) { + + trx->mysql_n_tables_locked++; + } + } else { + trx->n_mysql_tables_in_use--; + auto_inc_counter_for_this_stat = 0; + + if (trx->n_mysql_tables_in_use == 0) { + + trx->mysql_n_tables_locked = 0; + + /* Here we release the search latch, auto_inc_lock, + and InnoDB thread FIFO ticket if they were reserved. */ + + innobase_release_stat_resources(trx); + + if (!(thd->options + & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))) { + + innobase_commit(thd, trx); + } + } + } + + DBUG_RETURN(error); +} + /**************************************************************************** Handling the shared INNOBASE_SHARE structure that is needed to provide table locking. -- cgit v1.2.1 From b908f410fbe1c9e27042fb40950398baca0e7db7 Mon Sep 17 00:00:00 2001 From: "heikki@donna.mysql.fi" <> Date: Wed, 30 Jan 2002 14:10:26 +0200 Subject: ha_innobase.cc: Assume selectivity of any key prefix is better than 1 / 100, regardless of what the estimator returns; this balances the pessimistic assumption of the optimizer thatany secondary key access to the full row incurs a page read from disk --- sql/ha_innobase.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'sql') diff --git a/sql/ha_innobase.cc b/sql/ha_innobase.cc index a923a259ebd..acdc9736a4f 100644 --- a/sql/ha_innobase.cc +++ b/sql/ha_innobase.cc @@ -3130,6 +3130,22 @@ ha_innobase::info( rec_per_key = 1; } + /* Since the MySQL optimizer is often too + pessimistic in the assumption that a table + does not fit in the buffer pool, we + increase the attractiveness of indexes + by assuming the selectivity of any prefix + of an index is 1 / 100 or better. + (Actually, we should look at the table + size, and if the table is smaller than + the buffer pool, we should uniformly + increase the attractiveness of indexes, + regardless of the estimated selectivity.) */ + + if (rec_per_key > records / 100) { + rec_per_key = records / 100; + } + table->key_info[i].rec_per_key[j] = rec_per_key; } -- cgit v1.2.1 From fef87f20af68e96a586a5d4966cccccea494bb2e Mon Sep 17 00:00:00 2001 From: "monty@hundin.mysql.fi" <> Date: Wed, 30 Jan 2002 16:09:19 +0200 Subject: Fix in SHOW GRANTS: REFERENCE -> REFERENCES --- sql/sql_acl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index ce66b60a49f..7ad778cf5d0 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2315,7 +2315,7 @@ uint get_column_grant(THD *thd, TABLE_LIST *table, Field *field) static const char *command_array[]= {"SELECT", "INSERT","UPDATE","DELETE","CREATE", "DROP","RELOAD","SHUTDOWN", "PROCESS","FILE","GRANT","REFERENCES","INDEX","ALTER"}; -static int command_lengths[]={6,6,6,6,6,4,6,8,7,4,5,9,5,5}; +static int command_lengths[]={6,6,6,6,6,4,6,8,7,4,5,10,5,5}; int mysql_show_grants(THD *thd,LEX_USER *lex_user) { -- cgit v1.2.1