diff options
author | unknown <monty@mysql.com> | 2004-06-25 20:13:05 +0300 |
---|---|---|
committer | unknown <monty@mysql.com> | 2004-06-25 20:13:05 +0300 |
commit | c6e23c85493688417c0274b4630a6b7c44f59d10 (patch) | |
tree | 983268d5f30394d4fa4ffdd75cd095f6227e5170 /sql | |
parent | 4e664e3e43b1b0e2a37eadb8a6e28142db444352 (diff) | |
parent | 07589a6da51e7fb0b741cfca025202341bfa64e6 (diff) | |
download | mariadb-git-c6e23c85493688417c0274b4630a6b7c44f59d10.tar.gz |
Merge with 4.0 to get the latest bug patches to 4.1
BitKeeper/etc/ignore:
added sql/mysql_tzinfo_to_sql
BitKeeper/etc/logging_ok:
auto-union
acinclude.m4:
Auto merged
extra/perror.c:
Auto merged
include/mysql.h:
Auto merged
innobase/include/mach0data.ic:
Auto merged
innobase/include/mtr0log.h:
Auto merged
innobase/include/mtr0log.ic:
Auto merged
innobase/mem/mem0dbg.c:
Auto merged
innobase/pars/lexyy.c:
Auto merged
BitKeeper/deleted/.del-4.0.XX-gpl.ipr~f5909a9e9bd8094:
Auto merged
BitKeeper/deleted/.del-Clients and Tools.fgl~bf0f776883577f02:
Auto merged
BitKeeper/deleted/.del-Development.fgl~6392ce285e73f5fc:
Auto merged
mysql-test/mysql-test-run.sh:
Auto merged
mysql-test/r/innodb_cache.result:
Auto merged
mysql-test/r/lowercase_table2.result:
Auto merged
mysql-test/t/innodb_cache.test:
Auto merged
mysql-test/t/lowercase_table2.test:
Auto merged
sql/ha_berkeley.cc:
Auto merged
sql/handler.cc:
Auto merged
scripts/make_win_src_distribution.sh:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_parse.cc:
Auto merged
sql/sql_yacc.yy:
Auto merged
libmysql/libmysql.c:
Merge with 4.0
mysql-test/r/bdb.result:
Merge with 4.0
mysql-test/r/range.result:
Merge with 4.0
mysql-test/t/bdb.test:
Merge with 4.0
mysys/hash.c:
Merge with 4.0
scripts/mysql_install_db.sh:
Merge with 4.0
sql/field.cc:
Merge with 4.0
sql/field.h:
Merge with 4.0
sql/mysql_priv.h:
Merge with 4.0
sql/sql_handler.cc:
Merge with 4.0
sql/sql_select.cc:
Merge with 4.0
sql/sql_table.cc:
Merge with 4.0
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 80 | ||||
-rw-r--r-- | sql/field.h | 6 | ||||
-rw-r--r-- | sql/ha_berkeley.cc | 35 | ||||
-rw-r--r-- | sql/handler.cc | 5 | ||||
-rw-r--r-- | sql/mysql_priv.h | 5 | ||||
-rw-r--r-- | sql/sql_base.cc | 5 | ||||
-rw-r--r-- | sql/sql_handler.cc | 181 | ||||
-rw-r--r-- | sql/sql_select.cc | 2 | ||||
-rw-r--r-- | sql/sql_table.cc | 13 |
9 files changed, 292 insertions, 40 deletions
diff --git a/sql/field.cc b/sql/field.cc index 75b3e0add3d..2d3729817b7 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4684,6 +4684,42 @@ uint32 Field_blob::get_length(const char *pos) } +/* + Put a blob length field into a record buffer. + + SYNOPSIS + Field_blob::put_length() + pos Pointer into the record buffer. + length The length value to put. + + DESCRIPTION + Depending on the maximum length of a blob, its length field is + put into 1 to 4 bytes. This is a property of the blob object, + described by 'packlength'. + + RETURN + nothing +*/ + +void Field_blob::put_length(char *pos, uint32 length) +{ + switch (packlength) { + case 1: + *pos= (char) length; + break; + case 2: + int2store(pos, length); + break; + case 3: + int3store(pos, length); + break; + case 4: + int4store(pos, length); + break; + } +} + + int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) { if (!length) @@ -5058,6 +5094,50 @@ char *Field_blob::pack_key(char *to, const char *from, uint max_length) return to+length; } + +/* + Unpack a blob key into a record buffer. + + SYNOPSIS + Field_blob::unpack_key() + to Pointer into the record buffer. + from Pointer to the packed key. + max_length Key length limit from key description. + + DESCRIPTION + A blob key has a maximum size of 64K-1. + In its packed form, the length field is one or two bytes long, + depending on 'max_length'. + Depending on the maximum length of a blob, its length field is + put into 1 to 4 bytes. This is a property of the blob object, + described by 'packlength'. + Blobs are internally stored apart from the record buffer, which + contains a pointer to the blob buffer. + + RETURN + Pointer into 'from' past the last byte copied from packed key. +*/ + +const char *Field_blob::unpack_key(char *to, const char *from, uint max_length) +{ + /* get length of the blob key */ + uint32 length= *((uchar*) from++); + if (max_length > 255) + length+= (*((uchar*) from++)) << 8; + + /* put the length into the record buffer */ + put_length(to, length); + + /* put the address of the blob buffer or NULL */ + if (length) + memcpy_fixed(to + packlength, &from, sizeof(from)); + else + bzero(to + packlength, sizeof(from)); + + /* point to first byte of next field in 'from' */ + return from + length; +} + /* Create a packed key that will be used for storage from a MySQL key */ char *Field_blob::pack_key_from_key_image(char *to, const char *from, diff --git a/sql/field.h b/sql/field.h index e7a30372e43..a2fe77e18a3 100644 --- a/sql/field.h +++ b/sql/field.h @@ -251,6 +251,10 @@ public: { return pack(to,from,max_length); } + virtual const char *unpack_key(char* to, const char *from, uint max_length) + { + return unpack(to,from); + } virtual uint packed_col_length(const char *to, uint length) { return length;} virtual uint max_packed_col_length(uint max_length) @@ -1017,6 +1021,7 @@ public: inline uint32 get_length(uint row_offset=0) { return get_length(ptr+row_offset); } uint32 get_length(const char *ptr); + void put_length(char *pos, uint32 length); inline void get_ptr(char **str) { memcpy_fixed(str,ptr+packlength,sizeof(char*)); @@ -1049,6 +1054,7 @@ public: const char *unpack(char *to, const char *from); char *pack_key(char *to, const char *from, uint max_length); char *pack_key_from_key_image(char* to, const char *from, uint max_length); + const char *unpack_key(char* to, const char *from, uint max_length); int pack_cmp(const char *a, const char *b, uint key_length); int pack_cmp(const char *b, uint key_length); uint packed_col_length(const char *col_ptr, uint length); diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 42ff3d4dca6..ecdf4c60d3e 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -724,8 +724,8 @@ void ha_berkeley::unpack_key(char *record, DBT *key, uint index) } record[key_part->null_offset]&= ~key_part->null_bit; } - pos= (char*) key_part->field->unpack(record + key_part->field->offset(), - pos); + pos= (char*) key_part->field->unpack_key(record + key_part->field->offset(), + pos, key_part->length); } } @@ -1643,13 +1643,44 @@ int ha_berkeley::rnd_pos(byte * buf, byte *pos) (char*) buf, primary_key, ¤t_row, (DBT*) 0, 0)); } +/* + Set a reference to the current record in (ref,ref_length). + + SYNOPSIS + ha_berkeley::position() + record The current record buffer + + DESCRIPTION + The BDB handler stores the primary key in (ref,ref_length). + There is either an explicit primary key, or an implicit (hidden) + primary key. + During open(), 'ref_length' is calculated as the maximum primary + key length. When an actual key is shorter than that, the rest of + the buffer must be cleared out. The row cannot be identified, if + garbage follows behind the end of the key. There is no length + field for the current key, so that the whole ref_length is used + for comparison. + + RETURN + nothing +*/ + void ha_berkeley::position(const byte *record) { DBT key; + DBUG_ENTER("ha_berkeley::position"); if (hidden_primary_key) + { + DBUG_ASSERT(ref_length == BDB_HIDDEN_PRIMARY_KEY_LENGTH); memcpy_fixed(ref, (char*) current_ident, BDB_HIDDEN_PRIMARY_KEY_LENGTH); + } else + { create_key(&key, primary_key, (char*) ref, record); + if (key.size < ref_length) + bzero(ref + key.size, ref_length - key.size); + } + DBUG_VOID_RETURN; } diff --git a/sql/handler.cc b/sql/handler.cc index e278d1a5308..017b9d9d4c8 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -625,13 +625,12 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans) 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; + if (operation_done) + thd->transaction.cleanup(); } 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); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 03313adf76b..e3ef39fcbf6 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -671,8 +671,9 @@ my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show); /* sql_handler.cc */ int mysql_ha_open(THD *thd, TABLE_LIST *tables); -int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok=0); -int mysql_ha_closeall(THD *thd, TABLE_LIST *tables); +int mysql_ha_close(THD *thd, TABLE_LIST *tables, + bool dont_send_ok=0, bool dont_lock=0, bool no_alias=0); +int mysql_ha_close_list(THD *thd, TABLE_LIST *tables, bool flushed=0); int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f705b592e5a..b6d14092885 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -300,6 +300,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, thd->proc_info="Flushing tables"; close_old_data_files(thd,thd->open_tables,1,1); + mysql_ha_close_list(thd, tables); bool found=1; /* Wait until all threads has closed all the tables we had locked */ DBUG_PRINT("info", @@ -850,6 +851,9 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, DBUG_RETURN(0); } + /* close handler tables which are marked for flush */ + mysql_ha_close_list(thd, (TABLE_LIST*) NULL, /*flushed*/ 1); + for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; table && table->in_use ; table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length)) @@ -1220,6 +1224,7 @@ bool wait_for_tables(THD *thd) { thd->some_tables_deleted=0; close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0); + mysql_ha_close_list(thd, (TABLE_LIST*) NULL, /*flushed*/ 1); if (!table_is_used(thd->open_tables,1)) break; (void) pthread_cond_wait(&COND_refresh,&LOCK_open); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 7dfe707a317..c31763d7f1d 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -43,7 +43,9 @@ thd->handler_tables=tmp; } static TABLE **find_table_ptr_by_name(THD *thd,const char *db, - const char *table_name, bool is_alias); + const char *table_name, + bool is_alias, bool dont_lock, + bool *was_flushed); int mysql_ha_open(THD *thd, TABLE_LIST *tables) { @@ -66,25 +68,61 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables) return 0; } -int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok) + +/* + Close a HANDLER table. + + SYNOPSIS + mysql_ha_close() + thd Thread identifier. + tables A list of tables with the first entry to close. + dont_send_ok Suppresses the commands' ok message and + error message and error return. + dont_lock Suppresses the normal locking of LOCK_open. + + DESCRIPTION + Though this function takes a list of tables, only the first list entry + will be closed. Broadcasts a COND_refresh condition. + If mysql_ha_close() is not called from the parser, 'dont_send_ok' + must be set. + If the caller did already lock LOCK_open, it must set 'dont_lock'. + + IMPLEMENTATION + find_table_ptr_by_name() closes the table, if a FLUSH TABLE is outstanding. + It returns a NULL pointer in this case, but flags the situation in + 'was_flushed'. In that case the normal ER_UNKNOWN_TABLE error messages + is suppressed. + + RETURN + 0 ok + -1 error +*/ + +int mysql_ha_close(THD *thd, TABLE_LIST *tables, + bool dont_send_ok, bool dont_lock, bool no_alias) { - TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->alias, 1); + TABLE **table_ptr; + bool was_flushed; - if (*ptr) + table_ptr= find_table_ptr_by_name(thd, tables->db, tables->alias, + !no_alias, dont_lock, &was_flushed); + if (*table_ptr) { (*ptr)->file->ha_index_or_rnd_end(); - VOID(pthread_mutex_lock(&LOCK_open)); - if (close_thread_table(thd, ptr)) + if (!dont_lock) + VOID(pthread_mutex_lock(&LOCK_open)); + if (close_thread_table(thd, table_ptr)) { /* Tell threads waiting for refresh that something has happened */ VOID(pthread_cond_broadcast(&COND_refresh)); } - VOID(pthread_mutex_unlock(&LOCK_open)); + if (!dont_lock) + VOID(pthread_mutex_unlock(&LOCK_open)); } - else + else if (!was_flushed && !dont_send_ok) { - my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0), - tables->alias, "HANDLER"); + my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), + tables->alias, "HANDLER"); return -1; } if (!dont_send_ok) @@ -92,16 +130,64 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok) return 0; } -int mysql_ha_closeall(THD *thd, TABLE_LIST *tables) + +/* + Close a list of HANDLER tables. + + SYNOPSIS + mysql_ha_close_list() + thd Thread identifier. + tables The list of tables to close. If NULL, + close all HANDLER tables. + flushed Close only tables which are marked flushed. + Used only if tables is NULL. + + DESCRIPTION + The list of HANDLER tables may be NULL, in which case all HANDLER + tables are closed. Broadcasts a COND_refresh condition, for + every table closed. If 'tables' is NULL and 'flushed' is set, + all HANDLER tables marked for flush are closed. + The caller must lock LOCK_open. + + IMPLEMENTATION + find_table_ptr_by_name() closes the table, if it is marked for flush. + It returns a NULL pointer in this case, but flags the situation in + 'was_flushed'. In that case the normal ER_UNKNOWN_TABLE error messages + is suppressed. + + RETURN + 0 ok +*/ + +int mysql_ha_close_list(THD *thd, TABLE_LIST *tables, bool flushed) { - TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->real_name, 0); - if (*ptr) + TABLE_LIST *tl_item; + TABLE **table_ptr; + + if (tables) { - (*ptr)->file->ha_index_or_rnd_end(); - if (close_thread_table(thd, ptr)) + for (tl_item= tables ; tl_item; tl_item= tl_item->next) { - /* Tell threads waiting for refresh that something has happened */ - VOID(pthread_cond_broadcast(&COND_refresh)); + mysql_ha_close(thd, tl_item, /*dont_send_ok*/ 1, + /*dont_lock*/ 1, /*no_alias*/ 1); + } + } + else + { + table_ptr= &(thd->handler_tables); + while (*table_ptr) + { + if (! flushed || ((*table_ptr)->version != refresh_version)) + { + (*table_ptr)->file->ha_index_or_rnd_end(); + if (close_thread_table(thd, table_ptr)) + { + /* Tell threads waiting for refresh that something has happened */ + VOID(pthread_cond_broadcast(&COND_refresh)); + } + continue; + } + table_ptr= &((*table_ptr)->next); } } return 0; @@ -117,7 +203,10 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, ha_rows select_limit,ha_rows offset_limit) { int err, keyno=-1; - TABLE *table=*find_table_ptr_by_name(thd, tables->db, tables->alias, 1); + bool was_flushed; + TABLE *table= *find_table_ptr_by_name(thd, tables->db, tables->alias, + /*is_alias*/ 1, /*dont_lock*/ 0, + &was_flushed); if (!table) { my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0), @@ -298,17 +387,51 @@ err0: } +/* + Find a HANDLER table by name. + + SYNOPSIS + find_table_ptr_by_name() + thd Thread identifier. + db Database (schema) name. + table_name Table name ;-). + is_alias Table name may be an alias name. + dont_lock Suppresses the normal locking of LOCK_open. + + DESCRIPTION + Find the table 'db'.'table_name' in the list of HANDLER tables of the + thread 'thd'. If the table has been marked by FLUSH TABLE(S), close it, + flag this situation in '*was_flushed' and broadcast a COND_refresh + condition. + An empty database (schema) name matches all database (schema) names. + If the caller did already lock LOCK_open, it must set 'dont_lock'. + + IMPLEMENTATION + Just in case that the table is twice in 'thd->handler_tables' (!?!), + the loop does not break when the table was flushed. If another table + by that name was found and not flushed, '*was_flushed' is cleared again, + since a pointer to an open HANDLER table is returned. + + RETURN + *was_flushed Table has been closed due to FLUSH TABLE. + NULL A HANDLER Table by that name does not exist (any more). + != NULL Pointer to the TABLE structure. +*/ + static TABLE **find_table_ptr_by_name(THD *thd, const char *db, - const char *table_name, bool is_alias) + const char *table_name, + bool is_alias, bool dont_lock, + bool *was_flushed) { int dblen; - TABLE **ptr; + TABLE **table_ptr; DBUG_ASSERT(db); dblen= strlen(db); - ptr= &(thd->handler_tables); + table_ptr= &(thd->handler_tables); + *was_flushed= FALSE; - for (TABLE *table= *ptr; table ; table= *ptr) + for (TABLE *table= *table_ptr; table ; table= *table_ptr) { if ((db == any_db || !memcmp(table->table_cache_key, db, dblen)) && !my_strcasecmp(system_charset_info, @@ -317,18 +440,22 @@ static TABLE **find_table_ptr_by_name(THD *thd, const char *db, { if (table->version != refresh_version) { - VOID(pthread_mutex_lock(&LOCK_open)); - if (close_thread_table(thd, ptr)) + if (!dont_lock) + VOID(pthread_mutex_lock(&LOCK_open)); + if (close_thread_table(thd, table_ptr)) { /* Tell threads waiting for refresh that something has happened */ VOID(pthread_cond_broadcast(&COND_refresh)); } - VOID(pthread_mutex_unlock(&LOCK_open)); + if (!dont_lock) + VOID(pthread_mutex_unlock(&LOCK_open)); + *was_flushed= TRUE; continue; } + *was_flushed= FALSE; break; } - ptr= &(table->next); + table_ptr= &(table->next); } - return ptr; + return table_ptr; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 932ceff2f43..a5de5397ec8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2283,7 +2283,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level, !(cond_func->used_tables() & OUTER_REF_TABLE_BIT)) add_key_field(key_fields,*and_level,cond_func, ((Item_field*) (cond_func->key_item()->real_item()))-> - field, 0, + field, cond_func->argument_count() == 2, cond_func->arguments()+1, cond_func->argument_count()-1, usable_tables); break; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 6e447271b2e..6c9ec41c728 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -191,7 +191,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, for (table=tables ; table ; table=table->next) { char *db=table->db; - mysql_ha_closeall(thd, table); + mysql_ha_close(thd, table, /*dont_send_ok*/ 1, /*dont_lock*/ 1); if (!close_temporary_table(thd, db, table->real_name)) { tmp_table_deleted=1; @@ -1727,7 +1727,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, if (protocol->send_fields(&field_list, 1)) DBUG_RETURN(-1); - mysql_ha_closeall(thd, tables); + mysql_ha_close(thd, tables, /*dont_send_ok*/ 1, /*dont_lock*/ 1); for (table = tables; table; table = table->next) { char table_name[NAME_LEN*2+2]; @@ -2254,7 +2254,7 @@ int mysql_discard_or_import_tablespace(THD *thd, thd->tablespace_op=TRUE; /* we set this flag so that ha_innobase::open and ::external_lock() do not complain when we lock the table */ - mysql_ha_closeall(thd, table_list); + mysql_ha_close(thd, table_list, /*dont_send_ok*/ 1, /*dont_lock*/ 1); if (!(table=open_ltable(thd,table_list,TL_WRITE))) { @@ -2533,7 +2533,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, new_db= db; used_fields=create_info->used_fields; - mysql_ha_closeall(thd, table_list); + mysql_ha_close(thd, table_list, /*dont_send_ok*/ 1, /*dont_lock*/ 1); /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */ if (alter_info->tablespace_op != NO_TABLESPACE_OP) @@ -2588,7 +2588,10 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } } else - new_alias= new_name= table_name; + { + new_alias= (lower_case_table_names == 2) ? alias : table_name; + new_name= table_name; + } old_db_type=table->db_type; if (create_info->db_type == DB_TYPE_DEFAULT) |