diff options
author | unknown <mskold@mysql.com> | 2005-05-16 08:12:35 +0200 |
---|---|---|
committer | unknown <mskold@mysql.com> | 2005-05-16 08:12:35 +0200 |
commit | aeda265208d7abc29b874ddd03fcc869cc054d65 (patch) | |
tree | 59db4f3848621bf4573f1e130268483823ca71b1 | |
parent | db2616673f03ef4fd7fbe2da16ced78b53d87a9a (diff) | |
parent | 3e029b363f4625031e7d3aae858e95f129cba120 (diff) | |
download | mariadb-git-aeda265208d7abc29b874ddd03fcc869cc054d65.tar.gz |
Merge mskold@bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/usr/local/home/marty/MySQL/test/mysql-5.0-ndb
BitKeeper/etc/logging_ok:
auto-union
mysql-test/mysql-test-run.sh:
Auto merged
ndb/src/kernel/blocks/dbtc/DbtcMain.cpp:
Auto merged
ndb/test/ndbapi/testNodeRestart.cpp:
Auto merged
sql/item.cc:
Auto merged
sql/mysqld.cc:
Auto merged
sql/sql_parse.cc:
Auto merged
sql/sql_select.cc:
Auto merged
134 files changed, 2658 insertions, 729 deletions
diff --git a/BUILD/check-cpu b/BUILD/check-cpu index dfdf96d6b29..7619224314b 100755 --- a/BUILD/check-cpu +++ b/BUILD/check-cpu @@ -55,6 +55,10 @@ case "$cpu_family--$model_name" in *Pentium*III*CPU*) cpu_flag="pentium3"; ;; + *Pentium*M*pro*) + cpu_flag="pentium-m"; + cpu_flag_old="pentium"; + ;; *Athlon*64*) cpu_flag="athlon64"; cpu_flag_old="athlon"; diff --git a/BitKeeper/etc/config b/BitKeeper/etc/config index c609fcdbd49..1ac24031dca 100644 --- a/BitKeeper/etc/config +++ b/BitKeeper/etc/config @@ -69,6 +69,7 @@ pager: hours: [serg:]checkout:get [arjen:]checkout:get +[kostja:]checkout:get [nick:]checkout:get checkout:edit eoln:unix diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 311403f93e6..3f0d0ce05fb 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -126,6 +126,7 @@ kaa@polly.local kaj@work.mysql.com kent@mysql.com konstantin@mysql.com +kosipov@production.mysql.com kostja@oak.local lars@mysql.com lenz@kallisto.mysql.com diff --git a/client/mysqltest.c b/client/mysqltest.c index 4991e565594..9240e10ce03 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -593,7 +593,7 @@ static void abort_not_supported_test() printf("skipped\n"); free_used_memory(); my_end(MY_CHECK_ERROR); - exit(2); + exit(62); } static void verbose_msg(const char* fmt, ...) @@ -2729,6 +2729,8 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) if (!disable_result_log) { + ulong affected_rows; /* Ok to be undef if 'disable_info' is set */ + if (res) { MYSQL_FIELD *field= mysql_fetch_fields(res); @@ -2751,6 +2753,13 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) } /* + Need to call mysql_affected_rows() before the new + query to find the warnings + */ + if (!disable_info) + affected_rows= (ulong)mysql_affected_rows(mysql); + + /* Add all warnings to the result. We can't do this if we are in the middle of processing results from multi-statement, because this will break protocol. @@ -2777,7 +2786,7 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) if (!disable_info) { char buf[40]; - sprintf(buf,"affected rows: %lu\n",(ulong) mysql_affected_rows(mysql)); + sprintf(buf,"affected rows: %lu\n", affected_rows); dynstr_append(ds, buf); if (mysql_info(mysql)) { diff --git a/cmd-line-utils/libedit/vi.c b/cmd-line-utils/libedit/vi.c index 4a0352859dd..b977ce716c6 100644 --- a/cmd-line-utils/libedit/vi.c +++ b/cmd-line-utils/libedit/vi.c @@ -1014,7 +1014,7 @@ vi_histedit(EditLine *el, int c) return CC_ERROR; case 0: close(fd); - execlp("vi", "vi", tempfile, 0); + execlp("vi", "vi", tempfile, (char *) NULL); exit(0); /*NOTREACHED*/ default: diff --git a/configure.in b/configure.in index 44fe34ad655..cd4f011e1ce 100644 --- a/configure.in +++ b/configure.in @@ -141,8 +141,11 @@ AC_ARG_WITH(darwin-mwcc, export CC CXX LD AR RANLIB AC_SUBST(AR) AC_SUBST(RANLIB) + with_darwin_mwcc=yes ]) +AM_CONDITIONAL(DARWIN_MWCC, test x$with_darwin_mwcc = xyes) + if test "x${CFLAGS-}" = x ; then cflags_is_set=no else diff --git a/include/errmsg.h b/include/errmsg.h index ae3b04b4f3a..fd3da392df4 100644 --- a/include/errmsg.h +++ b/include/errmsg.h @@ -95,6 +95,7 @@ extern const char *client_errors[]; /* Error messages */ #define CR_FETCH_CANCELED 2050 #define CR_NO_DATA 2051 #define CR_NO_STMT_METADATA 2052 -#define CR_ERROR_LAST /*Copy last error nr:*/ 2052 +#define CR_NO_RESULT_SET 2053 +#define CR_ERROR_LAST /*Copy last error nr:*/ 2053 /* Add error numbers before CR_ERROR_LAST and change it accordingly. */ diff --git a/include/my_global.h b/include/my_global.h index 9f3acef0ff6..5448aa3e871 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -308,9 +308,15 @@ C_MODE_END #ifndef CONFIG_SMP #define CONFIG_SMP #endif +#if defined(__ia64__) +#define new my_arg_new +#endif C_MODE_START #include <asm/atomic.h> C_MODE_END +#if defined(__ia64__) +#undef new +#endif #endif #include <errno.h> /* Recommended by debian */ /* We need the following to go around a problem with openssl on solaris */ diff --git a/include/my_sys.h b/include/my_sys.h index f235b5a072e..a744a71ba6e 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -778,6 +778,11 @@ extern void reset_root_defaults(MEM_ROOT *mem_root, uint block_size, extern char *strdup_root(MEM_ROOT *root,const char *str); extern char *strmake_root(MEM_ROOT *root,const char *str,uint len); extern char *memdup_root(MEM_ROOT *root,const char *str,uint len); +extern int my_correct_defaults_file(const char *file_location, + const char *option, + const char *option_value, + const char *section_name, + int remove_option); extern void get_defaults_files(int argc, char **argv, char **defaults, char **extra_defaults); extern int load_defaults(const char *conf_file, const char **groups, diff --git a/include/myisam.h b/include/myisam.h index e0eb8715aef..7d3f0e0c801 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -190,10 +190,10 @@ typedef struct st_columndef /* column information */ typedef void (* invalidator_by_filename)(const char * filename); extern my_string myisam_log_filename; /* Name of logfile */ -extern uint myisam_block_size; +extern ulong myisam_block_size; +extern ulong myisam_concurrent_insert; extern my_bool myisam_flush,myisam_delay_key_write,myisam_single_user; -extern my_bool myisam_concurrent_insert; -extern my_off_t myisam_max_temp_length,myisam_max_extra_temp_length; +extern my_off_t myisam_max_temp_length; extern ulong myisam_bulk_insert_tree_size, myisam_data_pointer_size; /* Prototypes for myisam-functions */ diff --git a/include/mysql.h b/include/mysql.h index 24f1961a260..bcff8fa8645 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -384,6 +384,7 @@ unsigned int STDCALL mysql_warning_count(MYSQL *mysql); const char * STDCALL mysql_info(MYSQL *mysql); unsigned long STDCALL mysql_thread_id(MYSQL *mysql); const char * STDCALL mysql_character_set_name(MYSQL *mysql); +int STDCALL mysql_set_character_set(MYSQL *mysql, char *csname); MYSQL * STDCALL mysql_init(MYSQL *mysql); my_bool STDCALL mysql_ssl_set(MYSQL *mysql, const char *key, diff --git a/include/thr_lock.h b/include/thr_lock.h index 947b17bf2b6..dc4f9968cb7 100644 --- a/include/thr_lock.h +++ b/include/thr_lock.h @@ -88,10 +88,10 @@ typedef struct st_thr_lock { struct st_lock_list read; struct st_lock_list write_wait; struct st_lock_list write; -/* write_lock_count is incremented for write locks and reset on read locks */ + /* write_lock_count is incremented for write locks and reset on read locks */ ulong write_lock_count; uint read_no_write_count; - void (*get_status)(void*); /* When one gets a lock */ + void (*get_status)(void*, int); /* When one gets a lock */ void (*copy_status)(void*,void*); void (*update_status)(void*); /* Before release of write */ my_bool (*check_status)(void *); diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 7f78a5b723b..fd720046e31 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1885,10 +1885,18 @@ row_create_table_for_mysql( trx_general_rollback_for_mysql(trx, FALSE, NULL); if (err == DB_OUT_OF_FILE_SPACE) { - fputs("InnoDB: Warning: cannot create table ", stderr); + ut_print_timestamp(stderr); + + fputs(" InnoDB: Warning: cannot create table ", + stderr); ut_print_name(stderr, trx, table->name); fputs(" because tablespace full\n", stderr); - row_drop_table_for_mysql(table->name, trx, FALSE); + + if (dict_table_get_low(table->name)) { + + row_drop_table_for_mysql(table->name, trx, + FALSE); + } } else if (err == DB_DUPLICATE_KEY) { ut_print_timestamp(stderr); diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index 204c833dd21..bcd2ec6c057 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -67,7 +67,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ mf_iocache2.lo my_seek.lo my_sleep.lo \ my_pread.lo mf_cache.lo md5.lo sha1.lo \ my_getopt.lo my_gethostbyname.lo my_port.lo \ - my_rename.lo + my_rename.lo my_chsize.lo sqlobjects = net.lo sql_cmn_objects = pack.lo client.lo my_time.lo diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c index 90ad3aefaca..5d183b478ef 100644 --- a/libmysql/errmsg.c +++ b/libmysql/errmsg.c @@ -80,6 +80,7 @@ const char *client_errors[]= "Row retrieval was canceled by mysql_stmt_close() call", "Attempt to read column without prior row fetch", "Prepared statement contains no metadata", + "Attempt to read a row while there is no result set associated with the statement", "" }; @@ -141,6 +142,7 @@ const char *client_errors[]= "Row retrieval was canceled by mysql_stmt_close() call", "Attempt to read column without prior row fetch", "Prepared statement contains no metadata", + "Attempt to read a row while there is no result set associated with the statement", "" }; @@ -200,6 +202,7 @@ const char *client_errors[]= "Row retrieval was canceled by mysql_stmt_close() call", "Attempt to read column without prior row fetch", "Prepared statement contains no metadata", + "Attempt to read a row while there is no result set associated with the statement", "" }; #endif diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index bf797dfd580..f070d95780c 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -1495,6 +1495,36 @@ const char * STDCALL mysql_character_set_name(MYSQL *mysql) return mysql->charset->csname; } +int STDCALL mysql_set_character_set(MYSQL *mysql, char *cs_name) +{ + struct charset_info_st *cs; + const char *save_csdir = charsets_dir; + + if (mysql->options.charset_dir) + charsets_dir = mysql->options.charset_dir; + + if ( (cs = get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))) ) + { + char buff[MY_CS_NAME_SIZE + 10]; + charsets_dir = save_csdir; + sprintf(buff, "SET NAMES %s", cs_name); + if (!mysql_query(mysql, buff)) { + mysql->charset = cs; + } + } else { + char cs_dir_name[FN_REFLEN]; + get_charsets_dir(cs_dir_name); + mysql->net.last_errno=CR_CANT_READ_CHARSET; + strmov(mysql->net.sqlstate, unknown_sqlstate); + my_snprintf(mysql->net.last_error, sizeof(mysql->net.last_error)-1, + ER(mysql->net.last_errno), + cs_name, + cs_dir_name); + + } + charsets_dir = save_csdir; + return mysql->net.last_errno; +} uint STDCALL mysql_thread_safe(void) { @@ -1724,6 +1754,13 @@ static int stmt_read_row_no_data(MYSQL_STMT *stmt, unsigned char **row); static void stmt_update_metadata(MYSQL_STMT *stmt, MYSQL_ROWS *data); static my_bool setup_one_fetch_function(MYSQL_BIND *bind, MYSQL_FIELD *field); +/* Auxilary function used to reset statement handle. */ + +#define RESET_SERVER_SIDE 1 +#define RESET_LONG_DATA 2 + +static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags); + /* Maximum sizes of MYSQL_TYPE_DATE, MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME values stored in network buffer. @@ -2019,7 +2056,8 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) /* This is second prepare with another statement */ char buff[MYSQL_STMT_HEADER]; /* 4 bytes - stmt id */ - mysql_stmt_free_result(stmt); + if (reset_stmt_handle(stmt, RESET_LONG_DATA)) + DBUG_RETURN(1); /* These members must be reset for API to function in case of error or misuse. @@ -2702,12 +2740,8 @@ static int stmt_read_row_no_data(MYSQL_STMT *stmt __attribute__((unused)), unsigned char **row __attribute__((unused))) { - if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE) - { - set_stmt_error(stmt, CR_NO_PREPARE_STMT, unknown_sqlstate); - return 1; - } - return MYSQL_NO_DATA; + set_stmt_error(stmt, CR_NO_RESULT_SET, unknown_sqlstate); + return 1; } @@ -2817,7 +2851,8 @@ int STDCALL mysql_stmt_execute(MYSQL_STMT *stmt) DBUG_RETURN(1); } - mysql_stmt_free_result(stmt); + if (reset_stmt_handle(stmt, 0)) + DBUG_RETURN(1); /* No need to check for stmt->state: if the statement wasn't prepared we'll get 'unknown statement handler' error from server. @@ -4370,9 +4405,12 @@ my_bool STDCALL mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind) /* We only need to check that stmt->field_count - if it is not null stmt->bind was initialized in mysql_stmt_prepare - */ + stmt->bind overlaps with bind if mysql_stmt_bind_param + is called from mysql_stmt_store_result. + */ - memcpy((char*) stmt->bind, (char*) bind, sizeof(MYSQL_BIND) * bind_count); + if (stmt->bind != bind) + memcpy((char*) stmt->bind, (char*) bind, sizeof(MYSQL_BIND) * bind_count); for (param= stmt->bind, end= param + bind_count, field= stmt->fields ; param < end ; @@ -4805,16 +4843,21 @@ my_ulonglong STDCALL mysql_stmt_num_rows(MYSQL_STMT *stmt) DBUG_RETURN(stmt->result.rows); } -my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt) -{ - MYSQL_DATA *result= &stmt->result; - DBUG_ENTER("mysql_stmt_free_result"); - DBUG_ASSERT(stmt != 0); +/* + Free the client side memory buffers, reset long data state + on client if necessary, and reset the server side statement if + this has been requested. +*/ +static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags) +{ + /* If statement hasn't been prepared there is nothing to reset */ if ((int) stmt->state > (int) MYSQL_STMT_INIT_DONE) { MYSQL *mysql= stmt->mysql; + MYSQL_DATA *result= &stmt->result; + my_bool has_cursor= stmt->read_row_func == stmt_read_row_from_cursor; if (result->data) { @@ -4824,23 +4867,58 @@ my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt) result->rows= 0; stmt->data_cursor= NULL; } - - if (mysql && stmt->field_count && - (int) stmt->state > (int) MYSQL_STMT_PREPARE_DONE) + if (flags & RESET_LONG_DATA) { - if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled) - mysql->unbuffered_fetch_owner= 0; - if (mysql->status != MYSQL_STATUS_READY) + MYSQL_BIND *param= stmt->params, *param_end= param + stmt->param_count; + /* Clear long_data_used flags */ + for (; param < param_end; param++) + param->long_data_used= 0; + } + stmt->read_row_func= stmt_read_row_no_data; + if (mysql) + { + if ((int) stmt->state > (int) MYSQL_STMT_PREPARE_DONE) { - /* There is a result set and it belongs to this statement */ - (*mysql->methods->flush_use_result)(mysql); - mysql->status= MYSQL_STATUS_READY; + if (mysql->unbuffered_fetch_owner == &stmt->unbuffered_fetch_cancelled) + mysql->unbuffered_fetch_owner= 0; + if (stmt->field_count && mysql->status != MYSQL_STATUS_READY) + { + /* There is a result set and it belongs to this statement */ + (*mysql->methods->flush_use_result)(mysql); + if (mysql->unbuffered_fetch_owner) + *mysql->unbuffered_fetch_owner= TRUE; + mysql->status= MYSQL_STATUS_READY; + } + } + if (has_cursor || (flags & RESET_SERVER_SIDE)) + { + /* + Reset the server side statement and close the server side + cursor if it exists. + */ + char buff[MYSQL_STMT_HEADER]; /* packet header: 4 bytes for stmt id */ + int4store(buff, stmt->stmt_id); + if ((*mysql->methods->advanced_command)(mysql, COM_RESET_STMT, buff, + sizeof(buff), 0, 0, 0)) + { + set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, + mysql->net.sqlstate); + stmt->state= MYSQL_STMT_INIT_DONE; + return 1; + } } } stmt->state= MYSQL_STMT_PREPARE_DONE; - stmt->read_row_func= stmt_read_row_no_data; } - DBUG_RETURN(0); + return 0; +} + +my_bool STDCALL mysql_stmt_free_result(MYSQL_STMT *stmt) +{ + DBUG_ENTER("mysql_stmt_free_result"); + + /* Free the client side and close the server side cursor if there is one */ + DBUG_RETURN(reset_stmt_handle(stmt, RESET_LONG_DATA)); } /******************************************************************** @@ -4913,33 +4991,10 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) my_bool STDCALL mysql_stmt_reset(MYSQL_STMT *stmt) { - char buff[MYSQL_STMT_HEADER]; /* packet header: 4 bytes for stmt id */ - MYSQL *mysql; - MYSQL_BIND *param, *param_end; DBUG_ENTER("mysql_stmt_reset"); DBUG_ASSERT(stmt != 0); - - /* If statement hasnt been prepared there is nothing to reset */ - if ((int) stmt->state < (int) MYSQL_STMT_PREPARE_DONE) - DBUG_RETURN(0); - - mysql= stmt->mysql->last_used_con; - int4store(buff, stmt->stmt_id); /* Send stmt id to server */ - if ((*mysql->methods->advanced_command)(mysql, COM_RESET_STMT, buff, - sizeof(buff), 0, 0, 0)) - { - set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno, - mysql->net.sqlstate); - DBUG_RETURN(1); - } - - /* Clear long_data_used for next call (as we do in mysql_stmt_execute() */ - for (param= stmt->params, param_end= param + stmt->param_count; - param < param_end; - param++) - param->long_data_used= 0; - - DBUG_RETURN(0); + /* Reset the client and server sides of the prepared statement */ + DBUG_RETURN(reset_stmt_handle(stmt, RESET_SERVER_SIDE | RESET_LONG_DATA)); } /* diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 414ac4afd85..a597ee37682 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -148,6 +148,7 @@ EXPORTS mysql_embedded mysql_server_init mysql_server_end + mysql_set_character_set get_defaults_files get_charset_by_csname get_charsets_dir diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am index 5d3b365042f..6fc919c904f 100644 --- a/libmysqld/Makefile.am +++ b/libmysqld/Makefile.am @@ -87,6 +87,9 @@ INC_LIB= $(top_builddir)/regex/libregex.a \ # generate a total libmysqld.a from all library files, libmysqld.a: libmysqld_int.a $(INC_LIB) +if DARWIN_MWCC + mwld -lib -o $@ libmysqld_int.a `ls -1 $(INC_LIB) | sort -u` +else if test "$(host_os)" = "netware" ; \ then \ $(libmysqld_a_AR) libmysqld.a libmysqld_int.a $(INC_LIB) ; \ @@ -108,7 +111,7 @@ libmysqld.a: libmysqld_int.a $(INC_LIB) rm -f tmp/* ; \ $(RANLIB) libmysqld.a ; \ fi - +endif ## XXX: any time the client interface changes, we'll need to bump ## the version info for libmysqld; however, it's possible for the diff --git a/myisam/mi_create.c b/myisam/mi_create.c index 8635d6bcf36..12b03e65baa 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -191,11 +191,10 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, test(test_all_bits(options, HA_OPTION_CHECKSUM | HA_PACK_RECORD)); min_pack_length+=packed; - if (!ci->data_file_length) + if (!ci->data_file_length && ci->max_rows) { - if (ci->max_rows == 0 || pack_reclength == INT_MAX32) - ci->data_file_length= INT_MAX32-1; /* Should be enough */ - else if ((~(ulonglong) 0)/ci->max_rows < (ulonglong) pack_reclength) + if (pack_reclength == INT_MAX32 || + (~(ulonglong) 0)/ci->max_rows < (ulonglong) pack_reclength) ci->data_file_length= ~(ulonglong) 0; else ci->data_file_length=(ulonglong) ci->max_rows*pack_reclength; diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c index 3a4dafade23..8de500a7351 100644 --- a/myisam/mi_dynrec.c +++ b/myisam/mi_dynrec.c @@ -149,7 +149,9 @@ static int write_dynamic_record(MI_INFO *info, const byte *record, { if (_mi_find_writepos(info,reclength,&filepos,&length)) goto err; - if (_mi_write_part_record(info,filepos,length,info->s->state.dellink, + if (_mi_write_part_record(info,filepos,length, + (info->append_insert_at_end ? + HA_OFFSET_ERROR : info->s->state.dellink), (byte**) &record,&reclength,&flag)) goto err; } while (reclength); @@ -171,7 +173,8 @@ static int _mi_find_writepos(MI_INFO *info, ulong tmp; DBUG_ENTER("_mi_find_writepos"); - if (info->s->state.dellink != HA_OFFSET_ERROR) + if (info->s->state.dellink != HA_OFFSET_ERROR && + !info->append_insert_at_end) { /* Deleted blocks exists; Get last used block */ *filepos=info->s->state.dellink; @@ -420,8 +423,9 @@ int _mi_write_part_record(MI_INFO *info, else if (length-long_block < *reclength+4) { /* To short block */ if (next_filepos == HA_OFFSET_ERROR) - next_filepos=info->s->state.dellink != HA_OFFSET_ERROR ? - info->s->state.dellink : info->state->data_file_length; + next_filepos= (info->s->state.dellink != HA_OFFSET_ERROR && + !info->append_insert_at_end ? + info->s->state.dellink : info->state->data_file_length); if (*flag == 0) /* First block */ { if (*reclength > MI_MAX_BLOCK_LENGTH) diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c index 789d74680ef..8d48c5242e5 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -238,13 +238,24 @@ int mi_lock_database(MI_INFO *info, int lock_type) The following functions are called by thr_lock() in threaded applications ****************************************************************************/ -void mi_get_status(void* param) +/* + Create a copy of the current status for the table + + SYNOPSIS + mi_get_status() + param Pointer to Myisam handler + concurrent_insert Set to 1 if we are going to do concurrent inserts + (THR_WRITE_CONCURRENT_INSERT was used) +*/ + +void mi_get_status(void* param, int concurrent_insert) { MI_INFO *info=(MI_INFO*) param; DBUG_ENTER("mi_get_status"); - DBUG_PRINT("info",("key_file: %ld data_file: %ld", + DBUG_PRINT("info",("key_file: %ld data_file: %ld concurrent_insert: %d", (long) info->s->state.state.key_file_length, - (long) info->s->state.state.data_file_length)); + (long) info->s->state.state.data_file_length, + concurrent_insert)); #ifndef DBUG_OFF if (info->state->key_file_length > info->s->state.state.key_file_length || info->state->data_file_length > info->s->state.state.data_file_length) @@ -254,9 +265,11 @@ void mi_get_status(void* param) #endif info->save_state=info->s->state.state; info->state= &info->save_state; + info->append_insert_at_end= concurrent_insert; DBUG_VOID_RETURN; } + void mi_update_status(void* param) { MI_INFO *info=(MI_INFO*) param; @@ -281,6 +294,7 @@ void mi_update_status(void* param) info->s->state.state= *info->state; info->state= &info->s->state.state; } + info->append_insert_at_end= 0; /* We have to flush the write cache here as other threads may start @@ -307,20 +321,37 @@ void mi_copy_status(void* to,void *from) Check if should allow concurrent inserts IMPLEMENTATION - Don't allow concurrent inserts if we have a hole in the table. + Allow concurrent inserts if we don't have a hole in the table or + if there is no active write lock and there is active read locks and + myisam_concurrent_insert == 2. In this last case the new + row('s) are inserted at end of file instead of filling up the hole. + + The last case is to allow one to inserts into a heavily read-used table + even if there is holes. NOTES - Rtree indexes are disabled in mi_open() + If there is a an rtree indexes in the table, concurrent inserts are + disabled in mi_open() RETURN 0 ok to use concurrent inserts 1 not ok */ -my_bool mi_check_status(void* param) +my_bool mi_check_status(void *param) { MI_INFO *info=(MI_INFO*) param; - return (my_bool) (info->s->state.dellink != HA_OFFSET_ERROR); + /* + The test for w_locks == 1 is here because this thread has already done an + external lock (in other words: w_locks == 1 means no other threads has + a write lock) + */ + DBUG_PRINT("info",("dellink: %ld r_locks: %u w_locks: %u", + (long) info->s->state.dellink, (uint) info->s->r_locks, + (uint) info->s->w_locks)); + return (my_bool) !(info->s->state.dellink == HA_OFFSET_ERROR || + (myisam_concurrent_insert == 2 && info->s->r_locks && + info->s->w_locks == 1)); } diff --git a/myisam/mi_static.c b/myisam/mi_static.c index f41aeff8453..4c9d814f7d6 100644 --- a/myisam/mi_static.c +++ b/myisam/mi_static.c @@ -31,14 +31,13 @@ uchar NEAR myisam_pack_file_magic[]= my_string myisam_log_filename=(char*) "myisam.log"; File myisam_log_file= -1; uint myisam_quick_table_bits=9; -uint myisam_block_size=MI_KEY_BLOCK_LENGTH; /* Best by test */ +ulong myisam_block_size= MI_KEY_BLOCK_LENGTH; /* Best by test */ my_bool myisam_flush=0, myisam_delay_key_write=0, myisam_single_user=0; #if defined(THREAD) && !defined(DONT_USE_RW_LOCKS) -my_bool myisam_concurrent_insert=1; +ulong myisam_concurrent_insert= 2; #else -my_bool myisam_concurrent_insert=0; +ulong myisam_concurrent_insert= 0; #endif -my_off_t myisam_max_extra_temp_length= (my_off_t)MI_MAX_TEMP_LENGTH; my_off_t myisam_max_temp_length= MAX_FILE_SIZE; ulong myisam_bulk_insert_tree_size=8192*1024; ulong myisam_data_pointer_size=4; diff --git a/myisam/mi_statrec.c b/myisam/mi_statrec.c index 8f5cde45e24..42352f63c66 100644 --- a/myisam/mi_statrec.c +++ b/myisam/mi_statrec.c @@ -23,7 +23,8 @@ int _mi_write_static_record(MI_INFO *info, const byte *record) { uchar temp[8]; /* max pointer length */ - if (info->s->state.dellink != HA_OFFSET_ERROR) + if (info->s->state.dellink != HA_OFFSET_ERROR && + !info->append_insert_at_end) { my_off_t filepos=info->s->state.dellink; info->rec_cache.seek_not_done=1; /* We have done a seek */ diff --git a/myisam/mi_write.c b/myisam/mi_write.c index 5d7e245c58f..dd062b79769 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -67,7 +67,8 @@ int mi_write(MI_INFO *info, byte *record) MYF(MY_SEEK_NOT_DONE) | info->lock_wait)) goto err; #endif - filepos= ((share->state.dellink != HA_OFFSET_ERROR) ? + filepos= ((share->state.dellink != HA_OFFSET_ERROR && + !info->append_insert_at_end) ? share->state.dellink : info->state->data_file_length); diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index a2d3dedf6df..5688b377d3d 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -271,6 +271,7 @@ struct st_myisam_info { uint preload_buff_size; /* When preloading indexes */ myf lock_wait; /* is 0 or MY_DONT_WAIT */ my_bool was_locked; /* Was locked in panic */ + my_bool append_insert_at_end; /* Set if concurrent insert */ my_bool quick_mode; my_bool page_changed; /* If info->buff can't be used for rnext */ my_bool buff_used; /* If info->buff has to be reread for rnext */ @@ -702,7 +703,7 @@ int _mi_cmp_dynamic_unique(MI_INFO *info, MI_UNIQUEDEF *def, const byte *record, my_off_t pos); int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b, my_bool null_are_equal); -void mi_get_status(void* param); +void mi_get_status(void* param, int concurrent_insert); void mi_update_status(void* param); void mi_copy_status(void* to,void *from); my_bool mi_check_status(void* param); diff --git a/mysql-test/lib/init_db.sql b/mysql-test/lib/init_db.sql index 97fa6fb955c..18699497b64 100644 --- a/mysql-test/lib/init_db.sql +++ b/mysql-test/lib/init_db.sql @@ -1,4 +1,5 @@ -USE mysql; +use mysql; +set table_type=myisam; CREATE TABLE db ( Host char(60) binary DEFAULT '' NOT NULL, @@ -206,7 +207,7 @@ INSERT INTO time_zone_name (Name, Time_Zone_id) VALUES CREATE TABLE time_zone ( Time_zone_id int unsigned NOT NULL auto_increment, - Use_leap_seconds enum('Y','N') DEFAULT 'N' NOT NULL, + Use_leap_seconds enum('Y','N') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY TzId (Time_zone_id) ) engine=MyISAM CHARACTER SET utf8 diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index 8aefc235d72..78758e54aa4 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -344,7 +344,7 @@ sub mtr_kill_leftovers () { # We scan the "var/run/" directory for other process id's to kill # FIXME $path_run_dir or something - my $rundir= "$::glob_mysql_test_dir/var/run"; + my $rundir= "$::opt_vardir/run"; if ( -d $rundir ) { diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index fd665b154b8..cb41549422f 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -89,9 +89,10 @@ sub mtr_report_test_passed ($) { my $tinfo= shift; my $timer= ""; - if ( $::opt_timer and -f "$::glob_mysql_test_dir/var/log/timer" ) + if ( $::opt_timer and -f "$::opt_vardir/log/timer" ) { - $timer= mtr_fromfile("$::glob_mysql_test_dir/var/log/timer"); + $timer= mtr_fromfile("$::opt_vardir/log/timer"); + $::glob_tot_real_time += $timer; $timer= sprintf "%12s", $timer; } $tinfo->{'result'}= 'MTR_RES_PASSED'; @@ -177,8 +178,8 @@ sub mtr_report_stats ($) { # Report if there was any fatal warnings/errors in the log files # - unlink("$::glob_mysql_test_dir/var/log/warnings"); - unlink("$::glob_mysql_test_dir/var/log/warnings.tmp"); + unlink("$::opt_vardir/log/warnings"); + unlink("$::opt_vardir/log/warnings.tmp"); # Remove some non fatal warnings from the log files # FIXME what is going on ????? ;-) @@ -196,11 +197,11 @@ sub mtr_report_stats ($) { # found_error=1 # } # done -# unlink("$::glob_mysql_test_dir/var/log/warnings.tmp"); +# unlink("$::opt_vardir/log/warnings.tmp"); # if ( $found_error= "1" ) # { # print "WARNING: Got errors/warnings while running tests. Please examine\n" -# print "$::glob_mysql_test_dir/var/log/warnings for details.\n" +# print "$::opt_vardir/log/warnings for details.\n" # } # } } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index ae4136b5494..52ffff088b5 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -84,7 +84,7 @@ use Sys::Hostname; #use Carp; use IO::Socket; use IO::Socket::INET; -#use Data::Dumper; +use Data::Dumper; use strict; #use diagnostics; @@ -177,6 +177,7 @@ our $path_timefile; our $path_manager_log; # Used by mysqldadmin our $path_slave_load_tmpdir; # What is this?! our $path_my_basedir; +our $opt_vardir; # A path but set directly on cmd line our $opt_tmpdir; # A path but set directly on cmd line our $opt_usage; @@ -447,8 +448,6 @@ sub initial_setup () { $glob_basedir= dirname($glob_mysql_test_dir); $glob_mysql_bench_dir= "$glob_basedir/mysql-bench"; # FIXME make configurable - $path_timefile= "$glob_mysql_test_dir/var/log/mysqltest-time"; - # needs to be same length to test logging (FIXME what???) $path_slave_load_tmpdir= "../../var/tmp"; @@ -469,11 +468,6 @@ sub command_line_setup () { # These are defaults for things that are set on the command line $opt_suite= "main"; # Special default suite - $opt_tmpdir= "$glob_mysql_test_dir/var/tmp"; - # FIXME maybe unneded? - $path_manager_log= "$glob_mysql_test_dir/var/log/manager.log"; - $opt_current_test= "$glob_mysql_test_dir/var/log/current_test"; - my $opt_master_myport= 9306; my $opt_slave_myport= 9308; $opt_ndbcluster_port= 9350; @@ -549,6 +543,7 @@ sub command_line_setup () { 'unified-diff|udiff' => \$opt_udiff, 'user-test=s' => \$opt_user_test, 'user=s' => \$opt_user, + 'vardir=s' => \$opt_vardir, 'verbose' => \$opt_verbose, 'wait-timeout=i' => \$opt_wait_timeout, 'warnings|log-warnings' => \$opt_warnings, @@ -564,51 +559,35 @@ sub command_line_setup () { @opt_cases= @ARGV; - # Put this into a hash, will be a C struct - - $master->[0]->{'path_myddir'}= "$glob_mysql_test_dir/var/master-data"; - $master->[0]->{'path_myerr'}= "$glob_mysql_test_dir/var/log/master.err"; - $master->[0]->{'path_mylog'}= "$glob_mysql_test_dir/var/log/master.log"; - $master->[0]->{'path_mypid'}= "$glob_mysql_test_dir/var/run/master.pid"; - $master->[0]->{'path_mysock'}= "$opt_tmpdir/master.sock"; - $master->[0]->{'path_myport'}= $opt_master_myport; - $master->[0]->{'start_timeout'}= 400; # enough time create innodb tables - - $master->[0]->{'ndbcluster'}= 1; # ndbcluster not started + # -------------------------------------------------------------------------- + # Set the "var/" directory, as it is the base for everything else + # -------------------------------------------------------------------------- - $master->[1]->{'path_myddir'}= "$glob_mysql_test_dir/var/master1-data"; - $master->[1]->{'path_myerr'}= "$glob_mysql_test_dir/var/log/master1.err"; - $master->[1]->{'path_mylog'}= "$glob_mysql_test_dir/var/log/master1.log"; - $master->[1]->{'path_mypid'}= "$glob_mysql_test_dir/var/run/master1.pid"; - $master->[1]->{'path_mysock'}= "$opt_tmpdir/master1.sock"; - $master->[1]->{'path_myport'}= $opt_master_myport + 1; - $master->[1]->{'start_timeout'}= 400; # enough time create innodb tables + if ( ! $opt_vardir ) + { + $opt_vardir= "$glob_mysql_test_dir/var"; + } - $slave->[0]->{'path_myddir'}= "$glob_mysql_test_dir/var/slave-data"; - $slave->[0]->{'path_myerr'}= "$glob_mysql_test_dir/var/log/slave.err"; - $slave->[0]->{'path_mylog'}= "$glob_mysql_test_dir/var/log/slave.log"; - $slave->[0]->{'path_mypid'}= "$glob_mysql_test_dir/var/run/slave.pid"; - $slave->[0]->{'path_mysock'}= "$opt_tmpdir/slave.sock"; - $slave->[0]->{'path_myport'}= $opt_slave_myport; - $slave->[0]->{'start_timeout'}= 400; + if ( $opt_vardir !~ m,^/, ) + { + # Make absolute path, relative test dir + $opt_vardir= "$glob_mysql_test_dir/$opt_vardir"; + } - $slave->[1]->{'path_myddir'}= "$glob_mysql_test_dir/var/slave1-data"; - $slave->[1]->{'path_myerr'}= "$glob_mysql_test_dir/var/log/slave1.err"; - $slave->[1]->{'path_mylog'}= "$glob_mysql_test_dir/var/log/slave1.log"; - $slave->[1]->{'path_mypid'}= "$glob_mysql_test_dir/var/run/slave1.pid"; - $slave->[1]->{'path_mysock'}= "$opt_tmpdir/slave1.sock"; - $slave->[1]->{'path_myport'}= $opt_slave_myport + 1; - $slave->[1]->{'start_timeout'}= 300; + # -------------------------------------------------------------------------- + # If not set, set these to defaults + # -------------------------------------------------------------------------- - $slave->[2]->{'path_myddir'}= "$glob_mysql_test_dir/var/slave2-data"; - $slave->[2]->{'path_myerr'}= "$glob_mysql_test_dir/var/log/slave2.err"; - $slave->[2]->{'path_mylog'}= "$glob_mysql_test_dir/var/log/slave2.log"; - $slave->[2]->{'path_mypid'}= "$glob_mysql_test_dir/var/run/slave2.pid"; - $slave->[2]->{'path_mysock'}= "$opt_tmpdir/slave2.sock"; - $slave->[2]->{'path_myport'}= $opt_slave_myport + 2; - $slave->[2]->{'start_timeout'}= 300; + $opt_tmpdir= "$opt_vardir/tmp" unless $opt_tmpdir; + # FIXME maybe not needed? + $path_manager_log= "$opt_vardir/log/manager.log" + unless $path_manager_log; + $opt_current_test= "$opt_vardir/log/current_test" + unless $opt_current_test; + # -------------------------------------------------------------------------- # Do sanity checks of command line arguments + # -------------------------------------------------------------------------- if ( $opt_extern and $opt_local ) { @@ -621,13 +600,6 @@ sub command_line_setup () { $opt_socket= "/tmp/mysql.sock"; # FIXME } - if ( $opt_extern ) - { - $glob_use_running_server= 1; - $opt_skip_rpl= 1; # We don't run rpl test cases - $master->[0]->{'path_mysock'}= $opt_socket; - } - # -------------------------------------------------------------------------- # Look at the command line options and set script flags # -------------------------------------------------------------------------- @@ -746,6 +718,58 @@ sub command_line_setup () { } } + # Put this into a hash, will be a C struct + + $master->[0]->{'path_myddir'}= "$opt_vardir/master-data"; + $master->[0]->{'path_myerr'}= "$opt_vardir/log/master.err"; + $master->[0]->{'path_mylog'}= "$opt_vardir/log/master.log"; + $master->[0]->{'path_mypid'}= "$opt_vardir/run/master.pid"; + $master->[0]->{'path_mysock'}= "$opt_tmpdir/master.sock"; + $master->[0]->{'path_myport'}= $opt_master_myport; + $master->[0]->{'start_timeout'}= 400; # enough time create innodb tables + + $master->[0]->{'ndbcluster'}= 1; # ndbcluster not started + + $master->[1]->{'path_myddir'}= "$opt_vardir/master1-data"; + $master->[1]->{'path_myerr'}= "$opt_vardir/log/master1.err"; + $master->[1]->{'path_mylog'}= "$opt_vardir/log/master1.log"; + $master->[1]->{'path_mypid'}= "$opt_vardir/run/master1.pid"; + $master->[1]->{'path_mysock'}= "$opt_tmpdir/master1.sock"; + $master->[1]->{'path_myport'}= $opt_master_myport + 1; + $master->[1]->{'start_timeout'}= 400; # enough time create innodb tables + + $slave->[0]->{'path_myddir'}= "$opt_vardir/slave-data"; + $slave->[0]->{'path_myerr'}= "$opt_vardir/log/slave.err"; + $slave->[0]->{'path_mylog'}= "$opt_vardir/log/slave.log"; + $slave->[0]->{'path_mypid'}= "$opt_vardir/run/slave.pid"; + $slave->[0]->{'path_mysock'}= "$opt_tmpdir/slave.sock"; + $slave->[0]->{'path_myport'}= $opt_slave_myport; + $slave->[0]->{'start_timeout'}= 400; + + $slave->[1]->{'path_myddir'}= "$opt_vardir/slave1-data"; + $slave->[1]->{'path_myerr'}= "$opt_vardir/log/slave1.err"; + $slave->[1]->{'path_mylog'}= "$opt_vardir/log/slave1.log"; + $slave->[1]->{'path_mypid'}= "$opt_vardir/run/slave1.pid"; + $slave->[1]->{'path_mysock'}= "$opt_tmpdir/slave1.sock"; + $slave->[1]->{'path_myport'}= $opt_slave_myport + 1; + $slave->[1]->{'start_timeout'}= 300; + + $slave->[2]->{'path_myddir'}= "$opt_vardir/slave2-data"; + $slave->[2]->{'path_myerr'}= "$opt_vardir/log/slave2.err"; + $slave->[2]->{'path_mylog'}= "$opt_vardir/log/slave2.log"; + $slave->[2]->{'path_mypid'}= "$opt_vardir/run/slave2.pid"; + $slave->[2]->{'path_mysock'}= "$opt_tmpdir/slave2.sock"; + $slave->[2]->{'path_myport'}= $opt_slave_myport + 2; + $slave->[2]->{'start_timeout'}= 300; + + if ( $opt_extern ) + { + $glob_use_running_server= 1; + $opt_skip_rpl= 1; # We don't run rpl test cases + $master->[0]->{'path_mysock'}= $opt_socket; + } + + $path_timefile= "$opt_vardir/log/mysqltest-time"; } @@ -892,8 +916,8 @@ sub executable_setup () { } $path_ndb_backup_dir= - "$glob_mysql_test_dir/var/ndbcluster-$opt_ndbcluster_port"; - $file_ndb_testrun_log= "$glob_mysql_test_dir/var/log/ndb_testrun.log"; + "$opt_vardir/ndbcluster-$opt_ndbcluster_port"; + $file_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log"; } @@ -981,7 +1005,7 @@ sub kill_running_server () { # leftovers from previous runs. mtr_report("Killing Possible Leftover Processes"); - mkpath("$glob_mysql_test_dir/var/log"); # Needed for mysqladmin log + mkpath("$opt_vardir/log"); # Needed for mysqladmin log mtr_kill_leftovers(); ndbcluster_stop(); @@ -995,15 +1019,20 @@ sub kill_and_cleanup () { mtr_report("Removing Stale Files"); - rmtree("$glob_mysql_test_dir/var/log"); - rmtree("$glob_mysql_test_dir/var/ndbcluster-$opt_ndbcluster_port"); - rmtree("$glob_mysql_test_dir/var/run"); - rmtree("$glob_mysql_test_dir/var/tmp"); + if ( -l $opt_vardir and ! unlink($opt_vardir) ) + { + mtr_error("Can't remove soft link \"$opt_vardir\""); + } + + rmtree("$opt_vardir/log"); + rmtree("$opt_vardir/ndbcluster-$opt_ndbcluster_port"); + rmtree("$opt_vardir/run"); + rmtree("$opt_vardir/tmp"); - mkpath("$glob_mysql_test_dir/var/log"); - mkpath("$glob_mysql_test_dir/var/run"); - mkpath("$glob_mysql_test_dir/var/tmp"); - mkpath($opt_tmpdir); + mkpath("$opt_vardir/log"); + mkpath("$opt_vardir/run"); + mkpath("$opt_vardir/tmp"); + mkpath($opt_tmpdir) if $opt_tmpdir ne "$opt_vardir/tmp"; # FIXME do we really need to create these all, or are they # created for us when tables are created? @@ -1027,6 +1056,16 @@ sub kill_and_cleanup () { rmtree("$slave->[2]->{'path_myddir'}"); mkpath("$slave->[2]->{'path_myddir'}/mysql"); mkpath("$slave->[2]->{'path_myddir'}/test"); + + # To make some old test cases work, we create a soft + # link from the old "var" location to the new one + + if ( ! $glob_win32 and $opt_vardir ne "$glob_mysql_test_dir/var" ) + { + # FIXME why bother with the above, why not always remove all of var?! + rmtree("$glob_mysql_test_dir/var"); # Clean old var, FIXME or rename it?! + symlink($opt_vardir, "$glob_mysql_test_dir/var"); + } } @@ -1048,7 +1087,7 @@ sub ndbcluster_install () { my $ndbcluster_opts= $opt_bench ? "" : "--small"; if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", ["--port=$opt_ndbcluster_port", - "--data-dir=$glob_mysql_test_dir/var", + "--data-dir=$opt_vardir", $ndbcluster_opts, "--initial"], "", "", "", "") ) @@ -1072,7 +1111,7 @@ sub ndbcluster_start () { # FIXME, we want to _append_ output to file $file_ndb_testrun_log instead of /dev/null if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", ["--port=$opt_ndbcluster_port", - "--data-dir=$glob_mysql_test_dir/var"], + "--data-dir=$opt_vardir"], "", "/dev/null", "", "") ) { mtr_error("Error ndbcluster_start"); @@ -1091,7 +1130,7 @@ sub ndbcluster_stop () { # FIXME, we want to _append_ output to file $file_ndb_testrun_log instead of /dev/null mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", ["--port=$opt_ndbcluster_port", - "--data-dir=$glob_mysql_test_dir/var", + "--data-dir=$opt_vardir", "--stop"], "", "/dev/null", "", ""); @@ -1494,15 +1533,15 @@ sub run_testcase ($) { { mtr_report_test_passed($tinfo); } - elsif ( $res == 2 ) + elsif ( $res == 62 ) { # Testcase itself tell us to skip this one mtr_report_test_skipped($tinfo); } else { - # Test case failed - if ( $res > 2 ) + # Test case failed, if in control mysqltest returns 1 + if ( $res != 1 ) { mtr_tofile($path_timefile, "mysqltest returned unexpected code $res, " . @@ -1563,17 +1602,17 @@ sub do_before_start_master ($$) { $tname ne "rpl_crash_binlog_ib_3b") { # FIXME we really want separate dir for binlogs - foreach my $bin ( glob("$glob_mysql_test_dir/var/log/master*-bin.*") ) + foreach my $bin ( glob("$opt_vardir/log/master*-bin.*") ) { unlink($bin); } } # Remove old master.info and relay-log.info files - unlink("$glob_mysql_test_dir/var/master-data/master.info"); - unlink("$glob_mysql_test_dir/var/master-data/relay-log.info"); - unlink("$glob_mysql_test_dir/var/master1-data/master.info"); - unlink("$glob_mysql_test_dir/var/master1-data/relay-log.info"); + unlink("$opt_vardir/master-data/master.info"); + unlink("$opt_vardir/master-data/relay-log.info"); + unlink("$opt_vardir/master1-data/master.info"); + unlink("$opt_vardir/master1-data/relay-log.info"); # Run master initialization shell script if one exists if ( $init_script ) @@ -1600,13 +1639,13 @@ sub do_before_start_slave ($$) { $tname ne "rpl_crash_binlog_ib_3b" ) { # FIXME we really want separate dir for binlogs - foreach my $bin ( glob("$glob_mysql_test_dir/var/log/slave*-bin.*") ) + foreach my $bin ( glob("$opt_vardir/log/slave*-bin.*") ) { unlink($bin); } # FIXME really master?! - unlink("$glob_mysql_test_dir/var/slave-data/master.info"); - unlink("$glob_mysql_test_dir/var/slave-data/relay-log.info"); + unlink("$opt_vardir/slave-data/master.info"); + unlink("$opt_vardir/slave-data/relay-log.info"); } # Run slave initialization shell script if one exists @@ -1620,8 +1659,8 @@ sub do_before_start_slave ($$) { } } - `rm -f $glob_mysql_test_dir/var/slave-data/log.*`; -# unlink("$glob_mysql_test_dir/var/slave-data/log.*"); + `rm -f $opt_vardir/slave-data/log.*`; +# unlink("$opt_vardir/slave-data/log.*"); } sub mysqld_arguments ($$$$$) { @@ -1667,8 +1706,7 @@ sub mysqld_arguments ($$$$$) { if ( $type eq 'master' ) { - mtr_add_arg($args, "%s--log-bin=%s/var/log/master-bin", $prefix, - $glob_mysql_test_dir); + mtr_add_arg($args, "%s--log-bin=%s/log/master-bin", $prefix, $opt_vardir); mtr_add_arg($args, "%s--pid-file=%s", $prefix, $master->[$idx]->{'path_mypid'}); mtr_add_arg($args, "%s--port=%d", $prefix, @@ -1692,8 +1730,8 @@ sub mysqld_arguments ($$$$$) { # FIXME slave get this option twice?! mtr_add_arg($args, "%s--exit-info=256", $prefix); mtr_add_arg($args, "%s--init-rpl-role=slave", $prefix); - mtr_add_arg($args, "%s--log-bin=%s/var/log/slave%s-bin", $prefix, - $glob_mysql_test_dir, $sidx); # FIXME use own dir for binlogs + mtr_add_arg($args, "%s--log-bin=%s/log/slave%s-bin", $prefix, + $opt_vardir, $sidx); # FIXME use own dir for binlogs mtr_add_arg($args, "%s--log-slave-updates", $prefix); # FIXME option duplicated for slave mtr_add_arg($args, "%s--log=%s", $prefix, @@ -1703,8 +1741,8 @@ sub mysqld_arguments ($$$$$) { $slave->[$idx]->{'path_mypid'}); mtr_add_arg($args, "%s--port=%d", $prefix, $slave->[$idx]->{'path_myport'}); - mtr_add_arg($args, "%s--relay-log=%s/var/log/slave%s-relay-bin", $prefix, - $glob_mysql_test_dir, $sidx); + mtr_add_arg($args, "%s--relay-log=%s/log/slave%s-relay-bin", $prefix, + $opt_vardir, $sidx); mtr_add_arg($args, "%s--report-host=127.0.0.1", $prefix); mtr_add_arg($args, "%s--report-port=%d", $prefix, $slave->[$idx]->{'path_myport'}); @@ -1742,13 +1780,13 @@ sub mysqld_arguments ($$$$$) { { if ( $type eq 'master' ) { - mtr_add_arg($args, "%s--debug=d:t:i:A,%s/var/log/master%s.trace", - $prefix, $glob_mysql_test_dir, $sidx); + mtr_add_arg($args, "%s--debug=d:t:i:A,%s/log/master%s.trace", + $prefix, $opt_vardir, $sidx); } if ( $type eq 'slave' ) { - mtr_add_arg($args, "%s--debug=d:t:i:A,%s/var/log/slave%s.trace", - $prefix, $glob_mysql_test_dir, $sidx); + mtr_add_arg($args, "%s--debug=d:t:i:A,%s/log/slave%s.trace", + $prefix, $opt_vardir, $sidx); } } @@ -2000,7 +2038,7 @@ sub run_mysqltest ($$) { if ( $opt_debug ) { $cmdline_mysqldump .= - " --debug=d:t:A,$glob_mysql_test_dir/var/log/mysqldump.trace"; + " --debug=d:t:A,$opt_vardir/log/mysqldump.trace"; } my $cmdline_mysqlbinlog= @@ -2009,7 +2047,7 @@ sub run_mysqltest ($$) { if ( $opt_debug ) { $cmdline_mysqlbinlog .= - " --debug=d:t:A,$glob_mysql_test_dir/var/log/mysqlbinlog.trace"; + " --debug=d:t:A,$opt_vardir/log/mysqlbinlog.trace"; } my $cmdline_mysql= @@ -2072,13 +2110,13 @@ sub run_mysqltest ($$) { { $exe= "strace"; # FIXME there are ktrace, .... mtr_add_arg($args, "-o"); - mtr_add_arg($args, "%s/var/log/mysqltest.strace", $glob_mysql_test_dir); + mtr_add_arg($args, "%s/log/mysqltest.strace", $opt_vardir); mtr_add_arg($args, "$exe_mysqltest"); } if ( $opt_timer ) { - mtr_add_arg($args, "--timer-file=%s/var/log/timer", $glob_mysql_test_dir); + mtr_add_arg($args, "--timer-file=%s/log/timer", $opt_vardir); } if ( $opt_big_test ) @@ -2103,8 +2141,7 @@ sub run_mysqltest ($$) { if ( $opt_debug ) { - mtr_add_arg($args, "--debug=d:t:A,%s/var/log/mysqltest.trace", - $glob_mysql_test_dir); + mtr_add_arg($args, "--debug=d:t:A,%s/log/mysqltest.trace", $opt_vardir); } if ( $opt_with_openssl ) @@ -2126,7 +2163,7 @@ sub run_mysqltest ($$) { mysqld_arguments($args,'master',0,$tinfo->{'master_opt'},[]); } - return mtr_run_test($exe_mysqltest,$args,$tinfo->{'path'},"",$path_timefile,""); + return mtr_run_test($exe,$args,$tinfo->{'path'},"",$path_timefile,""); } ############################################################################## diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 1a648f98b1b..967d6e6408e 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -586,10 +586,7 @@ if [ x$SOURCE_DIST = x1 ] ; then NDB_MGM="$BASEDIR/ndb/src/mgmclient/ndb_mgm" if [ -n "$USE_PURIFY" ] ; then - PSUP="$MYSQL_TEST_DIR/purify.suppress" - echo "suppress UMR rw_read_held; mi_open; ha_myisam::open64; handler::ha_open; openfrm" > $PSUP - echo "suppress UMR my_end; main" >> $PSUP - echo "suppress UMR _doprnt; fprintf; my_end; main" >> $PSUP + PSUP="$MYSQL_TEST_DIR/suppress.purify" PURIFYOPTIONS="-windows=no -log-file=%v.purifylog -append-logfile -add-suppression-files=$PSUP" if [ -f "${MYSQL_TEST}-purify" ] ; then MYSQL_TEST="${MYSQL_TEST}-purify" @@ -1705,11 +1702,11 @@ run_testcase () $ECHO "$RES$RES_SPACE [ pass ] $TIMER" else # why the following ``if'' ? That is why res==1 is special ? - if [ $res = 2 ]; then + if [ $res = 62 ]; then skip_inc $ECHO "$RES$RES_SPACE [ skipped ]" else - if [ $res -gt 2 ]; then + if [ $res -ne 1 ]; then $ECHO "mysqltest returned unexpected code $res, it has probably crashed" >> $TIMEFILE fi total_inc diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index b251044d48b..338fc429090 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -606,6 +606,24 @@ ucs2_bin 00610009 ucs2_bin 0061 ucs2_bin 00610020 drop table t1; +select hex(substr(_ucs2 0x00e400e50068,1)); +hex(substr(_ucs2 0x00e400e50068,1)) +00E400E50068 +select hex(substr(_ucs2 0x00e400e50068,2)); +hex(substr(_ucs2 0x00e400e50068,2)) +00E50068 +select hex(substr(_ucs2 0x00e400e50068,3)); +hex(substr(_ucs2 0x00e400e50068,3)) +0068 +select hex(substr(_ucs2 0x00e400e50068,-1)); +hex(substr(_ucs2 0x00e400e50068,-1)) +0068 +select hex(substr(_ucs2 0x00e400e50068,-2)); +hex(substr(_ucs2 0x00e400e50068,-2)) +00E50068 +select hex(substr(_ucs2 0x00e400e50068,-3)); +hex(substr(_ucs2 0x00e400e50068,-3)) +00E400E50068 SET NAMES latin1; SET collation_connection='ucs2_swedish_ci'; CREATE TABLE t1 (Field1 int(10) default '0'); diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 490cde82ca3..8ab24fe550b 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -817,6 +817,9 @@ drop table t1; select 'c' like '\_' as want0; want0 0 +SELECT SUBSTR('ваÑÑ',-2); +SUBSTR('ваÑÑ',-2) +ÑÑ create table t1 (id integer, a varchar(100) character set utf8 collate utf8_unicode_ci); insert into t1 values (1, 'Test'); select * from t1 where soundex(a) = soundex('Test'); diff --git a/mysql-test/r/gis-rtree.result b/mysql-test/r/gis-rtree.result index 73cde35993e..22447e829a9 100644 --- a/mysql-test/r/gis-rtree.result +++ b/mysql-test/r/gis-rtree.result @@ -167,7 +167,7 @@ count(*) 150 EXPLAIN SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))')); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range g g 32 NULL 7 Using where +1 SIMPLE t1 range g g 32 NULL 8 Using where SELECT fid, AsText(g) FROM t1 WHERE Within(g, GeomFromText('Polygon((140 140,160 140,160 160,140 160,140 140))')); fid AsText(g) 1 LINESTRING(150 150,150 150) diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index 3037047b513..c03d4125018 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -287,7 +287,7 @@ b i421 l421 b m422 p422 explain select a1,a2,b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 9 Using where; Using index for group-by +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 10 Using where; Using index for group-by explain select a1,a2,b,min(c),max(c) from t1 where a1 >= 'b' group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 Using where; Using index for group-by @@ -317,22 +317,22 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 Using where; Using index for group-by explain select a1, max(c) from t1 where a1 in ('a','b','d') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 13 Using where; Using index for group-by +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 Using where; Using index for group-by explain select a1,a2,b, max(c) from t2 where a1 < 'd' group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 12 Using where; Using index for group-by +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 14 Using where; Using index for group-by explain select a1,a2,b,min(c),max(c) from t2 where a1 < 'd' group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 12 Using where; Using index for group-by +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 14 Using where; Using index for group-by explain select a1,a2,b,min(c),max(c) from t2 where a1 >= 'b' group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 16 Using where; Using index for group-by explain select a1,a2,b, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 18 Using where; Using index for group-by +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 17 Using where; Using index for group-by explain select a1, max(c) from t2 where a1 >= 'c' or a1 < 'b' group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 18 Using where; Using index for group-by +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 17 Using where; Using index for group-by explain select a1,a2,b,min(c),max(c) from t2 where a1 >= 'c' or a2 < 'b' group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 21 Using where; Using index for group-by @@ -353,7 +353,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 16 Using where; Using index for group-by explain select a1, max(c) from t2 where a1 in ('a','b','d') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 13 Using where; Using index for group-by +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 14 Using where; Using index for group-by select a1,a2,b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b; a1 a2 b min(c) max(c) a a a a111 d111 @@ -1398,10 +1398,10 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range NULL idx_t2_1 163 NULL 21 Using where; Using index for group-by explain select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c < 'h112') or (c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122')) group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 17 Using where; Using index for group-by +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 16 Using where; Using index for group-by explain select a1,a2,b,min(c) from t2 where ((a1 > 'a') or (a1 < '9')) and ((a2 >= 'b') and (a2 < 'z')) and (b = 'a') and ((c = 'j121') or (c > 'k121' and c < 'm122') or (c > 'o122') or (c < 'h112') or (c = 'c111')) group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 17 Using where; Using index for group-by +1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 163 NULL 16 Using where; Using index for group-by explain select a1,a2,b,min(c) from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range idx_t2_0,idx_t2_1,idx_t2_2 idx_t2_1 146 NULL 16 Using where; Using index for group-by @@ -1824,16 +1824,16 @@ ord(a1) + count(distinct a1,a2,b) 104 explain select a1,a2,b, concat(min(c), max(c)) from t1 where a1 < 'd' group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 9 Using where; Using index for group-by +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 10 Using where; Using index for group-by explain select concat(a1,min(c)),b from t1 where a1 < 'd' group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 9 Using where; Using index for group-by +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 10 Using where; Using index for group-by explain select concat(a1,min(c)),b,max(c) from t1 where a1 < 'd' group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 9 Using where; Using index for group-by +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 10 Using where; Using index for group-by explain select concat(a1,a2),b,min(c),max(c) from t1 where a1 < 'd' group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 9 Using where; Using index for group-by +1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 10 Using where; Using index for group-by explain select concat(ord(min(b)),ord(max(b))),min(b),max(b) from t1 group by a1,a2; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range NULL idx_t1_1 130 NULL 9 Using index for group-by diff --git a/mysql-test/r/index_merge.result b/mysql-test/r/index_merge.result index 693cc63ba9e..8f5db550d8b 100644 --- a/mysql-test/r/index_merge.result +++ b/mysql-test/r/index_merge.result @@ -17,11 +17,11 @@ Table Op Msg_type Msg_text test.t0 analyze status OK explain select * from t0 where key1 < 3 or key1 > 1020; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 range i1 i1 4 NULL 55 Using where +1 SIMPLE t0 range i1 i1 4 NULL 78 Using where explain select * from t0 where key1 < 3 or key2 > 1020; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 31 Using sort_union(i1,i2); Using where +1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 45 Using sort_union(i1,i2); Using where select * from t0 where key1 < 3 or key2 > 1020; key1 key2 key3 key4 key5 key6 key7 key8 1 1 1 1 1 1 1 1023 @@ -36,7 +36,7 @@ id select_type table type possible_keys key key_len ref rows Extra explain select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 9 Using sort_union(i1,i2); Using where +1 SIMPLE t0 index_merge i1,i2 i1,i2 4,4 NULL 11 Using sort_union(i1,i2); Using where select * from t0 where (key1 > 30 and key1<35) or (key2 >32 and key2 < 40); key1 key2 key3 key4 key5 key6 key7 key8 31 31 31 31 31 31 31 993 @@ -90,7 +90,7 @@ id select_type table type possible_keys key key_len ref rows Extra explain select key1 from t0 where (key1 <=> null) or (key1 < 5) or (key3=10) or (key4 <=> null); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i1,i3,i4 i1,i3 4,4 NULL 5 Using sort_union(i1,i3); Using where +1 SIMPLE t0 index_merge i1,i3,i4 i1,i3 4,4 NULL 6 Using sort_union(i1,i3); Using where explain select * from t0 where (key1 < 3 or key2 < 3) and (key3 < 4 or key4 < 4) and (key5 < 5 or key6 < 5); id select_type table type possible_keys key key_len ref rows Extra @@ -113,7 +113,7 @@ id select_type table type possible_keys key key_len ref rows Extra explain select * from t0 where (key1 < 3 or key2 < 3) and (key3 < 100); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 range i1,i2,i3 i3 4 NULL 96 Using where +1 SIMPLE t0 range i1,i2,i3 i3 4 NULL 95 Using where explain select * from t0 where (key1 < 3 or key2 < 3) and (key3 < 1000); id select_type table type possible_keys key key_len ref rows Extra @@ -152,7 +152,7 @@ explain select * from t0 where or ((key7 <7 or key8 < 4) and (key5 < 5 or key6 < 6)); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 index_merge i1,i2,i3,i5,i6,i7,i8 i3,i5,i7,i8 4,4,4,4 NULL 21 Using sort_union(i3,i5,i7,i8); Using where +1 SIMPLE t0 index_merge i1,i2,i3,i5,i6,i7,i8 i3,i5,i7,i8 4,4,4,4 NULL 20 Using sort_union(i3,i5,i7,i8); Using where explain select * from t0 where ((key3 <5 or key5 < 4) and (key1 < 4 or key2 < 4)) or @@ -257,7 +257,7 @@ explain select * from t0,t1 where (t0.key1=t1.key1) and (t0.key1=3 or t0.key2=4) and t1.key1<200; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t0 range i1,i2 i1 4 NULL 179 Using where +1 SIMPLE t0 ALL i1,i2 NULL NULL NULL 1024 Using where 1 SIMPLE t1 ref i1 i1 4 test.t0.key1 1 explain select * from t0,t1 where (t0.key1=t1.key1) and @@ -345,8 +345,8 @@ from t0 as A force index(i1,i2), t0 as B force index (i1,i2) where (A.key1 < 500000 or A.key2 < 3) and (B.key1 < 500000 or B.key2 < 3); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE A index_merge i1,i2 i1,i2 4,4 NULL 1016 Using sort_union(i1,i2); Using where -1 SIMPLE B index_merge i1,i2 i1,i2 4,4 NULL 1016 Using sort_union(i1,i2); Using where +1 SIMPLE A index_merge i1,i2 i1,i2 4,4 NULL 1013 Using sort_union(i1,i2); Using where +1 SIMPLE B index_merge i1,i2 i1,i2 4,4 NULL 1013 Using sort_union(i1,i2); Using where select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) from t0 as A force index(i1,i2), t0 as B force index (i1,i2) where (A.key1 < 500000 or A.key2 < 3) @@ -371,11 +371,11 @@ alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(20 update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500; explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) from t0 as A, t0 as B -where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7or16 = 1 or A.key8=1) -and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7or16 = 1 or B.key8=1); +where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key# = 1 or A.key8=1) +and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key# = 1 or B.key8=1); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE A index_merge i1,i2,i3,i4,i5,i6,i7?,i8 i2,i3,i4,i5,i6,i7?,i8 X NULL 7or16 Using union(intersect(i2,i3,i4,i5,i6,i7?),i8); Using where -1 SIMPLE B index_merge i1,i2,i3,i4,i5,i6,i7?,i8 i2,i3,i4,i5,i6,i7?,i8 X NULL 7or16 Using union(intersect(i2,i3,i4,i5,i6,i7?),i8); Using where +1 SIMPLE A index_merge i1,i2,i3,i4,i5,i6,i7?,i8 i2,i3,i4,i5,i6,i7?,i8 X NULL # Using union(intersect(i2,i3,i4,i5,i6,i7?),i8); Using where +1 SIMPLE B index_merge i1,i2,i3,i4,i5,i6,i7?,i8 i2,i3,i4,i5,i6,i7?,i8 X NULL # Using union(intersect(i2,i3,i4,i5,i6,i7?),i8); Using where select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) from t0 as A, t0 as B where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) diff --git a/mysql-test/r/index_merge_ror.result b/mysql-test/r/index_merge_ror.result index a1d306c3ea4..69cd11d1dbf 100644 --- a/mysql-test/r/index_merge_ror.result +++ b/mysql-test/r/index_merge_ror.result @@ -4,13 +4,13 @@ count(*) 64801 explain select key1,key2 from t1 where key1=100 and key2=100; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 3 Using intersect(key1,key2); Using where; Using index +1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 58 Using intersect(key1,key2); Using where; Using index select key1,key2 from t1 where key1=100 and key2=100; key1 key2 100 100 explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using union(intersect(key1,key2),intersect(key3,key4)); Using where +1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 154 Using union(intersect(key1,key2),intersect(key3,key4)); Using where select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; key1 key2 key3 key4 filler1 100 100 100 100 key1-key2-key3-key4 @@ -18,21 +18,21 @@ insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, -1, -1, 'key1 insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 100, 100, 'key4-key3'); explain select key1,key2,filler1 from t1 where key1=100 and key2=100; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 3 Using intersect(key1,key2); Using where +1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 58 Using intersect(key1,key2); Using where select key1,key2,filler1 from t1 where key1=100 and key2=100; key1 key2 filler1 100 100 key1-key2-key3-key4 100 100 key1-key2 explain select key1,key2 from t1 where key1=100 and key2=100; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 3 Using intersect(key1,key2); Using where; Using index +1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 58 Using intersect(key1,key2); Using where; Using index select key1,key2 from t1 where key1=100 and key2=100; key1 key2 100 100 100 100 explain select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using union(intersect(key1,key2),intersect(key3,key4)); Using where +1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 154 Using union(intersect(key1,key2),intersect(key3,key4)); Using where select key1,key2,key3,key4 from t1 where key1=100 and key2=100 or key3=100 and key4=100; key1 key2 key3 key4 100 100 100 100 @@ -40,7 +40,7 @@ key1 key2 key3 key4 -1 -1 100 100 explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using union(intersect(key1,key2),intersect(key3,key4)); Using where +1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 154 Using union(intersect(key1,key2),intersect(key3,key4)); Using where select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; key1 key2 key3 key4 filler1 100 100 100 100 key1-key2-key3-key4 @@ -48,14 +48,14 @@ key1 key2 key3 key4 filler1 -1 -1 100 100 key4-key3 explain select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3 key1,key2,key3 5,5,5 NULL 1 Using intersect(key1,key2,key3); Using where; Using index +1 SIMPLE t1 index_merge key1,key2,key3 key1,key2,key3 5,5,5 NULL 2 Using intersect(key1,key2,key3); Using where; Using index select key1,key2,key3 from t1 where key1=100 and key2=100 and key3=100; key1 key2 key3 100 100 100 insert into t1 (key1,key2,key3,key4,filler1) values (101,101,101,101, 'key1234-101'); explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3 key1,key2,key3 5,5,5 NULL 5 Using union(intersect(key1,key2),key3); Using where +1 SIMPLE t1 index_merge key1,key2,key3 key1,key2,key3 5,5,5 NULL 83 Using union(intersect(key1,key2),key3); Using where select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=101; key1 key2 key3 key4 filler1 100 100 100 100 key1-key2-key3-key4 @@ -72,19 +72,19 @@ select key1,key2,filler1 from t1 where key2=100 and key2=200; key1 key2 filler1 explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using union(intersect(key1,key2),intersect(key3,key4)); Using where +1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 152 Using union(intersect(key1,key2),intersect(key3,key4)); Using where select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; key1 key2 key3 key4 filler1 -1 -1 100 100 key4-key3 delete from t1 where key3=100 and key4=100; explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 8 Using union(intersect(key1,key2),intersect(key3,key4)); Using where +1 SIMPLE t1 index_merge key1,key2,key3,key4 key1,key2,key3,key4 5,5,5,5 NULL 152 Using union(intersect(key1,key2),intersect(key3,key4)); Using where select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100; key1 key2 key3 key4 filler1 explain select key1,key2 from t1 where key1=100 and key2=100; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 3 Using intersect(key1,key2); Using where; Using index +1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL 57 Using intersect(key1,key2); Using where; Using index select key1,key2 from t1 where key1=100 and key2=100; key1 key2 insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-1'); @@ -92,7 +92,7 @@ insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-3'); explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL 16 Using union(key3,intersect(key1,key2),key4); Using where +1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL 136 Using union(key3,intersect(key1,key2),key4); Using where select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; key1 key2 key3 key4 filler1 100 100 200 200 key1-key2-key3-key4-3 @@ -101,7 +101,7 @@ key1 key2 key3 key4 filler1 insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, -1, 200,'key4'); explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL 18 Using union(key3,intersect(key1,key2),key4); Using where +1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL 146 Using union(key3,intersect(key1,key2),key4); Using where select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; key1 key2 key3 key4 filler1 100 100 200 200 key1-key2-key3-key4-3 @@ -111,7 +111,7 @@ key1 key2 key3 key4 filler1 insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 200, -1,'key3'); explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL 20 Using union(key3,intersect(key1,key2),key4); Using where +1 SIMPLE t1 index_merge key1,key2,key3,key4 key3,key1,key2,key4 5,5,5,5 NULL 156 Using union(key3,intersect(key1,key2),key4); Using where select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200; key1 key2 key3 key4 filler1 100 100 200 200 key1-key2-key3-key4-3 @@ -121,50 +121,50 @@ key1 key2 key3 key4 filler1 -1 -1 200 -1 key3 explain select * from t1 where st_a=1 and st_b=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b st_a,st_b 4,4 NULL 2508 Using intersect(st_a,st_b); Using where +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b st_a,st_b 4,4 NULL 2637 Using intersect(st_a,st_b); Using where explain select st_a,st_b from t1 where st_a=1 and st_b=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b st_a,st_b 4,4 NULL 2508 Using intersect(st_a,st_b); Using where; Using index +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b st_a,st_b 4,4 NULL 2637 Using intersect(st_a,st_b); Using where; Using index explain select st_a from t1 ignore index (st_a) where st_a=1 and st_b=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,stb_swt1a_2b,stb_swt1b,st_b st_b 4 const 14720 Using where +1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,stb_swt1a_2b,stb_swt1b,st_b st_b 4 const 15093 Using where explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a sta_swt12a 12 const,const,const 958 +1 SIMPLE t1 ref sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a sta_swt21a 12 const,const,const 971 explain select * from t1 where st_b=1 and swt1b=1 and swt2b=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref stb_swt1a_2b,stb_swt1b,st_b stb_swt1b 8 const,const 3757 Using where +1 SIMPLE t1 ref stb_swt1a_2b,stb_swt1b,st_b stb_swt1a_2b 8 const,const 3879 Using where explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt12a,stb_swt1a_2b 12,12 NULL 42 Using intersect(sta_swt12a,stb_swt1a_2b); Using where +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt12a,stb_swt1a_2b 12,12 NULL 44 Using intersect(sta_swt12a,stb_swt1a_2b); Using where explain select * from t1 ignore index (sta_swt21a, stb_swt1a_2b) where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,st_a,stb_swt1b,st_b sta_swt12a,stb_swt1b 12,8 NULL 42 Using intersect(sta_swt12a,stb_swt1b); Using where +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,st_a,stb_swt1b,st_b sta_swt12a,stb_swt1b 12,8 NULL 44 Using intersect(sta_swt12a,stb_swt1b); Using where explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b) where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt1a,sta_swt2a,st_a,stb_swt1b,st_b sta_swt1a,sta_swt2a,stb_swt1b 8,8,8 NULL 41 Using intersect(sta_swt1a,sta_swt2a,stb_swt1b); Using where +1 SIMPLE t1 index_merge sta_swt1a,sta_swt2a,st_a,stb_swt1b,st_b sta_swt1a,sta_swt2a,stb_swt1b 8,8,8 NULL 43 Using intersect(sta_swt1a,sta_swt2a,stb_swt1b); Using where explain select * from t1 ignore index (sta_swt21a, sta_swt12a, stb_swt1a_2b, stb_swt1b) where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1 and swt2b=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt1a,sta_swt2a,st_a,st_b sta_swt1a,sta_swt2a,st_b 8,8,4 NULL 159 Using intersect(sta_swt1a,sta_swt2a,st_b); Using where +1 SIMPLE t1 index_merge sta_swt1a,sta_swt2a,st_a,st_b sta_swt1a,sta_swt2a,st_b 8,8,4 NULL 168 Using intersect(sta_swt1a,sta_swt2a,st_b); Using where explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1 and st_b=1 and swt1b=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt12a,stb_swt1a_2b 12,12 NULL 42 Using intersect(sta_swt12a,stb_swt1a_2b); Using where +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt12a,stb_swt1a_2b 12,12 NULL 44 Using intersect(sta_swt12a,stb_swt1a_2b); Using where explain select * from t1 where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL 163 Using intersect(sta_swt1a,stb_swt1b); Using where +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL 174 Using intersect(sta_swt1a,stb_swt1b); Using where explain select st_a from t1 where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL 163 Using intersect(sta_swt1a,stb_swt1b); Using where; Using index +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL 174 Using intersect(sta_swt1a,stb_swt1b); Using where; Using index explain select st_a from t1 where st_a=1 and swt1a=1 and st_b=1 and swt1b=1 and swt1b=1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL 163 Using intersect(sta_swt1a,stb_swt1b); Using where; Using index +1 SIMPLE t1 index_merge sta_swt12a,sta_swt1a,sta_swt2a,sta_swt21a,st_a,stb_swt1a_2b,stb_swt1b,st_b sta_swt1a,stb_swt1b 8,8 NULL 174 Using intersect(sta_swt1a,stb_swt1b); Using where; Using index drop table t0,t1; create table t2 ( a char(10), diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result new file mode 100644 index 00000000000..0ccb22be22a --- /dev/null +++ b/mysql-test/r/information_schema_db.result @@ -0,0 +1,28 @@ +use INFORMATION_SCHEMA; +show tables; +Tables_in_INFORMATION_SCHEMA +SCHEMATA +TABLES +COLUMNS +CHARACTER_SETS +COLLATIONS +COLLATION_CHARACTER_SET_APPLICABILITY +ROUTINES +STATISTICS +VIEWS +USER_PRIVILEGES +SCHEMA_PRIVILEGES +TABLE_PRIVILEGES +COLUMN_PRIVILEGES +TABLE_CONSTRAINTS +KEY_COLUMN_USAGE +show tables from INFORMATION_SCHEMA like 'T%'; +Tables_in_INFORMATION_SCHEMA (T%) +TABLES +TABLE_PRIVILEGES +TABLE_CONSTRAINTS +create database `inf%`; +use `inf%`; +show tables; +Tables_in_inf% +drop database `inf%`; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 54feabc6608..295ec80cd54 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -39,7 +39,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t3 range a a 4 NULL 18 Using where explain select * from t3 where a > 10 and a < 20; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 range a a 4 NULL 16 Using where +1 SIMPLE t3 range a a 4 NULL 17 Using where select * from t3 where a = 10; a b 10 Testing diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 1a8ace98d05..30e573fa31e 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -1203,3 +1203,60 @@ drop table t1; Got one of the listed errors drop table t1; ERROR 42S02: Unknown table 't1' +set @save_concurrent_insert=@@concurrent_insert; +set global concurrent_insert=1; +create table t1 (a int); +insert into t1 values (1),(2),(3),(4),(5); +lock table t1 read local; +insert into t1 values(6),(7); +unlock tables; +delete from t1 where a>=3 and a<=4; +lock table t1 read local; +set global concurrent_insert=2; +insert into t1 values (8),(9); +unlock tables; +insert into t1 values (10),(11),(12); +select * from t1; +a +1 +2 +11 +10 +5 +6 +7 +8 +9 +12 +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +create table t1 (a int, b varchar(30) default "hello"); +insert into t1 (a) values (1),(2),(3),(4),(5); +lock table t1 read local; +insert into t1 (a) values(6),(7); +unlock tables; +delete from t1 where a>=3 and a<=4; +lock table t1 read local; +set global concurrent_insert=2; +insert into t1 (a) values (8),(9); +unlock tables; +insert into t1 (a) values (10),(11),(12); +select a from t1; +a +1 +2 +11 +10 +5 +6 +7 +8 +9 +12 +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +drop table t1; +set global concurrent_insert=@save_concurrent_insert; diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result index c2b925072dd..4551fed2732 100644 --- a/mysql-test/r/null.result +++ b/mysql-test/r/null.result @@ -170,7 +170,7 @@ insert into t1 select i*2 from t1; insert into t1 values(null); explain select * from t1 where i=2 or i is null; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref_or_null i i 5 const 10 Using where; Using index +1 SIMPLE t1 ref_or_null i i 5 const 9 Using where; Using index select count(*) from t1 where i=2 or i is null; count(*) 10 @@ -179,7 +179,7 @@ Warnings: Warning 1265 Data truncated for column 'i' at row 513 explain select * from t1 where i=2 or i is null; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref i i 4 const 8 Using index +1 SIMPLE t1 ref i i 4 const 7 Using index select count(*) from t1 where i=2 or i is null; count(*) 9 diff --git a/mysql-test/r/preload.result b/mysql-test/r/preload.result index b5e6dcfcdbb..b668b07b398 100644 --- a/mysql-test/r/preload.result +++ b/mysql-test/r/preload.result @@ -55,15 +55,15 @@ count(*) 4181 show status like "key_read%"; Variable_name Value -Key_read_requests 217 -Key_reads 45 +Key_read_requests 294 +Key_reads 60 select count(*) from t1 where b = 'test1'; count(*) 4181 show status like "key_read%"; Variable_name Value -Key_read_requests 434 -Key_reads 45 +Key_read_requests 588 +Key_reads 60 flush tables; flush status; select @@preload_buffer_size; @@ -74,15 +74,15 @@ Table Op Msg_type Msg_text test.t1 preload_keys status OK show status like "key_read%"; Variable_name Value -Key_read_requests 581 -Key_reads 581 +Key_read_requests 774 +Key_reads 774 select count(*) from t1 where b = 'test1'; count(*) 4181 show status like "key_read%"; Variable_name Value -Key_read_requests 798 -Key_reads 581 +Key_read_requests 1068 +Key_reads 774 flush tables; flush status; show status like "key_read%"; @@ -98,15 +98,15 @@ Table Op Msg_type Msg_text test.t1 preload_keys status OK show status like "key_read%"; Variable_name Value -Key_read_requests 10 -Key_reads 10 +Key_read_requests 17 +Key_reads 17 select count(*) from t1 where b = 'test1'; count(*) 4181 show status like "key_read%"; Variable_name Value -Key_read_requests 227 -Key_reads 52 +Key_read_requests 311 +Key_reads 75 flush tables; flush status; show status like "key_read%"; @@ -123,8 +123,8 @@ test.t1 preload_keys status OK test.t2 preload_keys status OK show status like "key_read%"; Variable_name Value -Key_read_requests 587 -Key_reads 587 +Key_read_requests 785 +Key_reads 785 select count(*) from t1 where b = 'test1'; count(*) 4181 @@ -133,8 +133,8 @@ count(*) 2584 show status like "key_read%"; Variable_name Value -Key_read_requests 938 -Key_reads 613 +Key_read_requests 1266 +Key_reads 821 flush tables; flush status; show status like "key_read%"; @@ -149,8 +149,8 @@ Warnings: Error 1146 Table 'test.t3' doesn't exist show status like "key_read%"; Variable_name Value -Key_read_requests 355 -Key_reads 355 +Key_read_requests 478 +Key_reads 478 flush tables; flush status; show status like "key_read%"; diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index 6c616a99fb0..18bc76789b1 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -290,11 +290,11 @@ t2 1 t2_idx 1 b A NULL NULL NULL YES BTREE prepare stmt4 from ' show table status from test like ''t2%'' '; execute stmt4; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t2 MyISAM 10 Fixed 0 0 0 64424509439 1024 0 NULL # # # latin1_swedish_ci NULL +t2 MyISAM 10 Fixed 0 0 0 4222124650659839 1024 0 NULL # # # latin1_swedish_ci NULL prepare stmt4 from ' show table status from test like ''t9%'' '; execute stmt4; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t9 MyISAM 10 Dynamic 2 216 432 4294967295 2048 0 NULL # # # latin1_swedish_ci NULL +t9 MyISAM 10 Dynamic 2 216 432 281474976710655 2048 0 NULL # # # latin1_swedish_ci NULL prepare stmt4 from ' show status like ''Threads_running'' '; execute stmt4; Variable_name Value @@ -803,4 +803,4 @@ prepare stmt1 from @string ; execute stmt1 ; prepare stmt1 from ' select * from t5 ' ; execute stmt1 ; -drop table t5 ; +drop table t5, t9; diff --git a/mysql-test/r/ps_grant.result b/mysql-test/r/ps_grant.result index 3a302ba3ba8..8fbb06fe61b 100644 --- a/mysql-test/r/ps_grant.result +++ b/mysql-test/r/ps_grant.result @@ -1,7 +1,3 @@ -prepare stmt4 from ' show full processlist '; -execute stmt4; -Id User Host db Command Time State Info -number root localhost test Query time NULL show full processlist test_sequence ------ grant/revoke/drop affects a parallel session test ------ show grants for second_user@localhost ; @@ -91,3 +87,8 @@ revoke all privileges on test.t1 from drop_user@localhost ; prepare stmt3 from ' drop user drop_user@localhost '; ERROR HY000: This command is not supported in the prepared statement protocol yet drop user drop_user@localhost; +prepare stmt4 from ' show full processlist '; +execute stmt4; +Id User Host db Command Time State Info +number root localhost test Query time NULL show full processlist +deallocate prepare stmt4; diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index fea5754d704..095690fde00 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -421,19 +421,19 @@ test.t1 analyze status OK test.t2 analyze status Table is already up to date explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range uid_index uid_index 4 NULL 128 Using where +1 SIMPLE t1 range uid_index uid_index 4 NULL 112 Using where 1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 38 explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid > 0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range uid_index uid_index 4 NULL 128 Using where +1 SIMPLE t1 range uid_index uid_index 4 NULL 112 Using where 1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 38 explain select * from t1, t2 where t1.uid=t2.uid AND t1.uid != 0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range uid_index uid_index 4 NULL 129 Using where +1 SIMPLE t1 range uid_index uid_index 4 NULL 113 Using where 1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 38 explain select * from t1, t2 where t1.uid=t2.uid AND t2.uid != 0; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range uid_index uid_index 4 NULL 129 Using where +1 SIMPLE t1 range uid_index uid_index 4 NULL 113 Using where 1 SIMPLE t2 ref uid_index uid_index 4 test.t1.uid 38 select * from t1, t2 where t1.uid=t2.uid AND t1.uid > 0; id name uid id name uid diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index 6e5fccfe4e2..7b3249d553a 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -158,9 +158,6 @@ a select * from t2; a 3 -select if(compte<>3,"this is broken but documented","this unexpectedly works?") from (select count(*) as compte from t2) as aggreg; -if(compte<>3,"this is broken but documented","this unexpectedly works?") -this is broken but documented select * from mysql.proc where name="foo4" and db='mysqltest1'; db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment mysqltest1 foo4 PROCEDURE foo4 SQL CONTAINS_SQL YES INVOKER begin @@ -197,9 +194,6 @@ a select * from t1; a 21 -select if(compte<>1,"this is broken but documented","this unexpectedly works?") from (select count(*) as compte from t1 where a=20) as aggreg; -if(compte<>1,"this is broken but documented","this unexpectedly works?") -this is broken but documented select * from t2; a 23 @@ -230,6 +224,35 @@ db name type specific_name language sql_data_access is_deterministic security_ty mysqltest1 fn1 FUNCTION fn1 SQL CONTAINS_SQL YES DEFINER int(11) begin return unix_timestamp(); end @ # # +create trigger trg before insert on t1 for each row set new.a= 10; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +flush logs; +delete from t1; +create trigger trg before insert on t1 for each row set new.a= 10; +insert into t1 values (1); +select * from t1; +a +10 +select * from t1; +a +10 +delete from t1; +drop trigger t1.trg; +insert into t1 values (1); +select * from t1; +a +1 +show binlog events in 'master-bin.000002' from 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000002 # Query 1 # use `mysqltest1`; create trigger trg before insert on t1 for each row set new.a= 10 +master-bin.000002 # Query 1 # use `mysqltest1`; insert into t1 values (1) +master-bin.000002 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000002 # Query 1 # use `mysqltest1`; drop trigger t1.trg +master-bin.000002 # Query 1 # use `mysqltest1`; insert into t1 values (1) +select * from t1; +a +1 drop function fn1; drop database mysqltest1; drop user "zedjzlcsjhd"@127.0.0.1; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index fd67903a576..9b3c893aafa 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2476,3 +2476,13 @@ x NULL 1.0000 drop table t1; +create table t1 (a int(11)); +select all all * from t1; +a +select distinct distinct * from t1; +a +select all distinct * from t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'distinct * from t1' at line 1 +select distinct all * from t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'all * from t1' at line 1 +drop table t1; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 0cc16448625..c1164380f09 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3073,4 +3073,29 @@ update v1 set data = 10| call bug9841()| drop view v1| drop procedure bug9841| +drop procedure if exists bug5963| +create procedure bug5963_1 () begin declare v int; set v = (select s1 from t3); select v; end;| +create table t3 (s1 int)| +insert into t3 values (5)| +call bug5963_1()| +v +5 +call bug5963_1()| +v +5 +drop procedure bug5963_1| +drop table t3| +create procedure bug5963_2 (cfk_value int) +begin +if cfk_value in (select cpk from t3) then +set @x = 5; +end if; +end; +| +create table t3 (cpk int)| +insert into t3 values (1)| +call bug5963_2(1)| +call bug5963_2(1)| +drop procedure bug5963_2| +drop table t3| drop table t1,t2; diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index 7d1b6b67fd2..79be7a1923a 100644 --- a/mysql-test/r/strict.result +++ b/mysql-test/r/strict.result @@ -1232,3 +1232,8 @@ INSERT INTO t1 VALUES (DEFAULT,1); Warnings: Warning 1364 Field 'i' doesn't have a default value DROP TABLE t1; +set @@sql_mode='traditional'; +create table t1(a varchar(65537)); +ERROR 42000: Column length too big for column 'a' (max = 65535); use BLOB or TEXT instead +create table t1(a varbinary(65537)); +ERROR 42000: Column length too big for column 'a' (max = 65535); use BLOB or TEXT instead diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index 6f437ddbe0d..67a011231be 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -9,7 +9,7 @@ d mediumtext YES NULL e longtext YES NULL CREATE TABLE t2 (a char(255), b varbinary(70000), c varchar(70000000)); Warnings: -Note 1246 Converting column 'b' from VARCHAR to BLOB +Note 1246 Converting column 'b' from VARBINARY to BLOB Note 1246 Converting column 'c' from VARCHAR to TEXT CREATE TABLE t4 (c varchar(65530) character set utf8 not null); Warnings: diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 86c905b83a2..e775724ff54 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -863,3 +863,25 @@ select 0.190287977636363637 + 0.040372670 * 0 - 0; select -0.123 * 0; -0.123 * 0 0.000 +CREATE TABLE t1 (f1 DECIMAL (12,9), f2 DECIMAL(2,2)); +INSERT INTO t1 VALUES (10.5, 0); +UPDATE t1 SET f1 = 4.5; +SELECT * FROM t1; +f1 f2 +4.500000000 0.00 +DROP TABLE t1; +CREATE TABLE t1 (f1 DECIMAL (64,20), f2 DECIMAL(2,2)); +INSERT INTO t1 VALUES (9999999999999999999999999999999999, 0); +SELECT * FROM t1; +f1 f2 +9999999999999999999999999999999999.00000000000000000000 0.00 +DROP TABLE t1; +CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB; +INSERT INTO t1 (GRADE) VALUES (151),(252),(343); +SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300; +GRADE +252 +SELECT GRADE FROM t1 WHERE GRADE= 151; +GRADE +151 +DROP TABLE t1; diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 3479d209019..5e9a0e11c24 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -117,27 +117,23 @@ id select_type table type possible_keys key key_len ref rows Extra Warnings: Note 1003 select sql_no_cache 345 AS `@@IDENTITY`,last_insert_id() AS `last_insert_id()`,345 AS `@@identity` set big_tables=OFF, big_tables=ON, big_tables=0, big_tables=1, big_tables="OFF", big_tables="ON"; -set global concurrent_insert=ON; +set global concurrent_insert=2; show variables like 'concurrent_insert'; Variable_name Value -concurrent_insert ON +concurrent_insert 2 set global concurrent_insert=1; show variables like 'concurrent_insert'; Variable_name Value -concurrent_insert ON +concurrent_insert 1 set global concurrent_insert=0; show variables like 'concurrent_insert'; Variable_name Value -concurrent_insert OFF -set global concurrent_insert=OFF; -show variables like 'concurrent_insert'; -Variable_name Value -concurrent_insert OFF +concurrent_insert 0 set global concurrent_insert=DEFAULT; -show variables like 'concurrent_insert'; -Variable_name Value -concurrent_insert ON -set global timed_mutexes=1; +select @@concurrent_insert; +@@concurrent_insert +1 +set global timed_mutexes=ON; show variables like 'timed_mutexes'; Variable_name Value timed_mutexes ON @@ -281,8 +277,6 @@ select @@global.sql_auto_is_null; ERROR HY000: Variable 'sql_auto_is_null' is a SESSION variable set myisam_max_sort_file_size=100; ERROR HY000: Variable 'myisam_max_sort_file_size' is a GLOBAL variable and should be set with SET GLOBAL -set myisam_max_extra_sort_file_size=100; -ERROR HY000: Variable 'myisam_max_extra_sort_file_size' is a GLOBAL variable and should be set with SET GLOBAL set @@SQL_WARNINGS=NULL; ERROR 42000: Variable 'sql_warnings' can't be set to the value of 'NULL' set autocommit=1; @@ -338,11 +332,6 @@ select @@max_user_connections; @@max_user_connections 100 set global max_write_lock_count=100; -set global myisam_max_extra_sort_file_size=100; -select @@myisam_max_extra_sort_file_size; -@@myisam_max_extra_sort_file_size -100 -set global myisam_max_sort_file_size=100; set myisam_sort_buffer_size=100; set net_buffer_length=100; set net_read_timeout=100; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index f8629e578f0..4190b57418e 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1,4 +1,4 @@ -drop table if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6; +drop table if exists t1,t2,t9,`t1a``b`,v1,v2,v3,v4,v5,v6; drop view if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6; drop database if exists mysqltest; use test; @@ -51,7 +51,7 @@ explain extended select c from v1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Warnings: -Note 1003 select (`test`.`t1`.`b` + 1) AS `c` from `test`.`v1` +Note 1003 select (`test`.`t1`.`b` + 1) AS `c` from `test`.`t1` create algorithm=temptable view v2 (c) as select b+1 from t1; show create view v2; View Create View @@ -85,7 +85,7 @@ explain extended select c from v3; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Warnings: -Note 1003 select ((`test`.`t1`.`b` + 1) + 1) AS `c` from `test`.`v3` +Note 1003 select ((`test`.`t1`.`b` + 1) + 1) AS `c` from `test`.`t1` create algorithm=temptable view v4 (c) as select c+1 from v2; select c from v4; c @@ -114,7 +114,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived3> ALL NULL NULL NULL NULL 5 3 DERIVED t1 ALL NULL NULL NULL NULL 5 Warnings: -Note 1003 select (`v2`.`c` + 1) AS `c` from `test`.`v5` +Note 1003 select (`v2`.`c` + 1) AS `c` from `test`.`v2` create algorithm=temptable view v6 (c) as select c+1 from v1; select c from v6; c @@ -149,7 +149,7 @@ v5 VIEW v6 VIEW show table status; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment -t1 MyISAM 10 Fixed 5 9 45 38654705663 1024 0 NULL # # NULL latin1_swedish_ci NULL +t1 MyISAM 10 Fixed 5 9 45 2533274790395903 1024 0 NULL # # NULL latin1_swedish_ci NULL v1 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view v2 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view v3 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL # # NULL NULL NULL NULL view @@ -204,21 +204,6 @@ create table t1 (a int); insert into t1 values (1), (2), (3); create view v1 (a) as select a+1 from t1; create view v2 (a) as select a-1 from t1; -select * from t1 natural left join v1; -a a -1 NULL -2 2 -3 3 -select * from v2 natural left join t1; -a a -0 NULL -1 1 -2 2 -select * from v2 natural left join v1; -a a -0 NULL -1 NULL -2 2 drop view v1, v2; drop table t1; create table t1 (a int); @@ -378,7 +363,7 @@ explain extended select * from v1; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 5 Using where Warnings: -Note 1003 select `test`.`t1`.`b` AS `c` from `test`.`v1` where (`test`.`t1`.`a` < 3) +Note 1003 select `test`.`t1`.`b` AS `c` from `test`.`t1` where (`test`.`t1`.`a` < 3) update v1 set c=c+1; select * from t1; a b @@ -1393,7 +1378,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Warnings: -Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t3` left join (`test`.`v1` left join `test`.`v2` on((`test`.`t1`.`a` = `test`.`t2`.`a`))) on((`test`.`t3`.`a` = `test`.`t1`.`a`)) where 1 +Note 1003 select `test`.`t3`.`a` AS `a`,`test`.`t1`.`a` AS `a`,`test`.`t2`.`a` AS `b` from `test`.`t3` left join (`test`.`t1` left join (`test`.`t2`) on((`test`.`t1`.`a` = `test`.`t2`.`a`))) on((`test`.`t3`.`a` = `test`.`t1`.`a`)) where 1 prepare stmt1 from "select * from t3 left join v4 on (t3.a = v4.a);"; execute stmt1; a a b @@ -1712,3 +1697,18 @@ a b a b 3 3 3 3 drop view v1, v2; drop table t1, t2, t3; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); +INSERT INTO t1 VALUES (1), (2), (3), (4); +INSERT INTO t2 VALUES (4), (2); +CREATE VIEW v1 AS SELECT * FROM t1,t2 WHERE t1.a=t2.b; +SELECT * FROM v1; +a b +2 2 +4 4 +CREATE VIEW v2 AS SELECT * FROM v1; +SELECT * FROM v2; +a b +2 2 +4 4 +DROP VIEW v2,v1; diff --git a/mysql-test/suppress.purify b/mysql-test/suppress.purify new file mode 100644 index 00000000000..58553130c51 --- /dev/null +++ b/mysql-test/suppress.purify @@ -0,0 +1,10 @@ +suppress UMR rw_read_held; mi_open; ha_myisam::open64; handler::ha_open; openfrm +suppress UMR my_end; main +suppress UMR _doprnt; fprintf; my_end; main +suppress umr rw_read_held; mi_open +suppress umr _putmsg; putmsg; _tx_sndudata +suppress umr rw_read_held; Query_cache::store_query(THD*,st_table_list*); mysql_execute_command(THD*) +suppress sig ...; _select; select; handle_connections_sockets; main; _start +suppress sig ...; read; vio_read; my_real_read(st_net*,unsigned long*); my_net_read; do_command(THD*) +suppress sig ...; read; vio_read; my_real_read(st_net*,unsigned long*); my_net_read; net_safe_read +suppress sig ...; write; vio_write; net_real_write; net_write_buff(st_net*,const char*,unsigned long); my_net_write diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 9d5bd0459b0..2722e8572b0 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -376,6 +376,16 @@ SET NAMES latin1; SET collation_connection='ucs2_bin'; -- source include/ctype_filesort.inc +# +# Bug#10344 Some string functions fail for UCS2 +# +select hex(substr(_ucs2 0x00e400e50068,1)); +select hex(substr(_ucs2 0x00e400e50068,2)); +select hex(substr(_ucs2 0x00e400e50068,3)); +select hex(substr(_ucs2 0x00e400e50068,-1)); +select hex(substr(_ucs2 0x00e400e50068,-2)); +select hex(substr(_ucs2 0x00e400e50068,-3)); + SET NAMES latin1; # # Bug#8235 diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 194354f8718..02024adb34e 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -667,6 +667,12 @@ drop table t1; select 'c' like '\_' as want0; # +# SUBSTR with negative offset didn't work with multi-byte strings +# +SELECT SUBSTR('ваÑÑ',-2); + + +# # Bug #7730 Server crash using soundex on an utf8 table # create table t1 (id integer, a varchar(100) character set utf8 collate utf8_unicode_ci); diff --git a/mysql-test/t/index_merge.test b/mysql-test/t/index_merge.test index 5acbcd8eaeb..5ac91f1f8b1 100644 --- a/mysql-test/t/index_merge.test +++ b/mysql-test/t/index_merge.test @@ -310,7 +310,7 @@ update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500; # The next query will not use index i7 in intersection if the OS doesn't # support file sizes > 2GB. (ha_myisam::ref_length depends on this and index # scan cost estimates depend on ha_myisam::ref_length) ---replace_result "4,4,4,4,4,4,4" X "4,4,4,4,4,4" X "i6,i7" "i6,i7?" "i6" "i6,i7?" 7 7or16 16 7or16 +--replace_result "4,4,4,4,4,4,4" X "4,4,4,4,4,4" X "i6,i7" "i6,i7?" "i6" "i6,i7?" 7 # 16 # 18 # explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) from t0 as A, t0 as B where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) diff --git a/mysql-test/t/index_merge_ror.test b/mysql-test/t/index_merge_ror.test index 3a484157267..15c596ce149 100644 --- a/mysql-test/t/index_merge_ror.test +++ b/mysql-test/t/index_merge_ror.test @@ -184,6 +184,8 @@ explain select st_a from t1 ignore index (st_a) where st_a=1 and st_b=1; # Check that keys that don't improve selectivity are skipped. # +# Different value on 32 and 64 bit +--replace sta_swt12a sta_swt21a explain select * from t1 where st_a=1 and swt1a=1 and swt2a=1; explain select * from t1 where st_b=1 and swt1b=1 and swt2b=1; diff --git a/mysql-test/t/information_schema_db.test b/mysql-test/t/information_schema_db.test new file mode 100644 index 00000000000..f88d04c2783 --- /dev/null +++ b/mysql-test/t/information_schema_db.test @@ -0,0 +1,9 @@ +-- source include/testdb_only.inc + +use INFORMATION_SCHEMA; +show tables; +show tables from INFORMATION_SCHEMA like 'T%'; +create database `inf%`; +use `inf%`; +show tables; +drop database `inf%`; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 2b60e85fcc6..04f0de47e43 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -606,3 +606,57 @@ system rm ./var/master-data/test/t1.MYD ; drop table t1; --error 1051 drop table t1; + +# +# Test concurrent insert +# First with static record length +# +set @save_concurrent_insert=@@concurrent_insert; +set global concurrent_insert=1; +create table t1 (a int); +insert into t1 values (1),(2),(3),(4),(5); +lock table t1 read local; +connect (con1,localhost,root,,); +connection con1; +# Insert in table without hole +insert into t1 values(6),(7); +connection default; +unlock tables; +delete from t1 where a>=3 and a<=4; +lock table t1 read local; +connection con1; +set global concurrent_insert=2; +# Insert in table with hole -> Should insert at end +insert into t1 values (8),(9); +connection default; +unlock tables; +# Insert into hole +insert into t1 values (10),(11),(12); +select * from t1; +check table t1; +drop table t1; + +# Same test with dynamic record length +create table t1 (a int, b varchar(30) default "hello"); +insert into t1 (a) values (1),(2),(3),(4),(5); +lock table t1 read local; +connect (con1,localhost,root,,); +connection con1; +# Insert in table without hole +insert into t1 (a) values(6),(7); +connection default; +unlock tables; +delete from t1 where a>=3 and a<=4; +lock table t1 read local; +connection con1; +set global concurrent_insert=2; +# Insert in table with hole -> Should insert at end +insert into t1 (a) values (8),(9); +connection default; +unlock tables; +# Insert into hole +insert into t1 (a) values (10),(11),(12); +select a from t1; +check table t1; +drop table t1; +set global concurrent_insert=@save_concurrent_insert; diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test index 1fa9d30eaba..1c247240eb9 100644 --- a/mysql-test/t/ps_1general.test +++ b/mysql-test/t/ps_1general.test @@ -833,7 +833,7 @@ execute stmt1 ; --disable_metadata --horizontal_results -drop table t5 ; +drop table t5, t9; ##### RULES OF THUMB TO PRESERVE THE SYSTEMATICS OF THE PS TEST CASES ##### # diff --git a/mysql-test/t/ps_grant.test b/mysql-test/t/ps_grant.test index 07bd70f6cff..0b33a2dadde 100644 --- a/mysql-test/t/ps_grant.test +++ b/mysql-test/t/ps_grant.test @@ -1,10 +1,6 @@ # Can't test grants with embedded server -- source include/not_embedded.inc -# Tested here simply so it is not tested with embedded server -prepare stmt4 from ' show full processlist '; ---replace_column 1 number 6 time 3 localhost -execute stmt4; let $type= 'MYISAM' ; @@ -116,6 +112,7 @@ show grants for second_user@localhost ; drop database mysqltest; + ## grant/revoke + drop user --error 1295 prepare stmt3 from ' grant all on test.t1 to drop_user@localhost @@ -130,3 +127,10 @@ revoke all privileges on test.t1 from drop_user@localhost ; prepare stmt3 from ' drop user drop_user@localhost '; drop user drop_user@localhost; +# This test must be the last one, otherwise it may produce extra +# rows in the processlist under high load. +# Tested here simply so it is not tested with embedded server +prepare stmt4 from ' show full processlist '; +--replace_column 1 number 6 time 3 localhost +execute stmt4; +deallocate prepare stmt4; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index e86688c4315..5d5f845e2bc 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -437,6 +437,7 @@ explain select * from t1 where a='aaa' collate latin1_german1_ci; drop table t1; # Test for BUG#9348 "result for WHERE A AND (B OR C) differs from WHERE a AND (C OR B)" +--disable_warnings CREATE TABLE t1 ( `CLIENT` char(3) character set latin1 collate latin1_bin NOT NULL default '000', `ARG1` char(3) character set latin1 collate latin1_bin NOT NULL default '', @@ -445,6 +446,7 @@ CREATE TABLE t1 ( `FUNCTINT` int(11) NOT NULL default '0', KEY `VERI_CLNT~2` (`ARG1`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; +--enable_warnings INSERT INTO t1 VALUES ('000',' 0',' 0','Text 001',0), ('000',' 0',' 1','Text 002',0), ('000',' 1',' 2','Text 003',0), ('000',' 2',' 3','Text 004',0), diff --git a/mysql-test/t/rpl_sp.test b/mysql-test/t/rpl_sp.test index b8dc381630b..e2a8982ebaa 100644 --- a/mysql-test/t/rpl_sp.test +++ b/mysql-test/t/rpl_sp.test @@ -157,7 +157,6 @@ select * from t2; sync_slave_with_master; select * from t1; select * from t2; -select if(compte<>3,"this is broken but documented","this unexpectedly works?") from (select count(*) as compte from t2) as aggreg; # Test of DROP PROCEDURE @@ -194,7 +193,6 @@ select * from t1; select * from t2; sync_slave_with_master; select * from t1; -select if(compte<>1,"this is broken but documented","this unexpectedly works?") from (select count(*) as compte from t1 where a=20) as aggreg; select * from t2; connection master; @@ -225,6 +223,40 @@ select * from t1; --replace_column 13 # 14 # select * from mysql.proc where db='mysqltest1'; +# And now triggers + +connection con1; +--error 1227; +create trigger trg before insert on t1 for each row set new.a= 10; + +connection master; +# fn1() above uses timestamps, so in !ps-protocol, the timezone will be +# binlogged, but in --ps-protocol it will not be (BUG#9359) so +# the binlog offsets get shifted which spoils SHOW BINLOG EVENTS. +# To be immune, we take a new binlog. +flush logs; +delete from t1; +# TODO: when triggers can contain an update, test that this update +# does not go into binlog. +# I'm not setting user vars in the trigger, because replication of user vars +# would take care of propagating the user var's value to slave, so even if +# the trigger was not executed on slave it would not be discovered. +create trigger trg before insert on t1 for each row set new.a= 10; +insert into t1 values (1); +select * from t1; +sync_slave_with_master; +select * from t1; + +connection master; +delete from t1; +drop trigger t1.trg; +insert into t1 values (1); +select * from t1; +--replace_column 2 # 5 # +show binlog events in 'master-bin.000002' from 98; +sync_slave_with_master; +select * from t1; + # Clean up connection master; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 64f6674181c..d5efeeb331e 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -2056,3 +2056,19 @@ create table t1 (s1 int); insert into t1 values (null),(1); select distinct avg(s1) as x from t1 group by s1 with rollup; drop table t1; + + +# +# Bug#8733 server accepts malformed query (multiply mentioned distinct) +# +create table t1 (a int(11)); +select all all * from t1; +select distinct distinct * from t1; +--error 1064 +select all distinct * from t1; +--error 1064 +select distinct all * from t1; +drop table t1; + + +# diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index b4066df1666..80acaacfdb3 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3773,6 +3773,35 @@ drop procedure bug9841| # +# BUG#5963 subqueries in SET/IF +# +--disable_warnings +drop procedure if exists bug5963| +--enable_warnings + +create procedure bug5963_1 () begin declare v int; set v = (select s1 from t3); select v; end;| +create table t3 (s1 int)| +insert into t3 values (5)| +call bug5963_1()| +call bug5963_1()| +drop procedure bug5963_1| +drop table t3| + +create procedure bug5963_2 (cfk_value int) +begin + if cfk_value in (select cpk from t3) then + set @x = 5; + end if; + end; +| +create table t3 (cpk int)| +insert into t3 values (1)| +call bug5963_2(1)| +call bug5963_2(1)| +drop procedure bug5963_2| +drop table t3| + +# # BUG#NNNN: New bug synopsis # #--disable_warnings diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test index 333ec40b1b9..298653b554a 100644 --- a/mysql-test/t/strict.test +++ b/mysql-test/t/strict.test @@ -1083,3 +1083,13 @@ INSERT INTO t1 SET j = 1, i = DEFAULT; INSERT INTO t1 SET j = 1, i = DEFAULT(i); INSERT INTO t1 VALUES (DEFAULT,1); DROP TABLE t1; + +# +# Bugs #8295 and #8296: varchar and varbinary conversion +# + +set @@sql_mode='traditional'; +--error 1074 +create table t1(a varchar(65537)); +--error 1074 +create table t1(a varbinary(65537)); diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index 5ceb704eaf7..78ad5ed2286 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -892,3 +892,27 @@ select 0.190287977636363637 + 0.040372670 * 0 - 0; # Bug #9527 # select -0.123 * 0; + +# +# Bug #10232 +# + +CREATE TABLE t1 (f1 DECIMAL (12,9), f2 DECIMAL(2,2)); +INSERT INTO t1 VALUES (10.5, 0); +UPDATE t1 SET f1 = 4.5; +SELECT * FROM t1; +DROP TABLE t1; +CREATE TABLE t1 (f1 DECIMAL (64,20), f2 DECIMAL(2,2)); +INSERT INTO t1 VALUES (9999999999999999999999999999999999, 0); +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug #10465 +# + +CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB; +INSERT INTO t1 (GRADE) VALUES (151),(252),(343); +SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300; +SELECT GRADE FROM t1 WHERE GRADE= 151; +DROP TABLE t1; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 9931b72599f..b6059ac00e3 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -72,23 +72,20 @@ explain extended select @@IDENTITY,last_insert_id(), @@identity; set big_tables=OFF, big_tables=ON, big_tables=0, big_tables=1, big_tables="OFF", big_tables="ON"; -set global concurrent_insert=ON; +set global concurrent_insert=2; show variables like 'concurrent_insert'; set global concurrent_insert=1; show variables like 'concurrent_insert'; set global concurrent_insert=0; show variables like 'concurrent_insert'; -set global concurrent_insert=OFF; -show variables like 'concurrent_insert'; set global concurrent_insert=DEFAULT; -show variables like 'concurrent_insert'; +select @@concurrent_insert; -set global timed_mutexes=1; +set global timed_mutexes=ON; show variables like 'timed_mutexes'; set global timed_mutexes=0; show variables like 'timed_mutexes'; - set storage_engine=MYISAM, storage_engine="HEAP", global storage_engine="MERGE"; show local variables like 'storage_engine'; show global variables like 'storage_engine'; @@ -174,8 +171,6 @@ set @@global.sql_auto_is_null=1; select @@global.sql_auto_is_null; --error 1229 set myisam_max_sort_file_size=100; ---error 1229 -set myisam_max_extra_sort_file_size=100; --error 1231 set @@SQL_WARNINGS=NULL; @@ -222,9 +217,6 @@ set max_tmp_tables=100; set global max_user_connections=100; select @@max_user_connections; set global max_write_lock_count=100; -set global myisam_max_extra_sort_file_size=100; -select @@myisam_max_extra_sort_file_size; -set global myisam_max_sort_file_size=100; set myisam_sort_buffer_size=100; set net_buffer_length=100; set net_read_timeout=100; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 0303605a9ef..6f0cf59bb25 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1,5 +1,5 @@ --disable_warnings -drop table if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6; +drop table if exists t1,t2,t9,`t1a``b`,v1,v2,v3,v4,v5,v6; drop view if exists t1,t2,`t1a``b`,v1,v2,v3,v4,v5,v6; drop database if exists mysqltest; --enable_warnings @@ -148,9 +148,10 @@ insert into t1 values (1), (2), (3); create view v1 (a) as select a+1 from t1; create view v2 (a) as select a-1 from t1; -select * from t1 natural left join v1; -select * from v2 natural left join t1; -select * from v2 natural left join v1; +# WL #2486 should enable these tests +#select * from t1 natural left join v1; +#select * from v2 natural left join t1; +#select * from v2 natural left join v1; drop view v1, v2; drop table t1; @@ -1533,3 +1534,18 @@ select * from v2 A, v2 B where A.a = B.b; drop view v1, v2; drop table t1, t2, t3; +# +# Test case for bug #8528: select from view over multi-table view +# + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); +INSERT INTO t1 VALUES (1), (2), (3), (4); +INSERT INTO t2 VALUES (4), (2); + +CREATE VIEW v1 AS SELECT * FROM t1,t2 WHERE t1.a=t2.b; +SELECT * FROM v1; +CREATE VIEW v2 AS SELECT * FROM v1; +SELECT * FROM v2; + +DROP VIEW v2,v1; diff --git a/mysys/default.c b/mysys/default.c index 5afefa5463d..a680915b6d5 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -50,9 +50,11 @@ const char *default_directories[MAX_DEFAULT_DIRS + 1]; #ifdef __WIN__ static const char *f_extensions[]= { ".ini", ".cnf", 0 }; +#define NEWLINE "\r\n" static char system_dir[FN_REFLEN], shared_system_dir[FN_REFLEN]; #else static const char *f_extensions[]= { ".cnf", 0 }; +#define NEWLINE "\n" #endif /* @@ -79,6 +81,142 @@ static void init_default_directories(); static char *remove_end_comment(char *ptr); +/* + Add/remove option to the option file section. + + SYNOPSYS + my_correct_file() + file_location The location of configuration file to edit + option option to look for + option value The value of the option we would like to set + section_name the name of the section + remove_option This is true if we want to remove the option. + False otherwise. + IMPLEMENTATION + We open the option file first, then read the file line-by-line, + looking for the section we need. At the same time we put these lines + into a buffer. Then we look for the option within this section and + change/remove it. In the end we get a buffer with modified version of the + file. Then we write it to the file, truncate it if needed and close it. + + RETURN + 0 - ok + 1 - some error has occured. Probably due to the lack of resourses + -1 - cannot open the file +*/ + +int my_correct_defaults_file(const char *file_location, const char *option, + const char *option_value, + const char *section_name, int remove_option) +{ + FILE *cnf_file; + struct stat file_stat; + char linebuff[512], *ptr; + uint optlen; + uint len; + char *file_buffer; + uint position= 0; + int is_found= FALSE; + + optlen= strlen(option); + + DBUG_ENTER("my_correct_file"); + + if (!(cnf_file= my_fopen(file_location, O_RDWR, MYF(0)))) + goto err_fopen; + + /* my_fstat doesn't use the flag parameter */ + if (my_fstat(fileno(cnf_file), &file_stat, MYF(0))) + goto err; + + /* + Reserve space to read the contents of the file and some more + for the option we want ot add. + */ + file_buffer= (char*) my_malloc(sizeof(char)* + (file_stat.st_size + /* current file size */ + optlen + /* option name len */ + 2 + /* reserve space for newline */ + 1 + /* reserve for '=' char */ + strlen(option_value)), /* option value len */ + MYF(MY_WME)); + + if (!file_buffer) + goto malloc_err; + while (fgets(linebuff, sizeof(linebuff), cnf_file)) + { + len= strlen(linebuff); + + /* if the section is found traverse it */ + if (is_found) + { + /* skip the old value of the option we are changing */ + if (strncmp(linebuff, option, optlen)) + { + /* copy all other lines */ + strmake(file_buffer + position, linebuff, len); + position+= len; + } + } + else + { + strmake(file_buffer + position, linebuff, len); + position+= len; + } + + + /* looking for appropriate section */ + for (ptr= linebuff ; my_isspace(&my_charset_latin1,*ptr) ; ptr++) + {} + + if (*ptr == '[') + { + /* copy the line to the buffer */ + if (!strncmp(++ptr, section_name, strlen(section_name))) + { + is_found= TRUE; + /* add option */ + if (!remove_option) + { + strmake(file_buffer + position, option, optlen); + position+= optlen; + if (*option_value) + { + *(file_buffer + position++)= '='; + strmake(file_buffer + position, option_value, + strlen(option_value)); + position+= strlen(option_value); + } + /* add a newline */ + strcat(file_buffer + position, NEWLINE); + position+= strlen(NEWLINE); + } + } + else + is_found= FALSE; /* mark that this section is of no interest to us */ + } + + } + + if (my_chsize(fileno(cnf_file), position, 0, MYF(MY_WME)) || + my_fseek(cnf_file, 0, MY_SEEK_SET, MYF(0)) || + my_fwrite(cnf_file, file_buffer, position, MYF(MY_NABP)) || + my_fclose(cnf_file, MYF(MY_WME))) + goto err; + + my_free(file_buffer, MYF(0)); + + DBUG_RETURN(0); + +err: + my_free(file_buffer, MYF(0)); +malloc_err: + my_fclose(cnf_file, MYF(0)); + DBUG_RETURN(1); /* out of resources */ +err_fopen: + DBUG_RETURN(-1); /* cannot access the option file */ +} + /* Process config files in default directories. @@ -152,8 +290,8 @@ int my_search_option_files(const char *conf_file, int *argc, char ***argv, } else if (defaults_extra_file) { - if (search_default_file_with_ext(func, func_ctx, "", "", - defaults_extra_file, 0) < 0) + if ((error= search_default_file_with_ext(func, func_ctx, "", "", + defaults_extra_file, 0)) < 0) goto err; /* Fatal error */ if (error > 0) { diff --git a/mysys/my_chsize.c b/mysys/my_chsize.c index c258121226d..9760de29a08 100644 --- a/mysys/my_chsize.c +++ b/mysys/my_chsize.c @@ -30,7 +30,9 @@ MyFlags Flags DESCRIPTION - my_chsize() truncates file if shorter else fill with the filler character + my_chsize() truncates file if shorter else fill with the filler character. + The function also changes the file pointer. Usually it points to the end + of the file after execution. RETURN VALUE 0 Ok diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 9ce058f90fc..7761d2a9fc8 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -409,7 +409,7 @@ static my_bool wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, result=0; statistic_increment(locks_waited, &THR_LOCK_lock); if (data->lock->get_status) - (*data->lock->get_status)(data->status_param); + (*data->lock->get_status)(data->status_param, 0); check_locks(data->lock,"got wait_for_lock",0); } pthread_mutex_unlock(&data->lock->mutex); @@ -468,7 +468,7 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) lock->read_no_write_count++; check_locks(lock,"read lock with old write lock",0); if (lock->get_status) - (*lock->get_status)(data->status_param); + (*lock->get_status)(data->status_param, 0); statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } @@ -489,7 +489,7 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) data->prev=lock->read.last; lock->read.last= &data->next; if (lock->get_status) - (*lock->get_status)(data->status_param); + (*lock->get_status)(data->status_param, 0); if ((int) lock_type == (int) TL_READ_NO_INSERT) lock->read_no_write_count++; check_locks(lock,"read lock with no write locks",0); @@ -567,7 +567,7 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) lock->write.last= &data->next; check_locks(lock,"second write lock",0); if (data->lock->get_status) - (*data->lock->get_status)(data->status_param); + (*data->lock->get_status)(data->status_param, 0); statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; } @@ -580,9 +580,16 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) (ulong) lock->write_wait.data)); if (!lock->write_wait.data) { /* no scheduled write locks */ - if (lock_type == TL_WRITE_CONCURRENT_INSERT && - (*lock->check_status)(data->status_param)) - data->type=lock_type= thr_upgraded_concurrent_insert_lock; + my_bool concurrent_insert= 0; + if (lock_type == TL_WRITE_CONCURRENT_INSERT) + { + concurrent_insert= 1; + if ((*lock->check_status)(data->status_param)) + { + concurrent_insert= 0; + data->type=lock_type= thr_upgraded_concurrent_insert_lock; + } + } if (!lock->read.data || (lock_type <= TL_WRITE_DELAYED && @@ -594,7 +601,7 @@ int thr_lock(THR_LOCK_DATA *data,enum thr_lock_type lock_type) data->prev=lock->write.last; lock->write.last= &data->next; if (data->lock->get_status) - (*data->lock->get_status)(data->status_param); + (*data->lock->get_status)(data->status_param, concurrent_insert); check_locks(lock,"only write lock",0); statistic_increment(locks_immediate,&THR_LOCK_lock); goto end; @@ -1033,7 +1040,7 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data) if (!lock->read.data) /* No read locks */ { /* We have the lock */ if (data->lock->get_status) - (*data->lock->get_status)(data->status_param); + (*data->lock->get_status)(data->status_param, 0); pthread_mutex_unlock(&lock->mutex); DBUG_RETURN(0); } @@ -1221,7 +1228,8 @@ static ulong sum=0; /* The following functions is for WRITE_CONCURRENT_INSERT */ -static void test_get_status(void* param __attribute__((unused))) +static void test_get_status(void* param __attribute__((unused)), + int concurrent_insert __attribute__((unused))) { } diff --git a/server-tools/instance-manager/buffer.cc b/server-tools/instance-manager/buffer.cc index b000a48d5ae..26df401c3c5 100644 --- a/server-tools/instance-manager/buffer.cc +++ b/server-tools/instance-manager/buffer.cc @@ -64,7 +64,7 @@ int Buffer::append(uint position, const char *string, uint len_arg) DESCRIPTION - The method checks whether it is possible to pus a string of teh "len_arg" + The method checks whether it is possible to put a string of the "len_arg" length into the buffer, starting from "position" byte. In the case when the buffer is too small it reallocs the buffer. The total size of the buffer is restricted with 16 Mb. @@ -81,7 +81,7 @@ int Buffer::reserve(uint position, uint len_arg) if (position + len_arg >= buffer_size) { - buffer= (char *) my_realloc(buffer, + buffer= (char*) my_realloc(buffer, min(MAX_BUFFER_SIZE, max((uint) (buffer_size*1.5), position + len_arg)), MYF(0)); diff --git a/server-tools/instance-manager/commands.cc b/server-tools/instance-manager/commands.cc index e1f811ef57d..d6d4370fb7f 100644 --- a/server-tools/instance-manager/commands.cc +++ b/server-tools/instance-manager/commands.cc @@ -25,6 +25,40 @@ #include <m_string.h> #include <mysql.h> +#include <my_dir.h> + + +/* + Add a string to a buffer + + SYNOPSYS + put_to_buff() + buff buffer to add the string + str string to add + uint offset in the buff to add a string + + DESCRIPTION + + Function to add a string to the buffer. It is different from + store_to_string, which is used in the protocol.cc. The last + one also stores the length of the string in a special way. + This is required for MySQL client/server protocol support only. + + RETURN + 0 - ok + 1 - error occured +*/ + + +static inline int put_to_buff(Buffer *buff, const char *str, uint *position) +{ + uint len= strlen(str); + if (buff->append(*position, str, len)) + return 1; + + *position+= len; + return 0; +} /* implementation for Show_instances: */ @@ -34,15 +68,16 @@ The method sends a list of instances in the instance map to the client. SYNOPSYS - Show_instances::do_command() - net The network connection to the client. + Show_instances::execute() + net The network connection to the client. + connection_id Client connection ID RETURN 0 - ok 1 - error occured */ -int Show_instances::do_command(struct st_net *net) +int Show_instances::execute(struct st_net *net, ulong connection_id) { Buffer send_buff; /* buffer for packets */ LIST name, status; @@ -50,11 +85,11 @@ int Show_instances::do_command(struct st_net *net) LIST *field_list; uint position=0; - name_field.name= (char *) "instance_name"; - name_field.length= 20; + name_field.name= (char*) "instance_name"; + name_field.length= DEFAULT_FIELD_LENGTH; name.data= &name_field; - status_field.name= (char *) "status"; - status_field.length= 20; + status_field.name= (char*) "status"; + status_field.length= DEFAULT_FIELD_LENGTH; status.data= &status_field; field_list= list_add(NULL, &status); field_list= list_add(field_list, &name); @@ -71,9 +106,9 @@ int Show_instances::do_command(struct st_net *net) position= 0; store_to_string(&send_buff, instance->options.instance_name, &position); if (instance->is_running()) - store_to_string(&send_buff, (char *) "online", &position); + store_to_string(&send_buff, (char*) "online", &position); else - store_to_string(&send_buff, (char *) "offline", &position); + store_to_string(&send_buff, (char*) "offline", &position); if (my_net_write(net, send_buff.buffer, (uint) position)) goto err; } @@ -86,16 +121,7 @@ int Show_instances::do_command(struct st_net *net) return 0; err: - return 1; -} - - -int Show_instances::execute(struct st_net *net, ulong connection_id) -{ - if (do_command(net)) - return ER_OUT_OF_RESOURCES; - - return 0; + return ER_OUT_OF_RESOURCES; } @@ -103,10 +129,10 @@ int Show_instances::execute(struct st_net *net, ulong connection_id) int Flush_instances::execute(struct st_net *net, ulong connection_id) { - if (instance_map->flush_instances()) + if (instance_map->flush_instances() || + net_send_ok(net, connection_id, NULL)) return ER_OUT_OF_RESOURCES; - net_send_ok(net, connection_id); return 0; } @@ -119,11 +145,9 @@ Show_instance_status::Show_instance_status(Instance_map *instance_map_arg, { Instance *instance; - /* we make a search here, since we don't want t store the name */ + /* we make a search here, since we don't want to store the name */ if ((instance= instance_map->find(name, len))) - { instance_name= instance->options.instance_name; - } else instance_name= NULL; } @@ -143,8 +167,8 @@ Show_instance_status::Show_instance_status(Instance_map *instance_map_arg, */ -int Show_instance_status::do_command(struct st_net *net, - const char *instance_name) +int Show_instance_status::execute(struct st_net *net, + ulong connection_id) { enum { MAX_VERSION_LENGTH= 40 }; Buffer send_buff; /* buffer for packets */ @@ -153,14 +177,17 @@ int Show_instance_status::do_command(struct st_net *net, NAME_WITH_LENGTH name_field, status_field, version_field; uint position=0; + if (!instance_name) + return ER_BAD_INSTANCE_NAME; + /* create list of the fileds to be passed to send_fields */ - name_field.name= (char *) "instance_name"; - name_field.length= 20; + name_field.name= (char*) "instance_name"; + name_field.length= DEFAULT_FIELD_LENGTH; name.data= &name_field; - status_field.name= (char *) "status"; - status_field.length= 20; + status_field.name= (char*) "status"; + status_field.length= DEFAULT_FIELD_LENGTH; status.data= &status_field; - version_field.name= (char *) "version"; + version_field.name= (char*) "version"; version_field.length= MAX_VERSION_LENGTH; version.data= &version_field; field_list= list_add(NULL, &version); @@ -172,18 +199,18 @@ int Show_instance_status::do_command(struct st_net *net, { Instance *instance; - store_to_string(&send_buff, (char *) instance_name, &position); + store_to_string(&send_buff, (char*) instance_name, &position); if (!(instance= instance_map->find(instance_name, strlen(instance_name)))) goto err; if (instance->is_running()) { - store_to_string(&send_buff, (char *) "online", &position); + store_to_string(&send_buff, (char*) "online", &position); store_to_string(&send_buff, "unknown", &position); } else { - store_to_string(&send_buff, (char *) "offline", &position); - store_to_string(&send_buff, (char *) "unknown", &position); + store_to_string(&send_buff, (char*) "offline", &position); + store_to_string(&send_buff, (char*) "unknown", &position); } @@ -192,28 +219,13 @@ int Show_instance_status::do_command(struct st_net *net, goto err; } - send_eof(net); - net_flush(net); + if (send_eof(net) || net_flush(net)) + goto err; return 0; err: - return 1; -} - - -int Show_instance_status::execute(struct st_net *net, ulong connection_id) -{ - if ((instance_name)) - { - if (do_command(net, instance_name)) - return ER_OUT_OF_RESOURCES; - return 0; - } - else - { - return ER_BAD_INSTANCE_NAME; - } + return ER_OUT_OF_RESOURCES; } @@ -225,32 +237,31 @@ Show_instance_options::Show_instance_options(Instance_map *instance_map_arg, { Instance *instance; - /* we make a search here, since we don't want t store the name */ + /* we make a search here, since we don't want to store the name */ if ((instance= instance_map->find(name, len))) - { instance_name= instance->options.instance_name; - } else instance_name= NULL; } -int Show_instance_options::do_command(struct st_net *net, - const char *instance_name) +int Show_instance_options::execute(struct st_net *net, ulong connection_id) { - enum { MAX_VERSION_LENGTH= 40 }; Buffer send_buff; /* buffer for packets */ LIST name, option; LIST *field_list; NAME_WITH_LENGTH name_field, option_field; uint position=0; + if (!instance_name) + return ER_BAD_INSTANCE_NAME; + /* create list of the fileds to be passed to send_fields */ - name_field.name= (char *) "option_name"; - name_field.length= 20; + name_field.name= (char*) "option_name"; + name_field.length= DEFAULT_FIELD_LENGTH; name.data= &name_field; - option_field.name= (char *) "value"; - option_field.length= 20; + option_field.name= (char*) "value"; + option_field.length= DEFAULT_FIELD_LENGTH; option.data= &option_field; field_list= list_add(NULL, &option); field_list= list_add(field_list, &name); @@ -262,16 +273,16 @@ int Show_instance_options::do_command(struct st_net *net, if (!(instance= instance_map->find(instance_name, strlen(instance_name)))) goto err; - store_to_string(&send_buff, (char *) "instance_name", &position); - store_to_string(&send_buff, (char *) instance_name, &position); + store_to_string(&send_buff, (char*) "instance_name", &position); + store_to_string(&send_buff, (char*) instance_name, &position); if (my_net_write(net, send_buff.buffer, (uint) position)) goto err; if ((instance->options.mysqld_path)) { position= 0; - store_to_string(&send_buff, (char *) "mysqld-path", &position); + store_to_string(&send_buff, (char*) "mysqld-path", &position); store_to_string(&send_buff, - (char *) instance->options.mysqld_path, + (char*) instance->options.mysqld_path, &position); if (send_buff.is_error() || my_net_write(net, send_buff.buffer, (uint) position)) @@ -281,7 +292,7 @@ int Show_instance_options::do_command(struct st_net *net, if ((instance->options.nonguarded)) { position= 0; - store_to_string(&send_buff, (char *) "nonguarded", &position); + store_to_string(&send_buff, (char*) "nonguarded", &position); store_to_string(&send_buff, "", &position); if (send_buff.is_error() || my_net_write(net, send_buff.buffer, (uint) position)) @@ -305,7 +316,8 @@ int Show_instance_options::do_command(struct st_net *net, /* join name and the value into the same option again */ *option_value= '='; } - else store_to_string(&send_buff, tmp_option + 2, &position); + else + store_to_string(&send_buff, tmp_option + 2, &position); if (send_buff.is_error() || my_net_write(net, send_buff.buffer, (uint) position)) @@ -313,28 +325,13 @@ int Show_instance_options::do_command(struct st_net *net, } } - send_eof(net); - net_flush(net); + if (send_eof(net) || net_flush(net)) + goto err; return 0; err: - return 1; -} - - -int Show_instance_options::execute(struct st_net *net, ulong connection_id) -{ - if ((instance_name)) - { - if (do_command(net, instance_name)) - return ER_OUT_OF_RESOURCES; - return 0; - } - else - { - return ER_BAD_INSTANCE_NAME; - } + return ER_OUT_OF_RESOURCES; } @@ -344,7 +341,7 @@ Start_instance::Start_instance(Instance_map *instance_map_arg, const char *name, uint len) :Command(instance_map_arg) { - /* we make a search here, since we don't want t store the name */ + /* we make a search here, since we don't want to store the name */ if ((instance= instance_map->find(name, len))) instance_name= instance->options.instance_name; } @@ -354,9 +351,7 @@ int Start_instance::execute(struct st_net *net, ulong connection_id) { uint err_code; if (instance == 0) - { return ER_BAD_INSTANCE_NAME; /* haven't found an instance */ - } else { if ((err_code= instance->start())) @@ -365,19 +360,408 @@ int Start_instance::execute(struct st_net *net, ulong connection_id) if (!(instance->options.nonguarded)) instance_map->guardian->guard(instance); - net_send_ok(net, connection_id); + net_send_ok(net, connection_id, "Instance started"); return 0; } } +/* implementation for Show_instance_log: */ + +Show_instance_log::Show_instance_log(Instance_map *instance_map_arg, + const char *name, uint len, + Log_type log_type_arg, + const char *size_arg, + const char *offset_arg) + :Command(instance_map_arg) +{ + Instance *instance; + + if (offset_arg != NULL) + offset= atoi(offset_arg); + else + offset= 0; + size= atoi(size_arg); + log_type= log_type_arg; + + /* we make a search here, since we don't want to store the name */ + if ((instance= instance_map->find(name, len))) + instance_name= instance->options.instance_name; + else + instance_name= NULL; +} + + + +/* + Open the logfile, read requested part of the log and send the info + to the client. + + SYNOPSYS + Show_instance_log::execute() + net The network connection to the client. + connection_id Client connection ID + + DESCRIPTION + + Send a table with the content of the log requested. The function also + deals with errro handling, to be verbose. + + RETURN + ER_OFFSET_ERROR We were requested to read negative number of bytes + from the log + ER_NO_SUCH_LOG The kind log being read is not enabled in the instance + ER_GUESS_LOGFILE IM wasn't able to figure out the log placement, while + it is enabled. Probably user should specify the path + to the logfile explicitly. + ER_OPEN_LOGFILE Cannot open the logfile + ER_READ_FILE Cannot read the logfile + ER_OUT_OF_RESOURCES We weren't able to allocate some resources +*/ + +int Show_instance_log::execute(struct st_net *net, ulong connection_id) +{ + Buffer send_buff; /* buffer for packets */ + LIST name; + LIST *field_list; + NAME_WITH_LENGTH name_field; + uint position= 0; + + /* create list of the fileds to be passed to send_fields */ + name_field.name= (char*) "Log"; + name_field.length= DEFAULT_FIELD_LENGTH; + name.data= &name_field; + field_list= list_add(NULL, &name); + + if (!instance_name) + return ER_BAD_INSTANCE_NAME; + + /* cannot read negative number of bytes */ + if (offset > size) + return ER_OFFSET_ERROR; + + send_fields(net, field_list); + + { + Instance *instance; + const char *logpath; + File fd; + + if ((instance= instance_map->find(instance_name, + strlen(instance_name))) == NULL) + goto err; + + logpath= instance->options.logs[log_type]; + + /* Instance has no such log */ + if (logpath == NULL) + return ER_NO_SUCH_LOG; + else if (*logpath == '\0') + return ER_GUESS_LOGFILE; + + + if ((fd= my_open(logpath, O_RDONLY | O_BINARY, MYF(MY_WME))) >= 0) + { + size_t buff_size; + int read_len; + /* calculate buffer size */ + struct stat file_stat; + + /* my_fstat doesn't use the flag parameter */ + if (my_fstat(fd, &file_stat, MYF(0))) + goto err; + + buff_size= (size - offset); + + /* read in one chunk */ + read_len= my_seek(fd, file_stat.st_size - size, MY_SEEK_SET, MYF(0)); + + char *bf= (char*) malloc(sizeof(char)*buff_size); + if ((read_len= my_read(fd, bf, buff_size, MYF(0))) < 0) + return ER_READ_FILE; + store_to_string(&send_buff, (char*) bf, &position, read_len); + close(fd); + } + else + return ER_OPEN_LOGFILE; + + if (my_net_write(net, send_buff.buffer, (uint) position)) + goto err; + } + + if (send_eof(net) || net_flush(net)) + goto err; + + return 0; + +err: + return ER_OUT_OF_RESOURCES; +} + + +/* implementation for Show_instance_log_files: */ + +Show_instance_log_files::Show_instance_log_files + (Instance_map *instance_map_arg, const char *name, uint len) + :Command(instance_map_arg) +{ + Instance *instance; + + /* we make a search here, since we don't want to store the name */ + if ((instance= instance_map->find(name, len))) + instance_name= instance->options.instance_name; + else + instance_name= NULL; +} + + +/* + The method sends a table with a list of log files + used by the instance. + + SYNOPSYS + Show_instance_log_files::execute() + net The network connection to the client. + connection_id The ID of the client connection + + RETURN + ER_BAD_INSTANCE_NAME The instance name specified is not valid + ER_OUT_OF_RESOURCES some error occured + 0 - ok +*/ + +int Show_instance_log_files::execute(struct st_net *net, ulong connection_id) +{ + Buffer send_buff; /* buffer for packets */ + LIST name, path, size; + LIST *field_list; + NAME_WITH_LENGTH name_field, path_field, size_field; + uint position= 0; + + if (!instance_name) + return ER_BAD_INSTANCE_NAME; + + /* create list of the fileds to be passed to send_fields */ + name_field.name= (char*) "Logfile"; + name_field.length= DEFAULT_FIELD_LENGTH; + name.data= &name_field; + path_field.name= (char*) "Path"; + path_field.length= DEFAULT_FIELD_LENGTH; + path.data= &path_field; + size_field.name= (char*) "Filesize"; + size_field.length= DEFAULT_FIELD_LENGTH; + size.data= &size_field; + field_list= list_add(NULL, &size); + field_list= list_add(field_list, &path); + field_list= list_add(field_list, &name); + + send_fields(net, field_list); + + Instance *instance; + + if ((instance= instance_map-> + find(instance_name, strlen(instance_name))) == NULL) + goto err; + { + /* + We have alike structure in instance_options.cc. We use such to be able + to loop through the options, which we need to handle in some common way. + */ + struct log_files_st + { + const char *name; + const char *value; + } logs[]= + { + {"ERROR LOG", instance->options.logs[LOG_ERROR]}, + {"GENERAL LOG", instance->options.logs[LOG_GENERAL]}, + {"SLOW LOG", instance->options.logs[LOG_SLOW]}, + {NULL, NULL} + }; + struct log_files_st *log_files; + + for (log_files= logs; log_files->name; log_files++) + { + if (log_files->value != NULL) + { + struct stat file_stat; + /* + Save some more space for the log file names. In fact all + we need is srtlen("GENERAL_LOG") + 1 + */ + enum { LOG_NAME_BUFFER_SIZE= 20 }; + char buff[LOG_NAME_BUFFER_SIZE]; + + position= 0; + /* store the type of the log in the send buffer */ + store_to_string(&send_buff, log_files->name, &position); + if (stat(log_files->value, &file_stat)) + { + store_to_string(&send_buff, "", &position); + store_to_string(&send_buff, (char*) "0", &position); + } + else if (S_ISREG(file_stat.st_mode)) + { + store_to_string(&send_buff, + (char*) log_files->value, + &position); + int10_to_str(file_stat.st_size, buff, 10); + store_to_string(&send_buff, (char*) buff, &position); + } + + if (my_net_write(net, send_buff.buffer, (uint) position)) + goto err; + } + } + } + + if (send_eof(net) || net_flush(net)) + goto err; + + return 0; + +err: + return ER_OUT_OF_RESOURCES; +} + + +/* implementation for SET instance_name.option=option_value: */ + +Set_option::Set_option(Instance_map *instance_map_arg, + const char *name, uint len, + const char *option_arg, uint option_len_arg, + const char *option_value_arg, uint option_value_len_arg) + :Command(instance_map_arg) +{ + Instance *instance; + + /* we make a search here, since we don't want to store the name */ + if ((instance= instance_map->find(name, len))) + { + instance_name= instance->options.instance_name; + /* add prefix for add_option */ + if ((option_len_arg < MAX_OPTION_LEN - 1) || + (option_value_len_arg < MAX_OPTION_LEN - 1)) + { + strmake(option, option_arg, option_len_arg); + strmake(option_value, option_value_arg, option_value_len_arg); +/* strncpy(option, option_arg, option_len_arg); + option[option_len_arg]= 0; + strncpy(option_value, option_value_arg, option_value_len_arg); + option_value[option_value_len_arg]= 0; */ + } + else + { + option[0]= 0; + option_value[0]= 0; + } + instance_name_len= len; + } + else + { + instance_name= NULL; + instance_name_len= 0; + } +} + + +/* + The method sends a table with a list of log files + used by the instance. + + SYNOPSYS + Set_option::correct_file() + skip Skip the option, being searched while writing the result file. + That is, to delete it. + + DESCRIPTION + + Correct the option file. The "skip" option is used to remove the found + option. + + RETURN + ER_BAD_INSTANCE_NAME The instance name specified is not valid + ER_ACCESS_OPTION_FILE Cannot access the option file + 0 - ok +*/ + +int Set_option::correct_file(int skip) +{ + int error; + + error= my_correct_defaults_file("/etc/my.cnf", option, + option_value, instance_name, skip); + if (error > 0) + return ER_OUT_OF_RESOURCES; + else if (error < 0) + return ER_ACCESS_OPTION_FILE; + + /* everything was fine */ + return 0; +} + + +/* + The method sets an option in the the default config file (/etc/my.cnf). + + SYNOPSYS + Set_option::do_command() + net The network connection to the client. + + RETURN + 0 - ok + 1 - error occured +*/ + + +int Set_option::do_command(struct st_net *net) +{ + int error= 0; + + /* we must hold the instance_map mutex while changing config file */ + instance_map->lock(); + error= correct_file(FALSE); + instance_map->unlock(); + + return error; +} + + +int Set_option::execute(struct st_net *net, ulong connection_id) +{ + if (instance_name != NULL) + { + int val; + + val= do_command(net); + if (val == 0) + { + net_send_ok(net, connection_id, NULL); + return 0; + } + + return val; + } + else + return ER_BAD_INSTANCE_NAME; +} + + +/* the only function from Unset_option we need to Implement */ + +int Unset_option::do_command(struct st_net *net) +{ + return correct_file(TRUE); +} + + /* Implementation for Stop_instance: */ Stop_instance::Stop_instance(Instance_map *instance_map_arg, const char *name, uint len) :Command(instance_map_arg) { - /* we make a search here, since we don't want t store the name */ + /* we make a search here, since we don't want to store the name */ if ((instance= instance_map->find(name, len))) instance_name= instance->options.instance_name; } @@ -388,9 +772,7 @@ int Stop_instance::execute(struct st_net *net, ulong connection_id) uint err_code; if (instance == 0) - { return ER_BAD_INSTANCE_NAME; /* haven't found an instance */ - } else { if (!(instance->options.nonguarded)) @@ -398,7 +780,7 @@ int Stop_instance::execute(struct st_net *net, ulong connection_id) stop_guard(instance); if ((err_code= instance->stop())) return err_code; - net_send_ok(net, connection_id); + net_send_ok(net, connection_id, NULL); return 0; } } diff --git a/server-tools/instance-manager/commands.h b/server-tools/instance-manager/commands.h index bab67f9c6b4..bfd38d34889 100644 --- a/server-tools/instance-manager/commands.h +++ b/server-tools/instance-manager/commands.h @@ -18,6 +18,7 @@ #include "command.h" #include "instance.h" +#include "parse.h" /* Print all instances of this instance manager. @@ -30,7 +31,6 @@ public: Show_instances(Instance_map *instance_map_arg): Command(instance_map_arg) {} - int do_command(struct st_net *net); int execute(struct st_net *net, ulong connection_id); }; @@ -59,8 +59,8 @@ class Show_instance_status : public Command { public: - Show_instance_status(Instance_map *instance_map_arg, const char *name, uint len); - int do_command(struct st_net *net, const char *instance_name); + Show_instance_status(Instance_map *instance_map_arg, + const char *name, uint len); int execute(struct st_net *net, ulong connection_id); const char *instance_name; }; @@ -75,10 +75,10 @@ class Show_instance_options : public Command { public: - Show_instance_options(Instance_map *instance_map_arg, const char *name, uint len); + Show_instance_options(Instance_map *instance_map_arg, + const char *name, uint len); int execute(struct st_net *net, ulong connection_id); - int do_command(struct st_net *net, const char *instance_name); const char *instance_name; }; @@ -116,10 +116,48 @@ public: /* - Syntax error command. This command is issued if parser reported a syntax error. - We need it to distinguish the parse error and the situation when parser internal - error occured. E.g. parsing failed because we hadn't had enought memory. In the - latter case parse_command() should return an error. + Print requested part of the log + Grammar: + SHOW <instance_name> log {ERROR | SLOW | GENERAL} size[, offset_from_end] +*/ + +class Show_instance_log : public Command +{ +public: + + Show_instance_log(Instance_map *instance_map_arg, const char *name, + uint len, Log_type log_type_arg, const char *size_arg, + const char *offset_arg); + int execute(struct st_net *net, ulong connection_id); + Log_type log_type; + const char *instance_name; + uint size; + uint offset; +}; + + +/* + Shows the list of the log files, used by an instance. + Grammar: SHOW <instance_name> LOG FILES +*/ + +class Show_instance_log_files : public Command +{ +public: + + Show_instance_log_files(Instance_map *instance_map_arg, + const char *name, uint len); + int execute(struct st_net *net, ulong connection_id); + const char *instance_name; + const char *option; +}; + + +/* + Syntax error command. This command is issued if parser reported a syntax + error. We need it to distinguish the parse error and the situation when + parser internal error occured. E.g. parsing failed because we hadn't had + enought memory. In the latter case parse_command() should return an error. */ class Syntax_error : public Command @@ -128,4 +166,50 @@ public: int execute(struct st_net *net, ulong connection_id); }; +/* + Set an option for the instance. + Grammar: SET instance_name.option=option_value +*/ + +class Set_option : public Command +{ +public: + Set_option(Instance_map *instance_map_arg, const char *name, uint len, + const char *option_arg, uint option_len, + const char *option_value_arg, uint option_value_len); + /* + the following function is virtual to let Unset_option to use + */ + virtual int do_command(struct st_net *net); + int execute(struct st_net *net, ulong connection_id); +protected: + int correct_file(int skip); +public: + const char *instance_name; + uint instance_name_len; + /* buffer for the option */ + enum { MAX_OPTION_LEN= 1024 }; + char option[MAX_OPTION_LEN]; + char option_value[MAX_OPTION_LEN]; +}; + + +/* + Remove option of the instance from config file + Grammar: UNSET instance_name.option +*/ + +class Unset_option: public Set_option +{ +public: + Unset_option(Instance_map *instance_map_arg, const char *name, uint len, + const char *option_arg, uint option_len, + const char *option_value_arg, uint option_value_len): + Set_option(instance_map_arg, name, len, option_arg, option_len, + option_value_arg, option_value_len) + {} + int do_command(struct st_net *net); +}; + + #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_COMMANDS_H */ diff --git a/server-tools/instance-manager/factory.cc b/server-tools/instance-manager/factory.cc index 538d9353983..58ac32a9feb 100644 --- a/server-tools/instance-manager/factory.cc +++ b/server-tools/instance-manager/factory.cc @@ -16,40 +16,85 @@ #include "factory.h" + Show_instances *Command_factory::new_Show_instances() { return new Show_instances(&instance_map); } + Flush_instances *Command_factory::new_Flush_instances() { return new Flush_instances(&instance_map); } + Show_instance_status *Command_factory:: new_Show_instance_status(const char *name, uint len) { return new Show_instance_status(&instance_map, name, len); } + Show_instance_options *Command_factory:: new_Show_instance_options(const char *name, uint len) { return new Show_instance_options(&instance_map, name, len); } + Start_instance *Command_factory:: new_Start_instance(const char *name, uint len) { return new Start_instance(&instance_map, name, len); } + Stop_instance *Command_factory::new_Stop_instance(const char *name, uint len) { return new Stop_instance(&instance_map, name, len); } + Syntax_error *Command_factory::new_Syntax_error() { return new Syntax_error(); } + + +Set_option *Command_factory:: + new_Set_option(const char* name, uint len, + const char *option_arg, uint option_len, + const char *option_value_arg, uint option_value_len) +{ + return new Set_option(&instance_map, name, len, option_arg, + option_len, option_value_arg, option_value_len); +} + + +Unset_option *Command_factory:: + new_Unset_option(const char* name, uint len, + const char *option_arg, uint option_len, + const char *option_value_arg, uint option_value_len) +{ + return new Unset_option(&instance_map, name, len, option_arg, + option_len, option_value_arg, option_value_len); +} + + +Show_instance_log *Command_factory:: + new_Show_instance_log(const char *name, uint len, + Log_type log_type_arg, + const char *size, const char *offset) +{ + return new Show_instance_log(&instance_map, name, len, + log_type_arg, size, offset); +} + + +Show_instance_log_files *Command_factory:: + new_Show_instance_log_files(const char *name, uint len) +{ + return new Show_instance_log_files(&instance_map, name, len); +} + diff --git a/server-tools/instance-manager/factory.h b/server-tools/instance-manager/factory.h index 0a1b955d156..14073eb5007 100644 --- a/server-tools/instance-manager/factory.h +++ b/server-tools/instance-manager/factory.h @@ -26,6 +26,8 @@ Http_command_factory e.t.c. Also see comment in the instance_map.cc */ +class Show_instances; + class Command_factory { public: @@ -33,12 +35,26 @@ public: {} Show_instances *new_Show_instances (); + Flush_instances *new_Flush_instances (); + Syntax_error *new_Syntax_error (); Show_instance_status *new_Show_instance_status (const char *name, uint len); Show_instance_options *new_Show_instance_options (const char *name, uint len); Start_instance *new_Start_instance (const char *name, uint len); Stop_instance *new_Stop_instance (const char *name, uint len); - Flush_instances *new_Flush_instances (); - Syntax_error *new_Syntax_error (); + Show_instance_log *new_Show_instance_log (const char *name, uint len, + Log_type log_type_arg, + const char *size, + const char *offset); + Set_option *new_Set_option (const char *name, uint len, + const char *option_arg, uint option_len, + const char *option_value_arg, + uint option_value_len); + Unset_option *new_Unset_option (const char *name, uint len, + const char *option_arg, uint option_len, + const char *option_value_arg, + uint option_value_len); + Show_instance_log_files *new_Show_instance_log_files (const char *name, + uint len); Instance_map &instance_map; }; diff --git a/server-tools/instance-manager/guardian.cc b/server-tools/instance-manager/guardian.cc index 5d89f167f2f..404e9f34ab5 100644 --- a/server-tools/instance-manager/guardian.cc +++ b/server-tools/instance-manager/guardian.cc @@ -315,7 +315,7 @@ int Guardian_thread::guard(Instance *instance, bool nolock) content->restart_counter= 0; content->crash_moment= 0; content->state= NOT_STARTED; - node->data= (void *) content; + node->data= (void*) content; if (nolock) guarded_instances= list_add(guarded_instances, node); diff --git a/server-tools/instance-manager/instance.cc b/server-tools/instance-manager/instance.cc index 9fdcab7ce7c..615f16f9e22 100644 --- a/server-tools/instance-manager/instance.cc +++ b/server-tools/instance-manager/instance.cc @@ -304,12 +304,11 @@ void Instance::kill_instance(int signum) */ if (!kill(pid, signum)) options.unlink_pidfile(); - else - if (signum == SIGKILL) /* really killed instance with SIGKILL */ - log_error("The instance %s is being stopped forsibly. Normally \ - it should not happed. Probably the instance has been \ - hanging. You should also check your IM setup", - options.instance_name); + else if (signum == SIGKILL) /* really killed instance with SIGKILL */ + log_error("The instance %s is being stopped forsibly. Normally \ + it should not happed. Probably the instance has been \ + hanging. You should also check your IM setup", + options.instance_name); } return; } diff --git a/server-tools/instance-manager/instance_map.cc b/server-tools/instance-manager/instance_map.cc index 3e76c24a9a1..792ffff5fb6 100644 --- a/server-tools/instance-manager/instance_map.cc +++ b/server-tools/instance-manager/instance_map.cc @@ -246,7 +246,7 @@ int Instance_map::load() argv_options[1]= '\0'; if (my_search_option_files("my", &argc, (char ***) &argv, &args_used, - process_option, (void *) this) || + process_option, (void*) this) || complete_initialization()) return 1; diff --git a/server-tools/instance-manager/instance_options.cc b/server-tools/instance-manager/instance_options.cc index 0d602f88ad2..b2602af6066 100644 --- a/server-tools/instance-manager/instance_options.cc +++ b/server-tools/instance-manager/instance_options.cc @@ -24,7 +24,6 @@ #include "buffer.h" #include <my_sys.h> -#include <mysql.h> #include <signal.h> #include <m_string.h> @@ -36,7 +35,7 @@ get_default_option() result buffer to put found value result_len buffer size - oprion_name the name of the option, prefixed with "--" + option_name the name of the option, prefixed with "--" DESCRIPTION @@ -47,6 +46,7 @@ 1 - error occured */ + int Instance_options::get_default_option(char *result, size_t result_len, const char *option_name) { @@ -54,7 +54,7 @@ int Instance_options::get_default_option(char *result, size_t result_len, int rc= 1; char verbose_option[]= " --no-defaults --verbose --help"; - Buffer cmd(strlen(mysqld_path)+sizeof(verbose_option)+1); + Buffer cmd(strlen(mysqld_path) + sizeof(verbose_option) + 1); if (cmd.get_size()) /* malloc succeeded */ { cmd.append(position, mysqld_path, strlen(mysqld_path)); @@ -76,6 +76,146 @@ err: } +/* + Get compiled-in value of default_option + + SYNOPSYS + get_default_option() + result buffer to put found value + result_len buffer size + option_name the name of the option, prefixed with "--" + + DESCRIPTION + + Get compile-in value of requested option from server + + RETURN + 0 - ok + 1 - error occured +*/ + +int Instance_options::fill_log_options() +{ + Buffer buff; + uint position= 0; + char **tmp_argv= argv; + enum { MAX_LOG_OPTION_LENGTH= 256 }; + char datadir[MAX_LOG_OPTION_LENGTH]; + char hostname[MAX_LOG_OPTION_LENGTH]; + uint hostname_length; + struct log_files_st + { + const char *name; + uint length; + char **value; + const char *default_suffix; + } logs_st[]= + { + {"--log-error", 11, &(logs[LOG_ERROR]), ".err"}, + {"--log", 5, &(logs[LOG_GENERAL]), ".log"}, + {"--log-slow-queries", 18, &(logs[LOG_SLOW]), "-slow.log"}, + {NULL, 0, NULL, NULL} + }; + struct log_files_st *log_files; + + /* compute hostname and datadir for the instance */ + if (mysqld_datadir == NULL) + { + if (get_default_option(datadir, + MAX_LOG_OPTION_LENGTH, "--datadir")) + goto err; + } + else /* below is safe, as --datadir always has a value */ + strncpy(datadir, strchr(mysqld_datadir, '=') + 1, + MAX_LOG_OPTION_LENGTH); + + if (gethostname(hostname,sizeof(hostname)-1) < 0) + strmov(hostname, "mysql"); + + hostname[MAX_LOG_OPTION_LENGTH - 1]= 0; /* Safety */ + hostname_length= strlen(hostname); + + + for (log_files= logs_st; log_files->name; log_files++) + { + for (int i=0; (argv[i] != 0); i++) + { + if (!strncmp(argv[i], log_files->name, log_files->length)) + { + /* + This is really log_files->name option if and only if it is followed + by '=', '\0' or space character. This way we can distinguish such + options as '--log' and '--log-bin'. This is checked in the following + two statements. + */ + if (argv[i][log_files->length] == '\0' || + my_isspace(default_charset_info, argv[i][log_files->length])) + { + char full_name[MAX_LOG_OPTION_LENGTH]; + + fn_format(full_name, hostname, datadir, "", + MY_UNPACK_FILENAME | MY_SAFE_PATH); + + + if ((MAX_LOG_OPTION_LENGTH - strlen(full_name)) > + strlen(log_files->default_suffix)) + { + strcpy(full_name + strlen(full_name), + log_files->default_suffix); + } + else + goto err; + + /* + If there were specified two identical logfiles options, + we would loose some memory in MEM_ROOT here. However + this situation is not typical. + */ + *(log_files->value)= strdup_root(&alloc, full_name); + } + + if (argv[i][log_files->length] == '=') + { + char full_name[MAX_LOG_OPTION_LENGTH]; + + fn_format(full_name, argv[i] +log_files->length + 1, + datadir, "", MY_UNPACK_FILENAME | MY_SAFE_PATH); + + if (!(*(log_files->value)= + strdup_root(&alloc, full_name))) + goto err; + } + } + } + } + + return 0; + +err: + return 1; + +} + + +/* + Get the full pid file name with path + + SYNOPSYS + get_pid_filaname() + result buffer to sotre the pidfile value + + IMPLEMENTATION + Get the data directory, then get the pid filename + (which is always set for an instance), then load the + full path with my_load_path(). It takes into account + whether it is already an absolute path or it should be + prefixed with the datadir and so on. + + RETURN + 0 - ok + 1 - error occured +*/ + int Instance_options::get_pid_filename(char *result) { const char *pid_file= mysqld_pid_file; @@ -190,6 +330,8 @@ int Instance_options::complete_initialization(const char *default_path, options_array.elements*sizeof(char*)); argv[filled_default_options + options_array.elements]= 0; + fill_log_options(); + return 0; err: @@ -274,7 +416,7 @@ int Instance_options::add_to_argv(const char* option) DBUG_ASSERT(filled_default_options < MAX_NUMBER_OF_DEFAULT_OPTIONS); if ((option)) - argv[filled_default_options++]= (char *) option; + argv[filled_default_options++]= (char*) option; return 0; } @@ -302,10 +444,10 @@ int Instance_options::init(const char *instance_name_arg) init_alloc_root(&alloc, MEM_ROOT_BLOCK_SIZE, 0); - if (my_init_dynamic_array(&options_array, sizeof(char *), 0, 32)) + if (my_init_dynamic_array(&options_array, sizeof(char*), 0, 32)) goto err; - if (!(instance_name= strmake_root(&alloc, (char *) instance_name_arg, + if (!(instance_name= strmake_root(&alloc, (char*) instance_name_arg, instance_name_len))) goto err; diff --git a/server-tools/instance-manager/instance_options.h b/server-tools/instance-manager/instance_options.h index 06ad0156bc0..ebeeaa1978e 100644 --- a/server-tools/instance-manager/instance_options.h +++ b/server-tools/instance-manager/instance_options.h @@ -18,6 +18,7 @@ #include <my_global.h> #include <my_sys.h> +#include "parse.h" #ifdef __GNUC__ #pragma interface @@ -76,9 +77,13 @@ public: const char *nonguarded; const char *shutdown_delay; uint shutdown_delay_val; + /* log enums are defined in parse.h */ + char *logs[3]; + /* this value is computed and cashed here */ DYNAMIC_ARRAY options_array; private: + int fill_log_options(); int add_to_argv(const char *option); int get_default_option(char *result, size_t result_len, const char *option_name); diff --git a/server-tools/instance-manager/listener.cc b/server-tools/instance-manager/listener.cc index 946bab11a2e..98f5b64ca92 100644 --- a/server-tools/instance-manager/listener.cc +++ b/server-tools/instance-manager/listener.cc @@ -241,23 +241,20 @@ void Listener_thread::run() } } } - else - if (FD_ISSET(ip_socket, &read_fds_arg)) + else if (FD_ISSET(ip_socket, &read_fds_arg)) + { + int client_fd= accept(ip_socket, 0, 0); + /* accept may return -1 (failure or spurious wakeup) */ + if (client_fd >= 0) // connection established { - int client_fd= accept(ip_socket, 0, 0); - /* accept may return -1 (failure or spurious wakeup) */ - if (client_fd >= 0) // connection established + if (Vio *vio= vio_new(client_fd, VIO_TYPE_TCPIP, 0)) + handle_new_mysql_connection(vio); + else { - if (Vio *vio= vio_new(client_fd, VIO_TYPE_TCPIP, 0)) - { - handle_new_mysql_connection(vio); - } - else - { - shutdown(client_fd, SHUT_RDWR); - close(client_fd); - } + shutdown(client_fd, SHUT_RDWR); + close(client_fd); } + } } } } diff --git a/server-tools/instance-manager/log.cc b/server-tools/instance-manager/log.cc index 5491b4e70e9..88d777eeeb6 100644 --- a/server-tools/instance-manager/log.cc +++ b/server-tools/instance-manager/log.cc @@ -70,7 +70,7 @@ static inline void log(FILE *file, const char *format, va_list args) if (n < 0 || n == sizeof(buff_stack)) { int size= sizeof(buff_stack) * 2; - buff_msg= (char *) my_malloc(size, 0); + buff_msg= (char*) my_malloc(size, MYF(0)); while (true) { if (buff_msg == 0) @@ -86,16 +86,16 @@ static inline void log(FILE *file, const char *format, va_list args) size*= 2; /* realloc() does unnecessary memcpy */ my_free(buff_msg, 0); - buff_msg= (char *) my_malloc(size, 0); + buff_msg= (char*) my_malloc(size, MYF(0)); } } else if ((size_t) n > sizeof(buff_stack)) { - buff_msg= (char *) my_malloc(n + 1, 0); + buff_msg= (char*) my_malloc(n + 1, MYF(0)); #ifdef DBUG DBUG_ASSERT(n == vsnprintf(buff_msg, n + 1, format, args)); #else - vsnprintf(buff_msg, n + 1, format, args); + vsnprintf(buff_msg, n + 1, format, args); #endif } fprintf(file, "%s%s\n", buff_date, buff_msg); diff --git a/server-tools/instance-manager/manager.cc b/server-tools/instance-manager/manager.cc index fd8673c4d66..a4c81739b17 100644 --- a/server-tools/instance-manager/manager.cc +++ b/server-tools/instance-manager/manager.cc @@ -197,8 +197,7 @@ void manager(const Options &options) goto err; } - switch (signo) - { + switch (signo) { case THR_SERVER_ALARM: process_alarm(signo); break; diff --git a/server-tools/instance-manager/messages.cc b/server-tools/instance-manager/messages.cc index d044c0f65db..a9b00b9e01f 100644 --- a/server-tools/instance-manager/messages.cc +++ b/server-tools/instance-manager/messages.cc @@ -55,8 +55,21 @@ static const char *mysqld_error_message(unsigned sql_errno) case ER_CANNOT_START_INSTANCE: return "Cannot start instance. Possible reasons are wrong instance options" " or resources shortage"; + case ER_OFFSET_ERROR: + return "Cannot read negative number of bytes"; case ER_STOP_INSTANCE: return "Cannot stop instance"; + case ER_READ_FILE: + return "Cannot read requested part of the logfile"; + case ER_NO_SUCH_LOG: + return "The instance has no such log enabled"; + case ER_OPEN_LOGFILE: + return "Cannot open log file"; + case ER_GUESS_LOGFILE: + return "Cannot guess the log filename. Try specifying full log name" + "in the instance options"; + case ER_ACCESS_OPTION_FILE: + return "Cannot open the option file to edit. Check permissions"; default: DBUG_ASSERT(0); return 0; diff --git a/server-tools/instance-manager/mysql_connection.cc b/server-tools/instance-manager/mysql_connection.cc index 215dbe51b58..05fb6d4e0fb 100644 --- a/server-tools/instance-manager/mysql_connection.cc +++ b/server-tools/instance-manager/mysql_connection.cc @@ -261,10 +261,10 @@ int Mysql_connection_thread::check_connection() } client_capabilities|= ((ulong) uint2korr(net.read_pos + 2)) << 16; - pos= (char *) net.read_pos + 32; + pos= (char*) net.read_pos + 32; /* At least one byte for username and one byte for password */ - if (pos >= (char *) net.read_pos + pkt_len + 2) + if (pos >= (char*) net.read_pos + pkt_len + 2) { /*TODO add user and password handling in error messages*/ net_send_error(&net, ER_HANDSHAKE_ERROR); @@ -284,7 +284,7 @@ int Mysql_connection_thread::check_connection() net_send_error(&net, ER_ACCESS_DENIED_ERROR); return 1; } - net_send_ok(&net, connection_id); + net_send_ok(&net, connection_id, NULL); return 0; } @@ -301,9 +301,7 @@ int Mysql_connection_thread::do_command() { /* Check if we can continue without closing the connection */ if (net.error != 3) // what is 3 - find out - { return 1; - } if (thread_registry.is_shutdown()) return 1; net_send_error(&net, net.last_errno); @@ -332,7 +330,7 @@ int Mysql_connection_thread::dispatch_command(enum enum_server_command command, return 1; case COM_PING: log_info("query for connection %d received ping command", connection_id); - net_send_ok(&net, connection_id); + net_send_ok(&net, connection_id, NULL); break; case COM_QUERY: { @@ -346,14 +344,12 @@ int Mysql_connection_thread::dispatch_command(enum enum_server_command command, res= command->execute(&net, connection_id); delete command; if (!res) - { - log_info("query for connection %d executed ok",connection_id); - } + log_info("query for connection %d executed ok",connection_id); else { - log_info("query for connection %d executed err=%d",connection_id,res); - net_send_error(&net, res); - return 0; + log_info("query for connection %d executed err=%d",connection_id,res); + net_send_error(&net, res); + return 0; } } else diff --git a/server-tools/instance-manager/mysql_manager_error.h b/server-tools/instance-manager/mysql_manager_error.h index 2862e01649d..ff782923a8e 100644 --- a/server-tools/instance-manager/mysql_manager_error.h +++ b/server-tools/instance-manager/mysql_manager_error.h @@ -23,5 +23,11 @@ #define ER_INSTANCE_ALREADY_STARTED 3002 #define ER_CANNOT_START_INSTANCE 3003 #define ER_STOP_INSTANCE 3004 +#define ER_NO_SUCH_LOG 3005 +#define ER_OPEN_LOGFILE 3006 +#define ER_GUESS_LOGFILE 3007 +#define ER_ACCESS_OPTION_FILE 3008 +#define ER_OFFSET_ERROR 3009 +#define ER_READ_FILE 3010 #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_MYSQL_MANAGER_ERROR_H */ diff --git a/server-tools/instance-manager/mysqlmanager.cc b/server-tools/instance-manager/mysqlmanager.cc index 262686c3fab..5a6c398614b 100644 --- a/server-tools/instance-manager/mysqlmanager.cc +++ b/server-tools/instance-manager/mysqlmanager.cc @@ -136,7 +136,8 @@ static struct passwd *check_user(const char *user) { /* Allow a numeric uid to be used */ const char *pos; - for (pos= user; my_isdigit(default_charset_info, *pos); pos++) ; + for (pos= user; my_isdigit(default_charset_info, *pos); pos++) + {} if (*pos) /* Not numeric id */ goto err; if (!(user_info= getpwuid(atoi(user)))) diff --git a/server-tools/instance-manager/options.cc b/server-tools/instance-manager/options.cc index 4568d6b578d..28899940e47 100644 --- a/server-tools/instance-manager/options.cc +++ b/server-tools/instance-manager/options.cc @@ -158,7 +158,7 @@ static void passwd() fprintf(stderr, "Creating record for new user.\n"); fprintf(stderr, "Enter user name: "); - if (! fgets(user, sizeof(user), stdin)) + if (!fgets(user, sizeof(user), stdin)) { fprintf(stderr, "Unable to read user.\n"); return; diff --git a/server-tools/instance-manager/parse.cc b/server-tools/instance-manager/parse.cc index d3fb10b7c94..fae69375b61 100644 --- a/server-tools/instance-manager/parse.cc +++ b/server-tools/instance-manager/parse.cc @@ -15,38 +15,56 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "parse.h" +#include "factory.h" #include <string.h> + enum Token { - TOK_FLUSH = 0, + TOK_ERROR= 0, /* Encodes the "ERROR" word, it doesn't indicate error. */ + TOK_FILES, + TOK_FLUSH, + TOK_GENERAL, TOK_INSTANCE, TOK_INSTANCES, + TOK_LOG, TOK_OPTIONS, + TOK_SET, + TOK_SLOW, TOK_START, TOK_STATUS, TOK_STOP, TOK_SHOW, + TOK_UNSET, TOK_NOT_FOUND, // must be after all tokens TOK_END }; + struct tokens_st { uint length; const char *tok_name; }; + static struct tokens_st tokens[]= { + {5, "ERROR"}, + {5, "FILES"}, {5, "FLUSH"}, + {7, "GENERAL"}, {8, "INSTANCE"}, {9, "INSTANCES"}, + {3, "LOG"}, {7, "OPTIONS"}, + {3, "SET"}, + {4, "SLOW"}, {5, "START"}, {6, "STATUS"}, {4, "STOP"}, - {4, "SHOW"} + {4, "SHOW"}, + {5, "UNSET"} }; @@ -86,13 +104,6 @@ Token shift_token(const char **text, uint *word_len) } -void print_token(const char *token, uint tok_len) -{ - for (uint i= 0; i < tok_len; ++i) - printf("%c", token[i]); -} - - int get_text_id(const char **text, uint *word_len, const char **id) { get_word(text, word_len); @@ -108,7 +119,15 @@ Command *parse_command(Command_factory *factory, const char *text) uint word_len; const char *instance_name; uint instance_name_len; + const char *option; + uint option_len; + const char *option_value; + uint option_value_len; + const char *log_size; Command *command; + const char *saved_text= text; + bool skip= false; + const char *tmp; Token tok1= shift_token(&text, &word_len); @@ -143,6 +162,53 @@ Command *parse_command(Command_factory *factory, const char *text) command= factory->new_Flush_instances(); break; + case TOK_UNSET: + skip= true; + case TOK_SET: + + get_text_id(&text, &instance_name_len, &instance_name); + text+= instance_name_len; + + /* the next token should be a dot */ + get_word(&text, &word_len); + if (*text != '.') + goto syntax_error; + text++; + + get_word(&text, &option_len, NONSPACE); + option= text; + if ((tmp= strchr(text, '=')) != NULL) + option_len= tmp - text; + text+= option_len; + + get_word(&text, &word_len); + if (*text == '=') + { + text++; /* skip '=' */ + get_word(&text, &option_value_len, NONSPACE); + option_value= text; + text+= option_value_len; + } + else + { + option_value= ""; + option_value_len= 0; + } + + /* should be empty */ + get_word(&text, &word_len); + if (word_len) + goto syntax_error; + + if (skip) + command= factory->new_Unset_option(instance_name, instance_name_len, + option, option_len, option_value, + option_value_len); + else + command= factory->new_Set_option(instance_name, instance_name_len, + option, option_len, option_value, + option_value_len); + break; case TOK_SHOW: switch (shift_token(&text, &word_len)) { case TOK_INSTANCES: @@ -157,6 +223,7 @@ Command *parse_command(Command_factory *factory, const char *text) case TOK_STATUS: get_text_id(&text, &instance_name_len, &instance_name); text+= instance_name_len; + /* check that this is the end of the command */ get_word(&text, &word_len); if (word_len) goto syntax_error; @@ -172,7 +239,87 @@ Command *parse_command(Command_factory *factory, const char *text) } break; default: - goto syntax_error; + instance_name= text - word_len; + instance_name_len= word_len; + if (instance_name_len) + { + Log_type log_type; + switch (shift_token(&text, &word_len)) { + case TOK_LOG: + switch (Token tok3= shift_token(&text, &word_len)) { + case TOK_FILES: + get_word(&text, &word_len); + /* check that this is the end of the command */ + if (word_len) + goto syntax_error; + command= (Command *) + factory->new_Show_instance_log_files(instance_name, + instance_name_len); + break; + case TOK_ERROR: + case TOK_GENERAL: + case TOK_SLOW: + /* define a log type */ + switch (tok3) { + case TOK_ERROR: + log_type= LOG_ERROR; + break; + case TOK_GENERAL: + log_type= LOG_GENERAL; + break; + case TOK_SLOW: + log_type= LOG_SLOW; + break; + default: + goto syntax_error; + } + /* get the size of the log we want to retrieve */ + get_text_id(&text, &word_len, &log_size); + text+= word_len; + /* this parameter is required */ + if (!word_len) + goto syntax_error; + /* the next token should be comma, or nothing */ + get_word(&text, &word_len); + switch (*text) { + case ',': + text++; /* swallow the comma */ + /* read the next word */ + get_word(&text, &word_len); + if (!word_len) + goto syntax_error; + command= (Command *) + factory->new_Show_instance_log(instance_name, + instance_name_len, + log_type, + log_size, + text); + + //get_text_id(&text, &log_size_len, &log_size); + break; + case '\0': + command= (Command *) + factory->new_Show_instance_log(instance_name, + instance_name_len, + log_type, + log_size, + NULL); + break; /* this is ok */ + default: + goto syntax_error; + } + break; + default: + goto syntax_error; + } + break; + default: + goto syntax_error; + } + } + else + goto syntax_error; + break; } break; default: @@ -181,4 +328,3 @@ syntax_error: } return command; } - diff --git a/server-tools/instance-manager/parse.h b/server-tools/instance-manager/parse.h index 92519893302..0cfa33723c9 100644 --- a/server-tools/instance-manager/parse.h +++ b/server-tools/instance-manager/parse.h @@ -16,7 +16,18 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "factory.h" +#include <my_global.h> +#include <my_sys.h> + +class Command; +class Command_factory; + +enum Log_type +{ + LOG_ERROR= 0, + LOG_GENERAL, + LOG_SLOW +}; Command *parse_command(Command_factory *factory, const char *text); @@ -44,10 +55,12 @@ inline void get_word(const char **text, uint *word_len, while (my_isalnum(default_charset_info, *word_end)) ++word_end; else - while (!my_isspace(default_charset_info, *word_end)) + while (!my_isspace(default_charset_info, *word_end) && + (*word_end != '\0')) ++word_end; *word_len= word_end - *text; } + #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_H */ diff --git a/server-tools/instance-manager/parse_output.cc b/server-tools/instance-manager/parse_output.cc index 77fa40ca352..d6adb8079ce 100644 --- a/server-tools/instance-manager/parse_output.cc +++ b/server-tools/instance-manager/parse_output.cc @@ -47,7 +47,7 @@ int parse_output_and_get_value(const char *command, const char *word, { FILE *output; uint wordlen; - /* should be enought to store the string from the output */ + /* should be enough to store the string from the output */ enum { MAX_LINE_LEN= 512 }; char linebuf[MAX_LINE_LEN]; @@ -99,3 +99,4 @@ pclose: err: return 1; } + diff --git a/server-tools/instance-manager/parse_output.h b/server-tools/instance-manager/parse_output.h index 20503a74629..48fd2ae4068 100644 --- a/server-tools/instance-manager/parse_output.h +++ b/server-tools/instance-manager/parse_output.h @@ -1,3 +1,5 @@ +#ifndef INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H +#define INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H /* Copyright (C) 2004 MySQL AB This program is free software; you can redistribute it and/or modify @@ -17,3 +19,4 @@ int parse_output_and_get_value(const char *command, const char *word, char *result, size_t result_len); +#endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PARSE_OUTPUT_H */ diff --git a/server-tools/instance-manager/protocol.cc b/server-tools/instance-manager/protocol.cc index 9c8975a78be..62de48d0619 100644 --- a/server-tools/instance-manager/protocol.cc +++ b/server-tools/instance-manager/protocol.cc @@ -24,15 +24,25 @@ static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ -int net_send_ok(struct st_net *net, unsigned long connection_id) + +int net_send_ok(struct st_net *net, unsigned long connection_id, + const char *message) { - char buff[1 + // packet type code - 9 + // affected rows count - 9 + // connection id - 2 + // thread return status - 2]; // warning count + /* + The format of a packet + 1 packet type code + 1-9 affected rows count + 1-9 connection id + 2 thread return status + 2 warning count + 1-9 + message length message to send (isn't stored if no message) + */ + Buffer buff; + char *pos= buff.buffer; + + /* check that we have space to hold mandatory fields */ + buff.reserve(0, 23); - char *pos= buff; enum { OK_PACKET_CODE= 0 }; *pos++= OK_PACKET_CODE; pos= net_store_length(pos, (ulonglong) 0); @@ -43,7 +53,15 @@ int net_send_ok(struct st_net *net, unsigned long connection_id) int2store(pos, 0); pos+= 2; - return my_net_write(net, buff, pos - buff) || net_flush(net); + uint position= pos - buff.buffer; /* we might need it for message */ + + if (message != NULL) + { + buff.reserve(position, 9 + strlen(message)); + store_to_string(&buff, message, &position); + } + + return my_net_write(net, buff.buffer, position) || net_flush(net); } @@ -99,15 +117,16 @@ char *net_store_length(char *pkg, uint length) } -int store_to_string(Buffer *buf, const char *string, uint *position) +int store_to_string(Buffer *buf, const char *string, uint *position, + uint string_len) { uint currpos; - uint string_len; - string_len= strlen(string); - if (buf->reserve(*position, 2)) + /* reserve max amount of bytes needed to store length */ + if (buf->reserve(*position, 9)) goto err; - currpos= (net_store_length(buf->buffer + *position, string_len) - buf->buffer); + currpos= (net_store_length(buf->buffer + *position, + (ulonglong) string_len) - buf->buffer); if (buf->append(currpos, string, string_len)) goto err; *position= *position + string_len + (currpos - *position); @@ -118,6 +137,15 @@ err: } +int store_to_string(Buffer *buf, const char *string, uint *position) +{ + uint string_len; + + string_len= strlen(string); + return store_to_string(buf, string, position, string_len); +} + + int send_eof(struct st_net *net) { char buff[1 + /* eof packet code */ @@ -148,10 +176,10 @@ int send_fields(struct st_net *net, LIST *fields) position= 0; field= (NAME_WITH_LENGTH *) tmp->data; - store_to_string(&send_buff, (char *) "", &position); /* catalog name */ - store_to_string(&send_buff, (char *) "", &position); /* db name */ - store_to_string(&send_buff, (char *) "", &position); /* table name */ - store_to_string(&send_buff, (char *) "", &position); /* table name alias */ + store_to_string(&send_buff, (char*) "", &position); /* catalog name */ + store_to_string(&send_buff, (char*) "", &position); /* db name */ + store_to_string(&send_buff, (char*) "", &position); /* table name */ + store_to_string(&send_buff, (char*) "", &position); /* table name alias */ store_to_string(&send_buff, field->name, &position); /* column name */ store_to_string(&send_buff, field->name, &position); /* column name alias */ send_buff.reserve(position, 12); diff --git a/server-tools/instance-manager/protocol.h b/server-tools/instance-manager/protocol.h index b7b18b4b76c..a2ed9a31889 100644 --- a/server-tools/instance-manager/protocol.h +++ b/server-tools/instance-manager/protocol.h @@ -25,9 +25,13 @@ typedef struct field { uint length; } NAME_WITH_LENGTH; +/* default field length to be used in various field-realted functions */ +enum { DEFAULT_FIELD_LENGTH= 20 }; + struct st_net; -int net_send_ok(struct st_net *net, unsigned long connection_id); +int net_send_ok(struct st_net *net, unsigned long connection_id, + const char *message); int net_send_error(struct st_net *net, unsigned sql_errno); @@ -39,6 +43,9 @@ char *net_store_length(char *pkg, uint length); int store_to_string(Buffer *buf, const char *string, uint *position); +int store_to_string(Buffer *buf, const char *string, uint *position, + uint string_len); + int send_eof(struct st_net *net); #endif /* INCLUDES_MYSQL_INSTANCE_MANAGER_PROTOCOL_H */ diff --git a/sql-common/client.c b/sql-common/client.c index 59e27e4090a..4cbdb4b8e0d 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -864,6 +864,8 @@ mysql_free_result(MYSQL_RES *result) { (*mysql->methods->flush_use_result)(mysql); mysql->status=MYSQL_STATUS_READY; + if (mysql->unbuffered_fetch_owner) + *mysql->unbuffered_fetch_owner= TRUE; } } free_rows(result->data); diff --git a/sql/field.cc b/sql/field.cc index 78266441bda..34c5210b43c 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8060,7 +8060,12 @@ void create_field::create_length_to_internal_length(void) } break; case MYSQL_TYPE_NEWDECIMAL: - key_length= pack_length= my_decimal_get_binary_size(length, decimals); + key_length= pack_length= + my_decimal_get_binary_size(my_decimal_length_to_precision(length, + decimals, + flags & + UNSIGNED_FLAG), + decimals); break; default: key_length= pack_length= calc_pack_length(sql_type, length); diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc index c5062c4ea81..dcc542a7247 100644 --- a/sql/ha_blackhole.cc +++ b/sql/ha_blackhole.cc @@ -132,8 +132,9 @@ THR_LOCK_DATA **ha_blackhole::store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type) { + if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) + lock.type=lock_type; *to++= &lock; - return to; } diff --git a/sql/item.cc b/sql/item.cc index 30c134ebdd5..8100e78491b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -740,6 +740,13 @@ Item_splocal::this_item() return thd->spcont->get_item(m_offset); } + +Item ** +Item_splocal::this_item_addr(THD *thd, Item **addr) +{ + return thd->spcont->get_item_addr(m_offset); +} + Item * Item_splocal::this_const_item() const { diff --git a/sql/item.h b/sql/item.h index 0e15e539067..0166c5e8707 100644 --- a/sql/item.h +++ b/sql/item.h @@ -525,8 +525,17 @@ public: virtual Item *equal_fields_propagator(byte * arg) { return this; } virtual Item *set_no_const_sub(byte *arg) { return this; } virtual Item *replace_equal_field(byte * arg) { return this; } - - virtual Item *this_item() { return this; } /* For SPs mostly. */ + + /* + For SP local variable returns pointer to Item representing its + current value and pointer to current Item otherwise. + */ + virtual Item *this_item() { return this; } + /* + For SP local variable returns address of pointer to Item representing its + current value and pointer passed via parameter otherwise. + */ + virtual Item **this_item_addr(THD *thd, Item **addr) { return addr; } virtual Item *this_const_item() const { return const_cast<Item*>(this); } /* For SPs mostly. */ // Row emulation @@ -573,6 +582,7 @@ public: bool is_splocal() { return 1; } /* Needed for error checking */ Item *this_item(); + Item **this_item_addr(THD *thd, Item **); Item *this_const_item() const; bool fix_fields(THD *, struct st_table_list *, Item **); diff --git a/sql/item_func.cc b/sql/item_func.cc index 3c87b6ef920..db49b7b4ae9 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1255,8 +1255,8 @@ void Item_func_div::result_precision() void Item_func_div::fix_length_and_dec() { DBUG_ENTER("Item_func_div::fix_length_and_dec"); - Item_num_op::fix_length_and_dec(); prec_increment= current_thd->variables.div_precincrement; + Item_num_op::fix_length_and_dec(); switch(hybrid_type) { case REAL_RESULT: { diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 3fe1b819f36..fb7827ef932 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1013,7 +1013,7 @@ String *Item_func_substr::val_str(String *str) if ((null_value=(args[0]->null_value || args[1]->null_value || (arg_count == 3 && args[2]->null_value)))) return 0; /* purecov: inspected */ - start= (int32)((start < 0) ? res->length() + start : start -1); + start= (int32)((start < 0) ? res->numchars() + start : start -1); start=res->charpos(start); length=res->charpos(length,start); if (start < 0 || (uint) start+1 > res->length() || length <= 0) diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index d7c77829cfc..4c44db49489 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -18,7 +18,6 @@ /* This file defines all string functions */ #ifdef USE_PRAGMA_INTERFACE -#error PRAGMA #pragma interface /* gcc class implementation */ #endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 36fc315c3c0..25490b04ab3 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -268,6 +268,9 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define OPTION_SCHEMA_TABLE (1L << 29) /* Flag set if setup_tables already done */ #define OPTION_SETUP_TABLES_DONE (1L << 30) +/* Thr following is used to detect a conflict with DISTINCT + in the user query has requested */ +#define SELECT_ALL (ULL(1) << 32) /* Maximum length of time zone name that we support diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 90d4f9b9a99..84a041167f1 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4389,9 +4389,9 @@ Disable with --skip-bdb (will save memory).", (gptr*) &max_system_variables.completion_type, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 2, 0, 1, 0}, {"concurrent-insert", OPT_CONCURRENT_INSERT, - "Use concurrent insert with MyISAM. Disable with --skip-concurrent-insert.", + "Use concurrent insert with MyISAM. Disable with --concurrent-insert=0", (gptr*) &myisam_concurrent_insert, (gptr*) &myisam_concurrent_insert, - 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + 0, GET_LONG, OPT_ARG, 1, 0, 2, 0, 0, 0}, {"console", OPT_CONSOLE, "Write error output on screen; Don't remove the console window on windows.", (gptr*) &opt_console, (gptr*) &opt_console, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -5332,9 +5332,9 @@ The minimum value for this variable is 4096.", "Default pointer size to be used for MyISAM tables.", (gptr*) &myisam_data_pointer_size, (gptr*) &myisam_data_pointer_size, 0, GET_ULONG, REQUIRED_ARG, - 4, 2, 8, 0, 1, 0}, + 6, 2, 8, 0, 1, 0}, {"myisam_max_extra_sort_file_size", OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, - "Used to help MySQL to decide when to use the slow but safe key cache index create method.", + "Depricated option", (gptr*) &global_system_variables.myisam_max_extra_sort_file_size, (gptr*) &max_system_variables.myisam_max_extra_sort_file_size, 0, GET_ULL, REQUIRED_ARG, (ulonglong) MI_MAX_TEMP_LENGTH, @@ -5870,7 +5870,8 @@ static void mysql_init_variables(void) /* Things reset to zero */ opt_skip_slave_start= opt_reckless_slave = 0; mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0; - opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0; + opt_log= opt_update_log= opt_slow_log= 0; + opt_bin_log= 0; opt_disable_networking= opt_skip_show_db=0; opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0; opt_tc_log_file= (char *)"tc.log"; // no hostname in tc_log file name ! @@ -6170,7 +6171,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), opt_update_log=1; break; case (int) OPT_BIN_LOG: - opt_bin_log=1; + opt_bin_log= test(argument != disabled_my_option); break; case (int) OPT_ERROR_LOG_FILE: opt_error_log= 1; @@ -6570,6 +6571,13 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), ha_open_options|=HA_OPEN_ABORT_IF_CRASHED; break; } + case OPT_CONCURRENT_INSERT: + /* The following code is mainly here to emulate old behavior */ + if (!argument) /* --concurrent-insert */ + myisam_concurrent_insert= 1; + else if (argument == disabled_my_option) + myisam_concurrent_insert= 0; /* --skip-concurrent-insert */ + break; case OPT_TC_HEURISTIC_RECOVER: { if ((tc_heuristic_recover=find_type(argument, @@ -6747,8 +6755,6 @@ static void get_options(int argc,char **argv) my_default_record_cache_size=global_system_variables.read_buff_size; myisam_max_temp_length= (my_off_t) global_system_variables.myisam_max_sort_file_size; - myisam_max_extra_temp_length= - (my_off_t) global_system_variables.myisam_max_extra_sort_file_size; /* Set global variables based on startup options */ myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size); diff --git a/sql/set_var.cc b/sql/set_var.cc index 4add5d6b39b..373a499f485 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -108,7 +108,6 @@ static void fix_net_retry_count(THD *thd, enum_var_type type); static void fix_max_join_size(THD *thd, enum_var_type type); static void fix_query_cache_size(THD *thd, enum_var_type type); static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type); -static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type); static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type); static void fix_max_binlog_size(THD *thd, enum_var_type type); static void fix_max_relay_log_size(THD *thd, enum_var_type type); @@ -158,8 +157,8 @@ sys_var_thd_ulong sys_completion_type("completion_type", sys_var_collation_connection sys_collation_connection("collation_connection"); sys_var_collation_database sys_collation_database("collation_database"); sys_var_collation_server sys_collation_server("collation_server"); -sys_var_bool_ptr sys_concurrent_insert("concurrent_insert", - &myisam_concurrent_insert); +sys_var_long_ptr sys_concurrent_insert("concurrent_insert", + &myisam_concurrent_insert); sys_var_long_ptr sys_connect_timeout("connect_timeout", &connect_timeout); sys_var_enum sys_delay_key_write("delay_key_write", @@ -270,7 +269,6 @@ sys_var_thd_ulong sys_multi_range_count("multi_range_count", &SV::multi_range_count); sys_var_long_ptr sys_myisam_data_pointer_size("myisam_data_pointer_size", &myisam_data_pointer_size); -sys_var_thd_ulonglong sys_myisam_max_extra_sort_file_size("myisam_max_extra_sort_file_size", &SV::myisam_max_extra_sort_file_size, fix_myisam_max_extra_sort_file_size, 1); sys_var_thd_ulonglong sys_myisam_max_sort_file_size("myisam_max_sort_file_size", &SV::myisam_max_sort_file_size, fix_myisam_max_sort_file_size, 1); sys_var_thd_ulong sys_myisam_repair_threads("myisam_repair_threads", &SV::myisam_repair_threads); sys_var_thd_ulong sys_myisam_sort_buffer_size("myisam_sort_buffer_size", &SV::myisam_sort_buff_size); @@ -623,7 +621,6 @@ sys_var *sys_variables[]= &sys_max_write_lock_count, &sys_multi_range_count, &sys_myisam_data_pointer_size, - &sys_myisam_max_extra_sort_file_size, &sys_myisam_max_sort_file_size, &sys_myisam_repair_threads, &sys_myisam_sort_buffer_size, @@ -882,9 +879,6 @@ struct show_var_st init_vars[]= { {sys_max_write_lock_count.name, (char*) &sys_max_write_lock_count,SHOW_SYS}, {sys_multi_range_count.name, (char*) &sys_multi_range_count, SHOW_SYS}, {sys_myisam_data_pointer_size.name, (char*) &sys_myisam_data_pointer_size, SHOW_SYS}, - {sys_myisam_max_extra_sort_file_size.name, - (char*) &sys_myisam_max_extra_sort_file_size, - SHOW_SYS}, {sys_myisam_max_sort_file_size.name, (char*) &sys_myisam_max_sort_file_size, SHOW_SYS}, {"myisam_recover_options", (char*) &myisam_recover_options_str, SHOW_CHAR_PTR}, @@ -1141,14 +1135,6 @@ static void fix_low_priority_updates(THD *thd, enum_var_type type) static void -fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type) -{ - myisam_max_extra_temp_length= - (my_off_t) global_system_variables.myisam_max_extra_sort_file_size; -} - - -static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type) { myisam_max_temp_length= diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 388f47bf96f..848cc422dc2 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -4766,13 +4766,13 @@ ER_SUBQUERY_NO_1_ROW 21000 swe "Subquery returnerade mer än 1 rad" ukr "ð¦ÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ¦ÌØÛ ÎiÖ 1 ÚÁÐÉÓ" ER_UNKNOWN_STMT_HANDLER - dan "Unknown prepared statement handler (%ld) given to %s" + dan "Unknown prepared statement handler (%.*s) given to %s" eng "Unknown prepared statement handler (%.*s) given to %s" ger "Unbekannter Prepared-Statement-Handler (%.*s) für %s angegeben" por "Desconhecido manipulador de declaração preparado (%.*s) determinado para %s" - spa "Desconocido preparado comando handler (%ld) dado para %s" - swe "Okänd PREPARED STATEMENT id (%ld) var given till %s" - ukr "Unknown prepared statement handler (%ld) given to %s" + spa "Desconocido preparado comando handler (%.*s) dado para %s" + swe "Okänd PREPARED STATEMENT id (%.*s) var given till %s" + ukr "Unknown prepared statement handler (%.*s) given to %s" ER_CORRUPT_HELP_DB eng "Help database is corrupt or does not exist" ger "Die Hilfe-Datenbank ist beschädigt oder existiert nicht" @@ -5352,3 +5352,7 @@ ER_BINLOG_UNSAFE_ROUTINE eng "This routine is declared to be non-deterministic and to modify data and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)" ER_BINLOG_CREATE_ROUTINE_NEED_SUPER eng "You do not have SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_routine_creators variable)" +ER_EXEC_STMT_WITH_OPEN_CURSOR + eng "You can't execute a prepared statement which has an open cursor associated with it. Reset the statement to re-execute it." +ER_STMT_HAS_NO_OPEN_CURSOR + eng "The statement (%d) has no open cursor." diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 0be93c3e41c..2ffcd45b1a7 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -97,19 +97,48 @@ sp_multi_results_command(enum enum_sql_command cmd) } } + +/* + Prepare Item for execution (call of fix_fields) + + SYNOPSIS + sp_prepare_func_item() + thd thread handler + it_addr pointer on item refernce + + RETURN + NULL error + prepared item +*/ + +static Item * +sp_prepare_func_item(THD* thd, Item **it_addr) +{ + Item *it= *it_addr; + DBUG_ENTER("sp_prepare_func_item"); + it_addr= it->this_item_addr(thd, it_addr); + + if (!it->fixed && (*it_addr)->fix_fields(thd, 0, it_addr)) + { + DBUG_PRINT("info", ("fix_fields() failed")); + DBUG_RETURN(NULL); + } + DBUG_RETURN(*it_addr); +} + + /* Evaluate a (presumed) func item. Always returns an item, the parameter ** if nothing else. */ Item * -sp_eval_func_item(THD *thd, Item *it, enum enum_field_types type) +sp_eval_func_item(THD *thd, Item **it_addr, enum enum_field_types type) { DBUG_ENTER("sp_eval_func_item"); - it= it->this_item(); + Item *it= sp_prepare_func_item(thd, it_addr); DBUG_PRINT("info", ("type: %d", type)); - if (!it->fixed && it->fix_fields(thd, 0, &it)) + if (!it) { - DBUG_PRINT("info", ("fix_fields() failed")); DBUG_RETURN(NULL); } @@ -679,7 +708,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) for (i= 0 ; i < params && i < argcount ; i++) { sp_pvar_t *pvar = m_pcont->find_pvar(i); - Item *it= sp_eval_func_item(thd, *argp++, pvar->type); + Item *it= sp_eval_func_item(thd, argp++, pvar->type); if (it) nctx->push_item(it); @@ -761,7 +790,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) { Item_null *nit= NULL; // Re-use this, and only create if needed uint i; - List_iterator_fast<Item> li(*args); + List_iterator<Item> li(*args); Item *it; nctx= new sp_rcontext(csize, hmax, cmax); @@ -794,7 +823,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) } else { - Item *it2= sp_eval_func_item(thd, it, pvar->type); + Item *it2= sp_eval_func_item(thd, li.ref(), pvar->type); if (it2) nctx->push_item(it2); // IN or INOUT @@ -1439,7 +1468,7 @@ sp_instr_set::exec_core(THD *thd, uint *nextp) Item *it; int res; - it= sp_eval_func_item(thd, m_value, m_type); + it= sp_eval_func_item(thd, &m_value, m_type); if (! it) res= -1; else @@ -1569,13 +1598,13 @@ sp_instr_jump_if::exec_core(THD *thd, uint *nextp) Item *it; int res; - it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY); + it= sp_prepare_func_item(thd, &m_expr); if (!it) res= -1; else { res= 0; - if (it->val_int()) + if (it->val_bool()) *nextp = m_dest; else *nextp = m_ip+1; @@ -1627,13 +1656,13 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) Item *it; int res; - it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY); + it= sp_prepare_func_item(thd, &m_expr); if (! it) res= -1; else { res= 0; - if (! it->val_int()) + if (! it->val_bool()) *nextp = m_dest; else *nextp = m_ip+1; @@ -1685,7 +1714,7 @@ sp_instr_freturn::exec_core(THD *thd, uint *nextp) Item *it; int res; - it= sp_eval_func_item(thd, m_value, m_type); + it= sp_eval_func_item(thd, &m_value, m_type); if (! it) res= -1; else diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index def38009eee..672491a97f2 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -41,10 +41,10 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax) } int -sp_rcontext::set_item_eval(uint idx, Item *i, enum_field_types type) +sp_rcontext::set_item_eval(uint idx, Item **item_addr, enum_field_types type) { - extern Item *sp_eval_func_item(THD *thd, Item *it, enum_field_types type); - Item *it= sp_eval_func_item(current_thd, i, type); + extern Item *sp_eval_func_item(THD *thd, Item **it, enum_field_types type); + Item *it= sp_eval_func_item(current_thd, item_addr, type); if (! it) return -1; diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index afcd937a369..c132032e32c 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -74,7 +74,7 @@ class sp_rcontext : public Sql_alloc /* Returns 0 on success, -1 on (eval) failure */ int - set_item_eval(uint idx, Item *i, enum_field_types type); + set_item_eval(uint idx, Item **i, enum_field_types type); inline Item * get_item(uint idx) @@ -82,6 +82,14 @@ class sp_rcontext : public Sql_alloc return m_frame[idx]; } + + inline Item ** + get_item_addr(uint idx) + { + return m_frame + idx; + } + + inline void set_result(Item *it) { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index abdb21dae63..6439bc8a2d7 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3169,10 +3169,8 @@ TABLE_LIST **make_leaves_list(TABLE_LIST **list, TABLE_LIST *tables) { for (TABLE_LIST *table= tables; table; table= table->next_local) { - if (table->view && !table->table) + if (table->view && table->effective_algorithm == VIEW_ALGORITHM_MERGE) { - /* it is for multi table views only, check it */ - DBUG_ASSERT(table->ancestor->next_local != 0); list= make_leaves_list(list, table->ancestor); } else @@ -3309,7 +3307,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, 0) { my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), - name->c_ptr(), table->s->table_name); + name->c_ptr_safe(), table->s->table_name); map->set_all(); return 1; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a6a1f4d60ef..2d5c4722164 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1719,10 +1719,9 @@ bool select_dumpvar::send_data(List<Item> &items) List_iterator_fast<Item_func_set_user_var> li(vars); List_iterator_fast<Item_splocal> var_li(local_vars); List_iterator_fast<my_var> my_li(var_list); - List_iterator_fast<Item> it(items); + List_iterator<Item> it(items); Item_func_set_user_var *xx; Item_splocal *yy; - Item *item; my_var *zz; DBUG_ENTER("send_data"); if (unit->offset_limit_cnt) @@ -1741,13 +1740,13 @@ bool select_dumpvar::send_data(List<Item> &items) my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0)); DBUG_RETURN(1); } - while ((zz=my_li++) && (item=it++)) + while ((zz=my_li++) && (it++)) { if (zz->local) { if ((yy=var_li++)) { - if (thd->spcont->set_item_eval(yy->get_offset(), item, zz->type)) + if (thd->spcont->set_item_eval(yy->get_offset(), it.ref(), zz->type)) DBUG_RETURN(1); } } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index d524bbcf164..cded9e2a13e 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -46,8 +46,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, DBUG_RETURN(TRUE); if (!(table= table_list->table)) { - DBUG_ASSERT(table_list->view && - table_list->ancestor && table_list->ancestor->next_local); my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(-1); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f2b363a622b..adb33af05b9 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -81,8 +81,6 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, { if (!table) { - DBUG_ASSERT(table_list->view && - table_list->ancestor && table_list->ancestor->next_local); my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0), table_list->view_db.str, table_list->view_name.str); return -1; @@ -125,7 +123,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, thd->lex->select_lex.no_wrap_view_item= 0; if (res) return -1; - if (table == 0) + if (table_list->effective_algorithm == VIEW_ALGORITHM_MERGE) { /* it is join view => we need to find table for update */ List_iterator_fast<Item> it(fields); @@ -135,7 +133,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, while ((item= it++)) map|= item->used_tables(); - if (table_list->check_single_table(&tbl, map) || tbl == 0) + if (table_list->check_single_table(&tbl, map, table_list) || tbl == 0) { my_error(ER_VIEW_MULTIUPDATE, MYF(0), table_list->view_db.str, table_list->view_name.str); @@ -709,8 +707,6 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list, thd->lex->empty_field_list_on_rset= 1; if (!table_list->table) { - DBUG_ASSERT(table_list->view && - table_list->ancestor && table_list->ancestor->next_local); my_error(ER_VIEW_NO_INSERT_FIELD_LIST, MYF(0), table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(TRUE); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 94f1a8e0df4..a33d60df0d4 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -296,7 +296,7 @@ protected: *link_next, **link_prev; /* list of whole SELECT_LEX */ public: - ulong options; + ulonglong options; /* result of this query can't be cached, bit field, can be : UNCACHEABLE_DEPENDENT diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8c8dcc938cb..47ac8d3afc1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1764,7 +1764,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->lex-> select_lex.table_list.link_in_list((byte*) &table_list, (byte**) &table_list.next_local); - thd->lex->query_tables= &table_list; + thd->lex->add_to_query_tables(&table_list); /* switch on VIEW optimisation: do not fill temporary tables */ thd->lex->sql_command= SQLCOM_SHOW_FIELDS; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 17c5f51f1e1..b36d835a80a 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -135,7 +135,8 @@ find_prepared_statement(THD *thd, ulong id, const char *where) if (stmt == 0 || stmt->type() != Item_arena::PREPARED_STATEMENT) { char llbuf[22]; - my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), 22, llstr(id, llbuf), where); + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), llstr(id, llbuf), + where); return 0; } return (Prepared_statement *) stmt; @@ -1006,7 +1007,7 @@ static int mysql_test_update(Prepared_statement *stmt, if (!open_tables(thd, &table_list, &table_count)) { - if (table_list->ancestor && table_list->ancestor->next_local) + if (table_list->multitable_view) { DBUG_ASSERT(table_list->view != 0); DBUG_PRINT("info", ("Switch to multi-update")); @@ -1095,8 +1096,6 @@ static int mysql_test_delete(Prepared_statement *stmt, bool res; if (!table_list->table) { - DBUG_ASSERT(table_list->view && - table_list->ancestor && table_list->ancestor->next_local); my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(-1); @@ -1458,8 +1457,6 @@ static int mysql_test_multidelete(Prepared_statement *stmt, return res; if (!tables->table) { - DBUG_ASSERT(tables->view && - tables->ancestor && tables->ancestor->next_local); my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0), tables->view_db.str, tables->view_name.str); return -1; @@ -1969,7 +1966,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) { ulong stmt_id= uint4korr(packet); ulong flags= (ulong) ((uchar) packet[4]); - Cursor *cursor= 0; + Cursor *cursor; /* Query text for binary log, or empty string if the query is not put into binary log. @@ -1995,6 +1992,13 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) DBUG_VOID_RETURN; } + cursor= stmt->cursor; + if (cursor && cursor->is_open()) + { + my_error(ER_EXEC_STMT_WITH_OPEN_CURSOR, MYF(0)); + DBUG_VOID_RETURN; + } + DBUG_ASSERT(thd->free_list == NULL); mysql_reset_thd_for_next_command(thd); if (flags & (ulong) CURSOR_TYPE_READ_ONLY) @@ -2013,7 +2017,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) else { DBUG_PRINT("info",("Using READ_ONLY cursor")); - if (!stmt->cursor && + if (!cursor && !(cursor= stmt->cursor= new (&stmt->main_mem_root) Cursor())) DBUG_VOID_RETURN; /* If lex->result is set, mysql_execute_command will use it */ @@ -2208,13 +2212,15 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) Statement *stmt; DBUG_ENTER("mysql_stmt_fetch"); - if (!(stmt= thd->stmt_map.find(stmt_id)) || - !stmt->cursor || - !stmt->cursor->is_open()) + if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch"))) + DBUG_VOID_RETURN; + + if (!stmt->cursor || !stmt->cursor->is_open()) { - my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_id, "fetch"); + my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0)); DBUG_VOID_RETURN; } + thd->current_arena= stmt; thd->set_n_backup_statement(stmt, &thd->stmt_backup); stmt->cursor->init_thd(thd); @@ -2266,6 +2272,9 @@ void mysql_stmt_reset(THD *thd, char *packet) if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset"))) DBUG_VOID_RETURN; + if (stmt->cursor && stmt->cursor->is_open()) + stmt->cursor->close(); + stmt->state= Item_arena::PREPARED; /* diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 47c7de6eba7..5ba157cb608 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1742,6 +1742,7 @@ Cursor::init_from_thd(THD *thd) /* XXX: thd->locked_tables is not changed. What problems can we have with it if cursor is open? + TODO: must be fixed because of the prelocked mode. */ /* TODO: grab thd->free_list here? @@ -1871,10 +1872,6 @@ Cursor::fetch(ulong num_rows) } else if (error != NESTED_LOOP_KILLED) my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - /* free cursor memory */ - free_items(free_list); - free_list= 0; - free_root(&main_mem_root, MYF(0)); } } @@ -1914,6 +1911,13 @@ Cursor::close() } join= 0; unit= 0; + free_items(free_list); + free_list= 0; + /* + Must be last, as some memory might be allocated for free purposes, + like in free_tmp_table() (TODO: fix this issue) + */ + free_root(mem_root, MYF(0)); DBUG_VOID_RETURN; } @@ -1922,12 +1926,6 @@ Cursor::~Cursor() { if (is_open()) close(); - free_items(free_list); - /* - Must be last, as some memory might be allocated for free purposes, - like in free_tmp_table() (TODO: fix this issue) - */ - free_root(&main_mem_root, MYF(0)); } /*********************************************************************/ @@ -7300,7 +7298,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top) */ if (table->on_expr) { - Item *expr; + Item *expr= table->prep_on_expr ? table->prep_on_expr : table->on_expr; /* If an on expression E is attached to the table, check all null rejected predicates in this expression. @@ -7310,7 +7308,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top) the corresponding on expression is added to E. */ expr= simplify_joins(join, &nested_join->join_list, - table->on_expr, FALSE); + expr, FALSE); table->prep_on_expr= table->on_expr= expr; } nested_join->used_tables= (table_map) 0; diff --git a/sql/sql_select.h b/sql/sql_select.h index a27fbc60856..49ac58e913b 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -364,6 +364,10 @@ class JOIN :public Sql_alloc /* Server-side cursor (now stands only for basic read-only cursor) See class implementation in sql_select.cc + A cursor has its own runtime state - list of used items and memory root of + used memory - which is different from Prepared statement runtime: it must + be different at least for the purpose of reusing the same prepared + statement for many cursors. */ class Cursor: public Sql_alloc, public Item_arena diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9e3f82f9fd6..dfdff8ae914 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1779,32 +1779,77 @@ enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table) /* - Add 'information_schema' name to db_names list + Create db names list. Information schema name always is first in list SYNOPSIS - schema_db_add() + make_db_list() thd thread handler files list of db names wild wild string + 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 + is_wild_value if value is 1 then idx_field_vals->db_name is + wild string otherwise it's db name; RETURN 1 error 0 success */ -int schema_db_add(THD *thd, List<char> *files, - const char *wild, bool *with_i_schema) +int make_db_list(THD *thd, List<char> *files, + INDEX_FIELD_VALUES *idx_field_vals, + bool *with_i_schema, bool is_wild_value) { + LEX *lex= thd->lex; *with_i_schema= 0; - if (!wild || !wild_compare(information_schema_name.str, wild, 0)) + get_index_field_values(lex, idx_field_vals); + if (is_wild_value) { - *with_i_schema= 1; - if (files->push_back(thd->strdup(information_schema_name.str))) - return 1; + /* + This part of code is only for SHOW DATABASES command. + idx_field_vals->db_value can be 0 when we don't use + LIKE clause (see also get_index_field_values() function) + */ + if (!idx_field_vals->db_value || + !wild_case_compare(system_charset_info, + information_schema_name.str, + idx_field_vals->db_value)) + { + *with_i_schema= 1; + if (files->push_back(thd->strdup(information_schema_name.str))) + return 1; + } + return mysql_find_files(thd, files, NullS, mysql_data_home, + idx_field_vals->db_value, 1); } - return 0; + + /* + This part of code is for SHOW TABLES, SHOW TABLE STATUS commands. + idx_field_vals->db_value can't be 0 (see get_index_field_values() + function). lex->orig_sql_command can be not equal to SQLCOM_END + only in case of executing of SHOW commands. + */ + if (lex->orig_sql_command != SQLCOM_END) + { + if (!my_strcasecmp(system_charset_info, information_schema_name.str, + idx_field_vals->db_value)) + { + *with_i_schema= 1; + return files->push_back(thd->strdup(information_schema_name.str)); + } + return files->push_back(thd->strdup(idx_field_vals->db_value)); + } + + /* + Create list of existing databases. It is used in case + of select from information schema table + */ + if (files->push_back(thd->strdup(information_schema_name.str))) + return 1; + *with_i_schema= 1; + return mysql_find_files(thd, files, NullS, mysql_data_home, NullS, 1); } @@ -1882,14 +1927,9 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) if (schema_table_idx == SCH_TABLES) lock_type= TL_READ; - get_index_field_values(lex, &idx_field_vals); - - /* information schema name always is first in list */ - if (schema_db_add(thd, &bases, idx_field_vals.db_value, &with_i_schema)) - goto err; - if (mysql_find_files(thd, &bases, NullS, mysql_data_home, - idx_field_vals.db_value, 1)) + if (make_db_list(thd, &bases, &idx_field_vals, + &with_i_schema, 0)) goto err; partial_cond= make_cond_for_info_schema(cond, tables); @@ -2025,13 +2065,10 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond) TABLE *table= tables->table; DBUG_ENTER("fill_schema_shemata"); - get_index_field_values(thd->lex, &idx_field_vals); - /* information schema name always is first in list */ - if (schema_db_add(thd, &files, idx_field_vals.db_value, &with_i_schema)) - DBUG_RETURN(1); - if (mysql_find_files(thd, &files, NullS, mysql_data_home, - idx_field_vals.db_value, 1)) + if (make_db_list(thd, &files, &idx_field_vals, + &with_i_schema, 1)) DBUG_RETURN(1); + List_iterator_fast<char> it(files); while ((file_name=it++)) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index bbe7c53147b..ad0a0baae2d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1345,7 +1345,8 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field) /* Convert long VARCHAR columns to TEXT or BLOB */ char warn_buff[MYSQL_ERRMSG_SIZE]; - if (sql_field->def) + if (sql_field->def || (thd->variables.sql_mode & (MODE_STRICT_TRANS_TABLES | + MODE_STRICT_ALL_TABLES))) { my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name, MAX_FIELD_VARCHARLENGTH / sql_field->charset->mbmaxlen); @@ -1354,7 +1355,7 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field) sql_field->sql_type= FIELD_TYPE_BLOB; sql_field->flags|= BLOB_FLAG; sprintf(warn_buff, ER(ER_AUTO_CONVERT), sql_field->field_name, - "VARCHAR", + (sql_field->charset == &my_charset_bin) ? "VARBINARY" : "VARCHAR", (sql_field->charset == &my_charset_bin) ? "BLOB" : "TEXT"); push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_AUTO_CONVERT, warn_buff); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 680a80431c5..670c618bec5 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -98,6 +98,21 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) if (wait_if_global_read_lock(thd, 0, 0)) DBUG_RETURN(TRUE); + /* + There is no DETERMINISTIC clause for triggers, so can't check it. + But a trigger can in theory be used to do nasty things (if it supported + DROP for example) so we do the check for privileges. For now there is + already a stronger test above (see start of the function); but when this + stronger test will be removed, the test below will hold. + */ + if (!trust_routine_creators && mysql_bin_log.is_open() && + !(thd->master_access & SUPER_ACL)) + { + my_message(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER, + ER(ER_BINLOG_CREATE_ROUTINE_NEED_SUPER), MYF(0)); + DBUG_RETURN(TRUE); + } + VOID(pthread_mutex_lock(&LOCK_open)); result= (create ? table->triggers->create_trigger(thd, tables): @@ -109,7 +124,16 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) start_waiting_global_read_lock(thd); if (!result) - send_ok(thd); + { + if (mysql_bin_log.is_open()) + { + thd->clear_error(); + /* Such a statement can always go directly to binlog, no trans cache */ + Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); + mysql_bin_log.write(&qinfo); + } + send_ok(thd); + } DBUG_RETURN(result); } diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 7dd6734eb89..90c906fc72f 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -52,7 +52,15 @@ public: FIXME: We should juggle with security context here (because trigger should be invoked with creator rights). */ + /* + We disable binlogging, as in SP/functions, even though currently + triggers can't do updates. When triggers can do updates, someone + should add such a trigger to rpl_sp.test to verify that the update + does NOT go into binlog. + */ + tmp_disable_binlog(thd); res= bodies[event][time_type]->execute_function(thd, 0, 0, 0); + reenable_binlog(thd); #ifndef EMBEDDED_LIBRARY thd->net.no_send_ok= nsok; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 86aa0bf9890..95268c41aed 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -139,7 +139,7 @@ int mysql_update(THD *thd, if (open_tables(thd, &table_list, &table_count)) DBUG_RETURN(1); - if (table_list->ancestor && table_list->ancestor->next_local) + if (table_list->multitable_view) { DBUG_ASSERT(table_list->view != 0); DBUG_PRINT("info", ("Switch to multi-update")); @@ -706,9 +706,11 @@ bool mysql_multi_update_prepare(THD *thd) if (!tl->placeholder() && !tl->schema_table && !using_lock_tables) tl->table->reginfo.lock_type= tl->lock_type; } - + } + for(tl= table_list; tl; tl= tl->next_local) + { /* Check access privileges for table */ - if (!tl->derived && !tl->belong_to_view) + if (!tl->derived) { uint want_privilege= tl->updating ? UPDATE_ACL : SELECT_ACL; if (check_access(thd, want_privilege, @@ -721,12 +723,10 @@ bool mysql_multi_update_prepare(THD *thd) /* check single table update for view compound from several tables */ for (tl= table_list; tl; tl= tl->next_local) { - if (tl->table == 0) + if (tl->effective_algorithm == VIEW_ALGORITHM_MERGE) { - DBUG_ASSERT(tl->view && - tl->ancestor && tl->ancestor->next_local); TABLE_LIST *for_update= 0; - if (tl->check_single_table(&for_update, tables_for_update)) + if (tl->check_single_table(&for_update, tables_for_update, tl)) { my_error(ER_VIEW_MULTIUPDATE, MYF(0), tl->view_db.str, tl->view_name.str); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 15a8f52af20..289bf9d28a3 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -774,9 +774,9 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table) for (tbl= lex->select_lex.get_table_list(); tbl; tbl= tbl->next_local) tbl->select_lex= table->select_lex; - /* multi table view */ - if (view_tables->next_local) { + if (view_tables->next_local) + table->multitable_view= TRUE; /* make nested join structure for view tables */ NESTED_JOIN *nested_join; if (!(nested_join= table->nested_join= diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 2231df3f4c1..25a78178995 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4000,7 +4000,15 @@ select_option: YYABORT; Lex->lock_option= TL_READ_HIGH_PRIORITY; } - | DISTINCT { Select->options|= SELECT_DISTINCT; } + | DISTINCT + { + if (Select->options & SELECT_ALL) + { + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; + } + Select->options|= SELECT_DISTINCT; + } | SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; } | SQL_BIG_RESULT { Select->options|= SELECT_BIG_RESULT; } | SQL_BUFFER_RESULT @@ -4020,7 +4028,15 @@ select_option: { Lex->select_lex.options|= OPTION_TO_QUERY_CACHE; } - | ALL {} + | ALL + { + if (Select->options & SELECT_DISTINCT) + { + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; + } + Select->options|= SELECT_ALL; + } ; select_lock_type: diff --git a/sql/table.cc b/sql/table.cc index 8e0f52e1910..82a8afd826b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -59,6 +59,7 @@ static byte* get_field_name(Field **buff,uint *length, 3 Wrong data in .frm file 4 Error (see frm_error) 5 Error (see frm_error: charset unavailable) + 6 Unknown .frm version */ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, @@ -135,10 +136,14 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, *fn_ext(share->table_name)='\0'; // Remove extension *fn_ext(share->path)='\0'; // Remove extension - if (head[0] != (uchar) 254 || head[1] != 1 || - (head[2] != FRM_VER && head[2] != FRM_VER+1 && - ! (head[2] >= FRM_VER+3 && head[2] <= FRM_VER+4))) + if (head[0] != (uchar) 254 || head[1] != 1) + goto err; /* purecov: inspected */ + if (head[2] != FRM_VER && head[2] != FRM_VER+1 && + ! (head[2] >= FRM_VER+3 && head[2] <= FRM_VER+4)) + { + error= 6; goto err; /* purecov: inspected */ + } new_field_pack_flag=head[27]; new_frm_ver= (head[2] - FRM_VER); field_pack_length= new_frm_ver < 2 ? 11 : 17; @@ -1084,6 +1089,12 @@ static void frm_error(int error, TABLE *form, const char *name, MYF(0), csname, real_name); break; } + case 6: + my_printf_error(ER_NOT_FORM_FILE, + "Table '%-.64s' was created with a different version " + "of MySQL and cannot be read", + MYF(0), name); + break; default: /* Better wrong error than none */ case 4: my_error(ER_NOT_FORM_FILE, errortype, @@ -1644,11 +1655,13 @@ void st_table_list::set_ancestor() */ tbl->ancestor->set_ancestor(); } - tbl->table->grant= grant; + if (tbl->multitable_view) + multitable_view= TRUE; + if (tbl->table) + tbl->table->grant= grant; } while ((tbl= tbl->next_local)); - /* if view contain only one table, substitute TABLE of it */ - if (!ancestor->next_local) + if (!multitable_view) { table= ancestor->table; schema_table= ancestor->schema_table; @@ -1675,8 +1688,6 @@ void st_table_list::save_and_clear_want_privilege() } else { - DBUG_ASSERT(tbl->view && tbl->ancestor && - tbl->ancestor->next_local); tbl->save_and_clear_want_privilege(); } } @@ -1698,8 +1709,6 @@ void st_table_list::restore_want_privilege() tbl->table->grant.want_privilege= privilege_backup; else { - DBUG_ASSERT(tbl->view && tbl->ancestor && - tbl->ancestor->next_local); tbl->restore_want_privilege(); } } @@ -2053,16 +2062,17 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure) { if (check_option && check_option->val_int() == 0) { + TABLE_LIST *view= (belong_to_view ? belong_to_view : this); if (ignore_failure) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_VIEW_CHECK_FAILED, ER(ER_VIEW_CHECK_FAILED), - view_db.str, view_name.str); + view->view_db.str, view->view_name.str); return(VIEW_CHECK_SKIP); } else { - my_error(ER_VIEW_CHECK_FAILED, MYF(0), view_db.str, view_name.str); + my_error(ER_VIEW_CHECK_FAILED, MYF(0), view->view_db.str, view->view_name.str); return(VIEW_CHECK_ERROR); } } @@ -2080,13 +2090,15 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure) (should be 0 on call, to find table, or point to table for unique test) map bit mask of tables + view view for which we are looking table RETURN FALSE table not found or found only one TRUE found several tables */ -bool st_table_list::check_single_table(st_table_list **table, table_map map) +bool st_table_list::check_single_table(st_table_list **table, table_map map, + st_table_list *view) { for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) { @@ -2097,11 +2109,14 @@ bool st_table_list::check_single_table(st_table_list **table, table_map map) if (*table) return TRUE; else + { *table= tbl; + tbl->check_option= view->check_option; + } } } else - if (tbl->check_single_table(table, map)) + if (tbl->check_single_table(table, map, view)) return TRUE; } return FALSE; @@ -2131,7 +2146,7 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root) } else { - DBUG_ASSERT(view && ancestor && ancestor->next_local); + DBUG_ASSERT(view && ancestor); for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local) if (tbl->set_insert_values(mem_root)) return TRUE; diff --git a/sql/table.h b/sql/table.h index 0a4a06a75d1..2e397ff95bf 100644 --- a/sql/table.h +++ b/sql/table.h @@ -436,6 +436,10 @@ typedef struct st_table_list bool skip_temporary; /* this table shouldn't be temporary */ /* TRUE if this merged view contain auto_increment field */ bool contain_auto_increment; +#if 0 +#else + bool multitable_view; /* TRUE iff this is multitable view */ +#endif /* FRMTYPE_ERROR if any type is acceptable */ enum frm_type_enum required_type; char timestamp_buffer[20]; /* buffer for timestamp (19+1) */ @@ -454,7 +458,8 @@ typedef struct st_table_list void print(THD *thd, String *str); void save_and_clear_want_privilege(); void restore_want_privilege(); - bool check_single_table(st_table_list **table, table_map map); + bool check_single_table(st_table_list **table, table_map map, + st_table_list *view); bool set_insert_values(MEM_ROOT *mem_root); st_table_list *find_underlying_table(TABLE *table); } TABLE_LIST; diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c index e12ff189eaf..447eea3e635 100644 --- a/strings/ctype-big5.c +++ b/strings/ctype-big5.c @@ -6301,7 +6301,7 @@ uint my_well_formed_len_big5(CHARSET_INFO *cs __attribute__((unused)), const char *emb= e - 1; /* Last possible end of an MB character */ *error= 0; - while (pos && b < e) + while (pos-- && b < e) { if ((uchar) b[0] < 128) { diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index 9b7fd5097fa..a7d75da42c9 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -4591,7 +4591,7 @@ uint my_well_formed_len_sjis(CHARSET_INFO *cs __attribute__((unused)), { const char *b0= b; *error= 0; - while (pos && b < e) + while (pos-- && b < e) { if ((uchar) b[0] < 128) { diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index d15144b7438..e57ad8e7d69 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -1267,7 +1267,7 @@ uint my_charpos_ucs2(CHARSET_INFO *cs __attribute__((unused)), const char *e __attribute__((unused)), uint pos) { - return pos*2; + return pos > e - b ? e - b + 2 : pos * 2; } diff --git a/strings/decimal.c b/strings/decimal.c index 3fa06132cf1..1e62333ee66 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1162,6 +1162,8 @@ int decimal2bin(decimal_t *from, char *to, int precision, int frac) isize0=intg0*sizeof(dec1)+dig2bytes[intg0x], fsize0=frac0*sizeof(dec1)+dig2bytes[frac0x], fsize1=frac1*sizeof(dec1)+dig2bytes[frac1x]; + const int orig_isize0= isize0; + const int orig_fsize0= fsize0; char *orig_to= to; buf1= remove_leading_zeroes(from, &from_intg); @@ -1252,10 +1254,15 @@ int decimal2bin(decimal_t *from, char *to, int precision, int frac) } if (fsize0 > fsize1) { - while (fsize0-- > fsize1) + char *to_end= orig_to + orig_fsize0 + orig_isize0; + + while (fsize0-- > fsize1 && to < to_end) *to++=(uchar)mask; } orig_to[0]^= 0x80; + + /* Check that we have written the whole decimal and nothing more */ + DBUG_ASSERT(to == orig_to + orig_fsize0 + orig_isize0); return error; } diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 6ab5843803e..da57fbabaf2 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -2269,7 +2269,7 @@ static void test_ps_conj_select() check_execute(stmt, rc); int_data= 1; - strcpy(str_data, "hh"); + strmov(str_data, "hh"); str_length= strlen(str_data); rc= mysql_stmt_execute(stmt); @@ -7288,7 +7288,7 @@ static void test_decimal_bug() rc= mysql_stmt_bind_param(stmt, bind); check_execute(stmt, rc); - strcpy(data, "8.0"); + strmov(data, "8.0"); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); @@ -7306,7 +7306,7 @@ static void test_decimal_bug() rc= mysql_stmt_fetch(stmt); DIE_UNLESS(rc == MYSQL_NO_DATA); - strcpy(data, "5.61"); + strmov(data, "5.61"); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); @@ -7331,7 +7331,7 @@ static void test_decimal_bug() rc= mysql_stmt_fetch(stmt); DIE_UNLESS(rc == MYSQL_NO_DATA); - strcpy(data, "10.22"); is_null= 0; + strmov(data, "10.22"); is_null= 0; rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); @@ -8510,13 +8510,13 @@ static void test_sqlmode() myquery(rc); /* PIPES_AS_CONCAT */ - strcpy(query, "SET SQL_MODE= \"PIPES_AS_CONCAT\""); + strmov(query, "SET SQL_MODE= \"PIPES_AS_CONCAT\""); if (!opt_silent) fprintf(stdout, "\n With %s", query); rc= mysql_query(mysql, query); myquery(rc); - strcpy(query, "INSERT INTO test_piping VALUES(?||?)"); + strmov(query, "INSERT INTO test_piping VALUES(?||?)"); if (!opt_silent) fprintf(stdout, "\n query: %s", query); stmt= mysql_simple_prepare(mysql, query); @@ -8542,7 +8542,7 @@ static void test_sqlmode() rc= mysql_stmt_bind_param(stmt, bind); check_execute(stmt, rc); - strcpy(c1, "My"); strcpy(c2, "SQL"); + strmov(c1, "My"); strmov(c2, "SQL"); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); @@ -8552,20 +8552,20 @@ static void test_sqlmode() rc= mysql_query(mysql, "DELETE FROM test_piping"); myquery(rc); - strcpy(query, "SELECT connection_id ()"); + strmov(query, "SELECT connection_id ()"); if (!opt_silent) fprintf(stdout, "\n query: %s", query); stmt= mysql_simple_prepare(mysql, query); check_stmt_r(stmt); /* ANSI */ - strcpy(query, "SET SQL_MODE= \"ANSI\""); + strmov(query, "SET SQL_MODE= \"ANSI\""); if (!opt_silent) fprintf(stdout, "\n With %s", query); rc= mysql_query(mysql, query); myquery(rc); - strcpy(query, "INSERT INTO test_piping VALUES(?||?)"); + strmov(query, "INSERT INTO test_piping VALUES(?||?)"); if (!opt_silent) fprintf(stdout, "\n query: %s", query); stmt= mysql_simple_prepare(mysql, query); @@ -8576,7 +8576,7 @@ static void test_sqlmode() rc= mysql_stmt_bind_param(stmt, bind); check_execute(stmt, rc); - strcpy(c1, "My"); strcpy(c2, "SQL"); + strmov(c1, "My"); strmov(c2, "SQL"); rc= mysql_stmt_execute(stmt); check_execute(stmt, rc); @@ -8584,7 +8584,7 @@ static void test_sqlmode() verify_col_data("test_piping", "name", "MySQL"); /* ANSI mode spaces ... */ - strcpy(query, "SELECT connection_id ()"); + strmov(query, "SELECT connection_id ()"); if (!opt_silent) fprintf(stdout, "\n query: %s", query); stmt= mysql_simple_prepare(mysql, query); @@ -8604,13 +8604,13 @@ static void test_sqlmode() mysql_stmt_close(stmt); /* IGNORE SPACE MODE */ - strcpy(query, "SET SQL_MODE= \"IGNORE_SPACE\""); + strmov(query, "SET SQL_MODE= \"IGNORE_SPACE\""); if (!opt_silent) fprintf(stdout, "\n With %s", query); rc= mysql_query(mysql, query); myquery(rc); - strcpy(query, "SELECT connection_id ()"); + strmov(query, "SELECT connection_id ()"); if (!opt_silent) fprintf(stdout, "\n query: %s", query); stmt= mysql_simple_prepare(mysql, query); @@ -9115,7 +9115,7 @@ static void test_bug2248() /* This too should not hang but should return proper error */ rc= mysql_stmt_fetch(stmt); - DIE_UNLESS(rc == MYSQL_NO_DATA); + DIE_UNLESS(rc == 1); /* This too should not hang but should not bark */ rc= mysql_stmt_store_result(stmt); @@ -9124,7 +9124,7 @@ static void test_bug2248() /* This should return proper error */ rc= mysql_stmt_fetch(stmt); check_execute_r(stmt, rc); - DIE_UNLESS(rc == MYSQL_NO_DATA); + DIE_UNLESS(rc == 1); mysql_stmt_close(stmt); @@ -10266,7 +10266,7 @@ static void test_union_param() my_bool my_null= FALSE; myheader("test_union_param"); - strcpy(my_val, "abc"); + strmov(my_val, "abc"); query= (char*)"select ? as my_col union distinct select ?"; stmt= mysql_simple_prepare(mysql, query); @@ -10548,14 +10548,14 @@ static void test_bug3796() if (!opt_silent) printf("Concat result: '%s'\n", out_buff); check_execute(stmt, rc); - strcpy(canonical_buff, concat_arg0); + strmov(canonical_buff, concat_arg0); strcat(canonical_buff, "ONE"); DIE_UNLESS(strlen(canonical_buff) == out_length && strncmp(out_buff, canonical_buff, out_length) == 0); rc= mysql_stmt_fetch(stmt); check_execute(stmt, rc); - strcpy(canonical_buff + strlen(concat_arg0), "TWO"); + strmov(canonical_buff + strlen(concat_arg0), "TWO"); DIE_UNLESS(strlen(canonical_buff) == out_length && strncmp(out_buff, canonical_buff, out_length) == 0); if (!opt_silent) @@ -10852,7 +10852,8 @@ static void test_view() rc= mysql_stmt_prepare(stmt, query, strlen(query)); check_execute(stmt, rc); - strcpy(str_data, "TEST"); + strmov(str_data, "TEST"); + bzero(bind, sizeof(bind)); bind[0].buffer_type= FIELD_TYPE_STRING; bind[0].buffer= (char *)&str_data; bind[0].buffer_length= 50; @@ -10971,8 +10972,9 @@ static void test_view_2where() " AENAME,T0001.DEPENDVARS AS DEPENDVARS,T0001.INACTIVE AS " " INACTIVE from LTDX T0001 where (T0001.SRTF2 = 0)"); myquery(rc); + bzero(bind, sizeof(bind)); for (i=0; i < 8; i++) { - strcpy(parms[i], "1"); + strmov(parms[i], "1"); bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; bind[i].buffer = (char *)&parms[i]; bind[i].buffer_length = 100; @@ -11019,6 +11021,7 @@ static void test_view_star() myquery(rc); rc= mysql_query(mysql, "CREATE VIEW vt1 AS SELECT a FROM t1"); myquery(rc); + bzero(bind, sizeof(bind)); for (i= 0; i < 2; i++) { sprintf((char *)&parms[i], "%d", i); bind[i].buffer_type = MYSQL_TYPE_VAR_STRING; @@ -11084,6 +11087,7 @@ static void test_view_insert() rc= mysql_stmt_prepare(select_stmt, query, strlen(query)); check_execute(select_stmt, rc); + bzero(bind, sizeof(bind)); bind[0].buffer_type = FIELD_TYPE_LONG; bind[0].buffer = (char *)&my_val; bind[0].length = &my_length; @@ -11187,6 +11191,7 @@ static void test_view_insert_fields() " F7F8 AS F7F8, F6N4 AS F6N4, F5C8 AS F5C8, F9D8 AS F9D8" " from t1 T0001"); + bzero(bind, sizeof(bind)); for (i= 0; i < 11; i++) { l[i]= 20; @@ -11194,7 +11199,7 @@ static void test_view_insert_fields() bind[i].is_null= 0; bind[i].buffer= (char *)&parm[i]; - strcpy(parm[i], "1"); + strmov(parm[i], "1"); bind[i].buffer_length= 2; bind[i].length= &l[i]; } @@ -12707,6 +12712,7 @@ from t2);"); rc= mysql_query(mysql, "DROP VIEW v1"); myquery(rc); rc= mysql_query(mysql, "DROP TABLE t1, t2"); + mysql_free_result(res); myquery(rc); } @@ -12924,6 +12930,152 @@ static void test_bug9520() /* + We can't have more than one cursor open for a prepared statement. + Test re-executions of a PS with cursor; mysql_stmt_reset must close + the cursor attached to the statement, if there is one. +*/ + +static void test_bug9478() +{ + MYSQL_STMT *stmt; + MYSQL_BIND bind[1]; + char a[6]; + ulong a_len; + int rc, i; + + myheader("test_bug9478"); + + mysql_query(mysql, "drop table if exists t1"); + mysql_query(mysql, "create table t1 (id integer not null primary key, " + " name varchar(20) not null)"); + rc= mysql_query(mysql, "insert into t1 (id, name) values " + " (1, 'aaa'), (2, 'bbb'), (3, 'ccc')"); + myquery(rc); + + stmt= open_cursor("select name from t1 where id=2"); + + bzero(bind, sizeof(bind)); + bind[0].buffer_type= MYSQL_TYPE_STRING; + bind[0].buffer= (char*) a; + bind[0].buffer_length= sizeof(a); + bind[0].length= &a_len; + mysql_stmt_bind_result(stmt, bind); + + for (i= 0; i < 5; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + + /* + The query above is a one-row result set. Therefore, there is no + cursor associated with it, as the server won't bother with opening + a cursor for a one-row result set. The first row was read from the + server in the fetch above. But there is eof packet pending in the + network. mysql_stmt_execute will flush the packet and successfully + execute the statement. + */ + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + + rc= mysql_stmt_reset(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc && mysql_stmt_errno(stmt)); + if (!opt_silent && i == 0) + printf("Got error (as expected): %s\n", mysql_stmt_error(stmt)); + } + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + /* Test the case with a server side cursor */ + stmt= open_cursor("select name from t1"); + + mysql_stmt_bind_result(stmt, bind); + + for (i= 0; i < 5; i++) + { + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + /* + Although protocol-wise an attempt to execute a statement which + already has an open cursor associated with it will yield an error, + the client library behavior tested here is consistent with + the non-cursor execution scenario: mysql_stmt_execute will + silently close the cursor if necessary. + */ + { + char buff[9]; + bzero(buff, sizeof(buff)); + /* Fill in the execute packet */ + int4store(buff, stmt->stmt_id); + int4store(buff+5, 1); + rc= ((*mysql->methods->advanced_command)(mysql, COM_EXECUTE, buff, + sizeof(buff), 0,0,1) || + (*mysql->methods->read_query_result)(mysql)); + DIE_UNLESS(rc); + if (!opt_silent && i == 0) + printf("Got error (as expected): %s\n", mysql_error(mysql)); + } + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + while (! (rc= mysql_stmt_fetch(stmt))) + { + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + } + DIE_UNLESS(rc == MYSQL_NO_DATA); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + + rc= mysql_stmt_fetch(stmt); + check_execute(stmt, rc); + if (!opt_silent && i == 0) + printf("Fetched row: %s\n", a); + + rc= mysql_stmt_reset(stmt); + check_execute(stmt, rc); + rc= mysql_stmt_fetch(stmt); + DIE_UNLESS(rc && mysql_stmt_errno(stmt)); + if (!opt_silent && i == 0) + printf("Got error (as expected): %s\n", mysql_stmt_error(stmt)); + } + + rc= mysql_stmt_close(stmt); + DIE_UNLESS(rc == 0); + + rc= mysql_query(mysql, "drop table t1"); + myquery(rc); +} + + +/* Read and parse arguments and MySQL options from my.cnf */ @@ -13153,6 +13305,7 @@ static struct my_tests_st my_tests[]= { { "test_bug8880", test_bug8880 }, { "test_bug9159", test_bug9159 }, { "test_bug9520", test_bug9520 }, + { "test_bug9478", test_bug9478 }, { 0, 0 } }; |