diff options
40 files changed, 763 insertions, 335 deletions
diff --git a/include/my_sys.h b/include/my_sys.h index f8f3411f337..77364c3fefb 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -62,12 +62,14 @@ extern int NEAR my_errno; /* Last error in mysys */ #define MY_HOLD_ORIGINAL_MODES 128 /* my_copy() holds to file modes */ #define MY_REDEL_MAKE_BACKUP 256 #define MY_SEEK_NOT_DONE 32 /* my_lock may have to do a seek */ -#define MY_DONT_WAIT 64 /* my_lock() don't wait if can't lock */ +#define MY_SHORT_WAIT 64 /* my_lock() don't wait if can't lock */ +#define MY_FORCE_LOCK 128 /* use my_lock() even if disable_locking */ +#define MY_NO_WAIT 256 /* my_lock() don't wait at all */ #define MY_ZEROFILL 32 /* my_malloc(), fill array with zero */ #define MY_ALLOW_ZERO_PTR 64 /* my_realloc() ; zero ptr -> malloc */ #define MY_FREE_ON_ERROR 128 /* my_realloc() ; Free old ptr on error */ #define MY_HOLD_ON_ERROR 256 /* my_realloc() ; Return old ptr on error */ -#define MY_DONT_OVERWRITE_FILE 1024 /* my_copy: Don't overwrite file */ +#define MY_DONT_OVERWRITE_FILE 2048 /* my_copy: Don't overwrite file */ #define MY_THREADSAFE 2048 /* my_seek(): lock fd mutex */ #define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */ diff --git a/include/myisam.h b/include/myisam.h index ee0bf43782b..cad52380e97 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -225,7 +225,7 @@ struct st_mi_bit_buff; typedef struct st_columndef /* column information */ { - int16 type; /* en_fieldtype */ + enum en_fieldtype type; uint16 length; /* length of field */ uint32 offset; /* Offset to position in row */ uint8 null_bit; /* If column may be 0 */ diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index 945a9af6d2a..566ccfe0778 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -474,12 +474,6 @@ sub mtr_kill_leftovers () { } } } - else - { - mtr_warning("Found non pid file $elem in $rundir") - if -f "$rundir/$elem"; - next; - } } closedir(RUNDIR); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 234744e46d0..a4fa415caf6 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -3038,6 +3038,7 @@ sub install_db ($$) { mtr_add_arg($args, "--datadir=%s", $data_dir); mtr_add_arg($args, "--loose-skip-innodb"); mtr_add_arg($args, "--loose-skip-ndbcluster"); + mtr_add_arg($args, "--sync-frm=0"); mtr_add_arg($args, "--tmpdir=."); mtr_add_arg($args, "--core-file"); @@ -3778,6 +3779,7 @@ sub mysqld_arguments ($$$$) { mtr_add_arg($args, "%s--datadir=%s", $prefix, $mysqld->{'path_myddir'}); + mtr_add_arg($args, "--sync-frm=0"); # Faster test if ( $mysql_version_id >= 50106 ) { diff --git a/mysql-test/r/maria-recovery.result b/mysql-test/r/maria-recovery.result index 2cee14bffcd..4e756a9a1e5 100644 --- a/mysql-test/r/maria-recovery.result +++ b/mysql-test/r/maria-recovery.result @@ -1,3 +1,4 @@ +set global maria_log_file_size=4294967296; drop database if exists mysqltest; create database mysqltest; use mysqltest; diff --git a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test index fe3881ab08f..d2be173f068 100644 --- a/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test +++ b/mysql-test/suite/rpl/t/rpl_innodb_bug28430.test @@ -1,3 +1,4 @@ +--source include/big_test.inc --source include/have_innodb.inc --source include/have_binlog_format_mixed_or_row.inc --source include/master-slave.inc diff --git a/mysys/my_lock.c b/mysys/my_lock.c index c0522ee849d..4b8c067ba0d 100644 --- a/mysys/my_lock.c +++ b/mysys/my_lock.c @@ -54,7 +54,7 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length, #ifdef VMS DBUG_RETURN(0); #else - if (my_disable_locking) + if (my_disable_locking && ! (MyFlags & MY_FORCE_LOCK)) DBUG_RETURN(0); #if defined(__NETWARE__) @@ -131,10 +131,16 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length, lock.l_start= (off_t) start; lock.l_len= (off_t) length; - if (MyFlags & MY_DONT_WAIT) + if (MyFlags & (MY_NO_WAIT | MY_SHORT_WAIT)) { if (fcntl(fd,F_SETLK,&lock) != -1) /* Check if we can lock */ - DBUG_RETURN(0); /* Ok, file locked */ + DBUG_RETURN(0); /* Ok, file locked */ + if (MyFlags & MY_NO_WAIT) + { + my_errno= (errno == EACCES) ? EAGAIN : errno ? errno : -1; + DBUG_RETURN(-1); + } + DBUG_PRINT("info",("Was locked, trying with alarm")); ALARM_INIT; while ((value=fcntl(fd,F_SETLKW,&lock)) && ! ALARM_TEST && diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index c9ce6ab169f..aadb86d39ed 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -289,12 +289,12 @@ my_bool my_thread_init(void) #endif pthread_mutex_init(&tmp->mutex,MY_MUTEX_INIT_FAST); pthread_cond_init(&tmp->suspend, NULL); - tmp->init= 1; pthread_mutex_lock(&THR_LOCK_threads); tmp->id= ++thread_id; ++THR_thread_count; pthread_mutex_unlock(&THR_LOCK_threads); + tmp->init= 1; #ifndef DBUG_OFF /* Generate unique name for thread */ (void) my_thread_name(); @@ -392,7 +392,7 @@ extern void **my_thread_var_dbug() { struct st_my_thread_var *tmp= my_pthread_getspecific(struct st_my_thread_var*,THR_KEY_mysys); - return tmp ? &tmp->dbug : 0; + return tmp && tmp->init ? &tmp->dbug : 0; } #endif diff --git a/sql/handler.cc b/sql/handler.cc index 2fe04c5dba3..4a9052da7c0 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -26,7 +26,7 @@ #include "mysql_priv.h" #include "rpl_filter.h" #include <myisampack.h> -#include <errno.h> +#include "myisam.h" #ifdef WITH_PARTITION_STORAGE_ENGINE #include "ha_partition.h" diff --git a/sql/handler.h b/sql/handler.h index d9533739af2..d2ff337f6f5 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1359,14 +1359,18 @@ public: } virtual int read_first_row(uchar *buf, uint primary_key); /* - The following function is only needed for tables that may be temporary - tables during joins + The following 3 function is only needed for tables that may be + internal temporary tables during joins */ - virtual int restart_rnd_next(uchar *buf, uchar *pos) + virtual int remember_rnd_pos() + { return HA_ERR_WRONG_COMMAND; } + virtual int restart_rnd_next(uchar *buf) { return HA_ERR_WRONG_COMMAND; } virtual int rnd_same(uchar *buf, uint inx) { return HA_ERR_WRONG_COMMAND; } - virtual ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key) + + virtual ha_rows records_in_range(uint inx, key_range *min_key, + key_range *max_key) { return (ha_rows) 10; } virtual void position(const uchar *record)=0; virtual int info(uint)=0; // see my_base.h for full description diff --git a/sql/my_lock.c b/sql/my_lock.c index f66d7282f72..276259b106a 100644 --- a/sql/my_lock.c +++ b/sql/my_lock.c @@ -25,7 +25,15 @@ #include <thr_alarm.h> #include <errno.h> - /* Lock a part of a file */ +/** + @breif Lock a part of a file + + @note + This works like mysys/my_lock.c, with the exception that this function + uses the thr_alarm() to break long lock statements. + (mysys can't use thr_alarm() as by default the alarm handling doesn't + exists) +*/ int my_lock(File fd,int locktype,my_off_t start,my_off_t length,myf MyFlags) { @@ -36,29 +44,34 @@ int my_lock(File fd,int locktype,my_off_t start,my_off_t length,myf MyFlags) DBUG_ENTER("my_lock"); DBUG_PRINT("my",("Fd: %d Op: %d start: %ld Length: %ld MyFlags: %d", fd,locktype,(ulong) start,(ulong) length,MyFlags)); - if (my_disable_locking) + if (my_disable_locking && ! (MyFlags & MY_FORCE_LOCK)) DBUG_RETURN(0); /* purecov: inspected */ + m_lock.l_type=(short) locktype; m_lock.l_whence=0L; m_lock.l_start=(long) start; m_lock.l_len=(long) length; - wait_for_alarm=(MyFlags & MY_DONT_WAIT ? MY_HOW_OFTEN_TO_ALARM : - (uint) 12*60*60); if (fcntl(fd,F_SETLK,&m_lock) != -1) /* Check if we can lock */ DBUG_RETURN(0); /* Ok, file locked */ - DBUG_PRINT("info",("Was locked, trying with alarm")); - if (!thr_alarm(&alarmed,wait_for_alarm,&alarm_buff)) - { - int value; - while ((value=fcntl(fd,F_SETLKW,&m_lock)) && !thr_got_alarm(&alarmed) && - errno == EINTR) ; - thr_end_alarm(&alarmed); - if (value != -1) - DBUG_RETURN(0); - } - else + + if (!(MyFlags & MY_NO_WAIT)) { - errno=EINTR; + wait_for_alarm= (MyFlags & MY_SHORT_WAIT ? MY_HOW_OFTEN_TO_ALARM : + (uint) 12*60*60); + DBUG_PRINT("info",("Was locked, trying with alarm")); + if (!thr_alarm(&alarmed,wait_for_alarm,&alarm_buff)) + { + int value; + while ((value=fcntl(fd,F_SETLKW,&m_lock)) && !thr_got_alarm(&alarmed) && + errno == EINTR) ; + thr_end_alarm(&alarmed); + if (value != -1) + DBUG_RETURN(0); + } + else + { + errno=EINTR; + } } if (errno == EINTR || errno == EACCES) my_errno=EAGAIN; /* Easier to check for this */ diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f7738e44404..b178f7103cb 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1888,6 +1888,7 @@ extern TYPELIB log_output_typelib; extern SHOW_COMP_OPTION have_maria_db; extern handlerton *partition_hton; extern handlerton *myisam_hton; +extern handlerton *maria_hton; extern handlerton *heap_hton; extern SHOW_COMP_OPTION have_ssl, have_symlink, have_dlopen; diff --git a/sql/sql_class.h b/sql/sql_class.h index d4950ec0f60..964b31cd95c 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2159,7 +2159,14 @@ public: const HA_CREATE_INFO *get_create_info() { return create_info; }; }; + +#ifdef WITH_MARIA_STORAGE_ENGINE +#include <maria.h> +#define ENGINE_COLUMNDEF MARIA_COLUMNDEF +#else #include <myisam.h> +#define ENGINE_COLUMNDEF MI_COLUMNDEF +#endif /* Param to create temporary tables when doing SELECT:s @@ -2181,7 +2188,7 @@ public: Copy_field *save_copy_field, *save_copy_field_end; uchar *group_buff; Item **items_to_copy; /* Fields in tmp table */ - MI_COLUMNDEF *recinfo,*start_recinfo; + ENGINE_COLUMNDEF *recinfo, *start_recinfo; KEY *keyinfo; ha_rows end_write_records; uint field_count,sum_func_count,func_count; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 1f206e2ec17..850c15a11b8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -27,11 +27,16 @@ #include "mysql_priv.h" #include "sql_select.h" #include "sql_cursor.h" - #include <m_ctype.h> #include <my_bit.h> #include <hash.h> #include <ft_global.h> +#ifdef WITH_MARIA_STORAGE_ENGINE +#include "../storage/maria/ha_maria.h" +#define TMP_ENGINE_HTON maria_hton +#else +#define TMP_ENGINE_HTON myisam_hton +#endif const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref", "MAYBE_REF","ALL","range","index","fulltext", @@ -116,8 +121,14 @@ static COND *optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value); static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item); static bool open_tmp_table(TABLE *table); -static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, +static bool create_internal_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, ulonglong options); +static bool create_internal_tmp_table_from_heap2(THD *thd, TABLE *table, + TMP_TABLE_PARAM *param, + int error, + bool ignore_last_dupp, + handlerton *hton, + const char *proc_info); static int do_select(JOIN *join,List<Item> *fields,TABLE *tmp_table, Procedure *proc); @@ -9460,7 +9471,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, KEY *keyinfo; KEY_PART_INFO *key_part_info; Item **copy_func; - MI_COLUMNDEF *recinfo; + ENGINE_COLUMNDEF *recinfo; uint total_uneven_bit_length= 0; bool force_copy_fields= param->force_copy_fields; DBUG_ENTER("create_tmp_table"); @@ -9486,11 +9497,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, /* No need to change table name to lower case as we are only creating - MyISAM or HEAP tables here + MyISAM, Maria or HEAP tables here */ fn_format(path, path, mysql_tmpdir, "", MY_REPLACE_EXT|MY_UNPACK_FILENAME); - if (group) { if (!param->quick_group) @@ -9582,7 +9592,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, init_tmp_table_share(share, "", 0, tmpname, tmpname); share->blob_field= blob_field; share->blob_ptr_size= portable_sizeof_char_ptr; - share->db_low_byte_first=1; // True for HEAP and MyISAM + share->db_low_byte_first=1; // True for HEAP, MyISAM and Maria share->table_charset= param->table_charset; share->primary_key= MAX_KEY; // Indicate no primary key share->keys_for_keyread.init(); @@ -9714,6 +9724,12 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, *blob_field++= fieldnr; blob_count++; } + if (new_field->real_type() == MYSQL_TYPE_STRING || + new_field->real_type() == MYSQL_TYPE_VARCHAR) + { + string_count++; + string_total_length+= new_field->pack_length(); + } if (item->marker == 4 && item->maybe_null) { group_null_items++; @@ -9750,7 +9766,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, (select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) == OPTION_BIG_TABLES || (select_options & TMP_TABLE_FORCE_MYISAM)) { - share->db_plugin= ha_lock_engine(0, myisam_hton); + share->db_plugin= ha_lock_engine(0, TMP_ENGINE_HTON); table->file= get_new_handler(share, &table->mem_root, share->db_type()); if (group && @@ -9767,7 +9783,6 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, if (!table->file) goto err; - if (!using_unique_constraint) reclength+= group_null_items; // null flag is stored separately @@ -9903,13 +9918,16 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, /* Make entry for create table */ recinfo->length=length; if (field->flags & BLOB_FLAG) - recinfo->type= (int) FIELD_BLOB; + recinfo->type= FIELD_BLOB; else if (use_packed_rows && field->real_type() == MYSQL_TYPE_STRING && length >= MIN_STRING_LENGTH_TO_PACK_ROWS) - recinfo->type=FIELD_SKIP_ENDSPACE; + recinfo->type= FIELD_SKIP_ENDSPACE; + else if (field->real_type() == MYSQL_TYPE_VARCHAR) + recinfo->type= FIELD_VARCHAR; else - recinfo->type=FIELD_NORMAL; + recinfo->type= FIELD_NORMAL; + if (!--hidden_field_count) null_count=(null_count+7) & ~7; // move to next byte @@ -10072,9 +10090,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, if (thd->is_fatal_error) // If end of memory goto err; /* purecov: inspected */ share->db_record_offset= 1; - if (share->db_type() == myisam_hton) + if (share->db_type() == TMP_ENGINE_HTON) { - if (create_myisam_tmp_table(table,param,select_options)) + if (create_internal_tmp_table(table,param,select_options)) goto err; } if (open_tmp_table(table)) @@ -10239,15 +10257,149 @@ static bool open_tmp_table(TABLE *table) } -static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, - ulonglong options) +#ifdef WITH_MARIA_STORAGE_ENGINE + +/* Create internal Maria temporary table */ + +static bool create_internal_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, + ulonglong options) +{ + int error; + MARIA_KEYDEF keydef; + MARIA_UNIQUEDEF uniquedef; + KEY *keyinfo=param->keyinfo; + TABLE_SHARE *share= table->s; + MARIA_CREATE_INFO create_info; + DBUG_ENTER("create_internal_tmp_table"); + + if (share->keys) + { // Get keys for ni_create + bool using_unique_constraint=0; + HA_KEYSEG *seg= (HA_KEYSEG*) alloc_root(&table->mem_root, + sizeof(*seg) * keyinfo->key_parts); + if (!seg) + goto err; + + bzero(seg, sizeof(*seg) * keyinfo->key_parts); + if (keyinfo->key_length >= table->file->max_key_length() || + keyinfo->key_parts > table->file->max_key_parts() || + share->uniques) + { + /* Can't create a key; Make a unique constraint instead of a key */ + share->keys= 0; + share->uniques= 1; + using_unique_constraint=1; + bzero((char*) &uniquedef,sizeof(uniquedef)); + uniquedef.keysegs=keyinfo->key_parts; + uniquedef.seg=seg; + uniquedef.null_are_equal=1; + + /* Create extra column for hash value */ + bzero((uchar*) param->recinfo,sizeof(*param->recinfo)); + param->recinfo->type= FIELD_CHECK; + param->recinfo->length= MARIA_UNIQUE_HASH_LENGTH; + param->recinfo++; + share->reclength+= MARIA_UNIQUE_HASH_LENGTH; + } + else + { + /* Create an unique key */ + bzero((char*) &keydef,sizeof(keydef)); + keydef.flag=HA_NOSAME | HA_BINARY_PACK_KEY | HA_PACK_KEY; + keydef.keysegs= keyinfo->key_parts; + keydef.seg= seg; + } + for (uint i=0; i < keyinfo->key_parts ; i++,seg++) + { + Field *field=keyinfo->key_part[i].field; + seg->flag= 0; + seg->language= field->charset()->number; + seg->length= keyinfo->key_part[i].length; + seg->start= keyinfo->key_part[i].offset; + if (field->flags & BLOB_FLAG) + { + seg->type= + ((keyinfo->key_part[i].key_type & FIELDFLAG_BINARY) ? + HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2); + seg->bit_start= (uint8)(field->pack_length() - share->blob_ptr_size); + seg->flag= HA_BLOB_PART; + seg->length=0; // Whole blob in unique constraint + } + else + { + seg->type= keyinfo->key_part[i].type; + /* Tell handler if it can do suffic space compression */ + if (field->real_type() == MYSQL_TYPE_STRING && + keyinfo->key_part[i].length > 4) + seg->flag|= HA_SPACE_PACK; + } + if (!(field->flags & NOT_NULL_FLAG)) + { + seg->null_bit= field->null_bit; + seg->null_pos= (uint) (field->null_ptr - (uchar*) table->record[0]); + /* + We are using a GROUP BY on something that contains NULL + In this case we have to tell Maria that two NULL should + on INSERT be regarded at the same value + */ + if (!using_unique_constraint) + keydef.flag|= HA_NULL_ARE_EQUAL; + } + } + } + bzero((char*) &create_info,sizeof(create_info)); + + if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) == + OPTION_BIG_TABLES) + create_info.data_file_length= ~(ulonglong) 0; + + if ((error= maria_create(share->table_name.str, + share->reclength < 64 && + !share->blob_fields ? STATIC_RECORD : + BLOCK_RECORD, + share->keys, &keydef, + (uint) (param->recinfo-param->start_recinfo), + param->start_recinfo, + share->uniques, &uniquedef, + &create_info, + HA_CREATE_TMP_TABLE))) + { + table->file->print_error(error,MYF(0)); /* purecov: inspected */ + table->db_stat=0; + goto err; + } + status_var_increment(table->in_use->status_var.created_tmp_disk_tables); + share->db_record_offset= 1; + DBUG_RETURN(0); + err: + DBUG_RETURN(1); +} + + +bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, + TMP_TABLE_PARAM *param, + int error, + bool ignore_last_dupp_key_error) +{ + return create_internal_tmp_table_from_heap2(thd, table, param, error, + ignore_last_dupp_key_error, + maria_hton, + "converting HEAP to Maria"); +} + +#else + +/* Create internal MyISAM temporary table */ + +static bool create_internal_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, + ulonglong options) { int error; MI_KEYDEF keydef; MI_UNIQUEDEF uniquedef; KEY *keyinfo=param->keyinfo; TABLE_SHARE *share= table->s; - DBUG_ENTER("create_myisam_tmp_table"); + DBUG_ENTER("create_internal_tmp_table"); if (share->keys) { // Get keys for ni_create @@ -10350,54 +10502,43 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, } -void -free_tmp_table(THD *thd, TABLE *entry) -{ - MEM_ROOT own_root= entry->mem_root; - const char *save_proc_info; - DBUG_ENTER("free_tmp_table"); - DBUG_PRINT("enter",("table: %s",entry->alias)); - - save_proc_info=thd->proc_info; - thd->proc_info="removing tmp table"; - - if (entry->file) - { - if (entry->db_stat) - entry->file->drop_table(entry->s->table_name.str); - else - entry->file->delete_table(entry->s->table_name.str); - delete entry->file; - } - - /* free blobs */ - for (Field **ptr=entry->field ; *ptr ; ptr++) - (*ptr)->free(); - free_io_cache(entry); - - if (entry->temp_pool_slot != MY_BIT_NONE) - bitmap_lock_clear_bit(&temp_pool, entry->temp_pool_slot); +/* + If a HEAP table gets full, create a MyISAM table and copy all rows to this +*/ - plugin_unlock(0, entry->s->db_plugin); +bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, + TMP_TABLE_PARAM *param, + int error, + bool ignore_last_dupp_key_error) +{ + return create_internal_tmp_table_from_heap2(thd, table, param, error, + ignore_last_dupp_key_error, + myisam_hton, + "converting HEAP to MyISAM"); +} - free_root(&own_root, MYF(0)); /* the table is allocated in its own root */ - thd->proc_info=save_proc_info; +#endif /* WITH_MARIA_STORAGE_ENGINE */ - DBUG_VOID_RETURN; -} /* -* If a HEAP table gets full, create a MyISAM table and copy all rows to this + If a HEAP table gets full, create a internal table in MyISAM or Maria + and copy all rows to this */ -bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, - int error, bool ignore_last_dupp_key_error) + +static bool +create_internal_tmp_table_from_heap2(THD *thd, TABLE *table, + TMP_TABLE_PARAM *param, + int error, + bool ignore_last_dupp_key_error, + handlerton *hton, + const char *proc_info) { TABLE new_table; TABLE_SHARE share; const char *save_proc_info; int write_err; - DBUG_ENTER("create_myisam_from_heap"); + DBUG_ENTER("create_internal_tmp_table_from_heap2"); if (table->s->db_type() != heap_hton || error != HA_ERR_RECORD_FILE_FULL) @@ -10408,15 +10549,15 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, new_table= *table; share= *table->s; new_table.s= &share; - new_table.s->db_plugin= ha_lock_engine(thd, myisam_hton); + new_table.s->db_plugin= ha_lock_engine(thd, hton); if (!(new_table.file= get_new_handler(&share, &new_table.mem_root, new_table.s->db_type()))) DBUG_RETURN(1); // End of memory save_proc_info=thd->proc_info; - thd->proc_info="converting HEAP to MyISAM"; + thd->proc_info= proc_info; - if (create_myisam_tmp_table(&new_table, param, + if (create_internal_tmp_table(&new_table, param, thd->lex->select_lex.options | thd->options)) goto err2; if (open_tmp_table(&new_table)) @@ -10497,6 +10638,43 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, } +void +free_tmp_table(THD *thd, TABLE *entry) +{ + MEM_ROOT own_root= entry->mem_root; + const char *save_proc_info; + DBUG_ENTER("free_tmp_table"); + DBUG_PRINT("enter",("table: %s",entry->alias)); + + save_proc_info=thd->proc_info; + thd->proc_info="removing tmp table"; + + if (entry->file) + { + if (entry->db_stat) + entry->file->drop_table(entry->s->table_name.str); + else + entry->file->delete_table(entry->s->table_name.str); + delete entry->file; + } + + /* free blobs */ + for (Field **ptr=entry->field ; *ptr ; ptr++) + (*ptr)->free(); + free_io_cache(entry); + + if (entry->temp_pool_slot != MY_BIT_NONE) + bitmap_lock_clear_bit(&temp_pool, entry->temp_pool_slot); + + plugin_unlock(0, entry->s->db_plugin); + + free_root(&own_root, MYF(0)); /* the table is allocated in its own root */ + thd->proc_info=save_proc_info; + + DBUG_VOID_RETURN; +} + + /* SYNOPSIS setup_end_select_func() @@ -11915,7 +12093,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), { if (!table->file->is_fatal_error(error, HA_CHECK_DUP)) goto end; - if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param, + if (create_internal_tmp_table_from_heap(join->thd, table, &join->tmp_table_param, error,1)) DBUG_RETURN(NESTED_LOOP_ERROR); // Not a table_is_full error table->s->uniques=0; // To ensure rows are the same @@ -11999,7 +12177,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), copy_funcs(join->tmp_table_param.items_to_copy); if ((error=table->file->write_row(table->record[0]))) { - if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param, + if (create_internal_tmp_table_from_heap(join->thd, table, &join->tmp_table_param, error, 0)) DBUG_RETURN(NESTED_LOOP_ERROR); // Not a table_is_full error /* Change method to update rows */ @@ -12094,7 +12272,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (!join->having || join->having->val_int()) { int error= table->file->write_row(table->record[0]); - if (error && create_myisam_from_heap(join->thd, table, + if (error && create_internal_tmp_table_from_heap(join->thd, table, &join->tmp_table_param, error, 0)) DBUG_RETURN(NESTED_LOOP_ERROR); @@ -13348,13 +13526,14 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, else if (!found) { found=1; - file->position(record); // Remember position + if ((error= file->remember_rnd_pos())) + goto err; } } if (!found) break; // End of file - /* Restart search on next row */ - error=file->restart_rnd_next(record,file->ref); + /* Restart search on saved row */ + error=file->restart_rnd_next(record); } file->extra(HA_EXTRA_NO_CACHE); @@ -15444,7 +15623,7 @@ int JOIN::rollup_write_data(uint idx, TABLE *table_arg) copy_sum_funcs(sum_funcs_end[i+1], sum_funcs_end[i]); if ((write_error= table_arg->file->write_row(table_arg->record[0]))) { - if (create_myisam_from_heap(thd, table_arg, &tmp_table_param, + if (create_internal_tmp_table_from_heap(thd, table_arg, &tmp_table_param, write_error, 0)) return 1; } diff --git a/sql/sql_select.h b/sql/sql_select.h index efa92432e2b..2d9761a8364 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -542,7 +542,7 @@ bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, uint elements, List<Item> &fields); void copy_fields(TMP_TABLE_PARAM *param); void copy_funcs(Item **func_ptr); -bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, +bool create_internal_tmp_table_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, int error, bool ignore_last_dupp_error); uint find_shortest_key(TABLE *table, const key_map *usable_keys); Field* create_tmp_field_from_field(THD *thd, Field* org_field, diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 38db2fe85a5..4280722607b 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -165,15 +165,15 @@ static my_bool show_plugins(THD *thd, plugin_ref plugin, switch (plug->license) { case PLUGIN_LICENSE_GPL: - table->field[9]->store(PLUGIN_LICENSE_GPL_STRING, + table->field[9]->store(PLUGIN_LICENSE_GPL_STRING, strlen(PLUGIN_LICENSE_GPL_STRING), cs); break; case PLUGIN_LICENSE_BSD: - table->field[9]->store(PLUGIN_LICENSE_BSD_STRING, + table->field[9]->store(PLUGIN_LICENSE_BSD_STRING, strlen(PLUGIN_LICENSE_BSD_STRING), cs); break; default: - table->field[9]->store(PLUGIN_LICENSE_PROPRIETARY_STRING, + table->field[9]->store(PLUGIN_LICENSE_PROPRIETARY_STRING, strlen(PLUGIN_LICENSE_PROPRIETARY_STRING), cs); break; } @@ -481,7 +481,7 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db, file=dirp->dir_entry+i; if (dir) { /* Return databases */ - if ((file->name[0] == '.' && + if ((file->name[0] == '.' && ((file->name[1] == '.' && file->name[2] == '\0') || file->name[1] == '\0'))) continue; /* . or .. */ @@ -507,7 +507,7 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db, file_name_len= filename_to_tablename(file->name, uname, sizeof(uname)); if (wild && wild_compare(uname, wild, 0)) continue; - if (!(file_name= + if (!(file_name= thd->make_lex_string(file_name, uname, file_name_len, TRUE))) { my_dirend(dirp); @@ -546,7 +546,7 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db, continue; } #endif - if (!(file_name= + if (!(file_name= thd->make_lex_string(file_name, uname, file_name_len, TRUE)) || files->push_back(file_name)) { @@ -584,7 +584,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) /* Clear all messages with 'error' level status and - issue a warning with 'warning' level status in + issue a warning with 'warning' level status in case of invalid view and last error is ER_VIEW_INVALID */ mysql_reset_errors(thd, true); @@ -774,7 +774,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) Field **ptr,*field; for (ptr=table->field ; (field= *ptr); ptr++) { - if (!wild || !wild[0] || + if (!wild || !wild[0] || !wild_case_compare(system_charset_info, field->field_name,wild)) { if (table_list->view) @@ -985,13 +985,13 @@ static bool get_field_default_value(THD *thd, TABLE *table, bool has_default; bool has_now_default; - /* + /* We are using CURRENT_TIMESTAMP instead of NOW because it is more standard */ - has_now_default= table->timestamp_field == field && + has_now_default= table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_UN_FIELD; - + has_default= (field->type() != FIELD_TYPE_BLOB && !(field->flags & NO_DEFAULT_VALUE_FLAG) && field->unireg_check != Field::NEXT_NUMBER && @@ -1046,11 +1046,11 @@ static bool get_field_default_value(THD *thd, TABLE *table, to tailor the format of the statement. Can be NULL, in which case only SQL_MODE is considered when building the statement. - + NOTE Currently always return 0, but might return error code in the future. - + RETURN 0 OK */ @@ -1132,7 +1132,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, field->sql_type(type); packet->append(type.ptr(), type.length(), system_charset_info); - if (field->has_charset() && + if (field->has_charset() && !(thd->variables.sql_mode & (MODE_MYSQL323 | MODE_MYSQL40))) { if (field->charset() != share->table_charset) @@ -1140,8 +1140,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN(" CHARACTER SET ")); packet->append(field->charset()->csname); } - /* - For string types dump collation name only if + /* + For string types dump collation name only if collation is not primary for the given charset */ if (!(field->charset()->state & MY_CS_PRIMARY)) @@ -1168,11 +1168,11 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(def_value.ptr(), def_value.length(), system_charset_info); } - if (!limited_mysql_mode && table->timestamp_field == field && + if (!limited_mysql_mode && table->timestamp_field == field && field->unireg_check != Field::TIMESTAMP_DN_FIELD) packet->append(STRING_WITH_LEN(" ON UPDATE CURRENT_TIMESTAMP")); - if (field->unireg_check == Field::NEXT_NUMBER && + if (field->unireg_check == Field::NEXT_NUMBER && !(thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS)) packet->append(STRING_WITH_LEN(" AUTO_INCREMENT")); @@ -1321,7 +1321,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(buff, (uint) (end - buff)); } - + if (share->table_charset && !(thd->variables.sql_mode & MODE_MYSQL323) && !(thd->variables.sql_mode & MODE_MYSQL40)) @@ -1492,7 +1492,7 @@ view_store_options(THD *thd, TABLE_LIST *table, String *buff) /* Append DEFINER clause to the given buffer. - + SYNOPSIS append_definer() thd [in] thread handle @@ -1521,7 +1521,7 @@ static void append_algorithm(TABLE_LIST *table, String *buff) /* Append DEFINER clause to the given buffer. - + SYNOPSIS append_definer() thd [in] thread handle @@ -1681,8 +1681,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) "%s:%u", tmp_sctx->host_or_ip, tmp->peer_port); } else - thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ? - tmp_sctx->host_or_ip : + thd_info->host= thd->strdup(tmp_sctx->host_or_ip[0] ? + tmp_sctx->host_or_ip : tmp_sctx->host ? tmp_sctx->host : ""); if ((thd_info->db=tmp->db)) // Safe test thd_info->db=thd->strdup(thd_info->db); @@ -1711,7 +1711,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) thd_info->query=0; if (tmp->query) { - /* + /* query_length is always set to 0 when we set query = NULL; see the comment in sql_class.h why this prevents crashes in possible races with query_length @@ -1958,7 +1958,7 @@ void reset_status_vars() /* Note that SHOW_LONG_NOFLUSH variables are not reset */ if (ptr->type == SHOW_LONG) *(ulong*) ptr->value= 0; - } + } } /* @@ -2204,14 +2204,14 @@ void calc_sum_of_all_status(STATUS_VAR *to) I_List_iterator<THD> it(threads); THD *tmp; - + /* Get global values as base */ *to= global_status_var; - + /* Add to this status from existing threads */ while ((tmp= it++)) add_to_status(to, &tmp->status_var); - + VOID(pthread_mutex_unlock(&LOCK_thread_count)); DBUG_VOID_RETURN; } @@ -2246,7 +2246,7 @@ bool schema_table_store_record(THD *thd, TABLE *table) int error; if ((error= table->file->ha_write_row(table->record[0]))) { - if (create_myisam_from_heap(thd, table, + if (create_internal_tmp_table_from_heap(thd, table, table->pos_in_table_list->schema_table_param, error, 0)) return 1; @@ -2268,23 +2268,23 @@ int make_table_list(THD *thd, SELECT_LEX *sel, /** - @brief Get lookup value from the part of 'WHERE' condition + @brief Get lookup value from the part of 'WHERE' condition - @details This function gets lookup value from - the part of 'WHERE' condition if it's possible and + @details This function gets lookup value from + the part of 'WHERE' condition if it's possible and fill appropriate lookup_field_vals struct field with this value. @param[in] thd thread handler @param[in] item_func part of WHERE condition @param[in] table I_S table - @param[in, out] lookup_field_vals Struct which holds lookup values + @param[in, out] lookup_field_vals Struct which holds lookup values @return void */ void get_lookup_value(THD *thd, Item_func *item_func, - TABLE_LIST *table, + TABLE_LIST *table, LOOKUP_FIELD_VALUES *lookup_field_vals) { ST_SCHEMA_TABLE *schema_table= table->schema_table; @@ -2346,16 +2346,16 @@ void get_lookup_value(THD *thd, Item_func *item_func, /** - @brief Calculates lookup values from 'WHERE' condition + @brief Calculates lookup values from 'WHERE' condition @details This function calculates lookup value(database name, table name) - from 'WHERE' condition if it's possible and + from 'WHERE' condition if it's possible and fill lookup_field_vals struct fields with these values. @param[in] thd thread handler @param[in] cond WHERE condition @param[in] table I_S table - @param[in, out] lookup_field_vals Struct which holds lookup values + @param[in, out] lookup_field_vals Struct which holds lookup values @return void */ @@ -2495,7 +2495,7 @@ static COND * make_cond_for_info_schema(COND *cond, TABLE_LIST *table) @param[in] thd thread handler @param[in] cond WHERE condition @param[in] tables I_S table - @param[in, out] lookup_field_values Struct which holds lookup values + @param[in, out] lookup_field_values Struct which holds lookup values @return void */ @@ -2556,7 +2556,7 @@ enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table) idx_field_vals idx_field_vals->db_name contains db name or wild string with_i_schema returns 1 if we added 'IS' name to list - otherwise returns 0 + otherwise returns 0 RETURN zero success @@ -2580,7 +2580,7 @@ int make_db_list(THD *thd, List<LEX_STRING> *files, LIKE clause (see also get_index_field_values() function) */ if (!lookup_field_vals->db_value.str || - !wild_case_compare(system_charset_info, + !wild_case_compare(system_charset_info, INFORMATION_SCHEMA_NAME.str, lookup_field_vals->db_value.str)) { @@ -2624,7 +2624,7 @@ int make_db_list(THD *thd, List<LEX_STRING> *files, } -struct st_add_schema_table +struct st_add_schema_table { List<LEX_STRING> *files; const char *wild; @@ -2688,7 +2688,7 @@ int schema_tables_add(THD *thd, List<LEX_STRING> *files, const char *wild) else if (wild_compare(tmp_schema_table->table_name, wild, 0)) continue; } - if ((file_name= + if ((file_name= thd->make_lex_string(file_name, tmp_schema_table->table_name, strlen(tmp_schema_table->table_name), TRUE)) && !files->push_back(file_name)) @@ -2744,7 +2744,7 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex, } } else - { + { if (table_names->push_back(&lookup_field_vals->table_value)) return 1; /* @@ -2805,7 +2805,7 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex, @retval 1 error */ -static int +static int fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables, ST_SCHEMA_TABLE *schema_table, Open_tables_state *open_tables_state_backup) @@ -2832,7 +2832,7 @@ fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables, Let us set fake sql_command so views won't try to merge themselves into main statement. If we don't do this, SELECT * from information_schema.xxxx will cause problems. - SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()' + SQLCOM_SHOW_FIELDS is used because it satisfies 'only_view_structure()' */ lex->sql_command= SQLCOM_SHOW_FIELDS; res= open_normal_and_derived_tables(thd, show_table_list, @@ -2842,11 +2842,11 @@ fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables, get_all_tables() returns 1 on failure and 0 on success thus return only these and not the result code of ::process_table() - We should use show_table_list->alias instead of + We should use show_table_list->alias instead of show_table_list->table_name because table_name could be changed during opening of I_S tables. It's safe - to use alias because alias contains original table name - in this case(this part of code is used only for + to use alias because alias contains original table name + in this case(this part of code is used only for 'show columns' & 'show statistics' commands). */ table_name= thd->make_lex_string(&tmp_lex_string1, show_table_list->alias, @@ -2856,7 +2856,7 @@ fill_schema_show_cols_or_idxs(THD *thd, TABLE_LIST *tables, show_table_list->db_length, FALSE); else db_name= &show_table_list->view_db; - + error= test(schema_table->process_table(thd, show_table_list, table, res, db_name, @@ -2894,7 +2894,7 @@ static int fill_schema_table_names(THD *thd, TABLE *table, { enum legacy_db_type not_used; char path[FN_REFLEN]; - (void) build_table_filename(path, sizeof(path), db_name->str, + (void) build_table_filename(path, sizeof(path), db_name->str, table_name->str, reg_ext, 0); switch (mysql_frm_type(thd, path, ¬_used)) { case FRMTYPE_ERROR: @@ -2982,7 +2982,7 @@ static uint get_table_open_method(TABLE_LIST *tables, */ static int fill_schema_table_from_frm(THD *thd,TABLE *table, - ST_SCHEMA_TABLE *schema_table, + ST_SCHEMA_TABLE *schema_table, LEX_STRING *db_name, LEX_STRING *table_name, enum enum_schema_tables schema_table_idx) @@ -3009,7 +3009,7 @@ static int fill_schema_table_from_frm(THD *thd,TABLE *table, res= 0; goto err; } - + if (share->is_view) { if (schema_table->i_s_requested_object & OPEN_TABLE_ONLY) @@ -3021,7 +3021,7 @@ static int fill_schema_table_from_frm(THD *thd,TABLE *table, else if (schema_table->i_s_requested_object & OPEN_VIEW_FULL) { /* - tell get_all_tables() to fall back to + tell get_all_tables() to fall back to open_normal_and_derived_tables() */ res= 1; @@ -3090,7 +3090,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) List<LEX_STRING> db_names; List_iterator_fast<LEX_STRING> it(db_names); COND *partial_cond= 0; - uint derived_tables= lex->derived_tables; + uint derived_tables= lex->derived_tables; int error= 1; Open_tables_state open_tables_state_backup; bool save_view_prepare_mode= lex->view_prepare_mode; @@ -3111,7 +3111,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) */ thd->reset_n_backup_open_tables_state(&open_tables_state_backup); - /* + /* this branch processes SHOW FIELDS, SHOW INDEXES commands. see sql_parse.cc, prepare_schema_table() function where this values are initialized @@ -3131,7 +3131,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) if (!lookup_field_vals.wild_db_value && !lookup_field_vals.wild_table_value) { - /* + /* if lookup value is empty string then it's impossible table name or db name */ @@ -3149,7 +3149,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) !lookup_field_vals.wild_db_value) tables->has_db_lookup_value= TRUE; if (lookup_field_vals.table_value.length && - !lookup_field_vals.wild_table_value) + !lookup_field_vals.wild_table_value) tables->has_table_lookup_value= TRUE; if (tables->has_db_lookup_value && tables->has_table_lookup_value) @@ -3173,7 +3173,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) while ((db_name= it++)) { #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!check_access(thd,SELECT_ACL, db_name->str, + if (!check_access(thd,SELECT_ACL, db_name->str, &thd->col_access, 0, 1, with_i_schema) || sctx->master_access & (DB_ACLS | SHOW_DB_ACL) || acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0) || @@ -3203,7 +3203,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) { /* If table is I_S.tables and open_table_method is 0 (eg SKIP_OPEN) - we can skip table opening and we don't have lookup value for + we can skip table opening and we don't have lookup value for table name or lookup value is wild string(table name list is already created by make_table_name_list() function). */ @@ -3225,7 +3225,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) } else { - if (!(table_open_method & ~OPEN_FRM_ONLY) && + if (!(table_open_method & ~OPEN_FRM_ONLY) && !with_i_schema) { if (!fill_schema_table_from_frm(thd, table, schema_table, db_name, @@ -3256,7 +3256,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) res= open_normal_and_derived_tables(thd, show_table_list, MYSQL_LOCK_IGNORE_FLUSH); lex->sql_command= save_sql_command; - + if (thd->net.last_errno == ER_NO_SUCH_TABLE) { /* @@ -3271,10 +3271,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) else { /* - We should use show_table_list->alias instead of + We should use show_table_list->alias instead of show_table_list->table_name because table_name could be changed during opening of I_S tables. It's safe - to use alias because alias contains original table name + to use alias because alias contains original table name in this case. */ thd->make_lex_string(&tmp_lex_string, show_table_list->alias, @@ -3482,7 +3482,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE) ptr=strmov(ptr," delay_key_write=1"); if (share->row_type != ROW_TYPE_DEFAULT) - ptr=strxmov(ptr, " row_format=", + ptr=strxmov(ptr, " row_format=", ha_row_type[(uint) share->row_type], NullS); if (share->transactional != HA_CHOICE_UNDEF) @@ -3492,8 +3492,8 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, NullS); } #ifdef WITH_PARTITION_STORAGE_ENGINE - if (show_table->s->db_type() == partition_hton && - show_table->part_info != NULL && + if (show_table->s->db_type() == partition_hton && + show_table->part_info != NULL && show_table->part_info->no_parts > 0) ptr= strmov(ptr, " partitioned"); #endif @@ -3501,7 +3501,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, ptr= strxmov(ptr, " transactional=", ha_choice_values[(uint) share->transactional], NullS); table->field[19]->store(option_buff+1, - (ptr == option_buff ? 0 : + (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1), cs); if (share->comment.str) @@ -3615,7 +3615,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, /* I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS rather than in SHOW COLUMNS - */ + */ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, thd->net.last_errno, thd->net.last_error); thd->clear_error(); @@ -3653,7 +3653,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, uint col_access; check_access(thd,SELECT_ACL | EXTRA_ACL, db_name->str, &tables->grant.privilege, 0, 0, test(tables->schema_table)); - col_access= get_column_grant(thd, &tables->grant, + col_access= get_column_grant(thd, &tables->grant, db_name->str, table_name->str, field->field_name) & COL_ACLS; if (!tables->schema_table && !col_access) @@ -3676,7 +3676,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, cs); table->field[4]->store((longlong) count, TRUE); field->sql_type(type); - table->field[14]->store(type.ptr(), type.length(), cs); + table->field[14]->store(type.ptr(), type.length(), cs); tmp_buff= strchr(type.ptr(), '('); table->field[7]->store(type.ptr(), (tmp_buff ? tmp_buff - type.ptr() : @@ -3698,7 +3698,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, uint32 octet_max_length= field->max_display_length(); if (is_blob && octet_max_length != (uint32) 4294967295U) octet_max_length /= field->charset()->mbmaxlen; - longlong char_max_len= is_blob ? + longlong char_max_len= is_blob ? (longlong) octet_max_length / field->charset()->mbminlen : (longlong) octet_max_length / field->charset()->mbmaxlen; table->field[8]->store(char_max_len, TRUE); @@ -3731,7 +3731,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, field_length= field->max_display_length(); decimals= -1; // return NULL break; - case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: field_length= field->field_length; if (decimals == NOT_FIXED_DEC) @@ -3794,7 +3794,7 @@ int fill_schema_charsets(THD *thd, TABLE_LIST *tables, COND *cond) for (cs= all_charsets ; cs < all_charsets+255 ; cs++) { CHARSET_INFO *tmp_cs= cs[0]; - if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) && + if (tmp_cs && (tmp_cs->state & MY_CS_PRIMARY) && (tmp_cs->state & MY_CS_AVAILABLE) && !(tmp_cs->state & MY_CS_HIDDEN) && !(wild && wild[0] && @@ -3882,7 +3882,7 @@ int fill_schema_collation(THD *thd, TABLE_LIST *tables, COND *cond) for (cl= all_charsets; cl < all_charsets+255 ;cl ++) { CHARSET_INFO *tmp_cl= cl[0]; - if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || + if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || !my_charset_same(tmp_cs, tmp_cl)) continue; if (!(wild && wild[0] && @@ -3916,13 +3916,13 @@ int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond) { CHARSET_INFO **cl; CHARSET_INFO *tmp_cs= cs[0]; - if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || + if (!tmp_cs || !(tmp_cs->state & MY_CS_AVAILABLE) || !(tmp_cs->state & MY_CS_PRIMARY)) continue; for (cl= all_charsets; cl < all_charsets+255 ;cl ++) { CHARSET_INFO *tmp_cl= cl[0]; - if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || + if (!tmp_cl || !(tmp_cl->state & MY_CS_AVAILABLE) || !my_charset_same(tmp_cs,tmp_cl)) continue; restore_record(table, s->default_values); @@ -3988,7 +3988,7 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, table->field[10]->store(STRING_WITH_LEN("SQL"), cs); get_field(thd->mem_root, proc_table->field[6], &tmp_string); table->field[11]->store(tmp_string.ptr(), tmp_string.length(), cs); - table->field[12]->store(sp_data_access_name[enum_idx].str, + table->field[12]->store(sp_data_access_name[enum_idx].str, sp_data_access_name[enum_idx].length , cs); get_field(thd->mem_root, proc_table->field[7], &tmp_string); table->field[14]->store(tmp_string.ptr(), tmp_string.length(), cs); @@ -4281,10 +4281,10 @@ static int get_schema_views_record(THD *thd, TABLE_LIST *tables, if (schema_table_store_record(thd, table)) DBUG_RETURN(1); if (res && thd->net.last_errno) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, thd->net.last_errno, thd->net.last_error); } - if (res) + if (res) thd->clear_error(); DBUG_RETURN(0); } @@ -4325,7 +4325,7 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, TABLE *show_table= tables->table; KEY *key_info=show_table->key_info; uint primary_key= show_table->s->primary_key; - show_table->file->info(HA_STATUS_VARIABLE | + show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); for (uint i=0 ; i < show_table->s->keys ; i++, key_info++) @@ -4354,7 +4354,7 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, List_iterator_fast<FOREIGN_KEY_INFO> it(f_key_list); while ((f_key_info=it++)) { - if (store_constraints(thd, table, db_name, table_name, + if (store_constraints(thd, table, db_name, table_name, f_key_info->forein_id->str, strlen(f_key_info->forein_id->str), "FOREIGN KEY", 11)) @@ -4513,7 +4513,7 @@ static int get_schema_key_column_usage_record(THD *thd, TABLE *show_table= tables->table; KEY *key_info=show_table->key_info; uint primary_key= show_table->s->primary_key; - show_table->file->info(HA_STATUS_VARIABLE | + show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); for (uint i=0 ; i < show_table->s->keys ; i++, key_info++) @@ -4530,8 +4530,8 @@ static int get_schema_key_column_usage_record(THD *thd, restore_record(table, s->default_values); store_key_column_usage(table, db_name, table_name, key_info->name, - strlen(key_info->name), - key_part->field->field_name, + strlen(key_info->name), + key_part->field->field_name, strlen(key_part->field->field_name), (longlong) f_idx); if (schema_table_store_record(thd, table)) @@ -4567,7 +4567,7 @@ static int get_schema_key_column_usage_record(THD *thd, system_charset_info); table->field[9]->set_notnull(); table->field[10]->store(f_key_info->referenced_table->str, - f_key_info->referenced_table->length, + f_key_info->referenced_table->length, system_charset_info); table->field[10]->set_notnull(); table->field[11]->store(r_info->str, r_info->length, @@ -4735,7 +4735,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, tmp_res.append(partition_keywords[PKW_KEY].str, partition_keywords[PKW_KEY].length); else - tmp_res.append(partition_keywords[PKW_HASH].str, + tmp_res.append(partition_keywords[PKW_HASH].str, partition_keywords[PKW_HASH].length); table->field[7]->store(tmp_res.ptr(), tmp_res.length(), cs); break; @@ -4770,7 +4770,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, tmp_res.append(partition_keywords[PKW_KEY].str, partition_keywords[PKW_KEY].length); else - tmp_res.append(partition_keywords[PKW_HASH].str, + tmp_res.append(partition_keywords[PKW_HASH].str, partition_keywords[PKW_HASH].length); table->field[8]->store(tmp_res.ptr(), tmp_res.length(), cs); table->field[8]->set_notnull(); @@ -4849,7 +4849,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, /* SUBPARTITION_ORDINAL_POSITION */ table->field[6]->store((longlong) ++subpart_pos, TRUE); table->field[6]->set_notnull(); - + store_schema_partitions_record(thd, table, show_table, subpart_elem, file, part_id); part_id++; @@ -5067,7 +5067,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) else sch_table->field[ISE_ON_COMPLETION]-> store(STRING_WITH_LEN("PRESERVE"), scs); - + number_to_datetime(et.created, &time, 0, ¬_used); DBUG_ASSERT(not_used==0); sch_table->field[ISE_CREATED]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); @@ -5188,7 +5188,7 @@ int fill_status(THD *thd, TABLE_LIST *tables, COND *cond) tmp1= &tmp; } else - { + { option_type= OPT_SESSION; tmp1= &thd->status_var; } @@ -5243,7 +5243,7 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables, { List<FOREIGN_KEY_INFO> f_key_list; TABLE *show_table= tables->table; - show_table->file->info(HA_STATUS_VARIABLE | + show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME); @@ -5257,16 +5257,16 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables, table->field[9]->store(table_name->str, table_name->length, cs); table->field[2]->store(f_key_info->forein_id->str, f_key_info->forein_id->length, cs); - table->field[4]->store(f_key_info->referenced_db->str, + table->field[4]->store(f_key_info->referenced_db->str, f_key_info->referenced_db->length, cs); - table->field[10]->store(f_key_info->referenced_table->str, + table->field[10]->store(f_key_info->referenced_table->str, f_key_info->referenced_table->length, cs); - table->field[5]->store(f_key_info->referenced_key_name->str, + table->field[5]->store(f_key_info->referenced_key_name->str, f_key_info->referenced_key_name->length, cs); table->field[6]->store(STRING_WITH_LEN("NONE"), cs); - table->field[7]->store(f_key_info->update_method->str, + table->field[7]->store(f_key_info->update_method->str, f_key_info->update_method->length, cs); - table->field[8]->store(f_key_info->delete_method->str, + table->field[8]->store(f_key_info->delete_method->str, f_key_info->delete_method->length, cs); if (schema_table_store_record(thd, table)) DBUG_RETURN(1); @@ -5275,7 +5275,7 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables, DBUG_RETURN(0); } -struct schema_table_ref +struct schema_table_ref { const char *table_name; ST_SCHEMA_TABLE *schema_table; @@ -5342,7 +5342,7 @@ ST_SCHEMA_TABLE *find_schema_table(THD *thd, const char* table_name) } schema_table_a.table_name= table_name; - if (plugin_foreach(thd, find_schema_table_in_plugin, + if (plugin_foreach(thd, find_schema_table_in_plugin, MYSQL_INFORMATION_SCHEMA_PLUGIN, &schema_table_a)) DBUG_RETURN(schema_table_a.schema_table); @@ -5409,7 +5409,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) break; case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: - if ((item= new Item_float(fields_info->field_name, 0.0, NOT_FIXED_DEC, + if ((item= new Item_float(fields_info->field_name, 0.0, NOT_FIXED_DEC, fields_info->field_length)) == NULL) DBUG_RETURN(NULL); break; @@ -5462,7 +5462,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) tmp_table_param->schema_table= 1; SELECT_LEX *select_lex= thd->lex->current_select; if (!(table= create_tmp_table(thd, tmp_table_param, - field_list, (ORDER*) 0, 0, 0, + field_list, (ORDER*) 0, 0, 0, (select_lex->options | thd->options | TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, table_list->alias))) @@ -5807,7 +5807,7 @@ bool get_schema_tables_result(JOIN *join, thd->no_warnings_for_error= 1; for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++) - { + { if (!tab->table || !tab->table->pos_in_table_list) break; @@ -5926,17 +5926,17 @@ ST_FIELD_INFO tables_fields_info[]= {"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format", OPEN_FULL_TABLE}, {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", OPEN_FULL_TABLE}, - {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, + {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", OPEN_FULL_TABLE}, - {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, + {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", OPEN_FULL_TABLE}, {"MAX_DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", OPEN_FULL_TABLE}, - {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, + {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", OPEN_FULL_TABLE}, {"DATA_FREE", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", OPEN_FULL_TABLE}, - {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG, 0, + {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Auto_increment", OPEN_FULL_TABLE}, {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time", OPEN_FULL_TABLE}, {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time", OPEN_FULL_TABLE}, @@ -6401,9 +6401,9 @@ ST_FIELD_INFO files_fields_info[]= {"EXTENT_SIZE", 4, MYSQL_TYPE_LONGLONG, 0, 0, 0, SKIP_OPEN_TABLE}, {"INITIAL_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE}, - {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, + {"MAXIMUM_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE}, - {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, + {"AUTOEXTEND_SIZE", 21, MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), 0, SKIP_OPEN_TABLE}, {"CREATION_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE}, {"LAST_UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, 0, SKIP_OPEN_TABLE}, @@ -6415,20 +6415,20 @@ ST_FIELD_INFO files_fields_info[]= {"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format", SKIP_OPEN_TABLE}, {"TABLE_ROWS", 21 , MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Rows", SKIP_OPEN_TABLE}, - {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, + {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Avg_row_length", SKIP_OPEN_TABLE}, - {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, + {"DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_length", SKIP_OPEN_TABLE}, - {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, + {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Max_data_length", SKIP_OPEN_TABLE}, - {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, + {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Index_length", SKIP_OPEN_TABLE}, - {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0, + {"DATA_FREE", 21 , MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Data_free", SKIP_OPEN_TABLE}, {"CREATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Create_time", SKIP_OPEN_TABLE}, {"UPDATE_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Update_time", SKIP_OPEN_TABLE}, {"CHECK_TIME", 0, MYSQL_TYPE_DATETIME, 0, 1, "Check_time", SKIP_OPEN_TABLE}, - {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0, + {"CHECKSUM", 21 , MYSQL_TYPE_LONGLONG, 0, (MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED), "Checksum", SKIP_OPEN_TABLE}, {"STATUS", 20, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"EXTRA", 255, MYSQL_TYPE_STRING, 0, 1, 0, SKIP_OPEN_TABLE}, @@ -6477,13 +6477,13 @@ ST_FIELD_INFO referential_constraints_fields_info[]= ST_SCHEMA_TABLE schema_tables[]= { - {"CHARACTER_SETS", charsets_fields_info, create_schema_table, + {"CHARACTER_SETS", charsets_fields_info, create_schema_table, fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0, 0}, - {"COLLATIONS", collation_fields_info, create_schema_table, + {"COLLATIONS", collation_fields_info, create_schema_table, fill_schema_collation, make_old_format, 0, -1, -1, 0, 0}, {"COLLATION_CHARACTER_SET_APPLICABILITY", coll_charset_app_fields_info, create_schema_table, fill_schema_coll_charset_app, 0, 0, -1, -1, 0, 0}, - {"COLUMNS", columns_fields_info, create_schema_table, + {"COLUMNS", columns_fields_info, create_schema_table, get_all_tables, make_columns_old_format, get_schema_column_record, 1, 2, 0, OPTIMIZE_I_S_TABLE|OPEN_VIEW_FULL}, {"COLUMN_PRIVILEGES", column_privileges_fields_info, create_schema_table, @@ -6512,7 +6512,7 @@ ST_SCHEMA_TABLE schema_tables[]= {"REFERENTIAL_CONSTRAINTS", referential_constraints_fields_info, create_schema_table, get_all_tables, 0, get_referential_constraints_record, 1, 9, 0, OPEN_TABLE_ONLY}, - {"ROUTINES", proc_fields_info, create_schema_table, + {"ROUTINES", proc_fields_info, create_schema_table, fill_schema_proc, make_proc_old_format, 0, -1, -1, 0, 0}, {"SCHEMATA", schema_fields_info, create_schema_table, fill_schema_schemata, make_schemata_old_format, 0, 1, -1, 0, 0}, @@ -6522,12 +6522,12 @@ ST_SCHEMA_TABLE schema_tables[]= fill_status, make_old_format, 0, -1, -1, 0, 0}, {"SESSION_VARIABLES", variables_fields_info, create_schema_table, fill_variables, make_old_format, 0, -1, -1, 0, 0}, - {"STATISTICS", stat_fields_info, create_schema_table, + {"STATISTICS", stat_fields_info, create_schema_table, get_all_tables, make_old_format, get_schema_stat_record, 1, 2, 0, OPEN_TABLE_ONLY|OPTIMIZE_I_S_TABLE}, - {"STATUS", variables_fields_info, create_schema_table, fill_status, + {"STATUS", variables_fields_info, create_schema_table, fill_status, make_old_format, 0, -1, -1, 1, 0}, - {"TABLES", tables_fields_info, create_schema_table, + {"TABLES", tables_fields_info, create_schema_table, get_all_tables, make_old_format, get_schema_tables_record, 1, 2, 0, OPTIMIZE_I_S_TABLE}, {"TABLE_CONSTRAINTS", table_constraints_fields_info, create_schema_table, @@ -6539,11 +6539,11 @@ ST_SCHEMA_TABLE schema_tables[]= {"TRIGGERS", triggers_fields_info, create_schema_table, get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0, OPEN_TABLE_ONLY}, - {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table, + {"USER_PRIVILEGES", user_privileges_fields_info, create_schema_table, fill_schema_user_privileges, 0, 0, -1, -1, 0, 0}, {"VARIABLES", variables_fields_info, create_schema_table, fill_variables, make_old_format, 0, -1, -1, 1, 0}, - {"VIEWS", view_fields_info, create_schema_table, + {"VIEWS", view_fields_info, create_schema_table, get_all_tables, 0, get_schema_views_record, 1, 2, 0, OPEN_VIEW_ONLY|OPTIMIZE_I_S_TABLE}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @@ -6569,8 +6569,8 @@ int initialize_schema_table(st_plugin_int *plugin) { schema_table->create_table= create_schema_table; schema_table->old_format= make_old_format; - schema_table->idx_field1= -1, - schema_table->idx_field2= -1; + schema_table->idx_field1= -1, + schema_table->idx_field2= -1; /* Make the name available to the init() function. */ schema_table->table_name= plugin->name.str; @@ -6581,7 +6581,7 @@ int initialize_schema_table(st_plugin_int *plugin) plugin->name.str); goto err; } - + /* Make sure the plugin name is not set inside the init() function. */ schema_table->table_name= plugin->name.str; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 26f9833fd3d..6197d646cc1 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3137,8 +3137,9 @@ bool mysql_create_table_no_lock(THD *thd, if (check_engine(thd, table_name, create_info)) DBUG_RETURN(TRUE); db_options= create_info->table_options; - if (create_info->row_type == ROW_TYPE_DYNAMIC) - db_options|=HA_OPTION_PACK_RECORD; + if (create_info->row_type != ROW_TYPE_FIXED && + create_info->row_type != ROW_TYPE_DEFAULT) + db_options|= HA_OPTION_PACK_RECORD; alias= table_case_name(create_info, table_name); if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, create_info->db_type))) @@ -5015,8 +5016,7 @@ compare_tables(TABLE *table, } /* Don't pack rows in old tables if the user has requested this. */ - if (create_info->row_type == ROW_TYPE_DYNAMIC || - (new_field->flags & BLOB_FLAG) || + if ((new_field->flags & BLOB_FLAG) || new_field->sql_type == MYSQL_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED) create_info->table_options|= HA_OPTION_PACK_RECORD; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 5da4b97cc5d..33da9147b51 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -63,9 +63,9 @@ bool select_union::send_data(List<Item> &values) if ((error= table->file->ha_write_row(table->record[0]))) { - /* create_myisam_from_heap will generate error if needed */ + /* create_internal_tmp_table_from_heap will generate error if needed */ if (table->file->is_fatal_error(error, HA_CHECK_DUP) && - create_myisam_from_heap(thd, table, &tmp_table_param, error, 1)) + create_internal_tmp_table_from_heap(thd, table, &tmp_table_param, error, 1)) return 1; } return 0; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 4071bb86c90..bb1508321f4 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1694,7 +1694,7 @@ bool multi_update::send_data(List<Item> ¬_used_values) if (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE) { if (error && - create_myisam_from_heap(thd, tmp_table, + create_internal_tmp_table_from_heap(thd, tmp_table, tmp_table_param + offset, error, 1)) { do_update= 0; diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc index 606710f1f6c..4efa5ba1af7 100644 --- a/storage/maria/ha_maria.cc +++ b/storage/maria/ha_maria.cc @@ -267,8 +267,10 @@ static void _ma_check_print_msg(HA_CHECK *param, const char *msg_type, # error code */ -int table2maria(TABLE *table_arg, MARIA_KEYDEF **keydef_out, - MARIA_COLUMNDEF **recinfo_out, uint *records_out) +static int table2maria(TABLE *table_arg, data_file_type row_type, + MARIA_KEYDEF **keydef_out, + MARIA_COLUMNDEF **recinfo_out, uint *records_out, + MARIA_CREATE_INFO *create_info) { uint i, j, recpos, minpos, fieldpos, temp_length, length; enum ha_base_keytype type= HA_KEYTYPE_BINARY; @@ -281,6 +283,9 @@ int table2maria(TABLE *table_arg, MARIA_KEYDEF **keydef_out, uint options= share->db_options_in_use; DBUG_ENTER("table2maria"); + if (row_type == BLOCK_RECORD) + options|= HA_OPTION_PACK_RECORD; + if (!(my_multi_malloc(MYF(MY_WME), recinfo_out, (share->fields * 2 + 2) * sizeof(MARIA_COLUMNDEF), keydef_out, share->keys * sizeof(MARIA_KEYDEF), @@ -369,6 +374,8 @@ int table2maria(TABLE *table_arg, MARIA_KEYDEF **keydef_out, record= table_arg->record[0]; recpos= 0; recinfo_pos= recinfo; + create_info->null_bytes= table_arg->s->null_bytes; + while (recpos < (uint) share->reclength) { Field **field, *found= 0; @@ -394,13 +401,6 @@ int table2maria(TABLE *table_arg, MARIA_KEYDEF **keydef_out, } DBUG_PRINT("loop", ("found: 0x%lx recpos: %d minpos: %d length: %d", (long) found, recpos, minpos, length)); - if (recpos != minpos) - { - /* reserve space for null bits */ - bzero((char*) recinfo_pos, sizeof(*recinfo_pos)); - recinfo_pos->type= FIELD_NORMAL; - recinfo_pos++->length= (uint16) (minpos - recpos); - } if (!found) break; @@ -561,6 +561,7 @@ int maria_check_definition(MARIA_KEYDEF *t1_keyinfo, } } } + for (i= 0; i < t1_recs; i++) { MARIA_COLUMNDEF *t1_rec= &t1_recinfo[i]; @@ -1900,13 +1901,20 @@ int ha_maria::rnd_next(uchar *buf) } -int ha_maria::restart_rnd_next(uchar *buf, uchar *pos) +int ha_maria::remember_rnd_pos() { - return rnd_pos(buf, pos); + return (*file->s->scan_remember_pos)(file, &remember_pos); } -int ha_maria::rnd_pos(uchar * buf, uchar *pos) +int ha_maria::restart_rnd_next(uchar *buf) +{ + (*file->s->scan_restore_pos)(file, remember_pos); + return rnd_next(buf); +} + + +int ha_maria::rnd_pos(uchar *buf, uchar *pos) { ha_statistic_increment(&SSV::ha_read_rnd_count); int error= maria_rrnd(file, buf, my_get_ptr(pos, ref_length)); @@ -1915,7 +1923,7 @@ int ha_maria::rnd_pos(uchar * buf, uchar *pos) } -void ha_maria::position(const uchar * record) +void ha_maria::position(const uchar *record) { my_off_t row_position= maria_position(file); my_store_ptr(ref, ref_length, row_position); @@ -2216,9 +2224,10 @@ int ha_maria::create(const char *name, register TABLE *table_arg, ER_ILLEGAL_HA_CREATE_OPTION, "Row format set to PAGE because of TRANSACTIONAL=1 option"); - if ((error= table2maria(table_arg, &keydef, &recinfo, &record_count))) - DBUG_RETURN(error); /* purecov: inspected */ bzero((char*) &create_info, sizeof(create_info)); + if ((error= table2maria(table_arg, row_type, &keydef, &recinfo, + &record_count, &create_info))) + DBUG_RETURN(error); /* purecov: inspected */ create_info.max_rows= share->max_rows; create_info.reloc_rows= share->min_rows; create_info.with_auto_increment= share->next_number_key_offset == 0; @@ -2387,7 +2396,8 @@ bool ha_maria::check_if_incompatible_data(HA_CREATE_INFO *create_info, if (create_info->auto_increment_value != stats.auto_increment_value || create_info->data_file_name != data_file_name || create_info->index_file_name != index_file_name || - maria_row_type(create_info) != data_file_type || + (create_info->row_type != data_file_type && + create_info->row_type != ROW_TYPE_DEFAULT) || table_changes == IS_EQUAL_NO || table_changes & IS_EQUAL_PACK_LENGTH) // Not implemented yet return COMPATIBLE_DATA_NO; diff --git a/storage/maria/ha_maria.h b/storage/maria/ha_maria.h index 78d88cf52c6..cb4efffff5f 100644 --- a/storage/maria/ha_maria.h +++ b/storage/maria/ha_maria.h @@ -36,6 +36,7 @@ class ha_maria :public handler { MARIA_HA *file; ulonglong int_table_flags; + MARIA_RECORD_POS remember_pos; char *data_file_name, *index_file_name; enum data_file_type data_file_type; bool can_enable_indexes; @@ -101,7 +102,8 @@ public: int rnd_end(void); int rnd_next(uchar * buf); int rnd_pos(uchar * buf, uchar * pos); - int restart_rnd_next(uchar * buf, uchar * pos); + int remember_rnd_pos(); + int restart_rnd_next(uchar * buf); void position(const uchar * record); int info(uint); int extra(enum ha_extra_function operation); diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index eb3b588b69d..e1ba7de0c3d 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -502,7 +502,8 @@ my_bool _ma_init_block_record(MARIA_HA *info) sizeof(MARIA_BITMAP_BLOCK), default_extents, 64)) goto err; - if (!(info->cur_row.extents= my_malloc(default_extents * ROW_EXTENT_SIZE, + info->cur_row.extents_buffer_length= default_extents * ROW_EXTENT_SIZE; + if (!(info->cur_row.extents= my_malloc(info->cur_row.extents_buffer_length, MYF(MY_WME)))) goto err; @@ -1921,7 +1922,7 @@ static my_bool write_block_record(MARIA_HA *info, row_extents_first_part= data; data+= ROW_EXTENT_SIZE; } - if (share->base.pack_fields) + if (share->base.max_field_lengths) store_key_length_inc(data, row->field_lengths_length); if (share->calc_checksum) { @@ -3292,7 +3293,7 @@ my_bool _ma_delete_block_record(MARIA_HA *info, const uchar *record) delete_tails(info, info->cur_row.tail_positions)) goto err; - if (info->cur_row.extents && free_full_pages(info, &info->cur_row)) + if (info->cur_row.extents_count && free_full_pages(info, &info->cur_row)) goto err; if (share->now_transactional) @@ -4155,6 +4156,81 @@ void _ma_scan_end_block_record(MARIA_HA *info) DBUG_ENTER("_ma_scan_end_block_record"); my_free(info->scan.bitmap_buff, MYF(MY_ALLOW_ZERO_PTR)); info->scan.bitmap_buff= 0; + if (info->scan_save) + { + my_free(info->scan_save, MYF(0)); + info->scan_save= 0; + } + DBUG_VOID_RETURN; +} + + +/** + @brief Save current scan position + + @note + For the moment we can only remember one position, but this is + good enough for MySQL usage + + @Warning + When this function is called, we assume that the thread is not deleting + or updating the current row before ma_scan_restore_block_record() + is called! + + @return + @retval 0 ok + @retval HA_ERR_WRONG_IN_RECORD Could not allocate memory to hold position +*/ + +int _ma_scan_remember_block_record(MARIA_HA *info, + MARIA_RECORD_POS *lastpos) +{ + uchar *bitmap_buff; + DBUG_ENTER("_ma_scan_remember_block_record"); + if (!(info->scan_save)) + { + if (!(info->scan_save= my_malloc(ALIGN_SIZE(sizeof(*info->scan_save)) + + info->s->block_size * 2, + MYF(MY_WME)))) + DBUG_RETURN(HA_ERR_OUT_OF_MEM); + info->scan_save->bitmap_buff= ((uchar*) info->scan_save + + ALIGN_SIZE(sizeof(*info->scan_save))); + } + /* Point to the last read row */ + *lastpos= info->cur_row.nextpos - 1; + info->scan.dir+= DIR_ENTRY_SIZE; + + /* Remember used bitmap and used head page */ + bitmap_buff= info->scan_save->bitmap_buff; + memcpy(info->scan_save, &info->scan, sizeof(*info->scan_save)); + info->scan_save->bitmap_buff= bitmap_buff; + memcpy(bitmap_buff, info->scan.bitmap_buff, info->s->block_size * 2); + DBUG_RETURN(0); +} + + +/** + @brief restore scan block it's original values + + @note + In theory we could swap bitmap buffers instead of copy them. + For the moment we don't do that because there are variables pointing + inside the buffers and it's a bit of hassle to either make them relative + or repoint them. +*/ + +void _ma_scan_restore_block_record(MARIA_HA *info, + MARIA_RECORD_POS lastpos) +{ + uchar *bitmap_buff; + DBUG_ENTER("_ma_scan_restore_block_record"); + + info->cur_row.nextpos= lastpos; + bitmap_buff= info->scan.bitmap_buff; + memcpy(&info->scan, info->scan_save, sizeof(*info->scan_save)); + info->scan.bitmap_buff= bitmap_buff; + memcpy(bitmap_buff, info->scan_save->bitmap_buff, info->s->block_size * 2); + DBUG_VOID_RETURN; } @@ -4207,7 +4283,10 @@ restart_record_read: record_pos++; #ifdef SANITY_CHECKS if (info->scan.dir < info->scan.dir_end) + { + DBUG_ASSERT(0); goto err; + } #endif } /* found row */ @@ -4220,7 +4299,10 @@ restart_record_read: #ifdef SANITY_CHECKS if (end_of_data > info->scan.dir_end || offset < PAGE_HEADER_SIZE || length < share->base.min_block_length) + { + DBUG_ASSERT(0); goto err; + } #endif DBUG_PRINT("info", ("rowid: %lu", (ulong) info->cur_row.lastpos)); DBUG_RETURN(_ma_read_block_record2(info, record, data, end_of_data)); @@ -4259,8 +4341,20 @@ restart_bitmap_scan: PAGECACHE_LOCK_LEFT_UNLOCKED, 0))) DBUG_RETURN(my_errno); if (((info->scan.page_buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) != - HEAD_PAGE) || - (info->scan.number_of_rows= + HEAD_PAGE)) + { + /* + This may happen if someone has been deleting all rows + from a page since we read the bitmap, so it may be ok. + Print warning in debug log and continue. + */ + DBUG_PRINT("warning", + ("Found page of type %d when expecting head page", + (info->scan.page_buff[PAGE_TYPE_OFFSET] & + PAGE_TYPE_MASK))); + continue; + } + if ((info->scan.number_of_rows= (uint) (uchar) info->scan.page_buff[DIR_COUNT_OFFSET]) == 0) { DBUG_PRINT("error", ("Wrong page header")); @@ -5641,7 +5735,7 @@ my_bool _ma_apply_undo_row_insert(MARIA_HA *info, LSN undo_lsn, delete_tails(info, info->cur_row.tail_positions)) goto err; - if (info->cur_row.extents && free_full_pages(info, &info->cur_row)) + if (info->cur_row.extents_count && free_full_pages(info, &info->cur_row)) goto err; checksum= 0; @@ -5836,6 +5930,7 @@ my_bool _ma_apply_undo_row_delete(MARIA_HA *info, LSN undo_lsn, /* Row is now up to date. Time to insert the record */ res= allocate_and_write_block_record(info, record, &row, undo_lsn); + info->cur_row.lastpos= row.lastpos; my_free(record, MYF(0)); DBUG_RETURN(res); } @@ -5871,6 +5966,7 @@ my_bool _ma_apply_undo_row_update(MARIA_HA *info, LSN undo_lsn, rownr= dirpos_korr(header); header+= DIRPOS_STORE_SIZE; record_pos= ma_recordpos(page, rownr); + info->cur_row.lastpos= record_pos; /* For key insert */ DBUG_PRINT("enter", ("Page: %lu rownr: %u", (ulong) page, rownr)); if (share->calc_checksum) diff --git a/storage/maria/ma_blockrec.h b/storage/maria/ma_blockrec.h index 89cdf088ac1..781d5f255a7 100644 --- a/storage/maria/ma_blockrec.h +++ b/storage/maria/ma_blockrec.h @@ -159,6 +159,10 @@ my_bool _ma_cmp_block_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def, const uchar *record, MARIA_RECORD_POS pos); my_bool _ma_scan_init_block_record(MARIA_HA *info); void _ma_scan_end_block_record(MARIA_HA *info); +int _ma_scan_remember_block_record(MARIA_HA *info, + MARIA_RECORD_POS *lastpos); +void _ma_scan_restore_block_record(MARIA_HA *info, + MARIA_RECORD_POS lastpos); MARIA_RECORD_POS _ma_write_init_block_record(MARIA_HA *info, const uchar *record); diff --git a/storage/maria/ma_close.c b/storage/maria/ma_close.c index 87021820be5..b354b0fb79c 100644 --- a/storage/maria/ma_close.c +++ b/storage/maria/ma_close.c @@ -100,7 +100,7 @@ int maria_close(register MARIA_HA *info) File must be synced as it is going out of the maria_open_list and so becoming unknown to future Checkpoints. */ - if (my_sync(share->kfile.file, MYF(MY_WME))) + if (!share->temporary && my_sync(share->kfile.file, MYF(MY_WME))) error= my_errno; if (my_close(share->kfile.file, MYF(0))) error= my_errno; diff --git a/storage/maria/ma_control_file.c b/storage/maria/ma_control_file.c index 4510cc11b20..36efb52acec 100644 --- a/storage/maria/ma_control_file.c +++ b/storage/maria/ma_control_file.c @@ -214,6 +214,7 @@ CONTROL_FILE_ERROR ma_control_file_create_or_open() const char *errmsg; MY_STAT stat_buff; uint new_cf_create_time_size, new_cf_changeable_size, new_block_size; + uint retry; int open_flags= O_BINARY | /*O_DIRECT |*/ O_RDWR; int error= CONTROL_FILE_UNKNOWN_ERROR; DBUG_ENTER("ma_control_file_create_or_open"); @@ -347,6 +348,29 @@ CONTROL_FILE_ERROR ma_control_file_create_or_open() CF_LSN_OFFSET); last_logno= uint4korr(buffer + new_cf_create_time_size + CF_FILENO_OFFSET); + retry= 0; + + /* + We can't here use the automatic wait in my_lock() as the alarm thread + may not yet exists. + */ + + while (my_lock(control_file_fd, F_WRLCK, 0L, F_TO_EOF, + MYF(MY_SEEK_NOT_DONE | MY_FORCE_LOCK | MY_NO_WAIT))) + { + if (retry == 0) + my_printf_error(HA_ERR_INITIALIZATION, + "Can't lock maria control file '%s' for exclusive use, " + "error: %d. Will retry for %d seconds", 0, + name, my_errno, MARIA_MAX_CONTROL_FILE_LOCK_RETRY); + if (retry++ > MARIA_MAX_CONTROL_FILE_LOCK_RETRY) + { + errmsg= "Could not get an exclusive lock; File is probably in use by another process"; + goto err; + } + sleep(1); + } + DBUG_RETURN(0); err: @@ -463,6 +487,9 @@ int ma_control_file_end() if (control_file_fd < 0) /* already closed */ DBUG_RETURN(0); + (void) my_lock(control_file_fd, F_UNLCK, 0L, F_TO_EOF, + MYF(MY_SEEK_NOT_DONE | MY_FORCE_LOCK)); + close_error= my_close(control_file_fd, MYF(MY_WME)); /* As my_close() frees structures even if close() fails, we do the same, diff --git a/storage/maria/ma_create.c b/storage/maria/ma_create.c index 2922a91baef..913dc15999d 100644 --- a/storage/maria/ma_create.c +++ b/storage/maria/ma_create.c @@ -147,8 +147,17 @@ int maria_create(const char *name, enum data_file_type datafile_type, reclength+= column->length; type= column->type; - if (type == FIELD_SKIP_PRESPACE && datafile_type == BLOCK_RECORD) - type= FIELD_NORMAL; /* SKIP_PRESPACE not supported */ + if (datafile_type == BLOCK_RECORD) + { + if (type == FIELD_SKIP_PRESPACE) + type= FIELD_NORMAL; /* SKIP_PRESPACE not supported */ + if (type == FIELD_NORMAL && + column->length > FULL_PAGE_SIZE(maria_block_size)) + { + /* FIELD_NORMAL can't be split over many blocks, convert to a CHAR */ + type= column->type= FIELD_SKIP_ENDSPACE; + } + } if (type != FIELD_NORMAL && type != FIELD_CHECK) { @@ -623,7 +632,6 @@ int maria_create(const char *name, enum data_file_type datafile_type, } unique_key_parts=0; - offset=reclength-uniques*MARIA_UNIQUE_HASH_LENGTH; for (i=0, uniquedef=uniquedefs ; i < uniques ; i++ , uniquedef++) { uniquedef->key=keys+i; @@ -868,7 +876,7 @@ int maria_create(const char *name, enum data_file_type datafile_type, #endif } /* Create extra keys for unique definitions */ - offset=reclength-uniques*MARIA_UNIQUE_HASH_LENGTH; + offset= real_reclength - uniques*MARIA_UNIQUE_HASH_LENGTH; bzero((char*) &tmp_keydef,sizeof(tmp_keydef)); bzero((char*) &tmp_keyseg,sizeof(tmp_keyseg)); for (i=0; i < uniques ; i++) @@ -1194,7 +1202,7 @@ uint maria_get_pointer_length(ulonglong file_length, uint def) For same kind of fields, keep fields in original order */ -static inline int sign(longlong a) +static inline int sign(long a) { return a < 0 ? -1 : (a > 0 ? 1 : 0); } @@ -1214,12 +1222,12 @@ static int compare_columns(MARIA_COLUMNDEF **a_ptr, MARIA_COLUMNDEF **b_ptr) { if (b_type != FIELD_NORMAL || b->null_bit) return -1; - return sign((long) (a->offset - b->offset)); + return sign((long) a->offset - (long) b->offset); } if (b_type == FIELD_NORMAL && !b->null_bit) return 1; if (a_type == b_type) - return sign((long) (a->offset - b->offset)); + return sign((long) a->offset - (long) b->offset); if (a_type == FIELD_NORMAL) return -1; if (b_type == FIELD_NORMAL) @@ -1228,7 +1236,7 @@ static int compare_columns(MARIA_COLUMNDEF **a_ptr, MARIA_COLUMNDEF **b_ptr) return 1; if (b_type == FIELD_BLOB) return -1; - return sign((long) (a->offset - b->offset)); + return sign((long) a->offset - (long) b->offset); } diff --git a/storage/maria/ma_delete.c b/storage/maria/ma_delete.c index 1388d81df67..67d3d8d7092 100644 --- a/storage/maria/ma_delete.c +++ b/storage/maria/ma_delete.c @@ -192,7 +192,11 @@ int _ma_ck_delete(register MARIA_HA *info, uint keynr, uchar *key, log_type= LOGREC_UNDO_KEY_DELETE_WITH_ROOT; } - key_length+= share->rec_reflength; + /* + Note that for delete key, we don't log the reference to the record. + This is because the row may be inserted at a different place when + we exceute the undo + */ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (char*) log_data; log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos - log_data); log_array[TRANSLOG_INTERNAL_PARTS + 1].str= (char*) key_buff; diff --git a/storage/maria/ma_dynrec.c b/storage/maria/ma_dynrec.c index 9f42f2beaa2..cb33160bdf6 100644 --- a/storage/maria/ma_dynrec.c +++ b/storage/maria/ma_dynrec.c @@ -1501,7 +1501,10 @@ my_bool _ma_cmp_dynamic_unique(MARIA_HA *info, MARIA_UNIQUEDEF *def, old_rec_buff_size= info->rec_buff_size; if (info->s->base.blobs) + { info->rec_buff= 0; + info->rec_buff_size= 0; + } error= _ma_read_dynamic_record(info, old_record, pos) != 0; if (!error) error=_ma_unique_comp(def, record, old_record, def->null_are_equal) != 0; diff --git a/storage/maria/ma_extra.c b/storage/maria/ma_extra.c index 62e091a8928..26e129245d6 100644 --- a/storage/maria/ma_extra.c +++ b/storage/maria/ma_extra.c @@ -224,7 +224,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, info->lock_wait= 0; break; case HA_EXTRA_NO_WAIT_LOCK: - info->lock_wait= MY_DONT_WAIT; + info->lock_wait= MY_SHORT_WAIT; break; case HA_EXTRA_NO_KEYS: /* we're going to modify pieces of the state, stall Checkpoint */ @@ -273,11 +273,12 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, break; case HA_EXTRA_FORCE_REOPEN: /* - Normally MySQL uses this case when it is going to close all open - instances of the table, thus going to flush all data/index/state. + MySQL uses this case after it has closed all other instances + of this table. We however do a flush here for additional safety. */ /** @todo consider porting these flush-es to MyISAM */ + DBUG_ASSERT(share->reopen == 1); error= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX, FLUSH_FORCE_WRITE, FLUSH_FORCE_WRITE); if (!error && share->changed) @@ -287,19 +288,6 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function, share->changed= 0; pthread_mutex_unlock(&share->intern_lock); } - - /** - @todo RECOVERY BUG - Though we flushed the state, IF some other thread may have the same - table (same MARIA_SHARE) open at this time then it may have a - more recent state to flush when it closes, thus we don't set - share->changed to 0 here. On the other hand, this means that when our - thread closes its table, it will flush the state again, then it would - overwrite any state written by yet another thread which may have opened - the table (new MARIA_SHARE) and done some updates. - ASK_MONTY about the IF above. See also same tag in - HA_EXTRA_PREPARE_FOR_DROP|RENAME. - */ pthread_mutex_lock(&THR_LOCK_maria); pthread_mutex_lock(&share->intern_lock); /* protect against Checkpoint */ /* this makes the share not be re-used next time the table is opened */ diff --git a/storage/maria/ma_key_recover.c b/storage/maria/ma_key_recover.c index f929929083b..a4eb1e8cc5e 100644 --- a/storage/maria/ma_key_recover.c +++ b/storage/maria/ma_key_recover.c @@ -109,6 +109,20 @@ my_bool _ma_write_clr(MARIA_HA *info, LSN undo_lsn, page_store(log_pos + KEY_NR_STORE_SIZE, page); log_pos+= KEY_NR_STORE_SIZE + PAGE_STORE_SIZE; } + if (undo_type == LOGREC_UNDO_ROW_DELETE || + undo_type == LOGREC_UNDO_ROW_UPDATE) + { + /* + We need to store position to the row that was inserted to be + able to regenerate keys + */ + MARIA_RECORD_POS rowid= info->cur_row.lastpos; + ulonglong page= ma_recordpos_to_page(rowid); + uint dir_entry= ma_recordpos_to_dir_entry(rowid); + page_store(log_pos, page); + dirpos_store(log_pos+ PAGE_STORE_SIZE, dir_entry); + log_pos+= PAGE_STORE_SIZE + DIRPOS_STORE_SIZE; + } log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (char*) log_data; log_array[TRANSLOG_INTERNAL_PARTS + 0].length= (uint) (log_pos - log_data); @@ -937,7 +951,7 @@ my_bool _ma_apply_undo_key_insert(MARIA_HA *info, LSN undo_lsn, /** - @brief Undo of insert of key (ie, delete the inserted key) + @brief Undo of delete of key (ie, insert the deleted key) */ my_bool _ma_apply_undo_key_delete(MARIA_HA *info, LSN undo_lsn, @@ -959,11 +973,12 @@ my_bool _ma_apply_undo_key_delete(MARIA_HA *info, LSN undo_lsn, /* We have to copy key as _ma_ck_real_write_btree() may change it */ memcpy(key, header + KEY_NR_STORE_SIZE, length); - DBUG_DUMP("key", key, length); + _ma_dpointer(info, key + length, info->cur_row.lastpos); + DBUG_DUMP("key", key, length + share->rec_reflength); new_root= share->state.key_root[keynr]; res= _ma_ck_real_write_btree(info, share->keyinfo+keynr, key, - length - info->s->rec_reflength, + length, &new_root, share->keyinfo[keynr].write_comp_flag); diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c index 980d287468e..ffc9a613e78 100644 --- a/storage/maria/ma_open.c +++ b/storage/maria/ma_open.c @@ -871,6 +871,9 @@ void _ma_setup_functions(register MARIA_SHARE *share) share->end= maria_scan_end_dummy; share->scan_init= maria_scan_init_dummy;/* Compat. dummy function */ share->scan_end= maria_scan_end_dummy;/* Compat. dummy function */ + share->scan_remember_pos= _ma_def_scan_remember_pos; + share->scan_restore_pos= _ma_def_scan_restore_pos; + share->write_record_init= _ma_write_init_default; share->write_record_abort= _ma_write_abort_default; share->keypos_to_recpos= _ma_transparent_recpos; @@ -936,8 +939,10 @@ void _ma_setup_functions(register MARIA_SHARE *share) share->write_record_abort= _ma_write_abort_block_record; share->scan_init= _ma_scan_init_block_record; share->scan_end= _ma_scan_end_block_record; - share->read_record= _ma_read_block_record; share->scan= _ma_scan_block_record; + share->scan_remember_pos= _ma_scan_remember_block_record; + share->scan_restore_pos= _ma_scan_restore_block_record; + share->read_record= _ma_read_block_record; share->delete_record= _ma_delete_block_record; share->compare_record= _ma_compare_block_record; share->update_record= _ma_update_block_record; @@ -994,7 +999,8 @@ static void setup_key_functions(register MARIA_KEYDEF *keyinfo) if (keyinfo->seg[0].flag & HA_PACK_KEY) { /* Prefix compression */ if (!keyinfo->seg->charset || use_strnxfrm(keyinfo->seg->charset) || - (keyinfo->seg->flag & HA_NULL_PART)) + (keyinfo->seg->flag & HA_NULL_PART) || + keyinfo->seg->charset->mbminlen > 1) keyinfo->bin_search= _ma_seq_search; else keyinfo->bin_search= _ma_prefix_search; @@ -1468,12 +1474,14 @@ my_bool _ma_columndef_write(File file, MARIA_COLUMNDEF *columndef) uchar buff[MARIA_COLUMNDEF_SIZE]; uchar *ptr=buff; - mi_int2store(ptr,(ulong) columndef->offset); ptr+= 2; - mi_int2store(ptr,columndef->type); ptr+= 2; - mi_int2store(ptr,columndef->length); ptr+= 2; - mi_int2store(ptr,columndef->fill_length); ptr+= 2; - mi_int2store(ptr,columndef->null_pos); ptr+= 2; - mi_int2store(ptr,columndef->empty_pos); ptr+= 2; + mi_int2store(ptr,(ulong) columndef->column_nr); ptr+= 2; + mi_int2store(ptr,(ulong) columndef->offset); ptr+= 2; + mi_int2store(ptr,columndef->type); ptr+= 2; + mi_int2store(ptr,columndef->length); ptr+= 2; + mi_int2store(ptr,columndef->fill_length); ptr+= 2; + mi_int2store(ptr,columndef->null_pos); ptr+= 2; + mi_int2store(ptr,columndef->empty_pos); ptr+= 2; + (*ptr++)= columndef->null_bit; (*ptr++)= columndef->empty_bit; ptr[0]= ptr[1]= ptr[2]= ptr[3]= 0; ptr+= 4; /* For future */ @@ -1482,6 +1490,7 @@ my_bool _ma_columndef_write(File file, MARIA_COLUMNDEF *columndef) uchar *_ma_columndef_read(uchar *ptr, MARIA_COLUMNDEF *columndef) { + columndef->column_nr= mi_uint2korr(ptr); ptr+= 2; columndef->offset= mi_uint2korr(ptr); ptr+= 2; columndef->type= mi_sint2korr(ptr); ptr+= 2; columndef->length= mi_uint2korr(ptr); ptr+= 2; diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c index f1b34e444c0..5873db8db61 100644 --- a/storage/maria/ma_recovery.c +++ b/storage/maria/ma_recovery.c @@ -1761,6 +1761,24 @@ prototype_redo_exec_hook(COMMIT) } +/* + Set position for next active record that will have key inserted +*/ + +static void set_lastpos(MARIA_HA *info, uchar *pos) +{ + ulonglong page; + uint dir_entry; + + /* If we have checksum, it's before rowid */ + if (info->s->calc_checksum) + pos+= HA_CHECKSUM_STORE_SIZE; + page= page_korr(pos); + dir_entry= dirpos_korr(pos + PAGE_STORE_SIZE); + info->cur_row.lastpos= ma_recordpos(page, dir_entry); +} + + prototype_redo_exec_hook(CLR_END) { MARIA_HA *info= get_MARIA_HA_from_UNDO_record(rec); @@ -1769,6 +1787,7 @@ prototype_redo_exec_hook(CLR_END) enum translog_record_type undone_record_type; const LOG_DESC *log_desc; my_bool row_entry= 0; + uchar *logpos; DBUG_ENTER("exec_REDO_LOGREC_CLR_END"); if (info == NULL) @@ -1782,6 +1801,19 @@ prototype_redo_exec_hook(CLR_END) set_undo_lsn_for_active_trans(rec->short_trid, previous_undo_lsn); tprint(tracef, " CLR_END was about %s, undo_lsn now LSN (%lu,0x%lx)\n", log_desc->name, LSN_IN_PARTS(previous_undo_lsn)); + + enlarge_buffer(rec); + if (log_record_buffer.str == NULL || + translog_read_record(rec->lsn, 0, rec->record_length, + log_record_buffer.str, NULL) != + rec->record_length) + { + eprint(tracef, "Failed to read record\n"); + return 1; + } + logpos= (log_record_buffer.str + LSN_STORE_SIZE + FILEID_STORE_SIZE + + CLR_TYPE_STORE_SIZE); + if (cmp_translog_addr(rec->lsn, share->state.is_of_horizon) >= 0) { tprint(tracef, " state older than record\n"); @@ -1789,6 +1821,7 @@ prototype_redo_exec_hook(CLR_END) case LOGREC_UNDO_ROW_DELETE: row_entry= 1; share->state.state.records++; + set_lastpos(info, logpos); break; case LOGREC_UNDO_ROW_INSERT: share->state.state.records--; @@ -1796,6 +1829,7 @@ prototype_redo_exec_hook(CLR_END) break; case LOGREC_UNDO_ROW_UPDATE: row_entry= 1; + set_lastpos(info, logpos); break; case LOGREC_UNDO_KEY_INSERT: case LOGREC_UNDO_KEY_DELETE: @@ -1805,18 +1839,8 @@ prototype_redo_exec_hook(CLR_END) { uint key_nr; my_off_t page; - uchar buff[KEY_NR_STORE_SIZE + PAGE_STORE_SIZE]; - if (translog_read_record(rec->lsn, LSN_STORE_SIZE + FILEID_STORE_SIZE + - CLR_TYPE_STORE_SIZE, - KEY_NR_STORE_SIZE + PAGE_STORE_SIZE, - buff, NULL) != - KEY_NR_STORE_SIZE + PAGE_STORE_SIZE) - { - eprint(tracef, "Failed to read record\n"); - DBUG_RETURN(1); - } - key_nr= key_nr_korr(buff); - page= page_korr(buff + KEY_NR_STORE_SIZE); + key_nr= key_nr_korr(logpos); + page= page_korr(logpos + KEY_NR_STORE_SIZE); share->state.key_root[key_nr]= (page == IMPOSSIBLE_PAGE_NO ? HA_OFFSET_ERROR : page * share->block_size); @@ -1826,19 +1850,21 @@ prototype_redo_exec_hook(CLR_END) DBUG_ASSERT(0); } if (row_entry && share->calc_checksum) - { - uchar buff[HA_CHECKSUM_STORE_SIZE]; - if (translog_read_record(rec->lsn, LSN_STORE_SIZE + FILEID_STORE_SIZE + - CLR_TYPE_STORE_SIZE, HA_CHECKSUM_STORE_SIZE, - buff, NULL) != HA_CHECKSUM_STORE_SIZE) - { - eprint(tracef, "Failed to read record\n"); - DBUG_RETURN(1); - } - share->state.state.checksum+= ha_checksum_korr(buff); - } + share->state.state.checksum+= ha_checksum_korr(logpos); share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED; } + else + { + /* We must set lastpos for upcoming undo delete keys */ + switch (undone_record_type) { + case LOGREC_UNDO_ROW_DELETE: + case LOGREC_UNDO_ROW_UPDATE: + set_lastpos(info, logpos); + break; + default: + break; + } + } if (row_entry) tprint(tracef, " rows' count %lu\n", (ulong)share->state.state.records); _ma_unpin_all_pages(info, rec->lsn); diff --git a/storage/maria/ma_scan.c b/storage/maria/ma_scan.c index f9657833fdd..48e9e3400ce 100644 --- a/storage/maria/ma_scan.c +++ b/storage/maria/ma_scan.c @@ -58,3 +58,16 @@ void maria_scan_end(MARIA_HA *info) { (*info->s->scan_end)(info); } + + +int _ma_def_scan_remember_pos(MARIA_HA *info, MARIA_RECORD_POS *lastpos) +{ + *lastpos= info->cur_row.lastpos; + return 0; +} + + +void _ma_def_scan_restore_pos(MARIA_HA *info, MARIA_RECORD_POS lastpos) +{ + info->cur_row.nextpos= lastpos; +} diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h index 6748fc23318..525cf94d660 100644 --- a/storage/maria/maria_def.h +++ b/storage/maria/maria_def.h @@ -40,6 +40,7 @@ #define MAX_NONMAPPED_INSERTS 1000 #define MARIA_MAX_TREE_LEVELS 32 +#define MARIA_MAX_CONTROL_FILE_LOCK_RETRY 30 /* Retry this many times */ struct st_transaction; @@ -124,7 +125,7 @@ typedef struct st_maria_state_info #define MARIA_KEYDEF_SIZE (2+ 5*2) #define MARIA_UNIQUEDEF_SIZE (2+1+1) #define HA_KEYSEG_SIZE (6+ 2*2 + 4*2) -#define MARIA_COLUMNDEF_SIZE (6+2+2+2+2+2+1+1) +#define MARIA_COLUMNDEF_SIZE (2*7+1+1+4) #define MARIA_BASE_INFO_SIZE (MY_UUID_SIZE + 5*8 + 6*4 + 11*2 + 6 + 5*2 + 1 + 16) #define MARIA_INDEX_BLOCK_MARGIN 16 /* Safety margin for .MYI tables */ /* Internal management bytes needed to store 2 keys on an index page */ @@ -271,6 +272,8 @@ typedef struct st_maria_share int (*scan)(MARIA_HA *, uchar *, MARIA_RECORD_POS, my_bool); /* End scan */ void (*scan_end)(MARIA_HA *); + int (*scan_remember_pos)(MARIA_HA *, MARIA_RECORD_POS*); + void (*scan_restore_pos)(MARIA_HA *, MARIA_RECORD_POS); /* Pre-write of row (some handlers may do the actual write here) */ MARIA_RECORD_POS (*write_record_init)(MARIA_HA *, const uchar *); /* Write record (or accept write_record_init) */ @@ -424,7 +427,7 @@ struct st_maria_handler MARIA_STATUS_INFO *state, save_state; MARIA_ROW cur_row; /* The active row that we just read */ MARIA_ROW new_row; /* Storage for a row during update */ - MARIA_BLOCK_SCAN scan; + MARIA_BLOCK_SCAN scan, *scan_save; MARIA_BLOB *blobs; /* Pointer to blobs */ MARIA_BIT_BUFF bit_buff; DYNAMIC_ARRAY bitmap_blocks; @@ -477,7 +480,7 @@ struct st_maria_handler enum ha_rkey_function last_key_func; /* CONTAIN, OVERLAP, etc */ uint save_lastkey_length; uint pack_key_length; /* For MARIAMRG */ - myf lock_wait; /* is 0 or MY_DONT_WAIT */ + myf lock_wait; /* is 0 or MY_SHORT_WAIT */ int errkey; /* Got last error on this key */ int lock_type; /* How database was locked */ int tmp_lock_type; /* When locked by readinfo */ @@ -984,6 +987,9 @@ void _ma_restore_status(void *param); void _ma_copy_status(void *to, void *from); my_bool _ma_check_status(void *param); void _ma_reset_status(MARIA_HA *maria); +int _ma_def_scan_remember_pos(MARIA_HA *info, MARIA_RECORD_POS *lastpos); +void _ma_def_scan_restore_pos(MARIA_HA *info, MARIA_RECORD_POS lastpos); + #include "ma_commit.h" extern MARIA_HA *_ma_test_if_reopen(const char *filename); diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 5e58565364c..4aea0ebee98 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -255,28 +255,28 @@ int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out, { /* reserve space for null bits */ bzero((char*) recinfo_pos, sizeof(*recinfo_pos)); - recinfo_pos->type= (int) FIELD_NORMAL; + recinfo_pos->type= FIELD_NORMAL; recinfo_pos++->length= (uint16) (minpos - recpos); } if (!found) break; if (found->flags & BLOB_FLAG) - recinfo_pos->type= (int) FIELD_BLOB; + recinfo_pos->type= FIELD_BLOB; else if (found->type() == MYSQL_TYPE_VARCHAR) recinfo_pos->type= FIELD_VARCHAR; else if (!(options & HA_OPTION_PACK_RECORD)) - recinfo_pos->type= (int) FIELD_NORMAL; + recinfo_pos->type= FIELD_NORMAL; else if (found->zero_pack()) - recinfo_pos->type= (int) FIELD_SKIP_ZERO; + recinfo_pos->type= FIELD_SKIP_ZERO; else - recinfo_pos->type= (int) ((length <= 3 || - (found->flags & ZEROFILL_FLAG)) ? - FIELD_NORMAL : - found->type() == MYSQL_TYPE_STRING || - found->type() == MYSQL_TYPE_VAR_STRING ? - FIELD_SKIP_ENDSPACE : - FIELD_SKIP_PRESPACE); + recinfo_pos->type= ((length <= 3 || + (found->flags & ZEROFILL_FLAG)) ? + FIELD_NORMAL : + found->type() == MYSQL_TYPE_STRING || + found->type() == MYSQL_TYPE_VAR_STRING ? + FIELD_SKIP_ENDSPACE : + FIELD_SKIP_PRESPACE); if (found->null_ptr) { recinfo_pos->null_bit= found->null_bit; @@ -1675,9 +1675,15 @@ int ha_myisam::rnd_next(uchar *buf) return error; } -int ha_myisam::restart_rnd_next(uchar *buf, uchar *pos) +int ha_myisam::remember_rnd_pos() { - return rnd_pos(buf,pos); + position((uchar*) 0); + return 0; +} + +int ha_myisam::restart_rnd_next(uchar *buf) +{ + return rnd_pos(buf, ref); } int ha_myisam::rnd_pos(uchar *buf, uchar *pos) diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h index 96440b74c9d..74780abf42b 100644 --- a/storage/myisam/ha_myisam.h +++ b/storage/myisam/ha_myisam.h @@ -94,7 +94,8 @@ class ha_myisam: public handler int rnd_init(bool scan); int rnd_next(uchar *buf); int rnd_pos(uchar * buf, uchar *pos); - int restart_rnd_next(uchar *buf, uchar *pos); + int remember_rnd_pos(); + int restart_rnd_next(uchar *buf); void position(const uchar *record); int info(uint); int extra(enum ha_extra_function operation); diff --git a/storage/myisam/mi_check.c b/storage/myisam/mi_check.c index 152ffd3bb55..c07ed3424d2 100644 --- a/storage/myisam/mi_check.c +++ b/storage/myisam/mi_check.c @@ -2028,7 +2028,7 @@ int lock_file(HA_CHECK *param, File file, my_off_t start, int lock_type, { if (my_lock(file,lock_type,start,F_TO_EOF, param->testflag & T_WAIT_FOREVER ? MYF(MY_SEEK_NOT_DONE) : - MYF(MY_SEEK_NOT_DONE | MY_DONT_WAIT))) + MYF(MY_SEEK_NOT_DONE | MY_SHORT_WAIT))) { mi_check_print_error(param," %d when locking %s '%s'",my_errno,filetype,filename); param->error_printed=2; /* Don't give that data is crashed */ diff --git a/storage/myisam/mi_extra.c b/storage/myisam/mi_extra.c index 33c9d1210ca..d798ef50d7e 100644 --- a/storage/myisam/mi_extra.c +++ b/storage/myisam/mi_extra.c @@ -216,7 +216,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) info->lock_wait=0; break; case HA_EXTRA_NO_WAIT_LOCK: - info->lock_wait=MY_DONT_WAIT; + info->lock_wait= MY_SHORT_WAIT; break; case HA_EXTRA_NO_KEYS: if (info->lock_type == F_UNLCK) diff --git a/storage/myisam/mi_open.c b/storage/myisam/mi_open.c index 5ce8ec0275a..3e877513098 100644 --- a/storage/myisam/mi_open.c +++ b/storage/myisam/mi_open.c @@ -180,7 +180,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) { if ((lock_error=my_lock(kfile,F_RDLCK,0L,F_TO_EOF, MYF(open_flags & HA_OPEN_WAIT_IF_LOCKED ? - 0 : MY_DONT_WAIT))) && + 0 : MY_SHORT_WAIT))) && !(open_flags & HA_OPEN_IGNORE_IF_LOCKED)) goto err; } diff --git a/storage/myisam/myisamdef.h b/storage/myisam/myisamdef.h index 59d54bdc542..64c1a8214c3 100644 --- a/storage/myisam/myisamdef.h +++ b/storage/myisam/myisamdef.h @@ -284,7 +284,7 @@ struct st_myisam_info LIST open_list; IO_CACHE rec_cache; /* When cacheing records */ uint preload_buff_size; /* When preloading indexes */ - myf lock_wait; /* is 0 or MY_DONT_WAIT */ + myf lock_wait; /* is 0 or MY_SHORT_WAIT */ my_bool was_locked; /* Was locked in panic */ my_bool append_insert_at_end; /* Set if concurrent insert */ my_bool quick_mode; |