diff options
Diffstat (limited to 'sql/handler.cc')
-rw-r--r-- | sql/handler.cc | 265 |
1 files changed, 122 insertions, 143 deletions
diff --git a/sql/handler.cc b/sql/handler.cc index 564d91aa887..4180d98245c 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1,15 +1,15 @@ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -25,7 +25,7 @@ #include "ha_heap.h" #include "ha_myisam.h" #include "ha_myisammrg.h" -#ifndef NO_ISAM +#ifdef HAVE_ISAM #include "ha_isam.h" #include "ha_isammrg.h" #endif @@ -33,10 +33,7 @@ #include "ha_berkeley.h" #endif #ifdef HAVE_INNOBASE_DB -#include "ha_innobase.h" -#endif -#ifdef HAVE_GEMINI_DB -#include "ha_gemini.h" +#include "ha_innodb.h" #endif #include <myisampack.h> #include <errno.h> @@ -48,6 +45,7 @@ static int NEAR_F delete_file(const char *name,const char *ext,int extflag); ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count, ha_read_key_count, ha_read_next_count, ha_read_prev_count, ha_read_first_count, ha_read_last_count, + ha_commit_count, ha_rollback_count, ha_read_rnd_count, ha_read_rnd_next_count; const char *ha_table_type[] = { @@ -55,8 +53,10 @@ const char *ha_table_type[] = { "MRG_ISAM","MYISAM", "MRG_MYISAM", "BDB", "INNODB", "GEMINI", "?", "?",NullS }; -TYPELIB ha_table_typelib= {array_elements(ha_table_type)-4,"", - ha_table_type+1}; +TYPELIB ha_table_typelib= +{ + array_elements(ha_table_type)-3, "", ha_table_type +}; const char *ha_row_type[] = { "", "FIXED", "DYNAMIC", "COMPRESSED","?","?","?" @@ -78,21 +78,15 @@ enum db_type ha_checktype(enum db_type database_type) return(berkeley_skip ? DB_TYPE_MYISAM : database_type); #endif #ifdef HAVE_INNOBASE_DB - case DB_TYPE_INNOBASE: + case DB_TYPE_INNODB: return(innodb_skip ? DB_TYPE_MYISAM : database_type); #endif -#ifdef HAVE_GEMINI_DB - case DB_TYPE_GEMINI: - return(gemini_skip ? DB_TYPE_MYISAM : database_type); -#endif #ifndef NO_HASH case DB_TYPE_HASH: #endif -#ifndef NO_MERGE - case DB_TYPE_MRG_ISAM: -#endif -#ifndef NO_ISAM +#ifdef HAVE_ISAM case DB_TYPE_ISAM: + case DB_TYPE_MRG_ISAM: #endif case DB_TYPE_HEAP: case DB_TYPE_MYISAM: @@ -111,11 +105,9 @@ handler *get_new_handler(TABLE *table, enum db_type db_type) #ifndef NO_HASH return new ha_hash(table); #endif -#ifndef NO_MERGE +#ifdef HAVE_ISAM case DB_TYPE_MRG_ISAM: return new ha_isammrg(table); -#endif -#ifndef NO_ISAM case DB_TYPE_ISAM: return new ha_isam(table); #endif @@ -124,13 +116,9 @@ handler *get_new_handler(TABLE *table, enum db_type db_type) return new ha_berkeley(table); #endif #ifdef HAVE_INNOBASE_DB - case DB_TYPE_INNOBASE: + case DB_TYPE_INNODB: return new ha_innobase(table); #endif -#ifdef HAVE_GEMINI_DB - case DB_TYPE_GEMINI: - return new ha_gemini(table); -#endif case DB_TYPE_HEAP: return new ha_heap(table); case DB_TYPE_MYISAM: @@ -166,17 +154,6 @@ int ha_init() have_innodb=SHOW_OPTION_DISABLED; } #endif -#ifdef HAVE_GEMINI_DB - if (!gemini_skip) - { - if (gemini_init()) - return -1; - if (!gemini_skip) // If we couldn't use handler - opt_using_transactions=1; - else - have_gemini=SHOW_OPTION_DISABLED; - } -#endif return 0; } @@ -186,14 +163,14 @@ int ha_init() int ha_panic(enum ha_panic_function flag) { int error=0; -#ifndef NO_MERGE - error|=mrg_panic(flag); -#endif #ifndef NO_HASH error|=h_panic(flag); /* fix hash */ #endif - error|=heap_panic(flag); +#ifdef HAVE_ISAM + error|=mrg_panic(flag); error|=nisam_panic(flag); +#endif + error|=heap_panic(flag); error|=mi_panic(flag); error|=myrg_panic(flag); #ifdef HAVE_BERKELEY_DB @@ -204,10 +181,6 @@ int ha_panic(enum ha_panic_function flag) if (!innodb_skip) error|=innobase_end(); #endif -#ifdef HAVE_GEMINI_DB - if (!gemini_skip) - error|=gemini_end(); -#endif return error; } /* ha_panic */ @@ -225,12 +198,6 @@ void ha_close_connection(THD* thd) if (!innodb_skip) innobase_close_connection(thd); #endif -#ifdef HAVE_GEMINI_DB - if (!gemini_skip && thd->gemini.context) - { - gemini_disconnect(thd); - } -#endif /* HAVE_GEMINI_DB */ } /* @@ -251,8 +218,8 @@ int ha_autocommit_or_rollback(THD *thd, int error) } else (void) ha_rollback_stmt(thd); - - thd->tx_isolation=thd->session_tx_isolation; + + thd->variables.tx_isolation=thd->session_tx_isolation; } #endif DBUG_RETURN(error); @@ -306,6 +273,8 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans) #ifdef USING_TRANSACTIONS if (opt_using_transactions) { + bool operation_done= 0; + bool transaction_commited= 0; /* Update the binary log if we have cached some queries */ if (trans == &thd->transaction.all && mysql_bin_log.is_open() && my_b_tell(&thd->transaction.trans_log)) @@ -353,6 +322,8 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans) my_error(ER_ERROR_DURING_COMMIT, MYF(0), error); error=1; } + else + transaction_commited= 1; trans->bdb_tid=0; } #endif @@ -365,25 +336,23 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans) error=1; } trans->innodb_active_trans=0; + if (trans == &thd->transaction.all) + operation_done= transaction_commited= 1; + } #endif -#ifdef HAVE_GEMINI_DB - /* Commit the transaction in behalf of the commit statement - or if we're in auto-commit mode */ - if((trans == &thd->transaction.all) || - (!(thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)))) - { - error=gemini_commit(thd); - if (error) - { - my_error(ER_ERROR_DURING_COMMIT, MYF(0), error); - error=1; - } - } -#endif +#ifdef HAVE_QUERY_CACHE + if (transaction_commited) + query_cache.invalidate(thd->transaction.changed_tables); +#endif /*HAVE_QUERY_CACHE*/ if (error && trans == &thd->transaction.all && mysql_bin_log.is_open()) sql_print_error("Error: Got error during commit; Binlog is not up to date!"); - thd->tx_isolation=thd->session_tx_isolation; + thd->variables.tx_isolation=thd->session_tx_isolation; + if (operation_done) + { + statistic_increment(ha_commit_count,&LOCK_status); + thd->transaction.cleanup(); + } } #endif // using transactions DBUG_RETURN(error); @@ -397,6 +366,7 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans) #ifdef USING_TRANSACTIONS if (opt_using_transactions) { + bool operation_done=0; #ifdef HAVE_BERKELEY_DB if (trans->bdb_tid) { @@ -406,6 +376,7 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans) error=1; } trans->bdb_tid=0; + operation_done=1; } #endif #ifdef HAVE_INNOBASE_DB @@ -417,41 +388,24 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans) error=1; } trans->innodb_active_trans=0; - } -#endif -#ifdef HAVE_GEMINI_DB - if((trans == &thd->transaction.stmt) && - (thd->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN))) - error = gemini_rollback_to_savepoint(thd); - else - error=gemini_rollback(thd); - if (error) - { - my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error); - error=1; + operation_done=1; } #endif if (trans == &thd->transaction.all) 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; - thd->tx_isolation=thd->session_tx_isolation; + thd->variables.tx_isolation=thd->session_tx_isolation; + if (operation_done) + { + statistic_increment(ha_rollback_count,&LOCK_status); + thd->transaction.cleanup(); + } } #endif /* USING_TRANSACTIONS */ DBUG_RETURN(error); } -void ha_set_spin_retries(uint retries) -{ -#ifdef HAVE_GEMINI_DB - if (!gemini_skip) - { - gemini_set_option_long(GEM_OPTID_SPIN_RETRIES, retries); - } -#endif /* HAVE_GEMINI_DB */ -} - - bool ha_flush_logs() { bool result=0; @@ -480,7 +434,7 @@ int ha_delete_table(enum db_type table_type, const char *path) delete file; return error; } - + void ha_store_ptr(byte *buff, uint pack_length, my_off_t pos) { switch (pack_length) { @@ -567,9 +521,8 @@ int handler::ha_open(const char *name, int mode, int test_if_locked) { if (table->db_options_in_use & HA_OPTION_READ_ONLY_DATA) table->db_stat|=HA_READ_ONLY; - } - if (!error) - { + (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL + if (!alloc_root_inited(&table->mem_root)) // If temporary table ref=(byte*) sql_alloc(ALIGN_SIZE(ref_length)*2); else @@ -615,17 +568,37 @@ int handler::analyze(THD* thd, HA_CHECK_OPT* check_opt) return HA_ADMIN_NOT_IMPLEMENTED; } - /* Read first row from a table */ +/* + Read first row (only) from a table + This is never called for InnoDB or BDB tables, as these table types + has the HA_NOT_EXACT_COUNT set. +*/ -int handler::rnd_first(byte * buf) +int handler::read_first_row(byte * buf, uint primary_key) { register int error; - DBUG_ENTER("handler::rnd_first"); + DBUG_ENTER("handler::read_first_row"); statistic_increment(ha_read_first_count,&LOCK_status); - (void) rnd_init(); - while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ; - (void) rnd_end(); + + /* + If there is very few deleted rows in the table, find the first row by + scanning the table. + */ + if (deleted < 10 || primary_key >= MAX_KEY || + !(index_flags(primary_key) & HA_READ_ORDER)) + { + (void) rnd_init(); + while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ; + (void) rnd_end(); + } + else + { + /* Find the first row through the primary key */ + (void) index_init(primary_key); + error=index_first(buf); + (void) index_end(); + } DBUG_RETURN(error); } @@ -641,7 +614,7 @@ int handler::restart_rnd_next(byte *buf, byte *pos) } - /* Set a timestamp in record */ +/* Set a timestamp in record */ void handler::update_timestamp(byte *record) { @@ -657,9 +630,10 @@ void handler::update_timestamp(byte *record) return; } - /* Updates field with field_type NEXT_NUMBER according to following: - ** if field = 0 change field to the next free key in database. - */ +/* + Updates field with field_type NEXT_NUMBER according to following: + if field = 0 change field to the next free key in database. +*/ void handler::update_auto_increment() { @@ -687,16 +661,29 @@ longlong handler::get_auto_increment() { longlong nr; int error; + (void) extra(HA_EXTRA_KEYREAD); index_init(table->next_number_index); - error=index_last(table->record[1]); + if (!table->next_number_key_offset) + { // Autoincrement at key-start + error=index_last(table->record[1]); + } + else + { + byte key[MAX_KEY_LENGTH]; + key_copy(key,table,table->next_number_index, + table->next_number_key_offset); + error=index_read(table->record[1], key, table->next_number_key_offset, + HA_READ_PREFIX_LAST); + } + if (error) nr=1; else nr=(longlong) table->next_number_field-> val_int_offset(table->rec_buff_length)+1; - (void) extra(HA_EXTRA_NO_KEYREAD); index_end(); + (void) extra(HA_EXTRA_NO_KEYREAD); return nr; } @@ -842,22 +829,6 @@ int handler::rename_table(const char * from, const char * to) DBUG_RETURN(0); } -int ha_commit_rename(THD *thd) -{ - int error=0; -#ifdef HAVE_GEMINI_DB - /* Gemini needs to commit the rename; otherwise a rollback will change - ** the table names back internally but the physical files will still - ** have the new names. - */ - if (ha_commit_stmt(thd)) - error= -1; - if (ha_commit(thd)) - error= -1; -#endif - return error; -} - /* Tell the handler to turn on or off logging to the handler's recovery log */ @@ -866,14 +837,6 @@ int ha_recovery_logging(THD *thd, bool on) int error=0; DBUG_ENTER("ha_recovery_logging"); -#ifdef USING_TRANSACTIONS - if (opt_using_transactions) - { -#ifdef HAVE_GEMINI_DB - error = gemini_recovery_logging(thd, on); -#endif - } -#endif DBUG_RETURN(error); } @@ -893,8 +856,10 @@ int handler::index_next_same(byte *buf, const byte *key, uint keylen) /* - The following is only needed if we would like to use the database - for internal temporary tables + This is called to delete all rows in a table + If the handler don't support this, then this function will + return HA_ERR_WRONG_COMMAND and MySQL will delete the rows one + by one. */ int handler::delete_all_rows() @@ -922,19 +887,21 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info, if (update_create_info) { update_create_info_from_table(create_info, &table); - if (table.file->option_flag() & HA_DROP_BEFORE_CREATE) + if (table.file->table_flags() & HA_DROP_BEFORE_CREATE) table.file->delete_table(name); // Needed for BDB tables } error=table.file->create(name,&table,create_info); VOID(closefrm(&table)); - if (error) { - if (table.db_type == DB_TYPE_INNOBASE) { + if (error) + { + if (table.db_type == DB_TYPE_INNODB) + { /* Creation of InnoDB table cannot fail because of an OS error: put error as the number */ my_error(ER_CANT_CREATE_TABLE,MYF(ME_BELL+ME_WAITTANG),name,error); - } else { - my_error(ER_CANT_CREATE_TABLE,MYF(ME_BELL+ME_WAITTANG),name,my_errno); } + else + my_error(ER_CANT_CREATE_TABLE,MYF(ME_BELL+ME_WAITTANG),name,my_errno); } DBUG_RETURN(error != 0); } @@ -944,13 +911,25 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info, void ha_key_cache(void) { if (keybuff_size) - (void) init_key_cache(keybuff_size,0); -} /* ha_key_cache */ + (void) init_key_cache(keybuff_size); +} + + +void ha_resize_key_cache(void) +{ + (void) resize_key_cache(keybuff_size); +} static int NEAR_F delete_file(const char *name,const char *ext,int extflag) { char buff[FN_REFLEN]; VOID(fn_format(buff,name,"",ext,extflag | 4)); - return(my_delete(buff,MYF(MY_WME))); + return(my_delete_with_symlink(buff,MYF(MY_WME))); +} + +void st_ha_check_opt::init() +{ + flags= sql_flags= 0; + sort_buffer_size = current_thd->variables.myisam_sort_buff_size; } |