diff options
author | unknown <monty@hundin.mysql.fi> | 2002-08-08 15:24:47 +0300 |
---|---|---|
committer | unknown <monty@hundin.mysql.fi> | 2002-08-08 15:24:47 +0300 |
commit | 267b80834ad524c0d72976bc71e5b5bc9815ea1a (patch) | |
tree | e7f4a2013ed3d66e640f6574e62cb7e534a5d77f /sql | |
parent | ca1875f54033c5ea067ec3ec07b00375de6975d7 (diff) | |
parent | 40d3c3901b0427eba76119730f46784f946990b3 (diff) | |
download | mariadb-git-267b80834ad524c0d72976bc71e5b5bc9815ea1a.tar.gz |
merge with 3.23.52
BitKeeper/etc/logging_ok:
auto-union
configure.in:
Auto merged
Docs/manual.texi:
Auto merged
include/my_pthread.h:
Auto merged
include/mysql_com.h:
Auto merged
include/mysql_version.h.in:
Auto merged
innobase/btr/btr0cur.c:
Auto merged
innobase/btr/btr0sea.c:
Auto merged
innobase/buf/buf0buf.c:
Auto merged
innobase/buf/buf0lru.c:
Auto merged
innobase/configure.in:
Auto merged
innobase/dict/dict0dict.c:
Auto merged
innobase/fil/fil0fil.c:
Auto merged
innobase/fsp/fsp0fsp.c:
Auto merged
innobase/include/buf0buf.ic:
Auto merged
innobase/include/dyn0dyn.ic:
Auto merged
innobase/include/ha0ha.ic:
Auto merged
innobase/include/sync0rw.ic:
Auto merged
innobase/include/univ.i:
Auto merged
innobase/lock/lock0lock.c:
Auto merged
innobase/log/log0log.c:
Auto merged
innobase/mem/mem0dbg.c:
Auto merged
innobase/os/os0file.c:
Auto merged
innobase/os/os0thread.c:
Auto merged
innobase/page/page0cur.c:
Auto merged
innobase/srv/srv0srv.c:
Auto merged
innobase/sync/sync0arr.c:
Auto merged
innobase/sync/sync0rw.c:
Auto merged
innobase/sync/sync0sync.c:
Auto merged
innobase/trx/trx0trx.c:
Auto merged
myisam/mi_create.c:
Auto merged
sql/ha_innodb.h:
Auto merged
sql/lex.h:
Auto merged
sql/log.cc:
Auto merged
sql/mysqld.cc:
Auto merged
sql/sql_acl.cc:
Auto merged
sql/sql_insert.cc:
Auto merged
strings/Makefile.am:
Auto merged
support-files/mysql.server.sh:
Auto merged
include/my_base.h:
merge with 3.23.52 (use local file)
include/sslopt-usage.h:
merge with 3.23.52 (use local file)
myisam/mi_search.c:
merge with 3.23.52 (use local file)
myisam/mi_write.c:
merge with 3.23.52 (use local file)
mysql-test/r/group_by.result:
merge with 3.23.52
(Need to be fixed before push)
mysys/my_pthread.c:
merge with 3.23.52 (use local file)
sql/gen_lex_hash.cc:
merge with 3.23.52 (use local file)
sql/ha_innodb.cc:
Total hand-merge with 3.23.52
sql/sql_yacc.yy:
merge with 3.23.52 (use local file)
support-files/mysql.spec.sh:
merge with 3.23.52 (use local file)
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_innodb.cc | 369 | ||||
-rw-r--r-- | sql/ha_innodb.h | 3 | ||||
-rw-r--r-- | sql/lex.h | 4 | ||||
-rw-r--r-- | sql/log.cc | 10 | ||||
-rw-r--r-- | sql/mysqld.cc | 14 | ||||
-rw-r--r-- | sql/sql_acl.cc | 7 | ||||
-rw-r--r-- | sql/sql_base.cc | 40 | ||||
-rw-r--r-- | sql/sql_insert.cc | 5 | ||||
-rw-r--r-- | sql/sql_select.cc | 2 | ||||
-rw-r--r-- | sql/sql_show.cc | 4 | ||||
-rw-r--r-- | sql/sql_table.cc | 16 |
11 files changed, 323 insertions, 151 deletions
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index c82b4faf3f5..06931532f51 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & InnoDB Oy +/* Copyright (C) 2000 MySQL AB & Innobase Oy 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 @@ -55,6 +55,7 @@ typedef byte mysql_byte; extern "C" { #include "../innobase/include/univ.i" #include "../innobase/include/os0file.h" +#include "../innobase/include/os0thread.h" #include "../innobase/include/srv0start.h" #include "../innobase/include/srv0srv.h" #include "../innobase/include/trx0roll.h" @@ -110,8 +111,6 @@ my_bool innobase_fast_shutdown = TRUE; specify any startup options. */ -/* innobase_data_file_path=ibdata:15,idata2:1,... */ - char *innobase_data_file_path= (char*) "ibdata1:10M:autoextend"; static char *internal_innobase_data_file_path=0; @@ -138,8 +137,9 @@ 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. */ +Releases possible search latch and InnoDB thread FIFO ticket. These should +be released at each SQL statement end. It does no harm to release these +also in the middle of an SQL statement. */ static void innobase_release_stat_resources( @@ -150,16 +150,6 @@ innobase_release_stat_resources( 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 */ @@ -646,6 +636,16 @@ innobase_commit( trx = check_trx_exists(thd); + 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_handle != (void*)&innodb_dummy_stmt_trx_handle) { innobase_commit_low(trx); } @@ -714,6 +714,16 @@ innobase_rollback( trx = check_trx_exists(thd); + 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); + } + srv_conc_enter_innodb(trx); if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) { @@ -842,7 +852,7 @@ normalize_table_name( } /********************************************************************* -Creates and opens a handle to a table which already exists in an Innobase +Creates and opens a handle to a table which already exists in an InnoDB database. */ int @@ -913,13 +923,13 @@ have moved .frm files to another database?", primary_key = MAX_KEY; - if (!row_table_got_default_clust_index(ib_table)) { + /* Allocate a buffer for a 'row reference'. A row reference is + a string of bytes of length ref_length which uniquely specifies + a row in our table. Note that MySQL may also compare two row + references for equality by doing a simple memcmp on the strings + of length ref_length! */ - /* If we automatically created the clustered index, - then MySQL does not know about it and it must not be aware - of the index used on scan, to avoid checking if we update - the column of the index. The column is the row id in - the automatical case, and it will not be updated. */ + if (!row_table_got_default_clust_index(ib_table)) { ((row_prebuilt_t*)innobase_prebuilt) ->clust_index_was_generated = FALSE; @@ -928,13 +938,13 @@ have moved .frm files to another database?", key_used_on_scan = 0; /* - MySQL allocates the buffer for ref. - This includes all keys + one byte for each column - that may be NULL. - The ref_length must be exact as possible as - all reference buffers are allocated based on this. + MySQL allocates the buffer for ref. key_info->key_length + includes space for all key columns + one byte for each column + that may be NULL. ref_length must be as exact as possible to + save space, because all row reference buffers are allocated + based on ref_length. */ - + ref_length = table->key_info->key_length; } else { ((row_prebuilt_t*)innobase_prebuilt) @@ -942,6 +952,15 @@ have moved .frm files to another database?", ref_length = DATA_ROW_ID_LEN; + /* + If we automatically created the clustered index, then + MySQL does not know about it, and MySQL must NOT be aware + of the index used on scan, to make it avoid checking if we + update the column of the index. That is why we assert below + that key_used_on_scan is the undefined value MAX_KEY. + The column is the row id in the automatical generation case, + and it will never be updated anyway. + */ DBUG_ASSERT(key_used_on_scan == MAX_KEY); } @@ -1188,7 +1207,8 @@ get_innobase_type_from_mysql_type( } /*********************************************************************** -Stores a key value for a row to a buffer. */ +Stores a key value for a row to a buffer. This must currently only be used +to store a row reference to the 'ref' buffer of this table handle! */ uint ha_innobase::store_key_val_for_row( @@ -1196,7 +1216,8 @@ ha_innobase::store_key_val_for_row( /* out: key value length as stored in buff */ uint keynr, /* in: key number */ char* buff, /* in/out: buffer for the key value (in MySQL - format) */ + format); currently this MUST be the 'ref' + buffer! */ const mysql_byte* record)/* in: row in MySQL format */ { KEY* key_info = table->key_info + keynr; @@ -1225,8 +1246,9 @@ ha_innobase::store_key_val_for_row( } /* - We have to zero-fill the buffer to be able to compare two - keys to see if they are equal + We have to zero-fill the 'ref' buffer so that MySQL is able to + use a simple memcmp to compare two key values to determine if they + are equal */ bzero(buff, (ref_length- (uint) (buff - buff_start))); DBUG_RETURN(ref_length); @@ -1404,6 +1426,7 @@ ha_innobase::write_row( row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt; int error; longlong auto_inc; + longlong dummy; DBUG_ENTER("ha_innobase::write_row"); @@ -1426,7 +1449,31 @@ ha_innobase::write_row( if (table->next_number_field && record == table->record[0]) { /* This is the case where the table has an auto-increment column */ - + + /* Initialize the auto-inc counter if it has not been + initialized yet */ + + if (0 == dict_table_autoinc_peek(prebuilt->table)) { + + /* This call initializes the counter */ + error = innobase_read_and_init_auto_inc(&dummy); + + if (error) { + /* Deadlock or lock wait timeout */ + + goto func_exit; + } + + /* We have to set sql_stat_start to TRUE because + the above call probably has called a select, and + has reset that flag; row_insert_for_mysql has to + know to set the IX intention lock on the table, + something it only does at the start of each + statement */ + + prebuilt->sql_stat_start = TRUE; + } + /* Fetch the value the user possibly has set in the autoincrement field */ @@ -1459,10 +1506,9 @@ ha_innobase::write_row( } if (auto_inc != 0) { - /* This call will calculate the max of the - current value and the value supplied by the user, if - the auto_inc counter is already initialized - for the table */ + /* This call will calculate the max of the current + value and the value supplied by the user and + update the counter accordingly */ /* We have to use the transactional lock mechanism on the auto-inc counter of the table to ensure @@ -1502,46 +1548,18 @@ ha_innobase::write_row( auto_inc = dict_table_autoinc_get(prebuilt->table); srv_conc_exit_innodb(prebuilt->trx); - /* If auto_inc is now != 0 the autoinc counter - was already initialized for the table: we can give - the new value for MySQL to place in the field */ - - if (auto_inc != 0) { - user_thd->next_insert_id = auto_inc; - } - } - - update_auto_increment(); - - if (auto_inc == 0) { - /* The autoinc counter for our table was not yet - initialized, initialize it now */ - - auto_inc = table->next_number_field->val_int(); + /* We can give the new value for MySQL to place in + the field */ - srv_conc_enter_innodb(prebuilt->trx); - error = row_lock_table_autoinc_for_mysql(prebuilt); - srv_conc_exit_innodb(prebuilt->trx); - - if (error != DB_SUCCESS) { - - error = convert_error_code_to_mysql(error, - user_thd); - goto func_exit; - } - - dict_table_autoinc_initialize(prebuilt->table, - auto_inc); + user_thd->next_insert_id = auto_inc; } - /* We have to set sql_stat_start to TRUE because - update_auto_increment may have called a select, and - has reset that flag; row_insert_for_mysql has to - know to set the IX intention lock on the table, something - it only does at the start of each statement */ + /* This call of a handler.cc function places + user_thd->next_insert_id to the column value, if the column + value was not set by the user */ - prebuilt->sql_stat_start = TRUE; - } + update_auto_increment(); + } if (prebuilt->mysql_template == NULL || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) { @@ -1901,6 +1919,55 @@ convert_search_mode_to_innobase( return(0); } +/* + BACKGROUND INFO: HOW A SELECT SQL QUERY IS EXECUTED + --------------------------------------------------- +The following does not cover all the details, but explains how we determine +the start of a new SQL statement, and what is associated with it. + +For each table in the database the MySQL interpreter may have several +table handle instances in use, also in a single SQL query. For each table +handle instance there is an InnoDB 'prebuilt' struct which contains most +of the InnoDB data associated with this table handle instance. + + A) if the user has not explicitly set any MySQL table level locks: + + 1) MySQL calls ::external_lock to set an 'intention' table level lock on +the table of the handle instance. There we set +prebuilt->sql_stat_start = TRUE. The flag sql_stat_start should be set +true if we are taking this table handle instance to use in a new SQL +statement issued by the user. We also increment trx->n_mysql_tables_in_use. + + 2) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search +instructions to prebuilt->template of the table handle instance in +::index_read. The template is used to save CPU time in large joins. + + 3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we +allocate a new consistent read view for the trx if it does not yet have one, +or in the case of a locking read, set an InnoDB 'intention' table level +lock on the table. + + 4) We do the SELECT. MySQL may repeatedly call ::index_read for the +same table handle instance, if it is a join. + + 5) When the SELECT ends, MySQL removes its intention table level locks +in ::external_lock. When trx->n_mysql_tables_in_use drops to zero, + (a) we execute a COMMIT there if the autocommit is on, + (b) we also release possible 'SQL statement level resources' InnoDB may +have for this SQL statement. The MySQL interpreter does NOT execute +autocommit for pure read transactions, though it should. That is why the +table handler in that case has to execute the COMMIT in ::external_lock. + + B) If the user has explicitly set MySQL table level locks, then MySQL +does NOT call ::external_lock at the start of the statement. To determine +when we are at the start of a new SQL statement we at the start of +::index_read also compare the query id to the latest query id where the +table handle instance was used. If it has changed, we know we are at the +start of a new SQL statement. Since the query id can theoretically +overwrap, we use this test only as a secondary way of determining the +start of a new SQL statement. */ + + /************************************************************************** Positions an index cursor to the index specified in the handle. Fetches the row if any. */ @@ -1914,7 +1981,10 @@ ha_innobase::index_read( row */ const mysql_byte* key_ptr,/* in: key value; if this is NULL we position the cursor at the - start or end of index */ + start or end of index; this can + also contain an InnoDB row id, in + which case key_len is the InnoDB + row id length */ uint key_len,/* in: key value length */ enum ha_rkey_function find_flag)/* in: search flags from my_base.h */ { @@ -1941,10 +2011,8 @@ ha_innobase::index_read( index = prebuilt->index; - /* Note that if the select is used for an update, we always - fetch the clustered index record: therefore the index for which the - template is built is not necessarily prebuilt->index, but can also - be the clustered index */ + /* Note that if the index for which the search template is built is not + necessarily prebuilt->index, but can also be the clustered index */ if (prebuilt->sql_stat_start) { build_template(prebuilt, user_thd, table, @@ -1952,6 +2020,9 @@ ha_innobase::index_read( } if (key_ptr) { + /* Convert the search key value to InnoDB format into + prebuilt->search_tuple */ + row_sel_convert_mysql_key_to_innobase(prebuilt->search_tuple, (byte*) key_val_buff, index, @@ -2313,8 +2384,7 @@ ha_innobase::rnd_next( } /************************************************************************** -Fetches a row from the table based on a reference. TODO: currently we use -'ref_stored_len' of the handle as the key length. This may change. */ +Fetches a row from the table based on a row reference. */ int ha_innobase::rnd_pos( @@ -2322,7 +2392,11 @@ ha_innobase::rnd_pos( /* out: 0, HA_ERR_KEY_NOT_FOUND, or error code */ mysql_byte* buf, /* in/out: buffer for the row */ - mysql_byte* pos) /* in: primary key value in MySQL format */ + mysql_byte* pos) /* in: primary key value of the row in the + MySQL format, or the row id if the clustered + index was internally generated by InnoDB; + the length of data in pos has to be + ref_length */ { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; int error; @@ -2339,7 +2413,7 @@ ha_innobase::rnd_pos( /* No primary key was defined for the table and we generated the clustered index from the row id: the row reference is the row id, not any key value - that MySQL knows */ + that MySQL knows of */ error = change_active_index(MAX_KEY); } else { @@ -2351,7 +2425,10 @@ ha_innobase::rnd_pos( DBUG_RETURN(error); } - error = index_read(buf, pos, ref_stored_len, HA_READ_KEY_EXACT); + /* Note that we assume the length of the row reference is fixed + for the table, and it is == ref_length */ + + error = index_read(buf, pos, ref_length, HA_READ_KEY_EXACT); if (error) { DBUG_PRINT("error",("Got error: %ld",error)); @@ -2363,8 +2440,8 @@ ha_innobase::rnd_pos( /************************************************************************* Stores a reference to the current row to 'ref' field of the handle. Note -that the function parameter is illogical: we must assume that 'record' -is the current 'position' of the handle, because if row ref is actually +that in the case where we have generated the clustered index for the +table, the function parameter is illogical: we MUST ASSUME that 'record' the row id internally generated in InnoDB, then 'record' does not contain it. We just guess that the row id must be for the record where the handle was positioned the last time. */ @@ -2384,7 +2461,7 @@ ha_innobase::position( /* No primary key was defined for the table and we generated the clustered index from row id: the row reference will be the row id, not any key value - that MySQL knows */ + that MySQL knows of */ len = DATA_ROW_ID_LEN; @@ -2393,8 +2470,11 @@ ha_innobase::position( len = store_key_val_for_row(primary_key, (char*) ref, record); } - DBUG_ASSERT(len == ref_length); - ref_stored_len = len; + /* Since we do not store len to the buffer 'ref', we must assume + that len is always fixed for this table. The following assertion + checks this. */ + + ut_a(len == ref_length); } @@ -2612,7 +2692,7 @@ ha_innobase::create( /* Our function row_get_mysql_key_number_for_index assumes the primary key is always number 0, if it exists */ - assert(primary_key_no == -1 || primary_key_no == 0); + DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0); /* Create the keys */ @@ -2693,7 +2773,7 @@ ha_innobase::create( innobase_table = dict_table_get(norm_name, NULL); - assert(innobase_table != 0); + DBUG_ASSERT(innobase_table != 0); /* Tell the InnoDB server that there might be work for utility threads: */ @@ -3519,37 +3599,53 @@ ha_innobase::store_lock( } /*********************************************************************** -Returns the next auto-increment column value for the table. write_row -normally fetches the value from the cache in the data dictionary. This -function in used by SHOW TABLE STATUS and when the first insert to the table -is done after database startup. */ +This function initializes the auto-inc counter if it has not been +initialized yet. This function does not change the value of the auto-inc +counter if it already has been initialized. In parameter ret returns +the value of the auto-inc counter. */ -longlong -ha_innobase::get_auto_increment() -/*=============================*/ - /* out: the next auto-increment column value */ +int +ha_innobase::innobase_read_and_init_auto_inc( +/*=========================================*/ + /* out: 0 or error code: deadlock or + lock wait timeout */ + longlong* ret) /* out: auto-inc value */ { row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; - longlong nr; + longlong auto_inc; int error; + ut_a(prebuilt); ut_a(prebuilt->trx == (trx_t*) current_thd->transaction.all.innobase_tid); + ut_a(prebuilt->table); + + auto_inc = dict_table_autoinc_read(prebuilt->table); - /* Also SHOW TABLE STATUS calls this function. Previously, when we did - always read the max autoinc key value, setting x-locks, users were - surprised that SHOW TABLE STATUS could end up in a deadlock with - ordinary SQL queries. We avoid these deadlocks if the auto-inc - counter for the table has been initialized by fetching the value - from the table struct in dictionary cache. */ + if (auto_inc != 0) { + /* Already initialized */ + *ret = auto_inc; + + return(0); + } - assert(prebuilt->table); - - nr = dict_table_autoinc_read(prebuilt->table); + srv_conc_enter_innodb(prebuilt->trx); + error = row_lock_table_autoinc_for_mysql(prebuilt); + srv_conc_exit_innodb(prebuilt->trx); + + if (error != DB_SUCCESS) { + error = convert_error_code_to_mysql(error, user_thd); - if (nr != 0) { + goto func_exit; + } - return(nr + 1); + /* Check again if someone has initialized the counter meanwhile */ + auto_inc = dict_table_autoinc_read(prebuilt->table); + + if (auto_inc != 0) { + *ret = auto_inc; + + return(0); } (void) extra(HA_EXTRA_KEYREAD); @@ -3569,22 +3665,63 @@ ha_innobase::get_auto_increment() prebuilt->hint_no_need_to_fetch_extra_cols = FALSE; - prebuilt->trx->mysql_n_tables_locked += 1; + prebuilt->trx->mysql_n_tables_locked += 1; - error = index_last(table->record[1]); + error = index_last(table->record[1]); if (error) { - nr = 1; + if (error == HA_ERR_END_OF_FILE) { + /* The table was empty, initialize to 1 */ + auto_inc = 1; + + error = 0; + } else { + /* Deadlock or a lock wait timeout */ + auto_inc = -1; + + goto func_exit; + } } else { - nr = (longlong) table->next_number_field-> + /* Initialize to max(col) + 1 */ + auto_inc = (longlong) table->next_number_field-> val_int_offset(table->rec_buff_length) + 1; } + dict_table_autoinc_initialize(prebuilt->table, auto_inc); + +func_exit: (void) extra(HA_EXTRA_NO_KEYREAD); - index_end(); + index_end(); + + *ret = auto_inc; + + return(error); +} + +/*********************************************************************** +This function initializes the auto-inc counter if it has not been +initialized yet. This function does not change the value of the auto-inc +counter if it already has been initialized. Returns the value of the +auto-inc counter. */ + +longlong +ha_innobase::get_auto_increment() +/*=============================*/ + /* out: auto-increment column value, -1 if error + (deadlock or lock wait timeout) */ +{ + longlong nr; + int error; + + error = innobase_read_and_init_auto_inc(&nr); + + if (error) { + + return(-1); + } - return(nr); + return(nr); } #endif /* HAVE_INNOBASE_DB */ diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index a9a7c9997ad..3d5db845fc6 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -52,8 +52,6 @@ class ha_innobase: public handler byte* key_val_buff; /* buffer used in converting search key values from MySQL format to Innodb format */ - uint ref_stored_len; /* length of the key value stored to - 'ref' buffer of the handle, if any */ ulong int_table_flags; uint primary_key; uint last_dup_key; @@ -71,6 +69,7 @@ class ha_innobase: public handler int update_thd(THD* thd); int change_active_index(uint keynr); int general_fetch(byte* buf, uint direction, uint match_mode); + int innobase_read_and_init_auto_inc(longlong* ret); /* Init values for the class: */ public: diff --git a/sql/lex.h b/sql/lex.h index 39298323d75..1f7a121e262 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -251,7 +251,7 @@ static SYMBOL symbols[] = { { "NEW", SYM(NEW_SYM),0,0}, { "NCHAR", SYM(NCHAR_SYM),0,0}, { "NO", SYM(NO_SYM),0,0}, - { "NO_FOREIGN_KEY_CHECKS", SYM(NO_FOREIGN_KEY_CHECKS), 0, 0}, + { "FOREIGN_KEY_CHECKS", SYM(FOREIGN_KEY_CHECKS), 0, 0}, { "NOT", SYM(NOT),0,0}, { "NULL", SYM(NULL_SYM),0,0}, { "NUMERIC", SYM(NUMERIC_SYM),0,0}, @@ -285,7 +285,7 @@ static SYMBOL symbols[] = { { "RELAY_LOG_POS", SYM(RELAY_LOG_POS_SYM),0,0}, { "RELOAD", SYM(RELOAD),0,0}, { "REGEXP", SYM(REGEXP),0,0}, - { "RELAXED_UNIQUE_CHECKS", SYM(RELAXED_UNIQUE_CHECKS), 0, 0}, + { "UNIQUE_CHECKS", SYM(UNIQUE_CHECKS), 0, 0}, { "RENAME", SYM(RENAME),0,0}, { "REPAIR", SYM(REPAIR),0,0}, { "REPLACE", SYM(REPLACE),0,0}, diff --git a/sql/log.cc b/sql/log.cc index 19f2db8403b..b6a07d9021f 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1320,16 +1320,16 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, if (end != buff) { *end++=';'; - *end++='\n'; - *end=0; + *end='\n'; if (my_b_write(&log_file, (byte*) "SET ",4) || - my_b_write(&log_file, (byte*) buff+1,(uint) (end-buff)-1)) + my_b_write(&log_file, (byte*) buff+1,(uint) (end-buff))) tmp_errno=errno; } if (!query) { - query="#adminstrator command"; - query_length=21; + end=strxmov(buff, "# administrator command: ", + command_name[thd->command], NullS); + query_length=(ulong) (end-buff); } if (my_b_write(&log_file, (byte*) query,query_length) || my_b_write(&log_file, (byte*) ";\n",2) || diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ffa606272e3..829614fdb2c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1809,7 +1809,7 @@ int main(int argc, char **argv) exit( 1 ); } #endif - load_defaults("my",load_default_groups,&argc,&argv); + load_defaults(MYSQL_CONFIG_NAME,load_default_groups,&argc,&argv); defaults_argv=argv; /* Get default temporary directory */ @@ -2373,7 +2373,15 @@ static void create_new_thread(THD *thd) for (uint i=0; i < 8 ; i++) // Generate password teststring thd->scramble[i]= (char) (rnd(&sql_rand)*94+33); thd->scramble[8]=0; - thd->rand=sql_rand; + /* + We need good random number initialization for new thread + Just coping global one will not work + */ + { + ulong tmp=(ulong) (rnd(&sql_rand) * 3000000); + randominit(&(thd->rand), tmp + (ulong) start_time, + tmp + (ulong) thread_id); + } thd->real_id=pthread_self(); // Keep purify happy /* Start a new thread to handle connection */ @@ -3805,7 +3813,7 @@ Starts the MySQL server\n"); "); puts(""); #endif - print_defaults("my",load_default_groups); + print_defaults(MYSQL_CONFIG_NAME,load_default_groups); puts(""); fix_paths(); set_ports(); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index e2d462aa73c..aad37477a70 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -253,7 +253,7 @@ int acl_init(bool dont_read_acl_tables) continue; /* purecov: tested */ } get_salt_from_password(user.salt,user.password); - user.access=get_access(table,3); + user.access=get_access(table,3) & GLOBAL_ACLS; user.sort=get_sort(2,user.host.hostname,user.user); user.hostname_length= (user.host.hostname ? (uint) strlen(user.host.hostname) : 0); @@ -321,6 +321,11 @@ int acl_init(bool dont_read_acl_tables) ACL_DB db; update_hostname(&db.host,get_field(&mem, table,0)); db.db=get_field(&mem, table,1); + if (!db.db) + { + sql_print_error("Found an entry in the 'db' table with empty database name; Skipped"); + continue; + } db.user=get_field(&mem, table,2); db.access=get_access(table,3); db.access=fix_rights_for_db(db.access); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 58d251162ff..0f540a3a4fd 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -32,7 +32,7 @@ TABLE *unused_tables; /* Used by mysql_test */ HASH open_cache; /* Used by mysql_test */ static int open_unireg_entry(THD *thd,TABLE *entry,const char *db, - const char *name, const char *alias, bool locked); + const char *name, const char *alias); static void free_cache_entry(TABLE *entry); static void mysql_rm_tmp_tables(void); static key_map get_key_map_from_key_list(TABLE *table, @@ -275,6 +275,16 @@ void intern_close_table(TABLE *table) VOID(closefrm(table)); // close file } +/* + Remove table from the open table cache + + SYNOPSIS + free_cache_entry() + table Table to remove + + NOTE + We need to have a lock on LOCK_open when calling this +*/ static void free_cache_entry(TABLE *table) { @@ -709,7 +719,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list) key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1; pthread_mutex_lock(&LOCK_open); - if (open_unireg_entry(thd, table, db, table_name, table_name, 1) || + if (open_unireg_entry(thd, table, db, table_name, table_name) || !(table->table_cache_key =memdup_root(&table->mem_root,(char*) key, key_length))) { @@ -842,8 +852,11 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, /* make a new table */ if (!(table=(TABLE*) my_malloc(sizeof(*table),MYF(MY_WME)))) + { + VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_RETURN(NULL); - if (open_unireg_entry(thd, table,db,table_name,alias,1) || + } + if (open_unireg_entry(thd, table,db,table_name,alias) || !(table->table_cache_key=memdup_root(&table->mem_root,(char*) key, key_length))) { @@ -934,8 +947,7 @@ bool reopen_table(TABLE *table,bool locked) VOID(pthread_mutex_lock(&LOCK_open)); safe_mutex_assert_owner(&LOCK_open); - if (open_unireg_entry(current_thd,&tmp,db,table_name,table->table_name, - locked)) + if (open_unireg_entry(current_thd,&tmp,db,table_name,table->table_name)) goto end; free_io_cache(table); @@ -1176,7 +1188,6 @@ bool wait_for_tables(THD *thd) /* Now we can open all tables without any interference */ thd->proc_info="Reopen tables"; result=reopen_tables(thd,0,0); - } pthread_mutex_unlock(&LOCK_open); thd->proc_info=0; @@ -1241,7 +1252,7 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name) */ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, - const char *name, const char *alias, bool locked) + const char *name, const char *alias) { char path[FN_REFLEN]; int error; @@ -1261,23 +1272,17 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, table_list.db=(char*) db; table_list.name=(char*) name; table_list.next=0; - if (!locked) - pthread_mutex_lock(&LOCK_open); safe_mutex_assert_owner(&LOCK_open); if ((error=lock_table_name(thd,&table_list))) { if (error < 0) { - if (!locked) - pthread_mutex_unlock(&LOCK_open); goto err; } if (wait_for_locked_table_names(thd,&table_list)) { unlock_table_name(thd,&table_list); - if (!locked) - pthread_mutex_unlock(&LOCK_open); goto err; } } @@ -1307,9 +1312,9 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, thd->net.last_error[0]=0; // Clear error message thd->net.last_errno=0; } - if (locked) - pthread_mutex_lock(&LOCK_open); // Get back original lock + pthread_mutex_lock(&LOCK_open); unlock_table_name(thd,&table_list); + if (error) goto err; } @@ -1368,9 +1373,9 @@ int open_tables(THD *thd,TABLE_LIST *start) } } *prev_table=0; + pthread_mutex_unlock(&LOCK_open); if (found) VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh - pthread_mutex_unlock(&LOCK_open); goto restart; } result= -1; // Fatal error @@ -2207,6 +2212,7 @@ int setup_ftfuncs(THD *thd) return 0; } + int init_ftfuncs(THD *thd, bool no_order) { if (thd->lex.select->ftfunc_list.elements) @@ -2217,9 +2223,7 @@ int init_ftfuncs(THD *thd, bool no_order) thd->proc_info="FULLTEXT initialization"; while ((ifm=li++)) - { ifm->init_search(no_order); - } } return 0; } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 61d3544bfe0..e7a85c8262a 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1454,6 +1454,11 @@ bool select_create::send_eof() table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); VOID(pthread_mutex_lock(&LOCK_open)); mysql_unlock_tables(thd, lock); + /* + TODO: + Check if we can remove the following two rows. + We should be able to just keep the table in the table cache. + */ if (!table->tmp_table) hash_delete(&open_cache,(byte*) table); lock=0; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5a5745f87cd..169f95cc66b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3674,7 +3674,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, field_count= (uint) (reg_field - table->field); /* If result table is small; use a heap */ - if (blob_count || using_unique_constraint || + if (blob_count || using_unique_constraint || group_null_items || (select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) == OPTION_BIG_TABLES) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 24f5ddeab7a..6041132bd20 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -124,13 +124,15 @@ int mysqld_show_open_tables(THD *thd,const char *wild) net_store_data(&thd->packet,open_list->in_use); net_store_data(&thd->packet,open_list->locked); if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) + { DBUG_RETURN(-1); + } } - send_eof(&thd->net); DBUG_RETURN(0); } + /*************************************************************************** ** List all tables in a database (fast version) ** A table is a .frm file in the current databasedir diff --git a/sql/sql_table.cc b/sql/sql_table.cc index df84bff0adc..f58201ae429 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -782,7 +782,9 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, table->reginfo.lock_type=TL_WRITE; if (!((*lock)=mysql_lock_tables(thd,&table,1))) { + VOID(pthread_mutex_lock(&LOCK_open)); hash_delete(&open_cache,(byte*) table); + VOID(pthread_mutex_unlock(&LOCK_open)); quick_rm_table(create_info->db_type,db,name); DBUG_RETURN(0); } @@ -977,19 +979,25 @@ static int prepare_for_repair(THD* thd, TABLE_LIST* table, if (my_rename(from, tmp, MYF(MY_WME))) { + pthread_mutex_lock(&LOCK_open); unlock_table_name(thd, table); + pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(send_check_errmsg(thd, table, "repair", "Failed renaming .MYD file")); } if (mysql_truncate(thd, table, 1)) { + pthread_mutex_lock(&LOCK_open); unlock_table_name(thd, table); + pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(send_check_errmsg(thd, table, "repair", "Failed generating table from .frm file")); } if (my_rename(tmp, from, MYF(MY_WME))) { + pthread_mutex_lock(&LOCK_open); unlock_table_name(thd, table); + pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(send_check_errmsg(thd, table, "repair", "Failed restoring .MYD file")); } @@ -1000,7 +1008,11 @@ static int prepare_for_repair(THD* thd, TABLE_LIST* table, to finish the repair in the handler later on. */ if (!(table->table = reopen_name_locked_table(thd, table))) - unlock_table_name(thd, table); + { + pthread_mutex_lock(&LOCK_open); + unlock_table_name(thd, table); + pthread_mutex_unlock(&LOCK_open); + } DBUG_RETURN(0); } @@ -1855,8 +1867,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, error=1; if (error) { - VOID(pthread_cond_broadcast(&COND_refresh)); VOID(pthread_mutex_unlock(&LOCK_open)); + VOID(pthread_cond_broadcast(&COND_refresh)); goto err; } #ifdef HAVE_BERKELEY_DB |