diff options
author | unknown <guilhem@gbichot4.local> | 2007-07-27 12:06:39 +0200 |
---|---|---|
committer | unknown <guilhem@gbichot4.local> | 2007-07-27 12:06:39 +0200 |
commit | a3d2ae4648d739a7ec7820e22c05373fde65b770 (patch) | |
tree | 1c7c807fa27f54c3bc16968151fcc79e1f8b4667 /storage | |
parent | 662002fc8f6301ec78d2eca14c5f991212d4f67f (diff) | |
download | mariadb-git-a3d2ae4648d739a7ec7820e22c05373fde65b770.tar.gz |
merging MyISAM changes into Maria (not done in 5.1->maria merge of
Jul 7th). "maria.test" and "ps_maria.test" still fail;
"ma_test_all" starts failing (MyISAM has the same issue see BUG#30094).
include/maria.h:
merging MyISAM changes into Maria
mysys/mf_keycache.c:
mi_test_all showed "floating point exception", this was already
fixed in the latest 5.1, importing fix.
sql/item_xmlfunc.cc:
compiler warning (already fixed in latest 5.1)
storage/maria/ha_maria.cc:
merging MyISAM changes into Maria. See #ifdef ASK_MONTY.
storage/maria/ha_maria.h:
merging MyISAM changes into Maria
storage/maria/ma_cache.c:
merging MyISAM changes into Maria
storage/maria/ma_check.c:
merging MyISAM changes into Maria
storage/maria/ma_create.c:
merging MyISAM changes into Maria
storage/maria/ma_dynrec.c:
merging MyISAM changes into Maria
storage/maria/ma_extra.c:
merging MyISAM changes into Maria
storage/maria/ma_ft_boolean_search.c:
merging MyISAM changes into Maria
storage/maria/ma_ft_nlq_search.c:
merging MyISAM changes into Maria
storage/maria/ma_info.c:
merging MyISAM changes into Maria
storage/maria/ma_key.c:
merging MyISAM changes into Maria
storage/maria/ma_loghandler.c:
compiler warning (part->length is size_t)
storage/maria/ma_open.c:
merging MyISAM changes into Maria
storage/maria/ma_preload.c:
merging MyISAM changes into Maria
storage/maria/ma_range.c:
merging MyISAM changes into Maria
storage/maria/ma_rkey.c:
merging MyISAM changes into Maria
storage/maria/ma_rt_index.c:
merging MyISAM changes into Maria
storage/maria/ma_rt_key.c:
merging MyISAM changes into Maria
storage/maria/ma_rt_split.c:
merging MyISAM changes into Maria
storage/maria/ma_search.c:
merging MyISAM changes into Maria
storage/maria/ma_sort.c:
merging MyISAM changes into Maria
storage/maria/maria_def.h:
merging MyISAM changes into Maria
Diffstat (limited to 'storage')
-rw-r--r-- | storage/maria/ha_maria.cc | 198 | ||||
-rw-r--r-- | storage/maria/ha_maria.h | 13 | ||||
-rw-r--r-- | storage/maria/ma_cache.c | 4 | ||||
-rw-r--r-- | storage/maria/ma_check.c | 16 | ||||
-rw-r--r-- | storage/maria/ma_create.c | 26 | ||||
-rw-r--r-- | storage/maria/ma_dynrec.c | 14 | ||||
-rw-r--r-- | storage/maria/ma_extra.c | 10 | ||||
-rw-r--r-- | storage/maria/ma_ft_boolean_search.c | 51 | ||||
-rw-r--r-- | storage/maria/ma_ft_nlq_search.c | 8 | ||||
-rw-r--r-- | storage/maria/ma_info.c | 6 | ||||
-rw-r--r-- | storage/maria/ma_key.c | 64 | ||||
-rw-r--r-- | storage/maria/ma_loghandler.c | 4 | ||||
-rw-r--r-- | storage/maria/ma_open.c | 48 | ||||
-rw-r--r-- | storage/maria/ma_preload.c | 13 | ||||
-rw-r--r-- | storage/maria/ma_range.c | 63 | ||||
-rw-r--r-- | storage/maria/ma_rkey.c | 15 | ||||
-rw-r--r-- | storage/maria/ma_rt_index.c | 107 | ||||
-rw-r--r-- | storage/maria/ma_rt_key.c | 18 | ||||
-rw-r--r-- | storage/maria/ma_rt_split.c | 12 | ||||
-rw-r--r-- | storage/maria/ma_search.c | 42 | ||||
-rw-r--r-- | storage/maria/ma_sort.c | 17 | ||||
-rw-r--r-- | storage/maria/maria_def.h | 5 |
22 files changed, 499 insertions, 255 deletions
diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 05b79d6f10c..d0888278cca 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -114,6 +114,14 @@ static void _ma_check_print_msg(HA_CHECK *param, const char *msg_type, } length= (uint) (strxmov(name, param->db_name, ".", param->table_name, NullS) - name); + /* + TODO: switch from protocol to push_warning here. The main reason we didn't + it yet is parallel repair. Due to following trace: + ma_check_print_msg/push_warning/sql_alloc/my_pthread_getspecific_ptr. + + Also we likely need to lock mutex here (in both cases with protocol and + push_warning). + */ protocol->prepare_for_resend(); protocol->store(name, length, system_charset_info); protocol->store(param->op_name, system_charset_info); @@ -353,10 +361,11 @@ int table2maria(TABLE *table_arg, MARIA_KEYDEF **keydef_out, 0 - Equal definitions. 1 - Different definitions. - NOTES - This is currently not used. In MyISAM the corresponding function - (myisam_check_definition()) is used only by MERGE tables - (in ha_myisammrg.cc). + TODO + - compare FULLTEXT keys; + - compare SPATIAL keys; + - compare FIELD_SKIP_ZERO which is converted to FIELD_NORMAL correctly + (should be corretly detected in table2maria). */ int maria_check_definition(MARIA_KEYDEF *t1_keyinfo, MARIA_COLUMNDEF *t1_recinfo, @@ -383,6 +392,28 @@ int maria_check_definition(MARIA_KEYDEF *t1_keyinfo, { HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg; HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg; + if (t1_keyinfo[i].flag & HA_FULLTEXT && t2_keyinfo[i].flag & HA_FULLTEXT) + continue; + else if (t1_keyinfo[i].flag & HA_FULLTEXT || + t2_keyinfo[i].flag & HA_FULLTEXT) + { + DBUG_PRINT("error", ("Key %d has different definition", i)); + DBUG_PRINT("error", ("t1_fulltext= %d, t2_fulltext=%d", + test(t1_keyinfo[i].flag & HA_FULLTEXT), + test(t2_keyinfo[i].flag & HA_FULLTEXT))); + DBUG_RETURN(1); + } + if (t1_keyinfo[i].flag & HA_SPATIAL && t2_keyinfo[i].flag & HA_SPATIAL) + continue; + else if (t1_keyinfo[i].flag & HA_SPATIAL || + t2_keyinfo[i].flag & HA_SPATIAL) + { + DBUG_PRINT("error", ("Key %d has different definition", i)); + DBUG_PRINT("error", ("t1_spatial= %d, t2_spatial=%d", + test(t1_keyinfo[i].flag & HA_SPATIAL), + test(t2_keyinfo[i].flag & HA_SPATIAL))); + DBUG_RETURN(1); + } if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs || t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg) { @@ -419,7 +450,14 @@ int maria_check_definition(MARIA_KEYDEF *t1_keyinfo, { MARIA_COLUMNDEF *t1_rec= &t1_recinfo[i]; MARIA_COLUMNDEF *t2_rec= &t2_recinfo[i]; - if (t1_rec->type != t2_rec->type || + /* + FIELD_SKIP_ZERO can be changed to FIELD_NORMAL in maria_create, + see NOTE1 in ma_create.c + */ + if ((t1_rec->type != t2_rec->type && + !(t1_rec->type == (int) FIELD_SKIP_ZERO && + t1_rec->length == 1 && + t2_rec->type == (int) FIELD_NORMAL)) || t1_rec->length != t2_rec->length || t1_rec->null_bit != t2_rec->null_bit) { @@ -602,7 +640,7 @@ int ha_maria::dump(THD * thd, int fd) my_seek(data_fd, 0L, MY_SEEK_SET, MYF(MY_WME)); for (; bytes_to_read > 0;) { - uint bytes= my_read(data_fd, buf, block_size, MYF(MY_WME)); + size_t bytes= my_read(data_fd, buf, block_size, MYF(MY_WME)); if (bytes == MY_FILE_ERROR) { error= errno; @@ -644,7 +682,8 @@ err: bool ha_maria::check_if_locking_is_allowed(uint sql_command, ulong type, TABLE *table, - uint count, + uint count, uint current, + uint *system_count, bool called_by_privileged_thread) { /* @@ -653,10 +692,13 @@ bool ha_maria::check_if_locking_is_allowed(uint sql_command, we have to disallow write-locking of these tables with any other tables. */ if (table->s->system_table && - table->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE && count != 1) + table->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE) + (*system_count)++; + + /* 'current' is an index, that's why '<=' below. */ + if (*system_count > 0 && *system_count <= current) { - my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0), table->s->db.str, - table->s->table_name.str); + my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0)); return FALSE; } @@ -676,6 +718,9 @@ bool ha_maria::check_if_locking_is_allowed(uint sql_command, int ha_maria::open(const char *name, int mode, uint test_if_locked) { + MARIA_KEYDEF *keyinfo; + MARIA_COLUMNDEF *recinfo= 0; + uint recs; uint i; #ifdef NOT_USED @@ -701,6 +746,36 @@ int ha_maria::open(const char *name, int mode, uint test_if_locked) if (!(file= maria_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER))) return (my_errno ? my_errno : -1); +#ifdef ASK_MONTY + /* + This is a protection for the case of a frm and MAI containing incompatible + table definitions (as in BUG#25908). This was merged from MyISAM. + But it breaks maria.test and ps_maria.test ("incorrect key file") if the + table is BLOCK_RECORD (does it have to do with column reordering done in + ma_create.c ?). + */ + if (!table->s->tmp_table) /* No need to perform a check for tmp table */ + { + if ((my_errno= table2maria(table, &keyinfo, &recinfo, &recs))) + { + /* purecov: begin inspected */ + DBUG_PRINT("error", ("Failed to convert TABLE object to Maria " + "key and column definition")); + goto err; + /* purecov: end */ + } + if (maria_check_definition(keyinfo, recinfo, table->s->keys, recs, + file->s->keyinfo, file->s->columndef, + file->s->base.keys, file->s->base.fields, true)) + { + /* purecov: begin inspected */ + my_errno= HA_ERR_CRASHED; + goto err; + /* purecov: end */ + } + } +#endif + if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE)) VOID(maria_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0)); @@ -731,7 +806,18 @@ int ha_maria::open(const char *name, int mode, uint test_if_locked) (struct st_mysql_ftparser *)plugin_decl(parser)->info; table->key_info[i].block_size= file->s->keyinfo[i].block_length; } - return (0); + my_errno= 0; + goto end; + err: + this->close(); + end: + /* + Both recinfo and keydef are allocated by my_multi_malloc(), thus only + recinfo must be freed. + */ + if (recinfo) + my_free((uchar*) recinfo, MYF(0)); + return my_errno; } @@ -745,7 +831,7 @@ int ha_maria::close(void) int ha_maria::write_row(uchar * buf) { - statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status); + ha_statistic_increment(&SSV::ha_write_count); /* If we have a timestamp column, update it to the current time */ if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) @@ -1064,8 +1150,8 @@ int ha_maria::optimize(THD * thd, HA_CHECK_OPT *check_opt) param.sort_buffer_length= check_opt->sort_buffer_size; if ((error= repair(thd, param, 1)) && param.retry_repair) { - sql_print_warning("Warning: Optimize table got errno %d, retrying", - my_errno); + sql_print_warning("Warning: Optimize table got errno %d on %s.%s, retrying", + my_errno, param.db_name, param.table_name); param.testflag &= ~T_REP_BY_SORT; error= repair(thd, param, 1); } @@ -1084,6 +1170,22 @@ int ha_maria::repair(THD *thd, HA_CHECK ¶m, bool do_optimize) ha_rows rows= file->state->records; DBUG_ENTER("ha_maria::repair"); + /* + Normally this method is entered with a properly opened table. If the + repair fails, it can be repeated with more elaborate options. Under + special circumstances it can happen that a repair fails so that it + closed the data file and cannot re-open it. In this case file->dfile + is set to -1. We must not try another repair without an open data + file. (Bug #25289) + */ + if (file->dfile.file == -1) + { + sql_print_information("Retrying repair of: '%s' failed. " + "Please try REPAIR EXTENDED or maria_chk", + table->s->path.str); + DBUG_RETURN(HA_ADMIN_FAILED); + } + param.db_name= table->s->db.str; param.table_name= table->alias; param.tmpfile_createflag= O_RDWR | O_TRUNC; @@ -1222,7 +1324,7 @@ int ha_maria::assign_to_keycache(THD * thd, HA_CHECK_OPT *check_opt) PAGECACHE *new_pagecache= check_opt->pagecache; const char *errmsg= 0; int error= HA_ADMIN_OK; - ulonglong map= ~(ulonglong) 0; + ulonglong map; TABLE_LIST *table_list= table->pos_in_table_list; DBUG_ENTER("ha_maria::assign_to_keycache"); @@ -1268,9 +1370,10 @@ int ha_maria::preload_keys(THD * thd, HA_CHECK_OPT *check_opt) { int error; const char *errmsg; - ulonglong map= ~(ulonglong) 0; + ulonglong map; TABLE_LIST *table_list= table->pos_in_table_list; my_bool ignore_leaves= table_list->ignore_leaves; + char buf[ERRMSGSIZE+20]; DBUG_ENTER("ha_maria::preload_keys"); @@ -1298,7 +1401,6 @@ int ha_maria::preload_keys(THD * thd, HA_CHECK_OPT *check_opt) errmsg= "Failed to allocate buffer"; break; default: - char buf[ERRMSGSIZE + 20]; my_snprintf(buf, ERRMSGSIZE, "Failed to read from index file (errno: %d)", my_errno); errmsg= buf; @@ -1427,13 +1529,13 @@ int ha_maria::enable_indexes(uint mode) T_CREATE_MISSING_KEYS); param.myf_rw &= ~MY_WAIT_IF_FULL; param.sort_buffer_length= thd->variables.maria_sort_buff_size; - param.stats_method= (enum_handler_stats_method) thd->variables. - maria_stats_method; + param.stats_method= + (enum_handler_stats_method) thd->variables.maria_stats_method; param.tmpdir= &mysql_tmpdir_list; if ((error= (repair(thd, param, 0) != HA_ADMIN_OK)) && param.retry_repair) { - sql_print_warning("Warning: Enabling keys got errno %d, retrying", - my_errno); + sql_print_warning("Warning: Enabling keys got errno %d on %s.%s, retrying", + my_errno, param.db_name, param.table_name); /* Repairing by sort failed. Now try standard repair method. */ param.testflag &= ~(T_REP_BY_SORT | T_QUICK); error= (repair(thd, param, 0) != HA_ADMIN_OK); @@ -1442,8 +1544,10 @@ int ha_maria::enable_indexes(uint mode) might have been set by the first repair. They can still be seen with SHOW WARNINGS then. */ +#ifndef EMBEDDED_LIBRARY if (!error) thd->clear_error(); +#endif /* EMBEDDED_LIBRARY */ } info(HA_STATUS_CONST); thd->proc_info= save_proc_info; @@ -1607,7 +1711,7 @@ bool ha_maria::is_crashed() const int ha_maria::update_row(const uchar * old_data, uchar * new_data) { - statistic_increment(table->in_use->status_var.ha_update_count, &LOCK_status); + ha_statistic_increment(&SSV::ha_update_count); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) table->timestamp_field->set_time(); return maria_update(file, old_data, new_data); @@ -1616,41 +1720,41 @@ int ha_maria::update_row(const uchar * old_data, uchar * new_data) int ha_maria::delete_row(const uchar * buf) { - statistic_increment(table->in_use->status_var.ha_delete_count, &LOCK_status); + ha_statistic_increment(&SSV::ha_delete_count); return maria_delete(file, buf); } int ha_maria::index_read(uchar * buf, const uchar * key, - uint key_len, enum ha_rkey_function find_flag) + key_part_map keypart_map, + enum ha_rkey_function find_flag) { DBUG_ASSERT(inited == INDEX); - statistic_increment(table->in_use->status_var.ha_read_key_count, - &LOCK_status); - int error= maria_rkey(file, buf, active_index, key, key_len, find_flag); + ha_statistic_increment(&SSV::ha_read_key_count); + int error= maria_rkey(file, buf, active_index, key, keypart_map, find_flag); table->status= error ? STATUS_NOT_FOUND : 0; return error; } int ha_maria::index_read_idx(uchar * buf, uint index, const uchar * key, - uint key_len, enum ha_rkey_function find_flag) + key_part_map keypart_map, + enum ha_rkey_function find_flag) { - statistic_increment(table->in_use->status_var.ha_read_key_count, - &LOCK_status); - int error= maria_rkey(file, buf, index, key, key_len, find_flag); + ha_statistic_increment(&SSV::ha_read_key_count); + int error= maria_rkey(file, buf, index, key, keypart_map, find_flag); table->status= error ? STATUS_NOT_FOUND : 0; return error; } -int ha_maria::index_read_last(uchar * buf, const uchar * key, uint key_len) +int ha_maria::index_read_last(uchar * buf, const uchar * key, + key_part_map keypart_map) { DBUG_ENTER("ha_maria::index_read_last"); DBUG_ASSERT(inited == INDEX); - statistic_increment(table->in_use->status_var.ha_read_key_count, - &LOCK_status); - int error= maria_rkey(file, buf, active_index, key, key_len, + ha_statistic_increment(&SSV::ha_read_key_count); + int error= maria_rkey(file, buf, active_index, key, keypart_map, HA_READ_PREFIX_LAST); table->status= error ? STATUS_NOT_FOUND : 0; DBUG_RETURN(error); @@ -1660,8 +1764,7 @@ int ha_maria::index_read_last(uchar * buf, const uchar * key, uint key_len) int ha_maria::index_next(uchar * buf) { DBUG_ASSERT(inited == INDEX); - statistic_increment(table->in_use->status_var.ha_read_next_count, - &LOCK_status); + ha_statistic_increment(&SSV::ha_read_next_count); int error= maria_rnext(file, buf, active_index); table->status= error ? STATUS_NOT_FOUND : 0; return error; @@ -1671,8 +1774,7 @@ int ha_maria::index_next(uchar * buf) int ha_maria::index_prev(uchar * buf) { DBUG_ASSERT(inited == INDEX); - statistic_increment(table->in_use->status_var.ha_read_prev_count, - &LOCK_status); + ha_statistic_increment(&SSV::ha_read_prev_count); int error= maria_rprev(file, buf, active_index); table->status= error ? STATUS_NOT_FOUND : 0; return error; @@ -1682,8 +1784,7 @@ int ha_maria::index_prev(uchar * buf) int ha_maria::index_first(uchar * buf) { DBUG_ASSERT(inited == INDEX); - statistic_increment(table->in_use->status_var.ha_read_first_count, - &LOCK_status); + ha_statistic_increment(&SSV::ha_read_first_count); int error= maria_rfirst(file, buf, active_index); table->status= error ? STATUS_NOT_FOUND : 0; return error; @@ -1693,8 +1794,7 @@ int ha_maria::index_first(uchar * buf) int ha_maria::index_last(uchar * buf) { DBUG_ASSERT(inited == INDEX); - statistic_increment(table->in_use->status_var.ha_read_last_count, - &LOCK_status); + ha_statistic_increment(&SSV::ha_read_last_count); int error= maria_rlast(file, buf, active_index); table->status= error ? STATUS_NOT_FOUND : 0; return error; @@ -1706,8 +1806,7 @@ int ha_maria::index_next_same(uchar * buf, uint length __attribute__ ((unused))) { DBUG_ASSERT(inited == INDEX); - statistic_increment(table->in_use->status_var.ha_read_next_count, - &LOCK_status); + ha_statistic_increment(&SSV::ha_read_next_count); int error= maria_rnext_same(file, buf); table->status= error ? STATUS_NOT_FOUND : 0; return error; @@ -1732,8 +1831,7 @@ int ha_maria::rnd_end() int ha_maria::rnd_next(uchar *buf) { - statistic_increment(table->in_use->status_var.ha_read_rnd_next_count, - &LOCK_status); + ha_statistic_increment(&SSV::ha_read_rnd_next_count); int error= maria_scan(file, buf); table->status= error ? STATUS_NOT_FOUND : 0; return error; @@ -1748,8 +1846,7 @@ int ha_maria::restart_rnd_next(uchar *buf, uchar *pos) int ha_maria::rnd_pos(uchar * buf, uchar *pos) { - statistic_increment(table->in_use->status_var.ha_read_rnd_count, - &LOCK_status); + ha_statistic_increment(&SSV::ha_read_rnd_count); int error= maria_rrnd(file, buf, my_get_ptr(pos, ref_length)); table->status= error ? STATUS_NOT_FOUND : 0; return error; @@ -2111,7 +2208,8 @@ void ha_maria::get_auto_increment(ulonglong offset, ulonglong increment, table->key_info + table->s->next_number_index, table->s->next_number_key_offset); error= maria_rkey(file, table->record[1], (int) table->s->next_number_index, - key, table->s->next_number_key_offset, HA_READ_PREFIX_LAST); + key, make_prev_keypart_map(table->s->next_number_keypart), + HA_READ_PREFIX_LAST); if (error) nr= 1; else diff --git a/storage/maria/ha_maria.h b/storage/maria/ha_maria.h index c97919ab86a..7675778ab5b 100644 --- a/storage/maria/ha_maria.h +++ b/storage/maria/ha_maria.h @@ -68,18 +68,21 @@ public: virtual bool check_if_locking_is_allowed(uint sql_command, ulong type, TABLE * table, - uint count, + uint count, uint current, + uint *system_count, bool called_by_logger_thread); int open(const char *name, int mode, uint test_if_locked); int close(void); int write_row(uchar * buf); int update_row(const uchar * old_data, uchar * new_data); int delete_row(const uchar * buf); - int index_read(uchar * buf, const uchar * key, - uint key_len, enum ha_rkey_function find_flag); + int index_read(uchar * buf, const uchar * key, key_part_map keypart_map, + enum ha_rkey_function find_flag); int index_read_idx(uchar * buf, uint idx, const uchar * key, - uint key_len, enum ha_rkey_function find_flag); - int index_read_last(uchar * buf, const uchar * key, uint key_len); + key_part_map keypart_map, + enum ha_rkey_function find_flag); + int index_read_last(uchar * buf, const uchar * key, + key_part_map keypart_map); int index_next(uchar * buf); int index_prev(uchar * buf); int index_first(uchar * buf); diff --git a/storage/maria/ma_cache.c b/storage/maria/ma_cache.c index 44aa7a15058..6b1f9ec3fae 100644 --- a/storage/maria/ma_cache.c +++ b/storage/maria/ma_cache.c @@ -40,7 +40,7 @@ int _ma_read_cache(IO_CACHE *info, uchar *buff, my_off_t pos, uint length, { uint read_length,in_buff_length; my_off_t offset; - char *in_buff_pos; + uchar *in_buff_pos; DBUG_ENTER("_ma_read_cache"); if (pos < info->pos_in_file) @@ -61,7 +61,7 @@ int _ma_read_cache(IO_CACHE *info, uchar *buff, my_off_t pos, uint length, (my_off_t) (info->read_end - info->request_pos)) { in_buff_pos=info->request_pos+(uint) offset; - in_buff_length= min(length,(uint) ((char*)(info->read_end)-in_buff_pos)); + in_buff_length= min(length,(size_t) (info->read_end-in_buff_pos)); memcpy(buff,info->request_pos+(uint) offset,(size_t) in_buff_length); if (!(length-=in_buff_length)) DBUG_RETURN(0); diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c index 7d936409170..ce4a610cec9 100644 --- a/storage/maria/ma_check.c +++ b/storage/maria/ma_check.c @@ -344,7 +344,7 @@ int maria_chk_size(HA_CHECK *param, register MARIA_HA *info) flush_pagecache_blocks(info->s->pagecache, &info->s->kfile, FLUSH_FORCE_WRITE); - size= my_seek(info->s->kfile.file, 0L, MY_SEEK_END, MYF(0)); + size= my_seek(info->s->kfile.file, 0L, MY_SEEK_END, MYF(MY_THREADSAFE)); if ((skr=(my_off_t) info->state->key_file_length) != size) { /* Don't give error if file generated by mariapack */ @@ -539,7 +539,7 @@ int maria_chk_key(HA_CHECK *param, register MARIA_HA *info) maria_extra(info,HA_EXTRA_KEYREAD,0); bzero(info->lastkey,keyinfo->seg->length); if (!maria_rkey(info, info->rec_buff, key, (const uchar*) info->lastkey, - keyinfo->seg->length, HA_READ_KEY_EXACT)) + (key_part_map)1, HA_READ_KEY_EXACT)) { /* Don't count this as a real warning, as maria_chk can't correct it */ uint save=param->warning_printed; @@ -603,7 +603,8 @@ static int chk_index_down(HA_CHECK *param, MARIA_HA *info, { /* purecov: begin tested */ /* Give it a chance to fit in the real file size. */ - my_off_t max_length= my_seek(info->s->kfile.file, 0L, MY_SEEK_END, MYF(0)); + my_off_t max_length= my_seek(info->s->kfile.file, 0L, MY_SEEK_END, + MYF(MY_THREADSAFE)); _ma_check_print_error(param, "Invalid key block position: %s " "key block size: %u file_length: %s", llstr(page, llbuff), keyinfo->block_length, @@ -4772,10 +4773,11 @@ int maria_test_if_almost_full(MARIA_HA *info) { if (info->s->options & HA_OPTION_COMPRESS_RECORD) return 0; - return (my_seek(info->s->kfile.file, 0L, MY_SEEK_END, MYF(0))/10*9 > - (my_off_t) (info->s->base.max_key_file_length) || - my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0)) / 10 * 9 > - (my_off_t) info->s->base.max_data_file_length); + return my_seek(info->s->kfile.file, 0L, MY_SEEK_END, + MYF(MY_THREADSAFE))/10*9 > + (my_off_t) info->s->base.max_key_file_length || + my_seek(info->dfile.file, 0L, MY_SEEK_END, MYF(0)) / 10 * 9 > + (my_off_t) info->s->base.max_data_file_length; } /* Recreate table with bigger more alloced record-data */ diff --git a/storage/maria/ma_create.c b/storage/maria/ma_create.c index 1736e24a7b6..201c5603c25 100644 --- a/storage/maria/ma_create.c +++ b/storage/maria/ma_create.c @@ -239,6 +239,10 @@ int maria_create(const char *name, enum data_file_type datafile_type, column--; if (column->type == (int) FIELD_SKIP_ZERO && column->length == 1) { + /* + NOTE1: here we change a field type FIELD_SKIP_ZERO -> + FIELD_NORMAL + */ column->type=(int) FIELD_NORMAL; column->empty_pos= 0; column->empty_bit= 0; @@ -701,6 +705,10 @@ int maria_create(const char *name, enum data_file_type datafile_type, pthread_mutex_lock(&THR_LOCK_maria); + /* + NOTE: For test_if_reopen() we need a real path name. Hence we need + MY_RETURN_REAL_PATH for every fn_format(filename, ...). + */ if (ci->index_file_name) { char *iext= strrchr(ci->index_file_name, '.'); @@ -712,13 +720,14 @@ int maria_create(const char *name, enum data_file_type datafile_type, if ((path= strrchr(ci->index_file_name, FN_LIBCHAR))) *path= '\0'; fn_format(filename, name, ci->index_file_name, MARIA_NAME_IEXT, - MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_APPEND_EXT); + MY_REPLACE_DIR | MY_UNPACK_FILENAME | + MY_RETURN_REAL_PATH | MY_APPEND_EXT); } else { fn_format(filename, ci->index_file_name, "", MARIA_NAME_IEXT, - MY_UNPACK_FILENAME | (have_iext ? MY_REPLACE_EXT : - MY_APPEND_EXT)); + MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH | + (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT)); } fn_format(linkname, name, "", MARIA_NAME_IEXT, MY_UNPACK_FILENAME|MY_APPEND_EXT); @@ -734,10 +743,11 @@ int maria_create(const char *name, enum data_file_type datafile_type, } else { + char *iext= strrchr(name, '.'); + int have_iext= iext && !strcmp(iext, MARIA_NAME_IEXT); fn_format(filename, name, "", MARIA_NAME_IEXT, - (MY_UNPACK_FILENAME | - (flags & HA_DONT_TOUCH_DATA) ? MY_RETURN_REAL_PATH : 0) | - MY_APPEND_EXT); + MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH | + (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT)); linkname_ptr= NullS; /* Replace the current file. @@ -752,6 +762,10 @@ int maria_create(const char *name, enum data_file_type datafile_type, A TRUNCATE command checks for the table in the cache only and could be fooled to believe, the table is not open. Pull the emergency brake in this situation. (Bug #8306) + + + NOTE: The filename is compared against unique_file_name of every + open table. Hence we need a real path here. */ if (_ma_test_if_reopen(filename)) { diff --git a/storage/maria/ma_dynrec.c b/storage/maria/ma_dynrec.c index 28b970ef589..246f9787b09 100644 --- a/storage/maria/ma_dynrec.c +++ b/storage/maria/ma_dynrec.c @@ -887,7 +887,7 @@ uint _ma_rec_pack(MARIA_HA *info, register uchar *to, register const uchar *from) { uint length,new_length,flag,bit,i; - char *pos,*end,*startpos,*packpos; + uchar *pos,*end,*startpos,*packpos; enum en_fieldtype type; reg3 MARIA_COLUMNDEF *column; MARIA_BLOB *blob; @@ -941,7 +941,7 @@ uint _ma_rec_pack(MARIA_HA *info, register uchar *to, pos= (uchar*) from; end= (uchar*) from + length; if (type == FIELD_SKIP_ENDSPACE) { /* Pack trailing spaces */ - while (end > (char*) from && *(end-1) == ' ') + while (end > from && *(end-1) == ' ') end--; } else @@ -1007,8 +1007,8 @@ uint _ma_rec_pack(MARIA_HA *info, register uchar *to, *packpos= (char) (uchar) flag; if (info->s->calc_checksum) *to++= (uchar) info->cur_row.checksum; - DBUG_PRINT("exit",("packed length: %d",(int) ((char*)to-startpos))); - DBUG_RETURN((uint) ((char*)to-startpos)); + DBUG_PRINT("exit",("packed length: %d",(int) (to-startpos))); + DBUG_RETURN((uint) (to-startpos)); } /* _ma_rec_pack */ @@ -1018,12 +1018,12 @@ uint _ma_rec_pack(MARIA_HA *info, register uchar *to, Returns 0 if record is ok. */ -my_bool _ma_rec_check(MARIA_HA *info,const char *record, uchar *rec_buff, +my_bool _ma_rec_check(MARIA_HA *info,const uchar *record, uchar *rec_buff, ulong packed_length, my_bool with_checksum, ha_checksum checksum) { uint length,new_length,flag,bit,i; - char *pos,*end,*packpos,*to; + uchar *pos,*end,*packpos,*to; enum en_fieldtype type; reg3 MARIA_COLUMNDEF *column; DBUG_ENTER("_ma_rec_check"); @@ -1123,7 +1123,7 @@ my_bool _ma_rec_check(MARIA_HA *info,const char *record, uchar *rec_buff, else to+= length; } - if (packed_length != (uint) (to - (char*) rec_buff) + + if (packed_length != (uint) (to - rec_buff) + test(info->s->calc_checksum) || (bit != 1 && (flag & ~(bit - 1)))) goto err; if (with_checksum && ((uchar) checksum != (uchar) *to)) diff --git a/storage/maria/ma_extra.c b/storage/maria/ma_extra.c index 2fc4873d535..9ee3b1a8870 100644 --- a/storage/maria/ma_extra.c +++ b/storage/maria/ma_extra.c @@ -379,11 +379,13 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, break; /* Not supported */ pthread_mutex_lock(&share->intern_lock); /* - Memory map the data file if it is not already mapped and if there - are no other threads using this table. intern_lock prevents other - threads from starting to use the table while we are mapping it. + Memory map the data file if it is not already mapped. It is safe + to memory map a file while other threads are using file I/O on it. + Assigning a new address to a function pointer is an atomic + operation. intern_lock prevents that two or more mappings are done + at the same time. */ - if (!share->file_map && (share->tot_locks == 1)) + if (!share->file_map) { if (_ma_dynmap_file(info, share->state.state.data_file_length)) { diff --git a/storage/maria/ma_ft_boolean_search.c b/storage/maria/ma_ft_boolean_search.c index 41661d1c288..e09a076ceaa 100644 --- a/storage/maria/ma_ft_boolean_search.c +++ b/storage/maria/ma_ft_boolean_search.c @@ -286,8 +286,8 @@ static int ftb_parse_query_internal(MYSQL_FTPARSER_PARAM *param, } -static void _ftb_parse_query(FTB *ftb, uchar *query, uint len, - struct st_mysql_ftparser *parser) +static int _ftb_parse_query(FTB *ftb, uchar *query, uint len, + struct st_mysql_ftparser *parser) { MYSQL_FTPARSER_PARAM *param; MY_FTB_PARAM ftb_param; @@ -295,9 +295,9 @@ static void _ftb_parse_query(FTB *ftb, uchar *query, uint len, DBUG_ASSERT(parser); if (ftb->state != UNINITIALIZED) - DBUG_VOID_RETURN; + DBUG_RETURN(0); if (! (param= maria_ftparser_call_initializer(ftb->info, ftb->keynr, 0))) - DBUG_VOID_RETURN; + DBUG_RETURN(1); ftb_param.ftb= ftb; ftb_param.depth= 0; @@ -312,8 +312,7 @@ static void _ftb_parse_query(FTB *ftb, uchar *query, uint len, param->length= len; param->flags= 0; param->mode= MYSQL_FTPARSER_FULL_BOOLEAN_INFO; - parser->parse(param); - DBUG_VOID_RETURN; + DBUG_RETURN(parser->parse(param)); } @@ -537,9 +536,10 @@ FT_INFO * maria_ft_init_boolean_search(MARIA_HA *info, uint keynr, uchar *query, ftbe->phrase= NULL; ftbe->document= 0; ftb->root=ftbe; - _ftb_parse_query(ftb, query, query_len, keynr == NO_SUCH_KEY ? - &ft_default_parser : - info->s->keyinfo[keynr].parser); + if (unlikely(_ftb_parse_query(ftb, query, query_len, + keynr == NO_SUCH_KEY ? &ft_default_parser : + info->s->keyinfo[keynr].parser))) + goto err; /* Hack: instead of init_queue, we'll use reinit queue to be able to alloc queue with alloc_root() @@ -621,7 +621,7 @@ static int ftb_check_phrase_internal(MYSQL_FTPARSER_PARAM *param, { param->mysql_add_word(param, word.pos, word.len, 0); if (phrase_param->match) - return 1; + break; } return 0; } @@ -639,6 +639,7 @@ static int ftb_check_phrase_internal(MYSQL_FTPARSER_PARAM *param, RETURN VALUE 1 is returned if phrase found, 0 else. + -1 is returned if error occurs. */ static int _ftb_check_phrase(FTB *ftb, const uchar *document, uint len, @@ -666,12 +667,13 @@ static int _ftb_check_phrase(FTB *ftb, const uchar *document, uint len, param->length= len; param->flags= 0; param->mode= MYSQL_FTPARSER_WITH_STOPWORDS; - parser->parse(param); + if (unlikely(parser->parse(param))) + return -1; DBUG_RETURN(ftb_param.match ? 1 : 0); } -static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_orig) +static int _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_orig) { FT_SEG_ITERATOR ftsi; FTB_EXPR *ftbe; @@ -703,17 +705,19 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_ weight=ftbe->cur_weight*ftbe->weight; if (mode && ftbe->phrase) { - int not_found=1; + int found= 0; memcpy(&ftsi, ftsi_orig, sizeof(ftsi)); - while (_ma_ft_segiterator(&ftsi) && not_found) + while (_ma_ft_segiterator(&ftsi) && !found) { if (!ftsi.pos) continue; - not_found = ! _ftb_check_phrase(ftb, ftsi.pos, ftsi.len, - ftbe, parser); + found= _ftb_check_phrase(ftb, ftsi.pos, ftsi.len, ftbe, parser); + if (unlikely(found < 0)) + return 1; } - if (not_found) break; + if (!found) + break; } /* ftbe->quot */ } else @@ -745,6 +749,7 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_ weight*= ftbe->weight; } } + return 0; } @@ -777,7 +782,11 @@ int maria_ft_boolean_read_next(FT_INFO *ftb, char *record) { while (curdoc == (ftbw=(FTB_WORD *)queue_top(& ftb->queue))->docid[0]) { - _ftb_climb_the_tree(ftb, ftbw, 0); + if (unlikely(_ftb_climb_the_tree(ftb, ftbw, 0))) + { + my_errno= HA_ERR_OUT_OF_MEM; + goto err; + } /* update queue */ _ft2_search(ftb, ftbw, 0); @@ -853,7 +862,8 @@ static int ftb_find_relevance_add_word(MYSQL_FTPARSER_PARAM *param, if (ftbw->docid[1] == ftb->info->cur_row.lastpos) continue; ftbw->docid[1]= ftb->info->cur_row.lastpos; - _ftb_climb_the_tree(ftb, ftbw, ftb_param->ftsi); + if (unlikely(_ftb_climb_the_tree(ftb, ftbw, ftb_param->ftsi))) + return 1; } return(0); } @@ -926,7 +936,8 @@ float maria_ft_boolean_find_relevance(FT_INFO *ftb, uchar *record, uint length) continue; param->doc= (uchar *)ftsi.pos; param->length= ftsi.len; - parser->parse(param); + if (unlikely(parser->parse(param))) + return 0; } ftbe=ftb->root; if (ftbe->docid[1]==docid && ftbe->cur_weight>0 && diff --git a/storage/maria/ma_ft_nlq_search.c b/storage/maria/ma_ft_nlq_search.c index cad5238d4a5..18b101f0e05 100644 --- a/storage/maria/ma_ft_nlq_search.c +++ b/storage/maria/ma_ft_nlq_search.c @@ -258,8 +258,12 @@ FT_INFO *maria_ft_init_nlq_search(MARIA_HA *info, uint keynr, uchar *query, { info->update|= HA_STATE_AKTIV; ftparser_param->flags= MYSQL_FTFLAGS_NEED_COPY; - _ma_ft_parse(&wtree, info, keynr, record, ftparser_param, - &wtree.mem_root); + if (unlikely(_ma_ft_parse(&wtree, info, keynr, record, ftparser_param, + &wtree.mem_root))) + { + delete_queue(&best); + goto err; + } } } delete_queue(&best); diff --git a/storage/maria/ma_info.c b/storage/maria/ma_info.c index cfb4580a72f..4aecc33f816 100644 --- a/storage/maria/ma_info.c +++ b/storage/maria/ma_info.c @@ -57,9 +57,9 @@ int maria_status(MARIA_HA *info, register MARIA_INFO *x, uint flag) x->keys = share->state.header.keys; x->check_time = share->state.check_time; - x->mean_reclength = info->state->records ? - (ulong) ((info->state->data_file_length-info->state->empty)/ - info->state->records) : (ulong) share->min_pack_length; + x->mean_reclength = x->records ? + (ulong) ((x->data_file_length - x->delete_length) /x ->records) : + (ulong) share->min_pack_length; } if (flag & HA_STATUS_ERRKEY) { diff --git a/storage/maria/ma_key.c b/storage/maria/ma_key.c index 83ba6853330..96b8d2af0eb 100644 --- a/storage/maria/ma_key.c +++ b/storage/maria/ma_key.c @@ -206,7 +206,7 @@ uint _ma_make_key(register MARIA_HA *info, uint keynr, uchar *key, uint keynr key number key Store packed key here old Not packed key - k_length Length of 'old' to use + keypart_map bitmap of used keyparts last_used_keyseg out parameter. May be NULL RETURN @@ -216,34 +216,37 @@ uint _ma_make_key(register MARIA_HA *info, uint keynr, uchar *key, */ uint _ma_pack_key(register MARIA_HA *info, uint keynr, uchar *key, - const uchar *old, uint k_length, HA_KEYSEG **last_used_keyseg) + const uchar *old, key_part_map keypart_map, + HA_KEYSEG **last_used_keyseg) { uchar *start_key=key; HA_KEYSEG *keyseg; my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT; DBUG_ENTER("_ma_pack_key"); - for (keyseg=info->s->keyinfo[keynr].seg ; - keyseg->type && (int) k_length > 0; - old+=keyseg->length, keyseg++) + /* "one part" rtree key is 2*SPDIMS part key in Maria */ + if (info->s->keyinfo[keynr].key_alg == HA_KEY_ALG_RTREE) + keypart_map= (((key_part_map)1) << (2*SPDIMS)) - 1; + + /* only key prefixes are supported */ + DBUG_ASSERT(((keypart_map+1) & keypart_map) == 0); + + for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type && keypart_map; + old+= keyseg->length, keyseg++) { - enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type; - uint length=min((uint) keyseg->length,(uint) k_length); + enum ha_base_keytype type= (enum ha_base_keytype) keyseg->type; + uint length= keyseg->length; uint char_length; const uchar *pos; CHARSET_INFO *cs=keyseg->charset; + keypart_map>>= 1; if (keyseg->null_bit) { - k_length--; if (!(*key++= (char) 1-*old++)) /* Copy null marker */ { - k_length-=length; if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART)) - { - k_length-=2; /* Skip length */ old+= 2; - } continue; /* Found NULL */ } } @@ -253,17 +256,16 @@ uint _ma_pack_key(register MARIA_HA *info, uint keynr, uchar *key, if (keyseg->flag & HA_SPACE_PACK) { const uchar *end= pos + length; - if (type != HA_KEYTYPE_NUM) - { - while (end > pos && end[-1] == ' ') - end--; - } - else + if (type == HA_KEYTYPE_NUM) { while (pos < end && pos[0] == ' ') pos++; } - k_length-=length; + else if (type != HA_KEYTYPE_BINARY) + { + while (end > pos && end[-1] == ' ') + end--; + } length=(uint) (end-pos); FIX_LENGTH(cs, pos, length, char_length); store_key_length_inc(key,char_length); @@ -275,7 +277,6 @@ uint _ma_pack_key(register MARIA_HA *info, uint keynr, uchar *key, { /* Length of key-part used with maria_rkey() always 2 */ uint tmp_length=uint2korr(pos); - k_length-= 2+length; pos+=2; set_if_smaller(length,tmp_length); /* Safety */ FIX_LENGTH(cs, pos, length, char_length); @@ -288,11 +289,8 @@ uint _ma_pack_key(register MARIA_HA *info, uint keynr, uchar *key, else if (keyseg->flag & HA_SWAP_KEY) { /* Numerical column */ pos+=length; - k_length-=length; while (length--) - { *key++ = *--pos; - } continue; } FIX_LENGTH(cs, pos, length, char_length); @@ -300,30 +298,10 @@ uint _ma_pack_key(register MARIA_HA *info, uint keynr, uchar *key, if (length > char_length) cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' '); key+= length; - k_length-=length; } if (last_used_keyseg) *last_used_keyseg= keyseg; -#ifdef NOT_USED - if (keyseg->type) - { - /* Part-key ; fill with ASCII 0 for easier searching */ - length= (uint) -k_length; /* unused part of last key */ - do - { - if (keyseg->flag & HA_NULL_PART) - length++; - if (keyseg->flag & HA_SPACE_PACK) - length+=2; - else - length+= keyseg->length; - keyseg++; - } while (keyseg->type); - bzero(key,length); - key+=length; - } -#endif DBUG_PRINT("exit", ("length: %u", (uint) (key-start_key))); DBUG_RETURN((uint) (key-start_key)); } /* _ma_pack_key */ diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c index fd007e2a5ae..9d1514a67c3 100644 --- a/storage/maria/ma_loghandler.c +++ b/storage/maria/ma_loghandler.c @@ -3553,8 +3553,8 @@ static my_bool translog_relative_LSN_encode(struct st_translog_parts *parts, COMPRESSED_LSN_MAX_STORE_SIZE)) - dst_ptr); parts->record_length-= (economy= lsns_len - part->length); - DBUG_PRINT("info", ("new length of LSNs: %u economy: %d", - part->length, economy)); + DBUG_PRINT("info", ("new length of LSNs: %lu economy: %d", + (ulong)part->length, economy)); parts->total_record_length-= economy; part->str= (char*)dst_ptr; } diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c index e6df213609b..67a76144c26 100644 --- a/storage/maria/ma_open.c +++ b/storage/maria/ma_open.c @@ -392,7 +392,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) key_parts+=fulltext_keys*FT_SEGS; if (share->base.max_key_length > maria_max_key_length() || - keys > MARIA_MAX_KEY || key_parts >= MARIA_MAX_KEY * HA_MAX_KEY_SEG) + keys > MARIA_MAX_KEY || key_parts > MARIA_MAX_KEY * HA_MAX_KEY_SEG) { DBUG_PRINT("error",("Wrong key info: Max_key_length: %d keys: %d key_parts: %d", share->base.max_key_length, keys, key_parts)); my_errno=HA_ERR_UNSUPPORTED; @@ -667,22 +667,6 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) _ma_setup_functions(share); if ((*share->once_init)(share, info.dfile.file)) goto err; - if (open_flags & HA_OPEN_MMAP) - { - info.s= share; - if (_ma_dynmap_file(&info, share->state.state.data_file_length)) - { - /* purecov: begin inspected */ - /* Ignore if mmap fails. Use file I/O instead. */ - DBUG_PRINT("warning", ("mmap failed: errno: %d", errno)); - /* purecov: end */ - } - else - { - share->file_read= _ma_mmap_pread; - share->file_write= _ma_mmap_pwrite; - } - } share->is_log_table= FALSE; if (open_flags & HA_OPEN_TMP_TABLE) share->options|= HA_OPTION_TMP_TABLE; @@ -721,6 +705,14 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags) } } #endif + /* + Memory mapping can only be requested after initializing intern_lock. + */ + if (open_flags & HA_OPEN_MMAP) + { + info.s= share; + maria_extra(&info, HA_EXTRA_MMAP, 0); + } } else { @@ -1022,10 +1014,10 @@ uint _ma_state_info_write(File file, MARIA_STATE_INFO *state, uint pWrite) } if (pWrite & 1) - DBUG_RETURN(my_pwrite(file,(char*) buff, (uint) (ptr-buff), 0L, - MYF(MY_NABP | MY_THREADSAFE))); - DBUG_RETURN(my_write(file, (char*) buff, (uint) (ptr-buff), - MYF(MY_NABP))); + DBUG_RETURN(my_pwrite(file, buff, (size_t) (ptr-buff), 0L, + MYF(MY_NABP | MY_THREADSAFE)) != 0); + DBUG_RETURN(my_write(file, buff, (size_t) (ptr-buff), + MYF(MY_NABP)) != 0); } @@ -1089,10 +1081,10 @@ uint _ma_state_info_read_dsk(File file, MARIA_STATE_INFO *state, my_bool pRead) if (pRead) { if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP))) - return (MY_FILE_ERROR); + return 1; } else if (my_read(file, buff, state->state_length,MYF(MY_NABP))) - return (MY_FILE_ERROR); + return 1; _ma_state_info_read(buff, state); } return 0; @@ -1143,7 +1135,7 @@ uint _ma_base_info_write(File file, MARIA_BASE_INFO *base) *ptr++= base->extra_alloc_procent; bzero(ptr,16); ptr+= 16; /* extra */ DBUG_ASSERT((ptr - buff) == MARIA_BASE_INFO_SIZE); - return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP)); + return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0; } @@ -1204,7 +1196,7 @@ uint _ma_keydef_write(File file, MARIA_KEYDEF *keydef) mi_int2store(ptr,keydef->keylength); ptr+= 2; mi_int2store(ptr,keydef->minlength); ptr+= 2; mi_int2store(ptr,keydef->maxlength); ptr+= 2; - return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP)); + return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0; } char *_ma_keydef_read(char *ptr, MARIA_KEYDEF *keydef) @@ -1247,7 +1239,7 @@ int _ma_keyseg_write(File file, const HA_KEYSEG *keyseg) mi_int4store(ptr, pos); ptr+=4; - return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP)); + return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0; } @@ -1287,7 +1279,7 @@ uint _ma_uniquedef_write(File file, MARIA_UNIQUEDEF *def) *ptr++= (uchar) def->key; *ptr++ = (uchar) def->null_are_equal; - return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP)); + return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0; } char *_ma_uniquedef_read(char *ptr, MARIA_UNIQUEDEF *def) @@ -1315,7 +1307,7 @@ uint _ma_columndef_write(File file, MARIA_COLUMNDEF *columndef) mi_int2store(ptr,columndef->empty_pos); ptr+= 2; (*ptr++)= columndef->null_bit; (*ptr++)= columndef->empty_bit; - return my_write(file,(char*) buff, (uint) (ptr-buff), MYF(MY_NABP)); + return my_write(file, buff, (size_t) (ptr-buff), MYF(MY_NABP)) != 0; } char *_ma_columndef_read(char *ptr, MARIA_COLUMNDEF *columndef) diff --git a/storage/maria/ma_preload.c b/storage/maria/ma_preload.c index 35ae8868ee7..138bb94f7d0 100644 --- a/storage/maria/ma_preload.c +++ b/storage/maria/ma_preload.c @@ -55,12 +55,17 @@ int maria_preload(MARIA_HA *info, ulonglong key_map, my_bool ignore_leaves) block_length= keyinfo[0].block_length; - /* Check whether all indexes use the same block size */ - for (i= 1 ; i < keys ; i++) + if (ignore_leaves) { - if (keyinfo[i].block_length != block_length) - DBUG_RETURN(my_errno= HA_ERR_NON_UNIQUE_BLOCK_SIZE); + /* Check whether all indexes use the same block size */ + for (i= 1 ; i < keys ; i++) + { + if (keyinfo[i].block_length != block_length) + DBUG_RETURN(my_errno= HA_ERR_NON_UNIQUE_BLOCK_SIZE); + } } + else + block_length= share->pagecache->block_size; length= info->preload_buff_size/block_length * block_length; set_if_bigger(length, block_length); diff --git a/storage/maria/ma_range.c b/storage/maria/ma_range.c index 7250e6796d2..70dd522b8a1 100644 --- a/storage/maria/ma_range.c +++ b/storage/maria/ma_range.c @@ -21,12 +21,11 @@ #include "maria_def.h" #include "ma_rt_index.h" -static ha_rows _ma_record_pos(MARIA_HA *info,const uchar *key,uint key_len, - enum ha_rkey_function search_flag); -static double _ma_search_pos(MARIA_HA *info,MARIA_KEYDEF *keyinfo, uchar *key, - uint key_len,uint nextflag, my_off_t pos); -static uint _ma_keynr(MARIA_HA *info, MARIA_KEYDEF *keyinfo, uchar *page, - uchar *keypos, uint *ret_max_key); +static ha_rows _ma_record_pos(MARIA_HA *,const uchar *, key_part_map, + enum ha_rkey_function); +static double _ma_search_pos(MARIA_HA *, MARIA_KEYDEF *, uchar *, + uint, uint, my_off_t); +static uint _ma_keynr(MARIA_HA *, MARIA_KEYDEF *, uchar *, uchar *, uint *); /** @@ -84,7 +83,7 @@ ha_rows maria_records_in_range(MARIA_HA *info, int inx, key_range *min_key, } key_buff= info->lastkey+info->s->base.max_key_length; start_key_len= _ma_pack_key(info,inx, key_buff, - min_key->key, min_key->length, + min_key->key, min_key->keypart_map, (HA_KEYSEG**) 0); res= maria_rtree_estimate(info, inx, key_buff, start_key_len, maria_read_vec[min_key->flag]); @@ -95,13 +94,13 @@ ha_rows maria_records_in_range(MARIA_HA *info, int inx, key_range *min_key, case HA_KEY_ALG_BTREE: default: start_pos= (min_key ? - _ma_record_pos(info, min_key->key, min_key->length, + _ma_record_pos(info, min_key->key, min_key->keypart_map, min_key->flag) : (ha_rows) 0); end_pos= (max_key ? - _ma_record_pos(info, max_key->key, max_key->length, + _ma_record_pos(info, max_key->key, max_key->keypart_map, max_key->flag) : - info->state->records+ (ha_rows) 1); + info->state->records + (ha_rows) 1); res= (end_pos < start_pos ? (ha_rows) 0 : (end_pos == start_pos ? (ha_rows) 1 : end_pos-start_pos)); if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR) @@ -126,20 +125,22 @@ ha_rows maria_records_in_range(MARIA_HA *info, int inx, key_range *min_key, /* Find relative position (in records) for key in index-tree */ -static ha_rows _ma_record_pos(MARIA_HA *info, const uchar *key, uint key_len, +static ha_rows _ma_record_pos(MARIA_HA *info, const uchar *key, + key_part_map keypart_map, enum ha_rkey_function search_flag) { - uint inx=(uint) info->lastinx, nextflag; + uint inx=(uint) info->lastinx, nextflag, key_len; MARIA_KEYDEF *keyinfo=info->s->keyinfo+inx; uchar *key_buff; double pos; DBUG_ENTER("_ma_record_pos"); DBUG_PRINT("enter",("search_flag: %d",search_flag)); + DBUG_ASSERT(keypart_map); if (key_len == 0) key_len= USE_WHOLE_KEY; key_buff=info->lastkey+info->s->base.max_key_length; - key_len= _ma_pack_key(info, inx, key_buff, key, key_len, + key_len= _ma_pack_key(info, inx, key_buff, key, keypart_map, (HA_KEYSEG**) 0); DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, keyinfo->seg, key_buff, key_len);); @@ -147,8 +148,42 @@ static ha_rows _ma_record_pos(MARIA_HA *info, const uchar *key, uint key_len, if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST))) key_len=USE_WHOLE_KEY; + /* + my_handler.c:mi_compare_text() has a flag 'skip_end_space'. + This is set in my_handler.c:ha_key_cmp() in dependence on the + compare flags 'nextflag' and the column type. + + TEXT columns are of type HA_KEYTYPE_VARTEXT. In this case the + condition is skip_end_space= ((nextflag & (SEARCH_FIND | + SEARCH_UPDATE)) == SEARCH_FIND). + + SEARCH_FIND is used for an exact key search. The combination + SEARCH_FIND | SEARCH_UPDATE is used in write/update/delete + operations with a comment like "Not real duplicates", whatever this + means. From the condition above we can see that 'skip_end_space' is + always false for these operations. The result is that trailing space + counts in key comparison and hence, emtpy strings ('', string length + zero, but not NULL) compare less that strings starting with control + characters and these in turn compare less than strings starting with + blanks. + + When estimating the number of records in a key range, we request an + exact search for the minimum key. This translates into a plain + SEARCH_FIND flag. Using this alone would lead to a 'skip_end_space' + compare. Empty strings would be expected above control characters. + Their keys would not be found because they are located below control + characters. + + This is the reason that we add the SEARCH_UPDATE flag here. It makes + the key estimation compare in the same way like key write operations + do. Olny so we will find the keys where they have been inserted. + + Adding the flag unconditionally does not hurt as it is used in the + above mentioned condition only. So it can safely be used together + with other flags. + */ pos= _ma_search_pos(info,keyinfo, key_buff, key_len, - nextflag | SEARCH_SAVE_BUFF, + nextflag | SEARCH_SAVE_BUFF | SEARCH_UPDATE, info->s->state.key_root[inx]); if (pos >= 0.0) { diff --git a/storage/maria/ma_rkey.c b/storage/maria/ma_rkey.c index ef8b8468f1f..c9653d30110 100644 --- a/storage/maria/ma_rkey.c +++ b/storage/maria/ma_rkey.c @@ -22,7 +22,7 @@ /* Ordinary search_flag is 0 ; Give error if no record with key */ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key, - uint key_len, enum ha_rkey_function search_flag) + key_part_map keypart_map, enum ha_rkey_function search_flag) { uchar *key_buff; MARIA_SHARE *share=info->s; @@ -47,20 +47,21 @@ int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key, key is already packed!; This happens when we are using a MERGE TABLE */ key_buff= info->lastkey+info->s->base.max_key_length; - pack_key_length= key_len; - bmove(key_buff,key,key_len); - last_used_keyseg= 0; + pack_key_length= keypart_map; + bmove(key_buff, key, pack_key_length); + last_used_keyseg= info->s->keyinfo[inx].seg + info->last_used_keyseg; } else { - if (key_len == 0) - key_len=USE_WHOLE_KEY; + DBUG_ASSERT(keypart_map); /* Save the packed key for later use in the second buffer of lastkey. */ key_buff=info->lastkey+info->s->base.max_key_length; pack_key_length= _ma_pack_key(info,(uint) inx, key_buff, key, - key_len, &last_used_keyseg); + keypart_map, &last_used_keyseg); /* Save packed_key_length for use by the MERGE engine. */ info->pack_key_length= pack_key_length; + info->last_used_keyseg= (uint16) (last_used_keyseg - + info->s->keyinfo[inx].seg); DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, keyinfo->seg, key_buff, pack_key_length);); } diff --git a/storage/maria/ma_rt_index.c b/storage/maria/ma_rt_index.c index 4d99eade9b5..4980233fc11 100644 --- a/storage/maria/ma_rt_index.c +++ b/storage/maria/ma_rt_index.c @@ -187,6 +187,7 @@ int maria_rtree_find_first(MARIA_HA *info, uint keynr, uchar *key, /* Save searched key, include data pointer. The data pointer is required if the search_flag contains MBR_DATA. + (minimum bounding rectangle) */ memcpy(info->first_mbr_key, key, keyinfo->keylength); info->last_rkey_length = key_length; @@ -546,16 +547,19 @@ static int maria_rtree_insert_req(MARIA_HA *info, MARIA_KEYDEF *keyinfo, uint nod_flag; int res; uchar *page_buf, *k; + DBUG_ENTER("maria_rtree_insert_req"); if (!(page_buf= (uchar*) my_alloca((uint)keyinfo->block_length + HA_MAX_KEY_BUFF))) { my_errno = HA_ERR_OUT_OF_MEM; - return -1; + DBUG_RETURN(-1); /* purecov: inspected */ } if (!_ma_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0)) goto err1; nod_flag = _ma_test_if_nod(page_buf); + DBUG_PRINT("rtree", ("page: %lu level: %d ins_level: %d nod_flag: %u", + (ulong) page, level, ins_level, nod_flag)); if ((ins_level == -1 && nod_flag) || /* key: go down to leaf */ (ins_level > -1 && ins_level > level)) /* branch: go down to ins_level */ @@ -609,11 +613,11 @@ static int maria_rtree_insert_req(MARIA_HA *info, MARIA_KEYDEF *keyinfo, ok: my_afree(page_buf); - return res; + DBUG_RETURN(res); err1: my_afree(page_buf); - return -1; + DBUG_RETURN(-1); /* purecov: inspected */ } @@ -633,18 +637,19 @@ static int maria_rtree_insert_level(MARIA_HA *info, uint keynr, uchar *key, MARIA_KEYDEF *keyinfo = info->s->keyinfo + keynr; int res; my_off_t new_page; + DBUG_ENTER("maria_rtree_insert_level"); if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) { if ((old_root = _ma_new(info, keyinfo, DFLT_INIT_HITS)) == HA_OFFSET_ERROR) - return -1; + DBUG_RETURN(-1); info->keyread_buff_used = 1; maria_putint(info->buff, 2, 0); res = maria_rtree_add_key(info, keyinfo, key, key_length, info->buff, NULL); if (_ma_write_keypage(info, keyinfo, old_root, DFLT_INIT_HITS, info->buff)) - return 1; + DBUG_RETURN(1); info->s->state.key_root[keynr] = old_root; - return res; + DBUG_RETURN(res); } switch ((res = maria_rtree_insert_req(info, keyinfo, key, key_length, @@ -660,11 +665,12 @@ static int maria_rtree_insert_level(MARIA_HA *info, uint keynr, uchar *key, my_off_t new_root; uint nod_flag = info->s->base.key_reflength; + DBUG_PRINT("rtree", ("root was split, grow a new root")); if (!(new_root_buf= (uchar*) my_alloca((uint)keyinfo->block_length + HA_MAX_KEY_BUFF))) { my_errno = HA_ERR_OUT_OF_MEM; - return -1; + DBUG_RETURN(-1); /* purecov: inspected */ } maria_putint(new_root_buf, 2, nod_flag); @@ -694,12 +700,15 @@ static int maria_rtree_insert_level(MARIA_HA *info, uint keynr, uchar *key, DFLT_INIT_HITS, new_root_buf)) goto err1; info->s->state.key_root[keynr] = new_root; + DBUG_PRINT("rtree", ("new root page: %lu level: %d nod_flag: %u", + (ulong) new_root, 0, + _ma_test_if_nod(new_root_buf))); my_afree((uchar*)new_root_buf); break; err1: my_afree((uchar*)new_root_buf); - return -1; + DBUG_RETURN(-1); /* purecov: inspected */ } default: case -1: /* error */ @@ -707,7 +716,7 @@ err1: break; } } - return res; + DBUG_RETURN(res); } @@ -721,9 +730,10 @@ err1: int maria_rtree_insert(MARIA_HA *info, uint keynr, uchar *key, uint key_length) { - return (!key_length || - (maria_rtree_insert_level(info, keynr, key, key_length, -1) == -1)) ? - -1 : 0; + DBUG_ENTER("maria_rtree_insert"); + DBUG_RETURN((!key_length || + (maria_rtree_insert_level(info, keynr, key, key_length, -1) == -1)) ? + -1 : 0); } @@ -738,6 +748,8 @@ int maria_rtree_insert(MARIA_HA *info, uint keynr, uchar *key, uint key_length) static int maria_rtree_fill_reinsert_list(stPageList *ReinsertList, my_off_t page, int level) { + DBUG_ENTER("maria_rtree_fill_reinsert_list"); + DBUG_PRINT("rtree", ("page: %lu level: %d", (ulong) page, level)); if (ReinsertList->n_pages == ReinsertList->m_pages) { ReinsertList->m_pages += REINSERT_BUFFER_INC; @@ -749,10 +761,10 @@ static int maria_rtree_fill_reinsert_list(stPageList *ReinsertList, my_off_t pag ReinsertList->pages[ReinsertList->n_pages].offs = page; ReinsertList->pages[ReinsertList->n_pages].level = level; ReinsertList->n_pages++; - return 0; + DBUG_RETURN(0); err1: - return -1; + DBUG_RETURN(-1); /* purecov: inspected */ } @@ -776,15 +788,18 @@ static int maria_rtree_delete_req(MARIA_HA *info, MARIA_KEYDEF *keyinfo, uint nod_flag; int res; uchar *page_buf, *last, *k; + DBUG_ENTER("maria_rtree_delete_req"); if (!(page_buf = (uchar*) my_alloca((uint)keyinfo->block_length))) { my_errno = HA_ERR_OUT_OF_MEM; - return -1; + DBUG_RETURN(-1); /* purecov: inspected */ } if (!_ma_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0)) goto err1; nod_flag = _ma_test_if_nod(page_buf); + DBUG_PRINT("rtree", ("page: %lu level: %d nod_flag: %u", + (ulong) page, level, nod_flag)); k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); last = rt_PAGE_END(page_buf); @@ -806,6 +821,7 @@ static int maria_rtree_delete_req(MARIA_HA *info, MARIA_KEYDEF *keyinfo, rt_PAGE_MIN_SIZE(keyinfo->block_length)) { /* OK */ + /* Calculate a new key value (MBR) for the shrinked block. */ if (maria_rtree_set_key_mbr(info, keyinfo, k, key_length, _ma_kpos(nod_flag, k))) goto err1; @@ -815,11 +831,24 @@ static int maria_rtree_delete_req(MARIA_HA *info, MARIA_KEYDEF *keyinfo, } else { - /* too small: delete key & add it descendant to reinsert list */ + /* + Too small: delete key & add it descendant to reinsert list. + Store position and level of the block so that it can be + accessed later for inserting the remaining keys. + */ + DBUG_PRINT("rtree", ("too small. move block to reinsert list")); if (maria_rtree_fill_reinsert_list(ReinsertList, _ma_kpos(nod_flag, k), level + 1)) goto err1; + /* + Delete the key that references the block. This makes the + block disappear from the index. Hence we need to insert + its remaining keys later. Note: if the block is a branch + block, we do not only remove this block, but the whole + subtree. So we need to re-insert its keys on the same + level later to reintegrate the subtrees. + */ maria_rtree_delete_key(info, page_buf, k, key_length, nod_flag); if (_ma_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf)) @@ -879,11 +908,11 @@ static int maria_rtree_delete_req(MARIA_HA *info, MARIA_KEYDEF *keyinfo, ok: my_afree((uchar*)page_buf); - return res; + DBUG_RETURN(res); err1: my_afree((uchar*)page_buf); - return -1; + DBUG_RETURN(-1); /* purecov: inspected */ } @@ -901,12 +930,15 @@ int maria_rtree_delete(MARIA_HA *info, uint keynr, uchar *key, uint key_length) stPageList ReinsertList; my_off_t old_root; MARIA_KEYDEF *keyinfo = info->s->keyinfo + keynr; + DBUG_ENTER("maria_rtree_delete"); if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) { my_errno= HA_ERR_END_OF_FILE; - return -1; + DBUG_RETURN(-1); /* purecov: inspected */ } + DBUG_PRINT("rtree", ("starting deletion at root page: %lu", + (ulong) old_root)); ReinsertList.pages = NULL; ReinsertList.n_pages = 0; @@ -915,12 +947,12 @@ int maria_rtree_delete(MARIA_HA *info, uint keynr, uchar *key, uint key_length) switch (maria_rtree_delete_req(info, keyinfo, key, key_length, old_root, &page_size, &ReinsertList, 0)) { - case 2: + case 2: /* empty */ { info->s->state.key_root[keynr] = HA_OFFSET_ERROR; - return 0; + DBUG_RETURN(0); } - case 0: + case 0: /* deleted */ { uint nod_flag; ulong i; @@ -937,16 +969,35 @@ int maria_rtree_delete(MARIA_HA *info, uint keynr, uchar *key, uint key_length) DFLT_INIT_HITS, page_buf, 0)) goto err1; nod_flag = _ma_test_if_nod(page_buf); + DBUG_PRINT("rtree", ("reinserting keys from " + "page: %lu level: %d nod_flag: %u", + (ulong) ReinsertList.pages[i].offs, + ReinsertList.pages[i].level, nod_flag)); + k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); last = rt_PAGE_END(page_buf); for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag)) { - if (maria_rtree_insert_level(info, keynr, k, key_length, - ReinsertList.pages[i].level) == -1) + int res; + if ((res= + maria_rtree_insert_level(info, keynr, k, key_length, + ReinsertList.pages[i].level)) == -1) { my_afree(page_buf); goto err1; } + if (res) + { + ulong j; + DBUG_PRINT("rtree", ("root has been split, adjust levels")); + for (j= i; j < ReinsertList.n_pages; j++) + { + ReinsertList.pages[j].level++; + DBUG_PRINT("rtree", ("keys from page: %lu now level: %d", + (ulong) ReinsertList.pages[i].offs, + ReinsertList.pages[i].level)); + } + } } my_afree(page_buf); if (_ma_dispose(info, keyinfo, ReinsertList.pages[i].offs, @@ -973,19 +1024,19 @@ int maria_rtree_delete(MARIA_HA *info, uint keynr, uchar *key, uint key_length) info->s->state.key_root[keynr] = new_root; } info->update= HA_STATE_DELETED; - return 0; + DBUG_RETURN(0); err1: - return -1; + DBUG_RETURN(-1); /* purecov: inspected */ } case 1: /* not found */ { my_errno = HA_ERR_KEY_NOT_FOUND; - return -1; + DBUG_RETURN(-1); /* purecov: inspected */ } default: case -1: /* error */ - return -1; + DBUG_RETURN(-1); /* purecov: inspected */ } } diff --git a/storage/maria/ma_rt_key.c b/storage/maria/ma_rt_key.c index 1b9f246081d..b74d5d06690 100644 --- a/storage/maria/ma_rt_key.c +++ b/storage/maria/ma_rt_key.c @@ -34,6 +34,7 @@ int maria_rtree_add_key(MARIA_HA *info, MARIA_KEYDEF *keyinfo, uchar *key, { uint page_size = maria_data_on_page(page_buf); uint nod_flag = _ma_test_if_nod(page_buf); + DBUG_ENTER("maria_rtree_add_key"); if (page_size + key_length + info->s->base.rec_reflength <= keyinfo->block_length) @@ -42,22 +43,27 @@ int maria_rtree_add_key(MARIA_HA *info, MARIA_KEYDEF *keyinfo, uchar *key, if (nod_flag) { /* save key */ + DBUG_ASSERT(_ma_kpos(nod_flag, key) < info->state->key_file_length); memcpy(rt_PAGE_END(page_buf), key - nod_flag, key_length + nod_flag); page_size += key_length + nod_flag; } else { /* save key */ + DBUG_ASSERT(_ma_dpos(info, nod_flag, key + key_length + + info->s->base.rec_reflength) < + info->state->data_file_length + + info->s->base.pack_reclength); memcpy(rt_PAGE_END(page_buf), key, key_length + info->s->base.rec_reflength); page_size += key_length + info->s->base.rec_reflength; } maria_putint(page_buf, page_size, nod_flag); - return 0; + DBUG_RETURN(0); } - return (maria_rtree_split_page(info, keyinfo, page_buf, key, key_length, - new_page) ? -1 : 1); + DBUG_RETURN(maria_rtree_split_page(info, keyinfo, page_buf, key, key_length, + new_page) ? -1 : 1); } @@ -91,11 +97,13 @@ int maria_rtree_delete_key(MARIA_HA *info, uchar *page_buf, uchar *key, int maria_rtree_set_key_mbr(MARIA_HA *info, MARIA_KEYDEF *keyinfo, uchar *key, uint key_length, my_off_t child_page) { + DBUG_ENTER("maria_rtree_set_key_mbr"); if (!_ma_fetch_keypage(info, keyinfo, child_page, DFLT_INIT_HITS, info->buff, 0)) - return -1; + DBUG_RETURN(-1); - return maria_rtree_page_mbr(info, keyinfo->seg, info->buff, key, key_length); + DBUG_RETURN(maria_rtree_page_mbr(info, keyinfo->seg, + info->buff, key, key_length)); } #endif /*HAVE_RTREE_KEYS*/ diff --git a/storage/maria/ma_rt_split.c b/storage/maria/ma_rt_split.c index 9d195d802c1..a91eaa47bea 100644 --- a/storage/maria/ma_rt_split.c +++ b/storage/maria/ma_rt_split.c @@ -266,13 +266,15 @@ int maria_rtree_split_page(MARIA_HA *info, MARIA_KEYDEF *keyinfo, uint full_length= key_length + (nod_flag ? nod_flag : info->s->base.rec_reflength); int max_keys= (maria_data_on_page(page)-2) / (full_length); + DBUG_ENTER("maria_rtree_split_page"); + DBUG_PRINT("rtree", ("splitting block")); n_dim = keyinfo->keysegs / 2; if (!(coord_buf= (double*) my_alloca(n_dim * 2 * sizeof(double) * (max_keys + 1 + 4) + sizeof(SplitStruct) * (max_keys + 1)))) - return -1; + DBUG_RETURN(-1); /* purecov: inspected */ task= (SplitStruct *)(coord_buf + n_dim * 2 * (max_keys + 1 + 4)); @@ -343,12 +345,18 @@ int maria_rtree_split_page(MARIA_HA *info, MARIA_KEYDEF *keyinfo, else err_code= _ma_write_keypage(info, keyinfo, *new_page_offs, DFLT_INIT_HITS, new_page); + DBUG_PRINT("rtree", ("split new block: %lu", (ulong) *new_page_offs)); my_afree((uchar*)new_page); split_err: + /** + @todo the cast below is useless (coord_buf is uchar*); at the moment we + changed all "byte" to "uchar", some casts became useless and should be + removed. + */ my_afree((uchar*) coord_buf); - return err_code; + DBUG_RETURN(err_code); } #endif /*HAVE_RTREE_KEYS*/ diff --git a/storage/maria/ma_search.c b/storage/maria/ma_search.c index d9bc5cd6264..8cb3e56e646 100644 --- a/storage/maria/ma_search.c +++ b/storage/maria/ma_search.c @@ -927,11 +927,16 @@ uint _ma_get_binary_pack_key(register MARIA_KEYDEF *keyinfo, uint nod_flag, /* Keys are compressed the following way: - prefix length Packed length of prefix for the prev key. (1 or 3 bytes) + prefix length Packed length of prefix common with prev key. (1 or 3 bytes) for each key segment: [is null] Null indicator if can be null (1 byte, zero means null) [length] Packed length if varlength (1 or 3 bytes) + key segment 'length' bytes of key segment value pointer Reference to the data file (last_keyseg->length). + + get_key_length() is a macro. It gets the prefix length from 'page' + and puts it into 'length'. It increments 'page' by 1 or 3, depending + on the packed length of the prefix length. */ get_key_length(length,page); if (length) @@ -946,34 +951,44 @@ uint _ma_get_binary_pack_key(register MARIA_KEYDEF *keyinfo, uint nod_flag, my_errno=HA_ERR_CRASHED; DBUG_RETURN(0); /* Wrong key */ } - from=key; from_end=key+length; + /* Key is packed against prev key, take prefix from prev key. */ + from= key; + from_end= key + length; } else { - from=page; from_end=page_end; /* Not packed key */ + /* Key is not packed against prev key, take all from page buffer. */ + from= page; + from_end= page_end; } /* - The trouble is that key is split in two parts: - The first part is in from ...from_end-1. - The second part starts at page + The trouble is that key can be split in two parts: + The first part (prefix) is in from .. from_end - 1. + The second part starts at page. + The split can be at every byte position. So we need to check for + the end of the first part before using every byte. */ for (keyseg=keyinfo->seg ; keyseg->type ;keyseg++) { if (keyseg->flag & HA_NULL_PART) { + /* If prefix is used up, switch to rest. */ if (from == from_end) { from=page; from_end=page_end; } if (!(*key++ = *from++)) continue; /* Null part */ } if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK)) { - /* Get length of dynamic length key part */ + /* If prefix is used up, switch to rest. */ if (from == from_end) { from=page; from_end=page_end; } + /* Get length of dynamic length key part */ if ((length= (uint) (uchar) (*key++ = *from++)) == 255) { + /* If prefix is used up, switch to rest. */ if (from == from_end) { from=page; from_end=page_end; } length= ((uint) (uchar) ((*key++ = *from++))) << 8; + /* If prefix is used up, switch to rest. */ if (from == from_end) { from=page; from_end=page_end; } length+= (uint) (uchar) ((*key++ = *from++)); } @@ -994,14 +1009,26 @@ uint _ma_get_binary_pack_key(register MARIA_KEYDEF *keyinfo, uint nod_flag, key+=length; from+=length; } + /* + Last segment (type == 0) contains length of data pointer. + If we have mixed key blocks with data pointer and key block pointer, + we have to copy both. + */ length=keyseg->length+nod_flag; if ((tmp=(uint) (from_end-from)) <= length) { + /* Remaining length is less or equal max possible length. */ memcpy(key+tmp,page,length-tmp); /* Get last part of key */ *page_pos= page+length-tmp; } else { + /* + Remaining length is greater than max possible length. + This can happen only if we switched to the new key bytes already. + 'page_end' is calculated with MI_MAX_KEY_BUFF. So it can be far + behind the real end of the key. + */ if (from_end != page_end) { DBUG_PRINT("error",("Error when unpacking key")); @@ -1009,6 +1036,7 @@ uint _ma_get_binary_pack_key(register MARIA_KEYDEF *keyinfo, uint nod_flag, my_errno=HA_ERR_CRASHED; DBUG_RETURN(0); /* Error */ } + /* Copy data pointer and, if appropriate, key block pointer. */ memcpy((uchar*) key,(uchar*) from,(size_t) length); *page_pos= from+length; } diff --git a/storage/maria/ma_sort.c b/storage/maria/ma_sort.c index bc2b75807d9..2851a3a09dd 100644 --- a/storage/maria/ma_sort.c +++ b/storage/maria/ma_sort.c @@ -138,8 +138,9 @@ int _ma_create_index_by_sort(MARIA_SORT_PARAM *info, my_bool no_messages, while (memavl >= MIN_SORT_MEMORY) { - if ((my_off_t) (records+1)*(sort_length+sizeof(char*)) <= - (my_off_t) memavl) + if ((records < UINT_MAX32) && + ((my_off_t) (records + 1) * + (sort_length + sizeof(char*)) <= (my_off_t) memavl)) keys= records+1; else do @@ -151,7 +152,7 @@ int _ma_create_index_by_sort(MARIA_SORT_PARAM *info, my_bool no_messages, keys < (uint) maxbuffer) { _ma_check_print_error(info->sort_info->param, - "sort_buffer_size is to small"); + "maria_sort_buffer_size is too small"); goto err; } } @@ -175,7 +176,8 @@ int _ma_create_index_by_sort(MARIA_SORT_PARAM *info, my_bool no_messages, } if (memavl < MIN_SORT_MEMORY) { - _ma_check_print_error(info->sort_info->param,"Sort buffer to small"); /* purecov: tested */ + _ma_check_print_error(info->sort_info->param, "Maria sort buffer" + " too small"); /* purecov: tested */ goto err; /* purecov: tested */ } (*info->lock_in_memory)(info->sort_info->param);/* Everything is allocated */ @@ -369,7 +371,7 @@ pthread_handler_t _ma_thr_find_all_keys(void *arg) keys < (uint) maxbuffer) { _ma_check_print_error(sort_param->sort_info->param, - "sort_buffer_size is to small"); + "maria_sort_buffer_size is too small"); goto err; } } @@ -397,7 +399,7 @@ pthread_handler_t _ma_thr_find_all_keys(void *arg) if (memavl < MIN_SORT_MEMORY) { _ma_check_print_error(sort_param->sort_info->param, - "Sort buffer too small"); + "Maria sort buffer too small"); goto err; /* purecov: tested */ } @@ -775,7 +777,7 @@ static int NEAR_F merge_many_buff(MARIA_SORT_PARAM *info, uint keys, { if (merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff++, buffpek+i,buffpek+i+MERGEBUFF-1)) - break; /* purecov: inspected */ + goto cleanup; } if (merge_buffers(info,keys,from_file,to_file,sort_keys,lastbuff++, buffpek+i,buffpek+ *maxbuffer)) @@ -785,6 +787,7 @@ static int NEAR_F merge_many_buff(MARIA_SORT_PARAM *info, uint keys, temp=from_file; from_file=to_file; to_file=temp; *maxbuffer= (int) (lastbuff-buffpek)-1; } +cleanup: close_cached_file(to_file); /* This holds old result */ if (to_file == t_file) *t_file=t_file2; /* Copy result file */ diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h index 62f37077ceb..e2dc7d3be86 100644 --- a/storage/maria/maria_def.h +++ b/storage/maria/maria_def.h @@ -442,6 +442,7 @@ struct st_maria_info enum ha_rkey_function last_key_func; /* CONTAIN, OVERLAP, etc */ uint save_lastkey_length; uint pack_key_length; /* For MARIAMRG */ + uint16 last_used_keyseg; /* For MARIAMRG */ int errkey; /* Got last error on this key */ int lock_type; /* How database was locked */ int tmp_lock_type; /* When locked by readinfo */ @@ -749,7 +750,7 @@ extern my_off_t _ma_new(MARIA_HA *info, MARIA_KEYDEF *keyinfo, int level); extern uint _ma_make_key(MARIA_HA *info, uint keynr, uchar *key, const uchar *record, MARIA_RECORD_POS filepos); extern uint _ma_pack_key(MARIA_HA *info, uint keynr, uchar *key, - const uchar *old, uint key_length, + const uchar *old, key_part_map keypart_map, HA_KEYSEG ** last_used_keyseg); extern int _ma_read_key_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS); extern int _ma_read_cache(IO_CACHE *info, uchar *buff, MARIA_RECORD_POS pos, @@ -760,7 +761,7 @@ extern my_bool _ma_alloc_buffer(uchar **old_addr, size_t *old_size, size_t new_size); extern ulong _ma_rec_unpack(MARIA_HA *info, uchar *to, uchar *from, ulong reclength); -extern my_bool _ma_rec_check(MARIA_HA *info, const char *record, +extern my_bool _ma_rec_check(MARIA_HA *info, const uchar *record, uchar *packpos, ulong packed_length, my_bool with_checkum, ha_checksum checksum); extern int _ma_write_part_record(MARIA_HA *info, my_off_t filepos, |