diff --git a/.bzrignore b/.bzrignore index e794d7d51cc..10388d79013 100644 --- a/.bzrignore +++ b/.bzrignore @@ -924,3 +924,19 @@ Docs/Images/mydsn.txt Docs/Images/myflowchart.txt mysql-test/mysql_test_run_new ndb/tools/ndb_test_platform +help +ndbcluster-1186 +ndbcluster-1186/SCCS +ndbcluster-1186/config.ini +ndbcluster-1186/ndb_1.pid +ndbcluster-1186/ndb_1_out.log +ndbcluster-1186/ndb_1_signal.log +ndbcluster-1186/ndb_2.pid +ndbcluster-1186/ndb_2_out.log +ndbcluster-1186/ndb_2_signal.log +ndbcluster-1186/ndb_3.pid +ndbcluster-1186/ndb_3_cluster.log +ndbcluster-1186/ndb_3_out.log +ndbcluster-1186/ndbcluster.pid +ndb/tools/ndb_restore +ac_available_languages_fragment diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 1f1918027e2..00f4c86d319 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -101,6 +101,7 @@ lenz@mysql.com magnus@neptunus.(none) magnus@shellback.(none) marko@hundin.mysql.fi +mats@mysql.com matt@mysql.com matthias@three.local.lan miguel@hegel.(none) @@ -139,6 +140,7 @@ msvensson@build.mysql.com mwagner@cash.mwagner.org mwagner@evoq.mwagner.org mwagner@here.mwagner.org +mwagner@mysql.com mwagner@work.mysql.com mydev@mysql.com mysql@home.(none) @@ -163,6 +165,7 @@ pem@mysql.com peter@linux.local peter@mysql.com peterg@mysql.com +petr@mysql.com pgulutzan@linux.local ram@deer.(none) ram@gw.mysql.r18.ru @@ -199,6 +202,7 @@ tim@siva.hindu.god tim@threads.polyesthetic.msg tim@white.box tim@work.mysql.com +timour@mysql.com tom@basil-firewall.home.com tomas@mc05.(none) tomas@poseidon.(none) diff --git a/Build-tools/Do-compile b/Build-tools/Do-compile index f3c20c81a9f..e98c3d84937 100755 --- a/Build-tools/Do-compile +++ b/Build-tools/Do-compile @@ -10,7 +10,7 @@ use Sys::Hostname; $opt_distribution=$opt_user=$opt_config_env=$opt_config_extra_env=""; $opt_dbd_options=$opt_perl_options=$opt_config_options=$opt_make_options=$opt_suffix=""; $opt_tmp=$opt_version_suffix=""; -$opt_bundled_zlib=$opt_help=$opt_delete=$opt_debug=$opt_stage=$opt_no_test=$opt_no_perl=$opt_with_low_memory=$opt_fast_benchmark=$opt_static_client=$opt_static_server=$opt_static_perl=$opt_sur=$opt_with_small_disk=$opt_local_perl=$opt_tcpip=$opt_build_thread=$opt_use_old_distribution=$opt_enable_shared=$opt_no_crash_me=$opt_no_strip=$opt_with_cluster=$opt_with_debug=$opt_no_benchmark=$opt_no_mysqltest=$opt_without_embedded=$opt_readline=0; +$opt_bundled_zlib=$opt_help=$opt_delete=$opt_debug=$opt_stage=$opt_no_test=$opt_no_perl=$opt_one_error=$opt_with_low_memory=$opt_fast_benchmark=$opt_static_client=$opt_static_server=$opt_static_perl=$opt_sur=$opt_with_small_disk=$opt_local_perl=$opt_tcpip=$opt_build_thread=$opt_use_old_distribution=$opt_enable_shared=$opt_no_crash_me=$opt_no_strip=$opt_with_cluster=$opt_with_debug=$opt_no_benchmark=$opt_no_mysqltest=$opt_without_embedded=$opt_readline=0; $opt_innodb=$opt_bdb=$opt_raid=$opt_libwrap=$opt_clearlogs=0; GetOptions( @@ -37,6 +37,7 @@ GetOptions( "no-test", "no-mysqltest", "no-benchmark", + "one-error", "perl-files=s", "perl-options=s", "raid", @@ -310,6 +311,7 @@ if ($opt_stage <= 2) $command=$make; $command.= " $opt_make_options" if (defined($opt_make_options) && $opt_make_options ne ""); safe_system($command); + print LOG "Do-compile: Build successful\n"; } # @@ -372,11 +374,14 @@ $ENV{"LD_LIBRARY_PATH"}= ("$test_dir/lib" . if ($opt_stage <= 5 && !$opt_no_test && !$opt_no_mysqltest) { my $flags= ""; + my $force= ""; $flags.= " --with-ndbcluster" if ($opt_with_cluster); + $flags.= " --force" if (!$opt_one_error); log_timestamp(); system("mkdir $bench_tmpdir") if (! -d $bench_tmpdir); safe_cd("${test_dir}/mysql-test"); check_system("./mysql-test-run $flags --tmpdir=$bench_tmpdir --master_port=$mysql_tcp_port --slave_port=$slave_port --ndbcluster_port=$ndbcluster_port --manager-port=$manager_port --no-manager --sleep=10", "tests were successful"); + # 'mysql-test-run' writes its own final message for log evaluation. } # @@ -555,7 +560,10 @@ Do not run any tests. Do not run the benchmark test (written in perl) --no-mysqltest -Do not run the the mysql-test-run test (Same as 'make test') +Do not run the mysql-test-run test (Same as 'make test') + +--one-error +Terminate the mysql-test-run test after the first difference (default: use '--force') --no-perl Do not compile or install Perl modules, use the system installed ones diff --git a/VC++Files/client/mysqladmin.dsp b/VC++Files/client/mysqladmin.dsp index a7e4404e253..7a0b3bec1a7 100644 --- a/VC++Files/client/mysqladmin.dsp +++ b/VC++Files/client/mysqladmin.dsp @@ -115,7 +115,7 @@ LINK32=xilink6.exe # Name "mysqladmin - Win32 classic" # Begin Source File -SOURCE=.\mysqladmin.c +SOURCE=.\mysqladmin.cpp # End Source File # End Target # End Project diff --git a/client/Makefile.am b/client/Makefile.am index 1c552036f9b..fa317367f71 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -20,14 +20,14 @@ INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/regex \ $(openssl_includes) LIBS = @CLIENT_LIBS@ -DEPLIB= @ndb_mgmclient_libs@ \ - ../libmysql/libmysqlclient.la +DEPLIB= ../libmysql/libmysqlclient.la LDADD = @CLIENT_EXTRA_LDFLAGS@ $(DEPLIB) bin_PROGRAMS = mysql mysqladmin mysqlcheck mysqlshow \ mysqldump mysqlimport mysqltest mysqlbinlog mysqlmanagerc mysqlmanager-pwgen noinst_HEADERS = sql_string.h completion_hash.h my_readline.h \ client_priv.h mysql_SOURCES = mysql.cc readline.cc sql_string.cc completion_hash.cc +mysqladmin_SOURCES = mysqladmin.cc mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) $(CXXLDFLAGS) mysqlbinlog_LDADD = $(LDADD) $(CXXLDFLAGS) mysql_DEPENDENCIES= $(LIBRARIES) $(pkglib_LTLIBRARIES) $(DEPLIB) diff --git a/client/mysql.cc b/client/mysql.cc index 358b13e652b..8e9dd84c8f0 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1609,7 +1609,7 @@ static void print_help_item(MYSQL_ROW *cur, int num_name, int num_cat, char *las char ccat= (*cur)[num_cat][0]; if (*last_char != ccat) { - put_info(ccat == 'Y' ? "categories :" : "topics :", INFO_INFO); + put_info(ccat == 'Y' ? "categories:" : "topics:", INFO_INFO); *last_char= ccat; } tee_fprintf(PAGER, " %s\n", (*cur)[num_name]); @@ -1676,8 +1676,8 @@ static int com_server_help(String *buffer __attribute__((unused)), if (num_fields == 2) { - put_info("Many help items for your request exist", INFO_INFO); - put_info("To make a more specific request, please type 'help ',\nwhere item is one of next", INFO_INFO); + put_info("Many help items for your request exist.", INFO_INFO); + put_info("To make a more specific request, please type 'help ',\nwhere item is one of the following", INFO_INFO); num_name= 0; num_cat= 1; last_char= '_'; diff --git a/client/mysqladmin.c b/client/mysqladmin.cc similarity index 98% rename from client/mysqladmin.c rename to client/mysqladmin.cc index a32dfa14d28..b95ad83f7e8 100644 --- a/client/mysqladmin.c +++ b/client/mysqladmin.cc @@ -24,7 +24,7 @@ #include #include -#ifdef HAVE_NDBCLUSTER_DB +#ifdef LATER_HAVE_NDBCLUSTER_DB #include "../ndb/src/mgmclient/ndb_mgmclient.h" #endif @@ -45,7 +45,7 @@ static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations, opt_count_iterations= 0; static ulong opt_connect_timeout, opt_shutdown_timeout; static my_string unix_port=0; -#ifdef HAVE_NDBCLUSTER_DB +#ifdef LATER_HAVE_NDBCLUSTER_DB static my_bool opt_ndbcluster=0; static char *opt_ndb_connectstring=0; #endif @@ -101,7 +101,7 @@ enum commands { ADMIN_PING, ADMIN_EXTENDED_STATUS, ADMIN_FLUSH_STATUS, ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE, ADMIN_STOP_SLAVE, ADMIN_FLUSH_THREADS, ADMIN_OLD_PASSWORD -#ifdef HAVE_NDBCLUSTER_DB +#ifdef LATER_HAVE_NDBCLUSTER_DB ,ADMIN_NDB_MGM #endif }; @@ -114,7 +114,7 @@ static const char *command_names[]= { "ping", "extended-status", "flush-status", "flush-privileges", "start-slave", "stop-slave", "flush-threads","old-password", -#ifdef HAVE_NDBCLUSTER_DB +#ifdef LATER_HAVE_NDBCLUSTER_DB "ndb-mgm", #endif NullS @@ -125,6 +125,10 @@ static TYPELIB command_typelib= static struct my_option my_long_options[] = { +#ifdef __NETWARE__ + {"autoclose", 'a', " Auto close the screen on exit for NetWare", + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"count", 'c', "Number of iterations to make. This works with -i (--sleep) only.", (gptr*) &nr_iterations, (gptr*) &nr_iterations, 0, GET_UINT, @@ -197,7 +201,7 @@ static struct my_option my_long_options[] = {"shutdown_timeout", OPT_SHUTDOWN_TIMEOUT, "", (gptr*) &opt_shutdown_timeout, (gptr*) &opt_shutdown_timeout, 0, GET_ULONG, REQUIRED_ARG, SHUTDOWN_DEF_TIMEOUT, 0, 3600*12, 0, 1, 0}, -#ifdef HAVE_NDBCLUSTER_DB +#ifdef LATER_HAVE_NDBCLUSTER_DB {"ndbcluster", OPT_NDBCLUSTER, "" "", (gptr*) &opt_ndbcluster, (gptr*) &opt_ndbcluster, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -218,6 +222,11 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int error = 0; switch(optid) { +#ifdef __NETWARE__ + case 'a': + setscreenmode(SCR_AUTOCLOSE_ON_EXIT); // auto close the screen / + break; +#endif case 'c': opt_count_iterations= 1; break; @@ -608,7 +617,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) { char *pos,buff[40]; ulong sec; - pos=strchr(status,' '); + pos= (char*) strchr(status,' '); *pos++=0; printf("%s\t\t\t",status); /* print label */ if ((status=str2int(pos,10,0,LONG_MAX,(long*) &sec))) @@ -903,7 +912,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv) } mysql->reconnect=1; /* Automatic reconnect is default */ break; -#ifdef HAVE_NDBCLUSTER_DB +#ifdef LATER_HAVE_NDBCLUSTER_DB case ADMIN_NDB_MGM: { if (argc < 2) @@ -1287,9 +1296,6 @@ static my_bool wait_pidfile(char *pidfile, time_t last_modified, } DBUG_RETURN(error); } -#ifdef HAVE_NDBCLUSTER_DB -/* lib linked in contains c++ code */ #ifdef __GNUC__ FIX_GCC_LINKING_PROBLEM #endif -#endif diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc index 8015871428e..de53831c43d 100644 --- a/client/mysqlbinlog.cc +++ b/client/mysqlbinlog.cc @@ -44,7 +44,7 @@ static const char *load_default_groups[]= { "mysqlbinlog","client",0 }; void sql_print_error(const char *format, ...); -static bool one_database=0, to_last_remote_log= 0; +static bool one_database=0, to_last_remote_log= 0, disable_log_bin= 0; static const char* database= 0; static my_bool force_opt= 0, short_form= 0, remote_opt= 0; static ulonglong offset = 0; @@ -438,6 +438,13 @@ static struct my_option my_long_options[] = {"database", 'd', "List entries for just this database (local log only).", (gptr*) &database, (gptr*) &database, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"disable-log-bin", 'D', "Disable binary log. This is useful, if you " + "enabled --to-last-log and are sending the output to the same MySQL server. " + "This way you could avoid an endless loop. You would also like to use it " + "when restoring after a crash to avoid duplication of the statements you " + "already have. NOTE: you will need a SUPER privilege to use this option.", + (gptr*) &disable_log_bin, (gptr*) &disable_log_bin, 0, GET_BOOL, + NO_ARG, 0, 0, 0, 0, 0, 0}, {"force-read", 'f', "Force reading unknown binlog events.", (gptr*) &force_opt, (gptr*) &force_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -1068,6 +1075,11 @@ int main(int argc, char** argv) fprintf(result_file, "/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n"); + + if (disable_log_bin) + fprintf(result_file, + "/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n"); + for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ; (--argc >= 0) && !stop_passed ; ) { @@ -1082,6 +1094,9 @@ int main(int argc, char** argv) start_position= BIN_LOG_HEADER_SIZE; } + if (disable_log_bin) + fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n"); + if (tmpdir.list) free_tmpdir(&tmpdir); if (result_file != stdout) diff --git a/client/mysqldump.c b/client/mysqldump.c index cfe93a11024..5c78abc033e 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -1890,7 +1890,7 @@ static int init_dumping(char *database) MYSQL_ROW row; MYSQL_RES *dbinfo; - sprintf(qbuf,"SHOW CREATE DATABASE WITH IF NOT EXISTS %s", + sprintf(qbuf,"SHOW CREATE DATABASE IF NOT EXISTS %s", qdatabase); if (mysql_query_with_error_report(sock, &dbinfo, qbuf)) diff --git a/configure.in b/configure.in index f360ee46453..0d6e797f571 100644 --- a/configure.in +++ b/configure.in @@ -399,7 +399,6 @@ then then if $CXX -v 2>&1 | grep 'version 3' > /dev/null 2>&1 then - CFLAGS="$CFLAGS -DDEFINE_CXA_PURE_VIRTUAL" CXXFLAGS="$CXXFLAGS -DUSE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL" fi fi @@ -1932,9 +1931,11 @@ AC_CHECK_FUNCS(alarm bcmp bfill bmove bzero chsize cuserid fchmod fcntl \ # # case "$target" in - *-*-aix4*) + *-*-aix4* | *-*-sco*) # (grr) aix 4.3 has a stub for clock_gettime, (returning ENOSYS) # and using AC_TRY_RUN is hard when cross-compiling + # We also disable for SCO for the time being, the headers for the + # thread library we use conflicts with other headers. ;; *) AC_CHECK_FUNCS(clock_gettime) ;; diff --git a/extra/perror.c b/extra/perror.c index a28626fd873..1bd4b203120 100644 --- a/extra/perror.c +++ b/extra/perror.c @@ -69,7 +69,7 @@ static HA_ERRORS ha_errlist[]= { { 120,"Didn't find key on read or update" }, { 121,"Duplicate key on write or update" }, - { 123,"Someone has changed the row since it was read; Update with is recoverable" }, + { 123,"Someone has changed the row since it was read (while the table was locked to prevent it)" }, { 124,"Wrong index given to function" }, { 126,"Index file is crashed" }, { 127,"Record-file is crashed" }, diff --git a/heap/hp_rfirst.c b/heap/hp_rfirst.c index 1668376ed1c..85548fea212 100644 --- a/heap/hp_rfirst.c +++ b/heap/hp_rfirst.c @@ -52,6 +52,7 @@ int heap_rfirst(HP_INFO *info, byte *record, int inx) my_errno=HA_ERR_END_OF_FILE; DBUG_RETURN(my_errno); } + DBUG_ASSERT(0); /* TODO fix it */ info->current_record=0; info->current_hash_ptr=0; info->update=HA_STATE_PREV_FOUND; diff --git a/include/m_ctype.h b/include/m_ctype.h index ddc21070547..26e285b9683 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -63,7 +63,7 @@ typedef struct unicase_info_st #define MY_CS_UNICODE 128 /* is a charset is full unicode */ #define MY_CS_READY 256 /* if a charset is initialized */ #define MY_CS_AVAILABLE 512 /* If either compiled-in or loaded*/ - +#define MY_CS_CSSORT 1024 /* if case sensitive sort order */ #define MY_CHARSET_UNDEFINED 0 diff --git a/include/my_time.h b/include/my_time.h index dab17904b2d..94701e159c4 100644 --- a/include/my_time.h +++ b/include/my_time.h @@ -58,14 +58,15 @@ void init_time(void); my_time_t my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap); -void set_zero_time(MYSQL_TIME *tm); +void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type); /* Required buffer length for my_time_to_str, my_date_to_str, my_datetime_to_str and TIME_to_string functions. Note, that the caller is still responsible to check that given TIME structure has values in valid ranges, otherwise size of the buffer could - be not enough. + be not enough. We also rely on the fact that even wrong values + sent using binary protocol fit in this buffer. */ #define MAX_DATE_STRING_REP_LENGTH 30 diff --git a/include/mysql_time.h b/include/mysql_time.h index ec67d60dea5..5f4fc12c005 100644 --- a/include/mysql_time.h +++ b/include/mysql_time.h @@ -33,6 +33,18 @@ enum enum_mysql_timestamp_type }; +/* + Structure which is used to represent datetime values inside MySQL. + + We assume that values in this structure are normalized, i.e. year <= 9999, + month <= 12, day <= 31, hour <= 23, hour <= 59, hour <= 59. Many functions + in server such as my_system_gmt_sec() or make_time() family of functions + rely on this (actually now usage of make_*() family relies on a bit weaker + restriction). Also functions that produce MYSQL_TIME as result ensure this. + There is one exception to this rule though if this structure holds time + value (time_type == MYSQL_TIMESTAMP_TIME) days and hour member can hold + bigger values. +*/ typedef struct st_mysql_time { unsigned int year, month, day, hour, minute, second; diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c index adb69f3c3a7..699ad5fb42e 100644 --- a/innobase/buf/buf0buf.c +++ b/innobase/buf/buf0buf.c @@ -547,8 +547,9 @@ buf_pool_init( } /*----------------------------------------*/ } else { - buf_pool->frame_mem = ut_malloc( - UNIV_PAGE_SIZE * (n_frames + 1)); + buf_pool->frame_mem = ut_malloc_low( + UNIV_PAGE_SIZE * (n_frames + 1), + TRUE, FALSE); } if (buf_pool->frame_mem == NULL) { diff --git a/innobase/buf/buf0lru.c b/innobase/buf/buf0lru.c index 796311f0157..f3fb19ae183 100644 --- a/innobase/buf/buf0lru.c +++ b/innobase/buf/buf0lru.c @@ -42,6 +42,10 @@ initial segment in buf_LRU_get_recent_limit */ #define BUF_LRU_INITIAL_RATIO 8 +/* If we switch on the InnoDB monitor because there are too few available +frames in the buffer pool, we set this to TRUE */ +ibool buf_lru_switched_on_innodb_mon = FALSE; + /********************************************************************** Takes a block out of the LRU list and page hash table and sets the block state to BUF_BLOCK_REMOVE_HASH. */ @@ -287,6 +291,32 @@ buf_LRU_try_free_flushed_blocks(void) mutex_exit(&(buf_pool->mutex)); } +/********************************************************************** +Returns TRUE if less than 15 % of the buffer pool is available. This can be +used in heuristics to prevent huge transactions eating up the whole buffer +pool for their locks. */ + +ibool +buf_LRU_buf_pool_running_out(void) +/*==============================*/ + /* out: TRUE if less than 15 % of buffer pool + left */ +{ + ibool ret = FALSE; + + mutex_enter(&(buf_pool->mutex)); + + if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) + + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 7) { + + ret = TRUE; + } + + mutex_exit(&(buf_pool->mutex)); + + return(ret); +} + /********************************************************************** Returns a free block from buf_pool. The block is taken off the free list. If it is empty, blocks are moved from the end of the LRU list to the free @@ -325,7 +355,8 @@ loop: } else if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 5) { - if (!srv_print_innodb_monitor) { + + if (!buf_lru_switched_on_innodb_mon) { /* Over 80 % of the buffer pool is occupied by lock heaps or the adaptive hash index. This may be a memory @@ -342,16 +373,18 @@ loop: "InnoDB: lock heap and hash index sizes.\n", (ulong) (buf_pool->curr_size / (1024 * 1024 / UNIV_PAGE_SIZE))); + buf_lru_switched_on_innodb_mon = TRUE; srv_print_innodb_monitor = TRUE; os_event_set(srv_lock_timeout_thread_event); } - } else if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) - + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 4) { + } else if (buf_lru_switched_on_innodb_mon) { /* Switch off the InnoDB Monitor; this is a simple way to stop the monitor if the situation becomes less urgent, - but may also surprise users! */ + but may also surprise users if the user also switched on the + monitor! */ + buf_lru_switched_on_innodb_mon = FALSE; srv_print_innodb_monitor = FALSE; } diff --git a/innobase/configure.in b/innobase/configure.in index 652291f1f38..d83da9fdc5c 100644 --- a/innobase/configure.in +++ b/innobase/configure.in @@ -110,6 +110,9 @@ esac case "$target" in i[[4567]]86-*-*) CFLAGS="$CFLAGS -DUNIV_INTEL_X86";; + # The compiler on Linux/S390 does not seem to have inlining + s390-*-*) + CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";; esac AC_OUTPUT(Makefile os/Makefile ut/Makefile btr/Makefile dnl diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index 7d57468f632..de528355182 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -106,7 +106,7 @@ struct fil_node_struct { device or a raw disk partition */ ulint size; /* size of the file in database pages, 0 if not known yet; the possible last incomplete - megabyte is ignored if space == 0 */ + megabyte may be ignored if space == 0 */ ulint n_pending; /* count of pending i/o's on this file; closing of the file is not allowed if @@ -160,7 +160,9 @@ struct fil_space_struct { UT_LIST_BASE_NODE_T(fil_node_t) chain; /* base node for the file chain */ ulint size; /* space size in pages; 0 if a single-table - tablespace whose size we do not know yet */ + tablespace whose size we do not know yet; + last incomplete megabytes in data files may be + ignored if space == 0 */ ulint n_reserved_extents; /* number of reserved free extents for ongoing operations like B-tree page split */ @@ -3255,7 +3257,7 @@ fil_extend_space_to_desired_size( ulint* actual_size, /* out: size of the space after extension; if we ran out of disk space this may be lower than the desired size */ - ulint space_id, /* in: space id, must be != 0 */ + ulint space_id, /* in: space id */ ulint size_after_extend)/* in: desired size in pages after the extension; if the current space size is bigger than this already, the function does nothing */ @@ -3352,6 +3354,17 @@ fil_extend_space_to_desired_size( fil_node_complete_io(node, system, OS_FILE_WRITE); *actual_size = space->size; + + if (space_id == 0) { + ulint pages_per_mb = (1024 * 1024) / UNIV_PAGE_SIZE; + + /* Keep the last data file size info up to date, rounded to + full megabytes */ + + srv_data_file_sizes[srv_n_data_files - 1] = + (node->size / pages_per_mb) * pages_per_mb; + } + /* printf("Extended %s to %lu, actual size %lu pages\n", space->name, size_after_extend, *actual_size); */ diff --git a/innobase/include/buf0lru.h b/innobase/include/buf0lru.h index 69a376f8cab..45164dd561e 100644 --- a/innobase/include/buf0lru.h +++ b/innobase/include/buf0lru.h @@ -25,6 +25,16 @@ wasted. */ void buf_LRU_try_free_flushed_blocks(void); /*==================================*/ +/********************************************************************** +Returns TRUE if less than 15 % of the buffer pool is available. This can be +used in heuristics to prevent huge transactions eating up the whole buffer +pool for their locks. */ + +ibool +buf_LRU_buf_pool_running_out(void); +/*==============================*/ + /* out: TRUE if less than 15 % of buffer pool + left */ /*####################################################################### These are low-level functions diff --git a/innobase/include/db0err.h b/innobase/include/db0err.h index be7667bfd0c..de5ac44e73f 100644 --- a/innobase/include/db0err.h +++ b/innobase/include/db0err.h @@ -53,7 +53,11 @@ Created 5/24/1996 Heikki Tuuri name already exists */ #define DB_TABLESPACE_DELETED 44 /* tablespace does not exist or is being dropped right now */ - +#define DB_LOCK_TABLE_FULL 45 /* lock structs have exhausted the + buffer pool (for big transactions, + InnoDB stores the lock structs in the + buffer pool) */ + /* The following are partial failure codes */ #define DB_FAIL 1000 #define DB_OVERFLOW 1001 diff --git a/innobase/include/fil0fil.h b/innobase/include/fil0fil.h index 5a5db77073a..43327aab9d2 100644 --- a/innobase/include/fil0fil.h +++ b/innobase/include/fil0fil.h @@ -478,7 +478,7 @@ fil_extend_space_to_desired_size( ulint* actual_size, /* out: size of the space after extension; if we ran out of disk space this may be lower than the desired size */ - ulint space_id, /* in: space id, must be != 0 */ + ulint space_id, /* in: space id */ ulint size_after_extend);/* in: desired size in pages after the extension; if the current space size is bigger than this already, the function does nothing */ diff --git a/innobase/include/lock0lock.h b/innobase/include/lock0lock.h index f8435e14d97..1fd7492d517 100644 --- a/innobase/include/lock0lock.h +++ b/innobase/include/lock0lock.h @@ -463,13 +463,32 @@ lock_rec_hash( ulint space, /* in: space */ ulint page_no);/* in: page number */ /************************************************************************* -Gets the table covered by an IX table lock. */ +Gets the source table of an ALTER TABLE transaction. The table must be +covered by an IX or IS table lock. */ dict_table_t* -lock_get_ix_table( -/*==============*/ - /* out: the table covered by the lock */ - lock_t* lock); /* in: table lock */ +lock_get_src_table( +/*===============*/ + /* out: the source table of transaction, + if it is covered by an IX or IS table lock; + dest if there is no source table, and + NULL if the transaction is locking more than + two tables or an inconsistency is found */ + trx_t* trx, /* in: transaction */ + dict_table_t* dest, /* in: destination of ALTER TABLE */ + ulint* mode); /* out: lock mode of the source table */ +/************************************************************************* +Determine if the given table is exclusively "owned" by the given +transaction, i.e., transaction holds LOCK_IX and possibly LOCK_AUTO_INC +on the table. */ + +ibool +lock_is_table_exclusive( +/*====================*/ + /* out: TRUE if table is only locked by trx, + with LOCK_IX, and possibly LOCK_AUTO_INC */ + dict_table_t* table, /* in: table */ + trx_t* trx); /* in: transaction */ /************************************************************************* Checks that a transaction id is sensible, i.e., not in the future. */ diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index 73f41dea0da..f47ce74ce37 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -177,10 +177,12 @@ row_lock_table_for_mysql( /* out: error code or DB_SUCCESS */ row_prebuilt_t* prebuilt, /* in: prebuilt struct in the MySQL table handle */ - dict_table_t* table); /* in: table to LOCK_IX, or NULL + dict_table_t* table, /* in: table to lock, or NULL if prebuilt->table should be locked as LOCK_TABLE_EXP | prebuilt->select_lock_type */ + ulint mode); /* in: lock mode of table */ + /************************************************************************* Does an insert for MySQL. */ diff --git a/innobase/include/row0sel.h b/innobase/include/row0sel.h index bb6fb70ca86..8d5187bfc1c 100644 --- a/innobase/include/row0sel.h +++ b/innobase/include/row0sel.h @@ -120,6 +120,7 @@ row_search_for_mysql( /* out: DB_SUCCESS, DB_RECORD_NOT_FOUND, DB_END_OF_INDEX, DB_DEADLOCK, + DB_LOCK_TABLE_FULL, or DB_TOO_BIG_RECORD */ byte* buf, /* in/out: buffer for the fetched row in the MySQL format */ diff --git a/innobase/include/ut0mem.h b/innobase/include/ut0mem.h index 73ecb25101a..74357f6bf13 100644 --- a/innobase/include/ut0mem.h +++ b/innobase/include/ut0mem.h @@ -38,8 +38,10 @@ ut_malloc_low( /*==========*/ /* out, own: allocated memory */ ulint n, /* in: number of bytes to allocate */ - ibool set_to_zero); /* in: TRUE if allocated memory should be set + ibool set_to_zero, /* in: TRUE if allocated memory should be set to zero if UNIV_SET_MEM_TO_ZERO is defined */ + ibool assert_on_error); /* in: if TRUE, we crash mysqld if the memory + cannot be allocated */ /************************************************************************** Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is defined. */ diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c index 6f2d58b72c3..29a274261f8 100644 --- a/innobase/lock/lock0lock.c +++ b/innobase/lock/lock0lock.c @@ -365,6 +365,21 @@ lock_deadlock_recursive( ulint* cost); /* in/out: number of calculation steps thus far: if this exceeds LOCK_MAX_N_STEPS_... we return TRUE */ + +/************************************************************************* +Gets the type of a lock. */ +UNIV_INLINE +ulint +lock_get_type( +/*==========*/ + /* out: LOCK_TABLE or LOCK_REC */ + lock_t* lock) /* in: lock */ +{ + ut_ad(lock); + + return(lock->type_mode & LOCK_TYPE_MASK); +} + /************************************************************************* Gets the nth bit of a record lock. */ UNIV_INLINE @@ -395,19 +410,6 @@ lock_rec_get_nth_bit( return(ut_bit_get_nth(b, bit_index)); } -/************************************************************************* -Gets the table covered by an IX table lock. */ - -dict_table_t* -lock_get_ix_table( -/*==============*/ - /* out: the table covered by the lock */ - lock_t* lock) /* in: table lock */ -{ - ut_a(lock->type_mode == (LOCK_TABLE | LOCK_IX)); - return(lock->un_member.tab_lock.table); -} - /*************************************************************************/ #define lock_mutex_enter_kernel() mutex_enter(&kernel_mutex) @@ -581,20 +583,6 @@ lock_get_mode( return(lock->type_mode & LOCK_MODE_MASK); } -/************************************************************************* -Gets the type of a lock. */ -UNIV_INLINE -ulint -lock_get_type( -/*==========*/ - /* out: LOCK_TABLE or LOCK_REC */ - lock_t* lock) /* in: lock */ -{ - ut_ad(lock); - - return(lock->type_mode & LOCK_TYPE_MASK); -} - /************************************************************************* Gets the wait flag of a lock. */ UNIV_INLINE @@ -614,6 +602,128 @@ lock_get_wait( return(FALSE); } +/************************************************************************* +Gets the source table of an ALTER TABLE transaction. The table must be +covered by an IX or IS table lock. */ + +dict_table_t* +lock_get_src_table( +/*===============*/ + /* out: the source table of transaction, + if it is covered by an IX or IS table lock; + dest if there is no source table, and + NULL if the transaction is locking more than + two tables or an inconsistency is found */ + trx_t* trx, /* in: transaction */ + dict_table_t* dest, /* in: destination of ALTER TABLE */ + ulint* mode) /* out: lock mode of the source table */ +{ + dict_table_t* src; + lock_t* lock; + + src = NULL; + *mode = LOCK_NONE; + + for (lock = UT_LIST_GET_FIRST(trx->trx_locks); + lock; + lock = UT_LIST_GET_NEXT(trx_locks, lock)) { + lock_table_t* tab_lock; + ulint lock_mode; + if (!(lock_get_type(lock) & LOCK_TABLE)) { + /* We are only interested in table locks. */ + continue; + } + tab_lock = &lock->un_member.tab_lock; + if (dest == tab_lock->table) { + /* We are not interested in the destination table. */ + continue; + } else if (!src) { + /* This presumably is the source table. */ + src = tab_lock->table; + if (UT_LIST_GET_LEN(src->locks) != 1 || + UT_LIST_GET_FIRST(src->locks) != lock) { + /* We only support the case when + there is only one lock on this table. */ + return(NULL); + } + } else if (src != tab_lock->table) { + /* The transaction is locking more than + two tables (src and dest): abort */ + return(NULL); + } + + /* Check that the source table is locked by + LOCK_IX or LOCK_IS. */ + lock_mode = lock_get_mode(lock); + switch (lock_mode) { + case LOCK_IX: + case LOCK_IS: + if (*mode != LOCK_NONE && *mode != lock_mode) { + /* There are multiple locks on src. */ + return(NULL); + } + *mode = lock_mode; + break; + } + } + + if (!src) { + /* No source table lock found: flag the situation to caller */ + src = dest; + } + + return(src); +} + +/************************************************************************* +Determine if the given table is exclusively "owned" by the given +transaction, i.e., transaction holds LOCK_IX and possibly LOCK_AUTO_INC +on the table. */ + +ibool +lock_is_table_exclusive( +/*====================*/ + /* out: TRUE if table is only locked by trx, + with LOCK_IX, and possibly LOCK_AUTO_INC */ + dict_table_t* table, /* in: table */ + trx_t* trx) /* in: transaction */ +{ + lock_t* lock; + bool ok = FALSE; + + ut_ad(table && trx); + + for (lock = UT_LIST_GET_FIRST(table->locks); + lock; + lock = UT_LIST_GET_NEXT(locks, &lock->un_member.tab_lock)) { + if (lock->trx != trx) { + /* A lock on the table is held + by some other transaction. */ + return(FALSE); + } + + if (!(lock_get_type(lock) & LOCK_TABLE)) { + /* We are interested in table locks only. */ + continue; + } + + switch (lock_get_mode(lock)) { + case LOCK_IX: + ok = TRUE; + break; + case LOCK_AUTO_INC: + /* It is allowed for trx to hold an + auto_increment lock. */ + break; + default: + /* Other table locks than LOCK_IX are not allowed. */ + return(FALSE); + } + } + + return(ok); +} + /************************************************************************* Sets the wait flag of a lock and the back pointer in trx to lock. */ UNIV_INLINE @@ -4063,6 +4173,9 @@ lock_print_info( (ulong) ut_dulint_get_high(purge_sys->purge_undo_no), (ulong) ut_dulint_get_low(purge_sys->purge_undo_no)); + fprintf(file, + "History list length %lu\n", (ulong) trx_sys->rseg_history_len); + fprintf(file, "Total number of lock structs in row lock hash table %lu\n", (ulong) lock_get_n_rec_locks()); diff --git a/innobase/mem/mem0pool.c b/innobase/mem/mem0pool.c index 023369e8ec5..cb891a03092 100644 --- a/innobase/mem/mem0pool.c +++ b/innobase/mem/mem0pool.c @@ -199,7 +199,7 @@ mem_pool_create( but only when allocated at a higher level in mem0mem.c. This is to avoid masking useful Purify warnings. */ - pool->buf = ut_malloc_low(size, FALSE); + pool->buf = ut_malloc_low(size, FALSE, TRUE); pool->size = size; mutex_create(&(pool->mutex)); diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index c45818ddd26..6d1482b6720 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -1509,7 +1509,6 @@ row_ins_scan_sec_index_for_duplicate( ibool moved; mtr_t mtr; trx_t* trx; - const char* ptr; n_unique = dict_index_get_n_unique(index); @@ -1630,7 +1629,6 @@ row_ins_duplicate_error_in_clust( page_t* page; ulint n_unique; trx_t* trx = thr_get_trx(thr); - const char* ptr; UT_NOT_USED(mtr); diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 17747ae2a8e..dec2b19559c 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -308,7 +308,8 @@ handle_new_error: return(TRUE); - } else if (err == DB_DEADLOCK || err == DB_LOCK_WAIT_TIMEOUT) { + } else if (err == DB_DEADLOCK || err == DB_LOCK_WAIT_TIMEOUT + || err == DB_LOCK_TABLE_FULL) { /* Roll back the whole transaction; this resolution was added to version 3.23.43 */ @@ -781,10 +782,11 @@ row_lock_table_for_mysql( /* out: error code or DB_SUCCESS */ row_prebuilt_t* prebuilt, /* in: prebuilt struct in the MySQL table handle */ - dict_table_t* table) /* in: table to LOCK_IX, or NULL + dict_table_t* table, /* in: table to lock, or NULL if prebuilt->table should be locked as LOCK_TABLE_EXP | prebuilt->select_lock_type */ + ulint mode) /* in: lock mode of table */ { trx_t* trx = prebuilt->trx; que_thr_t* thr; @@ -818,7 +820,7 @@ run_again: trx_start_if_not_started(trx); if (table) { - err = lock_table(0, table, LOCK_IX, thr); + err = lock_table(0, table, mode, thr); } else { err = lock_table(LOCK_TABLE_EXP, prebuilt->table, prebuilt->select_lock_type, thr); diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 740241fa210..ce76f48e7a7 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -31,6 +31,7 @@ Created 12/19/1997 Heikki Tuuri #include "pars0pars.h" #include "row0mysql.h" #include "read0read.h" +#include "buf0lru.h" /* Maximum number of rows to prefetch; MySQL interface has another parameter */ #define SEL_MAX_N_PREFETCH 16 @@ -638,23 +639,24 @@ row_sel_get_clust_rec( if (!node->read_view) { /* Try to place a lock on the index record */ - /* If innodb_locks_unsafe_for_binlog option is used, - we lock only the record, i.e. next-key locking is - not used. - */ - if ( srv_locks_unsafe_for_binlog ) - { - err = lock_clust_rec_read_check_and_lock(0, clust_rec, - index,node->row_lock_mode, LOCK_REC_NOT_GAP, thr); - } - else - { - err = lock_clust_rec_read_check_and_lock(0, clust_rec, index, - node->row_lock_mode, LOCK_ORDINARY, thr); + /* If innodb_locks_unsafe_for_binlog option is used, + we lock only the record, i.e. next-key locking is + not used. + */ - } + if (srv_locks_unsafe_for_binlog) { + err = lock_clust_rec_read_check_and_lock(0, + clust_rec, + index, node->row_lock_mode, + LOCK_REC_NOT_GAP, thr); + } else { + err = lock_clust_rec_read_check_and_lock(0, + clust_rec, + index, node->row_lock_mode, + LOCK_ORDINARY, thr); + } - if (err != DB_SUCCESS) { + if (err != DB_SUCCESS) { return(err); } @@ -729,8 +731,18 @@ sel_set_rec_lock( ulint type, /* in: LOCK_ORDINARY, LOCK_GAP, or LOC_REC_NOT_GAP */ que_thr_t* thr) /* in: query thread */ { + trx_t* trx; ulint err; + trx = thr_get_trx(thr); + + if (UT_LIST_GET_LEN(trx->trx_locks) > 10000) { + if (buf_LRU_buf_pool_running_out()) { + + return(DB_LOCK_TABLE_FULL); + } + } + if (index->type & DICT_CLUSTERED) { err = lock_clust_rec_read_check_and_lock(0, rec, index, mode, type, thr); @@ -1205,22 +1217,24 @@ rec_loop: if (!consistent_read) { - /* If innodb_locks_unsafe_for_binlog option is used, - we lock only the record, i.e. next-key locking is - not used. - */ + /* If innodb_locks_unsafe_for_binlog option is used, + we lock only the record, i.e. next-key locking is + not used. + */ - if ( srv_locks_unsafe_for_binlog ) - { - err = sel_set_rec_lock(page_rec_get_next(rec), index, - node->row_lock_mode, LOCK_REC_NOT_GAP, thr); - } - else - { - err = sel_set_rec_lock(page_rec_get_next(rec), index, - node->row_lock_mode, LOCK_ORDINARY, thr); - } - if (err != DB_SUCCESS) { + if (srv_locks_unsafe_for_binlog) { + err = sel_set_rec_lock(page_rec_get_next(rec), + index, + node->row_lock_mode, + LOCK_REC_NOT_GAP, thr); + } else { + err = sel_set_rec_lock(page_rec_get_next(rec), + index, + node->row_lock_mode, + LOCK_ORDINARY, thr); + } + + if (err != DB_SUCCESS) { /* Note that in this case we will store in pcur the PREDECESSOR of the record we are waiting the lock for */ @@ -1245,21 +1259,18 @@ rec_loop: if (!consistent_read) { /* Try to place a lock on the index record */ - /* If innodb_locks_unsafe_for_binlog option is used, - we lock only the record, i.e. next-key locking is - not used. - */ + /* If innodb_locks_unsafe_for_binlog option is used, + we lock only the record, i.e. next-key locking is + not used. + */ - if ( srv_locks_unsafe_for_binlog ) - { - err = sel_set_rec_lock(rec, index, node->row_lock_mode, + if (srv_locks_unsafe_for_binlog) { + err = sel_set_rec_lock(rec, index, node->row_lock_mode, LOCK_REC_NOT_GAP, thr); - } - else - { - err = sel_set_rec_lock(rec, index, node->row_lock_mode, + } else { + err = sel_set_rec_lock(rec, index, node->row_lock_mode, LOCK_ORDINARY, thr); - } + } if (err != DB_SUCCESS) { @@ -2765,6 +2776,7 @@ row_search_for_mysql( /* out: DB_SUCCESS, DB_RECORD_NOT_FOUND, DB_END_OF_INDEX, DB_DEADLOCK, + DB_LOCK_TABLE_FULL, or DB_TOO_BIG_RECORD */ byte* buf, /* in/out: buffer for the fetched row in the MySQL format */ @@ -3209,8 +3221,7 @@ rec_loop: we do not lock gaps. Supremum record is really a gap and therefore we do not set locks there. */ - if ( srv_locks_unsafe_for_binlog == FALSE ) - { + if (srv_locks_unsafe_for_binlog == FALSE) { err = sel_set_rec_lock(rec, index, prebuilt->select_lock_type, LOCK_ORDINARY, thr); @@ -3312,11 +3323,18 @@ rec_loop: if (prebuilt->select_lock_type != LOCK_NONE && set_also_gap_locks) { - /* Try to place a lock on the index record */ - err = sel_set_rec_lock(rec, index, + /* Try to place a gap lock on the index + record only if innodb_locks_unsafe_for_binlog + option is not set */ + + if (srv_locks_unsafe_for_binlog == FALSE) { + + err = sel_set_rec_lock(rec, index, prebuilt->select_lock_type, LOCK_GAP, thr); + } + if (err != DB_SUCCESS) { goto lock_wait_or_error; @@ -3338,11 +3356,18 @@ rec_loop: if (prebuilt->select_lock_type != LOCK_NONE && set_also_gap_locks) { - /* Try to place a lock on the index record */ - err = sel_set_rec_lock(rec, index, + /* Try to place a gap lock on the index + record only if innodb_locks_unsafe_for_binlog + option is not set */ + + if (srv_locks_unsafe_for_binlog == FALSE) { + + err = sel_set_rec_lock(rec, index, prebuilt->select_lock_type, LOCK_GAP, thr); + } + if (err != DB_SUCCESS) { goto lock_wait_or_error; @@ -3376,19 +3401,16 @@ rec_loop: prebuilt->select_lock_type, LOCK_REC_NOT_GAP, thr); } else { - /* If innodb_locks_unsafe_for_binlog option is used, - we lock only the record, i.e. next-key locking is - not used. - */ - if ( srv_locks_unsafe_for_binlog ) - { - err = sel_set_rec_lock(rec, index, + /* If innodb_locks_unsafe_for_binlog option is used, + we lock only the record, i.e. next-key locking is + not used. */ + + if (srv_locks_unsafe_for_binlog) { + err = sel_set_rec_lock(rec, index, prebuilt->select_lock_type, LOCK_REC_NOT_GAP, thr); - } - else - { - err = sel_set_rec_lock(rec, index, + } else { + err = sel_set_rec_lock(rec, index, prebuilt->select_lock_type, LOCK_ORDINARY, thr); } diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index b8d03cfab5f..84e3886162a 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -1677,11 +1677,13 @@ loop: srv_printf_innodb_monitor(stderr); } - mutex_enter(&srv_monitor_file_mutex); - rewind(srv_monitor_file); - srv_printf_innodb_monitor(srv_monitor_file); - os_file_set_eof(srv_monitor_file); - mutex_exit(&srv_monitor_file_mutex); + if (srv_innodb_status) { + mutex_enter(&srv_monitor_file_mutex); + rewind(srv_monitor_file); + srv_printf_innodb_monitor(srv_monitor_file); + os_file_set_eof(srv_monitor_file); + mutex_exit(&srv_monitor_file_mutex); + } if (srv_print_innodb_tablespace_monitor && difftime(current_time, last_table_monitor_time) > 60) { diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 9709f5235de..69341a1d7d1 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1172,6 +1172,9 @@ NetWare. */ } if (ret == NULL) { + fprintf(stderr, +"InnoDB: Fatal error: cannot allocate the memory for the buffer pool\n"); + return(DB_ERROR); } diff --git a/innobase/trx/trx0purge.c b/innobase/trx/trx0purge.c index 5c62640e011..3df34111281 100644 --- a/innobase/trx/trx0purge.c +++ b/innobase/trx/trx0purge.c @@ -289,7 +289,7 @@ trx_purge_add_update_undo_to_history( flst_get_len(seg_header + TRX_UNDO_PAGE_LIST, mtr)); mlog_write_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE, - hist_size + undo->size, MLOG_4BYTES, mtr); + hist_size + undo->size, MLOG_4BYTES, mtr); } /* Add the log as the first in the history list */ @@ -646,6 +646,27 @@ trx_purge_rseg_get_next_history_log( mutex_exit(&(rseg->mutex)); mtr_commit(&mtr); + mutex_enter(&kernel_mutex); + + /* Add debug code to track history list corruption reported + on the MySQL mailing list on Nov 9, 2004. The fut0lst.c + file-based list was corrupt. The prev node pointer was + FIL_NULL, even though the list length was over 8 million nodes! + We assume that purge truncates the history list in moderate + size pieces, and if we here reach the head of the list, the + list cannot be longer than 20 000 undo logs now. */ + + if (trx_sys->rseg_history_len > 20000) { + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: Warning: purge reached the head of the history list,\n" +"InnoDB: but its length is still reported as %lu! Make a detailed bug\n" +"InnoDB: report, and post it to bugs.mysql.com\n", + (ulong)trx_sys->rseg_history_len); + } + + mutex_exit(&kernel_mutex); + return; } diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c index c1edc223cbc..8d1518753dd 100644 --- a/innobase/trx/trx0undo.c +++ b/innobase/trx/trx0undo.c @@ -1241,7 +1241,7 @@ trx_undo_lists_init( if (page_no != FIL_NULL && srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) { - + undo = trx_undo_mem_create_at_db_start(rseg, i, page_no, &mtr); size += undo->size; diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c index a6002d7fd83..6ed61b0b5de 100644 --- a/innobase/ut/ut0mem.c +++ b/innobase/ut/ut0mem.c @@ -61,8 +61,10 @@ ut_malloc_low( /*==========*/ /* out, own: allocated memory */ ulint n, /* in: number of bytes to allocate */ - ibool set_to_zero) /* in: TRUE if allocated memory should be set + ibool set_to_zero, /* in: TRUE if allocated memory should be set to zero if UNIV_SET_MEM_TO_ZERO is defined */ + ibool assert_on_error) /* in: if TRUE, we crash mysqld if the memory + cannot be allocated */ { void* ret; @@ -86,9 +88,7 @@ ut_malloc_low( "InnoDB: Check if you should increase the swap file or\n" "InnoDB: ulimits of your operating system.\n" "InnoDB: On FreeBSD check you have compiled the OS with\n" - "InnoDB: a big enough maximum process size.\n" - "InnoDB: We now intentionally generate a seg fault so that\n" - "InnoDB: on Linux we get a stack trace.\n", + "InnoDB: a big enough maximum process size.\n", (ulong) n, (ulong) ut_total_allocated_memory, #ifdef __WIN__ (ulong) GetLastError() @@ -110,7 +110,15 @@ ut_malloc_low( /* Intentional segfault on NetWare causes an abend. Avoid this by graceful exit handling in ut_a(). */ #if (!defined __NETWARE__) - if (*ut_mem_null_ptr) ut_mem_null_ptr = 0; + if (assert_on_error) { + fprintf(stderr, + "InnoDB: We now intentionally generate a seg fault so that\n" + "InnoDB: on Linux we get a stack trace.\n"); + + if (*ut_mem_null_ptr) ut_mem_null_ptr = 0; + } else { + return(NULL); + } #else ut_a(0); #endif @@ -144,7 +152,7 @@ ut_malloc( /* out, own: allocated memory */ ulint n) /* in: number of bytes to allocate */ { - return(ut_malloc_low(n, TRUE)); + return(ut_malloc_low(n, TRUE, TRUE)); } /************************************************************************** diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index a57c82e6424..cb20c5181a8 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -3257,11 +3257,12 @@ static void read_binary_time(MYSQL_TIME *tm, uchar **pos) tm->hour+= tm->day*24; tm->day= 0; } + tm->time_type= MYSQL_TIMESTAMP_TIME; + *pos+= length; } else - set_zero_time(tm); - tm->time_type= MYSQL_TIMESTAMP_TIME; + set_zero_time(tm, MYSQL_TIMESTAMP_TIME); } static void read_binary_datetime(MYSQL_TIME *tm, uchar **pos) @@ -3286,12 +3287,12 @@ static void read_binary_datetime(MYSQL_TIME *tm, uchar **pos) else tm->hour= tm->minute= tm->second= 0; tm->second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0; + tm->time_type= MYSQL_TIMESTAMP_DATETIME; *pos+= length; } else - set_zero_time(tm); - tm->time_type= MYSQL_TIMESTAMP_DATETIME; + set_zero_time(tm, MYSQL_TIMESTAMP_DATETIME); } static void read_binary_date(MYSQL_TIME *tm, uchar **pos) @@ -3308,12 +3309,12 @@ static void read_binary_date(MYSQL_TIME *tm, uchar **pos) tm->hour= tm->minute= tm->second= 0; tm->second_part= 0; tm->neg= 0; + tm->time_type= MYSQL_TIMESTAMP_DATE; *pos+= length; } else - set_zero_time(tm); - tm->time_type= MYSQL_TIMESTAMP_DATE; + set_zero_time(tm, MYSQL_TIMESTAMP_DATE); } diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 196cb5c21fb..c432ac5a16c 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -164,9 +164,9 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end, if (param.trunc) ftbw->flags|=FTB_FLAG_TRUNC; ftbw->weight=weight; ftbw->up=up; - ftbw->docid[0]=ftbw->docid[1]=HA_POS_ERROR; + ftbw->docid[0]=ftbw->docid[1]=HA_OFFSET_ERROR; ftbw->ndepth= (param.yesno<0) + depth; - ftbw->key_root=HA_POS_ERROR; + ftbw->key_root=HA_OFFSET_ERROR; memcpy(ftbw->word+1, w.pos, w.len); ftbw->word[0]=w.len; if (param.yesno > 0) up->ythresh++; @@ -181,7 +181,7 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end, ftbe->weight=weight; ftbe->up=up; ftbe->ythresh=ftbe->yweaks=0; - ftbe->docid[0]=ftbe->docid[1]=HA_POS_ERROR; + ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR; if ((ftbe->quot=param.quot)) ftb->with_scan|=2; if (param.yesno > 0) up->ythresh++; _ftb_parse_query(ftb, start, end, ftbe, depth+1); @@ -259,7 +259,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) { if (!ftbw->off || !(ftbw->flags & FTB_FLAG_TRUNC)) { - ftbw->docid[0]=HA_POS_ERROR; + ftbw->docid[0]=HA_OFFSET_ERROR; if ((ftbw->flags & FTB_FLAG_YES) && ftbw->up->up==0) { /* @@ -346,9 +346,9 @@ static void _ftb_init_index_search(FT_INFO *ftb) ftbe->up->ythresh - ftbe->up->yweaks >1) /* 1 */ { FTB_EXPR *top_ftbe=ftbe->up->up; - ftbw->docid[0]=HA_POS_ERROR; + ftbw->docid[0]=HA_OFFSET_ERROR; for (ftbe=ftbw->up; ftbe != top_ftbe; ftbe=ftbe->up) - if (ftbe->flags & FTB_FLAG_YES) + if (!(ftbe->flags & FTB_FLAG_NO)) ftbe->yweaks++; ftbe=0; break; @@ -356,7 +356,7 @@ static void _ftb_init_index_search(FT_INFO *ftb) } if (!ftbe) continue; - /* 3 */ + /* 4 */ if (!is_tree_inited(& ftb->no_dupes)) init_tree(& ftb->no_dupes,0,0,sizeof(my_off_t), _ftb_no_dupes_cmp,0,0,0); @@ -387,7 +387,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, ftb->charset= ((keynr==NO_SUCH_KEY) ? default_charset_info : info->s->keyinfo[keynr].seg->charset); ftb->with_scan=0; - ftb->lastpos=HA_POS_ERROR; + ftb->lastpos=HA_OFFSET_ERROR; bzero(& ftb->no_dupes, sizeof(TREE)); init_alloc_root(&ftb->mem_root, 1024, 1024); @@ -410,7 +410,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, ftbe->quot=0; ftbe->up=0; ftbe->ythresh=ftbe->yweaks=0; - ftbe->docid[0]=ftbe->docid[1]=HA_POS_ERROR; + ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR; ftb->root=ftbe; _ftb_parse_query(ftb, &query, query+query_len, ftbe, 0); ftb->list=(FTB_WORD **)alloc_root(&ftb->mem_root, @@ -561,7 +561,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) while (ftb->state == INDEX_SEARCH && (curdoc=((FTB_WORD *)queue_top(& ftb->queue))->docid[0]) != - HA_POS_ERROR) + HA_OFFSET_ERROR) { while (curdoc == (ftbw=(FTB_WORD *)queue_top(& ftb->queue))->docid[0]) { @@ -615,7 +615,7 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) const byte *end; my_off_t docid=ftb->info->lastpos; - if (docid == HA_POS_ERROR) + if (docid == HA_OFFSET_ERROR) return -2.0; if (!ftb->queue.elements) return 0; @@ -627,9 +627,9 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) for (i=0; i < ftb->queue.elements; i++) { - ftb->list[i]->docid[1]=HA_POS_ERROR; + ftb->list[i]->docid[1]=HA_OFFSET_ERROR; for (x=ftb->list[i]->up; x; x=x->up) - x->docid[1]=HA_POS_ERROR; + x->docid[1]=HA_OFFSET_ERROR; } } diff --git a/myisam/mi_create.c b/myisam/mi_create.c index 7fc7cc4edf1..f99a2c655d2 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -16,7 +16,7 @@ /* Create a MyISAM table */ -#include "fulltext.h" +#include "ftdefs.h" #include "sp_defs.h" #if defined(MSDOS) || defined(__WIN__) @@ -41,7 +41,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, File dfile,file; int errpos,save_errno; myf create_flag; - uint fields,length,max_key_length,packed,pointer, + uint fields,length,max_key_length,packed,pointer,real_length_diff, key_length,info_length,key_segs,options,min_key_length_skip, base_pos,varchar_count,long_varchar_count,varchar_length, max_key_block_length,unique_key_parts,fulltext_keys,offset; @@ -238,7 +238,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, { share.state.key_root[i]= HA_OFFSET_ERROR; - min_key_length_skip=length=0; + min_key_length_skip=length=real_length_diff=0; key_length=pointer; if (keydef->flag & HA_SPATIAL) { @@ -297,6 +297,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, key_length+= HA_FT_MAXBYTELEN+HA_FT_WLEN; length++; /* At least one length byte */ min_key_length_skip+=HA_FT_MAXBYTELEN; + real_length_diff=HA_FT_MAXBYTELEN-FT_MAX_WORD_LEN_FOR_SORT; } else { @@ -397,7 +398,8 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, key_segs) share.state.rec_per_key_part[key_segs-1]=1L; length+=key_length; - keydef->block_length= MI_BLOCK_SIZE(length,pointer,MI_MAX_KEYPTR_SIZE); + keydef->block_length= MI_BLOCK_SIZE(length-real_length_diff, + pointer,MI_MAX_KEYPTR_SIZE); if (keydef->block_length > MI_MAX_KEY_BLOCK_LENGTH || length >= MI_MAX_KEY_BUFF) { diff --git a/myisam/mi_test3.c b/myisam/mi_test3.c index dca04a9a64b..27d23317b5c 100644 --- a/myisam/mi_test3.c +++ b/myisam/mi_test3.c @@ -40,7 +40,7 @@ #endif -const char *filename= "test3.MSI"; +const char *filename= "test3"; uint tests=10,forks=10,key_cacheing=0,use_log=0; static void get_options(int argc, char *argv[]); @@ -363,7 +363,7 @@ int test_write(MI_INFO *file,int id,int lock_type) } sprintf(record.id,"%7d",getpid()); - strmov(record.text,"Testing..."); + strnmov(record.text,"Testing...", sizeof(record.text)); tries=(uint) rnd(100)+10; for (i=count=0 ; i < tries ; i++) diff --git a/myisam/mi_write.c b/myisam/mi_write.c index e059bbb569f..303e924118f 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -165,12 +165,7 @@ err: { uint j; for (j=0 ; j < share->base.keys ; j++) - { - if (is_tree_inited(&info->bulk_insert[j])) - { - reset_tree(&info->bulk_insert[j]); - } - } + mi_flush_bulk_insert(info, j); } info->errkey= (int) i; while ( i-- > 0) @@ -329,7 +324,7 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *temp_buff,*keypos; uchar keybuff[MI_MAX_KEY_BUFF]; my_bool was_last_key; - my_off_t next_page; + my_off_t next_page, dupp_key_pos; DBUG_ENTER("w_search"); DBUG_PRINT("enter",("page: %ld",page)); @@ -349,9 +344,9 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, /* get position to record with duplicated key */ tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff); if (tmp_key_length) - info->dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length); + dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length); else - info->dupp_key_pos= HA_OFFSET_ERROR; + dupp_key_pos= HA_OFFSET_ERROR; if (keyinfo->flag & HA_FULLTEXT) { uint off; @@ -370,7 +365,7 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, else { /* popular word. two-level tree. going down */ - my_off_t root=info->dupp_key_pos; + my_off_t root=dupp_key_pos; keyinfo=&info->s->ft2_keyinfo; get_key_full_length_rdonly(off, key); key+=off; @@ -389,6 +384,7 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, } else /* not HA_FULLTEXT, normal HA_NOSAME key */ { + info->dupp_key_pos= dupp_key_pos; my_afree((byte*) temp_buff); my_errno=HA_ERR_FOUND_DUPP_KEY; DBUG_RETURN(-1); diff --git a/mysql-test/include/ctype_common.inc b/mysql-test/include/ctype_common.inc new file mode 100644 index 00000000000..77937bdb854 --- /dev/null +++ b/mysql-test/include/ctype_common.inc @@ -0,0 +1,56 @@ +# +# Common tests for all character sets and collations. +# Include this file from a test with @test_characrer_set +# and @test_collation set to desired values. +# +# Please don't use SHOW CREATE TABLE in this file, +# we want it to be HANDLER independent. You can +# use SHOW FULL COLUMNS instead. +# +# Please surround all CREATE TABLE with --disable_warnings +# and --enable_warnings to be able to set storage_engine +# without having to check if the hanlder exists. + +SET @safe_character_set_server= @@character_set_server; +SET @safe_collation_server= @@collation_server; +SET character_set_server= @test_character_set; +SET collation_server= @test_collation; +CREATE DATABASE d1; +USE d1; + +# +# Bug 1883: LIKE did not work in some cases with a key. +# +--disable_warnings +CREATE TABLE t1 (c CHAR(10), KEY(c)); +--enable_warnings +# check the column was created with the expected charset/collation +SHOW FULL COLUMNS FROM t1; +INSERT INTO t1 VALUES ('aaa'),('aaaa'),('aaaaa'); +SELECT c as want3results FROM t1 WHERE c LIKE 'aaa%'; +DROP TABLE t1; + +# +# Bug 6643 incorrect response with partial utf8 index +# +--disable_warnings +CREATE TABLE t1 (c1 varchar(15), KEY c1 (c1(2))); +--enable_warnings +# check the column was created with the expected charset/collation +SHOW FULL COLUMNS FROM t1; +INSERT INTO t1 VALUES ('location'),('loberge'),('lotre'),('boabab'); +SELECT c1 as want3results from t1 where c1 like 'l%'; +SELECT c1 as want3results from t1 where c1 like 'lo%'; +SELECT c1 as want1result from t1 where c1 like 'loc%'; +SELECT c1 as want1result from t1 where c1 like 'loca%'; +SELECT c1 as want1result from t1 where c1 like 'locat%'; +SELECT c1 as want1result from t1 where c1 like 'locati%'; +SELECT c1 as want1result from t1 where c1 like 'locatio%'; +SELECT c1 as want1result from t1 where c1 like 'location%'; +DROP TABLE t1; + +DROP DATABASE d1; +# Restore settings +USE test; +SET character_set_server= @safe_character_set_server; +SET collation_server= @safe_collation_server; diff --git a/mysql-test/mysql_test_run.c b/mysql-test/mysql_test_run.c deleted file mode 100644 index 6f388fc4a45..00000000000 --- a/mysql-test/mysql_test_run.c +++ /dev/null @@ -1,1728 +0,0 @@ -/* - Copyright (c) 2002, 2003 Novell, Inc. All Rights Reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include -#ifndef __WIN__ -#include -#endif -#include -#ifdef __NETWARE__ -#include -#include -#endif -#include -#include -#ifndef __WIN__ -#include -#endif -#include -#ifdef __NETWARE__ -#include -#endif -#ifdef __WIN__ -#include -#include -#endif - -#include "my_manage.h" - -/****************************************************************************** - - macros - -******************************************************************************/ - -#define HEADER "TEST RESULT \n" -#define DASH "-------------------------------------------------------\n" - -#define NW_TEST_SUFFIX ".nw-test" -#define NW_RESULT_SUFFIX ".nw-result" -#define TEST_SUFFIX ".test" -#define RESULT_SUFFIX ".result" -#define REJECT_SUFFIX ".reject" -#define OUT_SUFFIX ".out" -#define ERR_SUFFIX ".err" - -const char *TEST_PASS = "[ pass ]"; -const char *TEST_SKIP = "[ skip ]"; -const char *TEST_FAIL = "[ fail ]"; -const char *TEST_BAD = "[ bad ]"; -const char *TEST_IGNORE = "[ignore]"; - -/****************************************************************************** - - global variables - -******************************************************************************/ -#ifdef __NETWARE__ -static char base_dir[PATH_MAX] = "sys:/mysql"; -#else -static char base_dir[PATH_MAX] = ".."; -#endif -static char db[PATH_MAX] = "test"; -static char user[PATH_MAX] = "root"; -static char password[PATH_MAX] = ""; - -int master_port = 9306; -int slave_port = 9307; - -#if !defined(__NETWARE__) && !defined(__WIN__) -static char master_socket[PATH_MAX] = "./var/tmp/master.sock"; -static char slave_socket[PATH_MAX] = "./var/tmp/slave.sock"; -#endif - -// comma delimited list of tests to skip or empty string -#ifndef __WIN__ -static char skip_test[PATH_MAX] = " lowercase_table3 , system_mysql_db_fix "; -#else -/* - The most ignore testes contain the calls of system command -*/ -#define MAX_COUNT_TESTES 1024 -/* - lowercase_table3 is disabled by Gerg - system_mysql_db_fix is disabled by Gerg - sp contains a command system - rpl_EE_error contains a command system - rpl_loaddatalocal contains a command system - ndb_autodiscover contains a command system - rpl_rotate_logs contains a command system - repair contains a command system - rpl_trunc_binlog contains a command system - mysqldump contains a command system - rpl000001 makes non-exit loop...temporary skiped -*/ -static char skip_test[PATH_MAX] = " lowercase_table3 , system_mysql_db_fix , sp , rpl_EE_error , rpl_loaddatalocal , ndb_autodiscover , rpl_rotate_logs , repair , rpl_trunc_binlog , mysqldump , rpl000001 "; -#endif -static char ignore_test[PATH_MAX] = ""; - -static char bin_dir[PATH_MAX]; -static char mysql_test_dir[PATH_MAX]; -static char test_dir[PATH_MAX]; -static char mysql_tmp_dir[PATH_MAX]; -static char result_dir[PATH_MAX]; -static char master_dir[PATH_MAX]; -static char slave_dir[PATH_MAX]; -static char lang_dir[PATH_MAX]; -static char char_dir[PATH_MAX]; - -static char mysqladmin_file[PATH_MAX]; -static char mysqld_file[PATH_MAX]; -static char mysqltest_file[PATH_MAX]; -#ifndef __WIN__ -static char master_pid[PATH_MAX]; -static char slave_pid[PATH_MAX]; -static char sh_file[PATH_MAX] = "/bin/sh"; -#else -static HANDLE master_pid; -static HANDLE slave_pid; -#endif - -static char master_opt[PATH_MAX] = ""; -static char slave_opt[PATH_MAX] = ""; - -static char slave_master_info[PATH_MAX] = ""; - -static char master_init_script[PATH_MAX] = ""; -static char slave_init_script[PATH_MAX] = ""; - -// OpenSSL -static char ca_cert[PATH_MAX]; -static char server_cert[PATH_MAX]; -static char server_key[PATH_MAX]; -static char client_cert[PATH_MAX]; -static char client_key[PATH_MAX]; - -int total_skip = 0; -int total_pass = 0; -int total_fail = 0; -int total_test = 0; - -int total_ignore = 0; - -int use_openssl = FALSE; -int master_running = FALSE; -int slave_running = FALSE; -int skip_slave = TRUE; -int single_test = TRUE; - -int restarts = 0; - -FILE *log_fd = NULL; - -/****************************************************************************** - - functions - -******************************************************************************/ - -/****************************************************************************** - - prototypes - -******************************************************************************/ - -void report_stats(); -void install_db(char *); -void mysql_install_db(); -void start_master(); -void start_slave(); -void mysql_start(); -void stop_slave(); -void stop_master(); -void mysql_stop(); -void mysql_restart(); -int read_option(char *, char *); -void run_test(char *); -void setup(char *); -void vlog(const char *, va_list); -void mlog(const char *, ...); -void log_info(const char *, ...); -void log_error(const char *, ...); -void log_errno(const char *, ...); -void die(const char *); -char *str_tok(char *string, const char *delim); -#ifndef __WIN__ -void run_init_script(const char *script_name); -#endif -/****************************************************************************** - - report_stats() - - Report the gathered statistics. - -******************************************************************************/ -void report_stats() -{ - if (total_fail == 0) - { - mlog("\nAll %d test(s) were successful.\n", total_test); - } - else - { - double percent = ((double)total_pass / total_test) * 100; - - mlog("\nFailed %u/%u test(s), %.02f%% successful.\n", - total_fail, total_test, percent); - mlog("\nThe .out and .err files in %s may give you some\n", result_dir); - mlog("hint of what when wrong.\n"); - mlog("\nIf you want to report this error, please first read the documentation\n"); - mlog("at: http://www.mysql.com/doc/M/y/MySQL_test_suite.html\n"); - } -} - -/****************************************************************************** - - install_db() - - Install the a database. - -******************************************************************************/ -void install_db(char *datadir) -{ - arg_list_t al; - int err; - char input[PATH_MAX]; - char output[PATH_MAX]; - char error[PATH_MAX]; - - // input file -#ifdef __NETWARE__ - snprintf(input, PATH_MAX, "%s/bin/init_db.sql", base_dir); -#else - snprintf(input, PATH_MAX, "%s/mysql-test/init_db.sql", base_dir); -#endif - snprintf(output, PATH_MAX, "%s/install.out", datadir); - snprintf(error, PATH_MAX, "%s/install.err", datadir); - - // args - init_args(&al); - add_arg(&al, mysqld_file); - add_arg(&al, "--no-defaults"); - add_arg(&al, "--bootstrap"); - add_arg(&al, "--skip-grant-tables"); - add_arg(&al, "--basedir=%s", base_dir); - add_arg(&al, "--datadir=%s", datadir); - add_arg(&al, "--skip-innodb"); - add_arg(&al, "--skip-bdb"); -#ifndef __NETWARE__ - add_arg(&al, "--character-sets-dir=%s", char_dir); - add_arg(&al, "--language=%s", lang_dir); -#endif - - // spawn - if ((err = spawn(mysqld_file, &al, TRUE, input, output, error, NULL)) != 0) - { - die("Unable to create database."); - } - - // free args - free_args(&al); -} - -/****************************************************************************** - - mysql_install_db() - - Install the test databases. - -******************************************************************************/ -void mysql_install_db() -{ - char temp[PATH_MAX]; - - // var directory - snprintf(temp, PATH_MAX, "%s/var", mysql_test_dir); - - // clean up old direcotry - del_tree(temp); - - // create var directory -#ifndef __WIN__ - mkdir(temp, S_IRWXU); - // create subdirectories - mlog("Creating test-suite folders...\n"); - snprintf(temp, PATH_MAX, "%s/var/run", mysql_test_dir); - mkdir(temp, S_IRWXU); - snprintf(temp, PATH_MAX, "%s/var/tmp", mysql_test_dir); - mkdir(temp, S_IRWXU); - snprintf(temp, PATH_MAX, "%s/var/master-data", mysql_test_dir); - mkdir(temp, S_IRWXU); - snprintf(temp, PATH_MAX, "%s/var/master-data/mysql", mysql_test_dir); - mkdir(temp, S_IRWXU); - snprintf(temp, PATH_MAX, "%s/var/master-data/test", mysql_test_dir); - mkdir(temp, S_IRWXU); - snprintf(temp, PATH_MAX, "%s/var/slave-data", mysql_test_dir); - mkdir(temp, S_IRWXU); - snprintf(temp, PATH_MAX, "%s/var/slave-data/mysql", mysql_test_dir); - mkdir(temp, S_IRWXU); - snprintf(temp, PATH_MAX, "%s/var/slave-data/test", mysql_test_dir); - mkdir(temp, S_IRWXU); -#else - mkdir(temp); - // create subdirectories - mlog("Creating test-suite folders...\n"); - snprintf(temp, PATH_MAX, "%s/var/run", mysql_test_dir); - mkdir(temp); - snprintf(temp, PATH_MAX, "%s/var/tmp", mysql_test_dir); - mkdir(temp); - snprintf(temp, PATH_MAX, "%s/var/master-data", mysql_test_dir); - mkdir(temp); - snprintf(temp, PATH_MAX, "%s/var/master-data/mysql", mysql_test_dir); - mkdir(temp); - snprintf(temp, PATH_MAX, "%s/var/master-data/test", mysql_test_dir); - mkdir(temp); - snprintf(temp, PATH_MAX, "%s/var/slave-data", mysql_test_dir); - mkdir(temp); - snprintf(temp, PATH_MAX, "%s/var/slave-data/mysql", mysql_test_dir); - mkdir(temp); - snprintf(temp, PATH_MAX, "%s/var/slave-data/test", mysql_test_dir); - mkdir(temp); -#endif - - // install databases - mlog("Creating test databases for master... \n"); - install_db(master_dir); - mlog("Creating test databases for slave... \n"); - install_db(slave_dir); -} - -/****************************************************************************** - - start_master() - - Start the master server. - -******************************************************************************/ -void start_master() -{ - arg_list_t al; - int err; - char master_out[PATH_MAX]; - char master_err[PATH_MAX]; -// char temp[PATH_MAX]; - char temp2[PATH_MAX]; - - // remove old berkeley db log files that can confuse the server - removef("%s/log.*", master_dir); - - // remove stale binary logs - removef("%s/var/log/*-bin.*", mysql_test_dir); - - // remove stale binary logs - removef("%s/var/log/*.index", mysql_test_dir); - - // remove master.info file - removef("%s/master.info", master_dir); - - // remove relay files - removef("%s/var/log/*relay*", mysql_test_dir); - - // remove relay-log.info file - removef("%s/relay-log.info", master_dir); - - // init script - if (master_init_script[0] != 0) - { -#ifdef __NETWARE__ - // TODO: use the scripts - if (strinstr(master_init_script, "repair_part2-master.sh") != 0) - { - FILE *fp; - - // create an empty index file - snprintf(temp, PATH_MAX, "%s/test/t1.MYI", master_dir); - fp = fopen(temp, "wb+"); - - fputs("1", fp); - - fclose(fp); - } -#elif !defined(__WIN__) - run_init_script(master_init_script); -#endif - } - - // redirection files - snprintf(master_out, PATH_MAX, "%s/var/run/master%u.out", - mysql_test_dir, restarts); - snprintf(master_err, PATH_MAX, "%s/var/run/master%u.err", - mysql_test_dir, restarts); -#ifndef __WIN__ - snprintf(temp2,PATH_MAX,"%s/var",mysql_test_dir); - mkdir(temp2,S_IRWXU); - snprintf(temp2,PATH_MAX,"%s/var/log",mysql_test_dir); - mkdir(temp2,S_IRWXU); -#else - snprintf(temp2,PATH_MAX,"%s/var",mysql_test_dir); - mkdir(temp2); - snprintf(temp2,PATH_MAX,"%s/var/log",mysql_test_dir); - mkdir(temp2); -#endif - // args - init_args(&al); - add_arg(&al, "%s", mysqld_file); - add_arg(&al, "--no-defaults"); - add_arg(&al, "--log-bin=%s/var/log/master-bin",mysql_test_dir); - add_arg(&al, "--server-id=1"); - add_arg(&al, "--basedir=%s", base_dir); - add_arg(&al, "--port=%u", master_port); -#if !defined(__NETWARE__) && !defined(__WIN__) - add_arg(&al, "--socket=%s",master_socket); -#endif - add_arg(&al, "--local-infile"); - add_arg(&al, "--core"); - add_arg(&al, "--datadir=%s", master_dir); -#ifndef __WIN__ - add_arg(&al, "--pid-file=%s", master_pid); -#endif - add_arg(&al, "--character-sets-dir=%s", char_dir); - add_arg(&al, "--tmpdir=%s", mysql_tmp_dir); - add_arg(&al, "--language=%s", lang_dir); -#ifdef DEBUG //only for debug builds - add_arg(&al, "--debug"); -#endif - - if (use_openssl) - { - add_arg(&al, "--ssl-ca=%s", ca_cert); - add_arg(&al, "--ssl-cert=%s", server_cert); - add_arg(&al, "--ssl-key=%s", server_key); - } - - // $MASTER_40_ARGS - add_arg(&al, "--rpl-recovery-rank=1"); - add_arg(&al, "--init-rpl-role=master"); - - // $SMALL_SERVER - add_arg(&al, "-O"); - add_arg(&al, "key_buffer_size=1M"); - add_arg(&al, "-O"); - add_arg(&al, "sort_buffer=256K"); - add_arg(&al, "-O"); - add_arg(&al, "max_heap_table_size=1M"); - - // $EXTRA_MASTER_OPT - if (master_opt[0] != 0) - { - char *p; - - p = (char *)str_tok(master_opt, " \t"); - if (!strstr(master_opt, "timezone")) - { - while (p) - { - add_arg(&al, "%s", p); - p = (char *)str_tok(NULL, " \t"); - } - } - } - - // remove the pid file if it exists -#ifndef __WIN__ - remove(master_pid); -#endif - - // spawn -#ifdef __WIN__ - if ((err= spawn(mysqld_file, &al, FALSE, NULL, master_out, master_err, &master_pid)) == 0) -#else - if ((err= spawn(mysqld_file, &al, FALSE, NULL, master_out, master_err, master_pid)) == 0) -#endif - { - sleep_until_file_exists(master_pid); - - if ((err = wait_for_server_start(bin_dir, mysqladmin_file, user, password, master_port, - mysql_tmp_dir)) == 0) - { - master_running = TRUE; - } - else - { - log_error("The master server went down early."); - } - } - else - { - log_error("Unable to start master server."); - } - - // free_args - free_args(&al); -} - -/****************************************************************************** - - start_slave() - - Start the slave server. - -******************************************************************************/ -void start_slave() -{ - arg_list_t al; - int err; - char slave_out[PATH_MAX]; - char slave_err[PATH_MAX]; - - // skip? - if (skip_slave) return; - - // remove stale binary logs - removef("%s/*-bin.*", slave_dir); - - // remove stale binary logs - removef("%s/*.index", slave_dir); - - // remove master.info file - removef("%s/master.info", slave_dir); - - // remove relay files - removef("%s/var/log/*relay*", mysql_test_dir); - - // remove relay-log.info file - removef("%s/relay-log.info", slave_dir); - - // init script - if (slave_init_script[0] != 0) - { -#ifdef __NETWARE__ - // TODO: use the scripts - if (strinstr(slave_init_script, "rpl000016-slave.sh") != 0) - { - // create empty master.info file - snprintf(temp, PATH_MAX, "%s/master.info", slave_dir); - close(open(temp, O_WRONLY | O_CREAT,S_IRWXU|S_IRWXG|S_IRWXO)); - } - else if (strinstr(slave_init_script, "rpl000017-slave.sh") != 0) - { - FILE *fp; - - // create a master.info file - snprintf(temp, PATH_MAX, "%s/master.info", slave_dir); - fp = fopen(temp, "wb+"); - - fputs("master-bin.000001\n", fp); - fputs("4\n", fp); - fputs("127.0.0.1\n", fp); - fputs("replicate\n", fp); - fputs("aaaaaaaaaaaaaaab\n", fp); - fputs("9306\n", fp); - fputs("1\n", fp); - fputs("0\n", fp); - - fclose(fp); - } - else if (strinstr(slave_init_script, "rpl_rotate_logs-slave.sh") != 0) - { - // create empty master.info file - snprintf(temp, PATH_MAX, "%s/master.info", slave_dir); - close(open(temp, O_WRONLY | O_CREAT,S_IRWXU|S_IRWXG|S_IRWXO)); - } -#elif !defined(__WIN__) - run_init_script(slave_init_script); -#endif - } - - // redirection files - snprintf(slave_out, PATH_MAX, "%s/var/run/slave%u.out", - mysql_test_dir, restarts); - snprintf(slave_err, PATH_MAX, "%s/var/run/slave%u.err", - mysql_test_dir, restarts); - - // args - init_args(&al); - add_arg(&al, "%s", mysqld_file); - add_arg(&al, "--no-defaults"); - add_arg(&al, "--log-bin=slave-bin"); - add_arg(&al, "--relay_log=slave-relay-bin"); - add_arg(&al, "--basedir=%s", base_dir); - add_arg(&al, "--port=%u", slave_port); -#if !defined(__NETWARE__) && !defined(__WIN__) - add_arg(&al, "--socket=%s",slave_socket); -#endif - add_arg(&al, "--datadir=%s", slave_dir); -#ifndef __WIN__ - add_arg(&al, "--pid-file=%s", slave_pid); -#endif - add_arg(&al, "--character-sets-dir=%s", char_dir); - add_arg(&al, "--core"); - add_arg(&al, "--tmpdir=%s", mysql_tmp_dir); - add_arg(&al, "--language=%s", lang_dir); - - add_arg(&al, "--exit-info=256"); - add_arg(&al, "--log-slave-updates"); - add_arg(&al, "--init-rpl-role=slave"); - add_arg(&al, "--skip-innodb"); - add_arg(&al, "--skip-slave-start"); - add_arg(&al, "--slave-load-tmpdir=../../var/tmp"); - - add_arg(&al, "--report-user=%s", user); - add_arg(&al, "--report-host=127.0.0.1"); - add_arg(&al, "--report-port=%u", slave_port); - - add_arg(&al, "--master-retry-count=10"); - add_arg(&al, "-O"); - add_arg(&al, "slave_net_timeout=10"); -#ifdef DEBUG //only for debug builds - add_arg(&al, "--debug"); -#endif - - if (use_openssl) - { - add_arg(&al, "--ssl-ca=%s", ca_cert); - add_arg(&al, "--ssl-cert=%s", server_cert); - add_arg(&al, "--ssl-key=%s", server_key); - } - - // slave master info - if (slave_master_info[0] != 0) - { - char *p; - - p = (char *)str_tok(slave_master_info, " \t"); - - while(p) - { - add_arg(&al, "%s", p); - - p = (char *)str_tok(NULL, " \t"); - } - } - else - { - add_arg(&al, "--master-user=%s", user); - add_arg(&al, "--master-password=%s", password); - add_arg(&al, "--master-host=127.0.0.1"); - add_arg(&al, "--master-port=%u", master_port); - add_arg(&al, "--master-connect-retry=1"); - add_arg(&al, "--server-id=2"); - add_arg(&al, "--rpl-recovery-rank=2"); - } - - // small server - add_arg(&al, "-O"); - add_arg(&al, "key_buffer_size=1M"); - add_arg(&al, "-O"); - add_arg(&al, "sort_buffer=256K"); - add_arg(&al, "-O"); - add_arg(&al, "max_heap_table_size=1M"); - - - // opt args - if (slave_opt[0] != 0) - { - char *p; - - p = (char *)str_tok(slave_opt, " \t"); - - while(p) - { - add_arg(&al, "%s", p); - - p = (char *)str_tok(NULL, " \t"); - } - } - - // remove the pid file if it exists -#ifndef __WIN__ - remove(slave_pid); -#endif - // spawn -#ifdef __WIN__ - if ((err = spawn(mysqld_file, &al, FALSE, NULL, slave_out, slave_err, &slave_pid)) == 0) -#else - if ((err = spawn(mysqld_file, &al, FALSE, NULL, slave_out, slave_err, slave_pid)) == 0) -#endif - { - sleep_until_file_exists(slave_pid); - - if ((err = wait_for_server_start(bin_dir, mysqladmin_file, user, password, slave_port, - mysql_tmp_dir)) == 0) - { - slave_running = TRUE; - } - else - { - log_error("The slave server went down early."); - } - } - else - { - log_error("Unable to start slave server."); - } - - // free args - free_args(&al); -} - -/****************************************************************************** - - mysql_start() - - Start the mysql servers. - -******************************************************************************/ -void mysql_start() -{ -// log_info("Starting the MySQL server(s): %u", ++restarts); - start_master(); - - start_slave(); - - // activate the test screen -#ifdef __NETWARE__ - ActivateScreen(getscreenhandle()); -#endif -} - -/****************************************************************************** - - stop_slave() - - Stop the slave server. - -******************************************************************************/ -void stop_slave() -{ - int err; - - // running? - if (!slave_running) return; - - // stop - if ((err = stop_server(bin_dir, mysqladmin_file, user, password, slave_port, slave_pid, - mysql_tmp_dir)) == 0) - { - slave_running = FALSE; - } - else - { - log_error("Unable to stop slave server."); - } -} - -/****************************************************************************** - - stop_master() - - Stop the master server. - -******************************************************************************/ -void stop_master() -{ - int err; - - // running? - if (!master_running) return; - - if ((err = stop_server(bin_dir, mysqladmin_file, user, password, master_port, master_pid, - mysql_tmp_dir)) == 0) - { - master_running = FALSE; - } - else - { - log_error("Unable to stop master server."); - } -} - -/****************************************************************************** - - mysql_stop() - - Stop the mysql servers. - -******************************************************************************/ -void mysql_stop() -{ - - stop_master(); - - stop_slave(); - - // activate the test screen -#ifdef __NETWARE__ - ActivateScreen(getscreenhandle()); -#endif -} - -/****************************************************************************** - - mysql_restart() - - Restart the mysql servers. - -******************************************************************************/ -void mysql_restart() -{ -// log_info("Restarting the MySQL server(s): %u", ++restarts); - - mysql_stop(); - - mlog(DASH); - - mysql_start(); -} - -/****************************************************************************** - - read_option() - - Read the option file. - -******************************************************************************/ -int read_option(char *opt_file, char *opt) -{ - int fd, err; - char *p; - char buf[PATH_MAX]; - - // copy current option - strncpy(buf, opt, PATH_MAX); - - // open options file - fd = open(opt_file, O_RDONLY); - - err = read(fd, opt, PATH_MAX); - - close(fd); - - if (err > 0) - { - // terminate string - if ((p = strchr(opt, '\n')) != NULL) - { - *p = 0; - - // check for a '\r' - if ((p = strchr(opt, '\r')) != NULL) - { - *p = 0; - } - } - else - { - opt[err] = 0; - } - - // check for $MYSQL_TEST_DIR - if ((p = strstr(opt, "$MYSQL_TEST_DIR")) != NULL) - { - char temp[PATH_MAX]; - - *p = 0; - - strcpy(temp, p + strlen("$MYSQL_TEST_DIR")); - - strcat(opt, mysql_test_dir); - - strcat(opt, temp); - } - // Check for double backslash and replace it with single bakslash - if ((p = strstr(opt, "\\\\")) != NULL) - { - /* bmove is guranteed to work byte by byte */ - bmove(p, p+1, strlen(p+1)); - } - } - else - { - // clear option - *opt = 0; - } - - // compare current option with previous - return strcmp(opt, buf); -} - -/****************************************************************************** - - run_test() - - Run the given test case. - -******************************************************************************/ -void run_test(char *test) -{ - char temp[PATH_MAX]; - const char *rstr; - int skip = FALSE, ignore=FALSE; - int restart = FALSE; - int flag = FALSE; - struct stat info; - - // skip tests in the skip list - snprintf(temp, PATH_MAX, " %s ", test); - skip = (strinstr(skip_test, temp) != 0); - if (skip == FALSE) - ignore = (strinstr(ignore_test, temp) != 0); - - snprintf(master_init_script, PATH_MAX, "%s/%s-master.sh", test_dir, test); - snprintf(slave_init_script, PATH_MAX, "%s/%s-slave.sh", test_dir, test); -#ifdef __WIN__ - if (! stat(master_init_script, &info)) - skip = TRUE; - if (!stat(slave_init_script, &info)) - skip = TRUE; -#endif - if (ignore) - { - // show test - mlog("%-46s ", test); - - // ignore - rstr = TEST_IGNORE; - ++total_ignore; - } - else if (!skip) // skip test? - { - char test_file[PATH_MAX]; - char master_opt_file[PATH_MAX]; - char slave_opt_file[PATH_MAX]; - char slave_master_info_file[PATH_MAX]; - char result_file[PATH_MAX]; - char reject_file[PATH_MAX]; - char out_file[PATH_MAX]; - char err_file[PATH_MAX]; - int err; - arg_list_t al; -#ifdef __WIN__ - /* - Clean test database - */ - removef("%s/test/*.*", master_dir); - removef("%s/test/*.*", slave_dir); - removef("%s/mysqltest/*.*", master_dir); - removef("%s/mysqltest/*.*", slave_dir); - -#endif - // skip slave? - flag = skip_slave; - skip_slave = (strncmp(test, "rpl", 3) != 0); - if (flag != skip_slave) restart = TRUE; - - // create files - snprintf(master_opt_file, PATH_MAX, "%s/%s-master.opt", test_dir, test); - snprintf(slave_opt_file, PATH_MAX, "%s/%s-slave.opt", test_dir, test); - snprintf(slave_master_info_file, PATH_MAX, "%s/%s.slave-mi", test_dir, test); - snprintf(reject_file, PATH_MAX, "%s/%s%s", result_dir, test, REJECT_SUFFIX); - snprintf(out_file, PATH_MAX, "%s/%s%s", result_dir, test, OUT_SUFFIX); - snprintf(err_file, PATH_MAX, "%s/%s%s", result_dir, test, ERR_SUFFIX); - - // netware specific files - snprintf(test_file, PATH_MAX, "%s/%s%s", test_dir, test, NW_TEST_SUFFIX); - if (stat(test_file, &info)) - { - snprintf(test_file, PATH_MAX, "%s/%s%s", test_dir, test, TEST_SUFFIX); - if (access(test_file,0)) - { - printf("Invalid test name %s, %s file not found\n",test,test_file); - return; - } - } - - snprintf(result_file, PATH_MAX, "%s/%s%s", result_dir, test, NW_RESULT_SUFFIX); - if (stat(result_file, &info)) - { - snprintf(result_file, PATH_MAX, "%s/%s%s", result_dir, test, RESULT_SUFFIX); - } - - // init scripts - if (stat(master_init_script, &info)) - master_init_script[0] = 0; - else - restart = TRUE; - - if (stat(slave_init_script, &info)) - slave_init_script[0] = 0; - else - restart = TRUE; - - // read options - if (read_option(master_opt_file, master_opt)) restart = TRUE; - if (read_option(slave_opt_file, slave_opt)) restart = TRUE; - if (read_option(slave_master_info_file, slave_master_info)) restart = TRUE; - - // cleanup previous run - remove(reject_file); - remove(out_file); - remove(err_file); - - // start or restart? - if (!master_running) mysql_start(); - else if (restart) mysql_restart(); - - // let the system stabalize - sleep(1); - - // show test - mlog("%-46s ", test); - - - // args - init_args(&al); - add_arg(&al, "%s", mysqltest_file); - add_arg(&al, "--no-defaults"); - add_arg(&al, "--port=%u", master_port); -#if !defined(__NETWARE__) && !defined(__WIN__) - add_arg(&al, "--socket=%s", master_socket); - add_arg(&al, "--tmpdir=%s", mysql_tmp_dir); -#endif - add_arg(&al, "--database=%s", db); - add_arg(&al, "--user=%s", user); - add_arg(&al, "--password=%s", password); - add_arg(&al, "--silent"); - add_arg(&al, "--basedir=%s/", mysql_test_dir); - add_arg(&al, "--host=127.0.0.1"); - add_arg(&al, "-v"); - add_arg(&al, "-R"); - add_arg(&al, "%s", result_file); - - if (use_openssl) - { - add_arg(&al, "--ssl-ca=%s", ca_cert); - add_arg(&al, "--ssl-cert=%s", client_cert); - add_arg(&al, "--ssl-key=%s", client_key); - } - - // spawn - err = spawn(mysqltest_file, &al, TRUE, test_file, out_file, err_file, NULL); - - // free args - free_args(&al); - - remove_empty_file(out_file); - remove_empty_file(err_file); - - if (err == 0) - { - // pass - rstr = TEST_PASS; - ++total_pass; - - // increment total - ++total_test; - } - else if (err == 2) - { - // skip - rstr = TEST_SKIP; - ++total_skip; - } - else if (err == 1) - { - // fail - rstr = TEST_FAIL; - ++total_fail; - - // increment total - ++total_test; - } - else - { - rstr = TEST_BAD; - } - } - else // early skips - { - // show test - mlog("%-46s ", test); - - // skip - rstr = TEST_SKIP; - ++total_skip; - } - - // result - mlog("%-14s\n", rstr); -} - -/****************************************************************************** - - vlog() - - Log the message. - -******************************************************************************/ -void vlog(const char *format, va_list ap) -{ - vfprintf(stdout, format, ap); - fflush(stdout); - - if (log_fd) - { - vfprintf(log_fd, format, ap); - fflush(log_fd); - } -} - -/****************************************************************************** - - log() - - Log the message. - -******************************************************************************/ -void mlog(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - - vlog(format, ap); - - va_end(ap); -} - -/****************************************************************************** - - log_info() - - Log the given information. - -******************************************************************************/ -void log_info(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - - mlog("-- INFO : "); - vlog(format, ap); - mlog("\n"); - - va_end(ap); -} - -/****************************************************************************** - - log_error() - - Log the given error. - -******************************************************************************/ -void log_error(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - - mlog("-- ERROR: "); - vlog(format, ap); - mlog("\n"); - - va_end(ap); -} - -/****************************************************************************** - - log_errno() - - Log the given error and errno. - -******************************************************************************/ -void log_errno(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - - mlog("-- ERROR: (%003u) ", errno); - vlog(format, ap); - mlog("\n"); - - va_end(ap); -} - -/****************************************************************************** - - die() - - Exit the application. - -******************************************************************************/ -void die(const char *msg) -{ - log_error(msg); -#ifdef __NETWARE__ - pressanykey(); -#endif - exit(-1); -} - -/****************************************************************************** - - setup() - - Setup the mysql test enviornment. - -******************************************************************************/ -void setup(char *file) -{ - char temp[PATH_MAX]; - char file_path[PATH_MAX*2]; - char *p; - int position; - - // set the timezone for the timestamp test -#ifdef __WIN__ - _putenv( "TZ=GMT-3" ); -#else - setenv("TZ", "GMT-3", TRUE); -#endif - // find base dir -#ifdef __NETWARE__ - strcpy(temp, strlwr(file)); - while((p = strchr(temp, '\\')) != NULL) *p = '/'; -#else - getcwd(temp, PATH_MAX); - position = strlen(temp); - temp[position] = '/'; - temp[position+1] = 0; -#ifdef __WIN__ - while((p = strchr(temp, '\\')) != NULL) *p = '/'; -#endif -#endif - - if ((position = strinstr(temp, "/mysql-test/")) != 0) - { - p = temp + position - 1; - *p = 0; - strcpy(base_dir, temp); - } - - log_info("Currect directory: %s",base_dir); - -#ifdef __NETWARE__ - // setup paths - snprintf(bin_dir, PATH_MAX, "%s/bin", base_dir); - snprintf(mysql_test_dir, PATH_MAX, "%s/mysql-test", base_dir); - snprintf(test_dir, PATH_MAX, "%s/t", mysql_test_dir); - snprintf(mysql_tmp_dir, PATH_MAX, "%s/var/tmp", mysql_test_dir); - snprintf(result_dir, PATH_MAX, "%s/r", mysql_test_dir); - snprintf(master_dir, PATH_MAX, "%s/var/master-data", mysql_test_dir); - snprintf(slave_dir, PATH_MAX, "%s/var/slave-data", mysql_test_dir); - snprintf(lang_dir, PATH_MAX, "%s/share/english", base_dir); - snprintf(char_dir, PATH_MAX, "%s/share/charsets", base_dir); - -#ifdef HAVE_OPENSSL - use_openssl = TRUE; -#endif // HAVE_OPENSSL - - // OpenSSL paths - snprintf(ca_cert, PATH_MAX, "%s/SSL/cacert.pem", base_dir); - snprintf(server_cert, PATH_MAX, "%s/SSL/server-cert.pem", base_dir); - snprintf(server_key, PATH_MAX, "%s/SSL/server-key.pem", base_dir); - snprintf(client_cert, PATH_MAX, "%s/SSL/client-cert.pem", base_dir); - snprintf(client_key, PATH_MAX, "%s/SSL/client-key.pem", base_dir); - - // setup files - snprintf(mysqld_file, PATH_MAX, "%s/mysqld", bin_dir); - snprintf(mysqltest_file, PATH_MAX, "%s/mysqltest", bin_dir); - snprintf(mysqladmin_file, PATH_MAX, "%s/mysqladmin", bin_dir); - snprintf(master_pid, PATH_MAX, "%s/var/run/master.pid", mysql_test_dir); - snprintf(slave_pid, PATH_MAX, "%s/var/run/slave.pid", mysql_test_dir); -#elif __WIN__ - // setup paths -#ifdef _DEBUG - snprintf(bin_dir, PATH_MAX, "%s/client_debug", base_dir); -#else - snprintf(bin_dir, PATH_MAX, "%s/client_release", base_dir); -#endif - snprintf(mysql_test_dir, PATH_MAX, "%s/mysql-test", base_dir); - snprintf(test_dir, PATH_MAX, "%s/t", mysql_test_dir); - snprintf(mysql_tmp_dir, PATH_MAX, "%s/var/tmp", mysql_test_dir); - snprintf(result_dir, PATH_MAX, "%s/r", mysql_test_dir); - snprintf(master_dir, PATH_MAX, "%s/var/master-data", mysql_test_dir); - snprintf(slave_dir, PATH_MAX, "%s/var/slave-data", mysql_test_dir); - snprintf(lang_dir, PATH_MAX, "%s/share/english", base_dir); - snprintf(char_dir, PATH_MAX, "%s/share/charsets", base_dir); - -#ifdef HAVE_OPENSSL - use_openssl = TRUE; -#endif // HAVE_OPENSSL - - // OpenSSL paths - snprintf(ca_cert, PATH_MAX, "%s/SSL/cacert.pem", base_dir); - snprintf(server_cert, PATH_MAX, "%s/SSL/server-cert.pem", base_dir); - snprintf(server_key, PATH_MAX, "%s/SSL/server-key.pem", base_dir); - snprintf(client_cert, PATH_MAX, "%s/SSL/client-cert.pem", base_dir); - snprintf(client_key, PATH_MAX, "%s/SSL/client-key.pem", base_dir); - - // setup files - snprintf(mysqld_file, PATH_MAX, "%s/mysqld.exe", bin_dir); - snprintf(mysqltest_file, PATH_MAX, "%s/mysqltest.exe", bin_dir); - snprintf(mysqladmin_file, PATH_MAX, "%s/mysqladmin.exe", bin_dir); -#else - // setup paths - snprintf(bin_dir, PATH_MAX, "%s/client", base_dir); - snprintf(mysql_test_dir, PATH_MAX, "%s/mysql-test", base_dir); - snprintf(test_dir, PATH_MAX, "%s/t", mysql_test_dir); - snprintf(mysql_tmp_dir, PATH_MAX, "%s/var/tmp", mysql_test_dir); - snprintf(result_dir, PATH_MAX, "%s/r", mysql_test_dir); - snprintf(master_dir, PATH_MAX, "%s/var/master-data", mysql_test_dir); - snprintf(slave_dir, PATH_MAX, "%s/var/slave-data", mysql_test_dir); - snprintf(lang_dir, PATH_MAX, "%s/sql/share/english", base_dir); - snprintf(char_dir, PATH_MAX, "%s/sql/share/charsets", base_dir); - -#ifdef HAVE_OPENSSL - use_openssl = TRUE; -#endif // HAVE_OPENSSL - - // OpenSSL paths - snprintf(ca_cert, PATH_MAX, "%s/SSL/cacert.pem", base_dir); - snprintf(server_cert, PATH_MAX, "%s/SSL/server-cert.pem", base_dir); - snprintf(server_key, PATH_MAX, "%s/SSL/server-key.pem", base_dir); - snprintf(client_cert, PATH_MAX, "%s/SSL/client-cert.pem", base_dir); - snprintf(client_key, PATH_MAX, "%s/SSL/client-key.pem", base_dir); - - // setup files - snprintf(mysqld_file, PATH_MAX, "%s/sql/mysqld", base_dir); - snprintf(mysqltest_file, PATH_MAX, "%s/mysqltest", bin_dir); - snprintf(mysqladmin_file, PATH_MAX, "%s/mysqladmin", bin_dir); - snprintf(master_pid, PATH_MAX, "%s/var/run/master.pid", mysql_test_dir); - snprintf(slave_pid, PATH_MAX, "%s/var/run/slave.pid", mysql_test_dir); - - snprintf(master_socket,PATH_MAX, "%s/var/tmp/master.sock", mysql_test_dir); - snprintf(slave_socket,PATH_MAX, "%s/var/tmp/slave.sock", mysql_test_dir); - -#endif - // create log file - snprintf(temp, PATH_MAX, "%s/mysql-test-run.log", mysql_test_dir); - if ((log_fd = fopen(temp, "w+")) == NULL) - { - log_errno("Unable to create log file."); - } - - // prepare skip test list - while((p = strchr(skip_test, ',')) != NULL) *p = ' '; - strcpy(temp, strlwr(skip_test)); - snprintf(skip_test, PATH_MAX, " %s ", temp); - - // environment -#ifdef __NETWARE__ - setenv("MYSQL_TEST_DIR", mysql_test_dir, 1); - snprintf(file_path, PATH_MAX*2, "%s/client/mysqldump --no-defaults -u root --port=%u", bin_dir, master_port); - setenv("MYSQL_DUMP", file_path, 1); - snprintf(file_path, PATH_MAX*2, "%s/client/mysqlbinlog --no-defaults --local-load=%s", bin_dir, mysql_tmp_dir); - setenv("MYSQL_BINLOG", file_path, 1); -#elif __WIN__ - snprintf(file_path,MAX_PATH,"MYSQL_TEST_DIR=%s",mysql_test_dir); - _putenv(file_path); - snprintf(file_path, PATH_MAX*2, "MYSQL_DUMP=%s/mysqldump.exe --no-defaults -u root --port=%u", bin_dir, master_port); - _putenv(file_path); - snprintf(file_path, PATH_MAX*2, "MYSQL_BINLOG=%s/mysqlbinlog.exe --no-defaults --local-load=%s", bin_dir, mysql_tmp_dir); - _putenv(file_path); -#else - setenv("MYSQL_TEST_DIR", mysql_test_dir, 1); - snprintf(file_path, PATH_MAX*2, "%s/mysqldump --no-defaults -u root --port=%u --socket=%s", bin_dir, master_port, master_socket); - setenv("MYSQL_DUMP", file_path, 1); - snprintf(file_path, PATH_MAX*2, "%s/mysqlbinlog --no-defaults --local-load=%s", bin_dir, mysql_tmp_dir); - setenv("MYSQL_BINLOG", file_path, 1); -#endif - -#ifndef __WIN__ - setenv("MASTER_MYPORT", "9306", 1); - setenv("SLAVE_MYPORT", "9307", 1); - setenv("MYSQL_TCP_PORT", "3306", 1); -#else - _putenv("MASTER_MYPORT=9306"); - _putenv("SLAVE_MYPORT=9307"); - _putenv("MYSQL_TCP_PORT=3306"); -#endif - -} - -/****************************************************************************** - - main() - -******************************************************************************/ -int main(int argc, char **argv) -{ - int is_ignore_list = 0; - // setup - setup(argv[0]); - - /* The --ignore option is comma saperated list of test cases to skip and - should be very first command line option to the test suite. - - The usage is now: - mysql_test_run --ignore=test1,test2 test3 test4 - where test1 and test2 are test cases to ignore - and test3 and test4 are test cases to run. - */ - if (argc >= 2 && !strnicmp(argv[1], "--ignore=", sizeof("--ignore=")-1)) - { - char *temp, *token; - temp= strdup(strchr(argv[1],'=') + 1); - for (token=str_tok(temp, ","); token != NULL; token=str_tok(NULL, ",")) - { - if (strlen(ignore_test) + strlen(token) + 2 <= PATH_MAX-1) - sprintf(ignore_test+strlen(ignore_test), " %s ", token); - else - { - free(temp); - die("ignore list too long."); - } - } - free(temp); - is_ignore_list = 1; - } - // header -#ifndef __WIN__ - mlog("MySQL Server %s, for %s (%s)\n\n", VERSION, SYSTEM_TYPE, MACHINE_TYPE); -#else - mlog("MySQL Server ---, for %s (%s)\n\n", SYSTEM_TYPE, MACHINE_TYPE); -#endif - - mlog("Initializing Tests...\n"); - - // install test databases - mysql_install_db(); - - mlog("Starting Tests...\n"); - - mlog("\n"); - mlog(HEADER); - mlog(DASH); - - if ( argc > 1 + is_ignore_list ) - { - int i; - - // single test - single_test = TRUE; - - for (i = 1 + is_ignore_list; i < argc; i++) - { - // run given test - run_test(argv[i]); - } - } - else - { - // run all tests -#ifndef __WIN__ - struct dirent **namelist; - int i,n; - char test[NAME_MAX]; - char *p; - int position; - - n = scandir(test_dir, &namelist, 0, alphasort); - if (n < 0) - die("Unable to open tests directory."); - else - { - for (i = 0; i < n; i++) - { - strcpy(test, strlwr(namelist[i]->d_name)); - // find the test suffix - if ((position = strinstr(test, TEST_SUFFIX)) != 0) - { - p = test + position - 1; - // null terminate at the suffix - *p = 0; - // run test - run_test(test); - } - free(namelist[n]); - } - free(namelist); - } -#else - struct _finddata_t dir; - intptr_t handle; - char test[NAME_MAX]; - char mask[PATH_MAX]; - char *p; - int position; - char **names = 0; - char **testes = 0; - int name_index; - int index; - - // single test - single_test = FALSE; - - snprintf(mask,MAX_PATH,"%s/*.test",test_dir); - - if ((handle=_findfirst(mask,&dir)) == -1L) - { - die("Unable to open tests directory."); - } - - names = malloc(MAX_COUNT_TESTES*4); - testes = names; - name_index = 0; - - do - { - if (!(dir.attrib & _A_SUBDIR)) - { - strcpy(test, strlwr(dir.name)); - - // find the test suffix - if ((position = strinstr(test, TEST_SUFFIX)) != 0) - { - p = test + position - 1; - // null terminate at the suffix - *p = 0; - - // insert test - *names = malloc(PATH_MAX); - strcpy(*names,test); - names++; - name_index++; - } - } - }while (_findnext(handle,&dir) == 0); - - _findclose(handle); - - qsort( (void *)testes, name_index, sizeof( char * ), compare ); - - for (index = 0; index <= name_index; index++) - { - run_test(testes[index]); - free(testes[index]); - } - - free(testes); -#endif - } - - // stop server - mysql_stop(); - - mlog(DASH); - mlog("\n"); - - mlog("Ending Tests...\n"); - - // report stats - report_stats(); - - // close log - if (log_fd) fclose(log_fd); - - // keep results up -#ifdef __NETWARE__ - pressanykey(); -#endif - return 0; -} - - -/* - Synopsis: - This function breaks the string into a sequence of tokens. The difference - between this function and strtok is that it respects the quoted string i.e. - it skips any delimiter character within the quoted part of the string. - It return tokens by eliminating quote character. It modifies the input string - passed. It will work with whitespace delimeter but may not work properly with - other delimeter. If the delimeter will contain any quote character, then - function will not tokenize and will return null string. - e.g. if input string is - --init-slave="set global max_connections=500" --skip-external-locking - then the output will two string i.e. - --init-slave=set global max_connections=500 - --skip-external-locking - -Arguments: - string: input string - delim: set of delimiter character -Output: - return the null terminated token of NULL. -*/ - - -char *str_tok(char *string, const char *delim) -{ - char *token; /* current token received from strtok */ - char *qt_token; /* token delimeted by the matching pair of quote */ - /* - if there are any quote chars found in the token then this variable - will hold the concatenated string to return to the caller - */ - char *ptr_token=NULL; - /* pointer to the quote character in the token from strtok */ - char *ptr_quote=NULL; - - /* See if the delimeter contains any quote character */ - if (strchr(delim,'\'') || strchr(delim,'\"')) - return NULL; - - /* repeate till we are getting some token from strtok */ - while ((token = (char*)strtok(string, delim) ) != NULL) - { - /* - make the input string NULL so that next time onward strtok can - be called with NULL input string. - */ - string = NULL; - /* - We don't need to remove any quote character for Windows version - */ -#ifndef __WIN__ - /* check if the current token contain double quote character*/ - if ((ptr_quote = (char*)strchr(token,'\"')) != NULL) - { - /* - get the matching the matching double quote in the remaining - input string - */ - qt_token = (char*)strtok(NULL,"\""); - } - /* check if the current token contain single quote character*/ - else if ((ptr_quote = (char*)strchr(token,'\'')) != NULL) - { - /* - get the matching the matching single quote in the remaining - input string - */ - qt_token = (char*)strtok(NULL,"\'"); - } -#endif - /* - if the current token does not contains any quote character then - return to the caller. - */ - if (ptr_quote == NULL) - { - /* - if there is any earlier token i.e. ptr_token then append the - current token in it and return it else return the current - token directly - */ - return ptr_token ? strcat(ptr_token,token) : token; - } - - /* - remove the quote character i.e. make NULL so that the token will - be devided in two part and later both part can be concatenated - and hence quote will be removed - */ - *ptr_quote= 0; - - /* check if ptr_token has been initialized or not */ - if (ptr_token == NULL) - { - /* initialize the ptr_token with current token */ - ptr_token= token; - /* copy entire string between matching pair of quote*/ - sprintf(ptr_token+strlen(ptr_token),"%s %s", ptr_quote+1, qt_token); - } - else - { - /* - copy the current token and entire string between matching pair - of quote - */ - if (qt_token == NULL) - { - sprintf(ptr_token+strlen(ptr_token),"%s%s", token, ptr_quote+1); - } - else - { - sprintf(ptr_token+strlen(ptr_token),"%s%s %s", token, ptr_quote+1, - qt_token ); - } - } - } - - /* return the concatenated token */ - return ptr_token; -} - -#ifndef __WIN__ - -/* - Synopsis: - This function run scripts files on Linux and Netware - -Arguments: - script_name: name of script file - -Output: - nothing -*/ -void run_init_script(const char *script_name) -{ - arg_list_t al; - int err; - - // args - init_args(&al); - add_arg(&al, sh_file); - add_arg(&al, script_name); - - // spawn - if ((err = spawn(sh_file, &al, TRUE, NULL, NULL, NULL, NULL)) != 0) - { - die("Unable to run script."); - } - - // free args - free_args(&al); -} -#endif diff --git a/mysql-test/r/ctype_big5.result b/mysql-test/r/ctype_big5.result index 44fad0cd96a..789b6e586ad 100644 --- a/mysql-test/r/ctype_big5.result +++ b/mysql-test/r/ctype_big5.result @@ -1,10 +1,58 @@ drop table if exists t1; -SET NAMES big5; -CREATE TABLE t1 (c CHAR(10) CHARACTER SET big5, KEY(c)); +SET @test_character_set= 'big5'; +SET @test_collation= 'big5_chinese_ci'; +SET @safe_character_set_server= @@character_set_server; +SET @safe_collation_server= @@collation_server; +SET character_set_server= @test_character_set; +SET collation_server= @test_collation; +CREATE DATABASE d1; +USE d1; +CREATE TABLE t1 (c CHAR(10), KEY(c)); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c char(10) big5_chinese_ci YES MUL NULL select,insert,update,references INSERT INTO t1 VALUES ('aaa'),('aaaa'),('aaaaa'); -SELECT * FROM t1 WHERE c LIKE 'aaa%'; -c +SELECT c as want3results FROM t1 WHERE c LIKE 'aaa%'; +want3results aaa aaaa aaaaa DROP TABLE t1; +CREATE TABLE t1 (c1 varchar(15), KEY c1 (c1(2))); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c1 varchar(15) big5_chinese_ci YES MUL NULL select,insert,update,references +INSERT INTO t1 VALUES ('location'),('loberge'),('lotre'),('boabab'); +SELECT c1 as want3results from t1 where c1 like 'l%'; +want3results +location +loberge +lotre +SELECT c1 as want3results from t1 where c1 like 'lo%'; +want3results +location +loberge +lotre +SELECT c1 as want1result from t1 where c1 like 'loc%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'loca%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locat%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locati%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locatio%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'location%'; +want1result +location +DROP TABLE t1; +DROP DATABASE d1; +USE test; +SET character_set_server= @safe_character_set_server; +SET collation_server= @safe_collation_server; diff --git a/mysql-test/r/ctype_latin1.result b/mysql-test/r/ctype_latin1.result index a8182438ac4..355f53b63a5 100644 --- a/mysql-test/r/ctype_latin1.result +++ b/mysql-test/r/ctype_latin1.result @@ -296,3 +296,12 @@ FD C3BD FD 1 FE C3BE FE 1 FF C3BF FF 1 DROP TABLE t1; +select 'a' regexp 'A' collate latin1_general_ci; +'a' regexp 'A' collate latin1_general_ci +1 +select 'a' regexp 'A' collate latin1_general_cs; +'a' regexp 'A' collate latin1_general_cs +0 +select 'a' regexp 'A' collate latin1_bin; +'a' regexp 'A' collate latin1_bin +0 diff --git a/mysql-test/r/ctype_uca.result b/mysql-test/r/ctype_uca.result index 90681795513..cb060ad7ee4 100644 --- a/mysql-test/r/ctype_uca.result +++ b/mysql-test/r/ctype_uca.result @@ -19,6 +19,9 @@ select 'a ' = 'a\t', 'a ' < 'a\t', 'a ' > 'a\t'; select 'a a' > 'a', 'a \t' < 'a'; 'a a' > 'a' 'a \t' < 'a' 1 1 +select 'c' like '\_' as want0; +want0 +0 CREATE TABLE t ( c char(20) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; @@ -2315,3 +2318,60 @@ HEX(CONVERT(col1 USING ucs2)) 064A06A9062F064A06AF0631 064A06A9064A DROP TABLE t1; +SET @test_character_set= 'utf8'; +SET @test_collation= 'utf8_swedish_ci'; +SET @safe_character_set_server= @@character_set_server; +SET @safe_collation_server= @@collation_server; +SET character_set_server= @test_character_set; +SET collation_server= @test_collation; +CREATE DATABASE d1; +USE d1; +CREATE TABLE t1 (c CHAR(10), KEY(c)); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c char(10) utf8_swedish_ci YES MUL NULL select,insert,update,references +INSERT INTO t1 VALUES ('aaa'),('aaaa'),('aaaaa'); +SELECT c as want3results FROM t1 WHERE c LIKE 'aaa%'; +want3results +aaa +aaaa +aaaaa +DROP TABLE t1; +CREATE TABLE t1 (c1 varchar(15), KEY c1 (c1(2))); +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +c1 varchar(15) utf8_swedish_ci YES MUL NULL select,insert,update,references +INSERT INTO t1 VALUES ('location'),('loberge'),('lotre'),('boabab'); +SELECT c1 as want3results from t1 where c1 like 'l%'; +want3results +location +loberge +lotre +SELECT c1 as want3results from t1 where c1 like 'lo%'; +want3results +location +loberge +lotre +SELECT c1 as want1result from t1 where c1 like 'loc%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'loca%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locat%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locati%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'locatio%'; +want1result +location +SELECT c1 as want1result from t1 where c1 like 'location%'; +want1result +location +DROP TABLE t1; +DROP DATABASE d1; +USE test; +SET character_set_server= @safe_character_set_server; +SET collation_server= @safe_collation_server; diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 0e36b00a670..6394bc28c6e 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -487,3 +487,18 @@ prepare stmt1 from @str2; execute stmt1 using @ivar; ? 1234 +SET TIMESTAMP=10000; +create table t2 (c char(30)) charset=ucs2; +set @v=convert('abc' using ucs2); +reset master; +insert into t2 values (@v); +show binlog events from 79; +Log_name Pos Event_type Server_id Orig_log_pos Info +master-bin.000001 79 User var 1 79 @`v`=_ucs2 0x006100620063 COLLATE ucs2_general_ci +master-bin.000001 119 Query 1 119 use `test`; insert into t2 values (@v) +/*!40019 SET @@session.max_insert_delayed_threads=0*/; +SET @`v`:=_ucs2 0x006100620063 COLLATE ucs2_general_ci; +use test; +SET TIMESTAMP=10000; +insert into t2 values (@v); +drop table t2; diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 945ec8eae99..599d49208e7 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -814,3 +814,6 @@ t2 CREATE TABLE `t2` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t2; drop table t1; +select 'c' like '\_' as want0; +want0 +0 diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index 5575ee1bf98..f1fba87c70b 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -16,12 +16,34 @@ SET AUTOCOMMIT=0; DELETE from t1; SET AUTOCOMMIT=1; drop table t1; -create table t1 (a bigint not null, primary key (a,a,a,a,a,a,a,a,a,a)); -insert into t1 values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23); +create table t1 ( +a bigint not null, +b bigint not null default 0, +c bigint not null default 0, +d bigint not null default 0, +e bigint not null default 0, +f bigint not null default 0, +g bigint not null default 0, +h bigint not null default 0, +i bigint not null default 0, +j bigint not null default 0, +primary key (a,b,c,d,e,f,g,h,i,j)); +insert into t1 (a) values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23); delete from t1 where a=26; drop table t1; -create table t1 (a bigint not null, primary key (a,a,a,a,a,a,a,a,a,a)); -insert into t1 values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23),(27); +create table t1 ( +a bigint not null, +b bigint not null default 0, +c bigint not null default 0, +d bigint not null default 0, +e bigint not null default 0, +f bigint not null default 0, +g bigint not null default 0, +h bigint not null default 0, +i bigint not null default 0, +j bigint not null default 0, +primary key (a,b,c,d,e,f,g,h,i,j)); +insert into t1 (a) values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23),(27); delete from t1 where a=27; drop table t1; CREATE TABLE `t1` ( diff --git a/mysql-test/r/flush_block_commit.result b/mysql-test/r/flush_block_commit.result index 17991f15382..4a7575d8f7a 100644 --- a/mysql-test/r/flush_block_commit.result +++ b/mysql-test/r/flush_block_commit.result @@ -20,4 +20,12 @@ commit; a 1 unlock tables; +commit; +begin; +insert into t1 values(10); +flush tables with read lock; +commit; +unlock tables; +flush tables with read lock; +unlock tables; drop table t1; diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index e976cc95383..7acc8a2d23f 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -190,6 +190,14 @@ a select * from t1 where match a against ("+aaa10 +(bbb*)" in boolean mode); a aaa10 bbb20 +select * from t1 where match a against ("+(+aaa* +bbb1*)" in boolean mode); +a +aaa20 bbb15 +aaa30 bbb10 +select * from t1 where match a against ("(+aaa* +bbb1*)" in boolean mode); +a +aaa20 bbb15 +aaa30 bbb10 drop table t1; CREATE TABLE t1 ( id int(11), @@ -382,3 +390,18 @@ s pära para para para para para DROP TABLE t1; +CREATE TABLE t1 (h text, FULLTEXT (h)); +INSERT INTO t1 VALUES ('Jesses Hasse Ling and his syncopators of Swing'); +REPAIR TABLE t1; +Table Op Msg_type Msg_text +test.t1 repair status OK +select count(*) from t1; +count(*) +1 +drop table t1; +create table t1 (a int primary key, b text, fulltext(b)); +create table t2 (a int, b text); +insert t1 values (1, "aaaa"), (2, "bbbb"); +insert t2 values (10, "aaaa"), (2, "cccc"); +replace t1 select * from t2; +drop table t1, t2; diff --git a/mysql-test/r/func_compress.result b/mysql-test/r/func_compress.result index 11dbcca9431..9bc8e417e19 100644 --- a/mysql-test/r/func_compress.result +++ b/mysql-test/r/func_compress.result @@ -69,6 +69,6 @@ Error 1259 ZLIB: Input data corrupted Error 1256 Uncompressed data size too large; the maximum size is 1048576 (probably, length of uncompressed data was corrupted) drop table t1; set @@max_allowed_packet=1048576*100; -select compress(repeat('aaaaaaaaaa', 10000000)) is null; -compress(repeat('aaaaaaaaaa', 10000000)) is null +select compress(repeat('aaaaaaaaaa', IF(XXX, 10, 10000000))) is null; +compress(repeat('aaaaaaaaaa', IF(XXX, 10, 10000000))) is null 0 diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result index c25f89d4df3..4bb79a1cb41 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -637,8 +637,22 @@ create table t1 (a char(10)); insert into t1 values ('a'),('b'),('c'); select coercibility(max(a)) from t1; coercibility(max(a)) -3 +2 drop table t1; +create table t1 (a char character set latin2); +insert into t1 values ('a'),('b'); +select charset(max(a)), coercibility(max(a)), +charset(min(a)), coercibility(min(a)) from t1; +charset(max(a)) coercibility(max(a)) charset(min(a)) coercibility(min(a)) +latin2 2 latin2 2 +create table t2 select max(a),min(a) from t1; +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `max(a)` char(1) character set latin2 default NULL, + `min(a)` char(1) character set latin2 default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t2,t1; create table t1 (a int); insert into t1 values (1); select max(a) as b from t1 having b=1; diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 2dc6bffd071..c78b16aed8a 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -474,6 +474,12 @@ unix_timestamp(@a) select unix_timestamp('1969-12-01 19:00:01'); unix_timestamp('1969-12-01 19:00:01') 0 +select from_unixtime(0); +from_unixtime(0) +NULL +select from_unixtime(2145916800); +from_unixtime(2145916800) +NULL CREATE TABLE t1 (datetime datetime, timestamp timestamp, date date, time time); INSERT INTO t1 values ("2001-01-02 03:04:05", "2002-01-02 03:04:05", "2003-01-02", "06:07:08"); SELECT * from t1; diff --git a/mysql-test/r/have_openssl_1.require b/mysql-test/r/have_openssl_1.require index 032b60d544a..b33a1d2854f 100644 --- a/mysql-test/r/have_openssl_1.require +++ b/mysql-test/r/have_openssl_1.require @@ -1,2 +1,2 @@ Variable_name Value -Ssl_cipher EDH-RSA-DES-CBC3-SHA +Ssl_cipher DHE-RSA-AES256-SHA diff --git a/mysql-test/r/heap.result b/mysql-test/r/heap.result index 4950799137a..1f994b100e2 100644 --- a/mysql-test/r/heap.result +++ b/mysql-test/r/heap.result @@ -233,3 +233,10 @@ SELECT * FROM t1 WHERE B is not null; a B 1 1 DROP TABLE t1; +CREATE TABLE t1 (pseudo char(35) PRIMARY KEY, date int(10) unsigned NOT NULL) ENGINE=HEAP; +INSERT INTO t1 VALUES ('massecot',1101106491),('altec',1101106492),('stitch+',1101106304),('Seb Corgan',1101106305),('beerfilou',1101106263),('flaker',1101106529),('joce8',5),('M4vrick',1101106418),('gabay008',1101106525),('Vamp irX',1101106291),('ZoomZip',1101106546),('rip666',1101106502),('CBP ',1101106397),('guezpard',1101106496); +DELETE FROM t1 WHERE date<1101106546; +SELECT * FROM t1; +pseudo date +ZoomZip 1101106546 +DROP TABLE t1; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 9d830367745..009432ec3ab 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1630,3 +1630,21 @@ show status like "binlog_cache_disk_use"; Variable_name Value Binlog_cache_disk_use 1 drop table t1; +create table t1 (c char(10), index (c,c)) engine=innodb; +ERROR 42S21: Duplicate column name 'c' +create table t1 (c1 char(10), c2 char(10), index (c1,c2,c1)) engine=innodb; +ERROR 42S21: Duplicate column name 'c1' +create table t1 (c1 char(10), c2 char(10), index (c1,c1,c2)) engine=innodb; +ERROR 42S21: Duplicate column name 'c1' +create table t1 (c1 char(10), c2 char(10), index (c2,c1,c1)) engine=innodb; +ERROR 42S21: Duplicate column name 'c1' +create table t1 (c1 char(10), c2 char(10)) engine=innodb; +alter table t1 add key (c1,c1); +ERROR 42S21: Duplicate column name 'c1' +alter table t1 add key (c2,c1,c1); +ERROR 42S21: Duplicate column name 'c1' +alter table t1 add key (c1,c2,c1); +ERROR 42S21: Duplicate column name 'c1' +alter table t1 add key (c1,c1,c2); +ERROR 42S21: Duplicate column name 'c1' +drop table t1; diff --git a/mysql-test/r/key.result b/mysql-test/r/key.result index e74bda23da9..cceaf393a60 100644 --- a/mysql-test/r/key.result +++ b/mysql-test/r/key.result @@ -307,3 +307,21 @@ test.t1 check status OK drop table t1; create table t1 (c char(10), index (c(0))); ERROR HY000: Key part 'c' length cannot be 0 +create table t1 (c char(10), index (c,c)); +ERROR 42S21: Duplicate column name 'c' +create table t1 (c1 char(10), c2 char(10), index (c1,c2,c1)); +ERROR 42S21: Duplicate column name 'c1' +create table t1 (c1 char(10), c2 char(10), index (c1,c1,c2)); +ERROR 42S21: Duplicate column name 'c1' +create table t1 (c1 char(10), c2 char(10), index (c2,c1,c1)); +ERROR 42S21: Duplicate column name 'c1' +create table t1 (c1 char(10), c2 char(10)); +alter table t1 add key (c1,c1); +ERROR 42S21: Duplicate column name 'c1' +alter table t1 add key (c2,c1,c1); +ERROR 42S21: Duplicate column name 'c1' +alter table t1 add key (c1,c2,c1); +ERROR 42S21: Duplicate column name 'c1' +alter table t1 add key (c1,c1,c2); +ERROR 42S21: Duplicate column name 'c1' +drop table t1; diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 31b14f9b822..d155a14bb60 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -529,6 +529,7 @@ show keys from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment t1 1 a 1 a A NULL NULL NULL YES BTREE disabled create table t2 (a int); +set @@rand_seed1=31415926,@@rand_seed2=2718281828; insert t1 select * from t2; show keys from t1; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 7e69620394b..239418733ba 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -332,3 +332,45 @@ CREATE TABLE `t1` ( 2 3 drop table t1; + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `test` /*!40100 DEFAULT CHARACTER SET latin1 */; + +USE `test`; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; + +create database mysqldump_test_db character set latin2 collate latin2_bin; + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; + +CREATE DATABASE /*!32312 IF NOT EXISTS*/ `mysqldump_test_db` /*!40100 DEFAULT CHARACTER SET latin2 COLLATE latin2_bin */; + +USE `mysqldump_test_db`; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; + +drop database mysqldump_test_db; diff --git a/mysql-test/r/ndb_charset.result b/mysql-test/r/ndb_charset.result index 93429a1fcb0..501bec99ea3 100644 --- a/mysql-test/r/ndb_charset.result +++ b/mysql-test/r/ndb_charset.result @@ -78,9 +78,9 @@ unique key(a) ) engine=ndb; insert into t1 values(1, 'aAa'); insert into t1 values(2, 'aaa'); -ERROR 23000: Can't write, because of unique constraint, to table 't1' +ERROR 23000: Duplicate entry '2' for key 1 insert into t1 values(3, 'AAA'); -ERROR 23000: Can't write, because of unique constraint, to table 't1' +ERROR 23000: Duplicate entry '3' for key 1 select * from t1 order by p; p a 1 aAa diff --git a/mysql-test/r/ndb_grant.result b/mysql-test/r/ndb_grant.result new file mode 100644 index 00000000000..6583065a0c4 --- /dev/null +++ b/mysql-test/r/ndb_grant.result @@ -0,0 +1,416 @@ +drop table if exists t1; +SET NAMES binary; +use mysql; +alter table columns_priv engine=ndb; +alter table db engine=ndb; +alter table func engine=ndb; +alter table help_category engine=ndb; +alter table help_keyword engine=ndb; +alter table help_relation engine=ndb; +alter table help_topic engine=ndb; +alter table host engine=ndb; +alter table tables_priv engine=ndb; +alter table time_zone engine=ndb; +alter table time_zone_leap_second engine=ndb; +alter table time_zone_name engine=ndb; +alter table time_zone_transition engine=ndb; +alter table time_zone_transition_type engine=ndb; +alter table user engine=ndb; +use test; +delete from mysql.user where user='mysqltest_1'; +delete from mysql.db where user='mysqltest_1'; +flush privileges; +begin; +grant select on mysqltest.* to mysqltest_1@localhost require cipher "EDH-RSA-DES-CBC3-SHA"; +commit; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +begin; +grant delete on mysqltest.* to mysqltest_1@localhost; +commit; +select * from mysql.user where user="mysqltest_1"; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections +localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N SPECIFIED EDH-RSA-DES-CBC3-SHA 0 0 0 +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA' +GRANT SELECT, DELETE ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +begin; +revoke delete on mysqltest.* from mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE CIPHER 'EDH-RSA-DES-CBC3-SHA' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +begin; +grant select on mysqltest.* to mysqltest_1@localhost require NONE; +commit; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +begin; +grant USAGE on mysqltest.* to mysqltest_1@localhost require cipher "EDH-RSA-DES-CBC3-SHA" AND SUBJECT "testsubject" ISSUER "MySQL AB"; +commit; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE ISSUER 'MySQL AB' SUBJECT 'testsubject' CIPHER 'EDH-RSA-DES-CBC3-SHA' +GRANT SELECT ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +begin; +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE ISSUER 'MySQL AB' SUBJECT 'testsubject' CIPHER 'EDH-RSA-DES-CBC3-SHA' +delete from mysql.user where user='mysqltest_1'; +flush privileges; +begin; +grant CREATE TEMPORARY TABLES, LOCK TABLES on mysqltest.* to mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT CREATE TEMPORARY TABLES, LOCK TABLES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +flush privileges; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT CREATE TEMPORARY TABLES, LOCK TABLES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +begin; +revoke CREATE TEMPORARY TABLES on mysqltest.* from mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT LOCK TABLES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +begin; +grant ALL PRIVILEGES on mysqltest.* to mysqltest_1@localhost with GRANT OPTION; +commit; +flush privileges; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT ALL PRIVILEGES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION +begin; +revoke LOCK TABLES, ALTER on mysqltest.* from mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, CREATE TEMPORARY TABLES ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION +begin; +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +commit; +delete from mysql.user where user='mysqltest_1'; +flush privileges; +begin; +grant usage on test.* to mysqltest_1@localhost with grant option; +commit; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT USAGE ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION +GRANT USAGE ON `test`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION +delete from mysql.user where user='mysqltest_1'; +delete from mysql.db where user='mysqltest_1'; +delete from mysql.tables_priv where user='mysqltest_1'; +delete from mysql.columns_priv where user='mysqltest_1'; +flush privileges; +show grants for mysqltest_1@localhost; +ERROR 42000: There is no such grant defined for user 'mysqltest_1' on host 'localhost' +create table t1 (a int); +begin; +GRANT select,update,insert on t1 to mysqltest_1@localhost; +GRANT select (a), update (a),insert(a), references(a) on t1 to mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, SELECT (a), INSERT, INSERT (a), UPDATE, UPDATE (a), REFERENCES (a) ON `test`.`t1` TO 'mysqltest_1'@'localhost' +select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1"; +table_priv column_priv +Select,Insert,Update Select,Insert,Update,References +begin; +REVOKE select (a), update on t1 from mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT SELECT, INSERT, INSERT (a), REFERENCES (a) ON `test`.`t1` TO 'mysqltest_1'@'localhost' +begin; +REVOKE select,update,insert,insert (a) on t1 from mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' +GRANT REFERENCES (a) ON `test`.`t1` TO 'mysqltest_1'@'localhost' +begin; +GRANT select,references on t1 to mysqltest_1@localhost; +commit; +select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1"; +table_priv column_priv +Select,References References +begin; +grant all on test.* to mysqltest_3@localhost with grant option; +revoke all on test.* from mysqltest_3@localhost; +commit; +show grants for mysqltest_3@localhost; +Grants for mysqltest_3@localhost +GRANT USAGE ON *.* TO 'mysqltest_3'@'localhost' +GRANT USAGE ON `test`.* TO 'mysqltest_3'@'localhost' WITH GRANT OPTION +begin; +revoke grant option on test.* from mysqltest_3@localhost; +commit; +show grants for mysqltest_3@localhost; +Grants for mysqltest_3@localhost +GRANT USAGE ON *.* TO 'mysqltest_3'@'localhost' +begin; +grant all on test.t1 to mysqltest_2@localhost with grant option; +revoke all on test.t1 from mysqltest_2@localhost; +commit; +show grants for mysqltest_2@localhost; +Grants for mysqltest_2@localhost +GRANT USAGE ON *.* TO 'mysqltest_2'@'localhost' +GRANT USAGE ON `test`.`t1` TO 'mysqltest_2'@'localhost' WITH GRANT OPTION +begin; +revoke grant option on test.t1 from mysqltest_2@localhost; +commit; +show grants for mysqltest_2@localhost; +Grants for mysqltest_2@localhost +GRANT USAGE ON *.* TO 'mysqltest_2'@'localhost' +delete from mysql.user where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +delete from mysql.db where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +delete from mysql.tables_priv where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +delete from mysql.columns_priv where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +flush privileges; +drop table t1; +begin; +GRANT FILE on mysqltest.* to mysqltest_1@localhost; +ERROR HY000: Incorrect usage of DB GRANT and GLOBAL PRIVILEGES +commit; +select 1; +1 +1 +create database mysqltest1; +begin; +grant usage on mysqltest1.* to test6123 identified by 'magic123'; +commit; +select host,db,user,select_priv,insert_priv from mysql.db where db="mysqltest1"; +host db user select_priv insert_priv +delete from mysql.user where user='test6123'; +drop database mysqltest1; +create table t1 (a int); +begin; +grant ALL PRIVILEGES on *.* to drop_user2@localhost with GRANT OPTION; +commit; +show grants for drop_user2@localhost; +Grants for drop_user2@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user2'@'localhost' WITH GRANT OPTION +begin; +revoke all privileges, grant option from drop_user2@localhost; +commit; +drop user drop_user2@localhost; +begin; +grant ALL PRIVILEGES on *.* to drop_user@localhost with GRANT OPTION; +grant ALL PRIVILEGES on test.* to drop_user@localhost with GRANT OPTION; +grant select(a) on test.t1 to drop_user@localhost; +commit; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT ALL PRIVILEGES ON `test`.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT SELECT (a) ON `test`.`t1` TO 'drop_user'@'localhost' +set sql_mode=ansi_quotes; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT ALL PRIVILEGES ON "test".* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT SELECT (a) ON "test"."t1" TO 'drop_user'@'localhost' +set sql_mode=default; +set sql_quote_show_create=0; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT ALL PRIVILEGES ON test.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT SELECT (a) ON test.t1 TO 'drop_user'@'localhost' +set sql_mode="ansi_quotes"; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT ALL PRIVILEGES ON test.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT SELECT (a) ON test.t1 TO 'drop_user'@'localhost' +set sql_quote_show_create=1; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT ALL PRIVILEGES ON "test".* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT SELECT (a) ON "test"."t1" TO 'drop_user'@'localhost' +set sql_mode=""; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT ALL PRIVILEGES ON *.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT ALL PRIVILEGES ON `test`.* TO 'drop_user'@'localhost' WITH GRANT OPTION +GRANT SELECT (a) ON `test`.`t1` TO 'drop_user'@'localhost' +revoke all privileges, grant option from drop_user@localhost; +show grants for drop_user@localhost; +Grants for drop_user@localhost +GRANT USAGE ON *.* TO 'drop_user'@'localhost' +drop user drop_user@localhost; +begin; +revoke all privileges, grant option from drop_user@localhost; +ERROR HY000: Can't revoke all privileges, grant for one or more of the requested users +commit; +begin; +grant select(a) on test.t1 to drop_user1@localhost; +commit; +flush privileges; +begin; +grant select on test.t1 to drop_user2@localhost; +grant select on test.* to drop_user3@localhost; +grant select on *.* to drop_user4@localhost; +commit; +drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, +drop_user4@localhost; +ERROR HY000: Can't drop one or more of the requested users +begin; +revoke all privileges, grant option from drop_user1@localhost, drop_user2@localhost, +drop_user3@localhost, drop_user4@localhost; +commit; +drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, +drop_user4@localhost; +drop table t1; +begin; +grant usage on *.* to mysqltest_1@localhost identified by "password"; +grant select, update, insert on test.* to mysqltest@localhost; +commit; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' IDENTIFIED BY PASSWORD '*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19' +drop user mysqltest_1@localhost; +SET NAMES koi8r; +CREATE DATABASE ÂÄ; +USE ÂÄ; +CREATE TABLE ÔÁÂ (ËÏÌ int); +begin; +GRANT SELECT ON ÂÄ.* TO ÀÚÅÒ@localhost; +commit; +SHOW GRANTS FOR ÀÚÅÒ@localhost; +Grants for ÀÚÅÒ@localhost +GRANT USAGE ON *.* TO 'ÀÚÅÒ'@'localhost' +GRANT SELECT ON `ÂÄ`.* TO 'ÀÚÅÒ'@'localhost' +begin; +REVOKE SELECT ON ÂÄ.* FROM ÀÚÅÒ@localhost; +commit; +begin; +GRANT SELECT ON ÂÄ.ÔÁÂ TO ÀÚÅÒ@localhost; +commit; +SHOW GRANTS FOR ÀÚÅÒ@localhost; +Grants for ÀÚÅÒ@localhost +GRANT USAGE ON *.* TO 'ÀÚÅÒ'@'localhost' +GRANT SELECT ON `ÂÄ`.`ÔÁÂ` TO 'ÀÚÅÒ'@'localhost' +begin; +REVOKE SELECT ON ÂÄ.ÔÁÂ FROM ÀÚÅÒ@localhost; +commit; +begin; +GRANT SELECT (ËÏÌ) ON ÂÄ.ÔÁÂ TO ÀÚÅÒ@localhost; +commit; +SHOW GRANTS FOR ÀÚÅÒ@localhost; +Grants for ÀÚÅÒ@localhost +GRANT USAGE ON *.* TO 'ÀÚÅÒ'@'localhost' +GRANT SELECT (ËÏÌ) ON `ÂÄ`.`ÔÁÂ` TO 'ÀÚÅÒ'@'localhost' +begin; +REVOKE SELECT (ËÏÌ) ON ÂÄ.ÔÁÂ FROM ÀÚÅÒ@localhost; +commit; +DROP DATABASE ÂÄ; +SET NAMES latin1; +USE test; +CREATE TABLE t1 (a int ); +CREATE TABLE t2 LIKE t1; +CREATE TABLE t3 LIKE t1; +CREATE TABLE t4 LIKE t1; +CREATE TABLE t5 LIKE t1; +CREATE TABLE t6 LIKE t1; +CREATE TABLE t7 LIKE t1; +CREATE TABLE t8 LIKE t1; +CREATE TABLE t9 LIKE t1; +CREATE TABLE t10 LIKE t1; +CREATE DATABASE testdb1; +CREATE DATABASE testdb2; +CREATE DATABASE testdb3; +CREATE DATABASE testdb4; +CREATE DATABASE testdb5; +CREATE DATABASE testdb6; +CREATE DATABASE testdb7; +CREATE DATABASE testdb8; +CREATE DATABASE testdb9; +CREATE DATABASE testdb10; +begin; +GRANT ALL ON testdb1.* TO testuser@localhost; +GRANT ALL ON testdb2.* TO testuser@localhost; +GRANT ALL ON testdb3.* TO testuser@localhost; +GRANT ALL ON testdb4.* TO testuser@localhost; +GRANT ALL ON testdb5.* TO testuser@localhost; +GRANT ALL ON testdb6.* TO testuser@localhost; +GRANT ALL ON testdb7.* TO testuser@localhost; +GRANT ALL ON testdb8.* TO testuser@localhost; +GRANT ALL ON testdb9.* TO testuser@localhost; +GRANT ALL ON testdb10.* TO testuser@localhost; +GRANT SELECT ON test.t1 TO testuser@localhost; +GRANT SELECT ON test.t2 TO testuser@localhost; +GRANT SELECT ON test.t3 TO testuser@localhost; +GRANT SELECT ON test.t4 TO testuser@localhost; +GRANT SELECT ON test.t5 TO testuser@localhost; +GRANT SELECT ON test.t6 TO testuser@localhost; +GRANT SELECT ON test.t7 TO testuser@localhost; +GRANT SELECT ON test.t8 TO testuser@localhost; +GRANT SELECT ON test.t9 TO testuser@localhost; +GRANT SELECT ON test.t10 TO testuser@localhost; +GRANT SELECT (a) ON test.t1 TO testuser@localhost; +GRANT SELECT (a) ON test.t2 TO testuser@localhost; +GRANT SELECT (a) ON test.t3 TO testuser@localhost; +GRANT SELECT (a) ON test.t4 TO testuser@localhost; +GRANT SELECT (a) ON test.t5 TO testuser@localhost; +GRANT SELECT (a) ON test.t6 TO testuser@localhost; +GRANT SELECT (a) ON test.t7 TO testuser@localhost; +GRANT SELECT (a) ON test.t8 TO testuser@localhost; +GRANT SELECT (a) ON test.t9 TO testuser@localhost; +GRANT SELECT (a) ON test.t10 TO testuser@localhost; +commit; +begin; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM testuser@localhost; +commit; +SHOW GRANTS FOR testuser@localhost; +Grants for testuser@localhost +GRANT USAGE ON *.* TO 'testuser'@'localhost' +DROP USER testuser@localhost; +DROP TABLE t1,t2,t3,t4,t5,t6,t7,t8,t9,t10; +DROP DATABASE testdb1; +DROP DATABASE testdb2; +DROP DATABASE testdb3; +DROP DATABASE testdb4; +DROP DATABASE testdb5; +DROP DATABASE testdb6; +DROP DATABASE testdb7; +DROP DATABASE testdb8; +DROP DATABASE testdb9; +DROP DATABASE testdb10; +use mysql; +alter table columns_priv engine=myisam; +alter table db engine=myisam; +alter table func engine=myisam; +alter table help_category engine=myisam; +alter table help_keyword engine=myisam; +alter table help_relation engine=myisam; +alter table help_topic engine=myisam; +alter table host engine=myisam; +alter table tables_priv engine=myisam; +alter table time_zone engine=myisam; +alter table time_zone_leap_second engine=myisam; +alter table time_zone_name engine=myisam; +alter table time_zone_transition engine=myisam; +alter table time_zone_transition_type engine=myisam; +alter table user engine=myisam; +use test; +flush privileges; diff --git a/mysql-test/r/ndb_index_unique.result b/mysql-test/r/ndb_index_unique.result index f1407dfe78d..f9cc89ee4cc 100644 --- a/mysql-test/r/ndb_index_unique.result +++ b/mysql-test/r/ndb_index_unique.result @@ -22,7 +22,7 @@ select * from t1 where b = 4 order by a; a b c 3 4 6 insert into t1 values(8, 2, 3); -ERROR 23000: Can't write, because of unique constraint, to table 't1' +ERROR 23000: Duplicate entry '8' for key 1 select * from t1 order by a; a b c 1 2 3 @@ -44,6 +44,53 @@ a b c 7 8 3 8 2 3 drop table t1; +CREATE TABLE t1 ( +a int unsigned NOT NULL PRIMARY KEY, +b int unsigned, +c int unsigned, +UNIQUE bc(b,c) +) engine = ndb; +insert into t1 values(1,1,1),(2,NULL,2),(3,NULL,NULL),(4,4,NULL); +select * from t1 use index (bc) where b IS NULL order by a; +a b c +2 NULL 2 +3 NULL NULL +select * from t1 use index (bc)order by a; +a b c +1 1 1 +2 NULL 2 +3 NULL NULL +4 4 NULL +select * from t1 use index (bc) order by a; +a b c +1 1 1 +2 NULL 2 +3 NULL NULL +4 4 NULL +select * from t1 use index (PRIMARY) where b IS NULL order by a; +a b c +2 NULL 2 +3 NULL NULL +select * from t1 use index (bc) where b IS NULL order by a; +a b c +2 NULL 2 +3 NULL NULL +select * from t1 use index (bc) where b IS NULL and c IS NULL order by a; +a b c +3 NULL NULL +select * from t1 use index (bc) where b IS NULL and c = 2 order by a; +a b c +2 NULL 2 +select * from t1 use index (bc) where b < 4 order by a; +a b c +1 1 1 +select * from t1 use index (bc) where b IS NOT NULL order by a; +a b c +1 1 1 +4 4 NULL +insert into t1 values(5,1,1); +ERROR 23000: Duplicate entry '5' for key 1 +drop table t1; CREATE TABLE t2 ( a int unsigned NOT NULL PRIMARY KEY, b int unsigned not null, @@ -65,7 +112,7 @@ select * from t2 where b = 4 order by a; a b c 3 4 6 insert into t2 values(8, 2, 3); -ERROR 23000: Can't write, because of unique constraint, to table 't2' +ERROR 23000: Duplicate entry '8' for key 1 select * from t2 order by a; a b c 1 2 3 @@ -87,6 +134,13 @@ a b c 7 8 3 8 2 3 drop table t2; +CREATE TABLE t2 ( +a int unsigned NOT NULL PRIMARY KEY, +b int unsigned not null, +c int unsigned, +UNIQUE USING HASH (b, c) +) engine=ndbcluster; +ERROR 42000: Column 'c' is used with UNIQUE or INDEX but is not defined as NOT NULL CREATE TABLE t3 ( a int unsigned NOT NULL, b int unsigned not null, @@ -123,7 +177,7 @@ pk a 3 NULL 4 4 insert into t1 values (5,0); -ERROR 23000: Can't write, because of unique constraint, to table 't1' +ERROR 23000: Duplicate entry '5' for key 1 select * from t1 order by pk; pk a -1 NULL @@ -156,7 +210,7 @@ pk a b c 0 NULL 18 NULL 1 3 19 abc insert into t2 values(2,3,19,'abc'); -ERROR 23000: Can't write, because of unique constraint, to table 't2' +ERROR 23000: Duplicate entry '2' for key 1 select * from t2 order by pk; pk a b c -1 1 17 NULL @@ -522,3 +576,39 @@ uid gid rid cid 1 1 2 3 1 1 2 4 drop table t1,t2,t3,t4,t5,t6,t7; +CREATE TABLE t1 ( +a int unsigned NOT NULL PRIMARY KEY, +b int unsigned, +c int unsigned, +UNIQUE bc(b,c) ) engine = ndb; +insert into t1 values(1,1,1),(2,NULL,2),(3,NULL,NULL),(4,4,NULL); +select * from t1 where b=1 and c=1; +a b c +1 1 1 +select * from t1 where b is null and c is null; +a b c +3 NULL NULL +select * from t1 where b is null and c = 2; +a b c +2 NULL 2 +select * from t1 where b = 4 and c is null; +a b c +4 4 NULL +create table t8 as +select * from t1 where (b = 1 and c = 1) +or (b is null and c is null) +or (b is null and c = 2) +or (b = 4 and c is null); +select * from t8 order by a; +a b c +1 1 1 +2 NULL 2 +3 NULL NULL +4 4 NULL +select * from t1 order by a; +a b c +1 1 1 +2 NULL 2 +3 NULL NULL +4 4 NULL +drop table t1, t8; diff --git a/mysql-test/r/ndb_insert.result b/mysql-test/r/ndb_insert.result index 16c76f39680..7503010a66b 100644 --- a/mysql-test/r/ndb_insert.result +++ b/mysql-test/r/ndb_insert.result @@ -535,27 +535,46 @@ count(*) 2000 insert into t1 select * from t1 where b < 10 order by pk1; ERROR 23000: Duplicate entry '9' for key 1 +DELETE FROM t1 WHERE pk1=2; begin; -INSERT IGNORE INTO t1 VALUES(1,2,3); -ERROR HY000: Table storage engine for 't1' doesn't have this option -commit; -select * from t1 where pk1=1; +INSERT IGNORE INTO t1 VALUES(1,2,3),(2,3,4); +select * from t1 where pk1 < 3 order by pk1; pk1 b c +0 0 0 1 1 1 -INSERT IGNORE INTO t1 VALUES(1,2,3); -ERROR HY000: Table storage engine for 't1' doesn't have this option -select * from t1 where pk1=1; +2 3 4 +rollback; +INSERT IGNORE INTO t1 VALUES(1,2,3),(2,3,4); +select * from t1 where pk1 < 3 order by pk1; pk1 b c +0 0 0 1 1 1 -REPLACE INTO t1 values(1, 2, 3); +2 3 4 +REPLACE INTO t1 values(1, 78, 3); select * from t1 where pk1=1; pk1 b c -1 2 3 -INSERT INTO t1 VALUES(1,1,1) ON DUPLICATE KEY UPDATE b=79; -ERROR HY000: Table storage engine for 't1' doesn't have this option -select * from t1 where pk1=1; +1 78 3 +INSERT INTO t1 VALUES(1,1,1),(3,4,5) ON DUPLICATE KEY UPDATE b=79; +select * from t1 where pk1 < 4 order by pk1; pk1 b c -1 2 3 +0 0 0 +1 79 3 +2 3 4 +3 79 3 +INSERT INTO t1 VALUES(1,1,1),(3,4,5) ON DUPLICATE KEY UPDATE b=pk1+c; +select * from t1 where pk1 < 4 order by pk1; +pk1 b c +0 0 0 +1 4 3 +2 3 4 +3 6 3 +DELETE FROM t1 WHERE pk1 = 2 OR pk1 = 4 OR pk1 = 6; +INSERT INTO t1 VALUES(1,1,1),(2,2,17),(3,4,5) ON DUPLICATE KEY UPDATE pk1=b; +select * from t1 where pk1 = b and b != c order by pk1; +pk1 b c +2 2 17 +4 4 3 +6 6 3 DROP TABLE t1; CREATE TABLE t1(a INT) ENGINE=ndb; INSERT IGNORE INTO t1 VALUES (1); diff --git a/mysql-test/r/openssl_1.result b/mysql-test/r/openssl_1.result index a87d0c33559..f7cb17a1a74 100644 --- a/mysql-test/r/openssl_1.result +++ b/mysql-test/r/openssl_1.result @@ -2,9 +2,9 @@ drop table if exists t1; create table t1(f1 int); insert into t1 values (5); grant select on test.* to ssl_user1@localhost require SSL; -grant select on test.* to ssl_user2@localhost require cipher "EDH-RSA-DES-CBC3-SHA"; -grant select on test.* to ssl_user3@localhost require cipher "EDH-RSA-DES-CBC3-SHA" AND SUBJECT "/C=SE/L=Uppsala/O=MySQL AB/CN=MySQL Client/Email=abstract.mysql.developer@mysql.com"; -grant select on test.* to ssl_user4@localhost require cipher "EDH-RSA-DES-CBC3-SHA" AND SUBJECT "/C=SE/L=Uppsala/O=MySQL AB/CN=MySQL Client/Email=abstract.mysql.developer@mysql.com" ISSUER "/C=SE/L=Uppsala/O=MySQL AB/CN=Abstract MySQL Developer/Email=abstract.mysql.developer@mysql.com"; +grant select on test.* to ssl_user2@localhost require cipher "DHE-RSA-AES256-SHA"; +grant select on test.* to ssl_user3@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "/C=SE/L=Uppsala/O=MySQL AB/CN=MySQL Client/Email=abstract.mysql.developer@mysql.com"; +grant select on test.* to ssl_user4@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "/C=SE/L=Uppsala/O=MySQL AB/CN=MySQL Client/Email=abstract.mysql.developer@mysql.com" ISSUER "/C=SE/L=Uppsala/O=MySQL AB/CN=Abstract MySQL Developer/Email=abstract.mysql.developer@mysql.com"; flush privileges; select * from t1; f1 diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 6d9cfabb5a7..4a4c8fe22e4 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -450,3 +450,24 @@ PREPARE stmt FROM 'UPDATE t1 AS P1 INNER JOIN (SELECT N FROM t1 GROUP BY N HAVIN EXECUTE stmt; DEALLOCATE PREPARE stmt; DROP TABLE t1; +prepare stmt from "select ? is null, ? is not null, ?"; +select @no_such_var is null, @no_such_var is not null, @no_such_var; +@no_such_var is null @no_such_var is not null @no_such_var +1 0 NULL +execute stmt using @no_such_var, @no_such_var, @no_such_var; +? is null ? is not null ? +1 0 NULL +set @var='abc'; +select @var is null, @var is not null, @var; +@var is null @var is not null @var +0 1 abc +execute stmt using @var, @var, @var; +? is null ? is not null ? +0 1 abc +set @var=null; +select @var is null, @var is not null, @var; +@var is null @var is not null @var +1 0 NULL +execute stmt using @var, @var, @var; +? is null ? is not null ? +1 0 NULL diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index 70118509d0b..4fe7f57973f 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -2,20 +2,19 @@ use test; drop table if exists t1, t9 ; create table t1 ( -a int not null, b varchar(30), +a int, b varchar(30), primary key(a) ) engine = 'NDB' ; -drop table if exists t9; create table t9 ( -c1 tinyint not null, c2 smallint, c3 mediumint, c4 int, +c1 tinyint, c2 smallint, c3 mediumint, c4 int, c5 integer, c6 bigint, c7 float, c8 double, c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), c13 date, c14 datetime, c15 timestamp(14), c16 time, c17 year, c18 bit, c19 bool, c20 char, -c21 char(10), c22 varchar(30), c23 char(100), c24 char(100), -c25 char(100), c26 char(100), c27 char(100), c28 char(100), -c29 char(100), c30 char(100), c31 enum('one', 'two', 'three'), +c21 char(10), c22 varchar(30), c23 tinyblob, c24 tinytext, +c25 blob, c26 text, c27 mediumblob, c28 mediumtext, +c29 longblob, c30 longtext, c31 enum('one', 'two', 'three'), c32 set('monday', 'tuesday', 'wednesday'), primary key(c1) ) engine = 'NDB' ; @@ -72,14 +71,14 @@ def test t9 t9 c19 c19 1 1 1 Y 32768 0 63 def test t9 t9 c20 c20 254 1 1 Y 0 0 8 def test t9 t9 c21 c21 253 10 10 Y 0 0 8 def test t9 t9 c22 c22 253 30 30 Y 0 0 8 -def test t9 t9 c23 c23 253 100 8 Y 0 0 8 -def test t9 t9 c24 c24 253 100 8 Y 0 0 8 -def test t9 t9 c25 c25 253 100 4 Y 0 0 8 -def test t9 t9 c26 c26 253 100 4 Y 0 0 8 -def test t9 t9 c27 c27 253 100 10 Y 0 0 8 -def test t9 t9 c28 c28 253 100 10 Y 0 0 8 -def test t9 t9 c29 c29 253 100 8 Y 0 0 8 -def test t9 t9 c30 c30 253 100 8 Y 0 0 8 +def test t9 t9 c23 c23 252 255 8 Y 144 0 63 +def test t9 t9 c24 c24 252 255 8 Y 16 0 8 +def test t9 t9 c25 c25 252 65535 4 Y 144 0 63 +def test t9 t9 c26 c26 252 65535 4 Y 16 0 8 +def test t9 t9 c27 c27 252 16777215 10 Y 144 0 63 +def test t9 t9 c28 c28 252 16777215 10 Y 16 0 8 +def test t9 t9 c29 c29 252 16777215 8 Y 144 0 63 +def test t9 t9 c30 c30 252 16777215 8 Y 16 0 8 def test t9 t9 c31 c31 254 5 3 Y 256 0 8 def test t9 t9 c32 c32 254 24 7 Y 2048 0 8 c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 c31 c32 @@ -1188,7 +1187,7 @@ c29= 'longblob', c30= 'longtext', c31='two', c32= 'tuesday'; commit ; prepare stmt1 from 'delete from t1 where a=2' ; execute stmt1; -select a,b from t1 where a=2 order by b; +select a,b from t1 where a=2; a b execute stmt1; insert into t1 values(0,NULL); @@ -1270,18 +1269,23 @@ execute stmt1 using @arg00, @arg00; select a,b from t1 where a=@arg00; a b 2 two +execute stmt1 using @arg01, @arg00; select a,b from t1 where a=@arg01; a b +22 two execute stmt1 using @arg00, @arg01; select a,b from t1 where a=@arg00; a b 2 two set @arg00=NULL; set @arg01=2; +execute stmt1 using @arg00, @arg01; +Warnings: +Warning 1263 Data truncated; NULL supplied to NOT NULL column 'a' at row 1 select a,b from t1 order by a; a b +0 two 1 one -2 two 3 three 4 four set @arg00=0; @@ -1302,15 +1306,19 @@ create table t2 as select a,b from t1 ; prepare stmt1 from 'update t1 set a=? where b=? and a in (select ? from t2 where b = ? or a = ?)'; +execute stmt1 using @arg00, @arg01, @arg02, @arg03, @arg04 ; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 select a,b from t1 where a = @arg00 ; a b +23 two prepare stmt1 from 'update t1 set a=? where b=? and a not in (select ? from t2 where b = ? or a = ?)'; execute stmt1 using @arg04, @arg01, @arg02, @arg03, @arg00 ; -affected rows: 0 -info: Rows matched: 0 Changed: 0 Warnings: 0 -select a,b from t1 order by a; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +select a,b from t1 order by a ; a b 1 one 2 two @@ -1319,21 +1327,25 @@ a b drop table t2 ; create table t2 ( -a int not null, b varchar(30), +a int, b varchar(30), primary key(a) ) engine = 'NDB' ; insert into t2(a,b) select a, b from t1 ; prepare stmt1 from 'update t1 set a=? where b=? and a in (select ? from t2 where b = ? or a = ?)'; +execute stmt1 using @arg00, @arg01, @arg02, @arg03, @arg04 ; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 select a,b from t1 where a = @arg00 ; a b +23 two prepare stmt1 from 'update t1 set a=? where b=? and a not in (select ? from t2 where b = ? or a = ?)'; execute stmt1 using @arg04, @arg01, @arg02, @arg03, @arg00 ; -affected rows: 0 -info: Rows matched: 0 Changed: 0 Warnings: 0 +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 select a,b from t1 order by a ; a b 1 one @@ -1474,7 +1486,7 @@ set @arg02=82 ; set @arg03='8-2' ; prepare stmt1 from 'insert into t1 values(?,?),(?,?)'; execute stmt1 using @arg00, @arg01, @arg02, @arg03 ; -select a,b from t1 where a in (@arg00,@arg02) order by a ; +select a,b from t1 where a in (@arg00,@arg02) ; a b 81 8-1 82 8-2 @@ -1489,6 +1501,7 @@ set @arg00=6 ; set @arg01=1 ; prepare stmt1 from 'insert into t1 set a=?, b=''sechs'' on duplicate key update a=a + ?, b=concat(b,''modified'') '; +execute stmt1 using @arg00, @arg01; select * from t1 order by a; a b 0 NULL @@ -1497,13 +1510,15 @@ a b 3 three 4 four 5 five -6 six +7 sixmodified 8 eight 9 nine 81 8-1 82 8-2 set @arg00=81 ; set @arg01=1 ; +execute stmt1 using @arg00, @arg01; +ERROR 23000: Duplicate entry '82' for key 1 drop table if exists t2 ; create table t2 (id int auto_increment primary key) ENGINE= 'NDB' ; @@ -1526,23 +1541,32 @@ set @x1100="x1100" ; set @100=100 ; set @updated="updated" ; insert into t1 values(1000,'x1000_1') ; +insert into t1 values(@1000,@x1000_2),(@1000,@x1000_3) +on duplicate key update a = a + @100, b = concat(b,@updated) ; select a,b from t1 where a >= 1000 order by a ; a b -1000 x1000_1 +1000 x1000_3 +1100 x1000_1updated delete from t1 where a >= 1000 ; insert into t1 values(1000,'x1000_1') ; prepare stmt1 from ' insert into t1 values(?,?),(?,?) on duplicate key update a = a + ?, b = concat(b,?) '; +execute stmt1 using @1000, @x1000_2, @1000, @x1000_3, @100, @updated ; select a,b from t1 where a >= 1000 order by a ; a b -1000 x1000_1 +1000 x1000_3 +1100 x1000_1updated delete from t1 where a >= 1000 ; insert into t1 values(1000,'x1000_1') ; +execute stmt1 using @1000, @x1000_2, @1100, @x1000_3, @100, @updated ; select a,b from t1 where a >= 1000 order by a ; a b -1000 x1000_1 +1200 x1000_1updatedupdated delete from t1 where a >= 1000 ; prepare stmt1 from ' replace into t1 (a,b) select 100, ''hundred'' '; +execute stmt1; +execute stmt1; +execute stmt1; test_sequence ------ multi table tests ------ delete from t1 ; @@ -1891,13 +1915,13 @@ def @arg19 254 20 1 Y 128 31 63 def @arg20 254 8192 1 Y 0 31 8 def @arg21 254 8192 10 Y 0 31 8 def @arg22 254 8192 30 Y 0 31 8 -def @arg23 254 8192 8 Y 0 31 8 +def @arg23 254 8192 8 Y 128 31 63 def @arg24 254 8192 8 Y 0 31 8 -def @arg25 254 8192 4 Y 0 31 8 +def @arg25 254 8192 4 Y 128 31 63 def @arg26 254 8192 4 Y 0 31 8 -def @arg27 254 8192 10 Y 0 31 8 +def @arg27 254 8192 10 Y 128 31 63 def @arg28 254 8192 10 Y 0 31 8 -def @arg29 254 8192 8 Y 0 31 8 +def @arg29 254 8192 8 Y 128 31 63 def @arg30 254 8192 8 Y 0 31 8 def @arg31 254 8192 3 Y 0 31 8 def @arg32 254 8192 6 Y 128 31 63 @@ -1938,13 +1962,13 @@ def @arg19 254 20 0 Y 128 31 63 def @arg20 254 8192 0 Y 0 31 8 def @arg21 254 8192 0 Y 0 31 8 def @arg22 254 8192 0 Y 0 31 8 -def @arg23 254 8192 0 Y 0 31 8 +def @arg23 254 8192 0 Y 128 31 63 def @arg24 254 8192 0 Y 0 31 8 -def @arg25 254 8192 0 Y 0 31 8 +def @arg25 254 8192 0 Y 128 31 63 def @arg26 254 8192 0 Y 0 31 8 -def @arg27 254 8192 0 Y 0 31 8 +def @arg27 254 8192 0 Y 128 31 63 def @arg28 254 8192 0 Y 0 31 8 -def @arg29 254 8192 0 Y 0 31 8 +def @arg29 254 8192 0 Y 128 31 63 def @arg30 254 8192 0 Y 0 31 8 def @arg31 254 8192 0 Y 0 31 8 def @arg32 254 8192 0 Y 0 31 8 @@ -1988,13 +2012,13 @@ def @arg19 254 20 1 Y 128 31 63 def @arg20 254 8192 1 Y 0 31 8 def @arg21 254 8192 10 Y 0 31 8 def @arg22 254 8192 30 Y 0 31 8 -def @arg23 254 8192 8 Y 0 31 8 +def @arg23 254 8192 8 Y 128 31 63 def @arg24 254 8192 8 Y 0 31 8 -def @arg25 254 8192 4 Y 0 31 8 +def @arg25 254 8192 4 Y 128 31 63 def @arg26 254 8192 4 Y 0 31 8 -def @arg27 254 8192 10 Y 0 31 8 +def @arg27 254 8192 10 Y 128 31 63 def @arg28 254 8192 10 Y 0 31 8 -def @arg29 254 8192 8 Y 0 31 8 +def @arg29 254 8192 8 Y 128 31 63 def @arg30 254 8192 8 Y 0 31 8 def @arg31 254 8192 3 Y 0 31 8 def @arg32 254 8192 6 Y 128 31 63 @@ -2028,13 +2052,13 @@ def @arg19 254 20 0 Y 128 31 63 def @arg20 254 8192 0 Y 0 31 8 def @arg21 254 8192 0 Y 0 31 8 def @arg22 254 8192 0 Y 0 31 8 -def @arg23 254 8192 0 Y 0 31 8 +def @arg23 254 8192 0 Y 128 31 63 def @arg24 254 8192 0 Y 0 31 8 -def @arg25 254 8192 0 Y 0 31 8 +def @arg25 254 8192 0 Y 128 31 63 def @arg26 254 8192 0 Y 0 31 8 -def @arg27 254 8192 0 Y 0 31 8 +def @arg27 254 8192 0 Y 128 31 63 def @arg28 254 8192 0 Y 0 31 8 -def @arg29 254 8192 0 Y 0 31 8 +def @arg29 254 8192 0 Y 128 31 63 def @arg30 254 8192 0 Y 0 31 8 def @arg31 254 8192 0 Y 0 31 8 def @arg32 254 8192 0 Y 0 31 8 @@ -2076,13 +2100,13 @@ def @arg19 254 20 1 Y 128 31 63 def @arg20 254 8192 1 Y 0 31 8 def @arg21 254 8192 10 Y 0 31 8 def @arg22 254 8192 30 Y 0 31 8 -def @arg23 254 8192 8 Y 0 31 8 +def @arg23 254 8192 8 Y 128 31 63 def @arg24 254 8192 8 Y 0 31 8 -def @arg25 254 8192 4 Y 0 31 8 +def @arg25 254 8192 4 Y 128 31 63 def @arg26 254 8192 4 Y 0 31 8 -def @arg27 254 8192 10 Y 0 31 8 +def @arg27 254 8192 10 Y 128 31 63 def @arg28 254 8192 10 Y 0 31 8 -def @arg29 254 8192 8 Y 0 31 8 +def @arg29 254 8192 8 Y 128 31 63 def @arg30 254 8192 8 Y 0 31 8 def @arg31 254 8192 3 Y 0 31 8 def @arg32 254 8192 6 Y 128 31 63 @@ -2120,13 +2144,13 @@ def @arg19 254 20 0 Y 128 31 63 def @arg20 254 8192 0 Y 0 31 8 def @arg21 254 8192 0 Y 0 31 8 def @arg22 254 8192 0 Y 0 31 8 -def @arg23 254 8192 0 Y 0 31 8 +def @arg23 254 8192 0 Y 128 31 63 def @arg24 254 8192 0 Y 0 31 8 -def @arg25 254 8192 0 Y 0 31 8 +def @arg25 254 8192 0 Y 128 31 63 def @arg26 254 8192 0 Y 0 31 8 -def @arg27 254 8192 0 Y 0 31 8 +def @arg27 254 8192 0 Y 128 31 63 def @arg28 254 8192 0 Y 0 31 8 -def @arg29 254 8192 0 Y 0 31 8 +def @arg29 254 8192 0 Y 128 31 63 def @arg30 254 8192 0 Y 0 31 8 def @arg31 254 8192 0 Y 0 31 8 def @arg32 254 8192 0 Y 0 31 8 @@ -2166,13 +2190,13 @@ def @arg19 254 20 1 Y 128 31 63 def @arg20 254 8192 1 Y 0 31 8 def @arg21 254 8192 10 Y 0 31 8 def @arg22 254 8192 30 Y 0 31 8 -def @arg23 254 8192 8 Y 0 31 8 +def @arg23 254 8192 8 Y 128 31 63 def @arg24 254 8192 8 Y 0 31 8 -def @arg25 254 8192 4 Y 0 31 8 +def @arg25 254 8192 4 Y 128 31 63 def @arg26 254 8192 4 Y 0 31 8 -def @arg27 254 8192 10 Y 0 31 8 +def @arg27 254 8192 10 Y 128 31 63 def @arg28 254 8192 10 Y 0 31 8 -def @arg29 254 8192 8 Y 0 31 8 +def @arg29 254 8192 8 Y 128 31 63 def @arg30 254 8192 8 Y 0 31 8 def @arg31 254 8192 3 Y 0 31 8 def @arg32 254 8192 6 Y 128 31 63 @@ -2204,13 +2228,13 @@ def @arg19 254 20 0 Y 128 31 63 def @arg20 254 8192 0 Y 0 31 8 def @arg21 254 8192 0 Y 0 31 8 def @arg22 254 8192 0 Y 0 31 8 -def @arg23 254 8192 0 Y 0 31 8 +def @arg23 254 8192 0 Y 128 31 63 def @arg24 254 8192 0 Y 0 31 8 -def @arg25 254 8192 0 Y 0 31 8 +def @arg25 254 8192 0 Y 128 31 63 def @arg26 254 8192 0 Y 0 31 8 -def @arg27 254 8192 0 Y 0 31 8 +def @arg27 254 8192 0 Y 128 31 63 def @arg28 254 8192 0 Y 0 31 8 -def @arg29 254 8192 0 Y 0 31 8 +def @arg29 254 8192 0 Y 128 31 63 def @arg30 254 8192 0 Y 0 31 8 def @arg31 254 8192 0 Y 0 31 8 def @arg32 254 8192 0 Y 0 31 8 @@ -2770,14 +2794,14 @@ c1 c20 c21 c22 c23 c24 c25 c26 c27 c28 c29 c30 41 4 41 41 41 41 41 41 41 41 41 41 42 4 42 42 42 42 42 42 42 42 42 42 43 4 43 43 43 43 43 43 43 43 43 43 -50 5 50 50 50 50 50 50 50 50 50 50 +50 5 50 50 50.00 50.00 50.00 50.00 50.00 50.00 50.00 50.00 51 5 51 51 51 51 51 51 51 51 51 51 -52 5 52 52 52 52 52 52 52 52 52 52 -53 5 53 53 53 53 53 53 53 53 53 53 -54 5 54 54 54 54 54 54 54 54 54 54 +52 5 52 52 52.00 52.00 52.00 52.00 52.00 52.00 52.00 52.00 +53 5 53 53 53.00 53.00 53.00 53.00 53.00 53.00 53.00 53.00 +54 5 54 54 54.00 54.00 54.00 54.00 54.00 54.00 54.00 54.00 55 5 55 55 55 55 55 55 55 55 55 55 -56 6 56 56 56 56 56 56 56 56 56 56 -57 6 57 57 57 57 57 57 57 57 57 57 +56 6 56 56 56.00 56.00 56.00 56.00 56.00 56.00 56.00 56.00 +57 6 57 57 57.00 57.00 57.00 57.00 57.00 57.00 57.00 57.00 60 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 61 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL 62 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 17ed9513653..fc2b4a78469 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -221,7 +221,7 @@ update t1 set y=x; explain select * from t1, t1 t2 where t1.y = 2 and t2.x between 7 and t1.y+0; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref y y 5 const 1 Using where -1 SIMPLE t2 range x x 5 NULL 4 Using where +1 SIMPLE t2 range x x 5 NULL 4 Range checked for each record (index map: 0x1) explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= 7 and t2.x <= t1.y+0; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref y y 5 const 1 Using where @@ -237,7 +237,7 @@ id select_type table type possible_keys key key_len ref rows Extra explain select * from t1, t1 t2 where t1.y = 2 and t2.x between 0 and t1.y; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref y y 5 const 1 Using where -1 SIMPLE t2 ALL x NULL NULL NULL 9 Using where +1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 0x1) explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= 0 and t2.x <= t1.y; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref y y 5 const 1 Using where diff --git a/mysql-test/r/rpl_start_stop_slave.result b/mysql-test/r/rpl_start_stop_slave.result new file mode 100644 index 00000000000..1fcb586d1fb --- /dev/null +++ b/mysql-test/r/rpl_start_stop_slave.result @@ -0,0 +1,12 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +stop slave; +create table t1(n int); +start slave; +stop slave io_thread; +start slave io_thread; +drop table t1; diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index 3417c7ecb85..a05b379ed88 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -2353,6 +2353,27 @@ select * from t2,t3 where t2.s = t3.s; s s two two drop table t1, t2, t3; +create table t1 (a integer, b integer, index(a), index(b)); +create table t2 (c integer, d integer, index(c), index(d)); +insert into t1 values (1,2), (2,2), (3,2), (4,2); +insert into t2 values (1,3), (2,3), (3,4), (4,4); +explain select * from t1 left join t2 on a=c where d in (4); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref c,d d 5 const 2 Using where +1 SIMPLE t1 ALL a NULL NULL NULL 3 Using where +select * from t1 left join t2 on a=c where d in (4); +a b c d +3 2 3 4 +4 2 4 4 +explain select * from t1 left join t2 on a=c where d = 4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ref c,d d 5 const 2 Using where +1 SIMPLE t1 ALL a NULL NULL NULL 3 Using where +select * from t1 left join t2 on a=c where d = 4; +a b c d +3 2 3 4 +4 2 4 4 +drop table t1, t2; CREATE TABLE t1 ( i int(11) NOT NULL default '0', c char(10) NOT NULL default '', @@ -2365,7 +2386,4 @@ INSERT INTO t1 VALUES (3,'c'); EXPLAIN SELECT i FROM t1 WHERE i=1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index -EXPLAIN SELECT i FROM t1 WHERE i=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index DROP TABLE t1; diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index f3c4be847ea..99827238540 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1990,6 +1990,21 @@ ac 700 NULL drop tables t1,t2; +create table t1 (a int not null, b int not null, c int, primary key (a,b)); +insert into t1 values (1,1,1), (2,2,2), (3,3,3); +set @b:= 0; +explain select sum(a) from t1 where b > @b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 index NULL PRIMARY 8 NULL 3 Using where; Using index +set @a:= (select sum(a) from t1 where b > @b); +explain select a from t1 where c=2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +do @a:= (select sum(a) from t1 where b > @b); +explain select a from t1 where c=2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using where +drop table t1; set @got_val= (SELECT 1 FROM (SELECT 'A' as my_col) as T1 ) ; create table t1 (a int, b int); create table t2 (a int, b int); diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index 95bba1d4ec7..8a0c74b3ae5 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -682,8 +682,8 @@ id txt 3 NULL 1 Chevy drop table t1; -CREATE TABLE t1 ( i int(11) NOT NULL default '0', c text NOT NULL, PRIMARY KEY (i), KEY (c(1),c(1))); -INSERT t1 VALUES (1,''),(2,''),(3,'asdfh'),(4,''); +CREATE TABLE t1 ( i int(11) NOT NULL default '0', c text NOT NULL, d varchar(1) NOT NULL DEFAULT ' ', PRIMARY KEY (i), KEY (c(1),d)); +INSERT t1 (i, c) VALUES (1,''),(2,''),(3,'asdfh'),(4,''); select max(i) from t1 where c = ''; max(i) 4 diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result index 524bc9c50d4..127a54e087b 100644 --- a/mysql-test/r/type_datetime.result +++ b/mysql-test/r/type_datetime.result @@ -97,13 +97,15 @@ select * from t1 where a is null or b is null; a b drop table t1; create table t1 (t datetime); -insert into t1 values (20030102030460),(20030102036301),(20030102240401),(20030132030401),(20031302030460); +insert into t1 values (20030102030460),(20030102036301),(20030102240401), +(20030132030401),(20031302030401),(100001202030401); Warnings: Warning 1265 Data truncated for column 't' at row 1 Warning 1265 Data truncated for column 't' at row 2 Warning 1265 Data truncated for column 't' at row 3 Warning 1265 Data truncated for column 't' at row 4 Warning 1265 Data truncated for column 't' at row 5 +Warning 1265 Data truncated for column 't' at row 6 select * from t1; t 0000-00-00 00:00:00 @@ -111,14 +113,18 @@ t 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 +0000-00-00 00:00:00 delete from t1; -insert into t1 values ("20030102030460"),("20030102036301"),("20030102240401"),("20030132030401"),("20031302030460"); +insert into t1 values +("2003-01-02 03:04:60"),("2003-01-02 03:63:01"),("2003-01-02 24:04:01"), +("2003-01-32 03:04:01"),("2003-13-02 03:04:01"), ("10000-12-02 03:04:00"); Warnings: Warning 1264 Data truncated; out of range for column 't' at row 1 Warning 1264 Data truncated; out of range for column 't' at row 2 Warning 1264 Data truncated; out of range for column 't' at row 3 Warning 1264 Data truncated; out of range for column 't' at row 4 Warning 1264 Data truncated; out of range for column 't' at row 5 +Warning 1264 Data truncated; out of range for column 't' at row 6 select * from t1; t 0000-00-00 00:00:00 @@ -126,6 +132,7 @@ t 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 +0000-00-00 00:00:00 delete from t1; insert into t1 values ("0000-00-00 00:00:00 some trailer"),("2003-01-01 00:00:00 some trailer"); Warnings: diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 7820cd1d6ff..49a2907f571 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -1110,4 +1110,14 @@ t1 CREATE TABLE `t1` ( `a` char(1) character set latin1 collate latin1_german1_ci default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +create table t1 as +(select a from t2) union +(select b from t2) union +(select 'c' collate latin1_german1_ci from t2); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(1) character set latin1 collate latin1_german1_ci default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; drop table t2; diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 659c392e153..4f521143d97 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -169,18 +169,12 @@ SET @`a b`='hello'; INSERT INTO t1 VALUES(@`a b`); set @var1= "';aaa"; insert into t1 values (@var1); -create table t2 (c char(30)) charset=ucs2; -set @v=convert('abc' using ucs2); -insert into t2 values (@v); show binlog events from 79; Log_name Pos Event_type Server_id Orig_log_pos Info master-bin.000001 79 User var 1 79 @`a b`=_latin1 0x68656C6C6F COLLATE latin1_swedish_ci master-bin.000001 120 Query 1 120 use `test`; INSERT INTO t1 VALUES(@`a b`) master-bin.000001 184 User var 1 184 @`var1`=_latin1 0x273B616161 COLLATE latin1_swedish_ci master-bin.000001 226 Query 1 226 use `test`; insert into t1 values (@var1) -master-bin.000001 290 Query 1 290 use `test`; create table t2 (c char(30)) charset=ucs2 -master-bin.000001 366 User var 1 366 @`v`=_ucs2 0x006100620063 COLLATE ucs2_general_ci -master-bin.000001 406 Query 1 406 use `test`; insert into t2 values (@v) /*!40019 SET @@session.max_insert_delayed_threads=0*/; SET @`a b`:=_latin1 0x68656C6C6F COLLATE latin1_swedish_ci; use test; @@ -189,12 +183,7 @@ INSERT INTO t1 VALUES(@`a b`); SET @`var1`:=_latin1 0x273B616161 COLLATE latin1_swedish_ci; SET TIMESTAMP=10000; insert into t1 values (@var1); -SET TIMESTAMP=10000; -create table t2 (c char(30)) charset=ucs2; -SET @`v`:=_ucs2 0x006100620063 COLLATE ucs2_general_ci; -SET TIMESTAMP=10000; -insert into t2 values (@v); -drop table t1, t2; +drop table t1; set @var= NULL ; select FIELD( @var,'1it','Hit') as my_column; my_column diff --git a/mysql-test/t/ctype_big5.test b/mysql-test/t/ctype_big5.test index 9bf1808636e..b1d71a6af15 100644 --- a/mysql-test/t/ctype_big5.test +++ b/mysql-test/t/ctype_big5.test @@ -7,12 +7,6 @@ drop table if exists t1; --enable_warnings -SET NAMES big5; - -# -# Bug 1883: LIKE did not work in some cases with a key. -# -CREATE TABLE t1 (c CHAR(10) CHARACTER SET big5, KEY(c)); -INSERT INTO t1 VALUES ('aaa'),('aaaa'),('aaaaa'); -SELECT * FROM t1 WHERE c LIKE 'aaa%'; -DROP TABLE t1; +SET @test_character_set= 'big5'; +SET @test_collation= 'big5_chinese_ci'; +-- source include/ctype_common.inc diff --git a/mysql-test/t/ctype_latin1.test b/mysql-test/t/ctype_latin1.test index 14062437428..677acd9faa9 100644 --- a/mysql-test/t/ctype_latin1.test +++ b/mysql-test/t/ctype_latin1.test @@ -53,3 +53,10 @@ SELECT hex(@l:=convert(@u using latin1)), a=@l FROM t1; DROP TABLE t1; + +# +# Bug #6737: REGEXP gives wrong result with case sensitive collation +# +select 'a' regexp 'A' collate latin1_general_ci; +select 'a' regexp 'A' collate latin1_general_cs; +select 'a' regexp 'A' collate latin1_bin; diff --git a/mysql-test/t/ctype_uca.test b/mysql-test/t/ctype_uca.test index 708a31d637e..11833ba9bc7 100644 --- a/mysql-test/t/ctype_uca.test +++ b/mysql-test/t/ctype_uca.test @@ -24,6 +24,11 @@ select 'a ' = 'a\t', 'a ' < 'a\t', 'a ' > 'a\t'; select 'a a' > 'a', 'a \t' < 'a'; +# +# Bug #6787 LIKE not working properly with _ and utf8 data +# +select 'c' like '\_' as want0; + # # Bug #5679 utf8_unicode_ci LIKE--trailing % doesn't equal zero characters # @@ -435,3 +440,7 @@ INSERT INTO t1 VALUES (CONVERT(_ucs2 0x06280648062F0646062F USING utf8)); INSERT INTO t1 VALUES (CONVERT(_ucs2 0x06450647064506270646 USING utf8)); SELECT HEX(CONVERT(col1 USING ucs2)) FROM t1 ORDER BY col1 COLLATE utf8_persian_ci, col1 COLLATE utf8_bin; DROP TABLE t1; + +SET @test_character_set= 'utf8'; +SET @test_collation= 'utf8_swedish_ci'; +-- source include/ctype_common.inc diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 4c6d1bbebef..0b8678ef59b 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -323,3 +323,19 @@ set @str1 = 'select ?'; set @str2 = convert(@str1 using ucs2); prepare stmt1 from @str2; execute stmt1 using @ivar; + +# +# Check correct binlogging of UCS2 user variables (BUG#3875) +# +SET TIMESTAMP=10000; +create table t2 (c char(30)) charset=ucs2; +set @v=convert('abc' using ucs2); +reset master; +insert into t2 values (@v); +show binlog events from 79; +# more important than SHOW BINLOG EVENTS, mysqlbinlog (where we +# absolutely need variables names to be quoted and strings to be +# escaped). +--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR +--exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001 +drop table t2; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index c75b1dee63c..42031be8f3c 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -660,3 +660,9 @@ create table t2 select concat(a,_utf8'') as a, concat(b,_utf8'')as b from t1; show create table t2; drop table t2; drop table t1; + +# +# Bug #6787 LIKE not working properly with _ and utf8 data +# +select 'c' like '\_' as want0; + diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index 5f60445d765..0bf7187865d 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -29,12 +29,34 @@ drop table t1; # (This assumes a block size of 1024) # -create table t1 (a bigint not null, primary key (a,a,a,a,a,a,a,a,a,a)); -insert into t1 values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23); +create table t1 ( + a bigint not null, + b bigint not null default 0, + c bigint not null default 0, + d bigint not null default 0, + e bigint not null default 0, + f bigint not null default 0, + g bigint not null default 0, + h bigint not null default 0, + i bigint not null default 0, + j bigint not null default 0, + primary key (a,b,c,d,e,f,g,h,i,j)); +insert into t1 (a) values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23); delete from t1 where a=26; drop table t1; -create table t1 (a bigint not null, primary key (a,a,a,a,a,a,a,a,a,a)); -insert into t1 values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23),(27); +create table t1 ( + a bigint not null, + b bigint not null default 0, + c bigint not null default 0, + d bigint not null default 0, + e bigint not null default 0, + f bigint not null default 0, + g bigint not null default 0, + h bigint not null default 0, + i bigint not null default 0, + j bigint not null default 0, + primary key (a,b,c,d,e,f,g,h,i,j)); +insert into t1 (a) values (2),(4),(6),(8),(10),(12),(14),(16),(18),(20),(22),(24),(26),(23),(27); delete from t1 where a=27; drop table t1; diff --git a/mysql-test/t/flush_block_commit.test b/mysql-test/t/flush_block_commit.test index 3d13086f517..ac14b7b98bc 100644 --- a/mysql-test/t/flush_block_commit.test +++ b/mysql-test/t/flush_block_commit.test @@ -48,5 +48,19 @@ reap; connection con3; reap; unlock tables; + +# BUG#6732 FLUSH TABLES WITH READ LOCK + COMMIT hangs later FLUSH TABLES +# WITH READ LOCK + +connection con2; +commit; # unlock InnoDB row locks to allow insertions connection con1; +begin; +insert into t1 values(10); +flush tables with read lock; +commit; +unlock tables; +connection con2; +flush tables with read lock; # bug caused hang here +unlock tables; drop table t1; diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 5a2f2d87194..008e965297f 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -98,6 +98,8 @@ select * from t1 where match a against ("+aaa* +bbb*" in boolean mode); select * from t1 where match a against ("+aaa* +bbb1*" in boolean mode); select * from t1 where match a against ("+aaa* +ccc*" in boolean mode); select * from t1 where match a against ("+aaa10 +(bbb*)" in boolean mode); +select * from t1 where match a against ("+(+aaa* +bbb1*)" in boolean mode); +select * from t1 where match a against ("(+aaa* +bbb1*)" in boolean mode); drop table t1; # @@ -295,3 +297,27 @@ insert into t1 (s) values ('p select * from t1 where match(s) against('para' in boolean mode); select * from t1 where match(s) against('par*' in boolean mode); DROP TABLE t1; + +# +# icc -ip bug (ip = interprocedural optimization) +# bug#5528 +# +CREATE TABLE t1 (h text, FULLTEXT (h)); +INSERT INTO t1 VALUES ('Jesses Hasse Ling and his syncopators of Swing'); +REPAIR TABLE t1; +select count(*) from t1; +drop table t1; + +# +# bug#6784 +# mi_flush_bulk_insert (on dup key error in mi_write) +# was mangling info->dupp_key_pos +# + +create table t1 (a int primary key, b text, fulltext(b)); +create table t2 (a int, b text); +insert t1 values (1, "aaaa"), (2, "bbbb"); +insert t2 values (10, "aaaa"), (2, "cccc"); +replace t1 select * from t2; +drop table t1, t2; + diff --git a/mysql-test/t/func_compress.test b/mysql-test/t/func_compress.test index 7b70289d2c0..f46589e9e0e 100644 --- a/mysql-test/t/func_compress.test +++ b/mysql-test/t/func_compress.test @@ -38,7 +38,10 @@ drop table t1; # # Bug #5497: a problem with large strings +# note that when LOW_MEMORY is set the "test" below is meaningless # set @@max_allowed_packet=1048576*100; -select compress(repeat('aaaaaaaaaa', 10000000)) is null; +--replace_result "''" XXX "'1'" XXX +eval select compress(repeat('aaaaaaaaaa', IF('$LOW_MEMORY', 10, 10000000))) is null; + diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 8d8779e9d1b..79d6112e6de 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -383,6 +383,17 @@ insert into t1 values ('a'),('b'),('c'); select coercibility(max(a)) from t1; drop table t1; +# +# Bug #6658 MAX(column) returns incorrect coercibility +# +create table t1 (a char character set latin2); +insert into t1 values ('a'),('b'); +select charset(max(a)), coercibility(max(a)), + charset(min(a)), coercibility(min(a)) from t1; +create table t2 select max(a),min(a) from t1; +show create table t2; +drop table t2,t1; + # # aggregate functions on static tables # diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 67192c55ef9..b9e592fc5d9 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -229,6 +229,13 @@ select @a:=FROM_UNIXTIME(1); select unix_timestamp(@a); select unix_timestamp('1969-12-01 19:00:01'); +# +# Test for bug #6439 "unix_timestamp() function returns wrong datetime +# values for too big argument". It should return error instead. +# +select from_unixtime(0); +select from_unixtime(2145916800); + # # Test types from + INTERVAL # diff --git a/mysql-test/t/heap.test b/mysql-test/t/heap.test index e1776245d9e..2eff36f3317 100644 --- a/mysql-test/t/heap.test +++ b/mysql-test/t/heap.test @@ -174,3 +174,14 @@ CREATE TABLE t1 (a INT NOT NULL, B INT, KEY(B)) ENGINE=HEAP; INSERT INTO t1 VALUES(1,1), (1,NULL); SELECT * FROM t1 WHERE B is not null; DROP TABLE t1; + +# +# Bug #6748 +# heap_rfirst() doesn't work (and never did!) +# +CREATE TABLE t1 (pseudo char(35) PRIMARY KEY, date int(10) unsigned NOT NULL) ENGINE=HEAP; +INSERT INTO t1 VALUES ('massecot',1101106491),('altec',1101106492),('stitch+',1101106304),('Seb Corgan',1101106305),('beerfilou',1101106263),('flaker',1101106529),('joce8',5),('M4vrick',1101106418),('gabay008',1101106525),('Vamp irX',1101106291),('ZoomZip',1101106546),('rip666',1101106502),('CBP ',1101106397),('guezpard',1101106496); +DELETE FROM t1 WHERE date<1101106546; +SELECT * FROM t1; +DROP TABLE t1; + diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index a452f79f949..cf7be4f882c 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1158,3 +1158,25 @@ show status like "binlog_cache_use"; show status like "binlog_cache_disk_use"; drop table t1; + +# +# Bug #6126: Duplicate columns in keys gives misleading error message +# +--error 1060 +create table t1 (c char(10), index (c,c)) engine=innodb; +--error 1060 +create table t1 (c1 char(10), c2 char(10), index (c1,c2,c1)) engine=innodb; +--error 1060 +create table t1 (c1 char(10), c2 char(10), index (c1,c1,c2)) engine=innodb; +--error 1060 +create table t1 (c1 char(10), c2 char(10), index (c2,c1,c1)) engine=innodb; +create table t1 (c1 char(10), c2 char(10)) engine=innodb; +--error 1060 +alter table t1 add key (c1,c1); +--error 1060 +alter table t1 add key (c2,c1,c1); +--error 1060 +alter table t1 add key (c1,c2,c1); +--error 1060 +alter table t1 add key (c1,c1,c2); +drop table t1; diff --git a/mysql-test/t/key.test b/mysql-test/t/key.test index 5ee2f68ab83..a0a291fdf3c 100644 --- a/mysql-test/t/key.test +++ b/mysql-test/t/key.test @@ -297,3 +297,26 @@ drop table t1; --error 1105 create table t1 (c char(10), index (c(0))); + +# +# Bug #6126: Duplicate columns in keys should fail +# Bug #6252: (dup) +# +--error 1060 +create table t1 (c char(10), index (c,c)); +--error 1060 +create table t1 (c1 char(10), c2 char(10), index (c1,c2,c1)); +--error 1060 +create table t1 (c1 char(10), c2 char(10), index (c1,c1,c2)); +--error 1060 +create table t1 (c1 char(10), c2 char(10), index (c2,c1,c1)); +create table t1 (c1 char(10), c2 char(10)); +--error 1060 +alter table t1 add key (c1,c1); +--error 1060 +alter table t1 add key (c2,c1,c1); +--error 1060 +alter table t1 add key (c1,c2,c1); +--error 1060 +alter table t1 add key (c1,c1,c2); +drop table t1; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index f9081e8769b..c8ed7910b76 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -498,11 +498,12 @@ alter table t1 disable keys; show keys from t1; create table t2 (a int); let $i=1000; +set @@rand_seed1=31415926,@@rand_seed2=2718281828; --disable_query_log while ($i) { dec $i; - eval insert t2 values (rand()*100000); + insert t2 values (rand()*100000); } --enable_query_log insert t1 select * from t2; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 89b3739f955..295658f21a8 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -127,3 +127,13 @@ insert into t1 values (1),(2),(3); --exec rm $MYSQL_TEST_DIR/var/tmp/t1.sql --exec rm $MYSQL_TEST_DIR/var/tmp/t1.txt drop table t1; + +# +# Bug #6101: create database problem +# + +--exec $MYSQL_DUMP --skip-comments --databases test + +create database mysqldump_test_db character set latin2 collate latin2_bin; +--exec $MYSQL_DUMP --skip-comments --databases mysqldump_test_db; +drop database mysqldump_test_db; diff --git a/mysql-test/t/ndb_autodiscover.test b/mysql-test/t/ndb_autodiscover.test index fd7fe0e60d8..6551732adba 100644 --- a/mysql-test/t/ndb_autodiscover.test +++ b/mysql-test/t/ndb_autodiscover.test @@ -199,7 +199,7 @@ insert into t4 values (1, "Automatic"); select * from t4; # Remove the table from NDB -system exec $NDB_TOOLS_DIR/ndb_drop_table -d test t4 > /dev/null ; +system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t4 > /dev/null ; # # Test that correct error is returned @@ -230,7 +230,7 @@ select * from t4; flush tables; # Remove the table from NDB -system exec $NDB_TOOLS_DIR/ndb_drop_table -d test t4 > /dev/null ; +system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t4 > /dev/null ; SHOW TABLES; @@ -264,8 +264,8 @@ insert into t8 values (8, "myisam table 8"); insert into t9 values (9); # Remove t3, t5 from NDB -system exec $NDB_TOOLS_DIR/ndb_drop_table -d test t3 > /dev/null ; -system exec $NDB_TOOLS_DIR/ndb_drop_table -d test t5 > /dev/null ; +system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t3 > /dev/null ; +system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t5 > /dev/null ; # Remove t6, t7 from disk system rm var/master-data/test/t6.frm > /dev/null ; system rm var/master-data/test/t7.frm > /dev/null ; @@ -306,8 +306,8 @@ insert into t8 values (8, "myisam table 8"); insert into t9 values (9); # Remove t3, t5 from NDB -system exec $NDB_TOOLS_DIR/ndb_drop_table -d test t3 > /dev/null ; -system exec $NDB_TOOLS_DIR/ndb_drop_table -d test t5 > /dev/null ; +system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t3 > /dev/null ; +system exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test t5 > /dev/null ; # Remove t6, t7 from disk system rm var/master-data/test/t6.frm > /dev/null ; system rm var/master-data/test/t7.frm > /dev/null ; @@ -479,4 +479,4 @@ create table t10 ( insert into t10 values (1, 'kalle'); ---exec $NDB_TOOLS_DIR/ndb_drop_table -d test `$NDB_TOOLS_DIR/ndb_show_tables | grep BLOB` > /dev/null 2>&1 || true +--exec $NDB_TOOLS_DIR/ndb_drop_table --no-defaults -d test `$NDB_TOOLS_DIR/ndb_show_tables --no-defaults | grep BLOB` > /dev/null 2>&1 || true diff --git a/mysql-test/t/ndb_charset.test b/mysql-test/t/ndb_charset.test index b9f28ed0faf..f1ec0485e12 100644 --- a/mysql-test/t/ndb_charset.test +++ b/mysql-test/t/ndb_charset.test @@ -86,9 +86,9 @@ create table t1 ( # ok insert into t1 values(1, 'aAa'); # fail ---error 1169 +--error 1062 insert into t1 values(2, 'aaa'); ---error 1169 +--error 1062 insert into t1 values(3, 'AAA'); # 1 select * from t1 order by p; diff --git a/mysql-test/t/ndb_grant.later b/mysql-test/t/ndb_grant.later new file mode 100644 index 00000000000..d3899d9972f --- /dev/null +++ b/mysql-test/t/ndb_grant.later @@ -0,0 +1,374 @@ +-- source include/have_ndb.inc +# Test of GRANT commands + +# Cleanup +--disable_warnings +drop table if exists t1; +--enable_warnings + +SET NAMES binary; + +# +# Alter mysql system tables to ndb +# make sure you alter all back in the end +# +use mysql; +alter table columns_priv engine=ndb; +alter table db engine=ndb; +alter table func engine=ndb; +alter table help_category engine=ndb; +alter table help_keyword engine=ndb; +alter table help_relation engine=ndb; +alter table help_topic engine=ndb; +alter table host engine=ndb; +alter table tables_priv engine=ndb; +alter table time_zone engine=ndb; +alter table time_zone_leap_second engine=ndb; +alter table time_zone_name engine=ndb; +alter table time_zone_transition engine=ndb; +alter table time_zone_transition_type engine=ndb; +alter table user engine=ndb; +use test; + +# +# Test that SSL options works properly +# +delete from mysql.user where user='mysqltest_1'; +delete from mysql.db where user='mysqltest_1'; +flush privileges; +begin; +grant select on mysqltest.* to mysqltest_1@localhost require cipher "EDH-RSA-DES-CBC3-SHA"; +commit; +show grants for mysqltest_1@localhost; +begin; +grant delete on mysqltest.* to mysqltest_1@localhost; +commit; +select * from mysql.user where user="mysqltest_1"; +show grants for mysqltest_1@localhost; +begin; +revoke delete on mysqltest.* from mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +begin; +grant select on mysqltest.* to mysqltest_1@localhost require NONE; +commit; +show grants for mysqltest_1@localhost; +begin; +grant USAGE on mysqltest.* to mysqltest_1@localhost require cipher "EDH-RSA-DES-CBC3-SHA" AND SUBJECT "testsubject" ISSUER "MySQL AB"; +commit; +show grants for mysqltest_1@localhost; +begin; +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +flush privileges; + +# +# Test that the new db privileges are stored/retrieved correctly +# + +begin; +grant CREATE TEMPORARY TABLES, LOCK TABLES on mysqltest.* to mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +flush privileges; +show grants for mysqltest_1@localhost; +begin; +revoke CREATE TEMPORARY TABLES on mysqltest.* from mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +begin; +grant ALL PRIVILEGES on mysqltest.* to mysqltest_1@localhost with GRANT OPTION; +commit; +flush privileges; +show grants for mysqltest_1@localhost; +begin; +revoke LOCK TABLES, ALTER on mysqltest.* from mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +begin; +revoke all privileges on mysqltest.* from mysqltest_1@localhost; +commit; +delete from mysql.user where user='mysqltest_1'; +flush privileges; +begin; +grant usage on test.* to mysqltest_1@localhost with grant option; +commit; +show grants for mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +delete from mysql.db where user='mysqltest_1'; +delete from mysql.tables_priv where user='mysqltest_1'; +delete from mysql.columns_priv where user='mysqltest_1'; +flush privileges; +--error 1141 +show grants for mysqltest_1@localhost; + +# +# Test what happens when you have same table and colum level grants +# + +create table t1 (a int); +begin; +GRANT select,update,insert on t1 to mysqltest_1@localhost; +GRANT select (a), update (a),insert(a), references(a) on t1 to mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1"; +begin; +REVOKE select (a), update on t1 from mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +begin; +REVOKE select,update,insert,insert (a) on t1 from mysqltest_1@localhost; +commit; +show grants for mysqltest_1@localhost; +begin; +GRANT select,references on t1 to mysqltest_1@localhost; +commit; +select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1"; +begin; +grant all on test.* to mysqltest_3@localhost with grant option; +revoke all on test.* from mysqltest_3@localhost; +commit; +show grants for mysqltest_3@localhost; +begin; +revoke grant option on test.* from mysqltest_3@localhost; +commit; +show grants for mysqltest_3@localhost; +begin; +grant all on test.t1 to mysqltest_2@localhost with grant option; +revoke all on test.t1 from mysqltest_2@localhost; +commit; +show grants for mysqltest_2@localhost; +begin; +revoke grant option on test.t1 from mysqltest_2@localhost; +commit; +show grants for mysqltest_2@localhost; +delete from mysql.user where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +delete from mysql.db where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +delete from mysql.tables_priv where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +delete from mysql.columns_priv where user='mysqltest_1' or user="mysqltest_2" or user="mysqltest_3"; +flush privileges; +drop table t1; + +# +# Test some error conditions +# +begin; +--error 1221 +GRANT FILE on mysqltest.* to mysqltest_1@localhost; +commit; +select 1; -- To test that the previous command didn't cause problems + +# +# Bug#6123: GRANT USAGE inserts useless Db row +# +create database mysqltest1; +begin; +grant usage on mysqltest1.* to test6123 identified by 'magic123'; +commit; +select host,db,user,select_priv,insert_priv from mysql.db where db="mysqltest1"; +delete from mysql.user where user='test6123'; +drop database mysqltest1; + +# +# Test for 'drop user', 'revoke privileges, grant' +# + +create table t1 (a int); +begin; +grant ALL PRIVILEGES on *.* to drop_user2@localhost with GRANT OPTION; +commit; +show grants for drop_user2@localhost; +begin; +revoke all privileges, grant option from drop_user2@localhost; +commit; +drop user drop_user2@localhost; + +begin; +grant ALL PRIVILEGES on *.* to drop_user@localhost with GRANT OPTION; +grant ALL PRIVILEGES on test.* to drop_user@localhost with GRANT OPTION; +grant select(a) on test.t1 to drop_user@localhost; +commit; +show grants for drop_user@localhost; + +# +# Bug3086 +# +set sql_mode=ansi_quotes; +show grants for drop_user@localhost; +set sql_mode=default; + +set sql_quote_show_create=0; +show grants for drop_user@localhost; +set sql_mode="ansi_quotes"; +show grants for drop_user@localhost; +set sql_quote_show_create=1; +show grants for drop_user@localhost; +set sql_mode=""; +show grants for drop_user@localhost; + +revoke all privileges, grant option from drop_user@localhost; +show grants for drop_user@localhost; +drop user drop_user@localhost; +begin; +--error 1269 +revoke all privileges, grant option from drop_user@localhost; +commit; + +begin; +grant select(a) on test.t1 to drop_user1@localhost; +commit; +flush privileges; +begin; +grant select on test.t1 to drop_user2@localhost; +grant select on test.* to drop_user3@localhost; +grant select on *.* to drop_user4@localhost; +commit; +--error 1268 +drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, +drop_user4@localhost; +begin; +revoke all privileges, grant option from drop_user1@localhost, drop_user2@localhost, +drop_user3@localhost, drop_user4@localhost; +commit; +drop user drop_user1@localhost, drop_user2@localhost, drop_user3@localhost, +drop_user4@localhost; +drop table t1; +begin; +grant usage on *.* to mysqltest_1@localhost identified by "password"; +grant select, update, insert on test.* to mysqltest@localhost; +commit; +show grants for mysqltest_1@localhost; +drop user mysqltest_1@localhost; + +# +# Bug #3403 Wrong encodin in SHOW GRANTS output +# +SET NAMES koi8r; +CREATE DATABASE ÂÄ; +USE ÂÄ; +CREATE TABLE ÔÁÂ (ËÏÌ int); + +begin; +GRANT SELECT ON ÂÄ.* TO ÀÚÅÒ@localhost; +commit; +SHOW GRANTS FOR ÀÚÅÒ@localhost; +begin; +REVOKE SELECT ON ÂÄ.* FROM ÀÚÅÒ@localhost; +commit; + +begin; +GRANT SELECT ON ÂÄ.ÔÁÂ TO ÀÚÅÒ@localhost; +commit; +SHOW GRANTS FOR ÀÚÅÒ@localhost; +begin; +REVOKE SELECT ON ÂÄ.ÔÁÂ FROM ÀÚÅÒ@localhost; +commit; + +begin; +GRANT SELECT (ËÏÌ) ON ÂÄ.ÔÁÂ TO ÀÚÅÒ@localhost; +commit; +SHOW GRANTS FOR ÀÚÅÒ@localhost; +begin; +REVOKE SELECT (ËÏÌ) ON ÂÄ.ÔÁÂ FROM ÀÚÅÒ@localhost; +commit; + +DROP DATABASE ÂÄ; +SET NAMES latin1; + +# +# Bug #5831: REVOKE ALL PRIVILEGES, GRANT OPTION does not revoke everything +# +USE test; +CREATE TABLE t1 (a int ); +CREATE TABLE t2 LIKE t1; +CREATE TABLE t3 LIKE t1; +CREATE TABLE t4 LIKE t1; +CREATE TABLE t5 LIKE t1; +CREATE TABLE t6 LIKE t1; +CREATE TABLE t7 LIKE t1; +CREATE TABLE t8 LIKE t1; +CREATE TABLE t9 LIKE t1; +CREATE TABLE t10 LIKE t1; +CREATE DATABASE testdb1; +CREATE DATABASE testdb2; +CREATE DATABASE testdb3; +CREATE DATABASE testdb4; +CREATE DATABASE testdb5; +CREATE DATABASE testdb6; +CREATE DATABASE testdb7; +CREATE DATABASE testdb8; +CREATE DATABASE testdb9; +CREATE DATABASE testdb10; +begin; +GRANT ALL ON testdb1.* TO testuser@localhost; +GRANT ALL ON testdb2.* TO testuser@localhost; +GRANT ALL ON testdb3.* TO testuser@localhost; +GRANT ALL ON testdb4.* TO testuser@localhost; +GRANT ALL ON testdb5.* TO testuser@localhost; +GRANT ALL ON testdb6.* TO testuser@localhost; +GRANT ALL ON testdb7.* TO testuser@localhost; +GRANT ALL ON testdb8.* TO testuser@localhost; +GRANT ALL ON testdb9.* TO testuser@localhost; +GRANT ALL ON testdb10.* TO testuser@localhost; +GRANT SELECT ON test.t1 TO testuser@localhost; +GRANT SELECT ON test.t2 TO testuser@localhost; +GRANT SELECT ON test.t3 TO testuser@localhost; +GRANT SELECT ON test.t4 TO testuser@localhost; +GRANT SELECT ON test.t5 TO testuser@localhost; +GRANT SELECT ON test.t6 TO testuser@localhost; +GRANT SELECT ON test.t7 TO testuser@localhost; +GRANT SELECT ON test.t8 TO testuser@localhost; +GRANT SELECT ON test.t9 TO testuser@localhost; +GRANT SELECT ON test.t10 TO testuser@localhost; +GRANT SELECT (a) ON test.t1 TO testuser@localhost; +GRANT SELECT (a) ON test.t2 TO testuser@localhost; +GRANT SELECT (a) ON test.t3 TO testuser@localhost; +GRANT SELECT (a) ON test.t4 TO testuser@localhost; +GRANT SELECT (a) ON test.t5 TO testuser@localhost; +GRANT SELECT (a) ON test.t6 TO testuser@localhost; +GRANT SELECT (a) ON test.t7 TO testuser@localhost; +GRANT SELECT (a) ON test.t8 TO testuser@localhost; +GRANT SELECT (a) ON test.t9 TO testuser@localhost; +GRANT SELECT (a) ON test.t10 TO testuser@localhost; +commit; +begin; +REVOKE ALL PRIVILEGES, GRANT OPTION FROM testuser@localhost; +commit; +SHOW GRANTS FOR testuser@localhost; +DROP USER testuser@localhost; +DROP TABLE t1,t2,t3,t4,t5,t6,t7,t8,t9,t10; +DROP DATABASE testdb1; +DROP DATABASE testdb2; +DROP DATABASE testdb3; +DROP DATABASE testdb4; +DROP DATABASE testdb5; +DROP DATABASE testdb6; +DROP DATABASE testdb7; +DROP DATABASE testdb8; +DROP DATABASE testdb9; +DROP DATABASE testdb10; + +# +# Alter mysql system tables back to myisam +# +use mysql; +alter table columns_priv engine=myisam; +alter table db engine=myisam; +alter table func engine=myisam; +alter table help_category engine=myisam; +alter table help_keyword engine=myisam; +alter table help_relation engine=myisam; +alter table help_topic engine=myisam; +alter table host engine=myisam; +alter table tables_priv engine=myisam; +alter table time_zone engine=myisam; +alter table time_zone_leap_second engine=myisam; +alter table time_zone_name engine=myisam; +alter table time_zone_transition engine=myisam; +alter table time_zone_transition_type engine=myisam; +alter table user engine=myisam; +use test; +flush privileges; diff --git a/mysql-test/t/ndb_index_unique.test b/mysql-test/t/ndb_index_unique.test index 4a0c689bafb..f235d1ffc30 100644 --- a/mysql-test/t/ndb_index_unique.test +++ b/mysql-test/t/ndb_index_unique.test @@ -21,7 +21,7 @@ select * from t1 where b = 4 order by b; insert into t1 values(7,8,3); select * from t1 where b = 4 order by a; --- error 1169 +-- error 1062 insert into t1 values(8, 2, 3); select * from t1 order by a; delete from t1 where a = 1; @@ -30,6 +30,32 @@ select * from t1 order by a; drop table t1; +# +# Indexing NULL values +# + +CREATE TABLE t1 ( + a int unsigned NOT NULL PRIMARY KEY, + b int unsigned, + c int unsigned, + UNIQUE bc(b,c) +) engine = ndb; + +insert into t1 values(1,1,1),(2,NULL,2),(3,NULL,NULL),(4,4,NULL); +select * from t1 use index (bc) where b IS NULL order by a; + +select * from t1 use index (bc)order by a; +select * from t1 use index (bc) order by a; +select * from t1 use index (PRIMARY) where b IS NULL order by a; +select * from t1 use index (bc) where b IS NULL order by a; +select * from t1 use index (bc) where b IS NULL and c IS NULL order by a; +select * from t1 use index (bc) where b IS NULL and c = 2 order by a; +select * from t1 use index (bc) where b < 4 order by a; +select * from t1 use index (bc) where b IS NOT NULL order by a; +-- error 1062 +insert into t1 values(5,1,1); +drop table t1; + # # Show use of UNIQUE USING HASH indexes @@ -49,7 +75,7 @@ select * from t2 where c = 6; insert into t2 values(7,8,3); select * from t2 where b = 4 order by a; --- error 1169 +-- error 1062 insert into t2 values(8, 2, 3); select * from t2 order by a; delete from t2 where a = 1; @@ -58,6 +84,14 @@ select * from t2 order by a; drop table t2; +-- error 1121 +CREATE TABLE t2 ( + a int unsigned NOT NULL PRIMARY KEY, + b int unsigned not null, + c int unsigned, + UNIQUE USING HASH (b, c) +) engine=ndbcluster; + # # Show use of PRIMARY KEY USING HASH indexes # @@ -92,7 +126,7 @@ insert into t1 values (-1,NULL), (0,0), (1,NULL),(2,2),(3,NULL),(4,4); select * from t1 order by pk; ---error 1169 +--error 1062 insert into t1 values (5,0); select * from t1 order by pk; delete from t1 where a = 0; @@ -111,7 +145,7 @@ insert into t2 values (-1,1,17,NULL),(0,NULL,18,NULL),(1,3,19,'abc'); select * from t2 order by pk; ---error 1169 +--error 1062 insert into t2 values(2,3,19,'abc'); select * from t2 order by pk; delete from t2 where c IS NOT NULL; @@ -231,4 +265,24 @@ select * from t4 where rid = 2 order by cid; drop table t1,t2,t3,t4,t5,t6,t7; +# test null in indexes +CREATE TABLE t1 ( + a int unsigned NOT NULL PRIMARY KEY, + b int unsigned, + c int unsigned, + UNIQUE bc(b,c) ) engine = ndb; + +insert into t1 values(1,1,1),(2,NULL,2),(3,NULL,NULL),(4,4,NULL); +select * from t1 where b=1 and c=1; +select * from t1 where b is null and c is null; +select * from t1 where b is null and c = 2; +select * from t1 where b = 4 and c is null; +create table t8 as +select * from t1 where (b = 1 and c = 1) + or (b is null and c is null) + or (b is null and c = 2) + or (b = 4 and c is null); +select * from t8 order by a; +select * from t1 order by a; +drop table t1, t8; diff --git a/mysql-test/t/ndb_insert.test b/mysql-test/t/ndb_insert.test index c3da4641014..611df3d84e9 100644 --- a/mysql-test/t/ndb_insert.test +++ b/mysql-test/t/ndb_insert.test @@ -564,23 +564,37 @@ select count(*) from t1; --error 1062 insert into t1 select * from t1 where b < 10 order by pk1; +DELETE FROM t1 WHERE pk1=2; begin; ---error 1031 -INSERT IGNORE INTO t1 VALUES(1,2,3); -commit; +INSERT IGNORE INTO t1 VALUES(1,2,3),(2,3,4); +select * from t1 where pk1 < 3 order by pk1; +rollback; + +INSERT IGNORE INTO t1 VALUES(1,2,3),(2,3,4); +select * from t1 where pk1 < 3 order by pk1; + +REPLACE INTO t1 values(1, 78, 3); select * from t1 where pk1=1; ---error 1031 -INSERT IGNORE INTO t1 VALUES(1,2,3); -select * from t1 where pk1=1; +INSERT INTO t1 VALUES(1,1,1),(3,4,5) ON DUPLICATE KEY UPDATE b=79; +select * from t1 where pk1 < 4 order by pk1; -REPLACE INTO t1 values(1, 2, 3); -select * from t1 where pk1=1; +INSERT INTO t1 VALUES(1,1,1),(3,4,5) ON DUPLICATE KEY UPDATE b=pk1+c; +select * from t1 where pk1 < 4 order by pk1; ---error 1031 -INSERT INTO t1 VALUES(1,1,1) ON DUPLICATE KEY UPDATE b=79; -select * from t1 where pk1=1; +DELETE FROM t1 WHERE pk1 = 2 OR pk1 = 4 OR pk1 = 6; +INSERT INTO t1 VALUES(1,1,1),(2,2,17),(3,4,5) ON DUPLICATE KEY UPDATE pk1=b; +select * from t1 where pk1 = b and b != c order by pk1; + +# The following test case currently does not work +#DELETE FROM t1; +#CREATE UNIQUE INDEX bi ON t1(b); +#INSERT INTO t1 VALUES +#(1,1,1),(2,2,2),(3,3,3),(4,4,4),(5,5,5), +#(6,6,6),(7,7,7),(8,8,8),(9,9,9),(10,10,10); +#INSERT INTO t1 VALUES(0,1,0),(21,21,21) ON DUPLICATE KEY UPDATE pk1=b+10,c=b+10; +#select * from t1 order by pk1; DROP TABLE t1; diff --git a/mysql-test/t/openssl_1.test b/mysql-test/t/openssl_1.test index 39612f680f3..912c9fb9bec 100644 --- a/mysql-test/t/openssl_1.test +++ b/mysql-test/t/openssl_1.test @@ -9,9 +9,9 @@ create table t1(f1 int); insert into t1 values (5); grant select on test.* to ssl_user1@localhost require SSL; -grant select on test.* to ssl_user2@localhost require cipher "EDH-RSA-DES-CBC3-SHA"; -grant select on test.* to ssl_user3@localhost require cipher "EDH-RSA-DES-CBC3-SHA" AND SUBJECT "/C=SE/L=Uppsala/O=MySQL AB/CN=MySQL Client/Email=abstract.mysql.developer@mysql.com"; -grant select on test.* to ssl_user4@localhost require cipher "EDH-RSA-DES-CBC3-SHA" AND SUBJECT "/C=SE/L=Uppsala/O=MySQL AB/CN=MySQL Client/Email=abstract.mysql.developer@mysql.com" ISSUER "/C=SE/L=Uppsala/O=MySQL AB/CN=Abstract MySQL Developer/Email=abstract.mysql.developer@mysql.com"; +grant select on test.* to ssl_user2@localhost require cipher "DHE-RSA-AES256-SHA"; +grant select on test.* to ssl_user3@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "/C=SE/L=Uppsala/O=MySQL AB/CN=MySQL Client/Email=abstract.mysql.developer@mysql.com"; +grant select on test.* to ssl_user4@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "/C=SE/L=Uppsala/O=MySQL AB/CN=MySQL Client/Email=abstract.mysql.developer@mysql.com" ISSUER "/C=SE/L=Uppsala/O=MySQL AB/CN=Abstract MySQL Developer/Email=abstract.mysql.developer@mysql.com"; flush privileges; connect (con1,localhost,ssl_user1,,); connect (con2,localhost,ssl_user2,,); diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 2b3e961fc28..7fe88ad0ddc 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -458,3 +458,17 @@ EXECUTE stmt; DEALLOCATE PREPARE stmt; DROP TABLE t1; +# +# Bug#6297 "prepared statement, wrong handling of IS NULL" +# Test that placeholders work with IS NULL/IS NOT NULL clauses. +# +prepare stmt from "select ? is null, ? is not null, ?"; +select @no_such_var is null, @no_such_var is not null, @no_such_var; +execute stmt using @no_such_var, @no_such_var, @no_such_var; +set @var='abc'; +select @var is null, @var is not null, @var; +execute stmt using @var, @var, @var; +set @var=null; +select @var is null, @var is not null, @var; +execute stmt using @var, @var, @var; + diff --git a/mysql-test/t/ps_7ndb.test b/mysql-test/t/ps_7ndb.test index 22370a7f3ac..b558f2f3c21 100644 --- a/mysql-test/t/ps_7ndb.test +++ b/mysql-test/t/ps_7ndb.test @@ -12,365 +12,11 @@ use test; -- source include/have_ndb.inc let $type= 'NDB' ; ---disable_warnings -drop table if exists t1, t9 ; ---enable_warnings -eval create table t1 -( - a int not null, b varchar(30), - primary key(a) -) engine = $type ; - ---disable_warnings -drop table if exists t9; ---enable_warnings -# The used table type doesn't support BLOB/TEXT columns. -# (The server would send error 1163 .) -# So we use char(100) instead. -eval create table t9 -( - c1 tinyint not null, c2 smallint, c3 mediumint, c4 int, - c5 integer, c6 bigint, c7 float, c8 double, - c9 double precision, c10 real, c11 decimal(7, 4), c12 numeric(8, 4), - c13 date, c14 datetime, c15 timestamp(14), c16 time, - c17 year, c18 bit, c19 bool, c20 char, - c21 char(10), c22 varchar(30), c23 char(100), c24 char(100), - c25 char(100), c26 char(100), c27 char(100), c28 char(100), - c29 char(100), c30 char(100), c31 enum('one', 'two', 'three'), - c32 set('monday', 'tuesday', 'wednesday'), - primary key(c1) -) engine = $type ; +-- source include/ps_create.inc -- source include/ps_renew.inc -- source include/ps_query.inc -# The following line is deactivated, because the ndb storage engine is not able -# to do primary key column updates . -#-- source include/ps_modify.inc -# let's include all statements which will work ---disable_query_log -select '------ delete tests ------' as test_sequence ; ---enable_query_log ---source include/ps_renew.inc - -## delete without parameter -prepare stmt1 from 'delete from t1 where a=2' ; -execute stmt1; -select a,b from t1 where a=2 order by b; -# delete with row not found -execute stmt1; - -## delete with one parameter in the where clause -insert into t1 values(0,NULL); -set @arg00=NULL; -prepare stmt1 from 'delete from t1 where b=?' ; -execute stmt1 using @arg00; -select a,b from t1 where b is NULL ; -set @arg00='one'; -execute stmt1 using @arg00; -select a,b from t1 where b=@arg00; - -## truncate a table ---error 1295 -prepare stmt1 from 'truncate table t1' ; - - ---disable_query_log -select '------ update tests ------' as test_sequence ; ---enable_query_log ---source include/ps_renew.inc - -## update without parameter -prepare stmt1 from 'update t1 set b=''a=two'' where a=2' ; -execute stmt1; -select a,b from t1 where a=2; -# dummy update -execute stmt1; -select a,b from t1 where a=2; - -## update with one parameter in the set clause -set @arg00=NULL; -prepare stmt1 from 'update t1 set b=? where a=2' ; -execute stmt1 using @arg00; -select a,b from t1 where a=2; -set @arg00='two'; -execute stmt1 using @arg00; -select a,b from t1 where a=2; - -## update with one parameter in the where cause -set @arg00=2; -prepare stmt1 from 'update t1 set b=NULL where a=?' ; -execute stmt1 using @arg00; -select a,b from t1 where a=@arg00; -update t1 set b='two' where a=@arg00; -# row not found in update -set @arg00=2000; -execute stmt1 using @arg00; -select a,b from t1 where a=@arg00; - -## update on primary key column (two parameters) -set @arg00=2; -set @arg01=22; -prepare stmt1 from 'update t1 set a=? where a=?' ; -# dummy update -execute stmt1 using @arg00, @arg00; -select a,b from t1 where a=@arg00; -# deactivated primary key column update -# execute stmt1 using @arg01, @arg00; -select a,b from t1 where a=@arg01; -execute stmt1 using @arg00, @arg01; -select a,b from t1 where a=@arg00; -set @arg00=NULL; -set @arg01=2; -# deactivated primary key column update -# execute stmt1 using @arg00, @arg01; -select a,b from t1 order by a; -set @arg00=0; -execute stmt1 using @arg01, @arg00; -select a,b from t1 order by a; - -## update with subquery and several parameters -set @arg00=23; -set @arg01='two'; -set @arg02=2; -set @arg03='two'; -set @arg04=2; ---disable_warnings -drop table if exists t2; ---enable_warnings -# t2 will be of table type 'MYISAM' -create table t2 as select a,b from t1 ; -prepare stmt1 from 'update t1 set a=? where b=? - and a in (select ? from t2 - where b = ? or a = ?)'; ---enable_info -# deactivated primary key column update -# execute stmt1 using @arg00, @arg01, @arg02, @arg03, @arg04 ; ---disable_info -select a,b from t1 where a = @arg00 ; -prepare stmt1 from 'update t1 set a=? where b=? - and a not in (select ? from t2 - where b = ? or a = ?)'; ---enable_info -execute stmt1 using @arg04, @arg01, @arg02, @arg03, @arg00 ; ---disable_info -select a,b from t1 order by a; -drop table t2 ; -# t2 is now of table type '$type' -# The test battery for table type 'MERGE' gets here only a 'MYISAM' table -eval create table t2 -( - a int not null, b varchar(30), - primary key(a) -) engine = $type ; -insert into t2(a,b) select a, b from t1 ; -prepare stmt1 from 'update t1 set a=? where b=? - and a in (select ? from t2 - where b = ? or a = ?)'; ---enable_info -# deactivated primary key column update -# execute stmt1 using @arg00, @arg01, @arg02, @arg03, @arg04 ; ---disable_info -select a,b from t1 where a = @arg00 ; -prepare stmt1 from 'update t1 set a=? where b=? - and a not in (select ? from t2 - where b = ? or a = ?)'; ---enable_info -execute stmt1 using @arg04, @arg01, @arg02, @arg03, @arg00 ; ---disable_info -select a,b from t1 order by a ; -drop table t2 ; - -## update with parameters in limit -set @arg00=1; -prepare stmt1 from 'update t1 set b=''bla'' -where a=2 -limit 1'; -execute stmt1 ; -select a,b from t1 where b = 'bla' ; -# currently (May 2004, Version 4.1) it is impossible --- error 1064 -prepare stmt1 from 'update t1 set b=''bla'' -where a=2 -limit ?'; - ---disable_query_log -select '------ insert tests ------' as test_sequence ; ---enable_query_log ---source include/ps_renew.inc - -## insert without parameter -prepare stmt1 from 'insert into t1 values(5, ''five'' )'; -execute stmt1; -select a,b from t1 where a = 5; - -## insert with one parameter in values part -set @arg00='six' ; -prepare stmt1 from 'insert into t1 values(6, ? )'; -execute stmt1 using @arg00; -select a,b from t1 where b = @arg00; -# the second insert fails, because the first column is primary key ---error 1062 -execute stmt1 using @arg00; -set @arg00=NULL ; -prepare stmt1 from 'insert into t1 values(0, ? )'; -execute stmt1 using @arg00; -select a,b from t1 where b is NULL; - -## insert with two parameter in values part -set @arg00=8 ; -set @arg01='eight' ; -prepare stmt1 from 'insert into t1 values(?, ? )'; -execute stmt1 using @arg00, @arg01 ; -select a,b from t1 where b = @arg01; -# cases derived from client_test.c: test_null() -set @NULL= null ; -set @arg00= 'abc' ; -# execute must fail, because first column is primary key (-> not null) ---error 1048 -execute stmt1 using @NULL, @NULL ; ---error 1048 -execute stmt1 using @NULL, @NULL ; ---error 1048 -execute stmt1 using @NULL, @arg00 ; ---error 1048 -execute stmt1 using @NULL, @arg00 ; -let $1 = 2; -while ($1) -{ - eval set @arg01= 10000 + $1 ; - execute stmt1 using @arg01, @arg00 ; - dec $1; -} -select * from t1 where a > 10000 order by a ; -delete from t1 where a > 10000 ; -let $1 = 2; -while ($1) -{ - eval set @arg01= 10000 + $1 ; - execute stmt1 using @arg01, @NULL ; - dec $1; -} -select * from t1 where a > 10000 order by a ; -delete from t1 where a > 10000 ; -let $1 = 10; -while ($1) -{ - eval set @arg01= 10000 + $1 ; - execute stmt1 using @arg01, @arg01 ; - dec $1; -} -select * from t1 where a > 10000 order by a ; -delete from t1 where a > 10000 ; - - -## insert with two rows in values part -set @arg00=81 ; -set @arg01='8-1' ; -set @arg02=82 ; -set @arg03='8-2' ; -prepare stmt1 from 'insert into t1 values(?,?),(?,?)'; -execute stmt1 using @arg00, @arg01, @arg02, @arg03 ; -select a,b from t1 where a in (@arg00,@arg02) order by a ; - -## insert with two parameter in the set part -set @arg00=9 ; -set @arg01='nine' ; -prepare stmt1 from 'insert into t1 set a=?, b=? '; -execute stmt1 using @arg00, @arg01 ; -select a,b from t1 where a = @arg00 ; - -## insert with parameters in the ON DUPLICATE KEY part -set @arg00=6 ; -set @arg01=1 ; -prepare stmt1 from 'insert into t1 set a=?, b=''sechs'' - on duplicate key update a=a + ?, b=concat(b,''modified'') '; -# There is no primary key collision, so there will be no key column update -# If a key column update would be necessary occurs BUG#4312 -# deactivated, activate when BUG#4312: is solved -# execute stmt1 using @arg00, @arg01; -select * from t1 order by a; -set @arg00=81 ; -set @arg01=1 ; -# deactivated, activate when BUG#4312: is solved -# execute stmt1 using @arg00, @arg01; - -## insert, autoincrement column and ' SELECT LAST_INSERT_ID() ' -# cases derived from client_test.c: test_bug3117() ---disable_warnings -drop table if exists t2 ; ---enable_warnings -# The test battery for table type 'MERGE' gets here only a 'MYISAM' table -eval create table t2 (id int auto_increment primary key) -ENGINE= $type ; -prepare stmt1 from ' select last_insert_id() ' ; -insert into t2 values (NULL) ; -execute stmt1 ; -insert into t2 values (NULL) ; -execute stmt1 ; -drop table t2 ; - -## many parameters -set @1000=1000 ; -set @x1000_2="x1000_2" ; -set @x1000_3="x1000_3" ; - -set @x1000="x1000" ; -set @1100=1100 ; -set @x1100="x1100" ; -set @100=100 ; -set @updated="updated" ; -insert into t1 values(1000,'x1000_1') ; -# deactivated, activate when BUG#4312: is solved -# insert into t1 values(@1000,@x1000_2),(@1000,@x1000_3) -# on duplicate key update a = a + @100, b = concat(b,@updated) ; -select a,b from t1 where a >= 1000 order by a ; -delete from t1 where a >= 1000 ; -insert into t1 values(1000,'x1000_1') ; -prepare stmt1 from ' insert into t1 values(?,?),(?,?) - on duplicate key update a = a + ?, b = concat(b,?) '; -# deactivated, activate when BUG#4312: is solved -# execute stmt1 using @1000, @x1000_2, @1000, @x1000_3, @100, @updated ; -select a,b from t1 where a >= 1000 order by a ; -delete from t1 where a >= 1000 ; -insert into t1 values(1000,'x1000_1') ; -# deactivated, activate when BUG#4312: is solved -# execute stmt1 using @1000, @x1000_2, @1100, @x1000_3, @100, @updated ; -select a,b from t1 where a >= 1000 order by a ; -delete from t1 where a >= 1000 ; - -## replace -prepare stmt1 from ' replace into t1 (a,b) select 100, ''hundred'' '; ---error 1031 - -## multi table statements ---disable_query_log -select '------ multi table tests ------' as test_sequence ; ---enable_query_log -# cases derived from client_test.c: test_multi -delete from t1 ; -delete from t9 ; -insert into t1(a,b) values (1, 'one'), (2, 'two'), (3, 'three') ; -insert into t9 (c1,c21) - values (1, 'one'), (2, 'two'), (3, 'three') ; -prepare stmt_delete from " delete t1, t9 - from t1, t9 where t1.a=t9.c1 and t1.b='updated' "; -prepare stmt_update from " update t1, t9 - set t1.b='updated', t9.c21='updated' - where t1.a=t9.c1 and t1.a=? "; -prepare stmt_select1 from " select a, b from t1 order by a" ; -prepare stmt_select2 from " select c1, c21 from t9 order by c1" ; -set @arg00= 1 ; -let $1= 3 ; -while ($1) -{ - execute stmt_update using @arg00 ; - execute stmt_delete ; - execute stmt_select1 ; - execute stmt_select2 ; - set @arg00= @arg00 + 1 ; - dec $1 ; -} - +-- source include/ps_modify.inc -- source include/ps_modify1.inc -- source include/ps_conv.inc diff --git a/mysql-test/t/rpl000001.test b/mysql-test/t/rpl000001.test index 2e0ba2fff25..835af92186f 100644 --- a/mysql-test/t/rpl000001.test +++ b/mysql-test/t/rpl000001.test @@ -98,7 +98,7 @@ wait_for_slave_to_stop; # The following test can't be done because the result of Pos will differ # on different computers -# --replace_result 9306 9999 3334 9999 3335 9999 +# --replace_result $MASTER_MYPORT MASTER_PORT # show slave status; set global sql_slave_skip_counter=1; diff --git a/mysql-test/t/rpl_start_stop_slave.test b/mysql-test/t/rpl_start_stop_slave.test new file mode 100644 index 00000000000..903ff204194 --- /dev/null +++ b/mysql-test/t/rpl_start_stop_slave.test @@ -0,0 +1,34 @@ +source include/master-slave.inc; + +# +# Bug#6148 () +# +connection slave; +stop slave; + +# Let the master do lots of insertions +connection master; +create table t1(n int); +let $1=5000; +disable_query_log; +while ($1) +{ + eval insert into t1 values($1); + dec $1; +} +enable_query_log; +save_master_pos; + +connection slave; +start slave; +sleep 1; +stop slave io_thread; +start slave io_thread; +sync_with_master; + +connection master; +drop table t1; +save_master_pos; + +connection slave; +sync_with_master; diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test index 3b36ba6bfb2..9bbd26a9c1c 100644 --- a/mysql-test/t/select.test +++ b/mysql-test/t/select.test @@ -1898,6 +1898,20 @@ select * from t1,t2 where t1.s = t2.s; select * from t2,t3 where t2.s = t3.s; drop table t1, t2, t3; +# +# Bug #3759 +# Both queries should produce identical plans and results. +# +create table t1 (a integer, b integer, index(a), index(b)); +create table t2 (c integer, d integer, index(c), index(d)); +insert into t1 values (1,2), (2,2), (3,2), (4,2); +insert into t2 values (1,3), (2,3), (3,4), (4,4); +explain select * from t1 left join t2 on a=c where d in (4); +select * from t1 left join t2 on a=c where d in (4); +explain select * from t1 left join t2 on a=c where d = 4; +select * from t1 left join t2 on a=c where d = 4; +drop table t1, t2; + # # Covering index is mentioned in EXPLAIN output for const tables (bug #5333) # @@ -1915,6 +1929,4 @@ INSERT INTO t1 VALUES (3,'c'); EXPLAIN SELECT i FROM t1 WHERE i=1; -EXPLAIN SELECT i FROM t1 WHERE i=1; - DROP TABLE t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 18f7d96b236..b76f5140e78 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1283,6 +1283,25 @@ SELECT b.sc FROM (SELECT (SELECT a.access FROM t1 a WHERE a.map = op.map AND a.s SELECT b.ac FROM (SELECT (SELECT a.access FROM t1 a WHERE a.map = op.map AND a.slave = op.pid AND a.master = 1) ac FROM t2 op WHERE op.id = 12 AND op.map = 0) b; drop tables t1,t2; +# +# Test for bug #6462. "Same request on same data returns different +# results." a.k.a. "Proper cleanup of subqueries is missing for +# SET and DO statements". +# +create table t1 (a int not null, b int not null, c int, primary key (a,b)); +insert into t1 values (1,1,1), (2,2,2), (3,3,3); +set @b:= 0; +# Let us check that subquery will use covering index +explain select sum(a) from t1 where b > @b; +# This should not crash -debug server due to failing assertion +set @a:= (select sum(a) from t1 where b > @b); +# And this should not falsely report index usage +explain select a from t1 where c=2; +# Same for DO statement +do @a:= (select sum(a) from t1 where b > @b); +explain select a from t1 where c=2; +drop table t1; + # # Subselect in non-select command just after connection # diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test index b67fa7a552d..f70193ddbe0 100644 --- a/mysql-test/t/type_blob.test +++ b/mysql-test/t/type_blob.test @@ -369,8 +369,8 @@ explain select * from t1 where txt='Chevy' or txt is NULL order by txt; select * from t1 where txt='Chevy' or txt is NULL order by txt; drop table t1; -CREATE TABLE t1 ( i int(11) NOT NULL default '0', c text NOT NULL, PRIMARY KEY (i), KEY (c(1),c(1))); -INSERT t1 VALUES (1,''),(2,''),(3,'asdfh'),(4,''); +CREATE TABLE t1 ( i int(11) NOT NULL default '0', c text NOT NULL, d varchar(1) NOT NULL DEFAULT ' ', PRIMARY KEY (i), KEY (c(1),d)); +INSERT t1 (i, c) VALUES (1,''),(2,''),(3,'asdfh'),(4,''); select max(i) from t1 where c = ''; drop table t1; diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test index 47866058524..04e4a73554a 100644 --- a/mysql-test/t/type_datetime.test +++ b/mysql-test/t/type_datetime.test @@ -77,10 +77,13 @@ drop table t1; # warnings (for both strings and numbers) # create table t1 (t datetime); -insert into t1 values (20030102030460),(20030102036301),(20030102240401),(20030132030401),(20031302030460); +insert into t1 values (20030102030460),(20030102036301),(20030102240401), + (20030132030401),(20031302030401),(100001202030401); select * from t1; delete from t1; -insert into t1 values ("20030102030460"),("20030102036301"),("20030102240401"),("20030132030401"),("20031302030460"); +insert into t1 values + ("2003-01-02 03:04:60"),("2003-01-02 03:63:01"),("2003-01-02 24:04:01"), + ("2003-01-32 03:04:01"),("2003-13-02 03:04:01"), ("10000-12-02 03:04:00"); select * from t1; delete from t1; insert into t1 values ("0000-00-00 00:00:00 some trailer"),("2003-01-01 00:00:00 some trailer"); diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 36027e8c4cb..468a88b83db 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -652,5 +652,11 @@ create table t1 as (select b collate latin1_german1_ci from t2); show create table t1; drop table t1; +create table t1 as +(select a from t2) union +(select b from t2) union +(select 'c' collate latin1_german1_ci from t2); +show create table t1; +drop table t1; drop table t2; diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index 3816af42c55..d985be05b94 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -108,16 +108,13 @@ SET @`a b`='hello'; INSERT INTO t1 VALUES(@`a b`); set @var1= "';aaa"; insert into t1 values (@var1); -create table t2 (c char(30)) charset=ucs2; -set @v=convert('abc' using ucs2); -insert into t2 values (@v); show binlog events from 79; # more important than SHOW BINLOG EVENTS, mysqlbinlog (where we # absolutely need variables names to be quoted and strings to be # escaped). --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR --exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001 -drop table t1, t2; +drop table t1; # diff --git a/mysys/charset.c b/mysys/charset.c index 1388fc40c6d..cb2379f8723 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -228,6 +228,7 @@ static int add_collation(CHARSET_INFO *cs) } else { + uchar *sort_order= all_charsets[cs->number]->sort_order; simple_cs_init_functions(all_charsets[cs->number]); new->mbminlen= 1; new->mbmaxlen= 1; @@ -236,6 +237,16 @@ static int add_collation(CHARSET_INFO *cs) all_charsets[cs->number]->state |= MY_CS_LOADED; } all_charsets[cs->number]->state|= MY_CS_AVAILABLE; + + /* + Check if case sensitive sort order: A < a < B. + We need MY_CS_FLAG for regex library, and for + case sensitivity flag for 5.0 client protocol, + to support isCaseSensitive() method in JDBC driver + */ + if (sort_order && sort_order['A'] < sort_order['a'] && + sort_order['a'] < sort_order['B']) + all_charsets[cs->number]->state|= MY_CS_CSSORT; } } else diff --git a/mysys/mf_keycaches.c b/mysys/mf_keycaches.c index 20465f3d23b..8bf203e249f 100644 --- a/mysys/mf_keycaches.c +++ b/mysys/mf_keycaches.c @@ -309,7 +309,7 @@ void multi_keycache_free(void) Get a key cache to be used for a specific table. SYNOPSIS - multi_key_cache_get() + multi_key_cache_search() key key to find (usually table path) uint length Length of key. diff --git a/ndb/docs/wl2077.txt b/ndb/docs/wl2077.txt new file mode 100644 index 00000000000..5a77c18aa2a --- /dev/null +++ b/ndb/docs/wl2077.txt @@ -0,0 +1,35 @@ + +100' * (select 1 from T1 (1M rows) where key = rand()); +1 host, 1 ndbd, api co-hosted +results in 1000 rows / sec + + wo/reset bounds w/ rb +4.1-read committed a) 4.9 b) 7.4 +4.1-read hold lock c) 4.7 d) 6.7 + +wl2077-read committed 6.4 (+30%) 10.8 (+45%) +wl2077-read hold lock 4.6 (-1%) 6.7 (+ 0%) + +-- Comparision e) +serial pk: 10.9' +batched (1000): 59' +serial uniq index: 8.4' +batched (1000): 33' +index range (1000): 186' + +---- + +load) testScanPerf -c 1 -d 1 T1 +a) testScanPerf -s 100000 -c 0 -d 0 -a 1 -l 0 -r 2 -q 0 T1 +b) testScanPerf -s 100000 -c 0 -d 0 -a 1 -l 0 -r 2 -q 1 T1 +c) testScanPerf -s 100000 -c 0 -d 0 -a 1 -l 1 -r 2 -q 0 T1 +d) testScanPerf -s 100000 -c 0 -d 0 -a 1 -l 1 -r 2 -q 1 T1 +e) testReadPerf -i 25 -c 0 -d 0 T1 + +--- music join 1db-co 2db-co + +4.1 13s 14s +4.1 wo/ blobs 1.7s 3.2s + +wl2077 12s 14s +wl2077 wo/ blobs 1.2s (-30%) 2.5s (-22%) diff --git a/ndb/include/Makefile.am b/ndb/include/Makefile.am index 7b3f80b5560..61f55cf9d61 100644 --- a/ndb/include/Makefile.am +++ b/ndb/include/Makefile.am @@ -29,13 +29,13 @@ ndbapi/ndberror.h mgmapiinclude_HEADERS = \ mgmapi/mgmapi.h \ -mgmapi/mgmapi_debug.h +mgmapi/mgmapi_debug.h \ +mgmapi/mgmapi_config_parameters.h \ +mgmapi/mgmapi_config_parameters_debug.h noinst_HEADERS = \ ndb_global.h \ -ndb_net.h \ -mgmapi/mgmapi_config_parameters.h \ -mgmapi/mgmapi_config_parameters_debug.h +ndb_net.h EXTRA_DIST = debugger editline kernel logger mgmcommon \ portlib transporter util diff --git a/ndb/include/kernel/signaldata/ArbitSignalData.hpp b/ndb/include/kernel/signaldata/ArbitSignalData.hpp index f255b8dcbbe..34b73644a13 100644 --- a/ndb/include/kernel/signaldata/ArbitSignalData.hpp +++ b/ndb/include/kernel/signaldata/ArbitSignalData.hpp @@ -94,13 +94,14 @@ public: // arbitration result LoseNodes = 41, // lose on ndb node count - WinGroups = 42, // we win, no need for arbitration - LoseGroups = 43, // we lose, missing node group - Partitioning = 44, // possible network partitioning - WinChoose = 45, // positive reply - LoseChoose = 46, // negative reply - LoseNorun = 47, // arbitrator required but not running - LoseNocfg = 48, // arbitrator required but none configured + WinNodes = 42, // win on ndb node count + WinGroups = 43, // we win, no need for arbitration + LoseGroups = 44, // we lose, missing node group + Partitioning = 45, // possible network partitioning + WinChoose = 46, // positive reply + LoseChoose = 47, // negative reply + LoseNorun = 48, // arbitrator required but not running + LoseNocfg = 49, // arbitrator required but none configured // general error codes ErrTicket = 91, // invalid arbitrator-ticket diff --git a/ndb/include/kernel/signaldata/BackupImpl.hpp b/ndb/include/kernel/signaldata/BackupImpl.hpp index 1872069daa7..2ac91570aad 100644 --- a/ndb/include/kernel/signaldata/BackupImpl.hpp +++ b/ndb/include/kernel/signaldata/BackupImpl.hpp @@ -78,15 +78,15 @@ public: STATIC_CONST( SignalLength = 3 ); enum ErrorCode { - Undefined = 200, - FailedToAllocateBuffers = 202, - FailedToSetupFsBuffers = 203, - FailedToAllocateTables = 204, - FailedInsertFileHeader = 205, - FailedInsertTableList = 206, - FailedAllocateTableMem = 207, - FailedToAllocateFileRecord = 208, - FailedToAllocateAttributeRecord = 209 + Undefined = 1340, + FailedToAllocateBuffers = 1342, + FailedToSetupFsBuffers = 1343, + FailedToAllocateTables = 1344, + FailedInsertFileHeader = 1345, + FailedInsertTableList = 1346, + FailedAllocateTableMem = 1347, + FailedToAllocateFileRecord = 1348, + FailedToAllocateAttributeRecord = 1349 }; private: Uint32 backupId; diff --git a/ndb/include/kernel/signaldata/BackupSignalData.hpp b/ndb/include/kernel/signaldata/BackupSignalData.hpp index 42eb8464d53..fb018026a49 100644 --- a/ndb/include/kernel/signaldata/BackupSignalData.hpp +++ b/ndb/include/kernel/signaldata/BackupSignalData.hpp @@ -119,12 +119,13 @@ public: private: enum ErrorCodes { - Undefined = 100, - IAmNotMaster = 101, - OutOfBackupRecord = 102, - OutOfResources = 103, - SequenceFailure = 104, - BackupDefinitionNotImplemented = 105 + Undefined = 1300, + IAmNotMaster = 1301, + OutOfBackupRecord = 1302, + OutOfResources = 1303, + SequenceFailure = 1304, + BackupDefinitionNotImplemented = 1305, + CannotBackupDiskless = 1306 }; Uint32 senderData; Uint32 errorCode; @@ -232,13 +233,13 @@ public: STATIC_CONST( SignalLength = 3 ); enum RequestType { - ClientAbort = 1, - BackupComplete = 2, - BackupFailure = 3, // General backup failure coordinator -> slave - LogBufferFull = 4, // slave -> coordinator - FileOrScanError = 5, // slave -> coordinator - BackupFailureDueToNodeFail = 6, // slave -> slave - OkToClean = 7 // master -> slave + ClientAbort = 1321, + BackupComplete = 1322, + BackupFailure = 1323, // General backup failure coordinator -> slave + LogBufferFull = 1324, // slave -> coordinator + FileOrScanError = 1325, // slave -> coordinator + BackupFailureDueToNodeFail = 1326, // slave -> slave + OkToClean = 1327 // master -> slave }; private: Uint32 requestType; diff --git a/ndb/include/kernel/signaldata/TupFrag.hpp b/ndb/include/kernel/signaldata/TupFrag.hpp index c1e861c5dff..c132b19c50a 100644 --- a/ndb/include/kernel/signaldata/TupFrag.hpp +++ b/ndb/include/kernel/signaldata/TupFrag.hpp @@ -132,9 +132,10 @@ class TupAddAttrConf { friend class Dblqh; friend class Dbtup; public: - STATIC_CONST( SignalLength = 1 ); + STATIC_CONST( SignalLength = 2 ); private: Uint32 userPtr; + Uint32 lastAttr; // bool: got last attr and closed frag op }; class TupAddAttrRef { @@ -171,9 +172,10 @@ class TuxAddAttrConf { friend class Dblqh; friend class Dbtux; public: - STATIC_CONST( SignalLength = 1 ); + STATIC_CONST( SignalLength = 2 ); private: Uint32 userPtr; + Uint32 lastAttr; // bool: got last attr and closed frag op }; class TuxAddAttrRef { diff --git a/ndb/include/mgmapi/mgmapi.h b/ndb/include/mgmapi/mgmapi.h index f1ef357421b..dc4f745adb2 100644 --- a/ndb/include/mgmapi/mgmapi.h +++ b/ndb/include/mgmapi/mgmapi.h @@ -356,11 +356,27 @@ extern "C" { /** * Create a handle to a management server * - * @return A management handle
- * or NULL if no management handle could be created. + * @return A management handle
+ * or NULL if no management handle could be created. */ NdbMgmHandle ndb_mgm_create_handle(); + /** + * Set connecst string to management server + * + * @param handle Management handle + * @param connect_string Connect string to the management server, + * + * @return -1 on error. + */ + int ndb_mgm_set_connectstring(NdbMgmHandle handle, + const char *connect_string); + + int ndb_mgm_get_configuration_nodeid(NdbMgmHandle handle); + int ndb_mgm_get_connected_port(NdbMgmHandle handle); + const char *ndb_mgm_get_connected_host(NdbMgmHandle handle); + const char *ndb_mgm_get_connectstring(NdbMgmHandle handle, char *buf, int buf_sz); + /** * Destroy a management server handle * @@ -378,11 +394,10 @@ extern "C" { * Connect to a management server * * @param handle Management handle. - * @param mgmsrv Hostname and port of the management server, - * "hostname:port". * @return -1 on error. */ - int ndb_mgm_connect(NdbMgmHandle handle, const char * mgmsrv); + int ndb_mgm_connect(NdbMgmHandle handle, int no_retries, + int retry_delay_in_seconds, int verbose); /** * Disconnect from a management server @@ -709,9 +724,7 @@ extern "C" { void ndb_mgm_destroy_configuration(struct ndb_mgm_configuration *); int ndb_mgm_alloc_nodeid(NdbMgmHandle handle, - unsigned version, - unsigned *pnodeid, - int nodetype); + unsigned version, int nodetype); /** * Config iterator */ @@ -734,6 +747,7 @@ extern "C" { int ndb_mgm_get_string_parameter(const ndb_mgm_configuration_iterator*, int param, const char ** value); int ndb_mgm_purge_stale_sessions(NdbMgmHandle handle, char **); + int ndb_mgm_check_connection(NdbMgmHandle handle); #ifdef __cplusplus } #endif diff --git a/ndb/include/mgmcommon/ConfigRetriever.hpp b/ndb/include/mgmcommon/ConfigRetriever.hpp index 6c32255e921..8461658748e 100644 --- a/ndb/include/mgmcommon/ConfigRetriever.hpp +++ b/ndb/include/mgmcommon/ConfigRetriever.hpp @@ -20,7 +20,6 @@ #include #include #include -#include /** * @class ConfigRetriever @@ -28,10 +27,11 @@ */ class ConfigRetriever { public: - ConfigRetriever(LocalConfig &local_config, Uint32 version, Uint32 nodeType); + ConfigRetriever(const char * _connect_string, + Uint32 version, Uint32 nodeType); ~ConfigRetriever(); - int do_connect(int exit_on_connect_failure= false); + int do_connect(int no_retries, int retry_delay_in_seconds, int verbose); /** * Get configuration for current node. @@ -46,12 +46,14 @@ public: */ struct ndb_mgm_configuration * getConfig(); + void resetError(); + int hasError(); const char * getErrorString(); /** * @return Node id of this node (as stated in local config or connectString) */ - Uint32 allocNodeId(); + Uint32 allocNodeId(int no_retries, int retry_delay_in_seconds); /** * Get config using socket @@ -68,22 +70,27 @@ public: */ bool verifyConfig(const struct ndb_mgm_configuration *, Uint32 nodeid); - Uint32 get_mgmd_port() const {return m_mgmd_port;}; - const char *get_mgmd_host() const {return m_mgmd_host;}; + Uint32 get_mgmd_port() const; + const char *get_mgmd_host() const; + const char *get_connectstring(char *buf, int buf_sz) const; + + Uint32 get_configuration_nodeid() const; private: BaseString errorString; enum ErrorType { - CR_ERROR = 0, - CR_RETRY = 1 + CR_NO_ERROR = 0, + CR_ERROR = 1, + CR_RETRY = 2 }; ErrorType latestErrorType; void setError(ErrorType, const char * errorMsg); - struct LocalConfig& _localConfig; - Uint32 _ownNodeId; + Uint32 _ownNodeId; + /* Uint32 m_mgmd_port; const char *m_mgmd_host; + */ Uint32 m_version; Uint32 m_node_type; diff --git a/ndb/include/ndbapi/NdbConnection.hpp b/ndb/include/ndbapi/NdbConnection.hpp index 7af5d27b922..256199dced7 100644 --- a/ndb/include/ndbapi/NdbConnection.hpp +++ b/ndb/include/ndbapi/NdbConnection.hpp @@ -607,8 +607,8 @@ private: NdbOperation* theLastExecOpInList; // Last executing operation in list. - NdbOperation* theCompletedFirstOp; // First operation in completed - // operation list. + NdbOperation* theCompletedFirstOp; // First & last operation in completed + NdbOperation* theCompletedLastOp; // operation list. Uint32 theNoOfOpSent; // How many operations have been sent Uint32 theNoOfOpCompleted; // How many operations have completed diff --git a/ndb/include/ndbapi/NdbIndexScanOperation.hpp b/ndb/include/ndbapi/NdbIndexScanOperation.hpp index 66b3fc9d43b..a3388f62f58 100644 --- a/ndb/include/ndbapi/NdbIndexScanOperation.hpp +++ b/ndb/include/ndbapi/NdbIndexScanOperation.hpp @@ -113,7 +113,7 @@ public: * Reset bounds and put operation in list that will be * sent on next execute */ - int reset_bounds(); + int reset_bounds(bool forceSend = false); bool getSorted() const { return m_ordered; } private: @@ -127,8 +127,8 @@ private: virtual NdbRecAttr* getValue_impl(const NdbColumnImpl*, char*); void fix_get_values(); - int next_result_ordered(bool fetchAllowed); - int send_next_scan_ordered(Uint32 idx); + int next_result_ordered(bool fetchAllowed, bool forceSend = false); + int send_next_scan_ordered(Uint32 idx, bool forceSend = false); int compare(Uint32 key, Uint32 cols, const NdbReceiver*, const NdbReceiver*); Uint32 m_sort_columns; diff --git a/ndb/include/ndbapi/NdbResultSet.hpp b/ndb/include/ndbapi/NdbResultSet.hpp index 478daf8aad2..dc0288a380c 100644 --- a/ndb/include/ndbapi/NdbResultSet.hpp +++ b/ndb/include/ndbapi/NdbResultSet.hpp @@ -89,17 +89,17 @@ public: * - 1: if there are no more tuples to scan. * - 2: if there are no more cached records in NdbApi */ - int nextResult(bool fetchAllowed = true); + int nextResult(bool fetchAllowed = true, bool forceSend = false); /** * Close result set (scan) */ - void close(); + void close(bool forceSend = false); /** * Restart */ - int restart(); + int restart(bool forceSend = false); /** * Transfer scan operation to an updating transaction. Use this function diff --git a/ndb/include/ndbapi/NdbScanOperation.hpp b/ndb/include/ndbapi/NdbScanOperation.hpp index 2e4d173ac75..f25f9405033 100644 --- a/ndb/include/ndbapi/NdbScanOperation.hpp +++ b/ndb/include/ndbapi/NdbScanOperation.hpp @@ -90,11 +90,11 @@ protected: NdbScanOperation(Ndb* aNdb); virtual ~NdbScanOperation(); - int nextResult(bool fetchAllowed = true); + int nextResult(bool fetchAllowed = true, bool forceSend = false); virtual void release(); - void closeScan(); - int close_impl(class TransporterFacade*); + void closeScan(bool forceSend = false); + int close_impl(class TransporterFacade*, bool forceSend = false); // Overloaded methods from NdbCursorOperation int executeCursor(int ProcessorId); @@ -103,6 +103,7 @@ protected: int init(const NdbTableImpl* tab, NdbConnection* myConnection); int prepareSend(Uint32 TC_ConnectPtr, Uint64 TransactionId); int doSend(int ProcessorId); + void checkForceSend(bool forceSend); virtual void setErrorCode(int aErrorCode); virtual void setErrorCodeAbort(int aErrorCode); @@ -127,18 +128,27 @@ protected: NdbReceiver** m_receivers; // All receivers Uint32* m_prepared_receivers; // These are to be sent - + + /** + * owned by API/user thread + */ Uint32 m_current_api_receiver; Uint32 m_api_receivers_count; NdbReceiver** m_api_receivers; // These are currently used by api + /** + * owned by receiver thread + */ Uint32 m_conf_receivers_count; // NOTE needs mutex to access NdbReceiver** m_conf_receivers; // receive thread puts them here + /** + * owned by receiver thread + */ Uint32 m_sent_receivers_count; // NOTE needs mutex to access NdbReceiver** m_sent_receivers; // receive thread puts them here - int send_next_scan(Uint32 cnt, bool close); + int send_next_scan(Uint32 cnt, bool close, bool forceSend = false); void receiver_delivered(NdbReceiver*); void receiver_completed(NdbReceiver*); void execCLOSE_SCAN_REP(); @@ -148,7 +158,7 @@ protected: Uint32 m_ordered; - int restart(); + int restart(bool forceSend = false); }; inline diff --git a/ndb/include/ndbapi/ndb_cluster_connection.hpp b/ndb/include/ndbapi/ndb_cluster_connection.hpp index f8e6f25ce73..6fa25caf5d0 100644 --- a/ndb/include/ndbapi/ndb_cluster_connection.hpp +++ b/ndb/include/ndbapi/ndb_cluster_connection.hpp @@ -19,7 +19,6 @@ #define CLUSTER_CONNECTION_HPP class TransporterFacade; -class LocalConfig; class ConfigRetriever; class NdbThread; @@ -31,14 +30,15 @@ class Ndb_cluster_connection { public: Ndb_cluster_connection(const char * connect_string = 0); ~Ndb_cluster_connection(); - int connect(int reconnect= 0); + int connect(int no_retries, int retry_delay_in_seconds, int verbose); int start_connect_thread(int (*connect_callback)(void)= 0); + const char *get_connectstring(char *buf, int buf_sz) const; + int get_connected_port() const; + const char *get_connected_host() const; private: friend void* run_ndb_cluster_connection_connect_thread(void*); void connect_thread(); - char *m_connect_string; TransporterFacade *m_facade; - LocalConfig *m_local_config; ConfigRetriever *m_config_retriever; NdbThread *m_connect_thread; int (*m_connect_callback)(void); diff --git a/ndb/include/ndbapi/ndberror.h b/ndb/include/ndbapi/ndberror.h index 5c2d85b82a6..ceb1881a4cc 100644 --- a/ndb/include/ndbapi/ndberror.h +++ b/ndb/include/ndbapi/ndberror.h @@ -46,7 +46,8 @@ typedef enum ndberror_cl_internal_error = 12, ndberror_cl_function_not_implemented = 13, ndberror_cl_unknown_error_code = 14, - ndberror_cl_node_shutdown = 15 + ndberror_cl_node_shutdown = 15, + ndberror_cl_configuration = 16 } ndberror_classification_enum; diff --git a/ndb/include/util/ndb_opts.h b/ndb/include/util/ndb_opts.h index 6cba9c04449..f7ae3b5489e 100644 --- a/ndb/include/util/ndb_opts.h +++ b/ndb/include/util/ndb_opts.h @@ -32,10 +32,13 @@ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, \ { "version", 'V', "Output version information and exit.", 0, 0, 0, \ GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, \ - { "connect-string", 'c', \ + { "ndb-connectstring", 'c', \ "Set connect string for connecting to ndb_mgmd. " \ - "=\"host=[;nodeid=]\". " \ - "Overides specifying entries in NDB_CONNECTSTRING and config file", \ + "Syntax: \"[nodeid=;][host=][:]\". " \ + "Overides specifying entries in NDB_CONNECTSTRING and Ndb.cfg", \ + (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0, \ + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\ + { "connect-string", 'c', "same as --ndb-connectstring",\ (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0, \ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 } #else @@ -46,11 +49,14 @@ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, \ { "version", 'V', "Output version information and exit.", 0, 0, 0, \ GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, \ - { "connect-string", 'c', \ + { "ndb-connectstring", 'c', \ "Set connect string for connecting to ndb_mgmd. " \ - "=\"host=[;nodeid=]\". " \ - "Overides specifying entries in NDB_CONNECTSTRING and config file", \ + "Syntax: \"[nodeid=;][host=][:]\". " \ + "Overides specifying entries in NDB_CONNECTSTRING and Ndb.cfg", \ (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0, \ + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\ + { "connect-string", 'c', "same as --ndb-connectstring",\ + (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0,\ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 } #endif diff --git a/ndb/src/common/debugger/EventLogger.cpp b/ndb/src/common/debugger/EventLogger.cpp index 8a09be9a0a7..59be0affcb4 100644 --- a/ndb/src/common/debugger/EventLogger.cpp +++ b/ndb/src/common/debugger/EventLogger.cpp @@ -421,6 +421,11 @@ EventLogger::getText(char * m_text, size_t m_text_len, "%sArbitration check lost - less than 1/2 nodes left", theNodeId); break; + case ArbitCode::WinNodes: + BaseString::snprintf(m_text, m_text_len, + "%sArbitration check won - all node groups and more than 1/2 nodes left", + theNodeId); + break; case ArbitCode::WinGroups: BaseString::snprintf(m_text, m_text_len, "%sArbitration check won - node group majority", diff --git a/ndb/src/common/debugger/signaldata/ScanTab.cpp b/ndb/src/common/debugger/signaldata/ScanTab.cpp index 72a4d9f94b9..0755ee0a856 100644 --- a/ndb/src/common/debugger/signaldata/ScanTab.cpp +++ b/ndb/src/common/debugger/signaldata/ScanTab.cpp @@ -30,13 +30,14 @@ printSCANTABREQ(FILE * output, const Uint32 * theData, Uint32 len, Uint16 receiv fprintf(output, " apiConnectPtr: H\'%.8x", sig->apiConnectPtr); fprintf(output, " requestInfo: H\'%.8x:\n", requestInfo); - fprintf(output, " Parallellism: %u, Batch: %u LockMode: %u, Keyinfo: %u Holdlock: %u, RangeScan: %u\n", + fprintf(output, " Parallellism: %u, Batch: %u LockMode: %u, Keyinfo: %u Holdlock: %u, RangeScan: %u ReadCommitted: %u\n", sig->getParallelism(requestInfo), sig->getScanBatch(requestInfo), sig->getLockMode(requestInfo), + sig->getKeyinfoFlag(requestInfo), sig->getHoldLockFlag(requestInfo), sig->getRangeScanFlag(requestInfo), - sig->getKeyinfoFlag(requestInfo)); + sig->getReadCommittedFlag(requestInfo)); Uint32 keyLen = (sig->attrLenKeyLen >> 16); Uint32 attrLen = (sig->attrLenKeyLen & 0xFFFF); diff --git a/ndb/src/common/logger/LogHandler.cpp b/ndb/src/common/logger/LogHandler.cpp index 4fab957fc50..a76cb622878 100644 --- a/ndb/src/common/logger/LogHandler.cpp +++ b/ndb/src/common/logger/LogHandler.cpp @@ -117,10 +117,9 @@ LogHandler::parseParams(const BaseString &_params) { _params.split(v_args, ","); for(size_t i=0; i < v_args.size(); i++) { Vector v_param_value; - - v_args[i].split(v_param_value, "=", 2); - if(v_param_value.size() == 2 && - !setParam(v_param_value[0], v_param_value[1])) + if(v_args[i].split(v_param_value, "=", 2) != 2) + ret = false; + else if (!setParam(v_param_value[0], v_param_value[1])) ret = false; } diff --git a/ndb/src/common/logger/Logger.cpp b/ndb/src/common/logger/Logger.cpp index 00a2fae67bc..f6f70fbeff7 100644 --- a/ndb/src/common/logger/Logger.cpp +++ b/ndb/src/common/logger/Logger.cpp @@ -169,10 +169,13 @@ Logger::addHandler(const BaseString &logstring) { size_t i; Vector logdest; Vectorloghandlers; + DBUG_ENTER("Logger::addHandler"); logstring.split(logdest, ";"); for(i = 0; i < logdest.size(); i++) { + DBUG_PRINT("info",("adding: %s",logdest[i].c_str())); + Vector v_type_args; logdest[i].split(v_type_args, ":", 2); @@ -191,16 +194,16 @@ Logger::addHandler(const BaseString &logstring) { handler = new ConsoleLogHandler(); if(handler == NULL) - return false; + DBUG_RETURN(false); if(!handler->parseParams(params)) - return false; + DBUG_RETURN(false); loghandlers.push_back(handler); } for(i = 0; i < loghandlers.size(); i++) addHandler(loghandlers[i]); - return true; /* @todo handle errors */ + DBUG_RETURN(true); /* @todo handle errors */ } bool diff --git a/ndb/src/common/mgmcommon/ConfigRetriever.cpp b/ndb/src/common/mgmcommon/ConfigRetriever.cpp index a1b979f62d8..744412870f5 100644 --- a/ndb/src/common/mgmcommon/ConfigRetriever.cpp +++ b/ndb/src/common/mgmcommon/ConfigRetriever.cpp @@ -20,7 +20,6 @@ #include #include -#include "LocalConfig.hpp" #include #include @@ -45,90 +44,67 @@ //**************************************************************************** //**************************************************************************** -ConfigRetriever::ConfigRetriever(LocalConfig &local_config, +ConfigRetriever::ConfigRetriever(const char * _connect_string, Uint32 version, Uint32 node_type) - : _localConfig(local_config) { - m_handle= 0; m_version = version; m_node_type = node_type; - _ownNodeId = _localConfig._ownNodeId; + _ownNodeId= 0; + + m_handle= ndb_mgm_create_handle(); + + if (m_handle == 0) { + setError(CR_ERROR, "Unable to allocate mgm handle"); + return; + } + + if (ndb_mgm_set_connectstring(m_handle, _connect_string)) + { + setError(CR_ERROR, ndb_mgm_get_latest_error_desc(m_handle)); + return; + } + resetError(); } -ConfigRetriever::~ConfigRetriever(){ - +ConfigRetriever::~ConfigRetriever() +{ if (m_handle) { ndb_mgm_disconnect(m_handle); ndb_mgm_destroy_handle(&m_handle); } } +Uint32 +ConfigRetriever::get_configuration_nodeid() const +{ + return ndb_mgm_get_configuration_nodeid(m_handle); +} + +Uint32 ConfigRetriever::get_mgmd_port() const +{ + return ndb_mgm_get_connected_port(m_handle); +} + +const char *ConfigRetriever::get_mgmd_host() const +{ + return ndb_mgm_get_connected_host(m_handle); +} + +const char *ConfigRetriever::get_connectstring(char *buf, int buf_sz) const +{ + return ndb_mgm_get_connectstring(m_handle, buf, buf_sz); +} //**************************************************************************** //**************************************************************************** int -ConfigRetriever::do_connect(int exit_on_connect_failure){ - - m_mgmd_port= 0; - m_mgmd_host= 0; - - if(!m_handle) - m_handle= ndb_mgm_create_handle(); - - if (m_handle == 0) { - setError(CR_ERROR, "Unable to allocate mgm handle"); - return -1; - } - - int retry = 1; - int retry_max = 12; // Max number of retry attempts - int retry_interval= 5; // Seconds between each retry - while(retry < retry_max){ - Uint32 type = CR_ERROR; - BaseString tmp; - for (unsigned int i = 0; i<_localConfig.ids.size(); i++){ - MgmtSrvrId * m = &_localConfig.ids[i]; - DBUG_PRINT("info",("trying %s:%d", - m->name.c_str(), - m->port)); - switch(m->type){ - case MgmId_TCP: - tmp.assfmt("%s:%d", m->name.c_str(), m->port); - if (ndb_mgm_connect(m_handle, tmp.c_str()) == 0) { - m_mgmd_port= m->port; - m_mgmd_host= m->name.c_str(); - DBUG_PRINT("info",("connected to ndb_mgmd at %s:%d", - m_mgmd_host, - m_mgmd_port)); - return 0; - } - setError(CR_RETRY, ndb_mgm_get_latest_error_desc(m_handle)); - case MgmId_File: - break; - } - } - if(latestErrorType == CR_RETRY){ - DBUG_PRINT("info",("CR_RETRY")); - if (exit_on_connect_failure) - return 1; - REPORT_WARNING("Failed to retrieve cluster configuration"); - ndbout << "(Cause of failure: " << getErrorString() << ")" << endl; - ndbout << "Attempt " << retry << " of " << retry_max << ". " - << "Trying again in "<< retry_interval <<" seconds..." - << endl << endl; - NdbSleep_SecSleep(retry_interval); - } else { - break; - } - retry++; - } - - ndb_mgm_destroy_handle(&m_handle); - m_handle= 0; - m_mgmd_port= 0; - m_mgmd_host= 0; - return -1; +ConfigRetriever::do_connect(int no_retries, + int retry_delay_in_seconds, int verbose) +{ + return + (ndb_mgm_connect(m_handle,no_retries,retry_delay_in_seconds,verbose)==0) ? + 0 : -1; } //**************************************************************************** @@ -140,22 +116,9 @@ ConfigRetriever::getConfig() { struct ndb_mgm_configuration * p = 0; - if(m_handle != 0){ + if(m_handle != 0) p = getConfig(m_handle); - } else { - for (unsigned int i = 0; i<_localConfig.ids.size(); i++){ - MgmtSrvrId * m = &_localConfig.ids[i]; - switch(m->type){ - case MgmId_File: - p = getConfig(m->name.c_str()); - break; - case MgmId_TCP: - break; - } - if(p) - break; - } - } + if(p == 0) return 0; @@ -227,6 +190,16 @@ ConfigRetriever::setError(ErrorType et, const char * s){ latestErrorType = et; } +void +ConfigRetriever::resetError(){ + setError(CR_NO_ERROR,0); +} + +int +ConfigRetriever::hasError() +{ + return latestErrorType != CR_NO_ERROR; +} const char * ConfigRetriever::getErrorString(){ @@ -341,16 +314,23 @@ ConfigRetriever::verifyConfig(const struct ndb_mgm_configuration * conf, Uint32 } Uint32 -ConfigRetriever::allocNodeId(){ - unsigned nodeid= _ownNodeId; - - if(m_handle != 0){ - int res= ndb_mgm_alloc_nodeid(m_handle, m_version, &nodeid, m_node_type); - if(res != 0) { - setError(CR_ERROR, ndb_mgm_get_latest_error_desc(m_handle)); - return 0; +ConfigRetriever::allocNodeId(int no_retries, int retry_delay_in_seconds) +{ + _ownNodeId= 0; + if(m_handle != 0) + { + while (1) + { + int res= ndb_mgm_alloc_nodeid(m_handle, m_version, m_node_type); + if(res >= 0) + return _ownNodeId= (Uint32)res; + if (no_retries == 0) + break; + no_retries--; + NdbSleep_SecSleep(retry_delay_in_seconds); } - } - - return _ownNodeId= nodeid; + setError(CR_ERROR, ndb_mgm_get_latest_error_desc(m_handle)); + } else + setError(CR_ERROR, "management server handle not initialized"); + return 0; } diff --git a/ndb/src/common/util/NdbSqlUtil.cpp b/ndb/src/common/util/NdbSqlUtil.cpp index 6e4e5919e43..5b2381df50a 100644 --- a/ndb/src/common/util/NdbSqlUtil.cpp +++ b/ndb/src/common/util/NdbSqlUtil.cpp @@ -582,7 +582,7 @@ NdbSqlUtil::usable_in_pk(Uint32 typeId, const void* info) cs->cset != 0 && cs->coll != 0 && cs->coll->strnxfrm != 0 && - cs->strxfrm_multiply == 1; // current limitation + cs->strxfrm_multiply <= 1; // current limitation } break; case Type::Varchar: @@ -618,7 +618,7 @@ NdbSqlUtil::usable_in_ordered_index(Uint32 typeId, const void* info) cs->coll != 0 && cs->coll->strnxfrm != 0 && cs->coll->strnncollsp != 0 && - cs->strxfrm_multiply == 1; // current limitation + cs->strxfrm_multiply <= 1; // current limitation } break; case Type::Varchar: @@ -633,7 +633,7 @@ NdbSqlUtil::usable_in_ordered_index(Uint32 typeId, const void* info) cs->coll != 0 && cs->coll->strnxfrm != 0 && cs->coll->strnncollsp != 0 && - cs->strxfrm_multiply == 1; // current limitation + cs->strxfrm_multiply <= 1; // current limitation } break; default: diff --git a/ndb/src/common/util/version.c b/ndb/src/common/util/version.c index 82acd949c46..f2b3d5bd522 100644 --- a/ndb/src/common/util/version.c +++ b/ndb/src/common/util/version.c @@ -70,7 +70,6 @@ struct NdbUpGradeCompatible { #ifndef TEST_VERSION struct NdbUpGradeCompatible ndbCompatibleTable_full[] = { { MAKE_VERSION(3,5,2), MAKE_VERSION(3,5,1), UG_Exact }, - { MAKE_VERSION(4,1,8), MAKE_VERSION(3,5,4), UG_Exact }, /* Aligned version with MySQL */ { 0, 0, UG_Null } }; diff --git a/ndb/src/kernel/blocks/ERROR_codes.txt b/ndb/src/kernel/blocks/ERROR_codes.txt index 70f11c33cd7..5193d3eae9d 100644 --- a/ndb/src/kernel/blocks/ERROR_codes.txt +++ b/ndb/src/kernel/blocks/ERROR_codes.txt @@ -1,8 +1,8 @@ Next QMGR 1 Next NDBCNTR 1000 Next NDBFS 2000 -Next DBACC 3001 -Next DBTUP 4007 +Next DBACC 3002 +Next DBTUP 4013 Next DBLQH 5042 Next DBDICT 6006 Next DBDIH 7174 @@ -10,7 +10,7 @@ Next DBTC 8035 Next CMVMI 9000 Next BACKUP 10022 Next DBUTIL 11002 -Next DBTUX 12001 +Next DBTUX 12007 Next SUMA 13001 TESTING NODE FAILURE, ARBITRATION @@ -393,6 +393,13 @@ Failed Create Table: -------------------- 7173: Create table failed due to not sufficient number of fragment or replica records. +3001: Fail create 1st fragment +4007 12001: Fail create 1st fragment +4008 12002: Fail create 2nd fragment +4009 12003: Fail create 1st attribute in 1st fragment +4010 12004: Fail create last attribute in 1st fragment +4011 12005: Fail create 1st attribute in 2nd fragment +4012 12006: Fail create last attribute in 2nd fragment Drop Table/Index: ----------------- diff --git a/ndb/src/kernel/blocks/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp index e6fe63d9014..9fc00883792 100644 --- a/ndb/src/kernel/blocks/backup/Backup.cpp +++ b/ndb/src/kernel/blocks/backup/Backup.cpp @@ -863,6 +863,13 @@ Backup::execBACKUP_REQ(Signal* signal) sendBackupRef(senderRef, signal, senderData, BackupRef::IAmNotMaster); return; }//if + + if (m_diskless) + { + sendBackupRef(senderRef, signal, senderData, + BackupRef::CannotBackupDiskless); + return; + } if(dataLen32 != 0) { jam(); diff --git a/ndb/src/kernel/blocks/backup/Backup.hpp b/ndb/src/kernel/blocks/backup/Backup.hpp index 4dc2cd13ae0..fb29cb03b96 100644 --- a/ndb/src/kernel/blocks/backup/Backup.hpp +++ b/ndb/src/kernel/blocks/backup/Backup.hpp @@ -526,6 +526,7 @@ public: NdbNodeBitmask c_aliveNodes; DLList c_backups; Config c_defaults; + Uint32 m_diskless; STATIC_CONST(NO_OF_PAGES_META_FILE = 2); diff --git a/ndb/src/kernel/blocks/backup/BackupInit.cpp b/ndb/src/kernel/blocks/backup/BackupInit.cpp index 8daad05558b..d98541f2ea8 100644 --- a/ndb/src/kernel/blocks/backup/BackupInit.cpp +++ b/ndb/src/kernel/blocks/backup/BackupInit.cpp @@ -42,6 +42,7 @@ Backup::Backup(const Configuration & conf) : ndbrequire(p != 0); Uint32 noBackups = 0, noTables = 0, noAttribs = 0; + ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_DISCLESS, &m_diskless)); ndb_mgm_get_int_parameter(p, CFG_DB_PARALLEL_BACKUPS, &noBackups); ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_NO_TABLES, &noTables)); ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DB_NO_ATTRIBUTES, &noAttribs)); diff --git a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp index c275e5382f7..5c7cc597672 100644 --- a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp +++ b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp @@ -1062,7 +1062,21 @@ void Dbacc::execACCFRAGREQ(Signal* signal) { const AccFragReq * const req = (AccFragReq*)&signal->theData[0]; jamEntry(); + if (ERROR_INSERTED(3001)) { + jam(); + addFragRefuse(signal, 1); + CLEAR_ERROR_INSERT_VALUE; + return; + } tabptr.i = req->tableId; +#ifndef VM_TRACE + // config mismatch - do not crash if release compiled + if (tabptr.i >= ctablesize) { + jam(); + addFragRefuse(signal, 800); + return; + } +#endif ptrCheckGuard(tabptr, ctablesize, tabrec); ndbrequire((req->reqInfo & 0xF) == ZADDFRAG); ndbrequire(!getrootfragmentrec(signal, rootfragrecptr, req->fragId)); diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp index 882557daae1..2b9072ab042 100644 --- a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp +++ b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp @@ -239,7 +239,11 @@ Dbdict::packTableIntoPagesImpl(SimpleProperties::Writer & w, w.add(DictTabInfo::TableName, tablePtr.p->tableName); w.add(DictTabInfo::TableId, tablePtr.i); +#ifdef HAVE_TABLE_REORG w.add(DictTabInfo::SecondTableId, tablePtr.p->secondTable); +#else + w.add(DictTabInfo::SecondTableId, (Uint32)0); +#endif w.add(DictTabInfo::TableVersion, tablePtr.p->tableVersion); w.add(DictTabInfo::NoOfKeyAttr, tablePtr.p->noOfPrimkey); w.add(DictTabInfo::NoOfAttributes, tablePtr.p->noOfAttributes); @@ -1436,6 +1440,7 @@ Uint32 Dbdict::getFreeTableRecord(Uint32 primaryTableId) jam(); return RNIL; }//if +#ifdef HAVE_TABLE_REORG bool secondFound = false; for (tablePtr.i = firstTablePtr.i + 1; tablePtr.i < tabSize ; tablePtr.i++) { jam(); @@ -1455,6 +1460,7 @@ Uint32 Dbdict::getFreeTableRecord(Uint32 primaryTableId) firstTablePtr.p->tabState = TableRecord::NOT_DEFINED; return RNIL; }//if +#endif return firstTablePtr.i; }//Dbdict::getFreeTableRecord() @@ -4623,7 +4629,7 @@ void Dbdict::handleTabInfoInit(SimpleProperties::Reader & it, jam(); tablePtr.p->tabState = TableRecord::DEFINING; }//if - +#ifdef HAVE_TABLE_REORG /* ---------------------------------------------------------------- */ // Get id of second table id and check that table doesn't already exist // and set up links between first and second table. @@ -4637,7 +4643,7 @@ void Dbdict::handleTabInfoInit(SimpleProperties::Reader & it, secondTablePtr.p->tabState = TableRecord::REORG_TABLE_PREPARED; secondTablePtr.p->secondTable = tablePtr.i; tablePtr.p->secondTable = secondTablePtr.i; - +#endif /* ---------------------------------------------------------------- */ // Set table version /* ---------------------------------------------------------------- */ @@ -5535,10 +5541,12 @@ void Dbdict::releaseTableObject(Uint32 tableId, bool removeFromHash) nextAttrRecord = attrPtr.p->nextAttrInTable; c_attributeRecordPool.release(attrPtr); }//if +#ifdef HAVE_TABLE_REORG Uint32 secondTableId = tablePtr.p->secondTable; initialiseTableRecord(tablePtr); c_tableRecordPool.getPtr(tablePtr, secondTableId); initialiseTableRecord(tablePtr); +#endif return; }//releaseTableObject() diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.hpp b/ndb/src/kernel/blocks/dbdict/Dbdict.hpp index 19c03a86e22..af80bcf5f94 100644 --- a/ndb/src/kernel/blocks/dbdict/Dbdict.hpp +++ b/ndb/src/kernel/blocks/dbdict/Dbdict.hpp @@ -151,10 +151,10 @@ public: /* Temporary record used during add/drop table */ Uint32 myConnect; - +#ifdef HAVE_TABLE_REORG /* Second table used by this table (for table reorg) */ Uint32 secondTable; - +#endif /* Next record in Pool */ Uint32 nextPool; diff --git a/ndb/src/kernel/blocks/dbdih/Dbdih.hpp b/ndb/src/kernel/blocks/dbdih/Dbdih.hpp index 14fa262f871..0a2d50cb876 100644 --- a/ndb/src/kernel/blocks/dbdih/Dbdih.hpp +++ b/ndb/src/kernel/blocks/dbdih/Dbdih.hpp @@ -147,7 +147,6 @@ public: Uint32 nfConnect; Uint32 table; Uint32 userpointer; - Uint32 nodeCount; BlockReference userblockref; }; typedef Ptr ConnectRecordPtr; diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 76aa745c3e0..4592b121c7e 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -7080,24 +7080,22 @@ void Dbdih::execDIGETPRIMREQ(Signal* signal) ndbrequire(tabPtr.p->tabStatus == TabRecord::TS_ACTIVE); connectPtr.i = signal->theData[0]; - if(connectPtr.i != RNIL){ + if(connectPtr.i != RNIL) + { jam(); ptrCheckGuard(connectPtr, cconnectFileSize, connectRecord); - ndbrequire(connectPtr.p->connectState == ConnectRecord::INUSE); - getFragstore(tabPtr.p, fragId, fragPtr); - connectPtr.p->nodeCount = extractNodeInfo(fragPtr.p, connectPtr.p->nodes); signal->theData[0] = connectPtr.p->userpointer; - signal->theData[1] = passThrough; - signal->theData[2] = connectPtr.p->nodes[0]; - sendSignal(connectPtr.p->userblockref, GSN_DIGETPRIMCONF, signal, 3, JBB); - return; - }//if - //connectPtr.i == RNIL -> question without connect record + } + else + { + jam(); + signal->theData[0] = RNIL; + } + Uint32 nodes[MAX_REPLICAS]; getFragstore(tabPtr.p, fragId, fragPtr); Uint32 count = extractNodeInfo(fragPtr.p, nodes); - signal->theData[0] = RNIL; signal->theData[1] = passThrough; signal->theData[2] = nodes[0]; signal->theData[3] = nodes[1]; diff --git a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp index d6987f3e478..0c63cb5fe17 100644 --- a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp +++ b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp @@ -550,6 +550,11 @@ public: UintR scanErrorCounter; UintR scanLocalFragid; UintR scanSchemaVersion; + + /** + * This is _always_ main table, even in range scan + * in which case scanTcrec->fragmentptr is different + */ Uint32 fragPtrI; UintR scanStoredProcId; ScanState scanState; @@ -2474,7 +2479,7 @@ private: void sendExecFragRefLab(Signal* signal); void fragrefLab(Signal* signal, BlockReference retRef, Uint32 retPtr, Uint32 errorCode); - void accFragRefLab(Signal* signal); + void abortAddFragOps(Signal* signal); void rwConcludedLab(Signal* signal); void sendsttorryLab(Signal* signal); void initialiseRecordsLab(Signal* signal, Uint32 data, Uint32, Uint32); @@ -2925,4 +2930,23 @@ Dblqh::ScanRecord::check_scan_batch_completed() const (max_bytes > 0 && (m_curr_batch_size_bytes >= max_bytes)); } +inline +void +Dblqh::i_get_acc_ptr(ScanRecord* scanP, Uint32* &acc_ptr, Uint32 index) +{ + if (index == 0) { + acc_ptr= (Uint32*)&scanP->scan_acc_op_ptr[0]; + } else { + Uint32 attr_buf_index, attr_buf_rec; + + AttrbufPtr regAttrPtr; + jam(); + attr_buf_rec= (index + 31) / 32; + attr_buf_index= (index - 1) & 31; + regAttrPtr.i= scanP->scan_acc_op_ptr[attr_buf_rec]; + ptrCheckGuard(regAttrPtr, cattrinbufFileSize, attrbuf); + acc_ptr= (Uint32*)®AttrPtr.p->attrbuf[attr_buf_index]; + } +} + #endif diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index af1131e5e55..c106a6ddfac 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -912,6 +912,10 @@ void Dblqh::execREAD_CONFIG_REQ(Signal* signal) /* *********************************************************> */ /* LQHFRAGREQ: Create new fragments for a table. Sender DICT */ /* *********************************************************> */ + +// this unbelievable mess could be replaced by one signal to LQH +// and execute direct to local DICT to get everything at once + void Dblqh::execLQHFRAGREQ(Signal* signal) { jamEntry(); @@ -1049,6 +1053,11 @@ void Dblqh::execLQHFRAGREQ(Signal* signal) addfragptr.p->lh3DistrBits = tlhstar; addfragptr.p->tableType = tableType; addfragptr.p->primaryTableId = primaryTableId; + // + addfragptr.p->tup1Connectptr = RNIL; + addfragptr.p->tup2Connectptr = RNIL; + addfragptr.p->tux1Connectptr = RNIL; + addfragptr.p->tux2Connectptr = RNIL; if (DictTabInfo::isTable(tableType) || DictTabInfo::isHashIndex(tableType)) { @@ -1329,15 +1338,21 @@ void Dblqh::execTUP_ADD_ATTCONF(Signal* signal) { jamEntry(); addfragptr.i = signal->theData[0]; + // implies that operation was released on the other side + const bool lastAttr = signal->theData[1]; ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); switch (addfragptr.p->addfragStatus) { case AddFragRecord::TUP_ATTR_WAIT1: jam(); + if (lastAttr) + addfragptr.p->tup1Connectptr = RNIL; addfragptr.p->addfragStatus = AddFragRecord::TUP_ATTR_WAIT2; sendAddAttrReq(signal); break; case AddFragRecord::TUP_ATTR_WAIT2: jam(); + if (lastAttr) + addfragptr.p->tup2Connectptr = RNIL; if (DictTabInfo::isOrderedIndex(addfragptr.p->tableType)) { addfragptr.p->addfragStatus = AddFragRecord::TUX_ATTR_WAIT1; sendAddAttrReq(signal); @@ -1347,11 +1362,15 @@ void Dblqh::execTUP_ADD_ATTCONF(Signal* signal) break; case AddFragRecord::TUX_ATTR_WAIT1: jam(); + if (lastAttr) + addfragptr.p->tux1Connectptr = RNIL; addfragptr.p->addfragStatus = AddFragRecord::TUX_ATTR_WAIT2; sendAddAttrReq(signal); break; case AddFragRecord::TUX_ATTR_WAIT2: jam(); + if (lastAttr) + addfragptr.p->tux2Connectptr = RNIL; goto done_with_attr; break; done_with_attr: @@ -1455,6 +1474,7 @@ Dblqh::sendAddAttrReq(Signal* signal) jam(); TupAddAttrConf* tupconf = (TupAddAttrConf*)signal->getDataPtrSend(); tupconf->userPtr = addfragptr.i; + tupconf->lastAttr = false; sendSignal(reference(), GSN_TUP_ADD_ATTCONF, signal, TupAddAttrConf::SignalLength, JBB); return; @@ -1485,6 +1505,7 @@ Dblqh::sendAddAttrReq(Signal* signal) jam(); TuxAddAttrConf* tuxconf = (TuxAddAttrConf*)signal->getDataPtrSend(); tuxconf->userPtr = addfragptr.i; + tuxconf->lastAttr = false; sendSignal(reference(), GSN_TUX_ADD_ATTRCONF, signal, TuxAddAttrConf::SignalLength, JBB); return; @@ -1549,6 +1570,40 @@ void Dblqh::fragrefLab(Signal* signal, return; }//Dblqh::fragrefLab() +/* + * Abort on-going ops. + */ +void Dblqh::abortAddFragOps(Signal* signal) +{ + fragptr.i = addfragptr.p->fragmentPtr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); + signal->theData[0] = (Uint32)-1; + if (addfragptr.p->tup1Connectptr != RNIL) { + jam(); + signal->theData[1] = addfragptr.p->tup1Connectptr; + sendSignal(fragptr.p->tupBlockref, GSN_TUPFRAGREQ, signal, 2, JBB); + addfragptr.p->tup1Connectptr = RNIL; + } + if (addfragptr.p->tup2Connectptr != RNIL) { + jam(); + signal->theData[1] = addfragptr.p->tup2Connectptr; + sendSignal(fragptr.p->tupBlockref, GSN_TUPFRAGREQ, signal, 2, JBB); + addfragptr.p->tup2Connectptr = RNIL; + } + if (addfragptr.p->tux1Connectptr != RNIL) { + jam(); + signal->theData[1] = addfragptr.p->tux1Connectptr; + sendSignal(fragptr.p->tuxBlockref, GSN_TUXFRAGREQ, signal, 2, JBB); + addfragptr.p->tux1Connectptr = RNIL; + } + if (addfragptr.p->tux2Connectptr != RNIL) { + jam(); + signal->theData[1] = addfragptr.p->tux2Connectptr; + sendSignal(fragptr.p->tuxBlockref, GSN_TUXFRAGREQ, signal, 2, JBB); + addfragptr.p->tux2Connectptr = RNIL; + } +} + /* ************>> */ /* ACCFRAGREF > */ /* ************>> */ @@ -1582,6 +1637,27 @@ void Dblqh::execTUPFRAGREF(Signal* signal) fragptr.i = addfragptr.p->fragmentPtr; ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); addfragptr.p->addfragErrorCode = terrorCode; + + // no operation to release, just add some jams + switch (addfragptr.p->addfragStatus) { + case AddFragRecord::WAIT_TWO_TUP: + jam(); + break; + case AddFragRecord::WAIT_ONE_TUP: + jam(); + break; + case AddFragRecord::WAIT_TWO_TUX: + jam(); + break; + case AddFragRecord::WAIT_ONE_TUX: + jam(); + break; + default: + ndbrequire(false); + break; + } + abortAddFragOps(signal); + const Uint32 ref = addfragptr.p->dictBlockref; const Uint32 senderData = addfragptr.p->dictConnectptr; const Uint32 errorCode = addfragptr.p->addfragErrorCode; @@ -1605,11 +1681,38 @@ void Dblqh::execTUXFRAGREF(Signal* signal) void Dblqh::execTUP_ADD_ATTRREF(Signal* signal) { jamEntry(); - addfragptr.i = signal->theData[0]; ptrCheckGuard(addfragptr, caddfragrecFileSize, addFragRecord); terrorCode = signal->theData[1]; addfragptr.p->addfragErrorCode = terrorCode; + + // operation was released on the other side + switch (addfragptr.p->addfragStatus) { + case AddFragRecord::TUP_ATTR_WAIT1: + jam(); + ndbrequire(addfragptr.p->tup1Connectptr != RNIL); + addfragptr.p->tup1Connectptr = RNIL; + break; + case AddFragRecord::TUP_ATTR_WAIT2: + jam(); + ndbrequire(addfragptr.p->tup2Connectptr != RNIL); + addfragptr.p->tup2Connectptr = RNIL; + break; + case AddFragRecord::TUX_ATTR_WAIT1: + jam(); + ndbrequire(addfragptr.p->tux1Connectptr != RNIL); + addfragptr.p->tux1Connectptr = RNIL; + break; + case AddFragRecord::TUX_ATTR_WAIT2: + jam(); + ndbrequire(addfragptr.p->tux2Connectptr != RNIL); + addfragptr.p->tux2Connectptr = RNIL; + break; + default: + ndbrequire(false); + break; + } + abortAddFragOps(signal); const Uint32 Ref = addfragptr.p->dictBlockref; const Uint32 senderData = addfragptr.p->dictConnectptr; @@ -2981,6 +3084,7 @@ void Dblqh::execATTRINFO(Signal* signal) return; break; default: + ndbout_c("%d", regTcPtr->transactionState); ndbrequire(false); break; }//switch @@ -7058,10 +7162,7 @@ void Dblqh::continueScanNextReqLab(Signal* signal) // Update timer on tcConnectRecord tcConnectptr.p->tcTimer = cLqhTimeOutCount; - init_acc_ptr_list(scanptr.p); - scanptr.p->m_curr_batch_size_rows = 0; - scanptr.p->m_curr_batch_size_bytes= 0; scanptr.p->scanFlag = NextScanReq::ZSCAN_NEXT; scanNextLoopLab(signal); }//Dblqh::continueScanNextReqLab() @@ -7260,22 +7361,32 @@ void Dblqh::scanLockReleasedLab(Signal* signal) tcConnectptr.i = scanptr.p->scanTcrec; ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); releaseActiveFrag(signal); + if (scanptr.p->scanReleaseCounter == scanptr.p->m_curr_batch_size_rows) { if ((scanptr.p->scanErrorCounter > 0) || (scanptr.p->scanCompletedStatus == ZTRUE)) { jam(); + scanptr.p->m_curr_batch_size_rows = 0; + scanptr.p->m_curr_batch_size_bytes = 0; closeScanLab(signal); } else if (scanptr.p->check_scan_batch_completed() && scanptr.p->scanLockHold != ZTRUE) { jam(); scanptr.p->scanState = ScanRecord::WAIT_SCAN_NEXTREQ; sendScanFragConf(signal, ZFALSE); + } else if (scanptr.p->m_last_row && !scanptr.p->scanLockHold) { + jam(); + closeScanLab(signal); + return; } else { jam(); /* - We came here after releasing locks after receiving SCAN_NEXTREQ from TC. We only - come here when scanHoldLock == ZTRUE - */ + * We came here after releasing locks after + * receiving SCAN_NEXTREQ from TC. We only come here + * when scanHoldLock == ZTRUE + */ + scanptr.p->m_curr_batch_size_rows = 0; + scanptr.p->m_curr_batch_size_bytes = 0; continueScanNextReqLab(signal); }//if } else if (scanptr.p->scanReleaseCounter < scanptr.p->m_curr_batch_size_rows) { @@ -7362,25 +7473,6 @@ Dblqh::init_acc_ptr_list(ScanRecord* scanP) scanP->scan_acc_index = 0; } -inline -void -Dblqh::i_get_acc_ptr(ScanRecord* scanP, Uint32* &acc_ptr, Uint32 index) -{ - if (index == 0) { - acc_ptr= (Uint32*)&scanP->scan_acc_op_ptr[0]; - } else { - Uint32 attr_buf_index, attr_buf_rec; - - AttrbufPtr regAttrPtr; - jam(); - attr_buf_rec= (index + 31) / 32; - attr_buf_index= (index - 1) & 31; - regAttrPtr.i= scanP->scan_acc_op_ptr[attr_buf_rec]; - ptrCheckGuard(regAttrPtr, cattrinbufFileSize, attrbuf); - acc_ptr= (Uint32*)®AttrPtr.p->attrbuf[attr_buf_index]; - } -} - Uint32 Dblqh::get_acc_ptr_from_scan_record(ScanRecord* scanP, Uint32 index, @@ -7611,6 +7703,9 @@ void Dblqh::abort_scan(Signal* signal, Uint32 scan_ptr_i, Uint32 errcode){ jam(); scanptr.i = scan_ptr_i; c_scanRecordPool.getPtr(scanptr); + + fragptr.i = tcConnectptr.p->fragmentptr; + ptrCheckGuard(fragptr, cfragrecFileSize, fragrecord); finishScanrec(signal); releaseScanrec(signal); tcConnectptr.p->transactionState = TcConnectionrec::IDLE; @@ -7904,6 +7999,13 @@ void Dblqh::nextScanConfScanLab(Signal* signal) /************************************************************* * STOP THE SCAN PROCESS IF THIS HAS BEEN REQUESTED. ************************************************************ */ + if (!scanptr.p->scanLockHold) + { + jam(); + closeScanLab(signal); + return; + } + if (scanptr.p->scanCompletedStatus == ZTRUE) { if ((scanptr.p->scanLockHold == ZTRUE) && (scanptr.p->m_curr_batch_size_rows > 0)) { @@ -8404,8 +8506,6 @@ void Dblqh::tupScanCloseConfLab(Signal* signal) ScanFragRef::SignalLength, JBB); } else { jam(); - scanptr.p->m_curr_batch_size_rows = 0; - scanptr.p->m_curr_batch_size_bytes= 0; sendScanFragConf(signal, ZSCAN_FRAG_CLOSED); }//if finishScanrec(signal); @@ -8477,7 +8577,7 @@ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq) tFragPtr.i = fragptr.p->tableFragptr; ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); scanptr.p->fragPtrI = fragptr.p->tableFragptr; - + /** * !idx uses 1 - (MAX_PARALLEL_SCANS_PER_FRAG - 1) = 1-11 * idx uses from MAX_PARALLEL_SCANS_PER_FRAG - MAX = 12-42) @@ -8486,10 +8586,10 @@ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq) Uint32 stop = (idx ? MAX_PARALLEL_INDEX_SCANS_PER_FRAG : MAX_PARALLEL_SCANS_PER_FRAG - 1); stop += start; Uint32 free = tFragPtr.p->m_scanNumberMask.find(start); - + if(free == Fragrecord::ScanNumberMask::NotFound || free >= stop){ jam(); - + if(scanPrio == 0){ jam(); return ScanFragRef::ZTOO_MANY_ACTIVE_SCAN_ERROR; @@ -8500,16 +8600,15 @@ Uint32 Dblqh::initScanrec(const ScanFragReq* scanFragReq) */ scanptr.p->scanState = ScanRecord::IN_QUEUE; LocalDLFifoList queue(c_scanRecordPool, - tFragPtr.p->m_queuedScans); + fragptr.p->m_queuedScans); queue.add(scanptr); return ZOK; } - scanptr.p->scanNumber = free; tFragPtr.p->m_scanNumberMask.clear(free);// Update mask - - LocalDLList active(c_scanRecordPool, tFragPtr.p->m_activeScans); + + LocalDLList active(c_scanRecordPool, fragptr.p->m_activeScans); active.add(scanptr); if(scanptr.p->scanKeyinfoFlag){ jam(); @@ -8569,12 +8668,8 @@ void Dblqh::finishScanrec(Signal* signal) { release_acc_ptr_list(scanptr.p); - FragrecordPtr tFragPtr; - tFragPtr.i = scanptr.p->fragPtrI; - ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); - LocalDLFifoList queue(c_scanRecordPool, - tFragPtr.p->m_queuedScans); + fragptr.p->m_queuedScans); if(scanptr.p->scanState == ScanRecord::IN_QUEUE){ jam(); @@ -8592,9 +8687,13 @@ void Dblqh::finishScanrec(Signal* signal) ndbrequire(tmp.p == scanptr.p); } - LocalDLList scans(c_scanRecordPool, tFragPtr.p->m_activeScans); + LocalDLList scans(c_scanRecordPool, fragptr.p->m_activeScans); scans.release(scanptr); + FragrecordPtr tFragPtr; + tFragPtr.i = scanptr.p->fragPtrI; + ptrCheckGuard(tFragPtr, cfragrecFileSize, fragrecord); + const Uint32 scanNumber = scanptr.p->scanNumber; ndbrequire(!tFragPtr.p->m_scanNumberMask.get(scanNumber)); ScanRecordPtr restart; @@ -8621,7 +8720,7 @@ void Dblqh::finishScanrec(Signal* signal) ptrCheckGuard(tcConnectptr, ctcConnectrecFileSize, tcConnectionrec); restart.p->scanNumber = scanNumber; restart.p->scanState = ScanRecord::WAIT_ACC_SCAN; - + queue.remove(restart); scans.add(restart); if(restart.p->scanKeyinfoFlag){ @@ -8809,6 +8908,13 @@ void Dblqh::sendScanFragConf(Signal* signal, Uint32 scanCompleted) conf->total_len= total_len; sendSignal(tcConnectptr.p->clientBlockref, GSN_SCAN_FRAGCONF, signal, ScanFragConf::SignalLength, JBB); + + if(!scanptr.p->scanLockHold) + { + jam(); + scanptr.p->m_curr_batch_size_rows = 0; + scanptr.p->m_curr_batch_size_bytes= 0; + } }//Dblqh::sendScanFragConf() /* ######################################################################### */ diff --git a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp index a209df24c44..fb90ccc8c90 100644 --- a/ndb/src/kernel/blocks/dbtc/Dbtc.hpp +++ b/ndb/src/kernel/blocks/dbtc/Dbtc.hpp @@ -1054,9 +1054,8 @@ public: // Id of the ScanRecord this fragment scan belongs to Uint32 scanRec; - // The maximum number of operations that can be scanned before - // returning to TC - Uint16 scanFragConcurrency; + // The value of fragmentCompleted in the last received SCAN_FRAGCONF + Uint8 m_scan_frag_conf_status; inline void startFragTimer(Uint32 timeVal){ scanFragTimer = timeVal; @@ -1193,8 +1192,10 @@ public: // Number of operation records per scanned fragment // Number of operations in first batch // Max number of bytes per batch - Uint16 noOprecPerFrag; - Uint16 first_batch_size; + union { + Uint16 first_batch_size_rows; + Uint16 batch_size_rows; + }; Uint32 batch_byte_size; Uint32 scanRequestInfo; // ScanFrag format diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index d8b3ee10532..07dbb370ec6 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -8646,9 +8646,9 @@ void Dbtc::initScanrec(ScanRecordPtr scanptr, scanptr.p->scanTableref = tabptr.i; scanptr.p->scanSchemaVersion = scanTabReq->tableSchemaVersion; scanptr.p->scanParallel = scanParallel; - scanptr.p->noOprecPerFrag = noOprecPerFrag; - scanptr.p->first_batch_size= scanTabReq->first_batch_size; - scanptr.p->batch_byte_size= scanTabReq->batch_byte_size; + scanptr.p->first_batch_size_rows = scanTabReq->first_batch_size; + scanptr.p->batch_byte_size = scanTabReq->batch_byte_size; + scanptr.p->batch_size_rows = noOprecPerFrag; Uint32 tmp = 0; const UintR ri = scanTabReq->requestInfo; @@ -8672,7 +8672,6 @@ void Dbtc::initScanrec(ScanRecordPtr scanptr, ndbrequire(list.seize(ptr)); ptr.p->scanRec = scanptr.i; ptr.p->scanFragId = 0; - ptr.p->scanFragConcurrency = noOprecPerFrag; ptr.p->m_apiPtr = cdata[i]; }//for @@ -8945,6 +8944,25 @@ void Dbtc::execDIGETPRIMCONF(Signal* signal) scanptr.i = scanFragptr.p->scanRec; ptrCheckGuard(scanptr, cscanrecFileSize, scanRecord); + /** + * This must be false as select count(*) otherwise + * can "pass" committing on backup fragments and + * get incorrect row count + */ + if(false && ScanFragReq::getReadCommittedFlag(scanptr.p->scanRequestInfo)) + { + jam(); + Uint32 max = 3+signal->theData[6]; + Uint32 nodeid = getOwnNodeId(); + for(Uint32 i = 3; itheData[i] == nodeid) + { + jam(); + tnodeid = nodeid; + break; + } + } + { /** * Check table @@ -9141,6 +9159,7 @@ void Dbtc::execSCAN_FRAGCONF(Signal* signal) const ScanFragConf * const conf = (ScanFragConf*)&signal->theData[0]; const Uint32 noCompletedOps = conf->completedOps; + const Uint32 status = conf->fragmentCompleted; scanFragptr.i = conf->senderData; c_scan_frag_pool.getPtr(scanFragptr); @@ -9163,11 +9182,9 @@ void Dbtc::execSCAN_FRAGCONF(Signal* signal) ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::LQH_ACTIVE); - const Uint32 status = conf->fragmentCompleted; - if(scanptr.p->scanState == ScanRecord::CLOSING_SCAN){ jam(); - if(status == ZFALSE){ + if(status == 0){ /** * We have started closing = we sent a close -> ignore this */ @@ -9184,11 +9201,11 @@ void Dbtc::execSCAN_FRAGCONF(Signal* signal) return; } - if(status == ZCLOSED && scanptr.p->scanNextFragId < scanptr.p->scanNoFrag){ + if(noCompletedOps == 0 && status != 0 && + scanptr.p->scanNextFragId < scanptr.p->scanNoFrag){ /** * Start on next fragment */ - ndbrequire(noCompletedOps == 0); scanFragptr.p->scanFragState = ScanFragRec::WAIT_GET_PRIMCONF; scanFragptr.p->startFragTimer(ctcTimer); @@ -9218,6 +9235,7 @@ void Dbtc::execSCAN_FRAGCONF(Signal* signal) scanptr.p->m_queued_count++; } + scanFragptr.p->m_scan_frag_conf_status = status; scanFragptr.p->m_ops = noCompletedOps; scanFragptr.p->m_totalLen = total_len; scanFragptr.p->scanFragState = ScanFragRec::QUEUED_FOR_DELIVERY; @@ -9311,7 +9329,6 @@ void Dbtc::execSCAN_NEXTREQ(Signal* signal) /********************************************************************* * APPLICATION IS CLOSING THE SCAN. **********************************************************************/ - ndbrequire(len == 0); close_scan_req(signal, scanptr, true); return; }//if @@ -9330,11 +9347,12 @@ void Dbtc::execSCAN_NEXTREQ(Signal* signal) // Copy op ptrs so I dont overwrite them when sending... memcpy(signal->getDataPtrSend()+25, signal->getDataPtr()+4, 4 * len); - ScanFragNextReq * nextReq = (ScanFragNextReq*)&signal->theData[0]; - nextReq->closeFlag = ZFALSE; - nextReq->transId1 = apiConnectptr.p->transid[0]; - nextReq->transId2 = apiConnectptr.p->transid[1]; - nextReq->batch_size_bytes= scanP->batch_byte_size; + ScanFragNextReq tmp; + tmp.closeFlag = ZFALSE; + tmp.transId1 = apiConnectptr.p->transid[0]; + tmp.transId2 = apiConnectptr.p->transid[1]; + tmp.batch_size_rows = scanP->batch_size_rows; + tmp.batch_size_bytes = scanP->batch_byte_size; ScanFragList running(c_scan_frag_pool, scanP->m_running_scan_frags); ScanFragList delivered(c_scan_frag_pool, scanP->m_delivered_scan_frags); @@ -9344,15 +9362,37 @@ void Dbtc::execSCAN_NEXTREQ(Signal* signal) c_scan_frag_pool.getPtr(scanFragptr); ndbrequire(scanFragptr.p->scanFragState == ScanFragRec::DELIVERED); - scanFragptr.p->scanFragState = ScanFragRec::LQH_ACTIVE; scanFragptr.p->startFragTimer(ctcTimer); - scanFragptr.p->m_ops = 0; - nextReq->senderData = scanFragptr.i; - nextReq->batch_size_rows= scanFragptr.p->scanFragConcurrency; - sendSignal(scanFragptr.p->lqhBlockref, GSN_SCAN_NEXTREQ, signal, - ScanFragNextReq::SignalLength, JBB); + if(scanFragptr.p->m_scan_frag_conf_status) + { + /** + * last scan was complete + */ + jam(); + ndbrequire(scanptr.p->scanNextFragId < scanptr.p->scanNoFrag); + scanFragptr.p->scanFragState = ScanFragRec::WAIT_GET_PRIMCONF; + + tcConnectptr.i = scanptr.p->scanTcrec; + ptrCheckGuard(tcConnectptr, ctcConnectFilesize, tcConnectRecord); + scanFragptr.p->scanFragId = scanptr.p->scanNextFragId++; + signal->theData[0] = tcConnectptr.p->dihConnectptr; + signal->theData[1] = scanFragptr.i; + signal->theData[2] = scanptr.p->scanTableref; + signal->theData[3] = scanFragptr.p->scanFragId; + sendSignal(cdihblockref, GSN_DIGETPRIMREQ, signal, 4, JBB); + } + else + { + jam(); + scanFragptr.p->scanFragState = ScanFragRec::LQH_ACTIVE; + ScanFragNextReq * req = (ScanFragNextReq*)signal->getDataPtrSend(); + * req = tmp; + req->senderData = scanFragptr.i; + sendSignal(scanFragptr.p->lqhBlockref, GSN_SCAN_NEXTREQ, signal, + ScanFragNextReq::SignalLength, JBB); + } delivered.remove(scanFragptr); running.add(scanFragptr); }//for @@ -9416,7 +9456,7 @@ Dbtc::close_scan_req(Signal* signal, ScanRecordPtr scanPtr, bool req_received){ ndbrequire(curr.p->scanFragState == ScanFragRec::DELIVERED); delivered.remove(curr); - if(curr.p->m_ops > 0){ + if(curr.p->m_ops > 0 && curr.p->m_scan_frag_conf_status == 0){ jam(); running.add(curr); curr.p->scanFragState = ScanFragRec::LQH_ACTIVE; @@ -9551,7 +9591,7 @@ void Dbtc::sendScanFragReq(Signal* signal, req->transId1 = apiConnectptr.p->transid[0]; req->transId2 = apiConnectptr.p->transid[1]; req->clientOpPtr = scanFragP->m_apiPtr; - req->batch_size_rows= scanFragP->scanFragConcurrency; + req->batch_size_rows= scanP->batch_size_rows; req->batch_size_bytes= scanP->batch_byte_size; sendSignal(scanFragP->lqhBlockref, GSN_SCAN_FRAGREQ, signal, ScanFragReq::SignalLength, JBB); @@ -9573,6 +9613,8 @@ void Dbtc::sendScanTabConf(Signal* signal, ScanRecordPtr scanPtr) { jam(); ops += 21; } + + Uint32 left = scanPtr.p->scanNoFrag - scanPtr.p->scanNextFragId; ScanTabConf * conf = (ScanTabConf*)&signal->theData[0]; conf->apiConnectPtr = apiConnectptr.p->ndbapiConnect; @@ -9588,24 +9630,25 @@ void Dbtc::sendScanTabConf(Signal* signal, ScanRecordPtr scanPtr) { ScanFragRecPtr curr = ptr; // Remove while iterating... queued.next(ptr); + bool done = curr.p->m_scan_frag_conf_status && --left; + * ops++ = curr.p->m_apiPtr; - * ops++ = curr.i; + * ops++ = done ? RNIL : curr.i; * ops++ = (curr.p->m_totalLen << 10) + curr.p->m_ops; queued.remove(curr); - if(curr.p->m_ops > 0){ + if(!done){ delivered.add(curr); curr.p->scanFragState = ScanFragRec::DELIVERED; curr.p->stopFragTimer(); } else { - (* --ops) = ScanTabConf::EndOfData; ops++; c_scan_frag_pool.release(curr); curr.p->scanFragState = ScanFragRec::COMPLETED; curr.p->stopFragTimer(); } } } - + if(scanPtr.p->m_delivered_scan_frags.isEmpty() && scanPtr.p->m_running_scan_frags.isEmpty()){ conf->requestInfo = op_count | ScanTabConf::EndOfData; @@ -10424,9 +10467,8 @@ Dbtc::execDUMP_STATE_ORD(Signal* signal) sfp.i, sfp.p->scanFragState, sfp.p->scanFragId); - infoEvent(" nodeid=%d, concurr=%d, timer=%d", + infoEvent(" nodeid=%d, timer=%d", refToNode(sfp.p->lqhBlockref), - sfp.p->scanFragConcurrency, sfp.p->scanFragTimer); } @@ -10504,7 +10546,7 @@ Dbtc::execDUMP_STATE_ORD(Signal* signal) sp.p->scanAiLength, sp.p->scanParallel, sp.p->scanReceivedOperations, - sp.p->noOprecPerFrag); + sp.p->batch_size_rows); infoEvent(" schv=%d, tab=%d, sproc=%d", sp.p->scanSchemaVersion, sp.p->scanTableref, diff --git a/ndb/src/kernel/blocks/dbtup/Dbtup.hpp b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp index 55ad1d0910a..b48546576f9 100644 --- a/ndb/src/kernel/blocks/dbtup/Dbtup.hpp +++ b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp @@ -504,6 +504,7 @@ struct Fragoperrec { Uint32 noOfNewAttrCount; Uint32 charsetIndex; BlockReference lqhBlockrefFrag; + bool inUse; }; typedef Ptr FragoperrecPtr; @@ -1936,6 +1937,7 @@ private: void setUpKeyArray(Tablerec* const regTabPtr); bool addfragtotab(Tablerec* const regTabPtr, Uint32 fragId, Uint32 fragIndex); void deleteFragTab(Tablerec* const regTabPtr, Uint32 fragId); + void abortAddFragOp(Signal* signal); void releaseTabDescr(Tablerec* const regTabPtr); void getFragmentrec(FragrecordPtr& regFragPtr, Uint32 fragId, Tablerec* const regTabPtr); diff --git a/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp b/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp index efea312b865..405f790954e 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp @@ -39,11 +39,18 @@ /* ---------------------------------------------------------------- */ void Dbtup::execTUPFRAGREQ(Signal* signal) { + ljamEntry(); + + if (signal->theData[0] == (Uint32)-1) { + ljam(); + abortAddFragOp(signal); + return; + } + FragoperrecPtr fragOperPtr; FragrecordPtr regFragPtr; TablerecPtr regTabPtr; - ljamEntry(); Uint32 userptr = signal->theData[0]; Uint32 userblockref = signal->theData[1]; Uint32 reqinfo = signal->theData[2]; @@ -62,6 +69,17 @@ void Dbtup::execTUPFRAGREQ(Signal* signal) Uint32 noOfAttributeGroups = signal->theData[12]; Uint32 globalCheckpointIdIndicator = signal->theData[13]; +#ifndef VM_TRACE + // config mismatch - do not crash if release compiled + if (regTabPtr.i >= cnoOfTablerec) { + ljam(); + signal->theData[0] = userptr; + signal->theData[1] = 800; + sendSignal(userblockref, GSN_TUPFRAGREF, signal, 2, JBB); + return; + } +#endif + ptrCheckGuard(regTabPtr, cnoOfTablerec, tablerec); if (cfirstfreeFragopr == RNIL) { ljam(); @@ -132,6 +150,15 @@ void Dbtup::execTUPFRAGREQ(Signal* signal) return; }//if + if (ERROR_INSERTED(4007) && regTabPtr.p->fragid[0] == fragId || + ERROR_INSERTED(4008) && regTabPtr.p->fragid[1] == fragId) { + ljam(); + terrorCode = 1; + fragrefuse4Lab(signal, fragOperPtr, regFragPtr, regTabPtr.p, fragId); + CLEAR_ERROR_INSERT_VALUE; + return; + } + if (regTabPtr.p->tableStatus == NOT_DEFINED) { ljam(); //------------------------------------------------------------------------------------- @@ -243,6 +270,7 @@ void Dbtup::seizeFragoperrec(FragoperrecPtr& fragOperPtr) ptrCheckGuard(fragOperPtr, cnoOfFragoprec, fragoperrec); cfirstfreeFragopr = fragOperPtr.p->nextFragoprec; fragOperPtr.p->nextFragoprec = RNIL; + fragOperPtr.p->inUse = true; }//Dbtup::seizeFragoperrec() /* **************************************************************** */ @@ -273,6 +301,7 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal* signal) ndbrequire(fragOperPtr.p->attributeCount > 0); fragOperPtr.p->attributeCount--; + const bool lastAttr = (fragOperPtr.p->attributeCount == 0); if ((regTabPtr.p->tableStatus == DEFINING) && (fragOperPtr.p->definingFragment)) { @@ -346,20 +375,30 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal* signal) addattrrefuseLab(signal, regFragPtr, fragOperPtr, regTabPtr.p, fragId); return; }//if - if ((fragOperPtr.p->attributeCount == 0) && - (fragOperPtr.p->freeNullBit != 0)) { + if (lastAttr && (fragOperPtr.p->freeNullBit != 0)) { ljam(); terrorCode = ZINCONSISTENT_NULL_ATTRIBUTE_COUNT; addattrrefuseLab(signal, regFragPtr, fragOperPtr, regTabPtr.p, fragId); return; }//if }//if + if (ERROR_INSERTED(4009) && regTabPtr.p->fragid[0] == fragId && attrId == 0 || + ERROR_INSERTED(4010) && regTabPtr.p->fragid[0] == fragId && lastAttr || + ERROR_INSERTED(4011) && regTabPtr.p->fragid[1] == fragId && attrId == 0 || + ERROR_INSERTED(4012) && regTabPtr.p->fragid[1] == fragId && lastAttr) { + ljam(); + terrorCode = 1; + addattrrefuseLab(signal, regFragPtr, fragOperPtr, regTabPtr.p, fragId); + CLEAR_ERROR_INSERT_VALUE; + return; + } /* **************************************************************** */ /* ************** TUP_ADD_ATTCONF ****************** */ /* **************************************************************** */ signal->theData[0] = fragOperPtr.p->lqhPtrFrag; - sendSignal(fragOperPtr.p->lqhBlockrefFrag, GSN_TUP_ADD_ATTCONF, signal, 1, JBB); - if (fragOperPtr.p->attributeCount > 0) { + signal->theData[1] = lastAttr; + sendSignal(fragOperPtr.p->lqhBlockrefFrag, GSN_TUP_ADD_ATTCONF, signal, 2, JBB); + if (! lastAttr) { ljam(); return; /* EXIT AND WAIT FOR MORE */ }//if @@ -491,11 +530,11 @@ void Dbtup::fragrefuseLab(Signal* signal, FragoperrecPtr fragOperPtr) void Dbtup::releaseFragoperrec(FragoperrecPtr fragOperPtr) { + fragOperPtr.p->inUse = false; fragOperPtr.p->nextFragoprec = cfirstfreeFragopr; cfirstfreeFragopr = fragOperPtr.i; }//Dbtup::releaseFragoperrec() - void Dbtup::deleteFragTab(Tablerec* const regTabPtr, Uint32 fragId) { for (Uint32 i = 0; i < (2 * MAX_FRAG_PER_NODE); i++) { @@ -510,6 +549,20 @@ void Dbtup::deleteFragTab(Tablerec* const regTabPtr, Uint32 fragId) ndbrequire(false); }//Dbtup::deleteFragTab() +/* + * LQH aborts on-going create table operation. The table is later + * dropped by DICT. + */ +void Dbtup::abortAddFragOp(Signal* signal) +{ + FragoperrecPtr fragOperPtr; + + fragOperPtr.i = signal->theData[1]; + ptrCheckGuard(fragOperPtr, cnoOfFragoprec, fragoperrec); + ndbrequire(fragOperPtr.p->inUse); + releaseFragoperrec(fragOperPtr); +} + void Dbtup::execDROP_TAB_REQ(Signal* signal) { diff --git a/ndb/src/kernel/blocks/dbtux/Dbtux.hpp b/ndb/src/kernel/blocks/dbtux/Dbtux.hpp index 8896324f793..8f49b7fa6d6 100644 --- a/ndb/src/kernel/blocks/dbtux/Dbtux.hpp +++ b/ndb/src/kernel/blocks/dbtux/Dbtux.hpp @@ -575,6 +575,7 @@ private: void execDROP_TAB_REQ(Signal* signal); bool allocDescEnt(IndexPtr indexPtr); void freeDescEnt(IndexPtr indexPtr); + void abortAddFragOp(Signal* signal); void dropIndex(Signal* signal, IndexPtr indexPtr, Uint32 senderRef, Uint32 senderData); /* @@ -684,6 +685,7 @@ private: friend class NdbOut& operator<<(NdbOut&, const ScanOp&); friend class NdbOut& operator<<(NdbOut&, const Index&); friend class NdbOut& operator<<(NdbOut&, const Frag&); + friend class NdbOut& operator<<(NdbOut&, const FragOp&); friend class NdbOut& operator<<(NdbOut&, const NodeHandle&); FILE* debugFile; NdbOut debugOut; diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp index c5c22264460..1e1b0d1d5b6 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxDebug.cpp @@ -403,6 +403,19 @@ operator<<(NdbOut& out, const Dbtux::Frag& frag) return out; } +NdbOut& +operator<<(NdbOut& out, const Dbtux::FragOp& fragOp) +{ + out << "[FragOp " << hex << &fragOp; + out << " [userPtr " << dec << fragOp.m_userPtr << "]"; + out << " [indexId " << dec << fragOp.m_indexId << "]"; + out << " [fragId " << dec << fragOp.m_fragId << "]"; + out << " [fragNo " << dec << fragOp.m_fragNo << "]"; + out << " numAttrsRecvd " << dec << fragOp.m_numAttrsRecvd << "]"; + out << "]"; + return out; +} + NdbOut& operator<<(NdbOut& out, const Dbtux::NodeHandle& node) { diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp index ded02696a89..18aa914de05 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxGen.cpp @@ -24,12 +24,7 @@ Dbtux::Dbtux(const Configuration& conf) : #ifdef VM_TRACE debugFile(0), debugOut(*new NullOutputStream()), - // until ndb_mgm supports dump -#ifdef DBTUX_DEBUG_TREE - debugFlags(DebugTree), -#else debugFlags(0), -#endif #endif c_internalStartPhase(0), c_typeOfStart(NodeState::ST_ILLEGAL_TYPE), @@ -86,7 +81,7 @@ Dbtux::execCONTINUEB(Signal* signal) jamEntry(); const Uint32* data = signal->getDataPtr(); switch (data[0]) { - case TuxContinueB::DropIndex: + case TuxContinueB::DropIndex: // currently unused { IndexPtr indexPtr; c_indexPool.getPtr(indexPtr, data[1]); @@ -174,7 +169,7 @@ Dbtux::execREAD_CONFIG_REQ(Signal* signal) ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TUX_ATTRIBUTE, &nAttribute)); ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_TUX_SCAN_OP, &nScanOp)); - const Uint32 nDescPage = (nIndex + nAttribute + DescPageSize - 1) / DescPageSize; + const Uint32 nDescPage = (nIndex * DescHeadSize + nAttribute * DescAttrSize + DescPageSize - 1) / DescPageSize; const Uint32 nScanBoundWords = nScanOp * ScanBoundSegmentSize * 4; c_indexPool.setSize(nIndex); diff --git a/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp b/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp index 1577c5045e0..b7526593a08 100644 --- a/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp +++ b/ndb/src/kernel/blocks/dbtux/DbtuxMeta.cpp @@ -29,6 +29,11 @@ void Dbtux::execTUXFRAGREQ(Signal* signal) { jamEntry(); + if (signal->theData[0] == (Uint32)-1) { + jam(); + abortAddFragOp(signal); + return; + } const TuxFragReq reqCopy = *(const TuxFragReq*)signal->getDataPtr(); const TuxFragReq* const req = &reqCopy; IndexPtr indexPtr; @@ -61,6 +66,11 @@ Dbtux::execTUXFRAGREQ(Signal* signal) fragOpPtr.p->m_fragId = req->fragId; fragOpPtr.p->m_fragNo = indexPtr.p->m_numFrags; fragOpPtr.p->m_numAttrsRecvd = 0; +#ifdef VM_TRACE + if (debugFlags & DebugMeta) { + debugOut << "Seize frag op " << fragOpPtr.i << " " << *fragOpPtr.p << endl; + } +#endif // check if index has place for more fragments ndbrequire(indexPtr.p->m_numFrags < MaxIndexFragments); // seize new fragment record @@ -129,6 +139,14 @@ Dbtux::execTUXFRAGREQ(Signal* signal) debugOut << "Add frag " << fragPtr.i << " " << *fragPtr.p << endl; } #endif + // error inserts + if (ERROR_INSERTED(12001) && fragOpPtr.p->m_fragNo == 0 || + ERROR_INSERTED(12002) && fragOpPtr.p->m_fragNo == 1) { + jam(); + errorCode = (TuxFragRef::ErrorCode)1; + CLEAR_ERROR_INSERT_VALUE; + break; + } // success TuxFragConf* const conf = (TuxFragConf*)signal->getDataPtrSend(); conf->userPtr = req->userPtr; @@ -145,10 +163,18 @@ Dbtux::execTUXFRAGREQ(Signal* signal) ref->errorCode = errorCode; sendSignal(req->userRef, GSN_TUXFRAGREF, signal, TuxFragRef::SignalLength, JBB); - if (fragOpPtr.i != RNIL) + if (fragOpPtr.i != RNIL) { +#ifdef VM_TRACE + if (debugFlags & DebugMeta) { + debugOut << "Release on frag error frag op " << fragOpPtr.i << " " << *fragOpPtr.p << endl; + } +#endif c_fragOpPool.release(fragOpPtr); - if (indexPtr.i != RNIL) - dropIndex(signal, indexPtr, 0, 0); + } + if (indexPtr.i != RNIL) { + jam(); + // let DICT drop the unfinished index + } } void @@ -203,7 +229,16 @@ Dbtux::execTUX_ADD_ATTRREQ(Signal* signal) } } #endif - if (indexPtr.p->m_numAttrs == fragOpPtr.p->m_numAttrsRecvd) { + const bool lastAttr = (indexPtr.p->m_numAttrs == fragOpPtr.p->m_numAttrsRecvd); + if (ERROR_INSERTED(12003) && fragOpPtr.p->m_fragNo == 0 && attrId == 0 || + ERROR_INSERTED(12004) && fragOpPtr.p->m_fragNo == 0 && lastAttr || + ERROR_INSERTED(12005) && fragOpPtr.p->m_fragNo == 1 && attrId == 0 || + ERROR_INSERTED(12006) && fragOpPtr.p->m_fragNo == 1 && lastAttr) { + errorCode = (TuxAddAttrRef::ErrorCode)1; + CLEAR_ERROR_INSERT_VALUE; + break; + } + if (lastAttr) { jam(); // initialize tree header TreeHead& tree = fragPtr.p->m_tree; @@ -246,11 +281,17 @@ Dbtux::execTUX_ADD_ATTRREQ(Signal* signal) } #endif // fragment is defined +#ifdef VM_TRACE + if (debugFlags & DebugMeta) { + debugOut << "Release frag op " << fragOpPtr.i << " " << *fragOpPtr.p << endl; + } +#endif c_fragOpPool.release(fragOpPtr); } // success TuxAddAttrConf* conf = (TuxAddAttrConf*)signal->getDataPtrSend(); conf->userPtr = fragOpPtr.p->m_userPtr; + conf->lastAttr = lastAttr; sendSignal(fragOpPtr.p->m_userRef, GSN_TUX_ADD_ATTRCONF, signal, TuxAddAttrConf::SignalLength, JBB); return; @@ -261,8 +302,32 @@ Dbtux::execTUX_ADD_ATTRREQ(Signal* signal) ref->errorCode = errorCode; sendSignal(fragOpPtr.p->m_userRef, GSN_TUX_ADD_ATTRREF, signal, TuxAddAttrRef::SignalLength, JBB); +#ifdef VM_TRACE + if (debugFlags & DebugMeta) { + debugOut << "Release on attr error frag op " << fragOpPtr.i << " " << *fragOpPtr.p << endl; + } +#endif c_fragOpPool.release(fragOpPtr); - dropIndex(signal, indexPtr, 0, 0); + // let DICT drop the unfinished index +} + +/* + * LQH aborts on-going create index operation. + */ +void +Dbtux::abortAddFragOp(Signal* signal) +{ + FragOpPtr fragOpPtr; + IndexPtr indexPtr; + c_fragOpPool.getPtr(fragOpPtr, signal->theData[1]); + c_indexPool.getPtr(indexPtr, fragOpPtr.p->m_indexId); +#ifdef VM_TRACE + if (debugFlags & DebugMeta) { + debugOut << "Release on abort frag op " << fragOpPtr.i << " " << *fragOpPtr.p << endl; + } +#endif + c_fragOpPool.release(fragOpPtr); + // let DICT drop the unfinished index } /* @@ -341,20 +406,13 @@ Dbtux::dropIndex(Signal* signal, IndexPtr indexPtr, Uint32 senderRef, Uint32 sen { jam(); indexPtr.p->m_state = Index::Dropping; - // drop one fragment at a time - if (indexPtr.p->m_numFrags > 0) { + // drop fragments + while (indexPtr.p->m_numFrags > 0) { jam(); - unsigned i = --indexPtr.p->m_numFrags; + Uint32 i = --indexPtr.p->m_numFrags; FragPtr fragPtr; c_fragPool.getPtr(fragPtr, indexPtr.p->m_fragPtrI[i]); c_fragPool.release(fragPtr); - // the real time break is not used for anything currently - signal->theData[0] = TuxContinueB::DropIndex; - signal->theData[1] = indexPtr.i; - signal->theData[2] = senderRef; - signal->theData[3] = senderData; - sendSignal(reference(), GSN_CONTINUEB, signal, 4, JBB); - return; } // drop attributes if (indexPtr.p->m_descPage != RNIL) { diff --git a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp index a433d72744e..da8596076ec 100644 --- a/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp +++ b/ndb/src/kernel/blocks/qmgr/QmgrMain.cpp @@ -2946,6 +2946,12 @@ void Qmgr::sendPrepFailReq(Signal* signal, Uint16 aNode) * the "handle" routines. */ +/** + * Should < 1/2 nodes die unconditionally. Affects only >= 3-way + * replication. + */ +static const bool g_ndb_arbit_one_half_rule = false; + /** * Config signals are logically part of CM_INIT. */ @@ -3157,7 +3163,8 @@ Qmgr::handleArbitCheck(Signal* signal) ndbrequire(cpresident == getOwnNodeId()); NodeBitmask ndbMask; computeArbitNdbMask(ndbMask); - if (2 * ndbMask.count() < cnoOfNodes) { + if (g_ndb_arbit_one_half_rule && + 2 * ndbMask.count() < cnoOfNodes) { jam(); arbitRec.code = ArbitCode::LoseNodes; } else { @@ -3181,6 +3188,11 @@ Qmgr::handleArbitCheck(Signal* signal) case CheckNodeGroups::Partitioning: jam(); arbitRec.code = ArbitCode::Partitioning; + if (g_ndb_arbit_one_half_rule && + 2 * ndbMask.count() > cnoOfNodes) { + jam(); + arbitRec.code = ArbitCode::WinNodes; + } break; default: ndbrequire(false); @@ -3190,8 +3202,12 @@ Qmgr::handleArbitCheck(Signal* signal) switch (arbitRec.code) { case ArbitCode::LoseNodes: jam(); + case ArbitCode::LoseGroups: + jam(); goto crashme; - case ArbitCode::WinGroups: + case ArbitCode::WinNodes: + jam(); + case ArbitCode::WinGroups: jam(); if (arbitRec.state == ARBIT_RUN) { jam(); @@ -3200,9 +3216,6 @@ Qmgr::handleArbitCheck(Signal* signal) arbitRec.state = ARBIT_INIT; arbitRec.newstate = true; break; - case ArbitCode::LoseGroups: - jam(); - goto crashme; case ArbitCode::Partitioning: if (arbitRec.state == ARBIT_RUN) { jam(); @@ -3762,8 +3775,7 @@ Qmgr::execARBIT_CHOOSEREF(Signal* signal) } /** - * Handle CRASH state. We must crash immediately. But it - * would be nice to wait until event reports have been sent. + * Handle CRASH state. We must crash immediately. * XXX tell other nodes in our party to crash too. */ void @@ -3773,12 +3785,11 @@ Qmgr::stateArbitCrash(Signal* signal) if (arbitRec.newstate) { jam(); CRASH_INSERTION((Uint32)910 + arbitRec.state); - arbitRec.setTimestamp(); arbitRec.code = 0; arbitRec.newstate = false; } -#if 0 +#ifdef ndb_arbit_crash_wait_for_event_report_to_get_out if (! (arbitRec.getTimediff() > getArbitTimeout())) return; #endif diff --git a/ndb/src/kernel/blocks/suma/Suma.cpp b/ndb/src/kernel/blocks/suma/Suma.cpp index d11d5f7176a..f6d9a0ac35a 100644 --- a/ndb/src/kernel/blocks/suma/Suma.cpp +++ b/ndb/src/kernel/blocks/suma/Suma.cpp @@ -1888,7 +1888,7 @@ SumaParticipant::SyncRecord::nextScan(Signal* signal){ req->requestInfo = 0; req->savePointId = 0; ScanFragReq::setLockMode(req->requestInfo, 0); - ScanFragReq::setHoldLockFlag(req->requestInfo, 0); + ScanFragReq::setHoldLockFlag(req->requestInfo, 1); ScanFragReq::setKeyinfoFlag(req->requestInfo, 0); ScanFragReq::setAttrLen(req->requestInfo, attrLen); req->fragmentNoKeyLen = fd.m_fragDesc.m_fragmentNo; diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp index 926647838c9..f34e16318cd 100644 --- a/ndb/src/kernel/main.cpp +++ b/ndb/src/kernel/main.cpp @@ -19,7 +19,6 @@ #include #include "Configuration.hpp" -#include #include #include "vm/SimBlockList.hpp" @@ -69,16 +68,9 @@ int main(int argc, char** argv) return NRT_Default; } - LocalConfig local_config; - if (!local_config.init(theConfig->getConnectString(),0)){ - local_config.printError(); - local_config.printUsage(); - return NRT_Default; - } - { // Do configuration signal(SIGPIPE, SIG_IGN); - theConfig->fetch_configuration(local_config); + theConfig->fetch_configuration(); } chdir(NdbConfig_get_path(0)); @@ -141,7 +133,7 @@ int main(int argc, char** argv) exit(0); } g_eventLogger.info("Ndb has terminated (pid %d) restarting", child); - theConfig->fetch_configuration(local_config); + theConfig->fetch_configuration(); } g_eventLogger.info("Angel pid: %d ndb pid: %d", getppid(), getpid()); diff --git a/ndb/src/kernel/vm/Configuration.cpp b/ndb/src/kernel/vm/Configuration.cpp index b3a436275f7..931b4da5a17 100644 --- a/ndb/src/kernel/vm/Configuration.cpp +++ b/ndb/src/kernel/vm/Configuration.cpp @@ -17,7 +17,6 @@ #include #include -#include #include "Configuration.hpp" #include #include "GlobalData.hpp" @@ -35,6 +34,7 @@ #include #include +#include #include "pc.hpp" #include #include @@ -108,7 +108,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), bool Configuration::init(int argc, char** argv) { - const char *load_default_groups[]= { "ndbd",0 }; + const char *load_default_groups[]= { "mysql_cluster","ndbd",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; @@ -189,7 +189,7 @@ Configuration::closeConfiguration(){ } void -Configuration::fetch_configuration(LocalConfig &local_config){ +Configuration::fetch_configuration(){ /** * Fetch configuration from management server */ @@ -199,8 +199,17 @@ Configuration::fetch_configuration(LocalConfig &local_config){ m_mgmd_port= 0; m_mgmd_host= 0; - m_config_retriever= new ConfigRetriever(local_config, NDB_VERSION, NODE_TYPE_DB); - if(m_config_retriever->do_connect() == -1){ + m_config_retriever= new ConfigRetriever(getConnectString(), + NDB_VERSION, NODE_TYPE_DB); + + if (m_config_retriever->hasError()) + { + ERROR_SET(fatal, ERR_INVALID_CONFIG, + "Could not connect initialize handle to management server", + m_config_retriever->getErrorString()); + } + + if(m_config_retriever->do_connect(12,5,1) == -1){ const char * s = m_config_retriever->getErrorString(); if(s == 0) s = "No error given!"; @@ -215,13 +224,7 @@ Configuration::fetch_configuration(LocalConfig &local_config){ ConfigRetriever &cr= *m_config_retriever; - if((globalData.ownId = cr.allocNodeId()) == 0){ - for(Uint32 i = 0; i<3; i++){ - NdbSleep_SecSleep(3); - if((globalData.ownId = cr.allocNodeId()) != 0) - break; - } - } + globalData.ownId = cr.allocNodeId(2 /*retry*/,3 /*delay*/); if(globalData.ownId == 0){ ERROR_SET(fatal, ERR_INVALID_CONFIG, @@ -452,6 +455,7 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ unsigned int noOfTables = 0; unsigned int noOfUniqueHashIndexes = 0; unsigned int noOfOrderedIndexes = 0; + unsigned int noOfTriggers = 0; unsigned int noOfReplicas = 0; unsigned int noOfDBNodes = 0; unsigned int noOfAPINodes = 0; @@ -476,6 +480,7 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ { CFG_DB_NO_TABLES, &noOfTables, false }, { CFG_DB_NO_ORDERED_INDEXES, &noOfOrderedIndexes, false }, { CFG_DB_NO_UNIQUE_HASH_INDEXES, &noOfUniqueHashIndexes, false }, + { CFG_DB_NO_TRIGGERS, &noOfTriggers, true }, { CFG_DB_NO_REPLICAS, &noOfReplicas, false }, { CFG_DB_NO_ATTRIBUTES, &noOfAttributes, false }, { CFG_DB_NO_OPS, &noOfOperations, false }, @@ -584,12 +589,41 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ ConfigValues::Iterator it2(*ownConfig, db.m_config); it2.set(CFG_DB_NO_TABLES, noOfTables); it2.set(CFG_DB_NO_ATTRIBUTES, noOfAttributes); + { + Uint32 neededNoOfTriggers = /* types: Insert/Update/Delete/Custom */ + 3 * noOfUniqueHashIndexes + /* for unique hash indexes, I/U/D */ + 3 * NDB_MAX_ACTIVE_EVENTS + /* for events in suma, I/U/D */ + 3 * noOfTables + /* for backup, I/U/D */ + noOfOrderedIndexes; /* for ordered indexes, C */ + if (noOfTriggers < neededNoOfTriggers) + { + noOfTriggers= neededNoOfTriggers; + it2.set(CFG_DB_NO_TRIGGERS, noOfTriggers); + } + } /** * Do size calculations */ ConfigValuesFactory cfg(ownConfig); + Uint32 noOfMetaTables= noOfTables + noOfOrderedIndexes + + noOfUniqueHashIndexes; + if (noOfMetaTables > MAX_TABLES) + noOfMetaTables= MAX_TABLES; + + { + /** + * Dict Size Alt values + */ + cfg.put(CFG_DICT_ATTRIBUTE, + noOfAttributes); + + cfg.put(CFG_DICT_TABLE, + noOfMetaTables); + } + + if (noOfLocalScanRecords == 0) { noOfLocalScanRecords = (noOfDBNodes * noOfScanRecords) + 1; } @@ -599,7 +633,7 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ Uint32 noOfTCScanRecords = noOfScanRecords; { - Uint32 noOfAccTables= noOfTables + noOfUniqueHashIndexes; + Uint32 noOfAccTables= noOfMetaTables/*noOfTables+noOfUniqueHashIndexes*/; /** * Acc Size Alt values */ @@ -641,19 +675,6 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ cfg.put(CFG_ACC_SCAN, noOfLocalScanRecords); } - Uint32 noOfMetaTables= noOfTables + noOfOrderedIndexes + - noOfUniqueHashIndexes; - { - /** - * Dict Size Alt values - */ - cfg.put(CFG_DICT_ATTRIBUTE, - noOfAttributes); - - cfg.put(CFG_DICT_TABLE, - noOfMetaTables); - } - { /** * Dih Size Alt values @@ -746,8 +767,8 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ noOfMetaTables); cfg.put(CFG_TUP_TABLE_DESC, - 4 * NO_OF_FRAG_PER_NODE * noOfAttributes* noOfReplicas + - 12 * NO_OF_FRAG_PER_NODE * noOfMetaTables* noOfReplicas ); + 2 * 6 * NO_OF_FRAG_PER_NODE * noOfAttributes * noOfReplicas + + 2 * 10 * NO_OF_FRAG_PER_NODE * noOfMetaTables * noOfReplicas ); cfg.put(CFG_TUP_STORED_PROC, noOfLocalScanRecords); @@ -758,9 +779,9 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){ * Tux Size Alt values */ cfg.put(CFG_TUX_INDEX, - noOfOrderedIndexes); + noOfMetaTables /*noOfOrderedIndexes*/); - cfg.put(CFG_TUX_FRAGMENT, + cfg.put(CFG_TUX_FRAGMENT, 2 * NO_OF_FRAG_PER_NODE * noOfOrderedIndexes * noOfReplicas); cfg.put(CFG_TUX_ATTRIBUTE, diff --git a/ndb/src/kernel/vm/Configuration.hpp b/ndb/src/kernel/vm/Configuration.hpp index e4cd64f5ca8..acf0e163a84 100644 --- a/ndb/src/kernel/vm/Configuration.hpp +++ b/ndb/src/kernel/vm/Configuration.hpp @@ -21,7 +21,6 @@ #include class ConfigRetriever; -class LocalConfig; class Configuration { public: @@ -33,7 +32,7 @@ public: */ bool init(int argc, char** argv); - void fetch_configuration(LocalConfig &local_config); + void fetch_configuration(); void setupConfiguration(); void closeConfiguration(); diff --git a/ndb/src/mgmapi/LocalConfig.cpp b/ndb/src/mgmapi/LocalConfig.cpp index d0ff97cdedf..1dc805557ee 100644 --- a/ndb/src/mgmapi/LocalConfig.cpp +++ b/ndb/src/mgmapi/LocalConfig.cpp @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include "LocalConfig.hpp" #include #include #include @@ -294,4 +294,27 @@ LocalConfig::readConnectString(const char * connectString, return return_value; } +char * +LocalConfig::makeConnectString(char *buf, int sz) +{ + int p= BaseString::snprintf(buf,sz,"nodeid=%d", _ownNodeId); + if (p < sz) + for (unsigned i = 0; i < ids.size(); i++) + { + if (ids[i].type != MgmId_TCP) + continue; + int new_p= p+BaseString::snprintf(buf+p,sz-p,",%s:%d", + ids[i].name.c_str(), ids[i].port); + if (new_p < sz) + p= new_p; + else + { + buf[p]= 0; + break; + } + } + buf[sz-1]=0; + return buf; +} + template class Vector; diff --git a/ndb/include/mgmapi/LocalConfig.hpp b/ndb/src/mgmapi/LocalConfig.hpp similarity index 97% rename from ndb/include/mgmapi/LocalConfig.hpp rename to ndb/src/mgmapi/LocalConfig.hpp index 9ceeffdba36..c415ec1be91 100644 --- a/ndb/include/mgmapi/LocalConfig.hpp +++ b/ndb/src/mgmapi/LocalConfig.hpp @@ -61,6 +61,7 @@ struct LocalConfig { bool parseHostName(const char *buf); bool parseFileName(const char *buf); bool parseString(const char *buf, BaseString &err); + char * makeConnectString(char *buf, int sz); }; #endif // LocalConfig_H diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index 51f2d7cee01..651a4a8a725 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include "mgmapi.h" #include "mgmapi_debug.h" @@ -83,8 +84,7 @@ typedef Parser Parser_t; #define NDB_MGM_MAX_ERR_DESC_SIZE 256 struct ndb_mgm_handle { - char * hostname; - unsigned short port; + int cfg_i; int connected; int last_error; @@ -95,7 +95,7 @@ struct ndb_mgm_handle { NDB_SOCKET_TYPE socket; - char cfg_ptr[sizeof(LocalConfig)]; + LocalConfig cfg; #ifdef MGMAPI_LOG FILE* logfile; @@ -148,14 +148,16 @@ ndb_mgm_create_handle() h->connected = 0; h->last_error = 0; h->last_error_line = 0; - h->hostname = 0; h->socket = NDB_INVALID_SOCKET; h->read_timeout = 50000; h->write_timeout = 100; - - new (h->cfg_ptr) LocalConfig; + h->cfg_i = 0; strncpy(h->last_error_desc, "No error", NDB_MGM_MAX_ERR_DESC_SIZE); + + new (&(h->cfg)) LocalConfig; + h->cfg.init(0, 0); + #ifdef MGMAPI_LOG h->logfile = 0; #endif @@ -163,6 +165,23 @@ ndb_mgm_create_handle() return h; } +extern "C" +int +ndb_mgm_set_connectstring(NdbMgmHandle handle, const char * mgmsrv) +{ + new (&(handle->cfg)) LocalConfig; + if (!handle->cfg.init(mgmsrv, 0) || + handle->cfg.ids.size() == 0) + { + new (&(handle->cfg)) LocalConfig; + handle->cfg.init(0, 0); /* reset the LocalCongig */ + SET_ERROR(handle, NDB_MGM_ILLEGAL_CONNECT_STRING, ""); + return -1; + } + handle->cfg_i= 0; + return 0; +} + /** * Destroy a handle */ @@ -175,14 +194,13 @@ ndb_mgm_destroy_handle(NdbMgmHandle * handle) if((* handle)->connected){ ndb_mgm_disconnect(* handle); } - my_free((* handle)->hostname,MYF(MY_ALLOW_ZERO_PTR)); #ifdef MGMAPI_LOG if ((* handle)->logfile != 0){ fclose((* handle)->logfile); (* handle)->logfile = 0; } #endif - ((LocalConfig*)((*handle)->cfg_ptr))->~LocalConfig(); + (*handle)->cfg.~LocalConfig(); my_free((char*)* handle,MYF(MY_ALLOW_ZERO_PTR)); * handle = 0; } @@ -314,7 +332,8 @@ ndb_mgm_call(NdbMgmHandle handle, const ParserRow *command_reply, */ extern "C" int -ndb_mgm_connect(NdbMgmHandle handle, const char * mgmsrv) +ndb_mgm_connect(NdbMgmHandle handle, int no_retries, + int retry_delay_in_seconds, int verbose) { SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_connect"); CHECK_HANDLE(handle, -1); @@ -331,36 +350,60 @@ ndb_mgm_connect(NdbMgmHandle handle, const char * mgmsrv) /** * Do connect */ - LocalConfig *cfg= (LocalConfig*)(handle->cfg_ptr); - new (cfg) LocalConfig; - if (!cfg->init(mgmsrv, 0) || - cfg->ids.size() == 0) - { - SET_ERROR(handle, NDB_MGM_ILLEGAL_CONNECT_STRING, ""); - return -1; - } - + LocalConfig &cfg= handle->cfg; NDB_SOCKET_TYPE sockfd= NDB_INVALID_SOCKET; Uint32 i; - for (i = 0; i < cfg->ids.size(); i++) + while (sockfd == NDB_INVALID_SOCKET) { - if (cfg->ids[i].type != MgmId_TCP) - continue; - SocketClient s(cfg->ids[i].name.c_str(), cfg->ids[i].port); - sockfd = s.connect(); + // do all the mgmt servers + for (i = 0; i < cfg.ids.size(); i++) + { + if (cfg.ids[i].type != MgmId_TCP) + continue; + SocketClient s(cfg.ids[i].name.c_str(), cfg.ids[i].port); + sockfd = s.connect(); + if (sockfd != NDB_INVALID_SOCKET) + break; + } if (sockfd != NDB_INVALID_SOCKET) break; - } - if (sockfd == NDB_INVALID_SOCKET) - { - setError(handle, NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET, __LINE__, - "Unable to connect using connectstring %s", mgmsrv); - return -1; + if (verbose > 0) { + char buf[1024]; + ndbout_c("Unable to connect with connect string: %s", + cfg.makeConnectString(buf,sizeof(buf))); + verbose= -1; + } + if (no_retries == 0) { + char buf[1024]; + setError(handle, NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET, __LINE__, + "Unable to connect with connect string: %s", + cfg.makeConnectString(buf,sizeof(buf))); + if (verbose == -2) + ndbout << ", failed." << endl; + return -1; + } + if (verbose == -1) { + ndbout << "Retrying every " << retry_delay_in_seconds << " seconds"; + if (no_retries > 0) + ndbout << ". Attempts left:"; + else + ndbout << ", until connected.";; + ndbout << flush; + verbose= -2; + } + if (no_retries > 0) { + if (verbose == -2) { + ndbout << " " << no_retries; + ndbout << flush; + } + no_retries--; + } + NdbSleep_SecSleep(retry_delay_in_seconds); } + if (verbose == -2) + ndbout << endl; - my_free(handle->hostname,MYF(MY_ALLOW_ZERO_PTR)); - handle->hostname = my_strdup(cfg->ids[i].name.c_str(),MYF(MY_WME)); - handle->port = cfg->ids[i].port; + handle->cfg_i = i; handle->socket = sockfd; handle->connected = 1; @@ -1068,7 +1111,9 @@ ndb_mgm_listen_event(NdbMgmHandle handle, int filter[]) }; CHECK_HANDLE(handle, -1); - SocketClient s(handle->hostname, handle->port); + const char *hostname= ndb_mgm_get_connected_host(handle); + int port= ndb_mgm_get_connected_port(handle); + SocketClient s(hostname, port); const NDB_SOCKET_TYPE sockfd = s.connect(); if (sockfd < 0) { setError(handle, NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET, __LINE__, @@ -1613,16 +1658,43 @@ ndb_mgm_destroy_configuration(struct ndb_mgm_configuration *cfg) extern "C" int -ndb_mgm_alloc_nodeid(NdbMgmHandle handle, unsigned int version, unsigned *pnodeid, int nodetype) +ndb_mgm_get_configuration_nodeid(NdbMgmHandle handle) { + CHECK_HANDLE(handle, 0); + return handle->cfg._ownNodeId; +} +extern "C" +int ndb_mgm_get_connected_port(NdbMgmHandle handle) +{ + return handle->cfg.ids[handle->cfg_i].port; +} + +extern "C" +const char *ndb_mgm_get_connected_host(NdbMgmHandle handle) +{ + return handle->cfg.ids[handle->cfg_i].name.c_str(); +} + +extern "C" +const char *ndb_mgm_get_connectstring(NdbMgmHandle handle, char *buf, int buf_sz) +{ + return handle->cfg.makeConnectString(buf,buf_sz); +} + +extern "C" +int +ndb_mgm_alloc_nodeid(NdbMgmHandle handle, unsigned int version, int nodetype) +{ CHECK_HANDLE(handle, 0); CHECK_CONNECTED(handle, 0); + int nodeid= handle->cfg._ownNodeId; + Properties args; args.put("version", version); args.put("nodetype", nodetype); - args.put("nodeid", *pnodeid); + args.put("nodeid", nodeid); args.put("user", "mysqld"); args.put("password", "mysqld"); args.put("public key", "a public key"); @@ -1638,26 +1710,29 @@ ndb_mgm_alloc_nodeid(NdbMgmHandle handle, unsigned int version, unsigned *pnodei prop= ndb_mgm_call(handle, reply, "get nodeid", &args); CHECK_REPLY(prop, -1); - int res= -1; + nodeid= -1; do { const char * buf; if(!prop->get("result", &buf) || strcmp(buf, "Ok") != 0){ + const char *hostname= ndb_mgm_get_connected_host(handle); + unsigned port= ndb_mgm_get_connected_port(handle); BaseString err; err.assfmt("Could not alloc node id at %s port %d: %s", - handle->hostname, handle->port, buf); + hostname, port, buf); setError(handle, NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET, __LINE__, err.c_str()); break; } - if(!prop->get("nodeid", pnodeid) != 0){ + Uint32 _nodeid; + if(!prop->get("nodeid", &_nodeid) != 0){ ndbout_c("ERROR Message: \n"); break; } - res= 0; + nodeid= _nodeid; }while(0); delete prop; - return res; + return nodeid; } /***************************************************************************** @@ -1864,4 +1939,38 @@ ndb_mgm_purge_stale_sessions(NdbMgmHandle handle, char **purged){ return res; } +extern "C" +int +ndb_mgm_check_connection(NdbMgmHandle handle){ + CHECK_HANDLE(handle, 0); + CHECK_CONNECTED(handle, 0); + SocketOutputStream out(handle->socket); + SocketInputStream in(handle->socket, handle->read_timeout); + char buf[32]; + + if (out.println("check connection")) + goto ndb_mgm_check_connection_error; + + if (out.println("")) + goto ndb_mgm_check_connection_error; + + in.gets(buf, sizeof(buf)); + if(strcmp("check connection reply\n", buf)) + goto ndb_mgm_check_connection_error; + + in.gets(buf, sizeof(buf)); + if(strcmp("result: Ok\n", buf)) + goto ndb_mgm_check_connection_error; + + in.gets(buf, sizeof(buf)); + if(strcmp("\n", buf)) + goto ndb_mgm_check_connection_error; + + return 0; + +ndb_mgm_check_connection_error: + ndb_mgm_disconnect(handle); + return -1; +} + template class Vector*>; diff --git a/ndb/src/mgmclient/CommandInterpreter.cpp b/ndb/src/mgmclient/CommandInterpreter.cpp index d940f6e165a..7ef62da9bb3 100644 --- a/ndb/src/mgmclient/CommandInterpreter.cpp +++ b/ndb/src/mgmclient/CommandInterpreter.cpp @@ -44,7 +44,7 @@ public: * Constructor * @param mgmtSrvr: Management server to use when executing commands */ - CommandInterpreter(const char *); + CommandInterpreter(const char *, int verbose); ~CommandInterpreter(); /** @@ -54,10 +54,11 @@ public: * * @return true until quit/bye/exit has been typed */ - int execute(const char *_line, int _try_reconnect=-1); + int execute(const char *_line, int _try_reconnect=-1, int *error= 0); private: void printError(); + int execute_impl(const char *_line); /** * Analyse the command line, after the first token. @@ -94,8 +95,9 @@ private: */ void executeHelp(char* parameters); void executeShow(char* parameters); + void executeConnect(char* parameters); void executePurge(char* parameters); - void executeShutdown(char* parameters); + int executeShutdown(char* parameters); void executeRun(char* parameters); void executeInfo(char* parameters); void executeClusterLog(char* parameters); @@ -120,7 +122,7 @@ public: void executeStatus(int processId, const char* parameters, bool all); void executeEventReporting(int processId, const char* parameters, bool all); void executeDumpState(int processId, const char* parameters, bool all); - void executeStartBackup(char * parameters); + int executeStartBackup(char * parameters); void executeAbortBackup(char * parameters); void executeRep(char* parameters); @@ -153,8 +155,9 @@ private: NdbMgmHandle m_mgmsrv; bool connected; - const char *host; + int m_verbose; int try_reconnect; + int m_error; #ifdef HAVE_GLOBAL_REPLICATION NdbRepHandle m_repserver; const char *rep_host; @@ -170,17 +173,17 @@ private: #include "ndb_mgmclient.hpp" #include "ndb_mgmclient.h" -Ndb_mgmclient::Ndb_mgmclient(const char *host) +Ndb_mgmclient::Ndb_mgmclient(const char *host,int verbose) { - m_cmd= new CommandInterpreter(host); + m_cmd= new CommandInterpreter(host,verbose); } Ndb_mgmclient::~Ndb_mgmclient() { delete m_cmd; } -int Ndb_mgmclient::execute(const char *_line, int _try_reconnect) +int Ndb_mgmclient::execute(const char *_line, int _try_reconnect, int *error) { - return m_cmd->execute(_line,_try_reconnect); + return m_cmd->execute(_line,_try_reconnect,error); } int Ndb_mgmclient::disconnect() @@ -193,7 +196,7 @@ extern "C" { { return (Ndb_mgmclient_handle) new Ndb_mgmclient(connect_string); } - int ndb_mgmclient_execute(Ndb_mgmclient_handle h, int argc, const char** argv) + int ndb_mgmclient_execute(Ndb_mgmclient_handle h, int argc, char** argv) { return ((Ndb_mgmclient*)h)->execute(argc, argv, 1); } @@ -226,7 +229,7 @@ extern "C" { #include #include -int Ndb_mgmclient::execute(int argc, const char** argv, int _try_reconnect) +int Ndb_mgmclient::execute(int argc, char** argv, int _try_reconnect, int *error) { if (argc <= 0) return 0; @@ -235,7 +238,7 @@ int Ndb_mgmclient::execute(int argc, const char** argv, int _try_reconnect) { _line.appfmt(" %s", argv[i]); } - return m_cmd->execute(_line.c_str(),_try_reconnect); + return m_cmd->execute(_line.c_str(),_try_reconnect, error); } /***************************************************************************** @@ -276,6 +279,7 @@ static const char* helpText = "REP CONNECT Connect to REP server on host:port\n" #endif "PURGE STALE SESSIONS Reset reserved nodeid's in the mgmt server\n" +"CONNECT [] Connect to management server (reconnect if already connected)\n" "QUIT Quit management client\n" ; @@ -374,20 +378,22 @@ convert(const char* s, int& val) { /* * Constructor */ -CommandInterpreter::CommandInterpreter(const char *_host) +CommandInterpreter::CommandInterpreter(const char *_host,int verbose) + : m_verbose(verbose) { m_mgmsrv = ndb_mgm_create_handle(); if(m_mgmsrv == NULL) { ndbout_c("Cannot create handle to management server."); + exit(-1); + } + if (ndb_mgm_set_connectstring(m_mgmsrv, _host)) + { printError(); + exit(-1); } connected = false; try_reconnect = 0; - if (_host) - host= my_strdup(_host,MYF(MY_WME)); - else - host= 0; #ifdef HAVE_GLOBAL_REPLICATION rep_host = NULL; m_repserver = NULL; @@ -402,8 +408,6 @@ CommandInterpreter::~CommandInterpreter() { connected = false; ndb_mgm_destroy_handle(&m_mgmsrv); - my_free((char *)host,MYF(MY_ALLOW_ZERO_PTR)); - host = NULL; } static bool @@ -425,6 +429,8 @@ emptyString(const char* s) void CommandInterpreter::printError() { + if (ndb_mgm_check_connection(m_mgmsrv)) + connected= false; ndbout_c("* %5d: %s", ndb_mgm_get_latest_error(m_mgmsrv), ndb_mgm_get_latest_error_msg(m_mgmsrv)); @@ -438,17 +444,15 @@ bool CommandInterpreter::connect() { if(!connected) { - int tries = try_reconnect; // tries == 0 => infinite - while(!connected) { - if(ndb_mgm_connect(m_mgmsrv, host) == -1) { - ndbout << "Cannot connect to management server (" << host << ")."; - tries--; - if (tries == 0) - break; - ndbout << "Retrying in 5 seconds." << endl; - NdbSleep_SecSleep(5); - } else - connected = true; + if(!ndb_mgm_connect(m_mgmsrv, try_reconnect-1, 5, 1)) + { + connected = true; + if (m_verbose) + { + printf("Connected to Management Server at: %s:%d\n", + ndb_mgm_get_connected_host(m_mgmsrv), + ndb_mgm_get_connected_port(m_mgmsrv)); + } } } return connected; @@ -457,7 +461,7 @@ CommandInterpreter::connect() bool CommandInterpreter::disconnect() { - if (ndb_mgm_disconnect(m_mgmsrv) == -1) { + if (connected && (ndb_mgm_disconnect(m_mgmsrv) == -1)) { ndbout_c("Could not disconnect from management server"); printError(); } @@ -469,92 +473,110 @@ CommandInterpreter::disconnect() //***************************************************************************** int -CommandInterpreter::execute(const char *_line, int _try_reconnect) +CommandInterpreter::execute(const char *_line, int _try_reconnect, + int *error) { if (_try_reconnect >= 0) try_reconnect=_try_reconnect; + int result= execute_impl(_line); + if (error) + *error= m_error; + return result; +} + +int +CommandInterpreter::execute_impl(const char *_line) +{ + DBUG_ENTER("CommandInterpreter::execute_impl"); + DBUG_PRINT("enter",("line=\"%s\"",_line)); + m_error= 0; + char * line; if(_line == NULL) { // ndbout << endl; - return false; + DBUG_RETURN(false); } line = my_strdup(_line,MYF(MY_WME)); My_auto_ptr ptr(line); if (emptyString(line)) { - return true; + DBUG_RETURN(true); } - for (unsigned int i = 0; i < strlen(line); ++i) { - line[i] = toupper(line[i]); - } - // if there is anything in the line proceed char* firstToken = strtok(line, " "); char* allAfterFirstToken = strtok(NULL, ""); - if (strcmp(firstToken, "HELP") == 0 || - strcmp(firstToken, "?") == 0) { + if (strcasecmp(firstToken, "HELP") == 0 || + strcasecmp(firstToken, "?") == 0) { executeHelp(allAfterFirstToken); - return true; + DBUG_RETURN(true); } - else if (strcmp(firstToken, "SHOW") == 0) { + else if (strcasecmp(firstToken, "CONNECT") == 0) { + executeConnect(allAfterFirstToken); + DBUG_RETURN(true); + } + else if((strcasecmp(firstToken, "QUIT") == 0 || + strcasecmp(firstToken, "EXIT") == 0 || + strcasecmp(firstToken, "BYE") == 0) && + allAfterFirstToken == NULL){ + DBUG_RETURN(false); + } + + if (!connect()) + DBUG_RETURN(true); + + if (strcasecmp(firstToken, "SHOW") == 0) { executeShow(allAfterFirstToken); - return true; + DBUG_RETURN(true); } - else if (strcmp(firstToken, "SHUTDOWN") == 0) { - executeShutdown(allAfterFirstToken); - return true; + else if (strcasecmp(firstToken, "SHUTDOWN") == 0) { + m_error= executeShutdown(allAfterFirstToken); + DBUG_RETURN(true); } - else if (strcmp(firstToken, "CLUSTERLOG") == 0){ + else if (strcasecmp(firstToken, "CLUSTERLOG") == 0){ executeClusterLog(allAfterFirstToken); - return true; + DBUG_RETURN(true); } - else if(strcmp(firstToken, "START") == 0 && + else if(strcasecmp(firstToken, "START") == 0 && allAfterFirstToken != NULL && - strncmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){ - executeStartBackup(allAfterFirstToken); - return true; + strncasecmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){ + m_error= executeStartBackup(allAfterFirstToken); + DBUG_RETURN(true); } - else if(strcmp(firstToken, "ABORT") == 0 && + else if(strcasecmp(firstToken, "ABORT") == 0 && allAfterFirstToken != NULL && - strncmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){ + strncasecmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){ executeAbortBackup(allAfterFirstToken); - return true; + DBUG_RETURN(true); } - else if (strcmp(firstToken, "PURGE") == 0) { + else if (strcasecmp(firstToken, "PURGE") == 0) { executePurge(allAfterFirstToken); - return true; + DBUG_RETURN(true); } #ifdef HAVE_GLOBAL_REPLICATION - else if(strcmp(firstToken, "REPLICATION") == 0 || - strcmp(firstToken, "REP") == 0) { + else if(strcasecmp(firstToken, "REPLICATION") == 0 || + strcasecmp(firstToken, "REP") == 0) { executeRep(allAfterFirstToken); - return true; + DBUG_RETURN(true); } #endif // HAVE_GLOBAL_REPLICATION - else if(strcmp(firstToken, "ENTER") == 0 && + else if(strcasecmp(firstToken, "ENTER") == 0 && allAfterFirstToken != NULL && - strncmp(allAfterFirstToken, "SINGLE USER MODE ", + strncasecmp(allAfterFirstToken, "SINGLE USER MODE ", sizeof("SINGLE USER MODE") - 1) == 0){ executeEnterSingleUser(allAfterFirstToken); - return true; + DBUG_RETURN(true); } - else if(strcmp(firstToken, "EXIT") == 0 && + else if(strcasecmp(firstToken, "EXIT") == 0 && allAfterFirstToken != NULL && - strncmp(allAfterFirstToken, "SINGLE USER MODE ", + strncasecmp(allAfterFirstToken, "SINGLE USER MODE ", sizeof("SINGLE USER MODE") - 1) == 0){ executeExitSingleUser(allAfterFirstToken); - return true; + DBUG_RETURN(true); } - else if (strcmp(firstToken, "ALL") == 0) { + else if (strcasecmp(firstToken, "ALL") == 0) { analyseAfterFirstToken(-1, allAfterFirstToken); - } - else if((strcmp(firstToken, "QUIT") == 0 || - strcmp(firstToken, "EXIT") == 0 || - strcmp(firstToken, "BYE") == 0) && - allAfterFirstToken == NULL){ - return false; } else { /** * First token should be a digit, node ID @@ -562,20 +584,20 @@ CommandInterpreter::execute(const char *_line, int _try_reconnect) int nodeId; if (! convert(firstToken, nodeId)) { - ndbout << "Invalid command: " << line << endl; + ndbout << "Invalid command: " << _line << endl; ndbout << "Type HELP for help." << endl << endl; - return true; + DBUG_RETURN(true); } - if (nodeId < 0) { + if (nodeId <= 0) { ndbout << "Invalid node ID: " << firstToken << "." << endl; - return true; + DBUG_RETURN(true); } analyseAfterFirstToken(nodeId, allAfterFirstToken); } - return true; + DBUG_RETURN(true); } @@ -628,7 +650,7 @@ CommandInterpreter::analyseAfterFirstToken(int processId, ExecuteFunction fun = 0; const char * command = 0; for(int i = 0; i*fun)(processId, allAfterSecondToken, false); ndbout << endl; @@ -694,17 +716,16 @@ CommandInterpreter::executeForAll(const char * cmd, ExecuteFunction fun, const char * allAfterSecondToken) { int nodeId = 0; - if(strcmp(cmd, "STOP") == 0) { + if(strcasecmp(cmd, "STOP") == 0) { ndbout_c("Executing STOP on all nodes."); (this->*fun)(nodeId, allAfterSecondToken, true); - } else if(strcmp(cmd, "RESTART") == 0) { + } else if(strcasecmp(cmd, "RESTART") == 0) { ndbout_c("Executing RESTART on all nodes."); ndbout_c("Starting shutdown. This may take a while. Please wait..."); (this->*fun)(nodeId, allAfterSecondToken, true); ndbout_c("Trying to start all nodes of system."); ndbout_c("Use ALL STATUS to see the system start-up phases."); } else { - connect(); struct ndb_mgm_cluster_state *cl= ndb_mgm_get_status(m_mgmsrv); if(cl == 0){ ndbout_c("Unable get status from management server"); @@ -713,7 +734,7 @@ CommandInterpreter::executeForAll(const char * cmd, ExecuteFunction fun, } NdbAutoPtr ap1((char*)cl); while(get_next_nodeid(cl, &nodeId, NDB_MGM_NODE_TYPE_NDB)) { - if(strcmp(cmd, "STATUS") != 0) + if(strcasecmp(cmd, "STATUS") != 0) ndbout_c("Executing %s on node %d.", cmd, nodeId); (this->*fun)(nodeId, allAfterSecondToken, true); ndbout << endl; @@ -741,7 +762,7 @@ CommandInterpreter::parseBlockSpecification(const char* allAfterLog, firstTokenAfterLog[i] = toupper(firstTokenAfterLog[i]); } - if (strcmp(firstTokenAfterLog, "BLOCK") != 0) { + if (strcasecmp(firstTokenAfterLog, "BLOCK") != 0) { ndbout << "Unexpected value: " << firstTokenAfterLog << ". Expected BLOCK." << endl; return false; @@ -754,7 +775,7 @@ CommandInterpreter::parseBlockSpecification(const char* allAfterLog, } char* secondTokenAfterLog = strtok(allAfterFirstToken, " "); - if (strcmp(secondTokenAfterLog, "=") != 0) { + if (strcasecmp(secondTokenAfterLog, "=") != 0) { ndbout << "Unexpected value: " << secondTokenAfterLog << ". Expected =." << endl; return false; @@ -762,7 +783,7 @@ CommandInterpreter::parseBlockSpecification(const char* allAfterLog, char* blockName = strtok(NULL, " "); bool all = false; - if (blockName != NULL && (strcmp(blockName, "ALL") == 0)) { + if (blockName != NULL && (strcasecmp(blockName, "ALL") == 0)) { all = true; } while (blockName != NULL) { @@ -813,15 +834,15 @@ CommandInterpreter::executeHelp(char* parameters) ndbout << " = " << "0 - 15" << endl; ndbout << " = " << "ALL | Any database node id" << endl; ndbout << endl; - } else if (strcmp(parameters, "SHOW") == 0) { + } else if (strcasecmp(parameters, "SHOW") == 0) { ndbout << helpTextShow; #ifdef HAVE_GLOBAL_REPLICATION - } else if (strcmp(parameters, "REPLICATION") == 0 || - strcmp(parameters, "REP") == 0) { + } else if (strcasecmp(parameters, "REPLICATION") == 0 || + strcasecmp(parameters, "REP") == 0) { ndbout << helpTextRep; #endif // HAVE_GLOBAL_REPLICATION #ifdef VM_TRACE // DEBUG ONLY - } else if (strcmp(parameters, "DEBUG") == 0) { + } else if (strcasecmp(parameters, "DEBUG") == 0) { ndbout << helpTextDebug; #endif } else { @@ -835,25 +856,23 @@ CommandInterpreter::executeHelp(char* parameters) * SHUTDOWN *****************************************************************************/ -void +int CommandInterpreter::executeShutdown(char* parameters) { - connect(); - ndb_mgm_cluster_state *state = ndb_mgm_get_status(m_mgmsrv); if(state == NULL) { ndbout_c("Could not get status"); printError(); - return; + return 1; } NdbAutoPtr ap1((char*)state); int result = 0; result = ndb_mgm_stop(m_mgmsrv, 0, 0); if (result < 0) { - ndbout << "Shutdown failed." << endl; + ndbout << "Shutdown off NDB Cluster storage node(s) failed." << endl; printError(); - return; + return result; } ndbout << result << " NDB Cluster storage node(s) have shutdown." << endl; @@ -868,21 +887,23 @@ CommandInterpreter::executeShutdown(char* parameters) ndbout << "Unable to locate management server, " << "shutdown manually with STOP" << endl; - return; + return 1; } } } - result = 0; result = ndb_mgm_stop(m_mgmsrv, 1, &mgm_id); if (result <= 0) { - ndbout << "Shutdown failed." << endl; + ndbout << "Shutdown of NDB Cluster management server failed." << endl; printError(); - return; + if (result == 0) + return 1; + return result; } + connected = false; ndbout << "NDB Cluster management server shutdown." << endl; - exit(0); + return 0; } /***************************************************************************** @@ -931,7 +952,7 @@ print_nodes(ndb_mgm_cluster_state *state, ndb_mgm_configuration_iterator *it, const char *hostname= node_state->connect_address; if (hostname == 0 || strlen(hostname) == 0 - || strcmp(hostname,"0.0.0.0") == 0) + || strcasecmp(hostname,"0.0.0.0") == 0) ndbout << " "; else ndbout << "\t@" << hostname; @@ -976,9 +997,9 @@ CommandInterpreter::executePurge(char* parameters) break; char* firstToken = strtok(parameters, " "); char* nextToken = strtok(NULL, " \0"); - if (strcmp(firstToken,"STALE") == 0 && + if (strcasecmp(firstToken,"STALE") == 0 && nextToken && - strcmp(nextToken, "SESSIONS") == 0) { + strcasecmp(nextToken, "SESSIONS") == 0) { command_ok= 1; break; } @@ -991,7 +1012,6 @@ CommandInterpreter::executePurge(char* parameters) int i; char *str; - connect(); if (ndb_mgm_purge_stale_sessions(m_mgmsrv, &str)) { ndbout_c("Command failed"); @@ -1011,11 +1031,7 @@ void CommandInterpreter::executeShow(char* parameters) { int i; - connect(); if (emptyString(parameters)) { - ndbout << "Cluster Configuration" << endl - << "---------------------" << endl; - ndb_mgm_cluster_state *state = ndb_mgm_get_status(m_mgmsrv); if(state == NULL) { ndbout_c("Could not get status"); @@ -1075,22 +1091,24 @@ CommandInterpreter::executeShow(char* parameters) } } + ndbout << "Cluster Configuration" << endl + << "---------------------" << endl; print_nodes(state, it, "ndbd", ndb_nodes, NDB_MGM_NODE_TYPE_NDB, master_id); print_nodes(state, it, "ndb_mgmd", mgm_nodes, NDB_MGM_NODE_TYPE_MGM, 0); print_nodes(state, it, "mysqld", api_nodes, NDB_MGM_NODE_TYPE_API, 0); // ndbout << helpTextShow; return; - } else if (strcmp(parameters, "PROPERTIES") == 0 || - strcmp(parameters, "PROP") == 0) { + } else if (strcasecmp(parameters, "PROPERTIES") == 0 || + strcasecmp(parameters, "PROP") == 0) { ndbout << "SHOW PROPERTIES is not yet implemented." << endl; // ndbout << "_mgmtSrvr.getConfig()->print();" << endl; /* XXX */ - } else if (strcmp(parameters, "CONFIGURATION") == 0 || - strcmp(parameters, "CONFIG") == 0){ + } else if (strcasecmp(parameters, "CONFIGURATION") == 0 || + strcasecmp(parameters, "CONFIG") == 0){ ndbout << "SHOW CONFIGURATION is not yet implemented." << endl; //nbout << "_mgmtSrvr.getConfig()->printConfigFile();" << endl; /* XXX */ - } else if (strcmp(parameters, "PARAMETERS") == 0 || - strcmp(parameters, "PARAMS") == 0 || - strcmp(parameters, "PARAM") == 0) { + } else if (strcasecmp(parameters, "PARAMETERS") == 0 || + strcasecmp(parameters, "PARAMS") == 0 || + strcasecmp(parameters, "PARAM") == 0) { ndbout << "SHOW PARAMETERS is not yet implemented." << endl; // ndbout << "_mgmtSrvr.getConfig()->getConfigInfo()->print();" // << endl; /* XXX */ @@ -1099,6 +1117,20 @@ CommandInterpreter::executeShow(char* parameters) } } +void +CommandInterpreter::executeConnect(char* parameters) +{ + disconnect(); + if (!emptyString(parameters)) { + if (ndb_mgm_set_connectstring(m_mgmsrv, + BaseString(parameters).trim().c_str())) + { + printError(); + return; + } + } + connect(); +} //***************************************************************************** //***************************************************************************** @@ -1106,7 +1138,6 @@ void CommandInterpreter::executeClusterLog(char* parameters) { int i; - connect(); if (parameters != 0 && strlen(parameters) != 0) { enum ndb_mgm_clusterlog_level severity = NDB_MGM_CLUSTERLOG_ALL; int isOk = true; @@ -1121,7 +1152,7 @@ CommandInterpreter::executeClusterLog(char* parameters) /******************** * CLUSTERLOG FILTER ********************/ - if (strcmp(item, "FILTER") == 0) { + if (strcasecmp(item, "FILTER") == 0) { item = strtok_r(NULL, " ", &tmpPtr); if (item == NULL) { @@ -1130,21 +1161,21 @@ CommandInterpreter::executeClusterLog(char* parameters) while (item != NULL) { snprintf(name, sizeof(name), item); - if (strcmp(item, "ALL") == 0) { + if (strcasecmp(item, "ALL") == 0) { severity = NDB_MGM_CLUSTERLOG_ALL; - } else if (strcmp(item, "ALERT") == 0) { + } else if (strcasecmp(item, "ALERT") == 0) { severity = NDB_MGM_CLUSTERLOG_ALERT; - } else if (strcmp(item, "CRITICAL") == 0) { + } else if (strcasecmp(item, "CRITICAL") == 0) { severity = NDB_MGM_CLUSTERLOG_CRITICAL; - } else if (strcmp(item, "ERROR") == 0) { + } else if (strcasecmp(item, "ERROR") == 0) { severity = NDB_MGM_CLUSTERLOG_ERROR; - } else if (strcmp(item, "WARNING") == 0) { + } else if (strcasecmp(item, "WARNING") == 0) { severity = NDB_MGM_CLUSTERLOG_WARNING; - } else if (strcmp(item, "INFO") == 0) { + } else if (strcasecmp(item, "INFO") == 0) { severity = NDB_MGM_CLUSTERLOG_INFO; - } else if (strcmp(item, "DEBUG") == 0) { + } else if (strcasecmp(item, "DEBUG") == 0) { severity = NDB_MGM_CLUSTERLOG_DEBUG; - } else if (strcmp(item, "OFF") == 0) { + } else if (strcasecmp(item, "OFF") == 0) { severity = NDB_MGM_CLUSTERLOG_OFF; } else { isOk = false; @@ -1157,17 +1188,17 @@ CommandInterpreter::executeClusterLog(char* parameters) ndbout << "Missing argument(s)." << endl; } else if (isOk) { if(ndb_mgm_filter_clusterlog(m_mgmsrv, severity, NULL)) { - if(strcmp(name, "ALL") == 0 || strcmp(name, "all") == 0) { + if(strcasecmp(name, "ALL") == 0) { ndbout << "All severities levels enabled." << endl; - } else if(strcmp(name, "OFF") == 0 || strcmp(name, "off") == 0) { + } else if(strcasecmp(name, "OFF") == 0) { ndbout << "Cluster logging enabled." << endl; } else { ndbout << name << " events disabled." << endl; } } else { - if(strcmp(name, "ALL") == 0) { + if(strcasecmp(name, "ALL") == 0) { ndbout << "All severities levels disabled." << endl; - } else if(strcmp(name, "OFF") == 0) { + } else if(strcasecmp(name, "OFF") == 0) { ndbout << "Cluster logging disabled." << endl; } else { ndbout << name << " events enabled." << endl; @@ -1180,7 +1211,7 @@ CommandInterpreter::executeClusterLog(char* parameters) /******************** * CLUSTERLOG INFO ********************/ - } else if (strcmp(item, "INFO") == 0) { + } else if (strcasecmp(item, "INFO") == 0) { Uint32 *enabled = ndb_mgm_get_logfilter(m_mgmsrv); if(enabled == NULL) { ndbout << "Couldn't get status" << endl; @@ -1205,7 +1236,7 @@ CommandInterpreter::executeClusterLog(char* parameters) /******************** * CLUSTERLOG OFF ********************/ - } else if (strcmp(item, "OFF") == 0) { + } else if (strcasecmp(item, "OFF") == 0) { Uint32 *enabled = ndb_mgm_get_logfilter(m_mgmsrv); if(enabled == NULL) { ndbout << "Couldn't get status" << endl; @@ -1223,7 +1254,7 @@ CommandInterpreter::executeClusterLog(char* parameters) /******************** * CLUSTERLOG ON ********************/ - } else if (strcmp(item, "ON") == 0) { + } else if (strcasecmp(item, "ON") == 0) { Uint32 *enabled = ndb_mgm_get_logfilter(m_mgmsrv); if(enabled == NULL) { ndbout << "Could not get status" << endl; @@ -1252,7 +1283,6 @@ CommandInterpreter::executeClusterLog(char* parameters) void CommandInterpreter::executeStop(int processId, const char *, bool all) { - connect(); int result = 0; if(all) { result = ndb_mgm_stop(m_mgmsrv, 0, 0); @@ -1274,7 +1304,6 @@ CommandInterpreter::executeStop(int processId, const char *, bool all) void CommandInterpreter::executeEnterSingleUser(char* parameters) { - connect(); strtok(parameters, " "); struct ndb_mgm_reply reply; char* id = strtok(NULL, " "); @@ -1301,7 +1330,6 @@ CommandInterpreter::executeEnterSingleUser(char* parameters) void CommandInterpreter::executeExitSingleUser(char* parameters) { - connect(); int result = ndb_mgm_exit_single_user(m_mgmsrv, 0); if (result != 0) { ndbout_c("Exiting single user mode failed."); @@ -1316,7 +1344,6 @@ void CommandInterpreter::executeStart(int processId, const char* parameters, bool all) { - connect(); int result; if(all) { result = ndb_mgm_start(m_mgmsrv, 0, 0); @@ -1340,7 +1367,6 @@ void CommandInterpreter::executeRestart(int processId, const char* parameters, bool all) { - connect(); int result; int nostart = 0; int initialstart = 0; @@ -1352,11 +1378,11 @@ CommandInterpreter::executeRestart(int processId, const char* parameters, char * tmpPtr = 0; char * item = strtok_r(tmpString, " ", &tmpPtr); while(item != NULL){ - if(strcmp(item, "-N") == 0) + if(strcasecmp(item, "-N") == 0) nostart = 1; - if(strcmp(item, "-I") == 0) + if(strcasecmp(item, "-I") == 0) initialstart = 1; - if(strcmp(item, "-A") == 0) + if(strcasecmp(item, "-A") == 0) abort = 1; item = strtok_r(NULL, " ", &tmpPtr); } @@ -1386,11 +1412,10 @@ void CommandInterpreter::executeDumpState(int processId, const char* parameters, bool all) { - if(parameters == 0 || strlen(parameters) == 0){ + if(emptyString(parameters)){ ndbout << "Expected argument" << endl; return; } - connect(); Uint32 no = 0; int pars[25]; @@ -1430,7 +1455,6 @@ CommandInterpreter::executeStatus(int processId, return; } - connect(); ndb_mgm_node_status status; Uint32 startPhase, version; bool system; @@ -1481,7 +1505,6 @@ void CommandInterpreter::executeLogLevel(int processId, const char* parameters, bool all) { - connect(); (void) all; BaseString tmp(parameters); @@ -1537,7 +1560,6 @@ void CommandInterpreter::executeError(int processId, return; } - connect(); // Copy parameters since strtok will modify it char* newpar = my_strdup(parameters,MYF(MY_WME)); My_auto_ptr ap1(newpar); @@ -1589,7 +1611,7 @@ CommandInterpreter::executeTrace(int /*processId*/, int result = _mgmtSrvr.setTraceNo(processId, traceNo); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } #endif } @@ -1601,7 +1623,6 @@ void CommandInterpreter::executeLog(int processId, const char* parameters, bool all) { - connect(); struct ndb_mgm_reply reply; Vector blocks; if (! parseBlockSpecification(parameters, blocks)) { @@ -1669,7 +1690,6 @@ CommandInterpreter::executeTestOn(int processId, ndbout << "No parameters expected to this command." << endl; return; } - connect(); struct ndb_mgm_reply reply; int result = ndb_mgm_start_signallog(m_mgmsrv, processId, &reply); if (result != 0) { @@ -1688,7 +1708,6 @@ CommandInterpreter::executeTestOff(int processId, ndbout << "No parameters expected to this command." << endl; return; } - connect(); struct ndb_mgm_reply reply; int result = ndb_mgm_stop_signallog(m_mgmsrv, processId, &reply); if (result != 0) { @@ -1752,7 +1771,7 @@ CommandInterpreter::executeSet(int /*processId*/, } } else { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; if (configBackupFileUpdated && configPrimaryFileUpdated) { ndbout << "The configuration files are however updated and " << "the value will be used next time the process is restarted." @@ -1787,7 +1806,7 @@ void CommandInterpreter::executeGetStat(int /*processId*/, MgmtSrvr::Statistics statistics; int result = _mgmtSrvr.getStatistics(processId, statistics); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; return; } #endif @@ -1806,8 +1825,10 @@ CommandInterpreter::executeEventReporting(int processId, const char* parameters, bool all) { - connect(); - + if (emptyString(parameters)) { + ndbout << "Expected argument" << endl; + return; + } BaseString tmp(parameters); Vector spec; tmp.split(spec, "="); @@ -1855,10 +1876,9 @@ CommandInterpreter::executeEventReporting(int processId, /***************************************************************************** * Backup *****************************************************************************/ -void +int CommandInterpreter::executeStartBackup(char* /*parameters*/) { - connect(); struct ndb_mgm_reply reply; unsigned int backupId; @@ -1869,7 +1889,7 @@ CommandInterpreter::executeStartBackup(char* /*parameters*/) ndbout << "Start of backup failed" << endl; printError(); close(fd); - return; + return result; } char *tmp; @@ -1900,12 +1920,12 @@ CommandInterpreter::executeStartBackup(char* /*parameters*/) } while(tmp && tmp[0] != 0); close(fd); + return 0; } void CommandInterpreter::executeAbortBackup(char* parameters) { - connect(); strtok(parameters, " "); struct ndb_mgm_reply reply; char* id = strtok(NULL, "\0"); @@ -1959,7 +1979,6 @@ CommandInterpreter::executeRep(char* parameters) return; } - connect(); char * line = my_strdup(parameters,MYF(MY_WME)); My_auto_ptr ap1((char*)line); char * firstToken = strtok(line, " "); @@ -1968,7 +1987,7 @@ CommandInterpreter::executeRep(char* parameters) unsigned int repId; - if (!strcmp(firstToken, "CONNECT")) { + if (!strcasecmp(firstToken, "CONNECT")) { char * host = strtok(NULL, "\0"); for (unsigned int i = 0; i < strlen(host); ++i) { host[i] = tolower(host[i]); @@ -2003,30 +2022,30 @@ CommandInterpreter::executeRep(char* parameters) /******** * START ********/ - if (!strcmp(firstToken, "START")) { + if (!strcasecmp(firstToken, "START")) { unsigned int req; char *startType = strtok(NULL, "\0"); if (startType == NULL) { req = GrepReq::START; - } else if (!strcmp(startType, "SUBSCRIPTION")) { + } else if (!strcasecmp(startType, "SUBSCRIPTION")) { req = GrepReq::START_SUBSCR; - } else if (!strcmp(startType, "METALOG")) { + } else if (!strcasecmp(startType, "METALOG")) { req = GrepReq::START_METALOG; - } else if (!strcmp(startType, "METASCAN")) { + } else if (!strcasecmp(startType, "METASCAN")) { req = GrepReq::START_METASCAN; - } else if (!strcmp(startType, "DATALOG")) { + } else if (!strcasecmp(startType, "DATALOG")) { req = GrepReq::START_DATALOG; - } else if (!strcmp(startType, "DATASCAN")) { + } else if (!strcasecmp(startType, "DATASCAN")) { req = GrepReq::START_DATASCAN; - } else if (!strcmp(startType, "REQUESTOR")) { + } else if (!strcasecmp(startType, "REQUESTOR")) { req = GrepReq::START_REQUESTOR; - } else if (!strcmp(startType, "TRANSFER")) { + } else if (!strcasecmp(startType, "TRANSFER")) { req = GrepReq::START_TRANSFER; - } else if (!strcmp(startType, "APPLY")) { + } else if (!strcasecmp(startType, "APPLY")) { req = GrepReq::START_APPLY; - } else if (!strcmp(startType, "DELETE")) { + } else if (!strcasecmp(startType, "DELETE")) { req = GrepReq::START_DELETE; } else { ndbout_c("Illegal argument to command 'REPLICATION START'"); @@ -2046,7 +2065,7 @@ CommandInterpreter::executeRep(char* parameters) /******** * STOP ********/ - if (!strcmp(firstToken, "STOP")) { + if (!strcasecmp(firstToken, "STOP")) { unsigned int req; char *startType = strtok(NULL, " "); unsigned int epoch = 0; @@ -2056,7 +2075,7 @@ CommandInterpreter::executeRep(char* parameters) * Stop immediately */ req = GrepReq::STOP; - } else if (!strcmp(startType, "EPOCH")) { + } else if (!strcasecmp(startType, "EPOCH")) { char *strEpoch = strtok(NULL, "\0"); if(strEpoch == NULL) { ndbout_c("Epoch expected!"); @@ -2064,23 +2083,23 @@ CommandInterpreter::executeRep(char* parameters) } req = GrepReq::STOP; epoch=atoi(strEpoch); - } else if (!strcmp(startType, "SUBSCRIPTION")) { + } else if (!strcasecmp(startType, "SUBSCRIPTION")) { req = GrepReq::STOP_SUBSCR; - } else if (!strcmp(startType, "METALOG")) { + } else if (!strcasecmp(startType, "METALOG")) { req = GrepReq::STOP_METALOG; - } else if (!strcmp(startType, "METASCAN")) { + } else if (!strcasecmp(startType, "METASCAN")) { req = GrepReq::STOP_METASCAN; - } else if (!strcmp(startType, "DATALOG")) { + } else if (!strcasecmp(startType, "DATALOG")) { req = GrepReq::STOP_DATALOG; - } else if (!strcmp(startType, "DATASCAN")) { + } else if (!strcasecmp(startType, "DATASCAN")) { req = GrepReq::STOP_DATASCAN; - } else if (!strcmp(startType, "REQUESTOR")) { + } else if (!strcasecmp(startType, "REQUESTOR")) { req = GrepReq::STOP_REQUESTOR; - } else if (!strcmp(startType, "TRANSFER")) { + } else if (!strcasecmp(startType, "TRANSFER")) { req = GrepReq::STOP_TRANSFER; - } else if (!strcmp(startType, "APPLY")) { + } else if (!strcasecmp(startType, "APPLY")) { req = GrepReq::STOP_APPLY; - } else if (!strcmp(startType, "DELETE")) { + } else if (!strcasecmp(startType, "DELETE")) { req = GrepReq::STOP_DELETE; } else { ndbout_c("Illegal argument to command 'REPLICATION STOP'"); @@ -2099,7 +2118,7 @@ CommandInterpreter::executeRep(char* parameters) /********* * STATUS *********/ - if (!strcmp(firstToken, "STATUS")) { + if (!strcasecmp(firstToken, "STATUS")) { struct rep_state repstate; int result = ndb_rep_get_status(m_repserver, &repId, &reply, &repstate); @@ -2119,7 +2138,7 @@ CommandInterpreter::executeRep(char* parameters) /********* * QUERY (see repapi.h for querable counters) *********/ - if (!strcmp(firstToken, "QUERY")) { + if (!strcasecmp(firstToken, "QUERY")) { char *query = strtok(NULL, "\0"); int queryCounter=-1; if(query != NULL) { diff --git a/ndb/src/mgmclient/main.cpp b/ndb/src/mgmclient/main.cpp index 401a9198f30..84e27790705 100644 --- a/ndb/src/mgmclient/main.cpp +++ b/ndb/src/mgmclient/main.cpp @@ -30,9 +30,10 @@ extern "C" int add_history(const char *command); /* From readline directory */ #include #include +#include +#include #include #include -#include #include "ndb_mgmclient.hpp" @@ -55,17 +56,23 @@ handler(int sig){ } } - +static const char default_prompt[]= "ndb_mgm> "; static unsigned _try_reconnect; static char *opt_connect_str= 0; +static const char *prompt= default_prompt; +static char *opt_execute_str= 0; static struct my_option my_long_options[] = { NDB_STD_OPTS("ndb_mgm"), + { "execute", 'e', + "execute command and exit", + (gptr*) &opt_execute_str, (gptr*) &opt_execute_str, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { "try-reconnect", 't', - "Specify number of retries for connecting to ndb_mgmd, default infinite", + "Specify number of tries for connecting to ndb_mgmd (0 = infinite)", (gptr*) &_try_reconnect, (gptr*) &_try_reconnect, 0, - GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + GET_UINT, REQUIRED_ARG, 3, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; static void short_usage_sub(void) @@ -115,13 +122,13 @@ read_and_execute(int _try_reconnect) } #ifdef HAVE_READLINE /* Get a line from the user. */ - line_read = readline ("ndb_mgm> "); + line_read = readline (prompt); /* If the line has any text in it, save it on the history. */ if (line_read && *line_read) add_history (line_read); #else static char linebuffer[254]; - fputs("ndb_mgm> ", stdout); + fputs(prompt, stdout); linebuffer[sizeof(linebuffer)-1]=0; line_read = fgets(linebuffer, sizeof(linebuffer)-1, stdin); if (line_read == linebuffer) { @@ -138,7 +145,7 @@ int main(int argc, char** argv){ NDB_INIT(argv[0]); const char *_host = 0; int _port = 0; - const char *load_default_groups[]= { "ndb_mgm",0 }; + const char *load_default_groups[]= { "mysql_cluster","ndb_mgm",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; @@ -154,15 +161,25 @@ int main(int argc, char** argv){ opt_connect_str= buf; } - ndbout << "-- NDB Cluster -- Management Client --" << endl; - printf("Connecting to Management Server: %s\n", opt_connect_str ? opt_connect_str : "default"); + if (!isatty(0) || opt_execute_str) + { + prompt= 0; + } signal(SIGPIPE, handler); - - com = new Ndb_mgmclient(opt_connect_str); - while(read_and_execute(_try_reconnect)); + com = new Ndb_mgmclient(opt_connect_str,1); + int ret= 0; + if (!opt_execute_str) + { + ndbout << "-- NDB Cluster -- Management Client --" << endl; + while(read_and_execute(_try_reconnect)); + } + else + { + com->execute(opt_execute_str,_try_reconnect, &ret); + } delete com; - return 0; + return ret; } diff --git a/ndb/src/mgmclient/ndb_mgmclient.h b/ndb/src/mgmclient/ndb_mgmclient.h index 265e6bc67ec..b62a33999a3 100644 --- a/ndb/src/mgmclient/ndb_mgmclient.h +++ b/ndb/src/mgmclient/ndb_mgmclient.h @@ -23,7 +23,7 @@ extern "C" { typedef void* Ndb_mgmclient_handle; Ndb_mgmclient_handle ndb_mgmclient_handle_create(const char *connect_string); -int ndb_mgmclient_execute(Ndb_mgmclient_handle, int argc, const char** argv); +int ndb_mgmclient_execute(Ndb_mgmclient_handle, int argc, char** argv); int ndb_mgmclient_handle_destroy(Ndb_mgmclient_handle); #ifdef __cplusplus diff --git a/ndb/src/mgmclient/ndb_mgmclient.hpp b/ndb/src/mgmclient/ndb_mgmclient.hpp index 933d1bab5ce..bffdf69f920 100644 --- a/ndb/src/mgmclient/ndb_mgmclient.hpp +++ b/ndb/src/mgmclient/ndb_mgmclient.hpp @@ -21,10 +21,10 @@ class CommandInterpreter; class Ndb_mgmclient { public: - Ndb_mgmclient(const char*); + Ndb_mgmclient(const char*,int verbose=0); ~Ndb_mgmclient(); - int execute(const char *_line, int _try_reconnect=-1); - int execute(int argc, const char** argv, int _try_reconnect=-1); + int execute(const char *_line, int _try_reconnect=-1, int *error= 0); + int execute(int argc, char** argv, int _try_reconnect=-1, int *error= 0); int disconnect(); private: CommandInterpreter *m_cmd; diff --git a/ndb/src/mgmsrv/CommandInterpreter.cpp b/ndb/src/mgmsrv/CommandInterpreter.cpp index 2a054a01f1e..02bf24f1d9c 100644 --- a/ndb/src/mgmsrv/CommandInterpreter.cpp +++ b/ndb/src/mgmsrv/CommandInterpreter.cpp @@ -113,6 +113,11 @@ private: void * m_ptr; }; +const char *CommandInterpreter::get_error_text(int err_no) +{ + return _mgmtSrvr.getErrorText(err_no, m_err_str, sizeof(m_err_str)); +} + //***************************************************************************** //***************************************************************************** int CommandInterpreter::readAndExecute() { @@ -600,8 +605,9 @@ stopCallback(int nodeId, void * anyData, int errCode){ ndbout << "\nNode " << nodeId << " has shutdown" << endl; } else { MgmtSrvr * mgm = (MgmtSrvr *)anyData; + char err_str[1024]; ndbout << "Node " << nodeId << " has not shutdown: " - << mgm->getErrorText(errCode) << endl; + << mgm->getErrorText(errCode,err_str,sizeof(err_str)) << endl; } } @@ -653,7 +659,8 @@ versionCallback(int nodeId, int version, void * anyData, int errCode){ } else { MgmtSrvr * mgm = (MgmtSrvr *)anyData; - ndbout << mgm->getErrorText(errCode) << endl; + char err_str[1024]; + ndbout << mgm->getErrorText(errCode,err_str,sizeof(err_str)) << endl; } } @@ -671,7 +678,7 @@ void CommandInterpreter::executeStop(int processId, result = _mgmtSrvr.stopNode(processId, false, stopCallback, this); if(result != 0) - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } @@ -686,7 +693,7 @@ void CommandInterpreter::executeStart(int processId, const char* parameters, int result = _mgmtSrvr.start(processId); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } } @@ -719,7 +726,7 @@ CommandInterpreter::executeRestart(int processId, const char* parameters, stopCallback, this); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } } @@ -760,7 +767,7 @@ CommandInterpreter::executeDumpState(int processId, const char* parameters, free(tmpString); int result = _mgmtSrvr.dumpState(processId, pars, no); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } } @@ -781,7 +788,7 @@ void CommandInterpreter::executeStatus(int processId, &status, &version, &startPhase, &system, &dynamicId, &nodeGroup, &connectCount); if(result != 0){ - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; return; } @@ -875,7 +882,7 @@ void CommandInterpreter::executeLogLevel(int processId, int result = _mgmtSrvr.setNodeLogLevel(processId, logLevel); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } #endif } @@ -913,7 +920,7 @@ void CommandInterpreter::executeError(int processId, int result = _mgmtSrvr.insertError(processId, errorNo); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } free(newpar); } @@ -953,7 +960,7 @@ void CommandInterpreter::executeTrace(int processId, int result = _mgmtSrvr.setTraceNo(processId, traceNo); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } free(newpar); } @@ -974,7 +981,7 @@ void CommandInterpreter::executeLog(int processId, int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::InOut, blocks); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } } @@ -995,7 +1002,7 @@ void CommandInterpreter::executeLogIn(int processId, int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::In, blocks); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } } @@ -1014,7 +1021,7 @@ void CommandInterpreter::executeLogOut(int processId, int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::Out, blocks); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } } @@ -1035,7 +1042,7 @@ void CommandInterpreter::executeLogOff(int processId, int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::Off, blocks); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } } @@ -1054,7 +1061,7 @@ void CommandInterpreter::executeTestOn(int processId, int result = _mgmtSrvr.startSignalTracing(processId); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } } @@ -1073,7 +1080,7 @@ void CommandInterpreter::executeTestOff(int processId, int result = _mgmtSrvr.stopSignalTracing(processId); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } } @@ -1126,7 +1133,7 @@ void CommandInterpreter::executeEventReporting(int processId, ndbout_c("processId %d", processId); int result = _mgmtSrvr.setEventReportingLevel(processId, logLevel); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } #endif } @@ -1136,7 +1143,7 @@ CommandInterpreter::executeStartBackup(char* parameters) { Uint32 backupId; int result = _mgmtSrvr.startBackup(backupId); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } else { // ndbout << "Start of backup ordered" << endl; } @@ -1153,7 +1160,7 @@ CommandInterpreter::executeAbortBackup(char* parameters) { } int result = _mgmtSrvr.abortBackup(bid); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } else { ndbout << "Abort of backup " << bid << " ordered" << endl; } @@ -1174,7 +1181,7 @@ CommandInterpreter::executeEnterSingleUser(char* parameters) { } int result = _mgmtSrvr.enterSingleUser(0, nodeId,0,0); if (result != 0) { - ndbout << _mgmtSrvr.getErrorText(result) << endl; + ndbout << get_error_text(result) << endl; } else { ndbout << "Entering single user mode, granting access for node " << nodeId << " OK." << endl; diff --git a/ndb/src/mgmsrv/CommandInterpreter.hpp b/ndb/src/mgmsrv/CommandInterpreter.hpp index db23f76a5bd..1a5184361d6 100644 --- a/ndb/src/mgmsrv/CommandInterpreter.hpp +++ b/ndb/src/mgmsrv/CommandInterpreter.hpp @@ -55,6 +55,9 @@ public: int readAndExecute(); private: + char m_err_str[1024]; + const char *get_error_text(int err_no); + /** * Read a string, and return a pointer to it. * diff --git a/ndb/src/mgmsrv/InitConfigFileParser.cpp b/ndb/src/mgmsrv/InitConfigFileParser.cpp index fdfe7823fc2..05102255eaa 100644 --- a/ndb/src/mgmsrv/InitConfigFileParser.cpp +++ b/ndb/src/mgmsrv/InitConfigFileParser.cpp @@ -213,48 +213,41 @@ InitConfigFileParser::parseConfig(FILE * file) { // Parse Name-Value Pair //**************************************************************************** -bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line) { - - char tmpLine[MAX_LINE_LENGTH]; - char fname[MAX_LINE_LENGTH], rest[MAX_LINE_LENGTH]; - char* t; - const char *separator_list[]= {":", "=", 0}; - const char *separator= 0; - +bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line) +{ if (ctx.m_currentSection == NULL){ ctx.reportError("Value specified outside section"); return false; } - strncpy(tmpLine, line, MAX_LINE_LENGTH); - // ************************************* - // Check if a separator exists in line + // Split string at first occurrence of + // '=' or ':' // ************************************* - for(int i= 0; separator_list[i] != 0; i++) { - if(strchr(tmpLine, separator_list[i][0])) { - separator= separator_list[i]; - break; - } - } - if (separator == 0) { + Vector tmp_string_split; + if (BaseString(line).split(tmp_string_split, + BaseString("=:"), + 2) != 2) + { ctx.reportError("Parse error"); return false; } - // ******************************************* - // Get pointer to substring before separator - // ******************************************* - t = strtok(tmpLine, separator); - - // ***************************************** - // Count number of tokens before separator - // ***************************************** - if (sscanf(t, "%120s%120s", fname, rest) != 1) { - ctx.reportError("Multiple names before \'%c\'", separator[0]); - return false; + // ************************************* + // Remove leading and trailing chars + // ************************************* + { + for (int i = 0; i < 2; i++) + tmp_string_split[i].trim("\r\n \t"); } + + // ************************************* + // First in split is fname + // ************************************* + + const char *fname= tmp_string_split[0].c_str(); + if (!ctx.m_currentInfo->contains(fname)) { ctx.reportError("[%s] Unknown parameter: %s", ctx.fname, fname); return false; @@ -273,24 +266,11 @@ bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line) { } } - // ****************************************** - // Get pointer to substring after separator - // ****************************************** - t = strtok(NULL, "\0"); - if (t == NULL) { - ctx.reportError("No value for parameter"); - return false; - } - - // ****************************************** - // Remove prefix and postfix spaces and tabs - // ******************************************* - trim(t); - // *********************** // Store name-value pair // *********************** - return storeNameValuePair(ctx, fname, t); + + return storeNameValuePair(ctx, fname, tmp_string_split[1].c_str()); } diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index a49b29af275..061aa2e0cb8 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -49,6 +49,8 @@ #include +#include + #include #include #include @@ -264,16 +266,6 @@ MgmtSrvr::isEventLogFilterEnabled(int severity) static ErrorItem errorTable[] = { - {200, "Backup undefined error"}, - {202, "Backup failed to allocate buffers (check configuration)"}, - {203, "Backup failed to setup fs buffers (check configuration)"}, - {204, "Backup failed to allocate tables (check configuration)"}, - {205, "Backup failed to insert file header (check configuration)"}, - {206, "Backup failed to insert table list (check configuration)"}, - {207, "Backup failed to allocate table memory (check configuration)"}, - {208, "Backup failed to allocate file record (check configuration)"}, - {209, "Backup failed to allocate attribute record (check configuration)"}, - {MgmtSrvr::NO_CONTACT_WITH_PROCESS, "No contact with the process (dead ?)."}, {MgmtSrvr::PROCESS_NOT_CONFIGURED, "The process is not configured."}, {MgmtSrvr::WRONG_PROCESS_TYPE, @@ -399,16 +391,20 @@ MgmtSrvr::getPort() const { } /* Constructor */ -MgmtSrvr::MgmtSrvr(NodeId nodeId, - SocketServer *socket_server, - const BaseString &configFilename, - LocalConfig &local_config, - Config * config): +int MgmtSrvr::init() +{ + if ( _ownNodeId > 0) + return 0; + return -1; +} + +MgmtSrvr::MgmtSrvr(SocketServer *socket_server, + const char *config_filename, + const char *connect_string) : _blockNumber(1), // Hard coded block number since it makes it easy to send // signals to other management servers. m_socket_server(socket_server), _ownReference(0), - m_local_config(local_config), theSignalIdleList(NULL), theWaitState(WAIT_SUBSCRIBE_CONF), m_statisticsListner(this) @@ -416,6 +412,8 @@ MgmtSrvr::MgmtSrvr(NodeId nodeId, DBUG_ENTER("MgmtSrvr::MgmtSrvr"); + _ownNodeId= 0; + _config = NULL; _isStopThread = false; @@ -426,12 +424,48 @@ MgmtSrvr::MgmtSrvr(NodeId nodeId, theFacade = 0; m_newConfig = NULL; - m_configFilename = configFilename; + if (config_filename) + m_configFilename.assign(config_filename); + else + m_configFilename.assign("config.ini"); m_nextConfigGenerationNumber = 0; - _config = (config == 0 ? readConfig() : config); - + m_config_retriever= new ConfigRetriever(connect_string, + NDB_VERSION, NDB_MGM_NODE_TYPE_MGM); + // if connect_string explicitly given or + // no config filename is given then + // first try to allocate nodeid from another management server + if ((connect_string || config_filename == NULL) && + (m_config_retriever->do_connect(0,0,0) == 0)) + { + int tmp_nodeid= 0; + tmp_nodeid= m_config_retriever->allocNodeId(0 /*retry*/,0 /*delay*/); + if (tmp_nodeid == 0) + { + ndbout_c(m_config_retriever->getErrorString()); + exit(-1); + } + // read config from other managent server + _config= fetchConfig(); + if (_config == 0) + { + ndbout << m_config_retriever->getErrorString() << endl; + exit(-1); + } + _ownNodeId= tmp_nodeid; + } + + if (_ownNodeId == 0) + { + // read config locally + _config= readConfig(); + if (_config == 0) { + ndbout << "Unable to read config file" << endl; + exit(-1); + } + } + theMgmtWaitForResponseCondPtr = NdbCondition_Create(); m_configMutex = NdbMutex_Create(); @@ -443,9 +477,11 @@ MgmtSrvr::MgmtSrvr(NodeId nodeId, nodeTypes[i] = (enum ndb_mgm_node_type)-1; m_connect_address[i].s_addr= 0; } + { - ndb_mgm_configuration_iterator * iter = ndb_mgm_create_configuration_iterator - (config->m_configValues, CFG_SECTION_NODE); + ndb_mgm_configuration_iterator + *iter = ndb_mgm_create_configuration_iterator(_config->m_configValues, + CFG_SECTION_NODE); for(ndb_mgm_first(iter); ndb_mgm_valid(iter); ndb_mgm_next(iter)){ unsigned type, id; if(ndb_mgm_get_int_parameter(iter, CFG_TYPE_OF_SECTION, &type) != 0) @@ -478,8 +514,6 @@ MgmtSrvr::MgmtSrvr(NodeId nodeId, } _props = NULL; - _ownNodeId= 0; - NodeId tmp= nodeId; BaseString error_string; if ((m_node_id_mutex = NdbMutex_Create()) == 0) @@ -488,43 +522,25 @@ MgmtSrvr::MgmtSrvr(NodeId nodeId, exit(-1); } -#if 0 - char my_hostname[256]; - struct sockaddr_in tmp_addr; - SOCKET_SIZE_TYPE addrlen= sizeof(tmp_addr); - if (!g_no_nodeid_checks) { - if (gethostname(my_hostname, sizeof(my_hostname))) { - ndbout << "error: gethostname() - " << strerror(errno) << endl; - exit(-1); - } - if (Ndb_getInAddr(&(((sockaddr_in*)&tmp_addr)->sin_addr),my_hostname)) { - ndbout << "error: Ndb_getInAddr(" << my_hostname << ") - " - << strerror(errno) << endl; + if (_ownNodeId == 0) // we did not get node id from other server + { + NodeId tmp= m_config_retriever->get_configuration_nodeid(); + + if (!alloc_node_id(&tmp, NDB_MGM_NODE_TYPE_MGM, + 0, 0, error_string)){ + ndbout << "Unable to obtain requested nodeid: " + << error_string.c_str() << endl; exit(-1); } + _ownNodeId = tmp; } - if (!alloc_node_id(&tmp, NDB_MGM_NODE_TYPE_MGM, - (struct sockaddr *)&tmp_addr, - &addrlen, error_string)){ - ndbout << "Unable to obtain requested nodeid: " - << error_string.c_str() << endl; - exit(-1); - } -#else - if (!alloc_node_id(&tmp, NDB_MGM_NODE_TYPE_MGM, - 0, 0, error_string)){ - ndbout << "Unable to obtain requested nodeid: " - << error_string.c_str() << endl; - exit(-1); - } -#endif - _ownNodeId = tmp; { DBUG_PRINT("info", ("verifyConfig")); - ConfigRetriever cr(m_local_config, NDB_VERSION, NDB_MGM_NODE_TYPE_MGM); - if (!cr.verifyConfig(config->m_configValues, _ownNodeId)) { - ndbout << cr.getErrorString() << endl; + if (!m_config_retriever->verifyConfig(_config->m_configValues, + _ownNodeId)) + { + ndbout << m_config_retriever->getErrorString() << endl; exit(-1); } } @@ -657,6 +673,8 @@ MgmtSrvr::~MgmtSrvr() NdbThread_WaitFor(m_signalRecvThread, &res); NdbThread_Destroy(&m_signalRecvThread); } + if (m_config_retriever) + delete m_config_retriever; } //**************************************************************************** @@ -1830,18 +1848,21 @@ MgmtSrvr::dumpState(int processId, const Uint32 args[], Uint32 no) //**************************************************************************** //**************************************************************************** -const char* MgmtSrvr::getErrorText(int errorCode) +const char* MgmtSrvr::getErrorText(int errorCode, char *buf, int buf_sz) { - static char text[255]; for (int i = 0; i < noOfErrorCodes; ++i) { if (errorCode == errorTable[i]._errorCode) { - return errorTable[i]._errorText; + BaseString::snprintf(buf, buf_sz, errorTable[i]._errorText); + buf[buf_sz-1]= 0; + return buf; } } - - BaseString::snprintf(text, 255, "Unknown management server error code %d", errorCode); - return text; + + ndb_error_string(errorCode, buf, buf_sz); + buf[buf_sz-1]= 0; + + return buf; } void diff --git a/ndb/src/mgmsrv/MgmtSrvr.hpp b/ndb/src/mgmsrv/MgmtSrvr.hpp index b3257491123..1afb0848ecc 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.hpp +++ b/ndb/src/mgmsrv/MgmtSrvr.hpp @@ -175,11 +175,10 @@ public: /* Constructor */ - MgmtSrvr(NodeId nodeId, /* Local nodeid */ - SocketServer *socket_server, - const BaseString &config_filename, /* Where to save config */ - LocalConfig &local_config, /* Ndb.cfg filename */ - Config * config); + MgmtSrvr(SocketServer *socket_server, + const char *config_filename, /* Where to save config */ + const char *connect_string); + int init(); NodeId getOwnNodeId() const {return _ownNodeId;}; /** @@ -467,7 +466,7 @@ public: * @param errorCode: Error code to get a match error text for. * @return The error text. */ - const char* getErrorText(int errorCode); + const char* getErrorText(int errorCode, char *buf, int buf_sz); /** * Get configuration @@ -538,7 +537,6 @@ private: NdbMutex *m_configMutex; const Config * _config; Config * m_newConfig; - LocalConfig &m_local_config; BaseString m_configFilename; Uint32 m_nextConfigGenerationNumber; @@ -755,6 +753,9 @@ private: Config *_props; int send(class NdbApiSignal* signal, Uint32 node, Uint32 node_type); + + ConfigRetriever *m_config_retriever; + public: /** * This method does not exist diff --git a/ndb/src/mgmsrv/MgmtSrvrConfig.cpp b/ndb/src/mgmsrv/MgmtSrvrConfig.cpp index 1d51061e909..6c4b4e9ae3c 100644 --- a/ndb/src/mgmsrv/MgmtSrvrConfig.cpp +++ b/ndb/src/mgmsrv/MgmtSrvrConfig.cpp @@ -272,30 +272,20 @@ MgmtSrvr::saveConfig(const Config *conf) { Config * MgmtSrvr::readConfig() { - Config *conf = NULL; - if(m_configFilename.length() != 0) { - /* Use config file */ - InitConfigFileParser parser; - conf = parser.parseConfig(m_configFilename.c_str()); - - if(conf == NULL) { - /* Try to get configuration from other MGM server */ - return fetchConfig(); - } - } + Config *conf; + InitConfigFileParser parser; + conf = parser.parseConfig(m_configFilename.c_str()); return conf; } Config * MgmtSrvr::fetchConfig() { - ConfigRetriever cr(m_local_config, NDB_VERSION, NODE_TYPE_MGM); - struct ndb_mgm_configuration * tmp = cr.getConfig(); + struct ndb_mgm_configuration * tmp = m_config_retriever->getConfig(); if(tmp != 0){ Config * conf = new Config(); conf->m_configValues = tmp; return conf; } - return 0; } diff --git a/ndb/src/mgmsrv/Services.cpp b/ndb/src/mgmsrv/Services.cpp index 0394c4e80bb..5834d40cc78 100644 --- a/ndb/src/mgmsrv/Services.cpp +++ b/ndb/src/mgmsrv/Services.cpp @@ -244,6 +244,8 @@ ParserRow commands[] = { MGM_CMD("purge stale sessions", &MgmApiSession::purge_stale_sessions, ""), + MGM_CMD("check connection", &MgmApiSession::check_connection, ""), + MGM_END() }; @@ -579,7 +581,7 @@ MgmApiSession::insertError(Parser::Context &, m_output->println("insert error reply"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else m_output->println("result: Ok"); m_output->println(""); @@ -597,7 +599,7 @@ MgmApiSession::setTrace(Parser::Context &, m_output->println("set trace reply"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else m_output->println("result: Ok"); m_output->println(""); @@ -665,7 +667,7 @@ MgmApiSession::startBackup(Parser::Context &, m_output->println("start backup reply"); if(result != 0) - m_output->println("result: %s(%d)", m_mgmsrv.getErrorText(result), result); + m_output->println("result: %s(%d)", get_error_text(result), result); else{ m_output->println("result: Ok"); m_output->println("id: %d", backupId); @@ -685,7 +687,7 @@ MgmApiSession::startBackup(Parser::Context &, m_output->println("start backup reply"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else{ m_output->println("result: Ok"); m_output->println("id: %d", backupId); @@ -705,7 +707,7 @@ MgmApiSession::abortBackup(Parser::Context &, m_output->println("abort backup reply"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else m_output->println("result: Ok"); m_output->println(""); @@ -727,7 +729,7 @@ MgmApiSession::repCommand(Parser::Context &, m_output->println("global replication reply"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else{ m_output->println("result: Ok"); m_output->println("id: %d", repReqId); @@ -749,7 +751,7 @@ MgmApiSession::dumpState(Parser::Context &, int result = m_mgmsrv.dumpState(node, args_str.c_str()); m_output->println("dump state reply"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else m_output->println("result: Ok"); m_output->println(""); @@ -834,7 +836,7 @@ MgmApiSession::stopSignalLog(Parser::Context &, m_output->println("stop signallog"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else m_output->println("result: Ok"); m_output->println(""); @@ -874,7 +876,7 @@ MgmApiSession::restart(Parser::Context &, m_output->println("restart reply"); if(result != 0){ - m_output->println("result: %d-%s", result, m_mgmsrv.getErrorText(result)); + m_output->println("result: %d-%s", result, get_error_text(result)); } else m_output->println("result: Ok"); m_output->println("restarted: %d", restarted); @@ -898,7 +900,7 @@ MgmApiSession::restartAll(Parser::Context &, m_output->println("restart reply"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else m_output->println("result: Ok"); m_output->println("restarted: %d", count); @@ -1029,7 +1031,7 @@ MgmApiSession::stop(Parser::Context &, m_output->println("stop reply"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else m_output->println("result: Ok"); m_output->println("stopped: %d", stopped); @@ -1051,7 +1053,7 @@ MgmApiSession::stopAll(Parser::Context &, m_output->println("stop reply"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else m_output->println("result: Ok"); m_output->println("stopped: %d", stopped); @@ -1067,7 +1069,7 @@ MgmApiSession::enterSingleUser(Parser::Context &, int result = m_mgmsrv.enterSingleUser(&stopped, nodeId); m_output->println("enter single user reply"); if(result != 0) { - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); } else { m_output->println("result: Ok"); @@ -1082,7 +1084,7 @@ MgmApiSession::exitSingleUser(Parser::Context &, int result = m_mgmsrv.exitSingleUser(&stopped, false); m_output->println("exit single user reply"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else m_output->println("result: Ok"); m_output->println(""); @@ -1100,7 +1102,7 @@ MgmApiSession::startSignalLog(Parser::Context &, m_output->println("start signallog reply"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else m_output->println("result: Ok"); m_output->println(""); @@ -1145,7 +1147,7 @@ MgmApiSession::logSignals(Parser::Context &, m_output->println("log signals reply"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else m_output->println("result: Ok"); m_output->println(""); @@ -1162,7 +1164,7 @@ MgmApiSession::start(Parser::Context &, m_output->println("start reply"); if(result != 0) - m_output->println("result: %s", m_mgmsrv.getErrorText(result)); + m_output->println("result: %s", get_error_text(result)); else m_output->println("result: Ok"); m_output->println(""); @@ -1454,6 +1456,15 @@ MgmApiSession::purge_stale_sessions(Parser_t::Context &ctx, m_output->println(""); } +void +MgmApiSession::check_connection(Parser_t::Context &ctx, + const class Properties &args) +{ + m_output->println("check connection reply"); + m_output->println("result: Ok"); + m_output->println(""); +} + template class MutexVector; template class Vector const*>; template class Vector; diff --git a/ndb/src/mgmsrv/Services.hpp b/ndb/src/mgmsrv/Services.hpp index bfc915f18f1..6a5f06a659e 100644 --- a/ndb/src/mgmsrv/Services.hpp +++ b/ndb/src/mgmsrv/Services.hpp @@ -39,10 +39,13 @@ private: OutputStream *m_output; Parser_t *m_parser; MgmtSrvr::Allocated_resources *m_allocated_resources; + char m_err_str[1024]; void getConfig_common(Parser_t::Context &ctx, const class Properties &args, bool compat = false); + const char *get_error_text(int err_no) + { return m_mgmsrv.getErrorText(err_no, m_err_str, sizeof(m_err_str)); } public: MgmApiSession(class MgmtSrvr & mgm, NDB_SOCKET_TYPE sock); @@ -88,6 +91,7 @@ public: void listen_event(Parser_t::Context &ctx, const class Properties &args); void purge_stale_sessions(Parser_t::Context &ctx, const class Properties &args); + void check_connection(Parser_t::Context &ctx, const class Properties &args); void repCommand(Parser_t::Context &ctx, const class Properties &args); }; diff --git a/ndb/src/mgmsrv/main.cpp b/ndb/src/mgmsrv/main.cpp index 76f0679b069..400a5301a19 100644 --- a/ndb/src/mgmsrv/main.cpp +++ b/ndb/src/mgmsrv/main.cpp @@ -62,7 +62,6 @@ struct MgmGlobals { int non_interactive; int interactive; const char * config_filename; - const char * local_config_filename; /** Stuff found in environment or in local config */ NodeId localNodeId; @@ -70,9 +69,6 @@ struct MgmGlobals { char * interface_name; int port; - /** The configuration of the cluster */ - Config * cluster_config; - /** The Mgmt Server */ MgmtSrvr * mgmObject; @@ -86,9 +82,6 @@ static MgmGlobals glob; /****************************************************************************** * Function prototypes ******************************************************************************/ -static bool readLocalConfig(); -static bool readGlobalConfig(); - /** * Global variables */ @@ -110,10 +103,14 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, { "version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 }, - { "connect-string", 1023, + { "ndb-connectstring", 1023, "Set connect string for connecting to ndb_mgmd. " - "=\"host=[;nodeid=]\". " - "Overides specifying entries in NDB_CONNECTSTRING and config file", + "Syntax: \"[nodeid=;][host=][:]\". " + "Overides specifying entries in NDB_CONNECTSTRING and Ndb.cfg", + (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + { "connect-string", 1023, + "same as --ndb-connectstring.", (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { "config-file", 'f', "Specify cluster configuration file", @@ -122,9 +119,6 @@ static struct my_option my_long_options[] = { "daemon", 'd', "Run ndb_mgmd in daemon mode (default)", (gptr*) &glob.daemon, (gptr*) &glob.daemon, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 }, - { "l", 'l', "Specify configuration file connect string (default Ndb.cfg if available)", - (gptr*) &glob.local_config_filename, (gptr*) &glob.local_config_filename, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { "interactive", 256, "Run interactive. Not supported but provided for testing purposes", (gptr*) &glob.interactive, (gptr*) &glob.interactive, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, @@ -194,9 +188,8 @@ int main(int argc, char** argv) #endif global_mgmt_server_check = 1; - glob.config_filename= "config.ini"; - const char *load_default_groups[]= { "ndb_mgmd",0 }; + const char *load_default_groups[]= { "mysql_cluster","ndb_mgmd",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; @@ -212,29 +205,16 @@ int main(int argc, char** argv) MgmApiService * mapi = new MgmApiService(); - /**************************** - * Read configuration files * - ****************************/ - LocalConfig local_config; - if(!local_config.init(opt_connect_str,glob.local_config_filename)){ - local_config.printError(); - goto error_end; - } - glob.localNodeId = local_config._ownNodeId; + glob.mgmObject = new MgmtSrvr(glob.socketServer, + glob.config_filename, + opt_connect_str); - if (!readGlobalConfig()) + if (glob.mgmObject->init()) goto error_end; - glob.mgmObject = new MgmtSrvr(glob.localNodeId, glob.socketServer, - BaseString(glob.config_filename), - local_config, - glob.cluster_config); - chdir(NdbConfig_get_path(0)); - glob.cluster_config = 0; glob.localNodeId= glob.mgmObject->getOwnNodeId(); - if (glob.localNodeId == 0) { goto error_end; } @@ -345,9 +325,7 @@ MgmGlobals::MgmGlobals(){ // Default values port = 0; config_filename = NULL; - local_config_filename = NULL; interface_name = 0; - cluster_config = 0; daemon = 1; non_interactive = 0; interactive = 0; @@ -360,27 +338,6 @@ MgmGlobals::~MgmGlobals(){ delete socketServer; if (mgmObject) delete mgmObject; - if (cluster_config) - delete cluster_config; if (interface_name) free(interface_name); } - -/** - * @fn readGlobalConfig - * @param glob : Global variables - * @return true if success, false otherwise. - */ -static bool -readGlobalConfig() { - if(glob.config_filename == NULL) - return false; - - /* Use config file */ - InitConfigFileParser parser; - glob.cluster_config = parser.parseConfig(glob.config_filename); - if(glob.cluster_config == 0){ - return false; - } - return true; -} diff --git a/ndb/src/ndbapi/NdbConnection.cpp b/ndb/src/ndbapi/NdbConnection.cpp index 4f6468eb4ae..f4bb000300a 100644 --- a/ndb/src/ndbapi/NdbConnection.cpp +++ b/ndb/src/ndbapi/NdbConnection.cpp @@ -55,6 +55,7 @@ NdbConnection::NdbConnection( Ndb* aNdb ) : theFirstExecOpInList(NULL), theLastExecOpInList(NULL), theCompletedFirstOp(NULL), + theCompletedLastOp(NULL), theNoOfOpSent(0), theNoOfOpCompleted(0), theNoOfOpFetched(0), @@ -124,6 +125,7 @@ NdbConnection::init() theLastExecOpInList = NULL; theCompletedFirstOp = NULL; + theCompletedLastOp = NULL; theGlobalCheckpointId = 0; theCommitStatus = Started; @@ -256,6 +258,8 @@ NdbConnection::handleExecuteCompletion() if (tLastExecOp != NULL) { tLastExecOp->next(theCompletedFirstOp); theCompletedFirstOp = tFirstExecOp; + if (theCompletedLastOp == NULL) + theCompletedLastOp = tLastExecOp; theFirstExecOpInList = NULL; theLastExecOpInList = NULL; }//if @@ -292,6 +296,8 @@ NdbConnection::execute(ExecType aTypeOfExec, ExecType tExecType; NdbOperation* tPrepOp; + NdbOperation* tCompletedFirstOp = NULL; + NdbOperation* tCompletedLastOp = NULL; int ret = 0; do { @@ -314,6 +320,7 @@ NdbConnection::execute(ExecType aTypeOfExec, } tPrepOp = tPrepOp->next(); } + // save rest of prepared ops if batch NdbOperation* tRestOp= 0; NdbOperation* tLastOp= 0; @@ -323,6 +330,7 @@ NdbConnection::execute(ExecType aTypeOfExec, tLastOp = theLastOpInList; theLastOpInList = tPrepOp; } + if (tExecType == Commit) { NdbOperation* tOp = theCompletedFirstOp; while (tOp != NULL) { @@ -338,6 +346,19 @@ NdbConnection::execute(ExecType aTypeOfExec, } } + // completed ops are in unspecified order + if (theCompletedFirstOp != NULL) { + if (tCompletedFirstOp == NULL) { + tCompletedFirstOp = theCompletedFirstOp; + tCompletedLastOp = theCompletedLastOp; + } else { + tCompletedLastOp->next(theCompletedFirstOp); + tCompletedLastOp = theCompletedLastOp; + } + theCompletedFirstOp = NULL; + theCompletedLastOp = NULL; + } + if (executeNoBlobs(tExecType, abortOption, forceSend) == -1) ret = -1; #ifndef VM_TRACE @@ -362,6 +383,7 @@ NdbConnection::execute(ExecType aTypeOfExec, tOp = tOp->next(); } } + // add saved prepared ops if batch if (tPrepOp != NULL && tRestOp != NULL) { if (theFirstOpInList == NULL) @@ -373,6 +395,18 @@ NdbConnection::execute(ExecType aTypeOfExec, assert(theFirstOpInList == NULL || tExecType == NoCommit); } while (theFirstOpInList != NULL || tExecType != aTypeOfExec); + if (tCompletedFirstOp != NULL) { + tCompletedLastOp->next(theCompletedFirstOp); + theCompletedFirstOp = tCompletedFirstOp; + if (theCompletedLastOp == NULL) + theCompletedLastOp = tCompletedLastOp; + } +#if ndb_api_count_completed_ops_after_blob_execute + { NdbOperation* tOp; unsigned n = 0; + for (tOp = theCompletedFirstOp; tOp != NULL; tOp = tOp->next()) n++; + ndbout << "completed ops: " << n << endl; + } +#endif DBUG_RETURN(ret); } @@ -894,6 +928,7 @@ NdbConnection::releaseOperations() releaseOps(theFirstExecOpInList); theCompletedFirstOp = NULL; + theCompletedLastOp = NULL; theFirstOpInList = NULL; theFirstExecOpInList = NULL; theLastOpInList = NULL; @@ -909,6 +944,7 @@ NdbConnection::releaseCompletedOperations() { releaseOps(theCompletedFirstOp); theCompletedFirstOp = NULL; + theCompletedLastOp = NULL; }//NdbConnection::releaseOperations() /****************************************************************************** @@ -1086,8 +1122,11 @@ NdbConnection::getNdbIndexScanOperation(const NdbIndexImpl* index, if (indexTable != 0){ NdbIndexScanOperation* tOp = getNdbScanOperation((NdbTableImpl *) indexTable); - tOp->m_currentTable = table; - if(tOp) tOp->m_cursor_type = NdbScanOperation::IndexCursor; + if(tOp) + { + tOp->m_currentTable = table; + tOp->m_cursor_type = NdbScanOperation::IndexCursor; + } return tOp; } else { setOperationErrorCodeAbort(theNdb->theError.code); @@ -1582,9 +1621,6 @@ from other transactions. /** * There's always a TCKEYCONF when using IgnoreError */ -#ifdef VM_TRACE - ndbout_c("Not completing transaction 2"); -#endif return -1; } /**********************************************************************/ @@ -1836,9 +1872,6 @@ NdbConnection::OpCompleteFailure(Uint8 abortOption, bool setFailure) /** * There's always a TCKEYCONF when using IgnoreError */ -#ifdef VM_TRACE - ndbout_c("Not completing transaction"); -#endif return -1; } diff --git a/ndb/src/ndbapi/NdbConnectionScan.cpp b/ndb/src/ndbapi/NdbConnectionScan.cpp index 3fe8993a42b..b0c546c512a 100644 --- a/ndb/src/ndbapi/NdbConnectionScan.cpp +++ b/ndb/src/ndbapi/NdbConnectionScan.cpp @@ -56,13 +56,19 @@ NdbConnection::receiveSCAN_TABREF(NdbApiSignal* aSignal){ const ScanTabRef * ref = CAST_CONSTPTR(ScanTabRef, aSignal->getDataPtr()); if(checkState_TransId(&ref->transId1)){ - theScanningOp->theError.code = ref->errorCode; + theScanningOp->setErrorCode(ref->errorCode); + theScanningOp->execCLOSE_SCAN_REP(); if(!ref->closeNeeded){ - theScanningOp->execCLOSE_SCAN_REP(); return 0; } - assert(theScanningOp->m_sent_receivers_count); + + /** + * Setup so that close_impl will actually perform a close + * and not "close scan"-optimze it away + */ theScanningOp->m_conf_receivers_count++; + theScanningOp->m_conf_receivers[0] = theScanningOp->m_receivers[0]; + theScanningOp->m_conf_receivers[0]->m_tcPtrI = ~0; return 0; } else { #ifdef NDB_NO_DROPPED_SIGNAL @@ -97,7 +103,7 @@ NdbConnection::receiveSCAN_TABCONF(NdbApiSignal* aSignal, theScanningOp->execCLOSE_SCAN_REP(); return 0; } - + for(Uint32 i = 0; iint2void(ptrI); assert(tPtr); // For now NdbReceiver* tOp = theNdb->void2rec(tPtr); - if (tOp && tOp->checkMagicNumber()){ - if(tOp->execSCANOPCONF(tcPtrI, totalLen, opCount)){ - /** - * - */ - theScanningOp->receiver_delivered(tOp); - } else if(info == ScanTabConf::EndOfData){ + if (tOp && tOp->checkMagicNumber()) + { + if (tcPtrI == RNIL && opCount == 0) theScanningOp->receiver_completed(tOp); - } - } - } - if (conf->requestInfo & ScanTabConf::EndOfData) { - if(theScanningOp->m_ordered) - theScanningOp->m_api_receivers_count = 0; - if(theScanningOp->m_api_receivers_count + - theScanningOp->m_conf_receivers_count + - theScanningOp->m_sent_receivers_count){ - abort(); + else if (tOp->execSCANOPCONF(tcPtrI, totalLen, opCount)) + theScanningOp->receiver_delivered(tOp); } } return 0; diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 304d1b904d4..345f2caac89 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -1571,7 +1571,13 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb, NdbApiSignal tSignal(m_reference); tSignal.theReceiversBlockNumber = DBDICT; - if (alter) { + + LinearSectionPtr ptr[3]; + ptr[0].p = (Uint32*)m_buffer.get_data(); + ptr[0].sz = m_buffer.length() / 4; + int ret; + if (alter) + { AlterTableReq * const req = CAST_PTR(AlterTableReq, tSignal.getDataPtrSend()); @@ -1582,8 +1588,10 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb, req->tableVersion = impl.m_version;; tSignal.theVerId_signalNumber = GSN_ALTER_TABLE_REQ; tSignal.theLength = AlterTableReq::SignalLength; + ret= alterTable(&tSignal, ptr); } - else { + else + { CreateTableReq * const req = CAST_PTR(CreateTableReq, tSignal.getDataPtrSend()); @@ -1591,25 +1599,21 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb, req->senderData = 0; tSignal.theVerId_signalNumber = GSN_CREATE_TABLE_REQ; tSignal.theLength = CreateTableReq::SignalLength; - } - - LinearSectionPtr ptr[3]; - ptr[0].p = (Uint32*)m_buffer.get_data(); - ptr[0].sz = m_buffer.length() / 4; + ret= createTable(&tSignal, ptr); - int ret = (alter) ? - alterTable(&tSignal, ptr) - : createTable(&tSignal, ptr); + if (ret) + return ret; - if (!alter && haveAutoIncrement) { - if (!ndb.setAutoIncrementValue(impl.m_externalName.c_str(), - autoIncrementValue)) { - if (ndb.theError.code == 0) { - m_error.code = 4336; - ndb.theError = m_error; - } else - m_error= ndb.theError; - ret = -1; // errorcode set in initialize_autoincrement + if (haveAutoIncrement) { + if (!ndb.setAutoIncrementValue(impl.m_externalName.c_str(), + autoIncrementValue)) { + if (ndb.theError.code == 0) { + m_error.code = 4336; + ndb.theError = m_error; + } else + m_error= ndb.theError; + ret = -1; // errorcode set in initialize_autoincrement + } } } return ret; diff --git a/ndb/src/ndbapi/NdbIndexOperation.cpp b/ndb/src/ndbapi/NdbIndexOperation.cpp index 3f174a61b64..23af646c4c7 100644 --- a/ndb/src/ndbapi/NdbIndexOperation.cpp +++ b/ndb/src/ndbapi/NdbIndexOperation.cpp @@ -272,7 +272,7 @@ int NdbIndexOperation::equal_impl(const NdbColumnImpl* tAttrInfo, CHARSET_INFO* cs = tAttrInfo->m_cs; if (cs != 0) { // current limitation: strxfrm does not increase length - assert(cs->strxfrm_multiply == 1); + assert(cs->strxfrm_multiply <= 1); unsigned n = (*cs->coll->strnxfrm)(cs, (uchar*)xfrmData, sizeof(xfrmData), diff --git a/ndb/src/ndbapi/NdbOperationSearch.cpp b/ndb/src/ndbapi/NdbOperationSearch.cpp index 69b4e803acd..28a70abcb9b 100644 --- a/ndb/src/ndbapi/NdbOperationSearch.cpp +++ b/ndb/src/ndbapi/NdbOperationSearch.cpp @@ -142,7 +142,7 @@ NdbOperation::equal_impl(const NdbColumnImpl* tAttrInfo, CHARSET_INFO* cs = tAttrInfo->m_cs; if (cs != 0) { // current limitation: strxfrm does not increase length - assert(cs->strxfrm_multiply == 1); + assert(cs->strxfrm_multiply <= 1); unsigned n = (*cs->coll->strnxfrm)(cs, (uchar*)xfrmData, sizeof(xfrmData), diff --git a/ndb/src/ndbapi/NdbResultSet.cpp b/ndb/src/ndbapi/NdbResultSet.cpp index f270584d227..d9d71464026 100644 --- a/ndb/src/ndbapi/NdbResultSet.cpp +++ b/ndb/src/ndbapi/NdbResultSet.cpp @@ -44,10 +44,10 @@ void NdbResultSet::init() { } -int NdbResultSet::nextResult(bool fetchAllowed) +int NdbResultSet::nextResult(bool fetchAllowed, bool forceSend) { int res; - if ((res = m_operation->nextResult(fetchAllowed)) == 0) { + if ((res = m_operation->nextResult(fetchAllowed, forceSend)) == 0) { // handle blobs NdbBlob* tBlob = m_operation->theBlobList; while (tBlob != 0) { @@ -67,9 +67,9 @@ int NdbResultSet::nextResult(bool fetchAllowed) return res; } -void NdbResultSet::close() +void NdbResultSet::close(bool forceSend) { - m_operation->closeScan(); + m_operation->closeScan(forceSend); } NdbOperation* @@ -98,6 +98,6 @@ NdbResultSet::deleteTuple(NdbConnection * takeOverTrans){ } int -NdbResultSet::restart(){ - return m_operation->restart(); +NdbResultSet::restart(bool forceSend){ + return m_operation->restart(forceSend); } diff --git a/ndb/src/ndbapi/NdbScanOperation.cpp b/ndb/src/ndbapi/NdbScanOperation.cpp index 373fec1a2b0..88208409c08 100644 --- a/ndb/src/ndbapi/NdbScanOperation.cpp +++ b/ndb/src/ndbapi/NdbScanOperation.cpp @@ -35,6 +35,8 @@ #include #include +#define DEBUG_NEXT_RESULT 0 + NdbScanOperation::NdbScanOperation(Ndb* aNdb) : NdbOperation(aNdb), m_resultSet(0), @@ -275,6 +277,9 @@ NdbScanOperation::fix_receivers(Uint32 parallel){ void NdbScanOperation::receiver_delivered(NdbReceiver* tRec){ if(theError.code == 0){ + if(DEBUG_NEXT_RESULT) + ndbout_c("receiver_delivered"); + Uint32 idx = tRec->m_list_index; Uint32 last = m_sent_receivers_count - 1; if(idx != last){ @@ -298,6 +303,9 @@ NdbScanOperation::receiver_delivered(NdbReceiver* tRec){ void NdbScanOperation::receiver_completed(NdbReceiver* tRec){ if(theError.code == 0){ + if(DEBUG_NEXT_RESULT) + ndbout_c("receiver_completed"); + Uint32 idx = tRec->m_list_index; Uint32 last = m_sent_receivers_count - 1; if(idx != last){ @@ -445,12 +453,12 @@ NdbScanOperation::executeCursor(int nodeId){ return -1; } -#define DEBUG_NEXT_RESULT 0 -int NdbScanOperation::nextResult(bool fetchAllowed) +int NdbScanOperation::nextResult(bool fetchAllowed, bool forceSend) { if(m_ordered) - return ((NdbIndexScanOperation*)this)->next_result_ordered(fetchAllowed); + return ((NdbIndexScanOperation*)this)->next_result_ordered(fetchAllowed, + forceSend); /** * Check current receiver @@ -486,8 +494,12 @@ int NdbScanOperation::nextResult(bool fetchAllowed) Uint32 nodeId = theNdbCon->theDBnode; TransporterFacade* tp = TransporterFacade::instance(); Guard guard(tp->theMutexPtr); + if(theError.code) + return -1; + Uint32 seq = theNdbCon->theNodeSequence; - if(seq == tp->getNodeSequence(nodeId) && send_next_scan(idx, false) == 0){ + if(seq == tp->getNodeSequence(nodeId) && send_next_scan(idx, false, + forceSend) == 0){ idx = m_current_api_receiver; last = m_api_receivers_count; @@ -578,8 +590,9 @@ int NdbScanOperation::nextResult(bool fetchAllowed) } int -NdbScanOperation::send_next_scan(Uint32 cnt, bool stopScanFlag){ - if(cnt > 0 || stopScanFlag){ +NdbScanOperation::send_next_scan(Uint32 cnt, bool stopScanFlag, + bool forceSend){ + if(cnt > 0){ NdbApiSignal tSignal(theNdb->theMyRef); tSignal.setSignal(GSN_SCAN_NEXTREQ); @@ -595,38 +608,57 @@ NdbScanOperation::send_next_scan(Uint32 cnt, bool stopScanFlag){ */ Uint32 last = m_sent_receivers_count; Uint32 * prep_array = (cnt > 21 ? m_prepared_receivers : theData + 4); + Uint32 sent = 0; for(Uint32 i = 0; im_list_index = last+i; - prep_array[i] = tRec->m_tcPtrI; - tRec->prepareSend(); + if((prep_array[sent] = tRec->m_tcPtrI) != RNIL) + { + m_sent_receivers[last+sent] = tRec; + tRec->m_list_index = last+sent; + tRec->prepareSend(); + sent++; + } } - memcpy(&m_api_receivers[0], &m_api_receivers[cnt], cnt * sizeof(char*)); + memmove(m_api_receivers, m_api_receivers+cnt, + (theParallelism-cnt) * sizeof(char*)); - Uint32 nodeId = theNdbCon->theDBnode; - TransporterFacade * tp = TransporterFacade::instance(); - int ret; - if(cnt > 21){ - tSignal.setLength(4); - LinearSectionPtr ptr[3]; - ptr[0].p = prep_array; - ptr[0].sz = cnt; - ret = tp->sendSignal(&tSignal, nodeId, ptr, 1); - } else { - tSignal.setLength(4+cnt); - ret = tp->sendSignal(&tSignal, nodeId); + int ret = 0; + if(sent) + { + Uint32 nodeId = theNdbCon->theDBnode; + TransporterFacade * tp = TransporterFacade::instance(); + if(cnt > 21){ + tSignal.setLength(4); + LinearSectionPtr ptr[3]; + ptr[0].p = prep_array; + ptr[0].sz = sent; + ret = tp->sendSignal(&tSignal, nodeId, ptr, 1); + } else { + tSignal.setLength(4+sent); + ret = tp->sendSignal(&tSignal, nodeId); + } } + + if (!ret) checkForceSend(forceSend); - m_sent_receivers_count = last + cnt + stopScanFlag; + m_sent_receivers_count = last + sent; m_api_receivers_count -= cnt; m_current_api_receiver = 0; - + return ret; } return 0; } +void NdbScanOperation::checkForceSend(bool forceSend) +{ + if (forceSend) { + TransporterFacade::instance()->forceSend(theNdb->theNdbBlockNumber); + } else { + TransporterFacade::instance()->checkForceSend(theNdb->theNdbBlockNumber); + }//if +} + int NdbScanOperation::prepareSend(Uint32 TC_ConnectPtr, Uint64 TransactionId) { @@ -642,7 +674,7 @@ NdbScanOperation::doSend(int ProcessorId) return 0; } -void NdbScanOperation::closeScan() +void NdbScanOperation::closeScan(bool forceSend) { if(m_transConnection){ if(DEBUG_NEXT_RESULT) @@ -657,7 +689,7 @@ void NdbScanOperation::closeScan() TransporterFacade* tp = TransporterFacade::instance(); Guard guard(tp->theMutexPtr); - close_impl(tp); + close_impl(tp, forceSend); } while(0); @@ -670,7 +702,6 @@ void NdbScanOperation::closeScan() void NdbScanOperation::execCLOSE_SCAN_REP(){ - m_api_receivers_count = 0; m_conf_receivers_count = 0; m_sent_receivers_count = 0; } @@ -1091,7 +1122,7 @@ NdbIndexScanOperation::setBound(const NdbColumnImpl* tAttrInfo, Uint32 xfrmData[2000]; if (cs != NULL && aValue != NULL) { // current limitation: strxfrm does not increase length - assert(cs->strxfrm_multiply == 1); + assert(cs->strxfrm_multiply <= 1); unsigned n = (*cs->coll->strnxfrm)(cs, (uchar*)xfrmData, sizeof(xfrmData), @@ -1293,7 +1324,8 @@ NdbIndexScanOperation::compare(Uint32 skip, Uint32 cols, } int -NdbIndexScanOperation::next_result_ordered(bool fetchAllowed){ +NdbIndexScanOperation::next_result_ordered(bool fetchAllowed, + bool forceSend){ Uint32 u_idx = 0, u_last = 0; Uint32 s_idx = m_current_api_receiver; // first sorted @@ -1317,9 +1349,12 @@ NdbIndexScanOperation::next_result_ordered(bool fetchAllowed){ if(DEBUG_NEXT_RESULT) ndbout_c("performing fetch..."); TransporterFacade* tp = TransporterFacade::instance(); Guard guard(tp->theMutexPtr); + if(theError.code) + return -1; Uint32 seq = theNdbCon->theNodeSequence; Uint32 nodeId = theNdbCon->theDBnode; - if(seq == tp->getNodeSequence(nodeId) && !send_next_scan_ordered(s_idx)){ + if(seq == tp->getNodeSequence(nodeId) && + !send_next_scan_ordered(s_idx, forceSend)){ Uint32 tmp = m_sent_receivers_count; s_idx = m_current_api_receiver; while(m_sent_receivers_count > 0 && !theError.code){ @@ -1330,6 +1365,13 @@ NdbIndexScanOperation::next_result_ordered(bool fetchAllowed){ continue; } if(DEBUG_NEXT_RESULT) ndbout_c("return -1"); + setErrorCode(4028); + return -1; + } + + if(theError.code){ + setErrorCode(theError.code); + if(DEBUG_NEXT_RESULT) ndbout_c("return -1"); return -1; } @@ -1339,11 +1381,9 @@ NdbIndexScanOperation::next_result_ordered(bool fetchAllowed){ memcpy(arr, m_conf_receivers, u_last * sizeof(char*)); if(DEBUG_NEXT_RESULT) ndbout_c("sent: %d recv: %d", tmp, u_last); - if(theError.code){ - setErrorCode(theError.code); - if(DEBUG_NEXT_RESULT) ndbout_c("return -1"); - return -1; - } + } else { + setErrorCode(4028); + return -1; } } else { if(DEBUG_NEXT_RESULT) ndbout_c("return 2"); @@ -1408,14 +1448,26 @@ NdbIndexScanOperation::next_result_ordered(bool fetchAllowed){ } int -NdbIndexScanOperation::send_next_scan_ordered(Uint32 idx){ +NdbIndexScanOperation::send_next_scan_ordered(Uint32 idx, bool forceSend){ if(idx == theParallelism) return 0; + NdbReceiver* tRec = m_api_receivers[idx]; NdbApiSignal tSignal(theNdb->theMyRef); tSignal.setSignal(GSN_SCAN_NEXTREQ); + Uint32 last = m_sent_receivers_count; Uint32* theData = tSignal.getDataPtrSend(); + Uint32* prep_array = theData + 4; + + m_current_api_receiver = idx + 1; + if((prep_array[0] = tRec->m_tcPtrI) == RNIL) + { + if(DEBUG_NEXT_RESULT) + ndbout_c("receiver completed, don't send"); + return 0; + } + theData[0] = theNdbCon->theTCConPtr; theData[1] = 0; Uint64 transId = theNdbCon->theTransactionId; @@ -1425,35 +1477,35 @@ NdbIndexScanOperation::send_next_scan_ordered(Uint32 idx){ /** * Prepare ops */ - Uint32 last = m_sent_receivers_count; - Uint32 * prep_array = theData + 4; - - NdbReceiver * tRec = m_api_receivers[idx]; m_sent_receivers[last] = tRec; tRec->m_list_index = last; - prep_array[0] = tRec->m_tcPtrI; tRec->prepareSend(); - m_sent_receivers_count = last + 1; - m_current_api_receiver = idx + 1; Uint32 nodeId = theNdbCon->theDBnode; TransporterFacade * tp = TransporterFacade::instance(); tSignal.setLength(4+1); - return tp->sendSignal(&tSignal, nodeId); + int ret= tp->sendSignal(&tSignal, nodeId); + if (!ret) checkForceSend(forceSend); + return ret; } int -NdbScanOperation::close_impl(TransporterFacade* tp){ +NdbScanOperation::close_impl(TransporterFacade* tp, bool forceSend){ Uint32 seq = theNdbCon->theNodeSequence; Uint32 nodeId = theNdbCon->theDBnode; - if(seq != tp->getNodeSequence(nodeId)){ + if(seq != tp->getNodeSequence(nodeId)) + { theNdbCon->theReleaseOnClose = true; return -1; } - while(theError.code == 0 && m_sent_receivers_count){ + /** + * Wait for outstanding + */ + while(theError.code == 0 && m_sent_receivers_count) + { theNdb->theWaiter.m_node = nodeId; theNdb->theWaiter.m_state = WAIT_SCAN; int return_code = theNdb->receiveResponse(WAITFOR_SCAN_TIMEOUT); @@ -1471,18 +1523,59 @@ NdbScanOperation::close_impl(TransporterFacade* tp){ } } - if(m_api_receivers_count+m_conf_receivers_count){ - // Send close scan - if(send_next_scan(0, true) == -1){ // Close scan - theNdbCon->theReleaseOnClose = true; - return -1; - } + if(theError.code) + { + m_api_receivers_count = 0; + m_current_api_receiver = m_ordered ? theParallelism : 0; + } + + + /** + * move all conf'ed into api + * so that send_next_scan can check if they needs to be closed + */ + Uint32 api = m_api_receivers_count; + Uint32 conf = m_conf_receivers_count; + + if(m_ordered) + { + /** + * Ordered scan, keep the m_api_receivers "to the right" + */ + memmove(m_api_receivers, m_api_receivers+m_current_api_receiver, + (theParallelism - m_current_api_receiver) * sizeof(char*)); + api = (theParallelism - m_current_api_receiver); + m_api_receivers_count = api; + } + + if(DEBUG_NEXT_RESULT) + ndbout_c("close_impl: [order api conf sent curr parr] %d %d %d %d %d %d", + m_ordered, api, conf, + m_sent_receivers_count, m_current_api_receiver, theParallelism); + + if(api+conf) + { + /** + * There's something to close + * setup m_api_receivers (for send_next_scan) + */ + memcpy(m_api_receivers+api, m_conf_receivers, conf * sizeof(char*)); + m_api_receivers_count = api + conf; + m_conf_receivers_count = 0; + } + + // Send close scan + if(send_next_scan(api+conf, true, forceSend) == -1) + { + theNdbCon->theReleaseOnClose = true; + return -1; } /** * wait for close scan conf */ - while(m_sent_receivers_count+m_api_receivers_count+m_conf_receivers_count){ + while(m_sent_receivers_count+m_api_receivers_count+m_conf_receivers_count) + { theNdb->theWaiter.m_node = nodeId; theNdb->theWaiter.m_state = WAIT_SCAN; int return_code = theNdb->receiveResponse(WAITFOR_SCAN_TIMEOUT); @@ -1499,6 +1592,7 @@ NdbScanOperation::close_impl(TransporterFacade* tp){ return -1; } } + return 0; } @@ -1520,7 +1614,7 @@ NdbScanOperation::reset_receivers(Uint32 parallell, Uint32 ordered){ } int -NdbScanOperation::restart() +NdbScanOperation::restart(bool forceSend) { TransporterFacade* tp = TransporterFacade::instance(); @@ -1529,7 +1623,7 @@ NdbScanOperation::restart() { int res; - if((res= close_impl(tp))) + if((res= close_impl(tp, forceSend))) { return res; } @@ -1548,13 +1642,13 @@ NdbScanOperation::restart() } int -NdbIndexScanOperation::reset_bounds(){ +NdbIndexScanOperation::reset_bounds(bool forceSend){ int res; { TransporterFacade* tp = TransporterFacade::instance(); Guard guard(tp->theMutexPtr); - res= close_impl(tp); + res= close_impl(tp, forceSend); } if(!res) diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp index 698bbcde4c6..48e62c36a5f 100644 --- a/ndb/src/ndbapi/Ndbinit.cpp +++ b/ndb/src/ndbapi/Ndbinit.cpp @@ -58,7 +58,7 @@ Ndb::Ndb( const char* aDataBase , const char* aSchema) { theNoOfNdbObjects++; if (global_ndb_cluster_connection == 0) { global_ndb_cluster_connection= new Ndb_cluster_connection(ndbConnectString); - global_ndb_cluster_connection->connect(); + global_ndb_cluster_connection->connect(12,5,1); } setup(global_ndb_cluster_connection, aDataBase, aSchema); DBUG_VOID_RETURN; diff --git a/ndb/src/ndbapi/ndb_cluster_connection.cpp b/ndb/src/ndbapi/ndb_cluster_connection.cpp index 4c42fe1aeef..f436ee56ede 100644 --- a/ndb/src/ndbapi/ndb_cluster_connection.cpp +++ b/ndb/src/ndbapi/ndb_cluster_connection.cpp @@ -40,12 +40,8 @@ Ndb_cluster_connection::Ndb_cluster_connection(const char *connect_string) DBUG_ENTER("Ndb_cluster_connection"); DBUG_PRINT("enter",("Ndb_cluster_connection this=0x%x", this)); m_facade= TransporterFacade::theFacadeInstance= new TransporterFacade(); - if (connect_string) - m_connect_string= my_strdup(connect_string,MYF(MY_WME)); - else - m_connect_string= 0; + m_config_retriever= 0; - m_local_config= 0; m_connect_thread= 0; m_connect_callback= 0; @@ -59,9 +55,39 @@ Ndb_cluster_connection::Ndb_cluster_connection(const char *connect_string) ndb_print_state_mutex= NdbMutex_Create(); } #endif + m_config_retriever= + new ConfigRetriever(connect_string, NDB_VERSION, NODE_TYPE_API); + if (m_config_retriever->hasError()) + { + printf("Could not connect initialize handle to management server: %s", + m_config_retriever->getErrorString()); + delete m_config_retriever; + m_config_retriever= 0; + } DBUG_VOID_RETURN; } +int Ndb_cluster_connection::get_connected_port() const +{ + if (m_config_retriever) + return m_config_retriever->get_mgmd_port(); + return -1; +} + +const char *Ndb_cluster_connection::get_connected_host() const +{ + if (m_config_retriever) + return m_config_retriever->get_mgmd_host(); + return 0; +} + +const char *Ndb_cluster_connection::get_connectstring(char *buf, int buf_sz) const +{ + if (m_config_retriever) + return m_config_retriever->get_connectstring(buf,buf_sz); + return 0; +} + extern "C" pthread_handler_decl(run_ndb_cluster_connection_connect_thread, me) { my_thread_init(); @@ -78,7 +104,7 @@ void Ndb_cluster_connection::connect_thread() int r; do { NdbSleep_SecSleep(1); - if ((r = connect(1)) == 0) + if ((r = connect(0,0,0)) == 0) break; if (r == -1) { printf("Ndb_cluster_connection::connect_thread error\n"); @@ -99,7 +125,7 @@ int Ndb_cluster_connection::start_connect_thread(int (*connect_callback)(void)) int r; DBUG_ENTER("Ndb_cluster_connection::start_connect_thread"); m_connect_callback= connect_callback; - if ((r = connect(1)) == 1) + if ((r = connect(0,0,0)) == 1) { DBUG_PRINT("info",("starting thread")); m_connect_thread= @@ -118,45 +144,17 @@ int Ndb_cluster_connection::start_connect_thread(int (*connect_callback)(void)) DBUG_RETURN(0); } -int Ndb_cluster_connection::connect(int reconnect) +int Ndb_cluster_connection::connect(int no_retries, int retry_delay_in_seconds, int verbose) { DBUG_ENTER("Ndb_cluster_connection::connect"); const char* error = 0; do { if (m_config_retriever == 0) - { - if (m_local_config == 0) { - m_local_config= new LocalConfig(); - if (!m_local_config->init(m_connect_string,0)) { - ndbout_c("Configuration error: Unable to retrieve local config"); - m_local_config->printError(); - m_local_config->printUsage(); - DBUG_RETURN(-1); - } - } - m_config_retriever= - new ConfigRetriever(*m_local_config, NDB_VERSION, NODE_TYPE_API); - } - else - if (reconnect == 0) - DBUG_RETURN(0); - if (reconnect) - { - int r= m_config_retriever->do_connect(1); - if (r == 1) - DBUG_RETURN(1); // mgmt server not up yet - if (r == -1) - break; - } - else - if(m_config_retriever->do_connect() == -1) - break; + DBUG_RETURN(-1); + if (m_config_retriever->do_connect(no_retries,retry_delay_in_seconds,verbose)) + DBUG_RETURN(1); // mgmt server not up yet - Uint32 nodeId = m_config_retriever->allocNodeId(); - for(Uint32 i = 0; nodeId == 0 && i<5; i++){ - NdbSleep_SecSleep(3); - nodeId = m_config_retriever->allocNodeId(); - } + Uint32 nodeId = m_config_retriever->allocNodeId(4/*retries*/,3/*delay*/); if(nodeId == 0) break; ndb_mgm_configuration * props = m_config_retriever->getConfig(); @@ -197,11 +195,8 @@ Ndb_cluster_connection::~Ndb_cluster_connection() abort(); TransporterFacade::theFacadeInstance= 0; } - my_free(m_connect_string,MYF(MY_ALLOW_ZERO_PTR)); if (m_config_retriever) delete m_config_retriever; - if (m_local_config) - delete m_local_config; DBUG_VOID_RETURN; } diff --git a/ndb/src/ndbapi/ndberror.c b/ndb/src/ndbapi/ndberror.c index 1a0d8132d71..c0a6b6ba122 100644 --- a/ndb/src/ndbapi/ndberror.c +++ b/ndb/src/ndbapi/ndberror.c @@ -35,6 +35,7 @@ typedef struct ErrorBundle { #define NE ndberror_cl_none #define AE ndberror_cl_application +#define CE ndberror_cl_configuration #define ND ndberror_cl_no_data_found #define CV ndberror_cl_constraint_violation #define SE ndberror_cl_schema_error @@ -53,8 +54,32 @@ typedef struct ErrorBundle { #define NI ndberror_cl_function_not_implemented #define UE ndberror_cl_unknown_error_code +static const char REDO_BUFFER_MSG[]= +"REDO log buffers overloaded, consult online manual (increase RedoBuffer, and|or decrease TimeBetweenLocalCheckpoints, and|or increase NoOfFragmentLogFiles)"; + static const char* empty_string = ""; +/* + * Error code ranges are reserved for respective block + * + * 200 - TC + * 300 - DIH + * 400 - LQH + * 600 - ACC + * 700 - DICT + * 800 - TUP + * 1200 - LQH + * 1300 - BACKUP + * 4000 - API + * 4100 - "" + * 4200 - "" + * 4300 - "" + * 4400 - "" + * 4500 - "" + * 4600 - "" + * 5000 - Management server + */ + static const ErrorBundle ErrorCodes[] = { @@ -137,9 +162,8 @@ ErrorBundle ErrorCodes[] = { { 805, TR, "Out of attrinfo records in tuple manager" }, { 830, TR, "Out of add fragment operation records" }, { 873, TR, "Out of attrinfo records for scan in tuple manager" }, - { 1217, TR, "1217" }, - { 1219, TR, "Out of operation records in local data manager (increase MaxNoOfLocalOperations)" }, - { 1220, TR, "1220" }, + { 1217, TR, "Out of operation records in local data manager (increase MaxNoOfLocalOperations)" }, + { 1220, TR, REDO_BUFFER_MSG }, { 1222, TR, "Out of transaction markers in LQH" }, { 4021, TR, "Out of Send Buffer space in NDB API" }, { 4022, TR, "Out of Send Buffer space in NDB API" }, @@ -165,14 +189,13 @@ ErrorBundle ErrorCodes[] = { { 297, TO, "Time-out in NDB, probably caused by deadlock" }, /* Scan trans timeout, temporary!! */ { 237, TO, "Transaction had timed out when trying to commit it" }, - /** * OverloadError */ - { 410, OL, "Out of log file space temporarily" }, + { 410, OL, REDO_BUFFER_MSG }, { 677, OL, "Index UNDO buffers overloaded (increase UndoIndexBuffer)" }, { 891, OL, "Data UNDO buffers overloaded (increase UndoDataBuffer)" }, - { 1221, OL, "REDO log buffers overloaded (increase RedoBuffer)" }, + { 1221, OL, REDO_BUFFER_MSG }, { 4006, OL, "Connect failure - out of connection objects (increase MaxNoOfConcurrentTransactions)" }, @@ -240,11 +263,12 @@ ErrorBundle ErrorCodes[] = { { 877, AE, "877" }, { 878, AE, "878" }, { 879, AE, "879" }, + { 880, AE, "Tried to read too much - too many getValue calls" }, { 884, AE, "Stack overflow in interpreter" }, { 885, AE, "Stack underflow in interpreter" }, { 886, AE, "More than 65535 instructions executed in interpreter" }, + { 897, AE, "Update attempt of primary key via ndbcluster internal api (if this occurs via the MySQL server it is a bug, please report)" }, { 4256, AE, "Must call Ndb::init() before this function" }, - { 880, AE, "Tried to read too much - too many getValue calls" }, { 4257, AE, "Tried to read too much - too many getValue calls" }, /** @@ -301,6 +325,36 @@ ErrorBundle ErrorCodes[] = { */ { 4003, NI, "Function not implemented yet" }, + /** + * Backup error codes + */ + + { 1300, IE, "Undefined error" }, + { 1301, IE, "Backup issued to not master (reissue command to master)" }, + { 1302, IE, "Out of backup record" }, + { 1303, IS, "Out of resources" }, + { 1304, IE, "Sequence failure" }, + { 1305, IE, "Backup definition not implemented" }, + { 1306, AE, "Backup not supported in diskless mode (change Diskless)" }, + + { 1321, IE, "Backup aborted by application" }, + { 1322, IE, "Backup already completed" }, + { 1323, IE, "1323" }, + { 1324, IE, "Backup log buffer full" }, + { 1325, IE, "File or scan error" }, + { 1326, IE, "Backup abortet due to node failure" }, + { 1327, IE, "1327" }, + + { 1340, IE, "Backup undefined error" }, + { 1342, AE, "Backup failed to allocate buffers (check configuration)" }, + { 1343, AE, "Backup failed to setup fs buffers (check configuration)" }, + { 1344, AE, "Backup failed to allocate tables (check configuration)" }, + { 1345, AE, "Backup failed to insert file header (check configuration)" }, + { 1346, AE, "Backup failed to insert table list (check configuration)" }, + { 1347, AE, "Backup failed to allocate table memory (check configuration)" }, + { 1348, AE, "Backup failed to allocate file record (check configuration)" }, + { 1349, AE, "Backup failed to allocate attribute record (check configuration)" }, + /** * Still uncategorized */ @@ -425,7 +479,8 @@ ErrorBundle ErrorCodes[] = { { 4267, IE, "Corrupted blob value" }, { 4268, IE, "Error in blob head update forced rollback of transaction" }, { 4268, IE, "Unknown blob error" }, - { 4269, IE, "No connection to ndb management server" } + { 4269, IE, "No connection to ndb management server" }, + { 4335, AE, "Only one autoincrement column allowed per table. Having a table without primary key uses an autoincremented hidden key, i.e. a table without a primary key can not have an autoincremented column" } }; static @@ -464,6 +519,7 @@ const ErrorStatusClassification StatusClassificationMapping[] = { { ST_S, NE, "No error"}, { ST_P, AE, "Application error"}, + { ST_P, CE, "Configuration or application error"}, { ST_P, ND, "No data found"}, { ST_P, CV, "Constraint violation"}, { ST_P, SE, "Schema error"}, diff --git a/ndb/test/include/HugoTransactions.hpp b/ndb/test/include/HugoTransactions.hpp index 19e4cb43336..b833f2ac629 100644 --- a/ndb/test/include/HugoTransactions.hpp +++ b/ndb/test/include/HugoTransactions.hpp @@ -36,15 +36,21 @@ public: bool allowConstraintViolation = true, int doSleep = 0, bool oneTrans = false); + int scanReadRecords(Ndb*, int records, int abort = 0, int parallelism = 0, - bool committed = false); - int scanReadCommittedRecords(Ndb*, - int records, - int abort = 0, - int parallelism = 0); + NdbOperation::LockMode = NdbOperation::LM_Read); + + int scanReadRecords(Ndb*, + const NdbDictionary::Index*, + int records, + int abort = 0, + int parallelism = 0, + NdbOperation::LockMode = NdbOperation::LM_Read, + bool sorted = false); + int pkReadRecords(Ndb*, int records, int batchsize = 1, diff --git a/ndb/test/include/NdbRestarter.hpp b/ndb/test/include/NdbRestarter.hpp index 114726f6a2b..19a88b4f8ad 100644 --- a/ndb/test/include/NdbRestarter.hpp +++ b/ndb/test/include/NdbRestarter.hpp @@ -87,8 +87,6 @@ protected: bool connected; BaseString addr; - BaseString host; - int port; NdbMgmHandle handle; ndb_mgm_configuration * m_config; protected: diff --git a/ndb/test/include/UtilTransactions.hpp b/ndb/test/include/UtilTransactions.hpp index 37cd99550a5..23902f3b317 100644 --- a/ndb/test/include/UtilTransactions.hpp +++ b/ndb/test/include/UtilTransactions.hpp @@ -53,11 +53,11 @@ public: int selectCount(Ndb*, int parallelism = 0, int* count_rows = NULL, - ScanLock lock = SL_Read, + NdbOperation::LockMode lm = NdbOperation::LM_CommittedRead, NdbConnection* pTrans = NULL); int scanReadRecords(Ndb*, int parallelism, - bool exclusive, + NdbOperation::LockMode lm, int records, int noAttribs, int* attrib_list, diff --git a/ndb/test/ndbapi/testBlobs.cpp b/ndb/test/ndbapi/testBlobs.cpp index efa0811aa39..4b532856709 100644 --- a/ndb/test/ndbapi/testBlobs.cpp +++ b/ndb/test/ndbapi/testBlobs.cpp @@ -22,6 +22,7 @@ #include #include #include +#include struct Bcol { bool m_nullable; @@ -59,6 +60,9 @@ struct Opt { bool m_oneblob; Bcol m_blob1; Bcol m_blob2; + // perf + const char* m_tnameperf; + unsigned m_rowsperf; // bugs int m_bug; int (*m_bugtest)(); @@ -84,6 +88,9 @@ struct Opt { m_oneblob(false), m_blob1(false, 7, 1137, 10), m_blob2(true, 99, 55, 1), + // perf + m_tnameperf("TBLOB2"), + m_rowsperf(10000), // bugs m_bug(0), m_bugtest(0) { @@ -107,6 +114,7 @@ printusage() << " -loop N loop N times 0=forever [" << d.m_loop << "]" << endl << " -parts N max parts in blob value [" << d.m_parts << "]" << endl << " -rows N number of rows [" << d.m_rows << "]" << endl + << " -rowsperf N rows for performace test [" << d.m_rowsperf << "]" << endl << " -seed N random seed 0=loop number [" << d.m_seed << "]" << endl << " -skip xxx skip given tests (see list) [no tests]" << endl << " -test xxx only given tests (see list) [all tests]" << endl @@ -118,6 +126,7 @@ printusage() << " i hash index ops" << endl << " s table scans" << endl << " r ordered index scans" << endl + << " p performance test" << endl << "additional flags for test/skip" << endl << " u update existing blob value" << endl << " n normal insert and update" << endl @@ -1381,6 +1390,292 @@ testmain() return 0; } +// separate performance test + +struct Tmr { // stolen from testOIBasic + Tmr() { + clr(); + } + void clr() { + m_on = m_ms = m_cnt = m_time[0] = m_text[0] = 0; + } + void on() { + assert(m_on == 0); + m_on = NdbTick_CurrentMillisecond(); + } + void off(unsigned cnt = 0) { + NDB_TICKS off = NdbTick_CurrentMillisecond(); + assert(m_on != 0 && off >= m_on); + m_ms += off - m_on; + m_cnt += cnt; + m_on = 0; + } + const char* time() { + if (m_cnt == 0) + sprintf(m_time, "%u ms", m_ms); + else + sprintf(m_time, "%u ms per %u ( %u ms per 1000 )", m_ms, m_cnt, (1000 * m_ms) / m_cnt); + return m_time; + } + const char* pct (const Tmr& t1) { + if (0 < t1.m_ms) + sprintf(m_text, "%u pct", (100 * m_ms) / t1.m_ms); + else + sprintf(m_text, "[cannot measure]"); + return m_text; + } + const char* over(const Tmr& t1) { + if (0 < t1.m_ms) { + if (t1.m_ms <= m_ms) + sprintf(m_text, "%u pct", (100 * (m_ms - t1.m_ms)) / t1.m_ms); + else + sprintf(m_text, "-%u pct", (100 * (t1.m_ms - m_ms)) / t1.m_ms); + } else + sprintf(m_text, "[cannot measure]"); + return m_text; + } + NDB_TICKS m_on; + unsigned m_ms; + unsigned m_cnt; + char m_time[100]; + char m_text[100]; +}; + +static int +testperf() +{ + if (! testcase('p')) + return 0; + DBG("=== perf test ==="); + g_ndb = new Ndb("TEST_DB"); + CHK(g_ndb->init() == 0); + CHK(g_ndb->waitUntilReady() == 0); + g_dic = g_ndb->getDictionary(); + NdbDictionary::Table tab(g_opt.m_tnameperf); + if (g_dic->getTable(tab.getName()) != 0) + CHK(g_dic->dropTable(tab) == 0); + // col A - pk + { NdbDictionary::Column col("A"); + col.setType(NdbDictionary::Column::Unsigned); + col.setPrimaryKey(true); + tab.addColumn(col); + } + // col B - char 20 + { NdbDictionary::Column col("B"); + col.setType(NdbDictionary::Column::Char); + col.setLength(20); + col.setNullable(true); + tab.addColumn(col); + } + // col C - text + { NdbDictionary::Column col("C"); + col.setType(NdbDictionary::Column::Text); + col.setInlineSize(20); + col.setPartSize(512); + col.setStripeSize(1); + col.setNullable(true); + tab.addColumn(col); + } + // create + CHK(g_dic->createTable(tab) == 0); + Uint32 cA = 0, cB = 1, cC = 2; + // timers + Tmr t1; + Tmr t2; + // insert char (one trans) + { + DBG("--- insert char ---"); + t1.on(); + CHK((g_con = g_ndb->startTransaction()) != 0); + for (Uint32 k = 0; k < g_opt.m_rowsperf; k++) { + CHK((g_opr = g_con->getNdbOperation(tab.getName())) != 0); + CHK(g_opr->insertTuple() == 0); + CHK(g_opr->equal(cA, (char*)&k) == 0); + CHK(g_opr->setValue(cB, "b") == 0); + CHK(g_con->execute(NoCommit) == 0); + } + t1.off(g_opt.m_rowsperf); + CHK(g_con->execute(Rollback) == 0); + DBG(t1.time()); + g_opr = 0; + g_con = 0; + } + // insert text (one trans) + { + DBG("--- insert text ---"); + t2.on(); + CHK((g_con = g_ndb->startTransaction()) != 0); + for (Uint32 k = 0; k < g_opt.m_rowsperf; k++) { + CHK((g_opr = g_con->getNdbOperation(tab.getName())) != 0); + CHK(g_opr->insertTuple() == 0); + CHK(g_opr->equal(cA, (char*)&k) == 0); + CHK((g_bh1 = g_opr->getBlobHandle(cC)) != 0); + CHK((g_bh1->setValue("c", 1) == 0)); + CHK(g_con->execute(NoCommit) == 0); + } + t2.off(g_opt.m_rowsperf); + CHK(g_con->execute(Rollback) == 0); + DBG(t2.time()); + g_bh1 = 0; + g_opr = 0; + g_con = 0; + } + // insert overhead + DBG("insert overhead: " << t2.over(t1)); + t1.clr(); + t2.clr(); + // insert + { + DBG("--- insert for read test ---"); + unsigned n = 0; + CHK((g_con = g_ndb->startTransaction()) != 0); + for (Uint32 k = 0; k < g_opt.m_rowsperf; k++) { + CHK((g_opr = g_con->getNdbOperation(tab.getName())) != 0); + CHK(g_opr->insertTuple() == 0); + CHK(g_opr->equal(cA, (char*)&k) == 0); + CHK(g_opr->setValue(cB, "b") == 0); + CHK((g_bh1 = g_opr->getBlobHandle(cC)) != 0); + CHK((g_bh1->setValue("c", 1) == 0)); + if (++n == g_opt.m_batch) { + CHK(g_con->execute(Commit) == 0); + g_ndb->closeTransaction(g_con); + CHK((g_con = g_ndb->startTransaction()) != 0); + n = 0; + } + } + if (n != 0) { + CHK(g_con->execute(Commit) == 0); + n = 0; + } + g_bh1 = 0; + g_opr = 0; + g_con = 0; + } + // pk read char (one trans) + { + DBG("--- pk read char ---"); + CHK((g_con = g_ndb->startTransaction()) != 0); + Uint32 a; + char b[20]; + t1.on(); + for (Uint32 k = 0; k < g_opt.m_rowsperf; k++) { + CHK((g_opr = g_con->getNdbOperation(tab.getName())) != 0); + CHK(g_opr->readTuple() == 0); + CHK(g_opr->equal(cA, (char*)&k) == 0); + CHK(g_opr->getValue(cA, (char*)&a) != 0); + CHK(g_opr->getValue(cB, b) != 0); + a = (Uint32)-1; + b[0] = 0; + CHK(g_con->execute(NoCommit) == 0); + CHK(a == k && strcmp(b, "b") == 0); + } + CHK(g_con->execute(Commit) == 0); + t1.off(g_opt.m_rowsperf); + DBG(t1.time()); + g_opr = 0; + g_con = 0; + } + // pk read text (one trans) + { + DBG("--- pk read text ---"); + CHK((g_con = g_ndb->startTransaction()) != 0); + Uint32 a; + char c[20]; + t2.on(); + for (Uint32 k = 0; k < g_opt.m_rowsperf; k++) { + CHK((g_opr = g_con->getNdbOperation(tab.getName())) != 0); + CHK(g_opr->readTuple() == 0); + CHK(g_opr->equal(cA, (char*)&k) == 0); + CHK(g_opr->getValue(cA, (char*)&a) != 0); + CHK((g_bh1 = g_opr->getBlobHandle(cC)) != 0); + a = (Uint32)-1; + c[0] = 0; + CHK(g_con->execute(NoCommit) == 0); + Uint32 m = 20; + CHK(g_bh1->readData(c, m) == 0); + CHK(a == k && m == 1 && strcmp(c, "c") == 0); + } + CHK(g_con->execute(Commit) == 0); + t2.off(g_opt.m_rowsperf); + DBG(t2.time()); + g_opr = 0; + g_con = 0; + } + // pk read overhead + DBG("pk read overhead: " << t2.over(t1)); + t1.clr(); + t2.clr(); + // scan read char + { + DBG("--- scan read char ---"); + NdbResultSet* rs; + Uint32 a; + char b[20]; + CHK((g_con = g_ndb->startTransaction()) != 0); + CHK((g_ops = g_con->getNdbScanOperation(tab.getName())) != 0); + CHK((rs = g_ops->readTuples(NdbScanOperation::LM_Read)) != 0); + CHK(g_ops->getValue(cA, (char*)&a) != 0); + CHK(g_ops->getValue(cB, b) != 0); + CHK(g_con->execute(NoCommit) == 0); + unsigned n = 0; + t1.on(); + while (1) { + a = (Uint32)-1; + b[0] = 0; + int ret; + CHK((ret = rs->nextResult(true)) == 0 || ret == 1); + if (ret == 1) + break; + CHK(a < g_opt.m_rowsperf && strcmp(b, "b") == 0); + n++; + } + CHK(n == g_opt.m_rowsperf); + t1.off(g_opt.m_rowsperf); + DBG(t1.time()); + g_ops = 0; + g_con = 0; + } + // scan read text + { + DBG("--- read text ---"); + NdbResultSet* rs; + Uint32 a; + char c[20]; + CHK((g_con = g_ndb->startTransaction()) != 0); + CHK((g_ops = g_con->getNdbScanOperation(tab.getName())) != 0); + CHK((rs = g_ops->readTuples(NdbScanOperation::LM_Read)) != 0); + CHK(g_ops->getValue(cA, (char*)&a) != 0); + CHK((g_bh1 = g_ops->getBlobHandle(cC)) != 0); + CHK(g_con->execute(NoCommit) == 0); + unsigned n = 0; + t2.on(); + while (1) { + a = (Uint32)-1; + c[0] = 0; + int ret; + CHK((ret = rs->nextResult(true)) == 0 || ret == 1); + if (ret == 1) + break; + Uint32 m = 20; + CHK(g_bh1->readData(c, m) == 0); + CHK(a < g_opt.m_rowsperf && m == 1 && strcmp(c, "c") == 0); + n++; + } + CHK(n == g_opt.m_rowsperf); + t2.off(g_opt.m_rowsperf); + DBG(t2.time()); + g_bh1 = 0; + g_ops = 0; + g_con = 0; + } + // scan read overhead + DBG("scan read overhead: " << t2.over(t1)); + t1.clr(); + t2.clr(); + delete g_ndb; + return 0; +} + // bug tests static int @@ -1498,6 +1793,12 @@ NDB_COMMAND(testOdbcDriver, "testBlobs", "testBlobs", "testBlobs", 65535) continue; } } + if (strcmp(arg, "-rowsperf") == 0) { + if (++argv, --argc > 0) { + g_opt.m_rowsperf = atoi(argv[0]); + continue; + } + } if (strcmp(arg, "-seed") == 0) { if (++argv, --argc > 0) { g_opt.m_seed = atoi(argv[0]); @@ -1558,7 +1859,7 @@ NDB_COMMAND(testOdbcDriver, "testBlobs", "testBlobs", "testBlobs", 65535) strcat(b, "r"); g_opt.m_skip = strdup(b); } - if (testmain() == -1) { + if (testmain() == -1 || testperf() == -1) { ndbout << "line " << __LINE__ << " FAIL loop=" << g_loop << endl; return NDBT_ProgramExit(NDBT_FAILED); } diff --git a/ndb/test/ndbapi/testDict.cpp b/ndb/test/ndbapi/testDict.cpp index 9552e321f00..0a43bb02fff 100644 --- a/ndb/test/ndbapi/testDict.cpp +++ b/ndb/test/ndbapi/testDict.cpp @@ -1479,6 +1479,84 @@ runTestDictionaryPerf(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_OK; } +int runFailAddFragment(NDBT_Context* ctx, NDBT_Step* step){ + static int acclst[] = { 3001 }; + static int tuplst[] = { 4007, 4008, 4009, 4010, 4011, 4012 }; + static int tuxlst[] = { 12001, 12002, 12003, 12004, 12005, 12006 }; + static unsigned acccnt = sizeof(acclst)/sizeof(acclst[0]); + static unsigned tupcnt = sizeof(tuplst)/sizeof(tuplst[0]); + static unsigned tuxcnt = sizeof(tuxlst)/sizeof(tuxlst[0]); + + NdbRestarter restarter; + int nodeId = restarter.getMasterNodeId(); + Ndb* pNdb = GETNDB(step); + NdbDictionary::Dictionary* pDic = pNdb->getDictionary(); + NdbDictionary::Table tab(*ctx->getTab()); + tab.setFragmentType(NdbDictionary::Object::FragAllLarge); + + // ordered index on first few columns + NdbDictionary::Index idx("X"); + idx.setTable(tab.getName()); + idx.setType(NdbDictionary::Index::OrderedIndex); + idx.setLogging(false); + for (int i_hate_broken_compilers = 0; + i_hate_broken_compilers < 3 && + i_hate_broken_compilers < tab.getNoOfColumns(); + i_hate_broken_compilers++) { + idx.addColumn(*tab.getColumn(i_hate_broken_compilers)); + } + + const int loops = ctx->getNumLoops(); + int result = NDBT_OK; + (void)pDic->dropTable(tab.getName()); + + for (int l = 0; l < loops; l++) { + for (unsigned i0 = 0; i0 < acccnt; i0++) { + unsigned j = (l == 0 ? i0 : myRandom48(acccnt)); + int errval = acclst[j]; + g_info << "insert error node=" << nodeId << " value=" << errval << endl; + CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0, + "failed to set error insert"); + CHECK2(pDic->createTable(tab) != 0, + "failed to fail after error insert " << errval); + CHECK2(pDic->createTable(tab) == 0, + pDic->getNdbError()); + CHECK2(pDic->dropTable(tab.getName()) == 0, + pDic->getNdbError()); + } + for (unsigned i1 = 0; i1 < tupcnt; i1++) { + unsigned j = (l == 0 ? i1 : myRandom48(tupcnt)); + int errval = tuplst[j]; + g_info << "insert error node=" << nodeId << " value=" << errval << endl; + CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0, + "failed to set error insert"); + CHECK2(pDic->createTable(tab) != 0, + "failed to fail after error insert " << errval); + CHECK2(pDic->createTable(tab) == 0, + pDic->getNdbError()); + CHECK2(pDic->dropTable(tab.getName()) == 0, + pDic->getNdbError()); + } + for (unsigned i2 = 0; i2 < tuxcnt; i2++) { + unsigned j = (l == 0 ? i2 : myRandom48(tuxcnt)); + int errval = tuxlst[j]; + g_info << "insert error node=" << nodeId << " value=" << errval << endl; + CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0, + "failed to set error insert"); + CHECK2(pDic->createTable(tab) == 0, + pDic->getNdbError()); + CHECK2(pDic->createIndex(idx) != 0, + "failed to fail after error insert " << errval); + CHECK2(pDic->createIndex(idx) == 0, + pDic->getNdbError()); + CHECK2(pDic->dropTable(tab.getName()) == 0, + pDic->getNdbError()); + } + } +end: + return result; +} + NDBT_TESTSUITE(testDict); TESTCASE("CreateAndDrop", "Try to create and drop the table loop number of times\n"){ @@ -1574,6 +1652,10 @@ TESTCASE("DictionaryPerf", ""){ INITIALIZER(runTestDictionaryPerf); } +TESTCASE("FailAddFragment", + "Fail add fragment or attribute in ACC or TUP or TUX\n"){ + INITIALIZER(runFailAddFragment); +} NDBT_TESTSUITE_END(testDict); int main(int argc, const char** argv){ @@ -1583,5 +1665,3 @@ int main(int argc, const char** argv){ myRandom48Init(NdbTick_CurrentMillisecond()); return testDict.execute(argc, argv); } - - diff --git a/ndb/test/ndbapi/testReadPerf.cpp b/ndb/test/ndbapi/testReadPerf.cpp index 380a809ad00..3adcb5a2d9b 100644 --- a/ndb/test/ndbapi/testReadPerf.cpp +++ b/ndb/test/ndbapi/testReadPerf.cpp @@ -391,8 +391,15 @@ run_read(){ void print_result(){ + int tmp = 1; + tmp *= g_paramters[P_RANGE].value; + tmp *= g_paramters[P_LOOPS].value; + + int t, t2; for(int i = 0; igetTab(); + Ndb* pNdb = GETNDB(step); + + // Create index + BaseString::snprintf(orderedPkIdxName, sizeof(orderedPkIdxName), + "IDC_O_PK_%s", pTab->getName()); + NdbDictionary::Index pIdx(orderedPkIdxName); + pIdx.setTable(pTab->getName()); + pIdx.setType(NdbDictionary::Index::OrderedIndex); + pIdx.setLogging(false); + + for (int c = 0; c< pTab->getNoOfColumns(); c++){ + const NdbDictionary::Column * col = pTab->getColumn(c); + if(col->getPrimaryKey()){ + pIdx.addIndexColumn(col->getName()); + } + } + + if (pNdb->getDictionary()->createIndex(pIdx) != 0){ + ndbout << "FAILED! to create index" << endl; + const NdbError err = pNdb->getDictionary()->getNdbError(); + ERR(err); + return NDBT_FAILED; + } + + return NDBT_OK; +} + +int createOrderedPkIndex_Drop(NDBT_Context* ctx, NDBT_Step* step){ + const NdbDictionary::Table* pTab = ctx->getTab(); + Ndb* pNdb = GETNDB(step); + + // Drop index + if (pNdb->getDictionary()->dropIndex(orderedPkIdxName, + pTab->getName()) != 0){ + ndbout << "FAILED! to drop index" << endl; + ERR(pNdb->getDictionary()->getNdbError()); + return NDBT_FAILED; + } + + return NDBT_OK; +} + + int runScanReadRandomTable(NDBT_Context* ctx, NDBT_Step* step){ int loops = ctx->getNumLoops(); int records = ctx->getNumRecords(); int parallelism = ctx->getProperty("Parallelism", 240); - int abort = ctx->getProperty("AbortProb"); + int abort = ctx->getProperty("AbortProb", 5); int i = 0; while (igetNumLoops(); int records = ctx->getNumRecords(); int parallelism = ctx->getProperty("Parallelism", 240); - int abort = ctx->getProperty("AbortProb"); + int abort = ctx->getProperty("AbortProb", 5); int i = 0; HugoTransactions hugoTrans(*ctx->getTab()); @@ -232,18 +280,66 @@ int runScanRead(NDBT_Context* ctx, NDBT_Step* step){ return NDBT_OK; } -int runScanReadCommitted(NDBT_Context* ctx, NDBT_Step* step){ +int runRandScanRead(NDBT_Context* ctx, NDBT_Step* step){ int loops = ctx->getNumLoops(); int records = ctx->getNumRecords(); int parallelism = ctx->getProperty("Parallelism", 240); - int abort = ctx->getProperty("AbortProb"); + int abort = ctx->getProperty("AbortProb", 5); int i = 0; HugoTransactions hugoTrans(*ctx->getTab()); while (iisTestStopped()) { g_info << i << ": "; - if (hugoTrans.scanReadCommittedRecords(GETNDB(step), records, - abort, parallelism) != 0){ + NdbOperation::LockMode lm = (NdbOperation::LockMode)(rand() % 3); + if (hugoTrans.scanReadRecords(GETNDB(step), + records, abort, parallelism, + lm) != 0){ + return NDBT_FAILED; + } + i++; + } + return NDBT_OK; +} + +int runScanReadIndex(NDBT_Context* ctx, NDBT_Step* step){ + int loops = ctx->getNumLoops(); + int records = ctx->getNumRecords(); + int parallelism = ctx->getProperty("Parallelism", 240); + int abort = ctx->getProperty("AbortProb", 5); + const NdbDictionary::Index * pIdx = + GETNDB(step)->getDictionary()->getIndex(orderedPkIdxName, + ctx->getTab()->getName()); + + int i = 0; + HugoTransactions hugoTrans(*ctx->getTab()); + while (pIdx && iisTestStopped()) { + g_info << i << ": "; + bool sort = (rand() % 100) > 50 ? true : false; + NdbOperation::LockMode lm = (NdbOperation::LockMode)(rand() % 3); + if (hugoTrans.scanReadRecords(GETNDB(step), pIdx, + records, abort, parallelism, + lm, + sort) != 0){ + return NDBT_FAILED; + } + i++; + } + return NDBT_OK; +} + +int runScanReadCommitted(NDBT_Context* ctx, NDBT_Step* step){ + int loops = ctx->getNumLoops(); + int records = ctx->getNumRecords(); + int parallelism = ctx->getProperty("Parallelism", 240); + int abort = ctx->getProperty("AbortProb", 5); + + int i = 0; + HugoTransactions hugoTrans(*ctx->getTab()); + while (iisTestStopped()) { + g_info << i << ": "; + if (hugoTrans.scanReadRecords(GETNDB(step), records, + abort, parallelism, + NdbOperation::LM_CommittedRead) != 0){ return NDBT_FAILED; } i++; @@ -424,7 +520,7 @@ int runScanUpdate(NDBT_Context* ctx, NDBT_Step* step){ int loops = ctx->getNumLoops(); int records = ctx->getNumRecords(); int parallelism = ctx->getProperty("Parallelism", 1); - int abort = ctx->getProperty("AbortProb"); + int abort = ctx->getProperty("AbortProb", 5); int i = 0; HugoTransactions hugoTrans(*ctx->getTab()); while (igetNumLoops(); int records = ctx->getNumRecords(); int parallelism = ctx->getProperty("Parallelism", 240); - int abort = ctx->getProperty("AbortProb"); + int abort = ctx->getProperty("AbortProb", 5); int i = 0; HugoTransactions hugoTrans(*ctx->getTab()); while (inumAttribs, alist.attriblist[i]->attribs) != 0){ @@ -647,7 +743,7 @@ int runCheckGetValue(NDBT_Context* ctx, NDBT_Step* step){ } if(utilTrans.scanReadRecords(GETNDB(step), parallelism, - true, + NdbOperation::LM_Read, records, alist.attriblist[i]->numAttribs, alist.attriblist[i]->attribs) != 0){ @@ -1079,7 +1175,30 @@ TESTCASE("ScanRead488", "When this limit is exceeded the scan will be aborted with errorcode "\ "488."){ INITIALIZER(runLoadTable); - STEPS(runScanRead, 70); + STEPS(runRandScanRead, 70); + FINALIZER(runClearTable); +} +TESTCASE("ScanRead488O", + "Verify scan requirement: It's only possible to have 11 concurrent "\ + "scans per fragment running in Ndb kernel at the same time. "\ + "When this limit is exceeded the scan will be aborted with errorcode "\ + "488."){ + INITIALIZER(createOrderedPkIndex); + INITIALIZER(runLoadTable); + STEPS(runScanReadIndex, 70); + FINALIZER(createOrderedPkIndex_Drop); + FINALIZER(runClearTable); +} +TESTCASE("ScanRead488_Mixed", + "Verify scan requirement: It's only possible to have 11 concurrent "\ + "scans per fragment running in Ndb kernel at the same time. "\ + "When this limit is exceeded the scan will be aborted with errorcode "\ + "488."){ + INITIALIZER(createOrderedPkIndex); + INITIALIZER(runLoadTable); + STEPS(runRandScanRead, 50); + STEPS(runScanReadIndex, 50); + FINALIZER(createOrderedPkIndex_Drop); FINALIZER(runClearTable); } TESTCASE("ScanRead488Timeout", diff --git a/ndb/test/ndbapi/testScanPerf.cpp b/ndb/test/ndbapi/testScanPerf.cpp index 003fc67179f..45f0468bc70 100644 --- a/ndb/test/ndbapi/testScanPerf.cpp +++ b/ndb/test/ndbapi/testScanPerf.cpp @@ -39,8 +39,9 @@ struct Parameter { #define P_LOOPS 8 #define P_CREATE 9 #define P_LOAD 10 +#define P_RESET 11 -#define P_MAX 11 +#define P_MAX 12 static Parameter @@ -55,7 +56,8 @@ g_paramters[] = { { "size", 1000000, 1, ~0 }, { "iterations", 3, 1, ~0 }, { "create_drop", 1, 0, 1 }, - { "data", 1, 0, 1 } + { "data", 1, 0, 1 }, + { "q-reset bounds", 0, 1, 0 } }; static Ndb* g_ndb = 0; @@ -219,21 +221,30 @@ run_scan(){ NDB_TICKS start1, stop; int sum_time= 0; + int sample_rows = 0; + int tot_rows = 0; + NDB_TICKS sample_start = NdbTick_CurrentMillisecond(); + Uint32 tot = g_paramters[P_ROWS].value; + if(g_paramters[P_BOUND].value == 2 || g_paramters[P_FILT].value == 2) + iter *= g_paramters[P_ROWS].value; + + NdbScanOperation * pOp = 0; + NdbIndexScanOperation * pIOp = 0; + NdbConnection * pTrans = 0; + NdbResultSet * rs = 0; + int check = 0; + for(int i = 0; istartTransaction(); + pTrans = pTrans ? pTrans : g_ndb->startTransaction(); if(!pTrans){ g_err << "Failed to start transaction" << endl; err(g_ndb->getNdbError()); return -1; } - NdbScanOperation * pOp; - NdbIndexScanOperation * pIOp; - - NdbResultSet * rs; int par = g_paramters[P_PARRA].value; int bat = g_paramters[P_BATCH].value; NdbScanOperation::LockMode lm; @@ -256,9 +267,17 @@ run_scan(){ assert(pOp); rs = pOp->readTuples(lm, bat, par); } else { - pOp = pIOp = pTrans->getNdbIndexScanOperation(g_indexname, g_tablename); - bool ord = g_paramters[P_ACCESS].value == 2; - rs = pIOp->readTuples(lm, bat, par, ord); + if(g_paramters[P_RESET].value == 0 || pIOp == 0) + { + pOp= pIOp= pTrans->getNdbIndexScanOperation(g_indexname, g_tablename); + bool ord = g_paramters[P_ACCESS].value == 2; + rs = pIOp->readTuples(lm, bat, par, ord); + } + else + { + pIOp->reset_bounds(); + } + switch(g_paramters[P_BOUND].value){ case 0: // All break; @@ -268,20 +287,22 @@ run_scan(){ case 2: { // 1 row default: assert(g_table->getNoOfPrimaryKeys() == 1); // only impl. so far - abort(); -#if 0 int tot = g_paramters[P_ROWS].value; int row = rand() % tot; +#if 0 fix_eq_bound(pIOp, row); +#else + pIOp->setBound((Uint32)0, NdbIndexScanOperation::BoundEQ, &row); #endif break; } } + if(g_paramters[P_RESET].value == 2) + goto execute; } assert(pOp); assert(rs); - int check = 0; switch(g_paramters[P_FILT].value){ case 0: // All check = pOp->interpret_exit_ok(); @@ -310,10 +331,13 @@ run_scan(){ } assert(check == 0); + if(g_paramters[P_RESET].value == 1) + g_paramters[P_RESET].value = 2; + for(int i = 0; igetNoOfColumns(); i++){ pOp->getValue(i); } - +execute: int rows = 0; check = pTrans->execute(NoCommit); assert(check == 0); @@ -334,19 +358,30 @@ run_scan(){ return -1; } assert(check == 1); - g_info << "Found " << rows << " rows" << endl; - - pTrans->close(); - + if(g_paramters[P_RESET].value == 0) + { + pTrans->close(); + pTrans = 0; + } stop = NdbTick_CurrentMillisecond(); + int time_passed= (int)(stop - start1); - g_err.println("Time: %d ms = %u rows/sec", time_passed, - (1000*tot)/time_passed); + sample_rows += rows; sum_time+= time_passed; + tot_rows+= rows; + + if(sample_rows >= tot) + { + int sample_time = (int)(stop - sample_start); + g_info << "Found " << sample_rows << " rows" << endl; + g_err.println("Time: %d ms = %u rows/sec", sample_time, + (1000*sample_rows)/sample_time); + sample_rows = 0; + sample_start = stop; + } } - sum_time= sum_time / iter; - g_err.println("Avg time: %d ms = %u rows/sec", sum_time, - (1000*tot)/sum_time); + g_err.println("Avg time: %d ms = %u rows/sec", sum_time/tot_rows, + (1000*tot_rows)/sum_time); return 0; } diff --git a/ndb/test/run-test/daily-basic-tests.txt b/ndb/test/run-test/daily-basic-tests.txt index 8d7e8a06c72..8a927b88194 100644 --- a/ndb/test/run-test/daily-basic-tests.txt +++ b/ndb/test/run-test/daily-basic-tests.txt @@ -222,6 +222,18 @@ max-time: 500 cmd: testScan args: -n ScanRead488 -l 10 T6 +max-time: 500 +cmd: testScan +args: -n ScanRead488O -l 10 T6 + +max-time: 1000 +cmd: testScan +args: -n ScanRead488_Mixed -l 10 T6 + +max-time: 500 +cmd: testScan +args: -n ScanRead488Timeout -l 10 T6 + max-time: 600 cmd: testScan args: -n ScanRead40 -l 100 T2 @@ -474,493 +486,13 @@ args: -n UpdateWithoutValues T6 #cmd: testInterpreter #args: T1 # -max-time: 1500 +max-time: 150000 cmd: testOperations -args: -n ReadRead +args: -max-time: 1500 -cmd: testOperations -args: -n ReadReadEx - -max-time: 1500 -cmd: testOperations -args: -n ReadInsert - -max-time: 1500 -cmd: testOperations -args: -n ReadUpdate - -max-time: 1500 -cmd: testOperations -args: -n ReadDelete - -max-time: 1500 -cmd: testOperations -args: -n FReadRead - -max-time: 1500 -cmd: testOperations -args: -n FReadReadEx - -max-time: 1500 -cmd: testOperations -args: -n FReadInsert - -max-time: 1500 -cmd: testOperations -args: -n FReadUpdate - -max-time: 1500 -cmd: testOperations -args: -n FReadDelete - -max-time: 1500 -cmd: testOperations -args: -n ReadExRead - -max-time: 1500 -cmd: testOperations -args: -n ReadExReadEx - -max-time: 1500 -cmd: testOperations -args: -n ReadExInsert - -max-time: 1500 -cmd: testOperations -args: -n ReadExUpdate - -max-time: 1500 -cmd: testOperations -args: -n ReadExDelete - -max-time: 1500 -cmd: testOperations -args: -n InsertRead - -max-time: 1500 -cmd: testOperations -args: -n InsertReadEx - -max-time: 1500 -cmd: testOperations -args: -n InsertInsert - -max-time: 1500 -cmd: testOperations -args: -n InsertUpdate - -max-time: 1500 -cmd: testOperations -args: -n InsertDelete - -max-time: 1500 -cmd: testOperations -args: -n UpdateRead - -max-time: 1500 -cmd: testOperations -args: -n UpdateReadEx - -max-time: 1500 -cmd: testOperations -args: -n UpdateInsert - -max-time: 1500 -cmd: testOperations -args: -n UpdateUpdate - -max-time: 1500 -cmd: testOperations -args: -n UpdateDelete - -max-time: 1500 -cmd: testOperations -args: -n DeleteRead - -max-time: 1500 -cmd: testOperations -args: -n DeleteReadEx - -max-time: 1500 -cmd: testOperations -args: -n DeleteInsert - -max-time: 1500 -cmd: testOperations -args: -n DeleteUpdate - -max-time: 1500 -cmd: testOperations -args: -n DeleteDelete - -max-time: 1500 -cmd: testOperations -args: -n ReadSimpleRead - -max-time: 1500 -cmd: testOperations -args: -n ReadDirtyRead - -max-time: 1500 -cmd: testOperations -args: -n FReadSimpleRead - -max-time: 1500 -cmd: testOperations -args: -n FReadDirtyRead - -max-time: 1500 -cmd: testOperations -args: -n ReadExSimpleRead - -max-time: 1500 -cmd: testOperations -args: -n ReadExDirtyRead - -max-time: 1500 -cmd: testOperations -args: -n InsertSimpleRead - -max-time: 1500 -cmd: testOperations -args: -n InsertDirtyRead - -max-time: 1500 -cmd: testOperations -args: -n UpdateSimpleRead - -max-time: 1500 -cmd: testOperations -args: -n UpdateDirtyRead - -max-time: 1500 -cmd: testOperations -args: -n DeleteSimpleRead - -max-time: 1500 -cmd: testOperations -args: -n DeleteDirtyRead - -max-time: 1500 -cmd: testTransactions -args: -n ReadRead - -max-time: 1500 -cmd: testTransactions -args: -n ReadReadEx - -max-time: 1500 -cmd: testTransactions -args: -n ReadInsert - -max-time: 1500 -cmd: testTransactions -args: -n ReadUpdate - -max-time: 1500 -cmd: testTransactions -args: -n ReadDelete - -max-time: 1500 -cmd: testTransactions -args: -n ReadExRead - -max-time: 1500 -cmd: testTransactions -args: -n ReadExReadEx - -max-time: 1500 -cmd: testTransactions -args: -n ReadExInsert - -max-time: 1500 -cmd: testTransactions -args: -n ReadExUpdate - -max-time: 1500 -cmd: testTransactions -args: -n ReadExDelete - -max-time: 1500 -cmd: testTransactions -args: -n InsertRead - -max-time: 1500 -cmd: testTransactions -args: -n InsertReadEx - -max-time: 1500 -cmd: testTransactions -args: -n InsertInsert - -max-time: 1500 -cmd: testTransactions -args: -n InsertUpdate - -max-time: 1500 -cmd: testTransactions -args: -n InsertDelete - -max-time: 1500 -cmd: testTransactions -args: -n UpdateRead - -max-time: 1500 -cmd: testTransactions -args: -n UpdateReadEx - -max-time: 1500 -cmd: testTransactions -args: -n UpdateInsert - -max-time: 1500 -cmd: testTransactions -args: -n UpdateUpdate - -max-time: 1500 -cmd: testTransactions -args: -n UpdateDelete - -max-time: 1500 -cmd: testTransactions -args: -n DeleteRead - -max-time: 1500 -cmd: testTransactions -args: -n DeleteReadEx - -max-time: 1500 -cmd: testTransactions -args: -n DeleteInsert - -max-time: 1500 -cmd: testTransactions -args: -n DeleteUpdate - -max-time: 1500 -cmd: testTransactions -args: -n DeleteDelete - -max-time: 1500 -cmd: testTransactions -args: -n ReadSimpleRead - -max-time: 1500 -cmd: testTransactions -args: -n ReadDirtyRead - -max-time: 1500 -cmd: testTransactions -args: -n ReadExSimpleRead - -max-time: 1500 -cmd: testTransactions -args: -n ReadExDirtyRead - -max-time: 1500 -cmd: testTransactions -args: -n InsertSimpleRead - -max-time: 1500 -cmd: testTransactions -args: -n InsertDirtyRead - -max-time: 1500 -cmd: testTransactions -args: -n UpdateSimpleRead - -max-time: 1500 -cmd: testTransactions -args: -n UpdateDirtyRead - -max-time: 1500 -cmd: testTransactions -args: -n DeleteSimpleRead - -max-time: 1500 -cmd: testTransactions -args: -n DeleteDirtyRead - -max-time: 1500 -cmd: testTransactions -args: -n ReadScan - -max-time: 1500 -cmd: testTransactions -args: -n ReadScanHl - -max-time: 1500 -cmd: testTransactions -args: -n ReadScanEx - -max-time: 1500 -cmd: testTransactions -args: -n ScanRead - -max-time: 1500 -cmd: testTransactions -args: -n ScanReadEx - -max-time: 1500 -cmd: testTransactions -args: -n ScanSimpleRead - -max-time: 1500 -cmd: testTransactions -args: -n ScanDirtyRead - -max-time: 1500 -cmd: testTransactions -args: -n ScanInsert - -max-time: 1500 -cmd: testTransactions -args: -n ScanUpdate - -max-time: 1500 -cmd: testTransactions -args: -n ScanDelete - -max-time: 1500 -cmd: testTransactions -args: -n ScanScan - -max-time: 1500 -cmd: testTransactions -args: -n ScanScanHl - -max-time: 1500 -cmd: testTransactions -args: -n ScanScanEx - -max-time: 1500 -cmd: testTransactions -args: -n ScanHlRead - -max-time: 1500 -cmd: testTransactions -args: -n ScanHlReadEx - -max-time: 1500 -cmd: testTransactions -args: -n ScanHlSimpleRead - -max-time: 1500 -cmd: testTransactions -args: -n ScanHlDirtyRead - -max-time: 1500 -cmd: testTransactions -args: -n ScanHlInsert - -max-time: 1500 -cmd: testTransactions -args: -n ScanHlUpdate - -max-time: 1500 -cmd: testTransactions -args: -n ScanHlDelete - -max-time: 1500 -cmd: testTransactions -args: -n ScanHlScan - -max-time: 1500 -cmd: testTransactions -args: -n ScanHlScanHl - -max-time: 1500 -cmd: testTransactions -args: -n ScanHlScanEx - -max-time: 1500 -cmd: testTransactions -args: -n ScanExRead - -max-time: 1500 -cmd: testTransactions -args: -n ScanExReadEx - -max-time: 1500 -cmd: testTransactions -args: -n ScanExSimpleRead - -max-time: 1500 -cmd: testTransactions -args: -n ScanExDirtyRead - -max-time: 1500 -cmd: testTransactions -args: -n ScanExInsert - -max-time: 1500 -cmd: testTransactions -args: -n ScanExUpdate - -max-time: 1500 -cmd: testTransactions -args: -n ScanExDelete - -max-time: 1500 -cmd: testTransactions -args: -n ScanExScan - -max-time: 1500 -cmd: testTransactions -args: -n ScanExScanHl - -max-time: 1500 -cmd: testTransactions -args: -n ScanExScanEx - -max-time: 1500 -cmd: testTransactions -args: -n ReadExScan - -max-time: 1500 -cmd: testTransactions -args: -n ReadExScanHl - -max-time: 1500 -cmd: testTransactions -args: -n ReadExScanEx - -max-time: 1500 -cmd: testTransactions -args: -n InsertScan - -max-time: 1500 -cmd: testTransactions -args: -n InsertScanHl - -max-time: 1500 -cmd: testTransactions -args: -n InsertScanEx - -max-time: 1500 -cmd: testTransactions -args: -n UpdateScan - -max-time: 1500 -cmd: testTransactions -args: -n UpdateScanHl - -max-time: 1500 -cmd: testTransactions -args: -n UpdateScanEx - -max-time: 1500 -cmd: testTransactions -args: -n DeleteScan - -max-time: 1500 -cmd: testTransactions -args: -n DeleteScanHl - -max-time: 1500 +max-time: 150000 cmd: testTransactions -args: -n DeleteScanEx +args: max-time: 1500 cmd: testRestartGci diff --git a/ndb/test/run-test/main.cpp b/ndb/test/run-test/main.cpp index e5f73bc6a5c..ac7710d9546 100644 --- a/ndb/test/run-test/main.cpp +++ b/ndb/test/run-test/main.cpp @@ -538,15 +538,19 @@ connect_ndb_mgm(atrt_process & proc){ } BaseString tmp = proc.m_hostname; tmp.appfmt(":%d", proc.m_ndb_mgm_port); - time_t start = time(0); - const time_t max_connect_time = 30; - do { - if(ndb_mgm_connect(handle, tmp.c_str()) != -1){ - proc.m_ndb_mgm_handle = handle; - return true; - } - sleep(1); - } while(time(0) < (start + max_connect_time)); + + if (ndb_mgm_set_connectstring(handle,tmp.c_str())) + { + g_logger.critical("Unable to create parse connectstring"); + return false; + } + + if(ndb_mgm_connect(handle, 30, 1, 0) != -1) + { + proc.m_ndb_mgm_handle = handle; + return true; + } + g_logger.critical("Unable to connect to ndb mgm %s", tmp.c_str()); return false; } diff --git a/ndb/test/src/HugoTransactions.cpp b/ndb/test/src/HugoTransactions.cpp index 456bfffbb77..096f5406bbf 100644 --- a/ndb/test/src/HugoTransactions.cpp +++ b/ndb/test/src/HugoTransactions.cpp @@ -29,20 +29,13 @@ HugoTransactions::~HugoTransactions(){ deallocRows(); } - -int HugoTransactions::scanReadCommittedRecords(Ndb* pNdb, - int records, - int abortPercent, - int parallelism){ - return scanReadRecords(pNdb, records, abortPercent, parallelism, true); -} - int HugoTransactions::scanReadRecords(Ndb* pNdb, int records, int abortPercent, int parallelism, - bool committed){ + NdbOperation::LockMode lm) +{ int retryAttempt = 0; const int retryMax = 100; @@ -80,8 +73,163 @@ HugoTransactions::scanReadRecords(Ndb* pNdb, } NdbResultSet * rs; - rs = pOp ->readTuples(committed ? NdbScanOperation::LM_CommittedRead : - NdbScanOperation::LM_Read); + rs = pOp ->readTuples(lm); + + if( rs == 0 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + check = pOp->interpret_exit_ok(); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + for(a = 0; agetValue(tab.getColumn(a)->getName())) == 0) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + } + + check = pTrans->execute(NoCommit); + if( check == -1 ) { + const NdbError err = pTrans->getNdbError(); + if (err.status == NdbError::TemporaryError){ + ERR(err); + pNdb->closeTransaction(pTrans); + NdbSleep_MilliSleep(50); + retryAttempt++; + continue; + } + ERR(err); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + // Abort after 1-100 or 1-records rows + int ranVal = rand(); + int abortCount = ranVal % (records == 0 ? 100 : records); + bool abortTrans = false; + if (abort > 0){ + // Abort if abortCount is less then abortPercent + if (abortCount < abortPercent) + abortTrans = true; + } + + int eof; + int rows = 0; + while((eof = rs->nextResult(true)) == 0){ + rows++; + if (calc.verifyRowValues(&row) != 0){ + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + if (abortCount == rows && abortTrans == true){ + ndbout << "Scan is aborted" << endl; + g_info << "Scan is aborted" << endl; + rs->close(); + if( check == -1 ) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + pNdb->closeTransaction(pTrans); + return NDBT_OK; + } + } + if (eof == -1) { + const NdbError err = pTrans->getNdbError(); + + if (err.status == NdbError::TemporaryError){ + ERR_INFO(err); + pNdb->closeTransaction(pTrans); + NdbSleep_MilliSleep(50); + switch (err.code){ + case 488: + case 245: + case 490: + // Too many active scans, no limit on number of retry attempts + break; + default: + retryAttempt++; + } + continue; + } + ERR(err); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + pNdb->closeTransaction(pTrans); + + g_info << rows << " rows have been read" << endl; + if (records != 0 && rows != records){ + g_err << "Check expected number of records failed" << endl + << " expected=" << records <<", " << endl + << " read=" << rows << endl; + return NDBT_FAILED; + } + + return NDBT_OK; + } + return NDBT_FAILED; +} + +int +HugoTransactions::scanReadRecords(Ndb* pNdb, + const NdbDictionary::Index * pIdx, + int records, + int abortPercent, + int parallelism, + NdbOperation::LockMode lm, + bool sorted) +{ + + int retryAttempt = 0; + const int retryMax = 100; + int check, a; + NdbConnection *pTrans; + NdbIndexScanOperation *pOp; + + while (true){ + + if (retryAttempt >= retryMax){ + g_err << "ERROR: has retried this operation " << retryAttempt + << " times, failing!" << endl; + return NDBT_FAILED; + } + + pTrans = pNdb->startTransaction(); + if (pTrans == NULL) { + const NdbError err = pNdb->getNdbError(); + + if (err.status == NdbError::TemporaryError){ + ERR(err); + NdbSleep_MilliSleep(50); + retryAttempt++; + continue; + } + ERR(err); + return NDBT_FAILED; + } + + pOp = pTrans->getNdbIndexScanOperation(pIdx->getName(), tab.getName()); + if (pOp == NULL) { + ERR(pTrans->getNdbError()); + pNdb->closeTransaction(pTrans); + return NDBT_FAILED; + } + + NdbResultSet * rs; + rs = pOp ->readTuples(lm, 0, parallelism, sorted); if( rs == 0 ) { ERR(pTrans->getNdbError()); diff --git a/ndb/test/src/NDBT_Test.cpp b/ndb/test/src/NDBT_Test.cpp index 367223f8c98..1434617c988 100644 --- a/ndb/test/src/NDBT_Test.cpp +++ b/ndb/test/src/NDBT_Test.cpp @@ -839,9 +839,9 @@ void NDBT_TestSuite::execute(Ndb* ndb, const NdbDictionary::Table* pTab, continue; } pTab2 = pDict->getTable(pTab->getName()); - } else { + } else if(!pTab2) { pTab2 = pTab; - } + } ctx = new NDBT_Context(); ctx->setTab(pTab2); diff --git a/ndb/test/src/NdbBackup.cpp b/ndb/test/src/NdbBackup.cpp index 1ce48d495a5..09f52bf0bed 100644 --- a/ndb/test/src/NdbBackup.cpp +++ b/ndb/test/src/NdbBackup.cpp @@ -69,28 +69,19 @@ NdbBackup::getBackupDataDirForNode(int _node_id){ /** * Fetch configuration from management server */ - LocalConfig lc; - if (!lc.init(0,0)) { - abort(); - } - ConfigRetriever cr(lc, 0, NODE_TYPE_API); - ndb_mgm_configuration * p = 0; + ndb_mgm_configuration *p; + if (connect()) + return NULL; - BaseString tmp; tmp.assfmt("%s:%d", host.c_str(), port); - NdbMgmHandle handle = ndb_mgm_create_handle(); - if(handle == 0 || ndb_mgm_connect(handle, tmp.c_str()) != 0 || - (p = ndb_mgm_get_configuration(handle, 0)) == 0){ - - const char * s = 0; - if(p == 0 && handle != 0){ - s = ndb_mgm_get_latest_error_msg(handle); - if(s == 0) - s = "No error given!"; + if ((p = ndb_mgm_get_configuration(handle, 0)) == 0) + { + const char * s= ndb_mgm_get_latest_error_msg(handle); + if(s == 0) + s = "No error given!"; - ndbout << "Could not fetch configuration" << endl; - ndbout << s << endl; - return NULL; - } + ndbout << "Could not fetch configuration" << endl; + ndbout << s << endl; + return NULL; } /** @@ -155,13 +146,14 @@ NdbBackup::execRestore(bool _restore_data, ndbout << "scp res: " << res << endl; - BaseString::snprintf(buf, 255, "%sndb_restore -c \"host=%s\" -n %d -b %d %s %s .", + BaseString::snprintf(buf, 255, "%sndb_restore -c \"%s:%d\" -n %d -b %d %s %s .", #if 1 "", #else "valgrind --leak-check=yes -v " #endif - addr.c_str(), + ndb_mgm_get_connected_host(handle), + ndb_mgm_get_connected_port(handle), _node_id, _backup_id, _restore_data?"-r":"", diff --git a/ndb/test/src/NdbRestarter.cpp b/ndb/test/src/NdbRestarter.cpp index 4d6d3ddc001..91c0963feae 100644 --- a/ndb/test/src/NdbRestarter.cpp +++ b/ndb/test/src/NdbRestarter.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -33,42 +32,11 @@ NdbRestarter::NdbRestarter(const char* _addr): connected(false), - port(-1), handle(NULL), m_config(0) { if (_addr == NULL){ - LocalConfig lcfg; - if(!lcfg.init()){ - lcfg.printError(); - lcfg.printUsage(); - g_err << "NdbRestarter - Error parsing local config file" << endl; - return; - } - - if (lcfg.ids.size() == 0){ - g_err << "NdbRestarter - No management servers configured in local config file" << endl; - return; - } - - for (int i = 0; itype){ - case MgmId_TCP: - char buf[255]; - snprintf(buf, 255, "%s:%d", m->name.c_str(), m->port); - addr.assign(buf); - host.assign(m->name.c_str()); - port = m->port; - return; - break; - case MgmId_File: - break; - default: - break; - } - } + addr.assign(""); } else { addr.assign(_addr); } @@ -391,13 +359,22 @@ NdbRestarter::isConnected(){ int NdbRestarter::connect(){ + disconnect(); handle = ndb_mgm_create_handle(); if (handle == NULL){ g_err << "handle == NULL" << endl; return -1; } g_info << "Connecting to mgmsrv at " << addr.c_str() << endl; - if (ndb_mgm_connect(handle, addr.c_str()) == -1) { + if (ndb_mgm_set_connectstring(handle,addr.c_str())) + { + MGMERR(handle); + g_err << "Connection to " << addr.c_str() << " failed" << endl; + return -1; + } + + if (ndb_mgm_connect(handle, 0, 0, 0) == -1) + { MGMERR(handle); g_err << "Connection to " << addr.c_str() << " failed" << endl; return -1; diff --git a/ndb/test/src/UtilTransactions.cpp b/ndb/test/src/UtilTransactions.cpp index c0e6effd244..869f7fc76cb 100644 --- a/ndb/test/src/UtilTransactions.cpp +++ b/ndb/test/src/UtilTransactions.cpp @@ -619,7 +619,7 @@ UtilTransactions::addRowToInsert(Ndb* pNdb, int UtilTransactions::scanReadRecords(Ndb* pNdb, int parallelism, - bool exclusive, + NdbOperation::LockMode lm, int records, int noAttribs, int *attrib_list, @@ -669,10 +669,7 @@ UtilTransactions::scanReadRecords(Ndb* pNdb, return NDBT_FAILED; } - NdbResultSet * rs = pOp->readTuples(exclusive ? - NdbScanOperation::LM_Exclusive : - NdbScanOperation::LM_Read, - 0, parallelism); + NdbResultSet * rs = pOp->readTuples(lm, 0, parallelism); if( rs == 0 ) { ERR(pTrans->getNdbError()); pNdb->closeTransaction(pTrans); @@ -761,7 +758,7 @@ int UtilTransactions::selectCount(Ndb* pNdb, int parallelism, int* count_rows, - ScanLock lock, + NdbOperation::LockMode lm, NdbConnection* pTrans){ int retryAttempt = 0; @@ -785,19 +782,7 @@ UtilTransactions::selectCount(Ndb* pNdb, return NDBT_FAILED; } - NdbResultSet * rs; - switch(lock){ - case SL_ReadHold: - rs = pOp->readTuples(NdbScanOperation::LM_Read); - break; - case SL_Exclusive: - rs = pOp->readTuples(NdbScanOperation::LM_Exclusive); - break; - case SL_Read: - default: - rs = pOp->readTuples(NdbScanOperation::LM_CommittedRead); - } - + NdbResultSet * rs = pOp->readTuples(lm); if( rs == 0) { ERR(pTrans->getNdbError()); pNdb->closeTransaction(pTrans); diff --git a/ndb/test/tools/create_index.cpp b/ndb/test/tools/create_index.cpp index 75a657522f6..6e4c5377f4a 100644 --- a/ndb/test/tools/create_index.cpp +++ b/ndb/test/tools/create_index.cpp @@ -30,7 +30,7 @@ main(int argc, const char** argv){ const char* _dbname = "TEST_DB"; int _help = 0; - int _ordered, _pk; + int _ordered = 0, _pk = 1; struct getargs args[] = { { "database", 'd', arg_string, &_dbname, "dbname", diff --git a/ndb/test/tools/hugoScanRead.cpp b/ndb/test/tools/hugoScanRead.cpp index cdfdcea4654..42180207a8a 100644 --- a/ndb/test/tools/hugoScanRead.cpp +++ b/ndb/test/tools/hugoScanRead.cpp @@ -35,13 +35,17 @@ int main(int argc, const char** argv){ int _parallelism = 1; const char* _tabname = NULL; int _help = 0; - + int lock = NdbOperation::LM_Read; + int sorted = 0; + struct getargs args[] = { { "aborts", 'a', arg_integer, &_abort, "percent of transactions that are aborted", "abort%" }, { "loops", 'l', arg_integer, &_loops, "number of times to run this program(0=infinite loop)", "loops" }, { "parallelism", 'p', arg_integer, &_parallelism, "parallelism(1-240)", "para" }, { "records", 'r', arg_integer, &_records, "Number of records", "recs" }, - { "usage", '?', arg_flag, &_help, "Print help", "" } + { "usage", '?', arg_flag, &_help, "Print help", "" }, + { "lock", 'm', arg_integer, &lock, "lock mode", "" }, + { "sorted", 's', arg_flag, &sorted, "sorted", "" } }; int num_args = sizeof(args) / sizeof(args[0]); int optind = 0; @@ -73,16 +77,48 @@ int main(int argc, const char** argv){ ndbout << " Table " << _tabname << " does not exist!" << endl; return NDBT_ProgramExit(NDBT_WRONGARGS); } + + const NdbDictionary::Index * pIdx = 0; + if(optind+1 < argc) + { + pIdx = MyNdb.getDictionary()->getIndex(argv[optind+1], _tabname); + if(!pIdx) + ndbout << " Index " << argv[optind+1] << " not found" << endl; + else + if(pIdx->getType() != NdbDictionary::Index::UniqueOrderedIndex && + pIdx->getType() != NdbDictionary::Index::OrderedIndex) + { + ndbout << " Index " << argv[optind+1] << " is not scannable" << endl; + pIdx = 0; + } + } HugoTransactions hugoTrans(*pTab); int i = 0; while (i<_loops || _loops==0) { ndbout << i << ": "; - if(hugoTrans.scanReadRecords(&MyNdb, - 0, - _abort, - _parallelism) != 0){ - return NDBT_ProgramExit(NDBT_FAILED); + if(!pIdx) + { + if(hugoTrans.scanReadRecords(&MyNdb, + 0, + _abort, + _parallelism, + (NdbOperation::LockMode)lock) != 0) + { + return NDBT_ProgramExit(NDBT_FAILED); + } + } + else + { + if(hugoTrans.scanReadRecords(&MyNdb, pIdx, + 0, + _abort, + _parallelism, + (NdbOperation::LockMode)lock, + sorted) != 0) + { + return NDBT_ProgramExit(NDBT_FAILED); + } } i++; } diff --git a/ndb/tools/Makefile.am b/ndb/tools/Makefile.am index 9c086d665c1..7a61a9b1be5 100644 --- a/ndb/tools/Makefile.am +++ b/ndb/tools/Makefile.am @@ -26,7 +26,7 @@ ndb_select_all_SOURCES = select_all.cpp \ ../test/src/NDBT_ResultRow.cpp \ $(tools_common_sources) ndb_select_count_SOURCES = select_count.cpp $(tools_common_sources) -ndb_restore_SOURCES = restore/main.cpp \ +ndb_restore_SOURCES = restore/restore_main.cpp \ restore/consumer.cpp \ restore/consumer_restore.cpp \ restore/consumer_printer.cpp \ diff --git a/ndb/tools/delete_all.cpp b/ndb/tools/delete_all.cpp index a4fd73a5128..046ac8005d2 100644 --- a/ndb/tools/delete_all.cpp +++ b/ndb/tools/delete_all.cpp @@ -67,7 +67,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) diff --git a/ndb/tools/desc.cpp b/ndb/tools/desc.cpp index 8f7a2031ef0..c5e9efdfa8a 100644 --- a/ndb/tools/desc.cpp +++ b/ndb/tools/desc.cpp @@ -67,7 +67,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) diff --git a/ndb/tools/drop_index.cpp b/ndb/tools/drop_index.cpp index 1d4b454682f..6600811e0c4 100644 --- a/ndb/tools/drop_index.cpp +++ b/ndb/tools/drop_index.cpp @@ -64,7 +64,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) diff --git a/ndb/tools/drop_tab.cpp b/ndb/tools/drop_tab.cpp index 3362c7de47b..0661a8c599b 100644 --- a/ndb/tools/drop_tab.cpp +++ b/ndb/tools/drop_tab.cpp @@ -64,7 +64,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) diff --git a/ndb/tools/listTables.cpp b/ndb/tools/listTables.cpp index 05e864a35c4..ccb6967e2dc 100644 --- a/ndb/tools/listTables.cpp +++ b/ndb/tools/listTables.cpp @@ -220,7 +220,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); const char* _tabname; - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) @@ -228,10 +228,11 @@ int main(int argc, char** argv){ _tabname = argv[0]; ndb_cluster_connection = new Ndb_cluster_connection(opt_connect_str); + if (ndb_cluster_connection->connect(12,5,1)) + fatal("unable to connect"); ndb = new Ndb(ndb_cluster_connection, _dbname); if (ndb->init() != 0) fatal("init"); - ndb_cluster_connection->connect(); if (ndb->waitUntilReady(30) < 0) fatal("waitUntilReady"); dic = ndb->getDictionary(); diff --git a/ndb/tools/restore/main.cpp b/ndb/tools/restore/restore_main.cpp similarity index 94% rename from ndb/tools/restore/main.cpp rename to ndb/tools/restore/restore_main.cpp index 482212911cb..409ebd54764 100644 --- a/ndb/tools/restore/main.cpp +++ b/ndb/tools/restore/restore_main.cpp @@ -74,7 +74,7 @@ static struct my_option my_long_options[] = "No of parallel transactions during restore of data." "(parallelism can be 1 to 1024)", (gptr*) &ga_nParallelism, (gptr*) &ga_nParallelism, 0, - GET_INT, REQUIRED_ARG, 128, 0, 0, 0, 0, 0 }, + GET_INT, REQUIRED_ARG, 128, 1, 1024, 0, 1, 0 }, { "print", 256, "Print data and log to stdout", (gptr*) &_print, (gptr*) &_print, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 }, @@ -120,6 +120,20 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'V': print_version(); exit(0); + case 'n': + if (ga_nodeId == 0) + { + printf("Error in --nodeid,-n setting, see --help\n"); + exit(1); + } + break; + case 'b': + if (ga_backupId == 0) + { + printf("Error in --backupid,-b setting, see --help\n"); + exit(1); + } + break; case '?': usage(); exit(0); @@ -129,13 +143,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), bool readArguments(int *pargc, char*** pargv) { - const char *load_default_groups[]= { "ndb_tools","ndb_restore",0 }; + const char *load_default_groups[]= { "mysql_cluster","ndb_restore",0 }; load_defaults("my",load_default_groups,pargc,pargv); - if (handle_options(pargc, pargv, my_long_options, get_one_option) || - ga_nodeId == 0 || - ga_backupId == 0 || - ga_nParallelism < 1 || - ga_nParallelism >1024) { + if (handle_options(pargc, pargv, my_long_options, get_one_option)) + { exit(1); } @@ -343,7 +354,8 @@ main(int argc, char** argv) if (res < 0) { - err << "Restore: An error occured while restoring data. Exiting... res=" << res << endl; + err << "Restore: An error occured while restoring data. Exiting... " + << "res=" << res << endl; return -1; } @@ -369,7 +381,8 @@ main(int argc, char** argv) } if (res < 0) { - err << "Restore: An restoring the data log. Exiting... res=" << res << endl; + err << "Restore: An restoring the data log. Exiting... res=" + << res << endl; return -1; } logIter.validateFooter(); //not implemented diff --git a/ndb/tools/select_all.cpp b/ndb/tools/select_all.cpp index 758c1e48c88..5efeed485a4 100644 --- a/ndb/tools/select_all.cpp +++ b/ndb/tools/select_all.cpp @@ -50,7 +50,7 @@ static struct my_option my_long_options[] = GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { "parallelism", 'p', "parallelism", (gptr*) &_parallelism, (gptr*) &_parallelism, 0, - GET_INT, REQUIRED_ARG, 240, 0, 0, 0, 0, 0 }, + GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, { "lock", 'l', "Read(0), Read-hold(1), Exclusive(2)", (gptr*) &_lock, (gptr*) &_lock, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, @@ -105,7 +105,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); const char* _tabname; int ho_error; @@ -133,13 +133,18 @@ int main(int argc, char** argv){ const NdbDictionary::Table* pTab = NDBT_Table::discoverTableFromDb(&MyNdb, _tabname); const NdbDictionary::Index * pIdx = 0; if(argc > 1){ - pIdx = MyNdb.getDictionary()->getIndex(argv[0], _tabname); + pIdx = MyNdb.getDictionary()->getIndex(argv[1], _tabname); } if(pTab == NULL){ ndbout << " Table " << _tabname << " does not exist!" << endl; return NDBT_ProgramExit(NDBT_WRONGARGS); } + + if(argc > 1 && pIdx == 0) + { + ndbout << " Index " << argv[1] << " does not exists" << endl; + } if(_order && pIdx == NULL){ ndbout << " Order flag given without an index" << endl; diff --git a/ndb/tools/select_count.cpp b/ndb/tools/select_count.cpp index 6ee49ddbff0..c3491f842d8 100644 --- a/ndb/tools/select_count.cpp +++ b/ndb/tools/select_count.cpp @@ -83,7 +83,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); int ho_error; if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) diff --git a/ndb/tools/waiter.cpp b/ndb/tools/waiter.cpp index e24164ea807..5973b046f8f 100644 --- a/ndb/tools/waiter.cpp +++ b/ndb/tools/waiter.cpp @@ -23,7 +23,6 @@ #include #include #include -#include #include @@ -75,7 +74,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), int main(int argc, char** argv){ NDB_INIT(argv[0]); - const char *load_default_groups[]= { "ndb_tools",0 }; + const char *load_default_groups[]= { "mysql_cluster",0 }; load_defaults("my",load_default_groups,&argc,&argv); const char* _hostName = NULL; int ho_error; @@ -85,39 +84,8 @@ int main(int argc, char** argv){ char buf[255]; _hostName = argv[0]; - if (_hostName == NULL){ - LocalConfig lcfg; - if(!lcfg.init(opt_connect_str, 0)) - { - lcfg.printError(); - lcfg.printUsage(); - g_err << "Error parsing local config file" << endl; - return NDBT_ProgramExit(NDBT_FAILED); - } - - for (unsigned i = 0; itype){ - case MgmId_TCP: - snprintf(buf, 255, "%s:%d", m->name.c_str(), m->port); - _hostName = buf; - break; - case MgmId_File: - break; - default: - break; - } - if (_hostName != NULL) - break; - } - if (_hostName == NULL) - { - g_err << "No management servers configured in local config file" << endl; - return NDBT_ProgramExit(NDBT_FAILED); - } - } + if (_hostName == 0) + _hostName= opt_connect_str; if (_no_contact) { if (waitClusterStatus(_hostName, NDB_MGM_NODE_STATUS_NO_CONTACT, _timeout) != 0) @@ -210,13 +178,19 @@ waitClusterStatus(const char* _addr, int _nodes[MAX_NDB_NODES]; int _num_nodes = 0; - handle = ndb_mgm_create_handle(); + handle = ndb_mgm_create_handle(); if (handle == NULL){ g_err << "handle == NULL" << endl; return -1; } g_info << "Connecting to mgmsrv at " << _addr << endl; - if (ndb_mgm_connect(handle, _addr) == -1) { + if (ndb_mgm_set_connectstring(handle, _addr)) + { + MGMERR(handle); + g_err << "Connectstring " << _addr << " invalid" << endl; + return -1; + } + if (ndb_mgm_connect(handle,0,0,1)) { MGMERR(handle); g_err << "Connection to " << _addr << " failed" << endl; return -1; diff --git a/netware/comp_err.def b/netware/comp_err.def index d694c07174a..f27b40c7b78 100644 --- a/netware/comp_err.def +++ b/netware/comp_err.def @@ -2,7 +2,7 @@ # MySQL Error File Compiler #------------------------------------------------------------------------------ MODULE libc.nlm -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Error File Compiler" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/isamchk.def b/netware/isamchk.def index 69e8ac0405b..31cf3fc569a 100644 --- a/netware/isamchk.def +++ b/netware/isamchk.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL ISAM Table Check Tool" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL ISAM Table Check Tool" VERSION 4, 0 STACKSIZE 65536 diff --git a/netware/isamlog.def b/netware/isamlog.def index bb8312066ef..52f9de0d928 100644 --- a/netware/isamlog.def +++ b/netware/isamlog.def @@ -2,7 +2,7 @@ # ISAM Log #------------------------------------------------------------------------------ MODULE libc.nlm -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL ISAM Table Log Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/libmysql.def b/netware/libmysql.def index 7804c4468a5..fea117dedd1 100644 --- a/netware/libmysql.def +++ b/netware/libmysql.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm EXPORT @libmysql.imp -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Client Library" VERSION 4, 0 AUTOUNLOAD diff --git a/netware/my_print_defaults.def b/netware/my_print_defaults.def index 49f167341ae..826981256b5 100644 --- a/netware/my_print_defaults.def +++ b/netware/my_print_defaults.def @@ -2,7 +2,7 @@ # My Print Defaults #------------------------------------------------------------------------------ MODULE libc.nlm -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Print Defaults Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/myisam_ftdump.def b/netware/myisam_ftdump.def index 259d6617445..9639404b53b 100644 --- a/netware/myisam_ftdump.def +++ b/netware/myisam_ftdump.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL MyISAM Table Dump Tool" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL MyISAM Table Dump Tool" VERSION 4, 0 STACKSIZE 65536 diff --git a/netware/myisamchk.def b/netware/myisamchk.def index cdfe186058f..eaa01730872 100644 --- a/netware/myisamchk.def +++ b/netware/myisamchk.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL MyISAM Table Check Tool" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL MyISAM Table Check Tool" VERSION 4, 0 STACKSIZE 65536 diff --git a/netware/myisamlog.def b/netware/myisamlog.def index 5c4cbb23361..3580c870c10 100644 --- a/netware/myisamlog.def +++ b/netware/myisamlog.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL MyISAM Table Log Tool" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL MyISAM Table Log Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/myisampack.def b/netware/myisampack.def index 9111538c2c0..a6946982236 100644 --- a/netware/myisampack.def +++ b/netware/myisampack.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL MyISAM Table Pack Tool" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL MyISAM Table Pack Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/mysql.def b/netware/mysql.def index 9b4424ed4fb..5ae8dc102a0 100644 --- a/netware/mysql.def +++ b/netware/mysql.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL Monitor" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Monitor" VERSION 4, 0 MULTIPLE diff --git a/netware/mysql_install.def b/netware/mysql_install.def index 87fc76919f9..3392afb7298 100644 --- a/netware/mysql_install.def +++ b/netware/mysql_install.def @@ -2,7 +2,7 @@ # My Print Defaults #------------------------------------------------------------------------------ MODULE libc.nlm -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Install Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/mysql_install_db.def b/netware/mysql_install_db.def index 4653638b5ad..1657b7c17af 100644 --- a/netware/mysql_install_db.def +++ b/netware/mysql_install_db.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL Install" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Initial Database Installer" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/mysql_test_run.def b/netware/mysql_test_run.def index b34f62a1f91..d4d4baee168 100644 --- a/netware/mysql_test_run.def +++ b/netware/mysql_test_run.def @@ -4,7 +4,7 @@ MODULE libc.nlm STACKSIZE 65536 SCREENNAME "MySQL Test Run" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Test Run" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/mysql_waitpid.def b/netware/mysql_waitpid.def index 4d56d29c42f..da0884ccba3 100644 --- a/netware/mysql_waitpid.def +++ b/netware/mysql_waitpid.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm #SCREENNAME "MySQL Tool - Wait for a Program to Terminate" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Tool - Wait for a Program to Terminate" VERSION 4, 0 STACKSIZE 65536 diff --git a/netware/mysqladmin.def b/netware/mysqladmin.def index 0ace36992b1..46f90d531fa 100644 --- a/netware/mysqladmin.def +++ b/netware/mysqladmin.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL Admin" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Admin Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/mysqlbinlog.def b/netware/mysqlbinlog.def index 89677b4a353..25a470e7353 100644 --- a/netware/mysqlbinlog.def +++ b/netware/mysqlbinlog.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL Binary Log Dump Tool" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Binary Log Dump Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/mysqlcheck.def b/netware/mysqlcheck.def index 8820e9aae8e..7067b1d1729 100644 --- a/netware/mysqlcheck.def +++ b/netware/mysqlcheck.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL Check Tool" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Check Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/mysqld.def b/netware/mysqld.def index 6856aefe56c..42c2d176a1b 100644 --- a/netware/mysqld.def +++ b/netware/mysqld.def @@ -2,7 +2,7 @@ # MySQL Server #------------------------------------------------------------------------------ MODULE libc.nlm -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Database Server" VERSION 4, 0 MULTIPLE diff --git a/netware/mysqld_safe.def b/netware/mysqld_safe.def index 9080ef783c9..2a9ef04b47d 100644 --- a/netware/mysqld_safe.def +++ b/netware/mysqld_safe.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL Database Server" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Database Server Monitor" VERSION 4, 0 MULTIPLE diff --git a/netware/mysqldump.def b/netware/mysqldump.def index 901c9b262dc..ddacf7bc0d5 100644 --- a/netware/mysqldump.def +++ b/netware/mysqldump.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL Dump Tool" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Dump Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/mysqlimport.def b/netware/mysqlimport.def index d6f7fcb6bbd..5253da42567 100644 --- a/netware/mysqlimport.def +++ b/netware/mysqlimport.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL Import" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Import Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/mysqlshow.def b/netware/mysqlshow.def index 2b41386f643..0b61b81dcf9 100644 --- a/netware/mysqlshow.def +++ b/netware/mysqlshow.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm SCREENNAME "MySQL Show" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Show Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/mysqltest.def b/netware/mysqltest.def index d98f6436a4a..e134acede07 100644 --- a/netware/mysqltest.def +++ b/netware/mysqltest.def @@ -2,7 +2,7 @@ # MySQL Admin #------------------------------------------------------------------------------ MODULE libc.nlm -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Test Case Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/pack_isam.def b/netware/pack_isam.def index f0f5a7e328a..b93cfdffbeb 100644 --- a/netware/pack_isam.def +++ b/netware/pack_isam.def @@ -2,7 +2,7 @@ # Pack ISAM #------------------------------------------------------------------------------ MODULE libc.nlm -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL ISAM Table Pack Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/perror.def b/netware/perror.def index f1d23715f55..18c95d8b236 100644 --- a/netware/perror.def +++ b/netware/perror.def @@ -2,7 +2,7 @@ # PERROR #------------------------------------------------------------------------------ MODULE libc.nlm -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Error Code Description Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/replace.def b/netware/replace.def index b55690152b9..19348ee4245 100644 --- a/netware/replace.def +++ b/netware/replace.def @@ -2,7 +2,7 @@ # Replace #------------------------------------------------------------------------------ MODULE libc.nlm -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Text Replacement Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/netware/resolve_stack_dump.def b/netware/resolve_stack_dump.def index 21fd177fbc7..01042699d61 100644 --- a/netware/resolve_stack_dump.def +++ b/netware/resolve_stack_dump.def @@ -3,7 +3,7 @@ #------------------------------------------------------------------------------ MODULE libc.nlm #SCREENNAME "MySQL Stack Dump Resolve Tool" -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL Stack Dump Resolve Tool" VERSION 4, 0 STACKSIZE 65536 diff --git a/netware/resolveip.def b/netware/resolveip.def index 10b99304e22..244f52bb969 100644 --- a/netware/resolveip.def +++ b/netware/resolveip.def @@ -2,7 +2,7 @@ # Resolve IP #------------------------------------------------------------------------------ MODULE libc.nlm -COPYRIGHT "(c) 2003 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." +COPYRIGHT "(c) 2003-2005 Novell, Inc. Portions (c) 2003 MySQL AB. All Rights Reserved." DESCRIPTION "MySQL IP/Hostname Resolve Tool" VERSION 4, 0 XDCDATA ../netware/mysql.xdc diff --git a/scripts/mysql_fix_privilege_tables.sh b/scripts/mysql_fix_privilege_tables.sh index c9e8e0c4dfd..b84e512b69a 100644 --- a/scripts/mysql_fix_privilege_tables.sh +++ b/scripts/mysql_fix_privilege_tables.sh @@ -115,7 +115,7 @@ then password=$old_style_password fi -cmd="$bindir/mysql -f --user=$user --host=$host" +cmd="$bindir/mysql --no-defaults --force --user=$user --host=$host" if test ! -z "$password" ; then cmd="$cmd --password=$password" fi diff --git a/sql-common/my_time.c b/sql-common/my_time.c index d1a36a75a5a..29935696b7d 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -343,7 +343,8 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, (l_time->month || l_time->day)) l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); - if (number_of_fields < 3 || l_time->month > 12 || + if (number_of_fields < 3 || + l_time->year > 9999 || l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 || l_time->minute > 59 || l_time->second > 59 || (!(flags & TIME_FUZZY_DATE) && (l_time->month == 0 || l_time->day == 0))) @@ -733,10 +734,10 @@ my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap) /* Set MYSQL_TIME structure to 0000-00-00 00:00:00.000000 */ -void set_zero_time(MYSQL_TIME *tm) +void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type) { bzero((void*) tm, sizeof(*tm)); - tm->time_type= MYSQL_TIMESTAMP_NONE; + tm->time_type= time_type; } diff --git a/sql/field.cc b/sql/field.cc index bbd21247b8e..db4b8f352c7 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1860,9 +1860,9 @@ int Field_long::store(double nr) set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } - else if (nr > (double) (ulong) ~0L) + else if (nr > (double) UINT_MAX32) { - res=(int32) (uint32) ~0L; + res= UINT_MAX32; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1); error= 1; } @@ -4086,6 +4086,10 @@ int Field_datetime::store(longlong nr) void Field_datetime::store_time(TIME *ltime,timestamp_type type) { longlong tmp; + /* + We don't perform range checking here since values stored in TIME + structure always fit into DATETIME range. + */ if (type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME) tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+ (ltime->hour*10000L+ltime->minute*100+ltime->second)); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 07d8da63733..cc69762cbdb 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -331,6 +331,9 @@ convert_error_code_to_mysql( } else if (error == (int) DB_NO_SAVEPOINT) { return(HA_ERR_NO_SAVEPOINT); + } else if (error == (int) DB_LOCK_TABLE_FULL) { + + return(HA_ERR_LOCK_TABLE_FULL); } else { return(-1); // Unknown error } @@ -2321,20 +2324,58 @@ ha_innobase::write_row( position in the source table need not be adjusted after the intermediate COMMIT, since writes by other transactions are being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */ - ut_a(prebuilt->trx->mysql_n_tables_locked == 2); - ut_a(UT_LIST_GET_LEN(prebuilt->trx->trx_locks) >= 2); - dict_table_t* table = lock_get_ix_table( - UT_LIST_GET_FIRST(prebuilt->trx->trx_locks)); + + dict_table_t* src_table; + ibool mode; + num_write_row = 0; + /* Commit the transaction. This will release the table locks, so they have to be acquired again. */ - innobase_commit(user_thd, prebuilt->trx); - /* Note that this transaction is still active. */ - user_thd->transaction.all.innodb_active_trans = 1; - /* Re-acquire the IX table lock on the source table. */ - row_lock_table_for_mysql(prebuilt, table); - /* We will need an IX lock on the destination table. */ - prebuilt->sql_stat_start = TRUE; + + /* Altering an InnoDB table */ + /* Get the source table. */ + src_table = lock_get_src_table( + prebuilt->trx, prebuilt->table, &mode); + if (!src_table) { + no_commit: + /* Unknown situation: do not commit */ + /* + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB error: ALTER TABLE is holding lock" + " on %lu tables!\n", + prebuilt->trx->mysql_n_tables_locked); + */ + ; + } else if (src_table == prebuilt->table) { + /* Source table is not in InnoDB format: + no need to re-acquire locks on it. */ + + /* Altering to InnoDB format */ + innobase_commit(user_thd, prebuilt->trx); + /* Note that this transaction is still active. */ + user_thd->transaction.all.innodb_active_trans = 1; + /* We will need an IX lock on the destination table. */ + prebuilt->sql_stat_start = TRUE; + } else { + /* Ensure that there are no other table locks than + LOCK_IX and LOCK_AUTO_INC on the destination table. */ + if (!lock_is_table_exclusive(prebuilt->table, + prebuilt->trx)) { + goto no_commit; + } + + /* Commit the transaction. This will release the table + locks, so they have to be acquired again. */ + innobase_commit(user_thd, prebuilt->trx); + /* Note that this transaction is still active. */ + user_thd->transaction.all.innodb_active_trans = 1; + /* Re-acquire the table lock on the source table. */ + row_lock_table_for_mysql(prebuilt, src_table, mode); + /* We will need an IX lock on the destination table. */ + prebuilt->sql_stat_start = TRUE; + } } num_write_row++; @@ -5012,7 +5053,8 @@ ha_innobase::external_lock( if (thd->in_lock_tables && thd->variables.innodb_table_locks) { ulint error; - error = row_lock_table_for_mysql(prebuilt, 0); + error = row_lock_table_for_mysql(prebuilt, + NULL, LOCK_TABLE_EXP); if (error != DB_SUCCESS) { error = convert_error_code_to_mysql( diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index cdbf2eb3d6a..6c609cd54ac 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -39,9 +39,6 @@ static const int parallelism= 240; // createable against NDB from this handler static const int max_transactions= 256; -// Default value for prefetch of autoincrement values -static const ha_rows autoincrement_prefetch= 32; - // connectstring to cluster if given by mysqld const char *ndbcluster_connectstring= 0; @@ -103,51 +100,52 @@ struct err_code_mapping { int ndb_err; int my_err; + int show_warning; }; static const err_code_mapping err_map[]= { - { 626, HA_ERR_KEY_NOT_FOUND }, - { 630, HA_ERR_FOUND_DUPP_KEY }, - { 893, HA_ERR_FOUND_DUPP_UNIQUE }, - { 721, HA_ERR_TABLE_EXIST }, - { 4244, HA_ERR_TABLE_EXIST }, + { 626, HA_ERR_KEY_NOT_FOUND, 0 }, + { 630, HA_ERR_FOUND_DUPP_KEY, 0 }, + { 893, HA_ERR_FOUND_DUPP_KEY, 0 }, + { 721, HA_ERR_TABLE_EXIST, 1 }, + { 4244, HA_ERR_TABLE_EXIST, 1 }, - { 709, HA_ERR_NO_SUCH_TABLE }, - { 284, HA_ERR_NO_SUCH_TABLE }, + { 709, HA_ERR_NO_SUCH_TABLE, 1 }, + { 284, HA_ERR_NO_SUCH_TABLE, 1 }, - { 266, HA_ERR_LOCK_WAIT_TIMEOUT }, - { 274, HA_ERR_LOCK_WAIT_TIMEOUT }, - { 296, HA_ERR_LOCK_WAIT_TIMEOUT }, - { 297, HA_ERR_LOCK_WAIT_TIMEOUT }, - { 237, HA_ERR_LOCK_WAIT_TIMEOUT }, + { 266, HA_ERR_LOCK_WAIT_TIMEOUT, 1 }, + { 274, HA_ERR_LOCK_WAIT_TIMEOUT, 1 }, + { 296, HA_ERR_LOCK_WAIT_TIMEOUT, 1 }, + { 297, HA_ERR_LOCK_WAIT_TIMEOUT, 1 }, + { 237, HA_ERR_LOCK_WAIT_TIMEOUT, 1 }, - { 623, HA_ERR_RECORD_FILE_FULL }, - { 624, HA_ERR_RECORD_FILE_FULL }, - { 625, HA_ERR_RECORD_FILE_FULL }, - { 826, HA_ERR_RECORD_FILE_FULL }, - { 827, HA_ERR_RECORD_FILE_FULL }, - { 832, HA_ERR_RECORD_FILE_FULL }, + { 623, HA_ERR_RECORD_FILE_FULL, 1 }, + { 624, HA_ERR_RECORD_FILE_FULL, 1 }, + { 625, HA_ERR_RECORD_FILE_FULL, 1 }, + { 826, HA_ERR_RECORD_FILE_FULL, 1 }, + { 827, HA_ERR_RECORD_FILE_FULL, 1 }, + { 832, HA_ERR_RECORD_FILE_FULL, 1 }, - { 0, 1 }, + { 0, 1, 0 }, - { -1, -1 } + { -1, -1, 1 } }; static int ndb_to_mysql_error(const NdbError *err) { uint i; - for (i=0 ; err_map[i].ndb_err != err->code ; i++) + for (i=0; err_map[i].ndb_err != err->code && err_map[i].my_err != -1; i++); + if (err_map[i].show_warning) { - if (err_map[i].my_err == -1){ - // Push the NDB error message as warning - push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, - ER_GET_ERRMSG, ER(ER_GET_ERRMSG), - err->code, err->message, "NDB"); - return err->code; - } + // Push the NDB error message as warning + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_GET_ERRMSG, ER(ER_GET_ERRMSG), + err->code, err->message, "NDB"); } + if (err_map[i].my_err == -1) + return err->code; return err_map[i].my_err; } @@ -161,7 +159,7 @@ int execute_no_commit(ha_ndbcluster *h, NdbConnection *trans) if (m_batch_execute) return 0; #endif - return trans->execute(NoCommit,AbortOnError,1); + return trans->execute(NoCommit,AbortOnError,h->m_force_send); } inline @@ -172,7 +170,18 @@ int execute_commit(ha_ndbcluster *h, NdbConnection *trans) if (m_batch_execute) return 0; #endif - return trans->execute(Commit,AbortOnError,1); + return trans->execute(Commit,AbortOnError,h->m_force_send); +} + +inline +int execute_commit(THD *thd, NdbConnection *trans) +{ + int m_batch_execute= 0; +#ifdef NOT_USED + if (m_batch_execute) + return 0; +#endif + return trans->execute(Commit,AbortOnError,thd->variables.ndb_force_send); } inline @@ -183,7 +192,7 @@ int execute_no_commit_ie(ha_ndbcluster *h, NdbConnection *trans) if (m_batch_execute) return 0; #endif - return trans->execute(NoCommit,IgnoreError,1); + return trans->execute(NoCommit,IgnoreError,h->m_force_send); } /* @@ -226,6 +235,8 @@ void ha_ndbcluster::set_rec_per_key() void ha_ndbcluster::records_update() { + if (m_ha_not_exact_count) + return; DBUG_ENTER("ha_ndbcluster::records_update"); struct Ndb_table_local_info *info= (struct Ndb_table_local_info *)m_table_info; DBUG_PRINT("info", ("id=%d, no_uncommitted_rows_count=%d", @@ -249,6 +260,8 @@ void ha_ndbcluster::records_update() void ha_ndbcluster::no_uncommitted_rows_execute_failure() { + if (m_ha_not_exact_count) + return; DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_execute_failure"); THD *thd= current_thd; ((Thd_ndb*)(thd->transaction.thd_ndb))->error= 1; @@ -257,6 +270,8 @@ void ha_ndbcluster::no_uncommitted_rows_execute_failure() void ha_ndbcluster::no_uncommitted_rows_init(THD *thd) { + if (m_ha_not_exact_count) + return; DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_init"); struct Ndb_table_local_info *info= (struct Ndb_table_local_info *)m_table_info; Thd_ndb *thd_ndb= (Thd_ndb *)thd->transaction.thd_ndb; @@ -274,6 +289,8 @@ void ha_ndbcluster::no_uncommitted_rows_init(THD *thd) void ha_ndbcluster::no_uncommitted_rows_update(int c) { + if (m_ha_not_exact_count) + return; DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_update"); struct Ndb_table_local_info *info= (struct Ndb_table_local_info *)m_table_info; @@ -286,6 +303,8 @@ void ha_ndbcluster::no_uncommitted_rows_update(int c) void ha_ndbcluster::no_uncommitted_rows_reset(THD *thd) { + if (m_ha_not_exact_count) + return; DBUG_ENTER("ha_ndbcluster::no_uncommitted_rows_reset"); ((Thd_ndb*)(thd->transaction.thd_ndb))->count++; ((Thd_ndb*)(thd->transaction.thd_ndb))->error= 0; @@ -777,7 +796,8 @@ int ha_ndbcluster::build_index_list(TABLE *tab, enum ILBP phase) error= create_unique_index(unique_index_name, key_info); break; case UNIQUE_INDEX: - error= create_unique_index(unique_index_name, key_info); + if (!(error= check_index_fields_not_null(i))) + error= create_unique_index(unique_index_name, key_info); break; case ORDERED_INDEX: error= create_ordered_index(index_name, key_info); @@ -829,6 +849,26 @@ NDB_INDEX_TYPE ha_ndbcluster::get_index_type_from_table(uint inx) const ORDERED_INDEX); } +int ha_ndbcluster::check_index_fields_not_null(uint inx) +{ + KEY* key_info= table->key_info + inx; + KEY_PART_INFO* key_part= key_info->key_part; + KEY_PART_INFO* end= key_part+key_info->key_parts; + DBUG_ENTER("check_index_fields_not_null"); + + for (; key_part != end; key_part++) + { + Field* field= key_part->field; + if (field->maybe_null()) + { + my_printf_error(ER_NULL_COLUMN_IN_INDEX,ER(ER_NULL_COLUMN_IN_INDEX), + MYF(0),field->field_name); + DBUG_RETURN(ER_NULL_COLUMN_IN_INDEX); + } + } + + DBUG_RETURN(0); +} void ha_ndbcluster::release_metadata() { @@ -1018,7 +1058,8 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf) { Field *field= table->field[i]; if ((thd->query_id == field->query_id) || - m_retrieve_all_fields) + m_retrieve_all_fields || + (field->flags & PRI_KEY_FLAG) && m_retrieve_primary_key) { if (get_ndb_value(op, field, i, buf)) ERR_RETURN(trans->getNdbError()); @@ -1093,6 +1134,34 @@ int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data) DBUG_RETURN(0); } +/* + Peek to check if a particular row already exists +*/ + +int ha_ndbcluster::peek_row() +{ + NdbConnection *trans= m_active_trans; + NdbOperation *op; + THD *thd= current_thd; + DBUG_ENTER("peek_row"); + + NdbOperation::LockMode lm= + (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); + if (!(op= trans->getNdbOperation((const NDBTAB *) m_table)) || + op->readTuple(lm) != 0) + ERR_RETURN(trans->getNdbError()); + + int res; + if ((res= set_primary_key(op))) + ERR_RETURN(trans->getNdbError()); + + if (execute_no_commit_ie(this,trans) != 0) + { + table->status= STATUS_NOT_FOUND; + DBUG_RETURN(ndb_err(trans)); + } + DBUG_RETURN(0); +} /* Read one record from NDB using unique secondary index @@ -1128,9 +1197,10 @@ int ha_ndbcluster::unique_index_read(const byte *key, for (i= 0; key_part != end; key_part++, i++) { - if (set_ndb_key(op, key_part->field, i, key_ptr)) + if (set_ndb_key(op, key_part->field, i, + key_part->null_bit ? key_ptr + 1 : key_ptr)) ERR_RETURN(trans->getNdbError()); - key_ptr+= key_part->length; + key_ptr+= key_part->store_length; } // Get non-index attribute(s) @@ -1138,7 +1208,7 @@ int ha_ndbcluster::unique_index_read(const byte *key, { Field *field= table->field[i]; if ((thd->query_id == field->query_id) || - (field->flags & PRI_KEY_FLAG)) + (field->flags & PRI_KEY_FLAG)) // && m_retrieve_primary_key ?? { if (get_ndb_value(op, field, i, buf)) ERR_RETURN(op->getNdbError()); @@ -1199,7 +1269,7 @@ inline int ha_ndbcluster::next_result(byte *buf) m_ops_pending= 0; m_blobs_pending= FALSE; } - check= cursor->nextResult(contact_ndb); + check= cursor->nextResult(contact_ndb, m_force_send); if (check == 0) { // One more record found @@ -1222,7 +1292,8 @@ inline int ha_ndbcluster::next_result(byte *buf) DBUG_PRINT("info", ("ops_pending: %d", m_ops_pending)); if (m_ops_pending) { - if (current_thd->transaction.on) + // if (current_thd->transaction.on) + if (m_transaction_on) { if (execute_no_commit(this,trans) != 0) DBUG_RETURN(ndb_err(trans)); @@ -1491,7 +1562,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, DBUG_ASSERT(op->getSorted() == sorted); DBUG_ASSERT(op->getLockMode() == (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type)); - if(op->reset_bounds()) + if(op->reset_bounds(m_force_send)) DBUG_RETURN(ndb_err(m_active_trans)); } @@ -1566,7 +1637,7 @@ int ha_ndbcluster::filtered_scan(const byte *key, uint key_len, Field* field= key_part->field; uint ndb_fieldnr= key_part->fieldnr-1; DBUG_PRINT("key_part", ("fieldnr: %d", ndb_fieldnr)); - // const NDBCOL *col= tab->getColumn(ndb_fieldnr); + //const NDBCOL *col= ((const NDBTAB *) m_table)->getColumn(ndb_fieldnr); uint32 field_len= field->pack_length(); DBUG_DUMP("key", (char*)key, field_len); @@ -1635,9 +1706,17 @@ int ha_ndbcluster::write_row(byte *record) int res; DBUG_ENTER("write_row"); - if(m_ignore_dup_key_not_supported) + if(m_ignore_dup_key && table->primary_key != MAX_KEY) { - DBUG_RETURN(HA_ERR_WRONG_COMMAND); + int peek_res= peek_row(); + + if (!peek_res) + { + m_dupkey= table->primary_key; + DBUG_RETURN(HA_ERR_FOUND_DUPP_KEY); + } + if (peek_res != HA_ERR_KEY_NOT_FOUND) + DBUG_RETURN(peek_res); } statistic_increment(ha_write_count,&LOCK_status); @@ -1708,7 +1787,8 @@ int ha_ndbcluster::write_row(byte *record) (int)m_rows_inserted, (int)m_bulk_insert_rows)); m_bulk_insert_not_flushed= FALSE; - if (thd->transaction.on) + // if (thd->transaction.on) + if (m_transaction_on) { if (execute_no_commit(this,trans) != 0) { @@ -1881,7 +1961,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) for (i= 0; i < table->fields; i++) { Field *field= table->field[i]; - if ((thd->query_id == field->query_id) && + if (((thd->query_id == field->query_id) || m_retrieve_all_fields) && (!(field->flags & PRI_KEY_FLAG)) && set_ndb_value(op, field, i)) ERR_RETURN(op->getNdbError()); @@ -2149,17 +2229,15 @@ void ha_ndbcluster::print_results() break; } case NdbDictionary::Column::Char:{ - char buf[field->pack_length()+1]; - char *value= (char *) field->ptr; - snprintf(buf, field->pack_length(), "%s", value); - fprintf(DBUG_FILE, "Char\t'%s'", buf); + const char *value= (char *) field->ptr; + fprintf(DBUG_FILE, "Char\t'%.*s'", field->pack_length(), value); break; } case NdbDictionary::Column::Varchar: case NdbDictionary::Column::Binary: case NdbDictionary::Column::Varbinary: { - char *value= (char *) field->ptr; - fprintf(DBUG_FILE, "'%s'", value); + const char *value= (char *) field->ptr; + fprintf(DBUG_FILE, "Var\t'%.*s'", field->pack_length(), value); break; } case NdbDictionary::Column::Datetime: { @@ -2210,6 +2288,28 @@ int ha_ndbcluster::index_end() DBUG_RETURN(close_scan()); } +/** + * Check if key contains null + */ +static +int +check_null_in_key(const KEY* key_info, const byte *key, uint key_len) +{ + KEY_PART_INFO *curr_part, *end_part; + const byte* end_ptr = key + key_len; + curr_part= key_info->key_part; + end_part= curr_part + key_info->key_parts; + + + for (; curr_part != end_part && key < end_ptr; curr_part++) + { + if(curr_part->null_bit && *key) + return 1; + + key += curr_part->store_length; + } + return 0; +} int ha_ndbcluster::index_read(byte *buf, const byte *key, uint key_len, @@ -2227,6 +2327,8 @@ int ha_ndbcluster::index_read(byte *buf, case PRIMARY_KEY_INDEX: if (find_flag == HA_READ_KEY_EXACT && key_info->key_length == key_len) { + if(m_active_cursor && (error= close_scan())) + DBUG_RETURN(error); DBUG_RETURN(pk_read(key, key_len, buf)); } else if (type == PRIMARY_KEY_INDEX) @@ -2236,8 +2338,11 @@ int ha_ndbcluster::index_read(byte *buf, break; case UNIQUE_ORDERED_INDEX: case UNIQUE_INDEX: - if (find_flag == HA_READ_KEY_EXACT && key_info->key_length == key_len) + if (find_flag == HA_READ_KEY_EXACT && key_info->key_length == key_len && + !check_null_in_key(key_info, key, key_len)) { + if(m_active_cursor && (error= close_scan())) + DBUG_RETURN(error); DBUG_RETURN(unique_index_read(key, key_len, buf)); } else if (type == UNIQUE_INDEX) @@ -2311,7 +2416,7 @@ int ha_ndbcluster::index_last(byte *buf) int res; if((res= ordered_index_scan(0, 0, TRUE, buf)) == 0){ NdbResultSet *cursor= m_active_cursor; - while((res= cursor->nextResult(TRUE)) == 0); + while((res= cursor->nextResult(TRUE, m_force_send)) == 0); if(res == 1){ unpack_record(buf); table->status= 0; @@ -2341,6 +2446,8 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, start_key->length == key_info->key_length && start_key->flag == HA_READ_KEY_EXACT) { + if(m_active_cursor && (error= close_scan())) + DBUG_RETURN(error); error= pk_read(start_key->key, start_key->length, buf); DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error); } @@ -2348,10 +2455,12 @@ int ha_ndbcluster::read_range_first_to_buf(const key_range *start_key, case UNIQUE_ORDERED_INDEX: case UNIQUE_INDEX: key_info= table->key_info + active_index; - if (start_key && - start_key->length == key_info->key_length && - start_key->flag == HA_READ_KEY_EXACT) + if (start_key && start_key->length == key_info->key_length && + start_key->flag == HA_READ_KEY_EXACT && + !check_null_in_key(key_info, start_key->key, start_key->length)) { + if(m_active_cursor && (error= close_scan())) + DBUG_RETURN(error); error= unique_index_read(start_key->key, start_key->length, buf); DBUG_RETURN(error == HA_ERR_KEY_NOT_FOUND ? HA_ERR_END_OF_FILE : error); } @@ -2397,7 +2506,7 @@ int ha_ndbcluster::rnd_init(bool scan) { if (!scan) DBUG_RETURN(1); - int res= cursor->restart(); + int res= cursor->restart(m_force_send); DBUG_ASSERT(res == 0); } index_init(table->primary_key); @@ -2428,7 +2537,7 @@ int ha_ndbcluster::close_scan() m_ops_pending= 0; } - cursor->close(); + cursor->close(m_force_send); m_active_cursor= NULL; DBUG_RETURN(0); } @@ -2540,14 +2649,17 @@ void ha_ndbcluster::info(uint flag) DBUG_PRINT("info", ("HA_STATUS_VARIABLE")); if (m_table_info) { - records_update(); + if (m_ha_not_exact_count) + records= 100; + else + records_update(); } else { - Uint64 rows; - if(ndb_get_table_statistics(m_ndb, m_tabname, &rows, 0) == 0){ - records= rows; - } + Uint64 rows= 100; + if (current_thd->variables.ndb_use_exact_count) + ndb_get_table_statistics(m_ndb, m_tabname, &rows, 0); + records= rows; } } if (flag & HA_STATUS_CONST) @@ -2653,15 +2765,15 @@ int ha_ndbcluster::extra(enum ha_extra_function operation) m_use_write= TRUE; } else { - if (table->keys) - m_ignore_dup_key_not_supported= TRUE; + DBUG_PRINT("info", ("Ignoring duplicate key")); + m_ignore_dup_key= TRUE; } break; case HA_EXTRA_NO_IGNORE_DUP_KEY: DBUG_PRINT("info", ("HA_EXTRA_NO_IGNORE_DUP_KEY")); DBUG_PRINT("info", ("Turning OFF use of write instead of insert")); m_use_write= FALSE; - m_ignore_dup_key_not_supported= FALSE; + m_ignore_dup_key= FALSE; break; case HA_EXTRA_RETRIEVE_ALL_COLS: /* Retrieve all columns, not just those where field->query_id is the same as @@ -2680,6 +2792,7 @@ int ha_ndbcluster::extra(enum ha_extra_function operation) break; case HA_EXTRA_RETRIEVE_PRIMARY_KEY: DBUG_PRINT("info", ("HA_EXTRA_RETRIEVE_PRIMARY_KEY")); + m_retrieve_primary_key= TRUE; break; case HA_EXTRA_CHANGE_KEY_TO_UNIQUE: DBUG_PRINT("info", ("HA_EXTRA_CHANGE_KEY_TO_UNIQUE")); @@ -2936,12 +3049,23 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) pointer to point to the NDB transaction. */ + // store thread specific data first to set the right context + m_force_send= thd->variables.ndb_force_send; + m_ha_not_exact_count= !thd->variables.ndb_use_exact_count; + m_autoincrement_prefetch= thd->variables.ndb_autoincrement_prefetch_sz; + if (!thd->transaction.on) + m_transaction_on= FALSE; + else + m_transaction_on= thd->variables.ndb_use_transactions; + // m_use_local_query_cache= thd->variables.ndb_use_local_query_cache; + m_active_trans= thd->transaction.all.ndb_tid ? (NdbConnection*)thd->transaction.all.ndb_tid: (NdbConnection*)thd->transaction.stmt.ndb_tid; DBUG_ASSERT(m_active_trans); // Start of transaction m_retrieve_all_fields= FALSE; + m_retrieve_primary_key= FALSE; m_ops_pending= 0; { NDBDICT *dict= m_ndb->getDictionary(); @@ -3034,6 +3158,7 @@ int ha_ndbcluster::start_stmt(THD *thd) // Start of statement m_retrieve_all_fields= FALSE; + m_retrieve_primary_key= FALSE; m_ops_pending= 0; DBUG_RETURN(error); @@ -3056,7 +3181,7 @@ int ndbcluster_commit(THD *thd, void *ndb_transaction) "stmt" : "all")); DBUG_ASSERT(ndb && trans); - if (execute_commit(0,trans) != 0) + if (execute_commit(thd,trans) != 0) { const NdbError err= trans->getNdbError(); const NdbOperation *error_op= trans->getNdbErrorOperation(); @@ -3610,11 +3735,11 @@ longlong ha_ndbcluster::get_auto_increment() DBUG_ENTER("get_auto_increment"); DBUG_PRINT("enter", ("m_tabname: %s", m_tabname)); int cache_size= - (m_rows_to_insert - m_rows_inserted < autoincrement_prefetch) ? + (m_rows_to_insert - m_rows_inserted < m_autoincrement_prefetch) ? m_rows_to_insert - m_rows_inserted - : (m_rows_to_insert > autoincrement_prefetch) ? + : (m_rows_to_insert > m_autoincrement_prefetch) ? m_rows_to_insert - : autoincrement_prefetch; + : m_autoincrement_prefetch; Uint64 auto_value= (m_skip_auto_increment) ? m_ndb->readAutoIncrementValue((const NDBTAB *) m_table) @@ -3640,9 +3765,10 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): HA_NO_PREFIX_CHAR_KEYS), m_share(0), m_use_write(FALSE), - m_ignore_dup_key_not_supported(FALSE), + m_ignore_dup_key(FALSE), m_primary_key_update(FALSE), m_retrieve_all_fields(FALSE), + m_retrieve_primary_key(FALSE), m_rows_to_insert(1), m_rows_inserted(0), m_bulk_insert_rows(1024), @@ -3652,7 +3778,12 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): m_blobs_pending(0), m_blobs_buffer(0), m_blobs_buffer_size(0), - m_dupkey((uint) -1) + m_dupkey((uint) -1), + m_ha_not_exact_count(FALSE), + m_force_send(TRUE), + m_autoincrement_prefetch(32), + m_transaction_on(TRUE), + m_use_local_query_cache(FALSE) { int i; @@ -4100,7 +4231,7 @@ bool ndbcluster_init() new Ndb_cluster_connection(ndbcluster_connectstring)) == 0) { DBUG_PRINT("error",("Ndb_cluster_connection(%s)",ndbcluster_connectstring)); - DBUG_RETURN(TRUE); + goto ndbcluster_init_error; } // Create a Ndb object to open the connection to NDB @@ -4109,25 +4240,33 @@ bool ndbcluster_init() if (g_ndb->init() != 0) { ERR_PRINT (g_ndb->getNdbError()); - DBUG_RETURN(TRUE); + goto ndbcluster_init_error; } - if ((res= g_ndb_cluster_connection->connect(1)) == 0) + if ((res= g_ndb_cluster_connection->connect(0,0,0)) == 0) { + DBUG_PRINT("info",("NDBCLUSTER storage engine at %s on port %d", + g_ndb_cluster_connection->get_connected_host(), + g_ndb_cluster_connection->get_connected_port())); g_ndb->waitUntilReady(10); } else if(res == 1) { if (g_ndb_cluster_connection->start_connect_thread()) { DBUG_PRINT("error", ("g_ndb_cluster_connection->start_connect_thread()")); - DBUG_RETURN(TRUE); + goto ndbcluster_init_error; + } + { + char buf[1024]; + DBUG_PRINT("info",("NDBCLUSTER storage engine not started, will connect using %s", + g_ndb_cluster_connection->get_connectstring(buf,sizeof(buf)))); } } else { DBUG_ASSERT(res == -1); DBUG_PRINT("error", ("permanent error")); - DBUG_RETURN(TRUE); + goto ndbcluster_init_error; } (void) hash_init(&ndbcluster_open_tables,system_charset_info,32,0,0, @@ -4137,9 +4276,12 @@ bool ndbcluster_init() ndbcluster_inited= 1; #ifdef USE_DISCOVER_ON_STARTUP if (ndb_discover_tables() != 0) - DBUG_RETURN(TRUE); + goto ndbcluster_init_error; #endif DBUG_RETURN(FALSE); + ndbcluster_init_error: + ndbcluster_end(); + DBUG_RETURN(TRUE); } @@ -4302,6 +4444,65 @@ ha_ndbcluster::records_in_range(uint inx, key_range *min_key, DBUG_RETURN(10); /* Good guess when you don't know anything */ } +ulong ha_ndbcluster::table_flags(void) const +{ + if (m_ha_not_exact_count) + return m_table_flags | HA_NOT_EXACT_COUNT; + else + return m_table_flags; +} +const char * ha_ndbcluster::table_type() const +{ + return("ndbcluster"); +} +uint ha_ndbcluster::max_supported_record_length() const +{ + return NDB_MAX_TUPLE_SIZE; +} +uint ha_ndbcluster::max_supported_keys() const +{ + return MAX_KEY; +} +uint ha_ndbcluster::max_supported_key_parts() const +{ + return NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY; +} +uint ha_ndbcluster::max_supported_key_length() const +{ + return NDB_MAX_KEY_SIZE; +} +bool ha_ndbcluster::low_byte_first() const +{ +#ifdef WORDS_BIGENDIAN + return FALSE; +#else + return TRUE; +#endif +} +bool ha_ndbcluster::has_transactions() +{ + return m_transaction_on; +} +const char* ha_ndbcluster::index_type(uint key_number) +{ + switch (get_index_type(key_number)) { + case ORDERED_INDEX: + case UNIQUE_ORDERED_INDEX: + case PRIMARY_KEY_ORDERED_INDEX: + return "BTREE"; + case UNIQUE_INDEX: + case PRIMARY_KEY_INDEX: + default: + return "HASH"; + } +} +uint8 ha_ndbcluster::table_cache_type() +{ + if (m_use_local_query_cache) + return HA_CACHE_TBL_TRANSACT; + else + return HA_CACHE_TBL_NOCACHE; +} /* Handling the shared NDB_SHARE structure that is needed to @@ -4468,13 +4669,12 @@ ndb_get_table_statistics(Ndb* ndb, const char * table, { DBUG_ENTER("ndb_get_table_statistics"); DBUG_PRINT("enter", ("table: %s", table)); - + NdbConnection* pTrans= ndb->startTransaction(); do { - NdbConnection* pTrans= ndb->startTransaction(); if (pTrans == NULL) break; - + NdbScanOperation* pOp= pTrans->getNdbScanOperation(table); if (pOp == NULL) break; @@ -4491,13 +4691,13 @@ ndb_get_table_statistics(Ndb* ndb, const char * table, pOp->getValue(NdbDictionary::Column::ROW_COUNT, (char*)&rows); pOp->getValue(NdbDictionary::Column::COMMIT_COUNT, (char*)&commits); - check= pTrans->execute(NoCommit); + check= pTrans->execute(NoCommit, AbortOnError, TRUE); if (check == -1) break; Uint64 sum_rows= 0; Uint64 sum_commits= 0; - while((check= rs->nextResult(TRUE)) == 0) + while((check= rs->nextResult(TRUE, TRUE)) == 0) { sum_rows+= rows; sum_commits+= commits; @@ -4506,6 +4706,8 @@ ndb_get_table_statistics(Ndb* ndb, const char * table, if (check == -1) break; + rs->close(TRUE); + ndb->closeTransaction(pTrans); if(row_count) * row_count= sum_rows; @@ -4515,6 +4717,7 @@ ndb_get_table_statistics(Ndb* ndb, const char * table, DBUG_RETURN(0); } while(0); + ndb->closeTransaction(pTrans); DBUG_PRINT("exit", ("failed")); DBUG_RETURN(-1); } diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 2121228a869..f6c712620c1 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -118,15 +118,14 @@ class ha_ndbcluster: public handler int reset(); int external_lock(THD *thd, int lock_type); int start_stmt(THD *thd); - const char * table_type() const { return("ndbcluster");} + const char * table_type() const; const char ** bas_ext() const; - ulong table_flags(void) const { return m_table_flags; } + ulong table_flags(void) const; ulong index_flags(uint idx, uint part, bool all_parts) const; - uint max_supported_record_length() const { return NDB_MAX_TUPLE_SIZE; }; - uint max_supported_keys() const { return MAX_KEY; } - uint max_supported_key_parts() const - { return NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY; }; - uint max_supported_key_length() const { return NDB_MAX_KEY_SIZE;}; + uint max_supported_record_length() const; + uint max_supported_keys() const; + uint max_supported_key_parts() const; + uint max_supported_key_length() const; int rename_table(const char *from, const char *to); int delete_table(const char *name); @@ -135,28 +134,9 @@ class ha_ndbcluster: public handler THR_LOCK_DATA **to, enum thr_lock_type lock_type); - bool low_byte_first() const - { -#ifdef WORDS_BIGENDIAN - return FALSE; -#else - return TRUE; -#endif - } - bool has_transactions() { return TRUE; } - - const char* index_type(uint key_number) { - switch (get_index_type(key_number)) { - case ORDERED_INDEX: - case UNIQUE_ORDERED_INDEX: - case PRIMARY_KEY_ORDERED_INDEX: - return "BTREE"; - case UNIQUE_INDEX: - case PRIMARY_KEY_INDEX: - default: - return "HASH"; - } - } + bool low_byte_first() const; + bool has_transactions(); + const char* index_type(uint key_number); double scan_time(); ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key); @@ -165,7 +145,7 @@ class ha_ndbcluster: public handler static Thd_ndb* seize_thd_ndb(); static void release_thd_ndb(Thd_ndb* thd_ndb); - uint8 table_cache_type() { return HA_CACHE_TBL_NOCACHE; } + uint8 table_cache_type(); private: int alter_table_name(const char *from, const char *to); @@ -180,9 +160,11 @@ class ha_ndbcluster: public handler void release_metadata(); NDB_INDEX_TYPE get_index_type(uint idx_no) const; NDB_INDEX_TYPE get_index_type_from_table(uint index_no) const; - + int check_index_fields_not_null(uint index_no); + int pk_read(const byte *key, uint key_len, byte *buf); int complemented_pk_read(const byte *old_data, byte *new_data); + int peek_row(); int unique_index_read(const byte *key, uint key_len, byte *buf); int ordered_index_scan(const key_range *start_key, @@ -242,9 +224,10 @@ class ha_ndbcluster: public handler typedef union { NdbRecAttr *rec; NdbBlob *blob; void *ptr; } NdbValue; NdbValue m_value[NDB_MAX_ATTRIBUTES_IN_TABLE]; bool m_use_write; - bool m_ignore_dup_key_not_supported; + bool m_ignore_dup_key; bool m_primary_key_update; bool m_retrieve_all_fields; + bool m_retrieve_primary_key; ha_rows m_rows_to_insert; ha_rows m_rows_inserted; ha_rows m_bulk_insert_rows; @@ -256,6 +239,12 @@ class ha_ndbcluster: public handler char *m_blobs_buffer; uint32 m_blobs_buffer_size; uint m_dupkey; + // set from thread variables at external lock + bool m_ha_not_exact_count; + bool m_force_send; + ha_rows m_autoincrement_prefetch; + bool m_transaction_on; + bool m_use_local_query_cache; void set_rec_per_key(); void records_update(); @@ -265,6 +254,8 @@ class ha_ndbcluster: public handler void no_uncommitted_rows_reset(THD *); friend int execute_no_commit(ha_ndbcluster*, NdbConnection*); + friend int execute_commit(ha_ndbcluster*, NdbConnection*); + friend int execute_no_commit_ie(ha_ndbcluster*, NdbConnection*); }; bool ndbcluster_init(void); diff --git a/sql/handler.cc b/sql/handler.cc index 5dae7950390..7ddd7b80a34 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -953,8 +953,10 @@ int handler::read_first_row(byte * buf, uint primary_key) /* If there is very few deleted rows in the table, find the first row by scanning the table. + TODO remove the test for HA_READ_ORDER */ - if (deleted < 10 || primary_key >= MAX_KEY) + if (deleted < 10 || primary_key >= MAX_KEY || + !(index_flags(primary_key, 0, 0) & HA_READ_ORDER)) { (void) ha_rnd_init(1); while ((error= rnd_next(buf)) == HA_ERR_RECORD_DELETED) ; diff --git a/sql/item.cc b/sql/item.cc index 0e7a2b50b51..31c35e87cd4 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -837,6 +837,21 @@ void Item_param::set_double(double d) } +/* + Set parameter value from TIME value. + + SYNOPSIS + set_time() + tm - datetime value to set (time_type is ignored) + type - type of datetime value + max_length_arg - max length of datetime value as string + + NOTE + If we value to be stored is not normalized, zero value will be stored + instead and proper warning will be produced. This function relies on + the fact that even wrong value sent over binary protocol fits into + MAX_DATE_STRING_REP_LENGTH buffer. +*/ void Item_param::set_time(TIME *tm, timestamp_type type, uint32 max_length_arg) { DBUG_ENTER("Item_param::set_time"); @@ -844,6 +859,17 @@ void Item_param::set_time(TIME *tm, timestamp_type type, uint32 max_length_arg) value.time= *tm; value.time.time_type= type; + if (value.time.year > 9999 || value.time.month > 12 || + value.time.day > 31 || + type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23 || + value.time.minute > 59 || value.time.second > 59) + { + char buff[MAX_DATE_STRING_REP_LENGTH]; + uint length= my_TIME_to_str(&value.time, buff); + make_truncated_value_warning(current_thd, buff, length, type); + set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR); + } + state= TIME_VALUE; maybe_null= 0; max_length= max_length_arg; diff --git a/sql/item.h b/sql/item.h index 547577a7ee0..ccb0fda1c49 100644 --- a/sql/item.h +++ b/sql/item.h @@ -266,6 +266,14 @@ public: virtual bool get_time(TIME *ltime); virtual bool get_date_result(TIME *ltime,uint fuzzydate) { return get_date(ltime,fuzzydate); } + /* + This function is used only in Item_func_isnull/Item_func_isnotnull + (implementations of IS NULL/IS NOT NULL clauses). Item_func_is{not}null + calls this method instead of one of val/result*() methods, which + normally will set null_value. This allows to determine nullness of + a complex expression without fully evaluating it. + Any new item which can be NULL must implement this call. + */ virtual bool is_null() { return 0; } /* it is "top level" item of WHERE clause and we do not need correct NULL @@ -573,6 +581,8 @@ public: void print(String *str) { str->append('?'); } /* parameter never equal to other parameter of other item */ bool eq(const Item *item, bool binary_cmp) const { return 0; } + bool is_null() + { DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; } }; class Item_int :public Item_num diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index c36f2d191c7..ac43b36600d 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -735,7 +735,7 @@ void Item_func_interval::fix_length_and_dec() maybe_null= 0; max_length= 2; used_tables_cache|= row->used_tables(); - not_null_tables_cache&= row->not_null_tables(); + not_null_tables_cache= row->not_null_tables(); with_sum_func= with_sum_func || row->with_sum_func; const_item_cache&= row->const_item(); } @@ -2364,11 +2364,12 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) return 0; } int error; - if ((error=regcomp(&preg,res->c_ptr(), - (cmp_collation.collation->state & MY_CS_BINSORT) ? - REG_EXTENDED | REG_NOSUB : - REG_EXTENDED | REG_NOSUB | REG_ICASE, - cmp_collation.collation))) + if ((error= regcomp(&preg,res->c_ptr(), + ((cmp_collation.collation->state & MY_CS_BINSORT) || + (cmp_collation.collation->state & MY_CS_CSSORT)) ? + REG_EXTENDED | REG_NOSUB : + REG_EXTENDED | REG_NOSUB | REG_ICASE, + cmp_collation.collation))) { (void) regerror(error,&preg,buff,sizeof(buff)); my_printf_error(ER_REGEXP_ERROR,ER(ER_REGEXP_ERROR),MYF(0),buff); @@ -2416,10 +2417,11 @@ longlong Item_func_regex::val_int() regex_compiled=0; } if (regcomp(&preg,res2->c_ptr(), - (cmp_collation.collation->state & MY_CS_BINSORT) ? - REG_EXTENDED | REG_NOSUB : - REG_EXTENDED | REG_NOSUB | REG_ICASE, - cmp_collation.collation)) + ((cmp_collation.collation->state & MY_CS_BINSORT) || + (cmp_collation.collation->state & MY_CS_CSSORT)) ? + REG_EXTENDED | REG_NOSUB : + REG_EXTENDED | REG_NOSUB | REG_ICASE, + cmp_collation.collation)) { null_value=1; return 0; diff --git a/sql/item_func.cc b/sql/item_func.cc index c07e9f23ea2..32841ba447b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -350,6 +350,7 @@ void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array, { uint el= fields.elements; Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name); + new_item->collation.set(item->collation); fields.push_front(item); ref_pointer_array[el]= item; thd->change_item_tree(arg, new_item); @@ -1601,18 +1602,21 @@ longlong Item_func_bit_count::val_int() udf_handler::~udf_handler() { - if (initialized) + if (!not_original) { - if (u_d->func_deinit != NULL) + if (initialized) { - void (*deinit)(UDF_INIT *) = (void (*)(UDF_INIT*)) - u_d->func_deinit; - (*deinit)(&initid); + if (u_d->func_deinit != NULL) + { + void (*deinit)(UDF_INIT *) = (void (*)(UDF_INIT*)) + u_d->func_deinit; + (*deinit)(&initid); + } + free_udf(u_d); } - free_udf(u_d); + if (buffers) // Because of bug in ecc + delete [] buffers; } - if (buffers) // Because of bug in ecc - delete [] buffers; } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 3b3a6083725..c43a7d87f8f 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -218,16 +218,13 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) hybrid_type= item->result_type(); if (hybrid_type == INT_RESULT) { - cmp_charset= &my_charset_bin; max_length=20; } else if (hybrid_type == REAL_RESULT) { - cmp_charset= &my_charset_bin; max_length=float_length(decimals); }else { - cmp_charset= item->collation.collation; max_length=item->max_length; } decimals=item->decimals; @@ -557,7 +554,7 @@ bool Item_sum_min::add() { String *result=args[0]->val_str(&tmp_value); if (!args[0]->null_value && - (null_value || sortcmp(&value,result,cmp_charset) > 0)) + (null_value || sortcmp(&value,result,collation.collation) > 0)) { value.copy(*result); null_value=0; @@ -610,7 +607,7 @@ bool Item_sum_max::add() { String *result=args[0]->val_str(&tmp_value); if (!args[0]->null_value && - (null_value || sortcmp(&value,result,cmp_charset) < 0)) + (null_value || sortcmp(&value,result,collation.collation) < 0)) { value.copy(*result); null_value=0; @@ -921,7 +918,7 @@ Item_sum_hybrid::min_max_update_str_field() result_field->val_str(&tmp_value); if (result_field->is_null() || - (cmp_sign * sortcmp(res_str,&tmp_value,cmp_charset)) < 0) + (cmp_sign * sortcmp(res_str,&tmp_value,collation.collation)) < 0) result_field->store(res_str->ptr(),res_str->length(),res_str->charset()); result_field->set_notnull(); } diff --git a/sql/item_sum.h b/sql/item_sum.h index 5aa0d37190b..521c595712b 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -402,20 +402,19 @@ class Item_sum_hybrid :public Item_sum enum_field_types hybrid_field_type; int cmp_sign; table_map used_table_cache; - CHARSET_INFO *cmp_charset; public: Item_sum_hybrid(Item *item_par,int sign) :Item_sum(item_par), sum(0.0), sum_int(0), hybrid_type(INT_RESULT), hybrid_field_type(FIELD_TYPE_LONGLONG), - cmp_sign(sign), used_table_cache(~(table_map) 0), - cmp_charset(&my_charset_bin) - {} + cmp_sign(sign), used_table_cache(~(table_map) 0) + { collation.set(&my_charset_bin); } Item_sum_hybrid(THD *thd, Item_sum_hybrid *item): Item_sum(thd, item), value(item->value), sum(item->sum), sum_int(item->sum_int), hybrid_type(item->hybrid_type), hybrid_field_type(item->hybrid_field_type),cmp_sign(item->cmp_sign), - used_table_cache(item->used_table_cache), cmp_charset(item->cmp_charset) {} + used_table_cache(item->used_table_cache) + { collation.set(item->collation); } bool fix_fields(THD *, TABLE_LIST *, Item **); table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } @@ -532,7 +531,7 @@ public: :Item_sum( list ), udf(udf_arg) { quick_group=0;} Item_udf_sum(THD *thd, Item_udf_sum *item) - :Item_sum(thd, item), udf(item->udf) {} + :Item_sum(thd, item), udf(item->udf) { udf.not_original= TRUE; } const char *func_name() const { return udf.name(); } bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index d8142352e70..354c8b5c50c 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1601,50 +1601,46 @@ void Item_func_from_unixtime::fix_length_and_dec() String *Item_func_from_unixtime::val_str(String *str) { TIME time_tmp; - my_time_t tmp; - + DBUG_ASSERT(fixed == 1); - tmp= (time_t) args[0]->val_int(); - if ((null_value=args[0]->null_value)) - goto null_date; - - thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, tmp); - + + if (get_date(&time_tmp, 0)) + return 0; + if (str->alloc(20*MY_CHARSET_BIN_MB_MAXLEN)) - goto null_date; + { + null_value= 1; + return 0; + } + make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str); return str; - -null_date: - null_value=1; - return 0; } longlong Item_func_from_unixtime::val_int() { TIME time_tmp; - my_time_t tmp; - + DBUG_ASSERT(fixed == 1); - tmp= (time_t) (ulong) args[0]->val_int(); - if ((null_value=args[0]->null_value)) + if (get_date(&time_tmp, 0)) return 0; - - current_thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, tmp); - + return (longlong) TIME_to_ulonglong_datetime(&time_tmp); } bool Item_func_from_unixtime::get_date(TIME *ltime, uint fuzzy_date __attribute__((unused))) { - my_time_t tmp=(my_time_t) args[0]->val_int(); - if ((null_value=args[0]->null_value)) + longlong tmp= args[0]->val_int(); + + if ((null_value= (args[0]->null_value || + tmp < TIMESTAMP_MIN_VALUE || + tmp > TIMESTAMP_MAX_VALUE))) return 1; - - current_thd->variables.time_zone->gmt_sec_to_TIME(ltime, tmp); + + thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)tmp); return 0; } diff --git a/sql/lock.cc b/sql/lock.cc index 646babea6a1..7cfa2aebe7b 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -705,15 +705,70 @@ static void print_lock_error(int error) /**************************************************************************** Handling of global read locks - The global locks are handled through the global variables: - global_read_lock - global_read_lock_blocks_commit - waiting_for_read_lock - protect_against_global_read_lock - Taking the global read lock is TWO steps (2nd step is optional; without it, COMMIT of existing transactions will be allowed): lock_global_read_lock() THEN make_global_read_lock_block_commit(). + + The global locks are handled through the global variables: + global_read_lock + count of threads which have the global read lock (i.e. have completed at + least the first step above) + global_read_lock_blocks_commit + count of threads which have the global read lock and block + commits (i.e. have completed the second step above) + waiting_for_read_lock + count of threads which want to take a global read lock but cannot + protect_against_global_read_lock + count of threads which have set protection against global read lock. + + How blocking of threads by global read lock is achieved: that's + advisory. Any piece of code which should be blocked by global read lock must + be designed like this: + - call to wait_if_global_read_lock(). When this returns 0, no global read + lock is owned; if argument abort_on_refresh was 0, none can be obtained. + - job + - if abort_on_refresh was 0, call to start_waiting_global_read_lock() to + allow other threads to get the global read lock. I.e. removal of the + protection. + (Note: it's a bit like an implementation of rwlock). + + [ I am sorry to mention some SQL syntaxes below I know I shouldn't but found + no better descriptive way ] + + Why does FLUSH TABLES WITH READ LOCK need to block COMMIT: because it's used + to read a non-moving SHOW MASTER STATUS, and a COMMIT writes to the binary + log. + + Why getting the global read lock is two steps and not one. Because FLUSH + TABLES WITH READ LOCK needs to insert one other step between the two: + flushing tables. So the order is + 1) lock_global_read_lock() (prevents any new table write locks, i.e. stalls + all new updates) + 2) close_cached_tables() (the FLUSH TABLES), which will wait for tables + currently opened and being updated to close (so it's possible that there is + a moment where all new updates of server are stalled *and* FLUSH TABLES WITH + READ LOCK is, too). + 3) make_global_read_lock_block_commit(). + If we have merged 1) and 3) into 1), we would have had this deadlock: + imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB + table t. + thd1: SELECT * FROM t FOR UPDATE; + thd2: UPDATE t SET a=1; # blocked by row-level locks of thd1 + thd3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the + table instance of thd2 + thd1: COMMIT; # blocked by thd3. + thd1 blocks thd2 which blocks thd3 which blocks thd1: deadlock. + + Note that we need to support that one thread does + FLUSH TABLES WITH READ LOCK; and then COMMIT; + (that's what innobackup does, for some good reason). + So in this exceptional case the COMMIT should not be blocked by the FLUSH + TABLES WITH READ LOCK. + + TODO in MySQL 5.x: make_global_read_lock_block_commit() should be + killable. Normally CPU does not spend a long time in this function (COMMITs + are quite fast), but it would still be nice. + ****************************************************************************/ volatile uint global_read_lock=0; @@ -828,6 +883,8 @@ void start_waiting_global_read_lock(THD *thd) { bool tmp; DBUG_ENTER("start_waiting_global_read_lock"); + if (unlikely(thd->global_read_lock)) + DBUG_VOID_RETURN; (void) pthread_mutex_lock(&LOCK_open); tmp= (!--protect_against_global_read_lock && waiting_for_read_lock); (void) pthread_mutex_unlock(&LOCK_open); diff --git a/sql/log_event.cc b/sql/log_event.cc index 301c8ec222c..2fdc89504d7 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2842,7 +2842,7 @@ void Create_file_log_event::print(FILE* file, bool short_form, if (enable_local) { - Load_log_event::print(file, 1, last_db, !check_fname_outside_temp_buf()); + Load_log_event::print(file, short_form, last_db, !check_fname_outside_temp_buf()); /* That one is for "file_id: etc" below: in mysqlbinlog we want the #, in SHOW BINLOG EVENTS we don't. diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1da5359bae0..baab3017623 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -36,6 +36,28 @@ #ifdef HAVE_NDBCLUSTER_DB #include "ha_ndbcluster.h" #endif + +#ifdef HAVE_INNOBASE_DB +#define OPT_INNODB_DEFAULT 1 +#else +#define OPT_INNODB_DEFAULT 0 +#endif +#ifdef HAVE_BERKLEY_DB +#define OPT_BDB_DEFAULT 1 +#else +#define OPT_BDB_DEFAULT 0 +#endif +#ifdef HAVE_ISAM_DB +#define OPT_ISAM_DEFAULT 1 +#else +#define OPT_ISAM_DEFAULT 0 +#endif +#ifdef HAVE_NDBCLUSTER_DB +#define OPT_NDBCLUSTER_DEFAULT 0 +#else +#define OPT_NDBCLUSTER_DEFAULT 0 +#endif + #include #include #include @@ -146,6 +168,7 @@ static VolumeID_t datavolid; static event_handle_t eh; static Report_t ref; static void *refneb= NULL; +my_bool event_flag= FALSE; static int volumeid= -1; /* NEB event callback */ @@ -468,6 +491,7 @@ Query_cache query_cache; #ifdef HAVE_SMEM char *shared_memory_base_name= default_shared_memory_base_name; bool opt_enable_shared_memory; +HANDLE smem_event_connect_request= 0; #endif #include "sslopt-vars.h" @@ -743,6 +767,15 @@ void kill_mysql(void) CloseHandle(hEvent); */ } +#ifdef HAVE_SMEM + /* + Send event to smem_event_connect_request for aborting + */ + if (!SetEvent(smem_event_connect_request)) + { + DBUG_PRINT("error",("Got error: %ld from SetEvent of smem_event_connect_request",GetLastError())); + } +#endif #endif #elif defined(OS2) pthread_cond_signal( &eventShutdown); // post semaphore @@ -805,7 +838,8 @@ static void __cdecl kill_server(int sig_ptr) else unireg_end(); #ifdef __NETWARE__ - pthread_join(select_thread, NULL); // wait for main thread + if (!event_flag) + pthread_join(select_thread, NULL); // wait for main thread #endif /* __NETWARE__ */ pthread_exit(0); /* purecov: deadcode */ @@ -1515,20 +1549,20 @@ static void check_data_home(const char *path) // down server event callback void mysql_down_server_cb(void *, void *) { + event_flag = TRUE; kill_server(0); } // destroy callback resources void mysql_cb_destroy(void *) -{ - UnRegisterEventNotification(eh); // cleanup down event notification +{ + UnRegisterEventNotification(eh); // cleanup down event notification NX_UNWRAP_INTERFACE(ref); - - /* Deregister NSS volume deactivation event */ - NX_UNWRAP_INTERFACE(refneb); + /* Deregister NSS volume deactivation event */ + NX_UNWRAP_INTERFACE(refneb); if (neb_consumer_id) - UnRegisterConsumer(neb_consumer_id, NULL); + UnRegisterConsumer(neb_consumer_id, NULL); } @@ -1548,7 +1582,7 @@ void mysql_cb_init() Register for volume deactivation event Wrap the callback function, as it is called by non-LibC thread */ - (void)NX_WRAP_INTERFACE(neb_event_callback, 1, &refneb); + (void *) NX_WRAP_INTERFACE(neb_event_callback, 1, &refneb); registerwithneb(); NXVmRegisterExitHandler(mysql_cb_destroy, NULL); // clean-up @@ -1645,7 +1679,9 @@ ulong neb_event_callback(struct EventBlock *eblock) { consoleprintf("MySQL data volume is deactivated, shutting down MySQL Server \n"); nw_panic = TRUE; + event_flag= TRUE; kill_server(0); + } } return 0; @@ -1719,8 +1755,8 @@ static void init_signals(void) for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++) signal(signals[i], kill_server); mysql_cb_init(); // initialize callbacks -} +} static void start_signal_handler(void) { @@ -2227,7 +2263,13 @@ extern "C" pthread_handler_decl(handle_shutdown,arg) #endif -const char *load_default_groups[]= { "mysqld","server",MYSQL_BASE_VERSION,0,0}; +const char *load_default_groups[]= { +#ifdef HAVE_NDBCLUSTER_DB +"mysql_cluster", +#endif +"mysqld","server",MYSQL_BASE_VERSION,0,0}; +static const int load_default_groups_sz= +sizeof(load_default_groups)/sizeof(load_default_groups[0]); bool open_log(MYSQL_LOG *log, const char *hostname, const char *opt_name, const char *extension, @@ -2803,6 +2845,7 @@ int win_main(int argc, char **argv) int main(int argc, char **argv) #endif { + DEBUGGER_OFF; MY_INIT(argv[0]); // init my_sys library & pthreads @@ -2998,7 +3041,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); #endif /* __NT__ */ /* (void) pthread_attr_destroy(&connection_attrib); */ - + DBUG_PRINT("quit",("Exiting main thread")); #ifndef __WIN__ @@ -3048,6 +3091,7 @@ we force server id to 2, but this MySQL server will not act as a slave."); #endif clean_up_mutexes(); my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0); + exit(0); return(0); /* purecov: deadcode */ } @@ -3174,7 +3218,7 @@ int main(int argc, char **argv) and we are now stuck with it. */ if (my_strcasecmp(system_charset_info, argv[1],"mysql")) - load_default_groups[3]= argv[1]; + load_default_groups[load_default_groups_sz-2]= argv[1]; start_mode= 1; Service.Init(argv[1], mysql_service); return 0; @@ -3195,7 +3239,7 @@ int main(int argc, char **argv) opt_argv=argv; start_mode= 1; if (my_strcasecmp(system_charset_info, argv[2],"mysql")) - load_default_groups[3]= argv[2]; + load_default_groups[load_default_groups_sz-2]= argv[2]; Service.Init(argv[2], mysql_service); return 0; } @@ -3705,7 +3749,6 @@ pthread_handler_decl(handle_connections_shared_memory,arg) /* file-mapping object, use for create shared memory */ HANDLE handle_connect_file_map= 0; char *handle_connect_map= 0; // pointer on shared memory - HANDLE event_connect_request= 0; // for start connection actions HANDLE event_connect_answer= 0; ulong smem_buffer_length= shared_memory_buffer_length + 4; ulong connect_number= 1; @@ -3726,7 +3769,7 @@ pthread_handler_decl(handle_connections_shared_memory,arg) */ suffix_pos= strxmov(tmp,shared_memory_base_name,"_",NullS); strmov(suffix_pos, "CONNECT_REQUEST"); - if ((event_connect_request= CreateEvent(0,FALSE,FALSE,tmp)) == 0) + if ((smem_event_connect_request= CreateEvent(0,FALSE,FALSE,tmp)) == 0) { errmsg= "Could not create request event"; goto error; @@ -3757,7 +3800,13 @@ pthread_handler_decl(handle_connections_shared_memory,arg) while (!abort_loop) { /* Wait a request from client */ - WaitForSingleObject(event_connect_request,INFINITE); + WaitForSingleObject(smem_event_connect_request,INFINITE); + + /* + it can be after shutdown command + */ + if (abort_loop) + goto error; HANDLE handle_client_file_map= 0; char *handle_client_map= 0; @@ -3882,7 +3931,7 @@ error: if (handle_connect_map) UnmapViewOfFile(handle_connect_map); if (handle_connect_file_map) CloseHandle(handle_connect_file_map); if (event_connect_answer) CloseHandle(event_connect_answer); - if (event_connect_request) CloseHandle(event_connect_request); + if (smem_event_connect_request) CloseHandle(smem_event_connect_request); decrement_handler_count(); DBUG_RETURN(0); @@ -3947,7 +3996,10 @@ enum options_mysqld OPT_INNODB_FILE_PER_TABLE, OPT_CRASH_BINLOG_INNODB, OPT_INNODB_LOCKS_UNSAFE_FOR_BINLOG, OPT_SAFE_SHOW_DB, OPT_INNODB_SAFE_BINLOG, - OPT_INNODB, OPT_ISAM, OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, OPT_SKIP_SAFEMALLOC, + OPT_INNODB, OPT_ISAM, + OPT_NDBCLUSTER, OPT_NDB_CONNECTSTRING, OPT_NDB_USE_EXACT_COUNT, + OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ, + OPT_SKIP_SAFEMALLOC, OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS, OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL, @@ -4059,7 +4111,7 @@ struct my_option my_long_options[] = 0, 0, 0, 0, 0, 0}, {"bdb", OPT_BDB, "Enable Berkeley DB (if this version of MySQL supports it). \ Disable with --skip-bdb (will save memory).", - (gptr*) &opt_bdb, (gptr*) &opt_bdb, 0, GET_BOOL, NO_ARG, 1, 0, 0, + (gptr*) &opt_bdb, (gptr*) &opt_bdb, 0, GET_BOOL, NO_ARG, OPT_BDB_DEFAULT, 0, 0, 0, 0, 0}, #ifdef HAVE_BERKELEY_DB {"bdb-home", OPT_BDB_HOME, "Berkeley home directory.", (gptr*) &berkeley_home, @@ -4196,7 +4248,7 @@ Disable with --skip-bdb (will save memory).", REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"innodb", OPT_INNODB, "Enable InnoDB (if this version of MySQL supports it). \ Disable with --skip-innodb (will save memory).", - (gptr*) &opt_innodb, (gptr*) &opt_innodb, 0, GET_BOOL, NO_ARG, 1, 0, 0, + (gptr*) &opt_innodb, (gptr*) &opt_innodb, 0, GET_BOOL, NO_ARG, OPT_INNODB_DEFAULT, 0, 0, 0, 0, 0}, {"innodb_data_file_path", OPT_INNODB_DATA_FILE_PATH, "Path to individual files and their sizes.", @@ -4256,7 +4308,7 @@ Disable with --skip-innodb (will save memory).", #endif /* End HAVE_INNOBASE_DB */ {"isam", OPT_ISAM, "Enable ISAM (if this version of MySQL supports it). \ Disable with --skip-isam.", - (gptr*) &opt_isam, (gptr*) &opt_isam, 0, GET_BOOL, NO_ARG, 1, 0, 0, + (gptr*) &opt_isam, (gptr*) &opt_isam, 0, GET_BOOL, NO_ARG, OPT_ISAM_DEFAULT, 0, 0, 0, 0, 0}, {"language", 'L', "Client error messages in given language. May be given as a full path.", @@ -4383,12 +4435,29 @@ master-ssl", GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"ndbcluster", OPT_NDBCLUSTER, "Enable NDB Cluster (if this version of MySQL supports it). \ Disable with --skip-ndbcluster (will save memory).", - (gptr*) &opt_ndbcluster, (gptr*) &opt_ndbcluster, 0, GET_BOOL, NO_ARG, 1, 0, 0, - 0, 0, 0}, + (gptr*) &opt_ndbcluster, (gptr*) &opt_ndbcluster, 0, GET_BOOL, NO_ARG, + OPT_NDBCLUSTER_DEFAULT, 0, 0, 0, 0, 0}, #ifdef HAVE_NDBCLUSTER_DB - {"ndb-connectstring", OPT_NDB_CONNECTSTRING, "Connect string for ndbcluster.", - (gptr*) &ndbcluster_connectstring, (gptr*) &ndbcluster_connectstring, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"ndb-connectstring", OPT_NDB_CONNECTSTRING, + "Connect string for ndbcluster.", + (gptr*) &ndbcluster_connectstring, (gptr*) &ndbcluster_connectstring, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"ndb_autoincrement_prefetch_sz", OPT_NDB_AUTOINCREMENT_PREFETCH_SZ, + "Specify number of autoincrement values that are prefetched", + (gptr*) &global_system_variables.ndb_autoincrement_prefetch_sz, + (gptr*) &global_system_variables.ndb_autoincrement_prefetch_sz, + 0, GET_INT, REQUIRED_ARG, 32, 1, 256, 0, 0, 0}, + {"ndb_force_send", OPT_NDB_FORCE_SEND, + "Force send of buffers to ndb immediately without waiting for other threads", + (gptr*) &global_system_variables.ndb_force_send, + (gptr*) &global_system_variables.ndb_force_send, + 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, + {"ndb_use_exact_count", OPT_NDB_USE_EXACT_COUNT, + "Use exact records count during query planning and for " + "fast select count(*)", + (gptr*) &global_system_variables.ndb_use_exact_count, + (gptr*) &global_system_variables.ndb_use_exact_count, + 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, #endif {"new", 'n', "Use very new possible 'unsafe' functions.", (gptr*) &global_system_variables.new_mode, @@ -6201,6 +6270,24 @@ static void get_options(int argc,char **argv) if ((ho_error= handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); + +#ifndef HAVE_NDBCLUSTER_DB + if (opt_ndbcluster) + sql_print_warning("this binary does not contain NDBCLUSTER storage engine"); +#endif +#ifndef HAVE_INNOBASE_DB + if (opt_innodb) + sql_print_warning("this binary does not contain INNODB storage engine"); +#endif +#ifndef HAVE_ISAM + if (opt_isam) + sql_print_warning("this binary does not contain ISAM storage engine"); +#endif +#ifndef HAVE_BERKELEY_DB + if (opt_bdb) + sql_print_warning("this binary does not contain BDB storage engine"); +#endif + if (argc > 0) { fprintf(stderr, "%s: Too many arguments (first extra is '%s').\nUse --help to get a list of available options\n", my_progname, *argv); diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 720e82f414e..356ec80608c 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -921,8 +921,8 @@ int load_master_data(THD* thd) */ int error; - if (init_master_info(active_mi, master_info_file, relay_log_info_file, - 0)) + if (init_master_info(active_mi, master_info_file, relay_log_info_file, + 0, (SLAVE_IO | SLAVE_SQL))) send_error(thd, ER_MASTER_INFO); strmake(active_mi->master_log_name, row[0], sizeof(active_mi->master_log_name)); diff --git a/sql/set_var.cc b/sql/set_var.cc index a97506ad07c..2031ac15412 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -359,6 +359,23 @@ sys_var_thd_bool sys_innodb_table_locks("innodb_table_locks", sys_var_long_ptr sys_innodb_autoextend_increment("innodb_autoextend_increment", &srv_auto_extend_increment); #endif +#ifdef HAVE_NDBCLUSTER_DB +// ndb thread specific variable settings +sys_var_thd_ulong +sys_ndb_autoincrement_prefetch_sz("ndb_autoincrement_prefetch_sz", + &SV::ndb_autoincrement_prefetch_sz); +sys_var_thd_bool +sys_ndb_force_send("ndb_force_send", + &SV::ndb_force_send); +sys_var_thd_bool +sys_ndb_use_exact_count("ndb_use_exact_count", + &SV::ndb_use_exact_count); +sys_var_thd_bool +sys_ndb_use_transactions("ndb_use_transactions", + &SV::ndb_use_transactions); +// ndb server global variable settings +// none +#endif /* Time/date/datetime formats */ @@ -612,7 +629,13 @@ sys_var *sys_variables[]= &sys_innodb_table_locks, &sys_innodb_max_purge_lag, &sys_innodb_autoextend_increment, -#endif +#endif +#ifdef HAVE_NDBCLUSTER_DB + &sys_ndb_autoincrement_prefetch_sz, + &sys_ndb_force_send, + &sys_ndb_use_exact_count, + &sys_ndb_use_transactions, +#endif &sys_unique_checks, &sys_warning_count }; @@ -772,6 +795,13 @@ struct show_var_st init_vars[]= { {sys_myisam_sort_buffer_size.name, (char*) &sys_myisam_sort_buffer_size, SHOW_SYS}, #ifdef __NT__ {"named_pipe", (char*) &opt_enable_named_pipe, SHOW_MY_BOOL}, +#endif +#ifdef HAVE_NDBCLUSTER_DB + {sys_ndb_autoincrement_prefetch_sz.name, + (char*) &sys_ndb_autoincrement_prefetch_sz, SHOW_SYS}, + {sys_ndb_force_send.name, (char*) &sys_ndb_force_send, SHOW_SYS}, + {sys_ndb_use_exact_count.name,(char*) &sys_ndb_use_exact_count, SHOW_SYS}, + {sys_ndb_use_transactions.name,(char*) &sys_ndb_use_transactions, SHOW_SYS}, #endif {sys_net_buffer_length.name,(char*) &sys_net_buffer_length, SHOW_SYS}, {sys_net_read_timeout.name, (char*) &sys_net_read_timeout, SHOW_SYS}, @@ -2703,13 +2733,18 @@ int sql_set_variables(THD *thd, List *var_list) while ((var=it++)) { if ((error=var->check(thd))) - DBUG_RETURN(error); + goto err; } - if (thd->net.report_error) - DBUG_RETURN(1); - it.rewind(); - while ((var=it++)) - error|= var->update(thd); // Returns 0, -1 or 1 + if (!thd->net.report_error) + { + it.rewind(); + while ((var= it++)) + error|= var->update(thd); // Returns 0, -1 or 1 + } + else + error= 1; +err: + free_underlaid_joins(thd, &thd->lex->select_lex); DBUG_RETURN(error); } diff --git a/sql/slave.cc b/sql/slave.cc index b6ad35573ff..b5caf2627a6 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -161,7 +161,7 @@ int init_slave() } if (init_master_info(active_mi,master_info_file,relay_log_info_file, - !master_host)) + !master_host, (SLAVE_IO | SLAVE_SQL))) { sql_print_error("Failed to initialize the master info structure"); goto err; @@ -1032,7 +1032,7 @@ bool net_request_file(NET* net, const char* fname) } -const char *rewrite_db(const char* db, uint *new_len) +const char *rewrite_db(const char* db, uint32 *new_len) { if (replicate_rewrite_db.is_empty() || !db) return db; @@ -1043,7 +1043,7 @@ const char *rewrite_db(const char* db, uint *new_len) { if (!strcmp(tmp->key, db)) { - *new_len= strlen(tmp->val); + *new_len= (uint32)strlen(tmp->val); return tmp->val; } } @@ -1799,7 +1799,8 @@ void clear_until_condition(RELAY_LOG_INFO* rli) int init_master_info(MASTER_INFO* mi, const char* master_info_fname, const char* slave_info_fname, - bool abort_if_no_master_info_file) + bool abort_if_no_master_info_file, + int thread_mask) { int fd,error; char fname[FN_REFLEN+128]; @@ -1813,8 +1814,16 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, last time. If this case pos_in_file would be set and we would get a crash when trying to read the signature for the binary relay log. + + We only rewind the read position if we are starting the SQL + thread. The handle_slave_sql thread assumes that the read + position is at the beginning of the file, and will read the + "signature" and then fast-forward to the last position read. */ - my_b_seek(mi->rli.cur_log, (my_off_t) 0); + if (thread_mask & SLAVE_SQL) + { + my_b_seek(mi->rli.cur_log, (my_off_t) 0); + } DBUG_RETURN(0); } diff --git a/sql/slave.h b/sql/slave.h index 97f197fb50a..a4d123329c6 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -510,7 +510,7 @@ int add_table_rule(HASH* h, const char* table_spec); int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec); void init_table_rule_hash(HASH* h, bool* h_inited); void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited); -const char *rewrite_db(const char* db, uint *new_db_len); +const char *rewrite_db(const char* db, uint32 *new_db_len); const char *print_slave_db_safe(const char *db); int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code); void skip_load_data_infile(NET* net); @@ -522,7 +522,8 @@ void clear_until_condition(RELAY_LOG_INFO* rli); void clear_slave_error_timestamp(RELAY_LOG_INFO* rli); int init_master_info(MASTER_INFO* mi, const char* master_info_fname, const char* slave_info_fname, - bool abort_if_no_master_info_file); + bool abort_if_no_master_info_file, + int thread_mask); void end_master_info(MASTER_INFO* mi); int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname); void end_relay_log_info(RELAY_LOG_INFO* rli); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 98af43e17a7..d6f52fed1d2 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1384,8 +1384,10 @@ static bool update_user_table(THD *thd, const char *host, const char *user, table->field[0]->store(host,(uint) strlen(host), &my_charset_latin1); table->field[1]->store(user,(uint) strlen(user), &my_charset_latin1); + table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (table->file->index_read_idx(table->record[0],0, - (byte*) table->field[0]->ptr,0, + (byte*) table->field[0]->ptr, + table->key_info[0].key_length, HA_READ_KEY_EXACT)) { my_error(ER_PASSWORD_NO_MATCH,MYF(0)); /* purecov: deadcode */ @@ -1463,9 +1465,11 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1); table->field[1]->store(combo.user.str,combo.user.length, &my_charset_latin1); + table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (table->file->index_read_idx(table->record[0], 0, - (byte*) table->field[0]->ptr,0, - HA_READ_KEY_EXACT)) + (byte*) table->field[0]->ptr, + table->key_info[0].key_length, + HA_READ_KEY_EXACT)) { if (!create_user) { @@ -1568,6 +1572,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, We should NEVER delete from the user table, as a uses can still use mysqld even if he doesn't have any privileges in the user table! */ + table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (cmp_record(table,record[1]) && (error=table->file->update_row(table->record[1],table->record[0]))) { // This should never happen @@ -1645,8 +1650,11 @@ static int replace_db_table(TABLE *table, const char *db, table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1); table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1); table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1); - if (table->file->index_read_idx(table->record[0],0,(byte*) table->field[0]->ptr,0, - HA_READ_KEY_EXACT)) + table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); + if (table->file->index_read_idx(table->record[0],0, + (byte*) table->field[0]->ptr, + table->key_info[0].key_length, + HA_READ_KEY_EXACT)) { if (what == 'N') { // no row, no revoke @@ -1679,6 +1687,7 @@ static int replace_db_table(TABLE *table, const char *db, /* update old existing row */ if (rights) { + table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if ((error=table->file->update_row(table->record[1],table->record[0]))) goto table_error; /* purecov: deadcode */ } @@ -1953,8 +1962,10 @@ static int replace_column_table(GRANT_TABLE *g_t, table->field[4]->store(xx->column.ptr(),xx->column.length(), &my_charset_latin1); + table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr, - 0, HA_READ_KEY_EXACT)) + table->key_info[0].key_length, + HA_READ_KEY_EXACT)) { if (revoke_grant) { @@ -2022,8 +2033,10 @@ static int replace_column_table(GRANT_TABLE *g_t, if (revoke_grant) { + table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (table->file->index_read(table->record[0], (byte*) table->field[0]->ptr, - key_length, HA_READ_KEY_EXACT)) + table->key_info[0].key_length, + HA_READ_KEY_EXACT)) goto end; /* Scan through all rows with the same host,db,user and table */ @@ -2112,9 +2125,10 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1); table->field[3]->store(table_name,(uint) strlen(table_name), &my_charset_latin1); store_record(table,record[1]); // store at pos 1 - + table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (table->file->index_read_idx(table->record[0],0, - (byte*) table->field[0]->ptr,0, + (byte*) table->field[0]->ptr, + table->key_info[0].key_length, HA_READ_KEY_EXACT)) { /* @@ -3571,9 +3585,12 @@ int mysql_drop_user(THD *thd, List &list) tables[0].table->field[1]->store(user_name->user.str,(uint) user_name->user.length, system_charset_info); + tables[0].table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (!tables[0].table->file->index_read_idx(tables[0].table->record[0],0, (byte*) tables[0].table-> - field[0]->ptr,0, + field[0]->ptr, + tables[0].table-> + key_info[0].key_length, HA_READ_KEY_EXACT)) { int error; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index eda60b5cfdb..bab81d785c3 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -280,6 +280,9 @@ void THD::init(void) variables.date_format); variables.datetime_format= date_time_format_copy((THD*) 0, variables.datetime_format); +#ifdef HAVE_NDBCLUSTER_DB + variables.ndb_use_transactions= 1; +#endif pthread_mutex_unlock(&LOCK_global_system_variables); server_status= SERVER_STATUS_AUTOCOMMIT; options= thd_startup_options; diff --git a/sql/sql_class.h b/sql/sql_class.h index 6d77b75d70f..56824f2e27d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -399,6 +399,12 @@ struct system_variables #ifdef HAVE_INNOBASE_DB my_bool innodb_table_locks; #endif /* HAVE_INNOBASE_DB */ +#ifdef HAVE_NDBCLUSTER_DB + ulong ndb_autoincrement_prefetch_sz; + my_bool ndb_force_send; + my_bool ndb_use_exact_count; + my_bool ndb_use_transactions; +#endif /* HAVE_NDBCLUSTER_DB */ my_bool old_passwords; /* Only charset part of these variables is sensible */ diff --git a/sql/sql_do.cc b/sql/sql_do.cc index 25a8359f3d2..0d4529fb29e 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -29,6 +29,7 @@ int mysql_do(THD *thd, List &values) DBUG_RETURN(-1); while ((value = li++)) value->val_int(); + free_underlaid_joins(thd, &thd->lex->select_lex); thd->clear_error(); // DO always is OK send_ok(thd); DBUG_RETURN(0); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 822ce622b1b..d590d3b5093 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -453,8 +453,8 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, setup_tables(insert_table_list) || setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) || (duplic == DUP_UPDATE && - (setup_fields(thd, 0, insert_table_list, update_fields, 0, 0, 0) || - setup_fields(thd, 0, insert_table_list, update_values, 0, 0, 0)))) + (setup_fields(thd, 0, insert_table_list, update_fields, 1, 0, 0) || + setup_fields(thd, 0, insert_table_list, update_values, 1, 0, 0)))) DBUG_RETURN(-1); if (find_real_table_in_list(table_list->next, table_list->db, table_list->real_name)) @@ -462,6 +462,9 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); DBUG_RETURN(-1); } + if (duplic == DUP_UPDATE || duplic == DUP_REPLACE) + table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); + DBUG_RETURN(0); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ad68402aeab..b04e79e2988 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4123,7 +4123,7 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length) - SET uses tot_length. */ void calculate_interval_lengths(THD *thd, TYPELIB *interval, - uint *max_length, uint *tot_length) + uint32 *max_length, uint32 *tot_length) { const char **pos; uint *len; @@ -4135,7 +4135,7 @@ void calculate_interval_lengths(THD *thd, TYPELIB *interval, *len= (uint) strip_sp((char*) *pos); uint length= cs->cset->numchars(cs, *pos, *pos + *len); *tot_length+= length; - set_if_bigger(*max_length, length); + set_if_bigger(*max_length, (uint32)length); } } @@ -4454,7 +4454,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, if (new_field->pack_length > 4) new_field->pack_length=8; new_field->interval=interval; - uint dummy_max_length; + uint32 dummy_max_length; calculate_interval_lengths(thd, interval, &dummy_max_length, &new_field->length); new_field->length+= (interval->count - 1); @@ -4484,7 +4484,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, new_field->interval=interval; new_field->pack_length=interval->count < 256 ? 1 : 2; // Should be safe - uint dummy_tot_length; + uint32 dummy_tot_length; calculate_interval_lengths(thd, interval, &new_field->length, &dummy_tot_length); set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index d81ed2cd014..a790e6fe9d8 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -349,12 +349,6 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len) tm.neg= (bool) to[0]; day= (uint) sint4korr(to+1); - /* - Note, that though ranges of hour, minute and second are not checked - here we rely on them being < 256: otherwise - we'll get buffer overflow in make_{date,time} functions, - which are called when time value is converted to string. - */ tm.hour= (uint) to[5] + day * 24; tm.minute= (uint) to[6]; tm.second= (uint) to[7]; @@ -369,7 +363,7 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len) tm.day= tm.year= tm.month= 0; } else - set_zero_time(&tm); + set_zero_time(&tm, MYSQL_TIMESTAMP_TIME); param->set_time(&tm, MYSQL_TIMESTAMP_TIME, MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN); *pos+= length; @@ -388,11 +382,6 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len) tm.year= (uint) sint2korr(to); tm.month= (uint) to[2]; tm.day= (uint) to[3]; - /* - Note, that though ranges of hour, minute and second are not checked - here we rely on them being < 256: otherwise - we'll get buffer overflow in make_{date,time} functions. - */ if (length > 4) { tm.hour= (uint) to[4]; @@ -405,7 +394,7 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len) tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0; } else - set_zero_time(&tm); + set_zero_time(&tm, MYSQL_TIMESTAMP_DATETIME); param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME, MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN); *pos+= length; @@ -419,11 +408,7 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len) if (length >= 4) { uchar *to= *pos; - /* - Note, that though ranges of hour, minute and second are not checked - here we rely on them being < 256: otherwise - we'll get buffer overflow in make_{date,time} functions. - */ + tm.year= (uint) sint2korr(to); tm.month= (uint) to[2]; tm.day= (uint) to[3]; @@ -433,7 +418,7 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len) tm.neg= 0; } else - set_zero_time(&tm); + set_zero_time(&tm, MYSQL_TIMESTAMP_DATE); param->set_time(&tm, MYSQL_TIMESTAMP_DATE, MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN); *pos+= length; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index a84b63c270b..bbcea537ff1 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -683,7 +683,8 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report) thread_mask&= thd->lex->slave_thd_opt; if (thread_mask) //some threads are stopped, start them { - if (init_master_info(mi,master_info_file,relay_log_info_file, 0)) + if (init_master_info(mi,master_info_file,relay_log_info_file, 0, + thread_mask)) slave_errno=ER_MASTER_INFO; else if (server_id_supplied && *mi->host) { @@ -978,7 +979,8 @@ int change_master(THD* thd, MASTER_INFO* mi) thd->proc_info = "Changing master"; LEX_MASTER_INFO* lex_mi= &thd->lex->mi; // TODO: see if needs re-write - if (init_master_info(mi, master_info_file, relay_log_info_file, 0)) + if (init_master_info(mi, master_info_file, relay_log_info_file, 0, + thread_mask)) { send_error(thd, ER_MASTER_INFO); unlock_slave_threads(mi); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ec7ea9091be..9e23163c35e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2154,7 +2154,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, COND *cond, bool is_const=1; for (uint i=0; iconst_item(); + is_const&= value[i]->const_item(); if (is_const) stat[0].const_keys.merge(possible_keys); /* diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3a242dc6547..eedd9388877 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -835,7 +835,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, #endif } - List_iterator cols(key->columns); + List_iterator cols(key->columns), cols2(key->columns); CHARSET_INFO *ft_key_charset=0; // for FULLTEXT for (uint column_nr=0 ; (column=cols++) ; column_nr++) { @@ -853,6 +853,19 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, column->field_name); DBUG_RETURN(-1); } + for (uint dup_nr= 0; dup_nr < column_nr; dup_nr++) + { + key_part_spec *dup_column= cols2++; + if (!my_strcasecmp(system_charset_info, + column->field_name, dup_column->field_name)) + { + my_printf_error(ER_DUP_FIELDNAME, + ER(ER_DUP_FIELDNAME),MYF(0), + column->field_name); + DBUG_RETURN(-1); + } + } + cols2.rewind(); /* for fulltext keys keyseg length is 1 for blobs (it's ignored in ft code anyway, and 0 (set to column width later) for char's. it has to be correct col width for char's, as char data are not diff --git a/sql/sql_udf.h b/sql/sql_udf.h index 7b10b80f148..d1f99a6d232 100644 --- a/sql/sql_udf.h +++ b/sql/sql_udf.h @@ -56,8 +56,9 @@ class udf_handler :public Sql_alloc public: table_map used_tables_cache; bool const_item_cache; + bool not_original; udf_handler(udf_func *udf_arg) :u_d(udf_arg), buffers(0), error(0), - is_null(0), initialized(0) + is_null(0), initialized(0), not_original(0) {} ~udf_handler(); const char *name() const { return u_d ? u_d->name.str : "?"; } diff --git a/sql/table.cc b/sql/table.cc index 20ac714020d..cb565097c0b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -463,7 +463,26 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, /* old frm file */ field_type= (enum_field_types) f_packtype(pack_flag); - charset=f_is_binary(pack_flag) ? &my_charset_bin : outparam->table_charset; + if (f_is_binary(pack_flag)) + { + /* + Try to choose the best 4.1 type: + - for 4.0 "CHAR(N) BINARY" or "VARCHAR(N) BINARY" + try to find a binary collation for character set. + - for other types (e.g. BLOB) just use my_charset_bin. + */ + if (!f_is_blob(pack_flag)) + { + // 3.23 or 4.0 string + if (!(charset= get_charset_by_csname(outparam->table_charset->csname, + MY_CS_BINSORT, MYF(0)))) + charset= &my_charset_bin; + } + else + charset= &my_charset_bin; + } + else + charset= outparam->table_charset; bzero((char*) &comment, sizeof(comment)); } *field_ptr=reg_field= diff --git a/strings/ctype-czech.c b/strings/ctype-czech.c index 6f9e9f74d35..2177a18504e 100644 --- a/strings/ctype-czech.c +++ b/strings/ctype-czech.c @@ -589,12 +589,12 @@ static MY_COLLATION_HANDLER my_collation_latin2_czech_ci_handler = CHARSET_INFO my_charset_latin2_czech_ci = { - 2,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM, /* state */ - "latin2", /* cs name */ - "latin2_czech_cs", /* name */ - "", /* comment */ - NULL, /* tailoring */ + 2,0,0, /* number */ + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_CSSORT, /* state */ + "latin2", /* cs name */ + "latin2_czech_cs", /* name */ + "", /* comment */ + NULL, /* tailoring */ ctype_czech, to_lower_czech, to_upper_czech, diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index 7d81766c4cb..3cdf7f460cd 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -443,6 +443,37 @@ static void my_hash_sort_mb_bin(CHARSET_INFO *cs __attribute__((unused)), } } + +/* + Write max key: create a buffer with multibyte + representation of the max_sort_char character, + and copy it into max_str in a loop. +*/ +static void pad_max_char(CHARSET_INFO *cs, char *str, char *end) +{ + char buf[10]; + char buflen= cs->cset->wc_mb(cs, cs->max_sort_char, (uchar*) buf, + (uchar*) buf + sizeof(buf)); + DBUG_ASSERT(buflen > 0); + do + { + if ((str + buflen) < end) + { + /* Enough space for the characer */ + memcpy(str, buf, buflen); + str+= buflen; + } + else + { + /* + There is no space for whole multibyte + character, then add trailing spaces. + */ + *str++= ' '; + } + } while (str < end); +} + /* ** Calculate min_str and max_str that ranges a LIKE string. ** Arguments: @@ -467,10 +498,15 @@ my_bool my_like_range_mb(CHARSET_INFO *cs, char *min_str,char *max_str, uint *min_length,uint *max_length) { - const char *end=ptr+ptr_length; - char *min_org=min_str; - char *min_end=min_str+res_length; - char *max_end=max_str+res_length; + const char *end; + char *min_org= min_str; + char *min_end= min_str + res_length; + char *max_end= max_str + res_length; + uint charlen= my_charpos(cs, ptr, ptr+ptr_length, res_length/cs->mbmaxlen); + + if (charlen < ptr_length) + ptr_length= charlen; + end= ptr + ptr_length; for (; ptr != end && min_str != min_end ; ptr++) { @@ -482,16 +518,14 @@ my_bool my_like_range_mb(CHARSET_INFO *cs, } if (*ptr == w_one || *ptr == w_many) /* '_' and '%' in SQL */ { - char buf[10]; - uint buflen; - uint charlen= my_charpos(cs, min_org, min_str, res_length/cs->mbmaxlen); + charlen= my_charpos(cs, min_org, min_str, res_length/cs->mbmaxlen); if (charlen < (uint) (min_str - min_org)) min_str= min_org + charlen; /* Write min key */ *min_length= (uint) (min_str - min_org); - *max_length=res_length; + *max_length= res_length; do { *min_str++= (char) cs->min_sort_char; @@ -502,27 +536,7 @@ my_bool my_like_range_mb(CHARSET_INFO *cs, representation of the max_sort_char character, and copy it into max_str in a loop. */ - buflen= cs->cset->wc_mb(cs, cs->max_sort_char, (uchar*) buf, - (uchar*) buf + sizeof(buf)); - DBUG_ASSERT(buflen > 0); - do - { - if ((max_str + buflen) <= max_end) - { - /* Enough space for max characer */ - memcpy(max_str, buf, buflen); - max_str+= buflen; - } - else - { - /* - There is no space for whole multibyte - character, then add trailing spaces. - */ - - *max_str++= ' '; - } - } while (max_str != max_end); + pad_max_char(cs, max_str, max_end); return 0; } *min_str++= *max_str++ = *ptr; @@ -530,7 +544,8 @@ my_bool my_like_range_mb(CHARSET_INFO *cs, *min_length= *max_length = (uint) (min_str - min_org); while (min_str != min_end) - *min_str++ = *max_str++ = ' '; /* Because if key compression */ + *min_str++= ' '; /* Because if key compression */ + pad_max_char(cs, max_str, max_end); return 0; } diff --git a/strings/ctype-uca.c b/strings/ctype-uca.c index 91af7af0c54..89c876ad10c 100644 --- a/strings/ctype-uca.c +++ b/strings/ctype-uca.c @@ -7288,6 +7288,7 @@ int my_wildcmp_uca(CHARSET_INFO *cs, { while (1) { + my_bool escaped= 0; if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, (const uchar*)wildend)) <= 0) return 1; @@ -7305,6 +7306,7 @@ int my_wildcmp_uca(CHARSET_INFO *cs, (const uchar*)wildend)) <= 0) return 1; wildstr+= scan; + escaped= 1; } if ((scan= mb_wc(cs, &s_wc, (const uchar*)str, @@ -7312,7 +7314,7 @@ int my_wildcmp_uca(CHARSET_INFO *cs, return 1; str+= scan; - if (w_wc == (my_wc_t)w_one) + if (!escaped && w_wc == (my_wc_t)w_one) { result= 1; /* Found an anchor char */ } @@ -8567,7 +8569,7 @@ CHARSET_INFO my_charset_utf8_icelandic_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8594,7 +8596,7 @@ CHARSET_INFO my_charset_utf8_latvian_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8621,7 +8623,7 @@ CHARSET_INFO my_charset_utf8_romanian_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8648,7 +8650,7 @@ CHARSET_INFO my_charset_utf8_slovenian_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8675,7 +8677,7 @@ CHARSET_INFO my_charset_utf8_polish_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8702,7 +8704,7 @@ CHARSET_INFO my_charset_utf8_estonian_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8729,7 +8731,7 @@ CHARSET_INFO my_charset_utf8_spanish_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8756,7 +8758,7 @@ CHARSET_INFO my_charset_utf8_swedish_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8783,7 +8785,7 @@ CHARSET_INFO my_charset_utf8_turkish_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8810,7 +8812,7 @@ CHARSET_INFO my_charset_utf8_czech_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8838,7 +8840,7 @@ CHARSET_INFO my_charset_utf8_danish_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8865,7 +8867,7 @@ CHARSET_INFO my_charset_utf8_lithuanian_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8892,7 +8894,7 @@ CHARSET_INFO my_charset_utf8_slovak_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8919,7 +8921,7 @@ CHARSET_INFO my_charset_utf8_spanish2_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8946,7 +8948,7 @@ CHARSET_INFO my_charset_utf8_roman_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, @@ -8973,7 +8975,7 @@ CHARSET_INFO my_charset_utf8_persian_uca_ci= NULL, /* ident_map */ 8, /* strxfrm_multiply */ 1, /* mbminlen */ - 2, /* mbmaxlen */ + 3, /* mbmaxlen */ 9, /* min_sort_char */ 0xFFFF, /* max_sort_char */ &my_charset_utf8_handler, diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index b3097649158..ce9346eb475 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -1545,31 +1545,33 @@ int my_wildcmp_unicode(CHARSET_INFO *cs, { while (1) { + my_bool escaped= 0; if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, (const uchar*)wildend)) <= 0) return 1; - - if (w_wc == (my_wc_t)escape) - { - wildstr+= scan; - if ((scan= mb_wc(cs,&w_wc, (const uchar*)wildstr, - (const uchar*)wildend)) <= 0) - return 1; - } - + if (w_wc == (my_wc_t)w_many) { result= 1; /* Found an anchor char */ break; } - + wildstr+= scan; + if (w_wc == (my_wc_t)escape) + { + if ((scan= mb_wc(cs, &w_wc, (const uchar*)wildstr, + (const uchar*)wildend)) <= 0) + return 1; + wildstr+= scan; + escaped= 1; + } + if ((scan= mb_wc(cs, &s_wc, (const uchar*)str, - (const uchar*)str_end)) <=0) + (const uchar*)str_end)) <= 0) return 1; str+= scan; - if (w_wc == (my_wc_t)w_one) + if (!escaped && w_wc == (my_wc_t)w_one) { result= 1; /* Found an anchor char */ } diff --git a/strings/ctype-win1250ch.c b/strings/ctype-win1250ch.c index b4dbda3e8ed..4ada3d47bf5 100644 --- a/strings/ctype-win1250ch.c +++ b/strings/ctype-win1250ch.c @@ -624,12 +624,12 @@ static MY_COLLATION_HANDLER my_collation_czech_ci_handler = CHARSET_INFO my_charset_cp1250_czech_ci = { - 34,0,0, /* number */ - MY_CS_COMPILED|MY_CS_STRNXFRM, /* state */ - "cp1250", /* cs name */ - "cp1250_czech_cs", /* name */ - "", /* comment */ - NULL, /* tailoring */ + 34,0,0, /* number */ + MY_CS_COMPILED|MY_CS_STRNXFRM|MY_CS_CSSORT, /* state */ + "cp1250", /* cs name */ + "cp1250_czech_cs", /* name */ + "", /* comment */ + NULL, /* tailoring */ ctype_win1250ch, to_lower_win1250ch, to_upper_win1250ch, diff --git a/strings/uca-dump.c b/strings/uca-dump.c index 6836c321526..dd3b74a55e8 100644 --- a/strings/uca-dump.c +++ b/strings/uca-dump.c @@ -23,13 +23,14 @@ struct uca_item_st #define MY_UCA_PSHIFT 8 #endif +static char *pname[]= {"", "2", "3"}; + int main(int ac, char **av) { char str[256]; char *weights[64]; struct uca_item_st uca[64*1024]; - size_t code, page, w; - int pagemaxlen[MY_UCA_NPAGES]; + size_t code, w; int pageloaded[MY_UCA_NPAGES]; bzero(uca, sizeof(uca)); @@ -155,14 +156,20 @@ int main(int ac, char **av) printf("#define MY_UCA_CMASK %d\n",MY_UCA_CMASK); printf("#define MY_UCA_PSHIFT %d\n",MY_UCA_PSHIFT); - for (w=0; w<1; w++) + for (w=0; w<3; w++) { + size_t page; + int pagemaxlen[MY_UCA_NPAGES]; + for (page=0; page < MY_UCA_NPAGES; page++) { size_t offs; size_t maxnum= 0; size_t nchars= 0; size_t mchars; + size_t ndefs= 0; + + pagemaxlen[page]= 0; /* Skip this page if no weights were loaded @@ -183,15 +190,36 @@ int main(int ac, char **av) code= page*MY_UCA_NCHARS+offs; /* Calculate only non-zero weights */ - num=0; - for (i=0; i < uca[code].num; i++) + for (num=0, i=0; i < uca[code].num; i++) if (uca[code].weight[w][i]) num++; maxnum= maxnum < num ? num : maxnum; + + /* Check if default weight */ + if (w == 1 && num == 1) + { + /* 0020 0000 ... */ + if (uca[code].weight[w][0] == 0x0020) + ndefs++; + } + else if (w == 2 && num == 1) + { + /* 0002 0000 ... */ + if (uca[code].weight[w][0] == 0x0002) + ndefs++; + } } maxnum++; + /* + If the page have only default weights + then no needs to dump it, skip. + */ + if (ndefs == MY_UCA_NCHARS) + { + continue; + } switch (maxnum) { case 0: mchars= 8; break; @@ -210,8 +238,8 @@ int main(int ac, char **av) */ - printf("uint16 page%03Xdata[]= { /* %04X (%d weights per char) */\n", - page, page*MY_UCA_NCHARS, maxnum); + printf("uint16 page%03Xdata%s[]= { /* %04X (%d weights per char) */\n", + page, pname[w], page*MY_UCA_NCHARS, maxnum); for (offs=0; offs < MY_UCA_NCHARS; offs++) { @@ -234,7 +262,17 @@ int main(int ac, char **av) for (i=0; i < maxnum; i++) { - printf("0x%04X",(int)weight[i]); + /* + Invert weights for secondary level to + sort upper case letters before their + lower case counter part. + */ + int tmp= weight[i]; + if (w == 2 && tmp) + tmp= (int)(0x20 - weight[i]); + + + printf("0x%04X", tmp); if ((offs+1 != MY_UCA_NCHARS) || (i+1!=maxnum)) printf(","); nchars++; @@ -251,25 +289,28 @@ int main(int ac, char **av) } printf("};\n\n"); } + + printf("uchar uca_length%s[%d]={\n", pname[w], MY_UCA_NPAGES); + for (page=0; page < MY_UCA_NPAGES; page++) + { + printf("%d%s%s",pagemaxlen[page],pagecharsetnr, 0); + DIE_UNLESS(cs); if (!opt_silent) { fprintf(stdout, "\n field[%d]:", no); @@ -654,7 +657,7 @@ static void verify_prepare_field(MYSQL_RES *result, field->org_table, org_table); fprintf(stdout, "\n database :`%s`\t(expected: `%s`)", field->db, db); fprintf(stdout, "\n length :`%ld`\t(expected: `%ld`)", - field->length, length); + field->length, length * cs->mbmaxlen); fprintf(stdout, "\n maxlength:`%ld`", field->max_length); fprintf(stdout, "\n charsetnr:`%d`", field->charsetnr); fprintf(stdout, "\n default :`%s`\t(expected: `%s`)", @@ -663,11 +666,24 @@ static void verify_prepare_field(MYSQL_RES *result, } DIE_UNLESS(strcmp(field->name, name) == 0); DIE_UNLESS(strcmp(field->org_name, org_name) == 0); - DIE_UNLESS(field->type == type); + /* + XXX: silent column specification change works based on number of + bytes a column occupies. So CHAR -> VARCHAR upgrade is possible even + for CHAR(2) column if its character set is multibyte. + VARCHAR -> CHAR downgrade won't work for VARCHAR(3) as one would + expect. + */ + if (cs->mbmaxlen == 1) + DIE_UNLESS(field->type == type); DIE_UNLESS(strcmp(field->table, table) == 0); DIE_UNLESS(strcmp(field->org_table, org_table) == 0); DIE_UNLESS(strcmp(field->db, db) == 0); - DIE_UNLESS(field->length == length); + /* + Character set should be taken into account for multibyte encodings, such + as utf8. Field length is calculated as number of characters * maximum + number of bytes a character can occupy. + */ + DIE_UNLESS(field->length == length * cs->mbmaxlen); if (def) DIE_UNLESS(strcmp(field->def, def) == 0); } @@ -11105,6 +11121,140 @@ static void test_bug6096() } +/* + Test of basic checks that are performed in server for components + of MYSQL_TIME parameters. +*/ + +static void test_datetime_ranges() +{ + const char *stmt_text; + int rc, i; + MYSQL_STMT *stmt; + MYSQL_BIND bind[6]; + MYSQL_TIME tm[6]; + + myheader("test_datetime_ranges"); + + stmt_text= "drop table if exists t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "create table t1 (year datetime, month datetime, day datetime, " + "hour datetime, min datetime, sec datetime)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, + "INSERT INTO t1 VALUES (?, ?, ?, ?, ?, ?)"); + check_stmt(stmt); + verify_param_count(stmt, 6); + + bzero(bind, sizeof(bind)); + for (i= 0; i < 6; i++) + { + bind[i].buffer_type= MYSQL_TYPE_DATETIME; + bind[i].buffer= &tm[i]; + } + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + tm[0].year= 2004; tm[0].month= 11; tm[0].day= 10; + tm[0].hour= 12; tm[0].minute= 30; tm[0].second= 30; + tm[0].second_part= 0; tm[0].neg= 0; + + tm[5]= tm[4]= tm[3]= tm[2]= tm[1]= tm[0]; + tm[0].year= 10000; tm[1].month= 13; tm[2].day= 32; + tm[3].hour= 24; tm[4].minute= 60; tm[5].second= 60; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + DIE_UNLESS(mysql_warning_count(mysql) != 6); + + verify_col_data("t1", "year", "0000-00-00 00:00:00"); + verify_col_data("t1", "month", "0000-00-00 00:00:00"); + verify_col_data("t1", "day", "0000-00-00 00:00:00"); + verify_col_data("t1", "hour", "0000-00-00 00:00:00"); + verify_col_data("t1", "min", "0000-00-00 00:00:00"); + verify_col_data("t1", "sec", "0000-00-00 00:00:00"); + + mysql_stmt_close(stmt); + + stmt_text= "delete from t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, "INSERT INTO t1 (year, month, day) " + "VALUES (?, ?, ?)"); + check_stmt(stmt); + verify_param_count(stmt, 3); + + /* + We reuse contents of bind and tm arrays left from previous part of test. + */ + for (i= 0; i < 3; i++) + bind[i].buffer_type= MYSQL_TYPE_DATE; + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + DIE_UNLESS(mysql_warning_count(mysql) != 3); + + verify_col_data("t1", "year", "0000-00-00 00:00:00"); + verify_col_data("t1", "month", "0000-00-00 00:00:00"); + verify_col_data("t1", "day", "0000-00-00 00:00:00"); + + mysql_stmt_close(stmt); + + stmt_text= "drop table t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt_text= "create table t1 (day_ovfl time, day time, hour time, min time, sec time)"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); + + stmt= mysql_simple_prepare(mysql, + "INSERT INTO t1 VALUES (?, ?, ?, ?, ?)"); + check_stmt(stmt); + verify_param_count(stmt, 5); + + /* + Again we reuse what we can from previous part of test. + */ + for (i= 0; i < 5; i++) + bind[i].buffer_type= MYSQL_TYPE_TIME; + + rc= mysql_stmt_bind_param(stmt, bind); + check_execute(stmt, rc); + + tm[0].year= 0; tm[0].month= 0; tm[0].day= 10; + tm[0].hour= 12; tm[0].minute= 30; tm[0].second= 30; + tm[0].second_part= 0; tm[0].neg= 0; + + tm[4]= tm[3]= tm[2]= tm[1]= tm[0]; + tm[0].day= 35; tm[1].day= 34; tm[2].hour= 30; tm[3].minute= 60; tm[4].second= 60; + + rc= mysql_stmt_execute(stmt); + check_execute(stmt, rc); + DIE_UNLESS(mysql_warning_count(mysql) != 2); + + verify_col_data("t1", "day_ovfl", "838:59:59"); + verify_col_data("t1", "day", "828:30:30"); + verify_col_data("t1", "hour", "270:30:30"); + verify_col_data("t1", "min", "00:00:00"); + verify_col_data("t1", "sec", "00:00:00"); + + mysql_stmt_close(stmt); + + stmt_text= "drop table t1"; + rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text)); + myquery(rc); +} + + static void test_bug4172() { MYSQL_STMT *stmt; @@ -11439,6 +11589,7 @@ static struct my_tests_st my_tests[]= { { "test_bug6046", test_bug6046 }, { "test_bug6081", test_bug6081 }, { "test_bug6096", test_bug6096 }, + { "test_datetime_ranges", test_datetime_ranges }, { "test_bug4172", test_bug4172 }, { "test_conversion", test_conversion }, { 0, 0 }