summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--VC++Files/mysys/mysys.dsp4
-rw-r--r--VC++Files/mysys/mysys_ia64.dsp4
-rw-r--r--client/mysql.cc31
-rw-r--r--client/mysqltest.c43
-rw-r--r--include/my_sys.h3
-rw-r--r--include/myisam.h15
-rw-r--r--man/which.254
-rw-r--r--myisam/mi_check.c30
-rw-r--r--myisam/myisamchk.c27
-rwxr-xr-xmysql-test/mysql-test-run.pl155
-rw-r--r--mysql-test/r/innodb.result9
-rw-r--r--mysql-test/r/myisam.result61
-rw-r--r--mysql-test/r/rpl_multi_delete2.result29
-rw-r--r--mysql-test/r/type_decimal.result9
-rw-r--r--mysql-test/r/union.result15
-rw-r--r--mysql-test/t/innodb.test9
-rw-r--r--mysql-test/t/myisam.test47
-rw-r--r--mysql-test/t/rpl_multi_delete2-slave.opt2
-rw-r--r--mysql-test/t/rpl_multi_delete2.test45
-rw-r--r--mysql-test/t/type_decimal.test10
-rw-r--r--mysql-test/t/union.test8
-rw-r--r--mysys/my_conio.c217
-rw-r--r--ndb/include/ndbapi/Ndb.hpp28
-rw-r--r--ndb/include/ndbapi/NdbBlob.hpp6
-rw-r--r--ndb/include/ndbapi/NdbConnection.hpp12
-rw-r--r--ndb/include/ndbapi/NdbIndexOperation.hpp1
-rw-r--r--ndb/include/ndbapi/NdbIndexScanOperation.hpp2
-rw-r--r--ndb/include/ndbapi/NdbOperation.hpp8
-rw-r--r--ndb/include/ndbapi/NdbRecAttr.hpp7
-rw-r--r--ndb/src/ndbapi/NdbApiSignal.cpp19
-rw-r--r--ndb/src/ndbapi/NdbApiSignal.hpp3
-rw-r--r--ndb/src/ndbapi/NdbBlob.cpp2
-rw-r--r--ndb/src/ndbapi/NdbImpl.hpp119
-rw-r--r--ndb/src/ndbapi/NdbRecAttr.cpp4
-rw-r--r--ndb/src/ndbapi/NdbUtil.cpp16
-rw-r--r--ndb/src/ndbapi/NdbUtil.hpp40
-rw-r--r--ndb/src/ndbapi/Ndbif.cpp9
-rw-r--r--ndb/src/ndbapi/Ndbinit.cpp42
-rw-r--r--ndb/src/ndbapi/Ndblist.cpp519
-rw-r--r--ndb/src/ndbapi/ObjectMap.hpp33
-rw-r--r--ndb/test/include/NDBT_Test.hpp2
-rw-r--r--ndb/test/ndbapi/bank/BankLoad.cpp4
-rw-r--r--ndb/test/ndbapi/testOIBasic.cpp6
-rw-r--r--ndb/test/src/HugoCalculator.cpp6
-rw-r--r--ndb/test/src/NDBT_Test.cpp2
-rw-r--r--ndb/test/src/NdbBackup.cpp2
-rw-r--r--ndb/test/src/NdbRestarts.cpp30
-rw-r--r--ndb/tools/restore/Restore.cpp2
-rw-r--r--sql/field_conv.cc3
-rw-r--r--sql/ha_myisam.cc9
-rw-r--r--sql/ha_ndbcluster.cc46
-rw-r--r--sql/ha_ndbcluster.h2
-rw-r--r--sql/handler.h1
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/mysqld.cc29
-rw-r--r--sql/opt_sum.cc3
-rw-r--r--sql/set_var.cc10
-rw-r--r--sql/slave.cc9
-rw-r--r--sql/sql_class.h1
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_load.cc7
-rw-r--r--sql/sql_parse.cc61
-rw-r--r--sql/sql_yacc.yy13
63 files changed, 1224 insertions, 725 deletions
diff --git a/VC++Files/mysys/mysys.dsp b/VC++Files/mysys/mysys.dsp
index f47203d37bf..2f3d7bb272c 100644
--- a/VC++Files/mysys/mysys.dsp
+++ b/VC++Files/mysys/mysys.dsp
@@ -361,6 +361,10 @@ SOURCE=.\my_compress.c
# End Source File
# Begin Source File
+SOURCE=.\my_conio.c
+# End Source File
+# Begin Source File
+
SOURCE=.\my_copy.c
# End Source File
# Begin Source File
diff --git a/VC++Files/mysys/mysys_ia64.dsp b/VC++Files/mysys/mysys_ia64.dsp
index a0877457286..622ae1d5bce 100644
--- a/VC++Files/mysys/mysys_ia64.dsp
+++ b/VC++Files/mysys/mysys_ia64.dsp
@@ -362,6 +362,10 @@ SOURCE=.\my_compress.c
# End Source File
# Begin Source File
+SOURCE=.\my_conio.c
+# End Source File
+# Begin Source File
+
SOURCE=.\my_copy.c
# End Source File
# Begin Source File
diff --git a/client/mysql.cc b/client/mysql.cc
index 51822b64c82..be1541faaf5 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -938,10 +938,15 @@ static int get_options(int argc, char **argv)
static int read_lines(bool execute_commands)
{
-#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
+#if defined(OS2) || defined(__NETWARE__)
char linebuffer[254];
String buffer;
#endif
+#if defined(__WIN__)
+ String tmpbuf;
+ String buffer;
+#endif
+
char *line;
char in_string=0;
ulong line_number=0;
@@ -972,7 +977,7 @@ static int read_lines(bool execute_commands)
#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
tee_fputs(prompt, stdout);
-#ifdef __NETWARE__
+#if defined(__NETWARE__)
line=fgets(linebuffer, sizeof(linebuffer)-1, stdin);
/* Remove the '\n' */
if (line)
@@ -981,7 +986,22 @@ static int read_lines(bool execute_commands)
if (p != NULL)
*p = '\0';
}
-#else
+#elif defined(__WIN__)
+ if (!tmpbuf.is_alloced())
+ tmpbuf.alloc(65535);
+ buffer.length(0);
+ unsigned long clen;
+ do
+ {
+ line= my_cgets(tmpbuf.c_ptr(), tmpbuf.alloced_length(), &clen);
+ buffer.append(line, clen);
+ /*
+ if we got buffer fully filled than there is a chance that
+ something else is still in console input buffer
+ */
+ } while (tmpbuf.alloced_length() <= clen + 1);
+ line= buffer.c_ptr();
+#else /* OS2 */
buffer.length(0);
/* _cgets() expects the buffer size - 3 as the first byte */
linebuffer[0]= (char) sizeof(linebuffer) - 3;
@@ -1057,9 +1077,14 @@ static int read_lines(bool execute_commands)
status.exit_status=0;
}
}
+
#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__)
buffer.free();
#endif
+#if defined( __WIN__)
+ tmpbuf.free();
+#endif
+
return status.exit_status;
}
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 374f0cb1336..f5facccee3a 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -97,6 +97,10 @@
#define DEFAULT_DELIMITER ";"
#define MAX_DELIMITER 16
+#define RESULT_OK 0
+#define RESULT_CONTENT_MISMATCH 1
+#define RESULT_LENGTH_MISMATCH 2
+
enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD,
OPT_MANAGER_PORT,OPT_MANAGER_WAIT_TIMEOUT, OPT_SKIP_SAFEMALLOC,
OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH,
@@ -650,7 +654,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
{
DBUG_PRINT("info",("Size differs: result size: %u file size: %u",
ds->length, stat_info.st_size));
- DBUG_RETURN(2);
+ DBUG_RETURN(RESULT_LENGTH_MISMATCH);
}
if (!(tmp = (char*) my_malloc(stat_info.st_size + 1, MYF(MY_WME))))
die(NullS);
@@ -667,7 +671,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
res_ptr = res_ds.str;
if ((res_len = res_ds.length) != ds->length)
{
- res = 2;
+ res= RESULT_LENGTH_MISMATCH;
goto err;
}
}
@@ -677,7 +681,8 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
res_len = stat_info.st_size;
}
- res = (memcmp(res_ptr, ds->str, res_len)) ? 1 : 0;
+ res= (memcmp(res_ptr, ds->str, res_len)) ?
+ RESULT_CONTENT_MISMATCH : RESULT_OK;
err:
if (res && eval_result)
@@ -694,21 +699,21 @@ err:
static int check_result(DYNAMIC_STRING* ds, const char *fname,
my_bool require_option)
{
- int error = 0;
- int res=dyn_string_cmp(ds, fname);
+ int error= RESULT_OK;
+ int res= dyn_string_cmp(ds, fname);
if (res && require_option)
abort_not_supported_test();
switch (res) {
- case 0:
+ case RESULT_OK:
break; /* ok */
- case 2:
+ case RESULT_LENGTH_MISMATCH:
verbose_msg("Result length mismatch");
- error = 1;
+ error= RESULT_LENGTH_MISMATCH;
break;
- case 1:
+ case RESULT_CONTENT_MISMATCH:
verbose_msg("Result content mismatch");
- error = 1;
+ error= RESULT_CONTENT_MISMATCH;
break;
default: /* impossible */
die("Unknown error code from dyn_string_cmp()");
@@ -3738,8 +3743,9 @@ int main(int argc, char **argv)
{
int error = 0;
struct st_query *q;
- my_bool require_file=0, q_send_flag=0;
+ my_bool require_file=0, q_send_flag=0, query_executed= 0;
char save_file[FN_REFLEN];
+ MY_STAT res_info;
MY_INIT(argv[0]);
{
DBUG_ENTER("main");
@@ -3932,6 +3938,7 @@ int main(int argc, char **argv)
save_file[0]=0;
}
error |= run_query(&cur_con->mysql, q, flags);
+ query_executed= 1;
q->last_argument= q->end;
break;
}
@@ -3952,6 +3959,7 @@ int main(int argc, char **argv)
is given on this connection.
*/
error |= run_query(&cur_con->mysql, q, QUERY_SEND);
+ query_executed= 1;
q->last_argument= q->end;
break;
case Q_RESULT:
@@ -3992,6 +4000,7 @@ int main(int argc, char **argv)
break;
case Q_EXEC:
do_exec(q);
+ query_executed= 1;
break;
case Q_START_TIMER:
/* Overwrite possible earlier start of timer */
@@ -4048,6 +4057,18 @@ int main(int argc, char **argv)
parser.current_line += current_line_inc;
}
+ if (!query_executed && result_file && my_stat(result_file, &res_info, 0))
+ {
+ /*
+ my_stat() successful on result file. Check if we have not run a
+ single query, but we do have a result file that contains data.
+ Note that we don't care, if my_stat() fails. For example for
+ non-existing or non-readable file we assume it's fine to have
+ no query output from the test file, e.g. regarded as no error.
+ */
+ if (res_info.st_size)
+ error|= (RESULT_CONTENT_MISMATCH | RESULT_LENGTH_MISMATCH);
+ }
if (result_file && ds_res.length && !error)
{
if (!record)
diff --git a/include/my_sys.h b/include/my_sys.h
index 9127a58d71c..02ea188a18e 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -801,6 +801,9 @@ int my_security_attr_create(SECURITY_ATTRIBUTES **psa, const char **perror,
void my_security_attr_free(SECURITY_ATTRIBUTES *sa);
+/* implemented in my_conio.c */
+char* my_cgets(char *string, unsigned long clen, unsigned long* plen);
+
#endif
#ifdef __NETWARE__
void netware_reg_user(const char *ip, const char *user,
diff --git a/include/myisam.h b/include/myisam.h
index 6d097770646..e276d4efdff 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -311,6 +311,20 @@ typedef struct st_sort_key_blocks /* Used when sorting */
} SORT_KEY_BLOCKS;
+/*
+ MyISAM supports several statistics collection methods. Currently statistics
+ collection method is not stored in MyISAM file and has to be specified for
+ each table analyze/repair operation in MI_CHECK::stats_method.
+*/
+
+typedef enum
+{
+ /* Treat NULLs as inequal when collecting statistics (default for 4.1/5.0) */
+ MI_STATS_METHOD_NULLS_NOT_EQUAL,
+ /* Treat NULLs as equal when collecting statistics (like 4.0 did) */
+ MI_STATS_METHOD_NULLS_EQUAL
+} enum_mi_stats_method;
+
typedef struct st_mi_check_param
{
ulonglong auto_increment_value;
@@ -341,6 +355,7 @@ typedef struct st_mi_check_param
void *thd;
char *db_name,*table_name;
char *op_name;
+ enum_mi_stats_method stats_method;
} MI_CHECK;
typedef struct st_sort_ft_buf
diff --git a/man/which.2 b/man/which.2
deleted file mode 100644
index 30d5557ed01..00000000000
--- a/man/which.2
+++ /dev/null
@@ -1,54 +0,0 @@
-.TH WHICH 1 "20 December 2000"
-.SH NAME
-which - Jani please supply one.
-.SH USAGE
-which [options] [--] programname [...]
-.SH SYNOPSIS
-.B which
-.RB [ \-\-version | \-[vV] ]
-.RB [ \-\-skip\-dot ]
-.RB [ \-\-skip\-tilde ]
-.RB [ \-\-show\-dot ]
-.RB [ \-\-show\-tilde ]
-.RB [ \-\-tty\-only ]
-.RB [ \-\-all | \-a ]
-.RB [ \-\-read\-alias | \-i ]
-.RB [ \-\-skip\-alias ]
-.SH DESCRIPTION
-.TP
-.BR which
-supports by executing
-.TP
-.BR \-\-version | \-[vV]
-Print version and exit successfully.
-.TP
-.BR \-\-skip\-dot
-Skip directories in PATH that start with a dot.
-.TP
-.BR \-\-skip\-tilde
-Skip directories in PATH that start with a tilde.
-.TP
-.BR \-\-show\-dot
-Don\'t expand a dot to current directory in output.
-.TP
-.BR \-\-show\-tilde
-Output a tilde for HOME directory for non-root.
-.TP
-.BR \-\-tty\-only
-Stop processing options on the right if not on tty.
-.TP
-.BR \-\-all | \-a
-Print all matches in PATH, not just the first
-.TP
-.BR \-\-read\-alias | \-i
-Read list of aliases from stdin.
-.TP
-.BR \-\-skip\-alias
-Ignore option
-.BR --read-alias;
-don\'t read stdin.
-.SH "SEE ALSO"
-isamchk (1), isamlog (1), mysqlaccess (1), mysqladmin (1), mysqlbug (1), mysqld (1), mysqldump (1), mysqlshow (1), msql2mysql (1), perror (1), replace (1), mysqld_safe (1), which1 (1), zap (1),
-.SH AUTHOR
-Ver 1.0, distribution 3.23.29a Michael (Monty) Widenius (monty@tcx.se), TCX Datakonsult AB (http://www.tcx.se). This software comes with no warranty. Manual page by L. (Kill-9) Pedersen (kill-9@kill-9.dk), Mercurmedia Data Model Architect / system developer (http://www.mercurmedia.com)
-.\" end of man page \ No newline at end of file
diff --git a/myisam/mi_check.c b/myisam/mi_check.c
index 038ce8d953f..0c85b5234a1 100644
--- a/myisam/mi_check.c
+++ b/myisam/mi_check.c
@@ -80,6 +80,7 @@ void myisamchk_init(MI_CHECK *param)
param->start_check_pos=0;
param->max_record_length= LONGLONG_MAX;
param->key_cache_block_size= KEY_CACHE_BLOCK_SIZE;
+ param->stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
}
/* Check the status flags for the table */
@@ -558,10 +559,11 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
ha_checksum *key_checksum, uint level)
{
int flag;
- uint used_length,comp_flag,nod_flag,key_length=0,not_used;
+ uint used_length,comp_flag,nod_flag,key_length=0;
uchar key[MI_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*old_keypos,*endpos;
my_off_t next_page,record;
char llbuff[22];
+ uint diff_pos;
DBUG_ENTER("chk_index");
DBUG_DUMP("buff",(byte*) buff,mi_getint(buff));
@@ -619,7 +621,7 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
}
if ((*keys)++ &&
(flag=ha_key_cmp(keyinfo->seg,info->lastkey,key,key_length,
- comp_flag, &not_used)) >=0)
+ comp_flag, &diff_pos)) >=0)
{
DBUG_DUMP("old",(byte*) info->lastkey, info->lastkey_length);
DBUG_DUMP("new",(byte*) key, key_length);
@@ -635,11 +637,11 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo,
{
if (*keys != 1L) /* not first_key */
{
- uint diff;
- ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,
- SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL,
- &diff);
- param->unique_count[diff-1]++;
+ if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
+ ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY,
+ SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL,
+ &diff_pos);
+ param->unique_count[diff_pos-1]++;
}
}
(*key_checksum)+= mi_byte_checksum((byte*) key,
@@ -2013,7 +2015,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
sort_param.sort_info=&sort_info;
sort_param.fix_datafile= (my_bool) (! rep_quick);
sort_param.master =1;
-
+
del=info->state->del;
param->glob_crc=0;
if (param->testflag & T_CALC_CHECKSUM)
@@ -3249,9 +3251,10 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
cmp=ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
(uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE,
&diff_pos);
- ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
- (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL,
- &diff_pos);
+ if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL)
+ ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey,
+ (uchar*) a, USE_WHOLE_KEY,
+ SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, &diff_pos);
sort_param->unique[diff_pos-1]++;
}
else
@@ -3989,9 +3992,10 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info,
unique[0]= (#different values of {keypart1}) - 1
unique[1]= (#different values of {keypart2,keypart1} tuple) - unique[0] - 1
...
- Here we assume that NULL != NULL (see SEARCH_NULL_ARE_NOT_EQUAL). The
- 'unique' array is collected in one sequential scan through the entire
+ The 'unique' array is collected in one sequential scan through the entire
index. This is done in two places: in chk_index() and in sort_key_write().
+ Statistics collection may consider NULLs as either equal or inequal (see
+ SEARCH_NULL_ARE_NOT_EQUAL, MI_STATS_METHOD_*).
Output is an array:
rec_per_key_part[k] =
diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c
index 3b9742b79fb..1a7d2b2d9a8 100644
--- a/myisam/myisamchk.c
+++ b/myisam/myisamchk.c
@@ -67,6 +67,7 @@ static const char *field_pack[]=
"no zeros", "blob", "constant", "table-lockup",
"always zero","varchar","unique-hash","?","?"};
+static const char *myisam_stats_method_str="nulls_inequal";
static void get_options(int *argc,char * * *argv);
static void print_version(void);
@@ -155,7 +156,7 @@ enum options_mc {
OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE,
OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN,
OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE,
- OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE
+ OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD
};
static struct my_option my_long_options[] =
@@ -336,6 +337,11 @@ static struct my_option my_long_options[] =
"Use stopwords from this file instead of built-in list.",
(gptr*) &ft_stopword_file, (gptr*) &ft_stopword_file, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ {"stats_method", OPT_STATS_METHOD,
+ "Specifies how index statistics collection code should threat NULLs. "
+ "Possible values of name are \"nulls_inequal\" (default behavior for 4.1/5.0), and \"nulls_equal\" (emulate 4.0 behavior).",
+ (gptr*) &myisam_stats_method_str, (gptr*) &myisam_stats_method_str, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@@ -465,6 +471,12 @@ static void usage(void)
#include <help_end.h>
+const char *myisam_stats_method_names[] = {"nulls_inequal", "nulls_equal",
+ NullS};
+TYPELIB myisam_stats_method_typelib= {
+ array_elements(myisam_stats_method_names) - 1, "",
+ myisam_stats_method_names, NULL};
+
/* Read options */
static my_bool
@@ -684,6 +696,19 @@ get_one_option(int optid,
else
check_param.testflag|= T_CALC_CHECKSUM;
break;
+ case OPT_STATS_METHOD:
+ {
+ myisam_stats_method_str= argument;
+ int method;
+ if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
+ {
+ fprintf(stderr, "Invalid value of stats_method: %s.\n", argument);
+ exit(1);
+ }
+ check_param.stats_method= test(method-1)? MI_STATS_METHOD_NULLS_EQUAL :
+ MI_STATS_METHOD_NULLS_NOT_EQUAL;
+ break;
+ }
#ifdef DEBUG /* Only useful if debugging */
case OPT_START_CHECK_POS:
check_param.start_check_pos= strtoull(argument, NULL, 0);
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 013b8d49967..19a2679d956 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -237,8 +237,10 @@ our $opt_ps_protocol;
our $opt_sleep_time_after_restart= 1;
our $opt_sleep_time_for_delete= 10;
-our $opt_testcase_timeout= 5; # 5 min max
-our $opt_suite_timeout= 120; # 2 hours max
+our $opt_testcase_timeout;
+our $opt_suite_timeout;
+my $default_testcase_timeout= 10; # 10 min max
+my $default_suite_timeout= 120; # 2 hours max
our $opt_socket;
@@ -256,6 +258,7 @@ our $opt_user;
our $opt_user_test;
our $opt_valgrind;
+our $opt_valgrind_mysqltest;
our $opt_valgrind_all;
our $opt_valgrind_options;
@@ -509,8 +512,9 @@ sub command_line_setup () {
# Coverage, profiling etc
'gcov' => \$opt_gcov,
'gprof' => \$opt_gprof,
- 'valgrind' => \$opt_valgrind,
- 'valgrind-all' => \$opt_valgrind_all,
+ 'valgrind:s' => \$opt_valgrind,
+ 'valgrind-mysqltest:s' => \$opt_valgrind_mysqltest,
+ 'valgrind-all:s' => \$opt_valgrind_all,
'valgrind-options=s' => \$opt_valgrind_options,
# Misc
@@ -688,29 +692,42 @@ sub command_line_setup () {
$opt_with_ndbcluster= 0;
}
- # FIXME
+ # The ":s" in the argument spec, means we have three different cases
+ #
+ # undefined option not set
+ # "" option set with no argument
+ # "somestring" option is name/path of valgrind executable
+
+ # Take executable path from any of them, if any
+ $opt_valgrind= $opt_valgrind_mysqltest if $opt_valgrind_mysqltest;
+ $opt_valgrind= $opt_valgrind_all if $opt_valgrind_all;
+
+ # If valgrind flag not defined, define if other valgrind flags are
+ unless ( defined $opt_valgrind )
+ {
+ $opt_valgrind= ""
+ if defined $opt_valgrind_mysqltest or defined $opt_valgrind_all;
+ }
+
+ if ( ! $opt_testcase_timeout )
+ {
+ $opt_testcase_timeout= $default_testcase_timeout;
+ $opt_testcase_timeout*= 10 if defined $opt_valgrind;
+ }
- #if ( $opt_valgrind or $opt_valgrind_all )
- #{
- # VALGRIND=`which valgrind` # this will print an error if not found FIXME
- # Give good warning to the user and stop
- # if ( ! $VALGRIND )
- # {
- # print "You need to have the 'valgrind' program in your PATH to run mysql-test-run with option --valgrind. Valgrind's home page is http://valgrind.kde.org.\n"
- # exit 1
- # }
+ if ( ! $opt_suite_timeout )
+ {
+ $opt_suite_timeout= $default_suite_timeout;
+ $opt_suite_timeout*= 4 if defined $opt_valgrind;
+ }
+
+ if ( defined $opt_valgrind )
+ {
+ $opt_sleep_time_after_restart= 10;
+ $opt_sleep_time_for_delete= 60;
# >=2.1.2 requires the --tool option, some versions write to stdout, some to stderr
- # valgrind --help 2>&1 | grep "\-\-tool" > /dev/null && VALGRIND="$VALGRIND --tool=memcheck"
- # VALGRIND="$VALGRIND --alignment=8 --leak-check=yes --num-callers=16"
- # $opt_extra_mysqld_opt.= " --skip-safemalloc --skip-bdb";
- # SLEEP_TIME_AFTER_RESTART=10
- # $opt_sleep_time_for_delete= 60
- # $glob_use_running_server= ""
- # if ( "$1"= "--valgrind-all" )
- # {
- # VALGRIND="$VALGRIND -v --show-reachable=yes"
- # }
- #}
+ # valgrind --help 2>&1 | grep "\-\-tool" > /dev/null && VALGRIND="$VALGRIND --tool=memcheck"
+ }
if ( ! $opt_user )
{
@@ -1703,7 +1720,7 @@ sub mysqld_arguments ($$$$$) {
mtr_add_arg($args, "%s--language=%s", $prefix, $path_language);
mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix);
- if ( $opt_valgrind )
+ if ( defined $opt_valgrind )
{
mtr_add_arg($args, "%s--skip-safemalloc", $prefix);
mtr_add_arg($args, "%s--skip-bdb", $prefix);
@@ -1928,29 +1945,9 @@ sub mysqld_start ($$$$) {
mtr_init_args(\$args);
- if ( $opt_valgrind )
+ if ( defined $opt_valgrind )
{
-
- mtr_add_arg($args, "--tool=memcheck");
- mtr_add_arg($args, "--alignment=8");
- mtr_add_arg($args, "--leak-check=yes");
- mtr_add_arg($args, "--num-callers=16");
-
- if ( $opt_valgrind_all )
- {
- mtr_add_arg($args, "-v");
- mtr_add_arg($args, "--show-reachable=yes");
- }
-
- if ( $opt_valgrind_options )
- {
- # FIXME split earlier and put into @glob_valgrind_*
- mtr_add_arg($args, split(' ', $opt_valgrind_options));
- }
-
- mtr_add_arg($args, $exe);
-
- $exe= $opt_valgrind;
+ valgrind_arguments($args, \$exe);
}
mysqld_arguments($args,$type,$idx,$extra_opt,$slave_master_info);
@@ -2121,6 +2118,11 @@ sub run_mysqltest ($) {
mtr_init_args(\$args);
+ if ( defined $opt_valgrind_mysqltest )
+ {
+ valgrind_arguments($args, \$exe);
+ }
+
mtr_add_arg($args, "--no-defaults");
mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_mysock'});
mtr_add_arg($args, "--database=test");
@@ -2155,11 +2157,6 @@ sub run_mysqltest ($) {
mtr_add_arg($args, "--big-test");
}
- if ( $opt_record )
- {
- mtr_add_arg($args, "--record");
- }
-
if ( $opt_compress )
{
mtr_add_arg($args, "--compress");
@@ -2185,9 +2182,6 @@ sub run_mysqltest ($) {
$glob_mysql_test_dir);
}
- mtr_add_arg($args, "-R");
- mtr_add_arg($args, $tinfo->{'result_file'});
-
# ----------------------------------------------------------------------
# If embedded server, we create server args to give mysqltest to pass on
# ----------------------------------------------------------------------
@@ -2202,9 +2196,51 @@ sub run_mysqltest ($) {
# ----------------------------------------------------------------------
$ENV{'MYSQL_TEST'}= "$exe_mysqltest " . join(" ", @$args);
+ # ----------------------------------------------------------------------
+ # Add args that should not go into the MYSQL_TEST environment var
+ # ----------------------------------------------------------------------
+
+ mtr_add_arg($args, "-R");
+ mtr_add_arg($args, $tinfo->{'result_file'});
+
+ if ( $opt_record )
+ {
+ mtr_add_arg($args, "--record");
+ }
+
return mtr_run_test($exe,$args,$tinfo->{'path'},"",$path_timefile,"");
}
+
+sub valgrind_arguments {
+ my $args= shift;
+ my $exe= shift;
+
+ mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option
+ mtr_add_arg($args, "--alignment=8");
+ mtr_add_arg($args, "--leak-check=yes");
+ mtr_add_arg($args, "--num-callers=16");
+ mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir)
+ if -f "$glob_mysql_test_dir/valgrind.supp";
+
+ if ( defined $opt_valgrind_all )
+ {
+ mtr_add_arg($args, "-v");
+ mtr_add_arg($args, "--show-reachable=yes");
+ }
+
+ if ( $opt_valgrind_options )
+ {
+ # FIXME split earlier and put into @glob_valgrind_*
+ mtr_add_arg($args, split(' ', $opt_valgrind_options));
+ }
+
+ mtr_add_arg($args, $$exe);
+
+ $$exe= $opt_valgrind || "valgrind";
+}
+
+
##############################################################################
#
# Usage
@@ -2271,8 +2307,11 @@ Options for coverage, profiling etc
gcov FIXME
gprof FIXME
- valgrind FIXME
- valgrind-all FIXME
+ valgrind[=EXE] Run the "mysqltest" executable as well as the "mysqld"
+ server using valgrind, optionally specifying the
+ executable path/name
+ valgrind-mysqltest[=EXE] In addition, run the "mysqltest" executable with valgrind
+ valgrind-all[=EXE] Adds verbose flag, and --show-reachable to valgrind
valgrind-options=ARGS Extra options to give valgrind
Misc options
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index f47c78c9768..c7aef8ed792 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -1685,3 +1685,12 @@ explain select * from t1 order by a,b,c,d;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort
drop table t1;
+create table t1 (a char(1), b char(1), key(a, b)) engine=innodb;
+insert into t1 values ('8', '6'), ('4', '7');
+select min(a) from t1;
+min(a)
+4
+select min(b) from t1 where a='8';
+min(b)
+6
+drop table t1;
diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result
index 1837a4078a7..b3144a6903b 100644
--- a/mysql-test/r/myisam.result
+++ b/mysql-test/r/myisam.result
@@ -609,3 +609,64 @@ checksum table t2;
Table Checksum
test.t2 984116287
drop table t1, t2;
+show variables like 'myisam_stats_method';
+Variable_name Value
+myisam_stats_method nulls_inequal
+create table t1 (a int, key(a));
+insert into t1 values (0),(1),(2),(3),(4);
+insert into t1 select NULL from t1;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+show index 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 10 NULL NULL YES BTREE
+insert into t1 values (11);
+delete from t1 where a=11;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+show index 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 10 NULL NULL YES BTREE
+set myisam_stats_method=nulls_equal;
+show variables like 'myisam_stats_method';
+Variable_name Value
+myisam_stats_method nulls_equal
+insert into t1 values (11);
+delete from t1 where a=11;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+show index 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 5 NULL NULL YES BTREE
+insert into t1 values (11);
+delete from t1 where a=11;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+show index 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 5 NULL NULL YES BTREE
+set myisam_stats_method=DEFAULT;
+show variables like 'myisam_stats_method';
+Variable_name Value
+myisam_stats_method nulls_inequal
+insert into t1 values (11);
+delete from t1 where a=11;
+analyze table t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status OK
+show index 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 10 NULL NULL YES BTREE
+insert into t1 values (11);
+delete from t1 where a=11;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+show index 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 10 NULL NULL YES BTREE
+drop table t1;
diff --git a/mysql-test/r/rpl_multi_delete2.result b/mysql-test/r/rpl_multi_delete2.result
index c6c088111fc..73db9f62eb4 100644
--- a/mysql-test/r/rpl_multi_delete2.result
+++ b/mysql-test/r/rpl_multi_delete2.result
@@ -4,6 +4,26 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
+set sql_log_bin=0;
+create database mysqltest_from;
+set sql_log_bin=1;
+create database mysqltest_to;
+use mysqltest_from;
+drop table if exists a;
+CREATE TABLE a (i INT);
+INSERT INTO a VALUES(1);
+DELETE alias FROM a alias WHERE alias.i=1;
+SELECT * FROM a;
+i
+insert into a values(2),(3);
+delete a alias FROM a alias where alias.i=2;
+select * from a;
+i
+3
+use mysqltest_to;
+select * from a;
+i
+3
create table t1 (a int);
create table t2 (a int);
insert into t1 values (1);
@@ -15,7 +35,10 @@ select * from t2;
a
1
select * from t1;
-ERROR 42S02: Table 'test.t1' doesn't exist
+ERROR 42S02: Table 'mysqltest_to.t1' doesn't exist
select * from t2;
-ERROR 42S02: Table 'test.t2' doesn't exist
-drop table t1,t2;
+ERROR 42S02: Table 'mysqltest_to.t2' doesn't exist
+set sql_log_bin=0;
+drop database mysqltest_from;
+set sql_log_bin=1;
+drop database mysqltest_to;
diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result
index a9dcabd121e..c3b2d5090ef 100644
--- a/mysql-test/r/type_decimal.result
+++ b/mysql-test/r/type_decimal.result
@@ -646,3 +646,12 @@ a
9999.999
0000.000
drop table t1;
+create table t1(a decimal(10,5), b decimal(10,1));
+insert into t1 values(123.12345, 123.12345);
+update t1 set b=a;
+Warnings:
+Warning 1265 Data truncated for column 'b' at row 1
+select * from t1;
+a b
+123.12345 123.1
+drop table t1;
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result
index 1b5fa69d713..a3dd2c5c291 100644
--- a/mysql-test/r/union.result
+++ b/mysql-test/r/union.result
@@ -780,21 +780,6 @@ t1 CREATE TABLE `t1` (
`b` longblob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1,t2;
-create table t1 (d decimal(10,1));
-create table t2 (d decimal(10,9));
-insert into t1 values ("100000000.0");
-insert into t2 values ("1.23456780");
-create table t3 select * from t2 union select * from t1;
-select * from t3;
-d
-1.234567800
-100000000.0
-show create table t3;
-Table Create Table
-t3 CREATE TABLE `t3` (
- `d` decimal(10,9) default NULL
-) ENGINE=MyISAM DEFAULT CHARSET=latin1
-drop table t1,t2,t3;
create table t1 select 1 union select -1;
select * from t1;
1
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index a14370c6543..b966ea5b281 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -1230,4 +1230,13 @@ select * from t1 order by a,b,c,d;
explain select * from t1 order by a,b,c,d;
drop table t1;
+#
+# BUG#11039,#13218 Wrong key length in min()
+#
+
+create table t1 (a char(1), b char(1), key(a, b)) engine=innodb;
+insert into t1 values ('8', '6'), ('4', '7');
+select min(a) from t1;
+select min(b) from t1 where a='8';
+drop table t1;
# End of 4.1 tests
diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test
index 83e9e1ba7d2..dc40ecc2dd4 100644
--- a/mysql-test/t/myisam.test
+++ b/mysql-test/t/myisam.test
@@ -590,4 +590,51 @@ checksum table t1;
checksum table t2;
drop table t1, t2;
+# BUG#12232: New myisam_stats_method variable.
+show variables like 'myisam_stats_method';
+
+create table t1 (a int, key(a));
+insert into t1 values (0),(1),(2),(3),(4);
+insert into t1 select NULL from t1;
+
+# default: NULLs considered inequal
+analyze table t1;
+show index from t1;
+insert into t1 values (11);
+delete from t1 where a=11;
+check table t1;
+show index from t1;
+
+# Set nulls to be equal:
+set myisam_stats_method=nulls_equal;
+show variables like 'myisam_stats_method';
+insert into t1 values (11);
+delete from t1 where a=11;
+
+analyze table t1;
+show index from t1;
+
+insert into t1 values (11);
+delete from t1 where a=11;
+
+check table t1;
+show index from t1;
+
+# Set nulls back to be equal
+set myisam_stats_method=DEFAULT;
+show variables like 'myisam_stats_method';
+insert into t1 values (11);
+delete from t1 where a=11;
+
+analyze table t1;
+show index from t1;
+
+insert into t1 values (11);
+delete from t1 where a=11;
+
+check table t1;
+show index from t1;
+
+drop table t1;
+
# End of 4.1 tests
diff --git a/mysql-test/t/rpl_multi_delete2-slave.opt b/mysql-test/t/rpl_multi_delete2-slave.opt
index b828d03fafb..0febb2891b1 100644
--- a/mysql-test/t/rpl_multi_delete2-slave.opt
+++ b/mysql-test/t/rpl_multi_delete2-slave.opt
@@ -1 +1 @@
---replicate-wild-ignore-table=test.%
+"--replicate-rewrite-db=mysqltest_from->mysqltest_to" --replicate-do-table=mysqltest_to.a
diff --git a/mysql-test/t/rpl_multi_delete2.test b/mysql-test/t/rpl_multi_delete2.test
index 62d95a3a90f..c50311de363 100644
--- a/mysql-test/t/rpl_multi_delete2.test
+++ b/mysql-test/t/rpl_multi_delete2.test
@@ -1,4 +1,41 @@
+#multi delete replication bugs
+
+
source include/master-slave.inc;
+
+#BUG#11139 - improper wild-table and table rules
+#checking for multi deletes with an alias
+
+connection master;
+set sql_log_bin=0;
+create database mysqltest_from;
+set sql_log_bin=1;
+
+connection slave;
+create database mysqltest_to;
+
+
+connection master;
+use mysqltest_from;
+--disable_warnings
+drop table if exists a;
+--enable_warnings
+CREATE TABLE a (i INT);
+INSERT INTO a VALUES(1);
+DELETE alias FROM a alias WHERE alias.i=1;
+SELECT * FROM a;
+insert into a values(2),(3);
+delete a alias FROM a alias where alias.i=2;
+select * from a;
+save_master_pos;
+connection slave;
+
+use mysqltest_to;
+sync_with_master;
+select * from a;
+
+# BUG#3461
+connection master;
create table t1 (a int);
create table t2 (a int);
@@ -19,7 +56,13 @@ select * from t1;
error 1146;
select * from t2;
+# cleanup
connection master;
-drop table t1,t2;
+set sql_log_bin=0;
+drop database mysqltest_from;
+set sql_log_bin=1;
+connection slave;
+drop database mysqltest_to;
# End of 4.1 tests
+
diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test
index a6fd99e8c9a..1f133666910 100644
--- a/mysql-test/t/type_decimal.test
+++ b/mysql-test/t/type_decimal.test
@@ -266,4 +266,14 @@ insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000
select * from t1;
drop table t1;
+#
+# Bug #7589: a problem with update from column
+#
+
+create table t1(a decimal(10,5), b decimal(10,1));
+insert into t1 values(123.12345, 123.12345);
+update t1 set b=a;
+select * from t1;
+drop table t1;
+
# End of 4.1 tests
diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test
index 6acccaeafd5..6a54909536a 100644
--- a/mysql-test/t/union.test
+++ b/mysql-test/t/union.test
@@ -425,14 +425,6 @@ create table t1 SELECT b from t2 UNION select tx from t2;
select * from t1;
show create table t1;
drop table t1,t2;
-create table t1 (d decimal(10,1));
-create table t2 (d decimal(10,9));
-insert into t1 values ("100000000.0");
-insert into t2 values ("1.23456780");
-create table t3 select * from t2 union select * from t1;
-select * from t3;
-show create table t3;
-drop table t1,t2,t3;
create table t1 select 1 union select -1;
select * from t1;
show create table t1;
diff --git a/mysys/my_conio.c b/mysys/my_conio.c
new file mode 100644
index 00000000000..e381f9f23ef
--- /dev/null
+++ b/mysys/my_conio.c
@@ -0,0 +1,217 @@
+/* Copyright (C) 2000 MySQL AB
+
+ 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 "mysys_priv.h"
+
+#ifdef __WIN__
+
+static HANDLE my_coninpfh= 0; /* console input */
+
+/*
+ functions my_pthread_auto_mutex_lock & my_pthread_auto_mutex_free
+ are experimental at this moment, they are intended to bring
+ ability of protecting code sections without necessity to explicitly
+ initialize synchronization object in one of threads
+
+ if found useful they are to be exported in mysys
+*/
+
+/*
+ int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name,
+ int id, int time)
+
+ NOTES
+ creates a mutex with given name and tries to lock it time msec.
+ mutex name is appended with id to allow system wide or process wide
+ locks. Handle to created mutex returned in ph argument.
+
+ RETURN
+ 0 thread owns mutex
+ <>0 error
+
+*/
+static
+int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name, int id, int time)
+{
+ int res;
+ char tname[FN_REFLEN];
+
+ sprintf(tname, "%s-%08X", name, id);
+
+ *ph= CreateMutex(NULL, FALSE, tname);
+ if (*ph == NULL)
+ return GetLastError();
+
+ res= WaitForSingleObject(*ph, time);
+
+ if (res == WAIT_TIMEOUT)
+ return ERROR_SEM_TIMEOUT;
+
+ if (res == WAIT_FAILED)
+ return GetLastError();
+
+ return 0;
+}
+
+/*
+ int my_pthread_auto_mutex_free(HANDLE* ph)
+
+
+ NOTES
+ releases a mutex.
+
+ RETURN
+ 0 thread released mutex
+ <>0 error
+
+*/
+static
+int my_pthread_auto_mutex_free(HANDLE* ph)
+{
+ if (*ph)
+ {
+ ReleaseMutex(*ph);
+ CloseHandle(*ph);
+ *ph= NULL;
+ }
+
+ return 0;
+}
+
+
+#define pthread_auto_mutex_decl(name) \
+ HANDLE __h##name= NULL;
+
+#define pthread_auto_mutex_lock(name, proc, time) \
+ my_pthread_auto_mutex_lock(&__h##name, #name, (proc), (time))
+
+#define pthread_auto_mutex_free(name) \
+ my_pthread_auto_mutex_free(&__h##name)
+
+
+/*
+ char* my_cgets(char *string, unsigned long clen, unsigned long* plen)
+
+ NOTES
+ Replaces _cgets from libc to support input of more than 255 chars.
+ Reads from the console via ReadConsole into buffer which
+ should be at least clen characters.
+ Actual length of string returned in plen.
+
+ WARNING
+ my_cgets() does NOT check the pushback character buffer (i.e., _chbuf).
+ Thus, my_cgets() will not return any character that is pushed back by
+ the _ungetch() call.
+
+ RETURN
+ string pointer ok
+ NULL Error
+
+*/
+char* my_cgets(char *buffer, unsigned long clen, unsigned long* plen)
+{
+ ULONG state;
+ char *result;
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+ pthread_auto_mutex_decl(my_conio_cs);
+
+ /* lock the console for the current process*/
+ if (pthread_auto_mutex_lock(my_conio_cs, GetCurrentProcessId(), INFINITE))
+ {
+ /* can not lock console */
+ pthread_auto_mutex_free(my_conio_cs);
+ return NULL;
+ }
+
+ /* init console input */
+ if (my_coninpfh == 0)
+ {
+ /* same handle will be used until process termination */
+ my_coninpfh= CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, 0, NULL);
+ }
+
+ if (my_coninpfh == INVALID_HANDLE_VALUE)
+ {
+ /* unlock the console */
+ pthread_auto_mutex_free(my_conio_cs);
+ return(NULL);
+ }
+
+ GetConsoleMode((HANDLE)my_coninpfh, &state);
+ SetConsoleMode((HANDLE)my_coninpfh, ENABLE_LINE_INPUT |
+ ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT);
+
+ GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
+
+ /*
+ there is no known way to determine allowed buffer size for input
+ though it is known it should not be more than 64K
+ so we cut 64K and try first size of screen buffer
+ if it is still to large we cut half of it and try again
+ later we may want to cycle from min(clen, 65535) to allowed size
+ with small decrement to determine exact allowed buffer
+ */
+ clen= min(clen, 65535);
+ do
+ {
+ clen= min(clen, (unsigned long)csbi.dwSize.X*csbi.dwSize.Y);
+ if (!ReadConsole((HANDLE)my_coninpfh, (LPVOID)buffer, clen - 1, plen, NULL))
+ {
+ result= NULL;
+ clen>>= 1;
+ }
+ else
+ {
+ result= buffer;
+ break;
+ }
+ }
+ while (GetLastError() == ERROR_NOT_ENOUGH_MEMORY);
+
+
+ if (result != NULL)
+ {
+ if (buffer[*plen - 2] == '\r')
+ {
+ *plen= *plen - 2;
+ }
+ else
+ {
+ if (buffer[*plen - 1] == '\r')
+ {
+ char tmp[3];
+ int tmplen= sizeof(tmp);
+
+ *plen= *plen - 1;
+ /* read /n left in the buffer */
+ ReadConsole((HANDLE)my_coninpfh, (LPVOID)tmp, tmplen, &tmplen, NULL);
+ }
+ }
+ buffer[*plen]= '\0';
+ }
+
+ SetConsoleMode((HANDLE)my_coninpfh, state);
+ /* unlock the console */
+ pthread_auto_mutex_free(my_conio_cs);
+
+ return result;
+}
+
+#endif /* __WIN__ */
diff --git a/ndb/include/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp
index 766409d64e2..e905a304c97 100644
--- a/ndb/include/ndbapi/Ndb.hpp
+++ b/ndb/include/ndbapi/Ndb.hpp
@@ -882,10 +882,10 @@ class BaseString;
class NdbEventOperation;
class NdbBlob;
class NdbReceiver;
+template <class T> struct Ndb_free_list_t;
typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*);
-
#if defined NDB_OSE
/**
* Default time to wait for response after request has been sent to
@@ -1386,8 +1386,20 @@ public:
*/
NdbConnection* hupp( NdbConnection* );
Uint32 getReference() const { return theMyRef;}
+
+ struct Free_list_usage
+ {
+ const char * m_name;
+ Uint32 m_created;
+ Uint32 m_free;
+ Uint32 m_sizeof;
+ };
+
+ Free_list_usage * get_free_list_usage(Free_list_usage*);
#endif
+
+
/*****************************************************************************
* These are service routines used by the other classes in the NDBAPI.
****************************************************************************/
@@ -1562,22 +1574,8 @@ private:
class NdbDictionaryImpl* theDictionary;
class NdbGlobalEventBufferHandle* theGlobalEventBufferHandle;
- NdbConnection* theConIdleList; // First connection in idle list.
-
- NdbOperation* theOpIdleList; // First operation in the idle list.
-
- NdbIndexScanOperation* theScanOpIdleList; // First scan operation in the idle list.
- NdbIndexOperation* theIndexOpIdleList; // First index operation in the idle list.
NdbConnection* theTransactionList;
NdbConnection** theConnectionArray;
- NdbRecAttr* theRecAttrIdleList;
- NdbApiSignal* theSignalIdleList; // First signal in idlelist.
- NdbLabel* theLabelList; // First label descriptor in list
- NdbBranch* theBranchList; // First branch descriptor in list
- NdbSubroutine* theSubroutineList; // First subroutine descriptor in
- NdbCall* theCallList; // First call descriptor in list
- NdbReceiver* theScanList;
- NdbBlob* theNdbBlobIdleList;
Uint32 theMyRef; // My block reference
Uint32 theNode; // The node number of our node
diff --git a/ndb/include/ndbapi/NdbBlob.hpp b/ndb/include/ndbapi/NdbBlob.hpp
index b145c69b04b..a04f4f72bc9 100644
--- a/ndb/include/ndbapi/NdbBlob.hpp
+++ b/ndb/include/ndbapi/NdbBlob.hpp
@@ -262,7 +262,7 @@ private:
// for keeping in lists
NdbBlob* theNext;
// initialization
- NdbBlob();
+ NdbBlob(Ndb*);
void init();
void release();
// classify operations
@@ -314,6 +314,10 @@ private:
int getOperationType() const;
friend class NdbOut& operator<<(NdbOut&, const NdbBlob&);
#endif
+
+ void next(NdbBlob* obj) { theNext= obj;}
+ NdbBlob* next() { return theNext;}
+ friend struct Ndb_free_list_t<NdbBlob>;
};
#endif
diff --git a/ndb/include/ndbapi/NdbConnection.hpp b/ndb/include/ndbapi/NdbConnection.hpp
index 2ab6f7d6f64..75c3f80121d 100644
--- a/ndb/include/ndbapi/NdbConnection.hpp
+++ b/ndb/include/ndbapi/NdbConnection.hpp
@@ -18,8 +18,9 @@
#define NdbConnection_H
#include <ndb_types.h>
-#include <NdbError.hpp>
-#include <NdbDictionary.hpp>
+#include "NdbError.hpp"
+#include "NdbDictionary.hpp"
+#include "Ndb.hpp"
class NdbConnection;
class NdbOperation;
@@ -465,10 +466,10 @@ private:
/**************************************************************************
* These are the create and delete methods of this class. *
**************************************************************************/
-
NdbConnection(Ndb* aNdb);
-
~NdbConnection();
+ NdbConnection* next(); // Returns the next pointer
+ void next(NdbConnection*); // Sets the next pointer
void init(); // Initialize connection object for new transaction
@@ -487,8 +488,6 @@ private:
int getTC_ConnectPtr(); // Gets TC Connect pointer
void setBuddyConPtr(Uint32); // Sets Buddy Con Ptr
Uint32 getBuddyConPtr(); // Gets Buddy Con Ptr
- NdbConnection* next(); // Returns the next pointer
- void next(NdbConnection*); // Sets the next pointer
enum ConStatusType {
NotConnected,
@@ -691,6 +690,7 @@ private:
void define_scan_op(NdbIndexScanOperation*);
friend class HugoOperations;
+ friend struct Ndb_free_list_t<NdbConnection>;
};
inline
diff --git a/ndb/include/ndbapi/NdbIndexOperation.hpp b/ndb/include/ndbapi/NdbIndexOperation.hpp
index 1472f1b249e..2ab63cfc4f9 100644
--- a/ndb/include/ndbapi/NdbIndexOperation.hpp
+++ b/ndb/include/ndbapi/NdbIndexOperation.hpp
@@ -200,6 +200,7 @@ private:
Uint32 m_theIndexDefined[NDB_MAX_ATTRIBUTES_IN_INDEX][3];
Uint32 m_theIndexLen; // Length of the index in words
Uint32 m_theNoOfIndexDefined; // The number of index attributes
+ friend struct Ndb_free_list_t<NdbIndexOperation>;
};
#endif
diff --git a/ndb/include/ndbapi/NdbIndexScanOperation.hpp b/ndb/include/ndbapi/NdbIndexScanOperation.hpp
index a3388f62f58..7cd2daea6a6 100644
--- a/ndb/include/ndbapi/NdbIndexScanOperation.hpp
+++ b/ndb/include/ndbapi/NdbIndexScanOperation.hpp
@@ -132,6 +132,8 @@ private:
int compare(Uint32 key, Uint32 cols, const NdbReceiver*, const NdbReceiver*);
Uint32 m_sort_columns;
+
+ friend struct Ndb_free_list_t<NdbIndexScanOperation>;
};
#endif
diff --git a/ndb/include/ndbapi/NdbOperation.hpp b/ndb/include/ndbapi/NdbOperation.hpp
index 46d4ddab0f5..46e44226e18 100644
--- a/ndb/include/ndbapi/NdbOperation.hpp
+++ b/ndb/include/ndbapi/NdbOperation.hpp
@@ -22,6 +22,7 @@
#include "NdbError.hpp"
#include "NdbReceiver.hpp"
#include "NdbDictionary.hpp"
+#include "Ndb.hpp"
class Ndb;
class NdbApiSignal;
@@ -723,8 +724,6 @@ protected:
/******************************************************************************
* These are the methods used to create and delete the NdbOperation objects.
*****************************************************************************/
- NdbOperation(Ndb* aNdb);
- virtual ~NdbOperation();
bool needReply();
/******************************************************************************
@@ -736,8 +735,9 @@ protected:
int init(const class NdbTableImpl*, NdbConnection* aCon);
void initInterpreter();
+ NdbOperation(Ndb* aNdb);
+ virtual ~NdbOperation();
void next(NdbOperation*); // Set next pointer
-
NdbOperation* next(); // Get next pointer
enum OperationStatus{
@@ -925,6 +925,8 @@ protected:
* IgnoreError on connection level.
*/
Int8 m_abortOption;
+
+ friend struct Ndb_free_list_t<NdbOperation>;
};
#ifdef NDB_NO_DROPPED_SIGNAL
diff --git a/ndb/include/ndbapi/NdbRecAttr.hpp b/ndb/include/ndbapi/NdbRecAttr.hpp
index 05635a99385..741ea3d52e2 100644
--- a/ndb/include/ndbapi/NdbRecAttr.hpp
+++ b/ndb/include/ndbapi/NdbRecAttr.hpp
@@ -17,7 +17,8 @@
#ifndef NdbRecAttr_H
#define NdbRecAttr_H
-#include <NdbDictionary.hpp>
+#include "NdbDictionary.hpp"
+#include "Ndb.hpp"
class NdbOperation;
@@ -242,7 +243,6 @@ public:
*/
~NdbRecAttr();
private:
- NdbRecAttr();
Uint32 attrId() const; /* Get attribute id */
bool setNULL(); /* Set NULL indicator */
@@ -251,6 +251,7 @@ private:
void release(); /* Release memory if allocated */
void init(); /* Initialise object when allocated */
+ NdbRecAttr(Ndb*);
void next(NdbRecAttr* aRecAttr);
NdbRecAttr* next() const;
@@ -273,6 +274,8 @@ private:
Uint32 theAttrSize;
Uint32 theArraySize;
const NdbDictionary::Column* m_column;
+
+ friend struct Ndb_free_list_t<NdbRecAttr>;
};
inline
diff --git a/ndb/src/ndbapi/NdbApiSignal.cpp b/ndb/src/ndbapi/NdbApiSignal.cpp
index a1d34896968..953d87ac7b0 100644
--- a/ndb/src/ndbapi/NdbApiSignal.cpp
+++ b/ndb/src/ndbapi/NdbApiSignal.cpp
@@ -62,6 +62,25 @@ NdbApiSignal::NdbApiSignal(BlockReference ref)
theNextSignal = 0;
}
+NdbApiSignal::NdbApiSignal(Ndb* ndb)
+{
+ BlockReference ref = ndb->theMyRef;
+ theVerId_signalNumber = 0; // 4 bit ver id - 16 bit gsn
+ theReceiversBlockNumber = 0; // Only 16 bit blocknum
+ theSendersBlockRef = refToBlock(ref);
+ theLength = 0;
+ theSendersSignalId = 0;
+ theSignalId = 0;
+ theTrace = 0;
+ m_noOfSections = 0;
+ m_fragmentInfo = 0;
+ for (int i = 0; i < 25; i++)
+ theData[i] = 0x13579753;
+
+ setDataPtr(&theData[0]);
+ theNextSignal = 0;
+}
+
/**
* Copy constructor
*/
diff --git a/ndb/src/ndbapi/NdbApiSignal.hpp b/ndb/src/ndbapi/NdbApiSignal.hpp
index 52c3be2256c..9a8326bd666 100644
--- a/ndb/src/ndbapi/NdbApiSignal.hpp
+++ b/ndb/src/ndbapi/NdbApiSignal.hpp
@@ -46,7 +46,8 @@
class NdbApiSignal : public SignalHeader
{
public:
- NdbApiSignal(BlockReference myRef);
+ NdbApiSignal(Ndb* ndb);
+ NdbApiSignal(BlockReference ref);
NdbApiSignal(const NdbApiSignal &);
NdbApiSignal(const SignalHeader &header)
: SignalHeader(header), theNextSignal(0), theRealData(0) {};
diff --git a/ndb/src/ndbapi/NdbBlob.cpp b/ndb/src/ndbapi/NdbBlob.cpp
index f72361b86ac..c5692d79e83 100644
--- a/ndb/src/ndbapi/NdbBlob.cpp
+++ b/ndb/src/ndbapi/NdbBlob.cpp
@@ -137,7 +137,7 @@ NdbBlob::getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnIm
// initialization
-NdbBlob::NdbBlob()
+NdbBlob::NdbBlob(Ndb*)
{
init();
}
diff --git a/ndb/src/ndbapi/NdbImpl.hpp b/ndb/src/ndbapi/NdbImpl.hpp
index 00a8ef19f3a..33aaca8de96 100644
--- a/ndb/src/ndbapi/NdbImpl.hpp
+++ b/ndb/src/ndbapi/NdbImpl.hpp
@@ -32,6 +32,21 @@
#include "NdbDictionaryImpl.hpp"
#include "ObjectMap.hpp"
+template <class T>
+struct Ndb_free_list_t
+{
+ Ndb_free_list_t();
+ ~Ndb_free_list_t();
+
+ void fill(Ndb*, Uint32 cnt);
+ T* seize(Ndb*);
+ void release(T*);
+ void clear();
+ Uint32 get_sizeof() const { return sizeof(T); }
+ T * m_free_list;
+ Uint32 m_alloc_cnt, m_free_cnt;
+};
+
/**
* Private parts of the Ndb object (corresponding to Ndb.hpp in public API)
*/
@@ -59,6 +74,23 @@ public:
NdbWaiter theWaiter;
int m_optimized_node_selection;
+
+ /**
+ * NOTE free lists must be _after_ theNdbObjectIdMap take
+ * assure that destructors are run in correct order
+ */
+ Ndb_free_list_t<NdbConnection> theConIdleList;
+ Ndb_free_list_t<NdbOperation> theOpIdleList;
+ Ndb_free_list_t<NdbIndexScanOperation> theScanOpIdleList;
+ Ndb_free_list_t<NdbIndexOperation> theIndexOpIdleList;
+ Ndb_free_list_t<NdbRecAttr> theRecAttrIdleList;
+ Ndb_free_list_t<NdbApiSignal> theSignalIdleList;
+ Ndb_free_list_t<NdbLabel> theLabelList;
+ Ndb_free_list_t<NdbBranch> theBranchList;
+ Ndb_free_list_t<NdbSubroutine> theSubroutineList;
+ Ndb_free_list_t<NdbCall> theCallList;
+ Ndb_free_list_t<NdbBlob> theNdbBlobIdleList;
+ Ndb_free_list_t<NdbReceiver> theScanList;
};
#ifdef VM_TRACE
@@ -133,4 +165,91 @@ enum LockMode {
Delete
};
+template<class T>
+inline
+Ndb_free_list_t<T>::Ndb_free_list_t()
+{
+ m_free_list= 0;
+ m_alloc_cnt= m_free_cnt= 0;
+}
+
+template<class T>
+inline
+Ndb_free_list_t<T>::~Ndb_free_list_t()
+{
+ clear();
+}
+
+template<class T>
+inline
+void
+Ndb_free_list_t<T>::fill(Ndb* ndb, Uint32 cnt)
+{
+ if (m_free_list == 0)
+ {
+ m_free_cnt++;
+ m_alloc_cnt++;
+ m_free_list = new T(ndb);
+ }
+ while(m_alloc_cnt < cnt)
+ {
+ T* obj= new T(ndb);
+ if(obj == 0)
+ return;
+
+ obj->next(m_free_list);
+ m_free_cnt++;
+ m_alloc_cnt++;
+ m_free_list = obj;
+ }
+}
+
+template<class T>
+inline
+T*
+Ndb_free_list_t<T>::seize(Ndb* ndb)
+{
+ T* tmp = m_free_list;
+ if (tmp)
+ {
+ m_free_list = (T*)tmp->next();
+ tmp->next(NULL);
+ m_free_cnt--;
+ return tmp;
+ }
+
+ if((tmp = new T(ndb)))
+ {
+ m_alloc_cnt++;
+ }
+
+ return tmp;
+}
+
+template<class T>
+inline
+void
+Ndb_free_list_t<T>::release(T* obj)
+{
+ obj->next(m_free_list);
+ m_free_list = obj;
+ m_free_cnt++;
+}
+
+
+template<class T>
+inline
+void
+Ndb_free_list_t<T>::clear()
+{
+ T* obj = m_free_list;
+ while(obj)
+ {
+ T* curr = obj;
+ obj = (T*)obj->next();
+ delete curr;
+ m_alloc_cnt--;
+ }
+}
+
#endif
diff --git a/ndb/src/ndbapi/NdbRecAttr.cpp b/ndb/src/ndbapi/NdbRecAttr.cpp
index db83e9c5fcf..f993c652bf9 100644
--- a/ndb/src/ndbapi/NdbRecAttr.cpp
+++ b/ndb/src/ndbapi/NdbRecAttr.cpp
@@ -33,7 +33,7 @@ Adjust: 971206 UABRONM First version
#include "NdbDictionaryImpl.hpp"
#include <NdbTCP.h>
-NdbRecAttr::NdbRecAttr()
+NdbRecAttr::NdbRecAttr(Ndb*)
{
init();
}
@@ -109,7 +109,7 @@ NdbRecAttr::copyout()
NdbRecAttr *
NdbRecAttr::clone() const {
- NdbRecAttr * ret = new NdbRecAttr();
+ NdbRecAttr * ret = new NdbRecAttr(0);
ret->theAttrId = theAttrId;
ret->theNULLind = theNULLind;
diff --git a/ndb/src/ndbapi/NdbUtil.cpp b/ndb/src/ndbapi/NdbUtil.cpp
index 5c74d251ff9..6019ea675a1 100644
--- a/ndb/src/ndbapi/NdbUtil.cpp
+++ b/ndb/src/ndbapi/NdbUtil.cpp
@@ -30,8 +30,7 @@ Comment:
#include "NdbUtil.hpp"
-NdbLabel::NdbLabel() :
- theNext(NULL)
+NdbLabel::NdbLabel(Ndb*)
{
}
@@ -39,8 +38,7 @@ NdbLabel::~NdbLabel()
{
}
-NdbSubroutine::NdbSubroutine() :
- theNext(NULL)
+NdbSubroutine::NdbSubroutine(Ndb*)
{
}
@@ -48,9 +46,8 @@ NdbSubroutine::~NdbSubroutine()
{
}
-NdbBranch::NdbBranch() :
- theSignal(NULL),
- theNext(NULL)
+NdbBranch::NdbBranch(Ndb*) :
+ theSignal(NULL)
{
}
@@ -58,9 +55,8 @@ NdbBranch::~NdbBranch()
{
}
-NdbCall::NdbCall() :
- theSignal(NULL),
- theNext(NULL)
+NdbCall::NdbCall(Ndb*) :
+ theSignal(NULL)
{
}
diff --git a/ndb/src/ndbapi/NdbUtil.hpp b/ndb/src/ndbapi/NdbUtil.hpp
index 80fc15ddd8c..d14ac65ddef 100644
--- a/ndb/src/ndbapi/NdbUtil.hpp
+++ b/ndb/src/ndbapi/NdbUtil.hpp
@@ -34,41 +34,49 @@ Comment:
class NdbApiSignal;
class NdbOperation;
-class NdbLabel
+template<class T>
+struct Free_list_element
+{
+ Free_list_element() { theNext = 0;}
+ void next(T* obj) { theNext = obj;}
+ T* next() { return theNext;}
+
+ T* theNext;
+};
+
+class NdbLabel : public Free_list_element<NdbLabel>
{
friend class NdbOperation;
friend class Ndb;
-
-private:
- NdbLabel();
+public:
+ NdbLabel(Ndb*);
~NdbLabel();
- NdbLabel* theNext;
+private:
Uint32 theSubroutine[16];
Uint32 theLabelAddress[16];
Uint32 theLabelNo[16];
};
-class NdbSubroutine
+class NdbSubroutine : public Free_list_element<NdbSubroutine>
{
friend class NdbOperation;
friend class Ndb;
-private:
- NdbSubroutine();
+public:
+ NdbSubroutine(Ndb*);
~NdbSubroutine();
- NdbSubroutine* theNext;
Uint32 theSubroutineAddress[16];
};
-class NdbBranch
+class NdbBranch : public Free_list_element<NdbBranch>
{
friend class NdbOperation;
friend class Ndb;
-private:
- NdbBranch();
+public:
+ NdbBranch(Ndb*);
~NdbBranch();
NdbApiSignal* theSignal;
@@ -76,22 +84,20 @@ private:
Uint32 theBranchAddress;
Uint32 theBranchLabel;
Uint32 theSubroutine;
- NdbBranch* theNext;
};
-class NdbCall
+class NdbCall : public Free_list_element<NdbCall>
{
friend class NdbOperation;
friend class Ndb;
-private:
- NdbCall();
+public:
+ NdbCall(Ndb*);
~NdbCall();
NdbApiSignal* theSignal;
Uint32 theSignalAddress;
Uint32 theSubroutine;
- NdbCall* theNext;
};
#endif
diff --git a/ndb/src/ndbapi/Ndbif.cpp b/ndb/src/ndbapi/Ndbif.cpp
index 1caebe436ef..3ebba7e1c4a 100644
--- a/ndb/src/ndbapi/Ndbif.cpp
+++ b/ndb/src/ndbapi/Ndbif.cpp
@@ -143,15 +143,6 @@ Ndb::init(int aMaxNoOfTransactions)
error_handler:
ndbout << "error_handler" << endl;
releaseTransactionArrays();
- while ( theConIdleList != NULL )
- freeNdbCon();
- while ( theSignalIdleList != NULL )
- freeSignal();
- while (theRecAttrIdleList != NULL)
- freeRecAttr();
- while (theOpIdleList != NULL)
- freeOperation();
-
delete theDictionary;
TransporterFacade::instance()->close(theNdbBlockNumber, 0);
DBUG_RETURN(-1);
diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp
index a11dd842495..03704537c0a 100644
--- a/ndb/src/ndbapi/Ndbinit.cpp
+++ b/ndb/src/ndbapi/Ndbinit.cpp
@@ -99,20 +99,8 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection,
theMaxNoOfTransactions= 0;
theMinNoOfEventsToWakeUp= 0;
prefixEnd= NULL;
- theConIdleList= NULL;
- theOpIdleList= NULL;
- theScanOpIdleList= NULL;
- theIndexOpIdleList= NULL;
theTransactionList= NULL;
theConnectionArray= NULL;
- theRecAttrIdleList= NULL;
- theSignalIdleList= NULL;
- theLabelList= NULL;
- theBranchList= NULL;
- theSubroutineList= NULL;
- theCallList= NULL;
- theScanList= NULL;
- theNdbBlobIdleList= NULL;
the_last_check_time= 0;
theFirstTransId= 0;
theRestartGCI= 0;
@@ -204,33 +192,6 @@ Ndb::~Ndb()
TransporterFacade::instance()->close(theNdbBlockNumber, theFirstTransId);
}
-// if (theSchemaConToNdbList != NULL)
-// closeSchemaTransaction(theSchemaConToNdbList);
- while ( theConIdleList != NULL )
- freeNdbCon();
- while (theOpIdleList != NULL)
- freeOperation();
- while (theScanOpIdleList != NULL)
- freeScanOperation();
- while (theIndexOpIdleList != NULL)
- freeIndexOperation();
- while (theLabelList != NULL)
- freeNdbLabel();
- while (theBranchList != NULL)
- freeNdbBranch();
- while (theSubroutineList != NULL)
- freeNdbSubroutine();
- while (theCallList != NULL)
- freeNdbCall();
- while (theScanList != NULL)
- freeNdbScanRec();
- while (theNdbBlobIdleList != NULL)
- freeNdbBlob();
- while (theRecAttrIdleList != NULL)
- freeRecAttr();
- while ( theSignalIdleList != NULL )
- freeSignal();
-
releaseTransactionArrays();
delete []theConnectionArray;
@@ -296,7 +257,8 @@ NdbImpl::NdbImpl(Ndb_cluster_connection *ndb_cluster_connection,
: m_ndb_cluster_connection(ndb_cluster_connection->m_impl),
m_dictionary(ndb),
theCurrentConnectIndex(0),
- theNdbObjectIdMap(1024,1024),
+ theNdbObjectIdMap(ndb_cluster_connection->m_impl.m_transporter_facade->theMutexPtr,
+ 1024,1024),
theNoOfDBnodes(0)
{
int i;
diff --git a/ndb/src/ndbapi/Ndblist.cpp b/ndb/src/ndbapi/Ndblist.cpp
index 5902aa413dc..3001561a73a 100644
--- a/ndb/src/ndbapi/Ndblist.cpp
+++ b/ndb/src/ndbapi/Ndblist.cpp
@@ -76,25 +76,7 @@ Ndb::checkFailedNode()
int
Ndb::createConIdleList(int aNrOfCon)
{
- for (int i = 0; i < aNrOfCon; i++)
- {
- NdbConnection* tNdbCon = new NdbConnection(this);
- if (tNdbCon == NULL)
- {
- return -1;
- }
- if (theConIdleList == NULL)
- {
- theConIdleList = tNdbCon;
- theConIdleList->next(NULL);
- } else
- {
- tNdbCon->next(theConIdleList);
- theConIdleList = tNdbCon;
- }
- tNdbCon->Status(NdbConnection::NotConnected);
- }
- theNoOfAllocatedTransactions = aNrOfCon;
+ theImpl->theConIdleList.fill(this, aNrOfCon);
return aNrOfCon;
}
@@ -110,19 +92,7 @@ Ndb::createConIdleList(int aNrOfCon)
int
Ndb::createOpIdleList(int aNrOfOp)
{
- for (int i = 0; i < aNrOfOp; i++){
- NdbOperation* tOp = new NdbOperation(this);
- if ( tOp == NULL ){
- return -1;
- }
- if (theOpIdleList == NULL){
- theOpIdleList = tOp;
- theOpIdleList->next(NULL);
- } else{
- tOp->next(theOpIdleList);
- theOpIdleList = tOp;
- }
- }
+ theImpl->theOpIdleList.fill(this, aNrOfOp);
return aNrOfOp;
}
@@ -136,22 +106,7 @@ Ndb::createOpIdleList(int aNrOfOp)
NdbBranch*
Ndb::getNdbBranch()
{
- NdbBranch* tNdbBranch;
- if ( theBranchList == NULL )
- {
- tNdbBranch = new NdbBranch;
- if (tNdbBranch == NULL)
- {
- return NULL;
- }
- tNdbBranch->theNext = NULL;
- } else
- {
- tNdbBranch = theBranchList;
- theBranchList = tNdbBranch->theNext;
- tNdbBranch->theNext = NULL;
- }
- return tNdbBranch;
+ return theImpl->theBranchList.seize(this);
}
/***************************************************************************
@@ -164,22 +119,7 @@ Ndb::getNdbBranch()
NdbCall*
Ndb::getNdbCall()
{
- NdbCall* tNdbCall;
- if ( theCallList == NULL )
- {
- tNdbCall = new NdbCall;
- if (tNdbCall == NULL)
- {
- return NULL;
- }
- tNdbCall->theNext = NULL;
- } else
- {
- tNdbCall = theCallList;
- theCallList = tNdbCall->theNext;
- tNdbCall->theNext = NULL;
- }
- return tNdbCall;
+ return theImpl->theCallList.seize(this);
}
/***************************************************************************
@@ -192,25 +132,14 @@ Ndb::getNdbCall()
NdbConnection*
Ndb::getNdbCon()
{
- NdbConnection* tNdbCon;
- if ( theConIdleList == NULL ) {
- if (theNoOfAllocatedTransactions < theMaxNoOfTransactions) {
- tNdbCon = new NdbConnection(this);
- if (tNdbCon == NULL) {
- return NULL;
- }//if
- theNoOfAllocatedTransactions++;
- } else {
- ndbout << "theNoOfAllocatedTransactions = " << theNoOfAllocatedTransactions << " theMaxNoOfTransactions = " << theMaxNoOfTransactions << endl;
- return NULL;
- }//if
- tNdbCon->next(NULL);
- } else
+ NdbConnection* tNdbCon = theImpl->theConIdleList.seize(this);
+ if (unlikely(theImpl->theConIdleList.m_alloc_cnt > theMaxNoOfTransactions))
{
- tNdbCon = theConIdleList;
- theConIdleList = tNdbCon->next();
- tNdbCon->next(NULL);
- }
+ theImpl->theConIdleList.release(tNdbCon);
+ ndbout << "theNoOfAllocatedTransactions = " << theNoOfAllocatedTransactions << " theMaxNoOfTransactions = " << theMaxNoOfTransactions << endl;
+ return NULL;
+ }//if
+
tNdbCon->theMagicNumber = 0x37412619;
return tNdbCon;
}
@@ -225,22 +154,7 @@ Ndb::getNdbCon()
NdbLabel*
Ndb::getNdbLabel()
{
- NdbLabel* tNdbLabel;
- if ( theLabelList == NULL )
- {
- tNdbLabel = new NdbLabel;
- if (tNdbLabel == NULL)
- {
- return NULL;
- }
- tNdbLabel->theNext = NULL;
- } else
- {
- tNdbLabel = theLabelList;
- theLabelList = tNdbLabel->theNext;
- tNdbLabel->theNext = NULL;
- }
- return tNdbLabel;
+ return theImpl->theLabelList.seize(this);
}
/***************************************************************************
@@ -254,23 +168,7 @@ Ndb::getNdbLabel()
NdbReceiver*
Ndb::getNdbScanRec()
{
- NdbReceiver* tNdbScanRec;
- if ( theScanList == NULL )
- {
- tNdbScanRec = new NdbReceiver(this);
- if (tNdbScanRec == NULL)
- {
- return NULL;
- }
- tNdbScanRec->next(NULL);
- } else
- {
- tNdbScanRec = theScanList;
- theScanList = tNdbScanRec->next();
- tNdbScanRec->next(NULL);
- }
-
- return tNdbScanRec;
+ return theImpl->theScanList.seize(this);
}
/***************************************************************************
@@ -283,22 +181,7 @@ Ndb::getNdbScanRec()
NdbSubroutine*
Ndb::getNdbSubroutine()
{
- NdbSubroutine* tNdbSubroutine;
- if ( theSubroutineList == NULL )
- {
- tNdbSubroutine = new NdbSubroutine;
- if (tNdbSubroutine == NULL)
- {
- return NULL;
- }
- tNdbSubroutine->theNext = NULL;
- } else
- {
- tNdbSubroutine = theSubroutineList;
- theSubroutineList = tNdbSubroutine->theNext;
- tNdbSubroutine->theNext = NULL;
- }
- return tNdbSubroutine;
+ return theImpl->theSubroutineList.seize(this);
}
/***************************************************************************
@@ -311,18 +194,7 @@ Remark: Get an operation from theOpIdleList and return the object .
NdbOperation*
Ndb::getOperation()
{
- NdbOperation* tOp = theOpIdleList;
- if (tOp != NULL ) {
- NdbOperation* tOpNext = tOp->next();
- tOp->next(NULL);
- theOpIdleList = tOpNext;
- return tOp;
- } else {
- tOp = new NdbOperation(this);
- if (tOp != NULL)
- tOp->next(NULL);
- }
- return tOp;
+ return theImpl->theOpIdleList.seize(this);
}
/***************************************************************************
@@ -335,18 +207,7 @@ Remark: Get an operation from theScanOpIdleList and return the object .
NdbIndexScanOperation*
Ndb::getScanOperation()
{
- NdbIndexScanOperation* tOp = theScanOpIdleList;
- if (tOp != NULL ) {
- NdbIndexScanOperation* tOpNext = (NdbIndexScanOperation*)tOp->next();
- tOp->next(NULL);
- theScanOpIdleList = tOpNext;
- return tOp;
- } else {
- tOp = new NdbIndexScanOperation(this);
- if (tOp != NULL)
- tOp->next(NULL);
- }
- return tOp;
+ return theImpl->theScanOpIdleList.seize(this);
}
/***************************************************************************
@@ -359,18 +220,7 @@ Remark: Get an operation from theIndexOpIdleList and return the object .
NdbIndexOperation*
Ndb::getIndexOperation()
{
- NdbIndexOperation* tOp = theIndexOpIdleList;
- if (tOp != NULL ) {
- NdbIndexOperation* tOpNext = (NdbIndexOperation*) tOp->next();
- tOp->next(NULL);
- theIndexOpIdleList = tOpNext;
- return tOp;
- } else {
- tOp = new NdbIndexOperation(this);
- if (tOp != NULL)
- tOp->next(NULL);
- }
- return tOp;
+ return theImpl->theIndexOpIdleList.seize(this);
}
/***************************************************************************
@@ -382,21 +232,14 @@ Return Value: Return a reference to a receive attribute object.
NdbRecAttr*
Ndb::getRecAttr()
{
- NdbRecAttr* tRecAttr;
- tRecAttr = theRecAttrIdleList;
- if (tRecAttr != NULL) {
- NdbRecAttr* tRecAttrNext = tRecAttr->next();
+ NdbRecAttr* tRecAttr = theImpl->theRecAttrIdleList.seize(this);
+ if (tRecAttr != NULL)
+ {
tRecAttr->init();
- theRecAttrIdleList = tRecAttrNext;
return tRecAttr;
- } else {
- tRecAttr = new NdbRecAttr;
- if (tRecAttr == NULL)
- return NULL;
- tRecAttr->next(NULL);
- }//if
- tRecAttr->init();
- return tRecAttr;
+ }
+
+ return NULL;
}
/***************************************************************************
@@ -408,34 +251,16 @@ Return Value: Return a reference to a signal object.
NdbApiSignal*
Ndb::getSignal()
{
- NdbApiSignal* tSignal = theSignalIdleList;
- if (tSignal != NULL){
- NdbApiSignal* tSignalNext = tSignal->next();
- tSignal->next(NULL);
- theSignalIdleList = tSignalNext;
- } else {
- tSignal = new NdbApiSignal(theMyRef);
-#ifdef POORMANSPURIFY
- cnewSignals++;
-#endif
- if (tSignal != NULL)
- tSignal->next(NULL);
- }
-#ifdef POORMANSPURIFY
- cgetSignals++;
-#endif
- return tSignal;
+ return theImpl->theSignalIdleList.seize(this);
}
NdbBlob*
Ndb::getNdbBlob()
{
- NdbBlob* tBlob = theNdbBlobIdleList;
- if (tBlob != NULL) {
- theNdbBlobIdleList = tBlob->theNext;
+ NdbBlob* tBlob = theImpl->theNdbBlobIdleList.seize(this);
+ if(tBlob)
+ {
tBlob->init();
- } else {
- tBlob = new NdbBlob;
}
return tBlob;
}
@@ -449,8 +274,7 @@ Remark: Add a NdbBranch object into the Branch idlelist.
void
Ndb::releaseNdbBranch(NdbBranch* aNdbBranch)
{
- aNdbBranch->theNext = theBranchList;
- theBranchList = aNdbBranch;
+ theImpl->theBranchList.release(aNdbBranch);
}
/***************************************************************************
@@ -462,8 +286,7 @@ Remark: Add a NdbBranch object into the Branch idlelist.
void
Ndb::releaseNdbCall(NdbCall* aNdbCall)
{
- aNdbCall->theNext = theCallList;
- theCallList = aNdbCall;
+ theImpl->theCallList.release(aNdbCall);
}
/***************************************************************************
@@ -475,9 +298,8 @@ Remark: Add a Connection object into the signal idlelist.
void
Ndb::releaseNdbCon(NdbConnection* aNdbCon)
{
- aNdbCon->next(theConIdleList);
aNdbCon->theMagicNumber = 0xFE11DD;
- theConIdleList = aNdbCon;
+ theImpl->theConIdleList.release(aNdbCon);
}
/***************************************************************************
@@ -489,8 +311,7 @@ Remark: Add a NdbLabel object into the Label idlelist.
void
Ndb::releaseNdbLabel(NdbLabel* aNdbLabel)
{
- aNdbLabel->theNext = theLabelList;
- theLabelList = aNdbLabel;
+ theImpl->theLabelList.release(aNdbLabel);
}
/***************************************************************************
@@ -502,8 +323,7 @@ Remark: Add a NdbScanReceiver object into the Scan idlelist.
void
Ndb::releaseNdbScanRec(NdbReceiver* aNdbScanRec)
{
- aNdbScanRec->next(theScanList);
- theScanList = aNdbScanRec;
+ theImpl->theScanList.release(aNdbScanRec);
}
/***************************************************************************
@@ -515,8 +335,7 @@ Remark: Add a NdbSubroutine object into theSubroutine idlelist.
void
Ndb::releaseNdbSubroutine(NdbSubroutine* aNdbSubroutine)
{
- aNdbSubroutine->theNext = theSubroutineList;
- theSubroutineList = aNdbSubroutine;
+ theImpl->theSubroutineList.release(aNdbSubroutine);
}
/***************************************************************************
@@ -529,16 +348,14 @@ void
Ndb::releaseOperation(NdbOperation* anOperation)
{
if(anOperation->m_tcReqGSN == GSN_TCKEYREQ){
- anOperation->next(theOpIdleList);
anOperation->theNdbCon = NULL;
anOperation->theMagicNumber = 0xFE11D0;
- theOpIdleList = anOperation;
+ theImpl->theOpIdleList.release(anOperation);
} else {
assert(anOperation->m_tcReqGSN == GSN_TCINDXREQ);
- anOperation->next(theIndexOpIdleList);
anOperation->theNdbCon = NULL;
anOperation->theMagicNumber = 0xFE11D1;
- theIndexOpIdleList = (NdbIndexOperation*)anOperation;
+ theImpl->theIndexOpIdleList.release((NdbIndexOperation*)anOperation);
}
}
@@ -551,10 +368,9 @@ Remark: Add a NdbScanOperation object into the signal idlelist.
void
Ndb::releaseScanOperation(NdbIndexScanOperation* aScanOperation)
{
- aScanOperation->next(theScanOpIdleList);
aScanOperation->theNdbCon = NULL;
aScanOperation->theMagicNumber = 0xFE11D2;
- theScanOpIdleList = aScanOperation;
+ theImpl->theScanOpIdleList.release(aScanOperation);
}
/***************************************************************************
@@ -567,8 +383,7 @@ void
Ndb::releaseRecAttr(NdbRecAttr* aRecAttr)
{
aRecAttr->release();
- aRecAttr->next(theRecAttrIdleList);
- theRecAttrIdleList = aRecAttr;
+ theImpl->theRecAttrIdleList.release(aRecAttr);
}
/***************************************************************************
@@ -595,8 +410,7 @@ Ndb::releaseSignal(NdbApiSignal* aSignal)
#ifdef POORMANSPURIFY
creleaseSignals++;
#endif
- aSignal->next(theSignalIdleList);
- theSignalIdleList = aSignal;
+ theImpl->theSignalIdleList.release(aSignal);
}
void
@@ -612,163 +426,7 @@ Ndb::releaseSignalsInList(NdbApiSignal** pList){
void
Ndb::releaseNdbBlob(NdbBlob* aBlob)
{
- aBlob->release();
- aBlob->theNext = theNdbBlobIdleList;
- theNdbBlobIdleList = aBlob;
-}
-
-/***************************************************************************
-void freeOperation();
-
-Remark: Always release the first item in the free list
-***************************************************************************/
-void
-Ndb::freeOperation()
-{
- NdbOperation* tOp = theOpIdleList;
- theOpIdleList = theOpIdleList->next();
- delete tOp;
-}
-
-/***************************************************************************
-void freeScanOperation();
-
-Remark: Always release the first item in the free list
-***************************************************************************/
-void
-Ndb::freeScanOperation()
-{
- NdbIndexScanOperation* tOp = theScanOpIdleList;
- theScanOpIdleList = (NdbIndexScanOperation *)tOp->next();
- delete tOp;
-}
-
-/***************************************************************************
-void freeIndexOperation();
-
-Remark: Always release the first item in the free list
-***************************************************************************/
-void
-Ndb::freeIndexOperation()
-{
- NdbIndexOperation* tOp = theIndexOpIdleList;
- theIndexOpIdleList = (NdbIndexOperation *) theIndexOpIdleList->next();
- delete tOp;
-}
-
-/***************************************************************************
-void freeNdbBranch();
-
-Remark: Always release the first item in the free list
-***************************************************************************/
-void
-Ndb::freeNdbBranch()
-{
- NdbBranch* tNdbBranch = theBranchList;
- theBranchList = theBranchList->theNext;
- delete tNdbBranch;
-}
-
-/***************************************************************************
-void freeNdbCall();
-
-Remark: Always release the first item in the free list
-***************************************************************************/
-void
-Ndb::freeNdbCall()
-{
- NdbCall* tNdbCall = theCallList;
- theCallList = theCallList->theNext;
- delete tNdbCall;
-}
-
-/***************************************************************************
-void freeNdbScanRec();
-
-Remark: Always release the first item in the free list
-***************************************************************************/
-void
-Ndb::freeNdbScanRec()
-{
- NdbReceiver* tNdbScanRec = theScanList;
- theScanList = theScanList->next();
- delete tNdbScanRec;
-}
-
-/***************************************************************************
-void freeNdbCon();
-
-Remark: Always release the first item in the free list
-***************************************************************************/
-void
-Ndb::freeNdbCon()
-{
- NdbConnection* tNdbCon = theConIdleList;
- theConIdleList = theConIdleList->next();
- delete tNdbCon;
-}
-
-/***************************************************************************
-void freeNdbLabel();
-
-Remark: Always release the first item in the free list
-***************************************************************************/
-void
-Ndb::freeNdbLabel()
-{
- NdbLabel* tNdbLabel = theLabelList;
- theLabelList = theLabelList->theNext;
- delete tNdbLabel;
-}
-
-/***************************************************************************
-void freeNdbSubroutine();
-
-Remark: Always release the first item in the free list
-***************************************************************************/
-void
-Ndb::freeNdbSubroutine()
-{
- NdbSubroutine* tNdbSubroutine = theSubroutineList;
- theSubroutineList = theSubroutineList->theNext;
- delete tNdbSubroutine;
-}
-
-/***************************************************************************
-void freeRecAttr();
-
-Remark: Always release the first item in the free list
-***************************************************************************/
-void
-Ndb::freeRecAttr()
-{
- NdbRecAttr* tRecAttr = theRecAttrIdleList;
- theRecAttrIdleList = theRecAttrIdleList->next();
- delete tRecAttr;
-}
-
-/***************************************************************************
-void freeSignal();
-
-Remark: Delete a signal object from the signal idlelist.
-***************************************************************************/
-void
-Ndb::freeSignal()
-{
- NdbApiSignal* tSignal = theSignalIdleList;
- theSignalIdleList = tSignal->next();
- delete tSignal;
-#ifdef POORMANSPURIFY
- cfreeSignals++;
-#endif
-}
-
-void
-Ndb::freeNdbBlob()
-{
- NdbBlob* tBlob = theNdbBlobIdleList;
- theNdbBlobIdleList = tBlob->theNext;
- delete tBlob;
+ theImpl->theNdbBlobIdleList.release(aBlob);
}
/****************************************************************************
@@ -823,3 +481,102 @@ Ndb::releaseConnectToNdb(NdbConnection* a_con)
DBUG_VOID_RETURN;
}
+template<class T>
+static
+Ndb::Free_list_usage*
+update(Ndb::Free_list_usage* curr,
+ Ndb_free_list_t<T> & list,
+ const char * name)
+{
+ curr->m_name = name;
+ curr->m_created = list.m_alloc_cnt;
+ curr->m_free = list.m_free_cnt;
+ curr->m_sizeof = sizeof(T);
+ return curr;
+}
+
+Ndb::Free_list_usage*
+Ndb::get_free_list_usage(Ndb::Free_list_usage* curr)
+{
+ if (curr == 0)
+ {
+ return 0;
+ }
+
+ if(curr->m_name == 0)
+ {
+ update(curr, theImpl->theConIdleList, "NdbTransaction");
+ }
+ else if(!strcmp(curr->m_name, "NdbTransaction"))
+ {
+ update(curr, theImpl->theOpIdleList, "NdbOperation");
+ }
+ else if(!strcmp(curr->m_name, "NdbOperation"))
+ {
+ update(curr, theImpl->theScanOpIdleList, "NdbIndexScanOperation");
+ }
+ else if(!strcmp(curr->m_name, "NdbIndexScanOperation"))
+ {
+ update(curr, theImpl->theIndexOpIdleList, "NdbIndexOperation");
+ }
+ else if(!strcmp(curr->m_name, "NdbIndexOperation"))
+ {
+ update(curr, theImpl->theRecAttrIdleList, "NdbRecAttr");
+ }
+ else if(!strcmp(curr->m_name, "NdbRecAttr"))
+ {
+ update(curr, theImpl->theSignalIdleList, "NdbApiSignal");
+ }
+ else if(!strcmp(curr->m_name, "NdbApiSignal"))
+ {
+ update(curr, theImpl->theLabelList, "NdbLabel");
+ }
+ else if(!strcmp(curr->m_name, "NdbLabel"))
+ {
+ update(curr, theImpl->theBranchList, "NdbBranch");
+ }
+ else if(!strcmp(curr->m_name, "NdbBranch"))
+ {
+ update(curr, theImpl->theSubroutineList, "NdbSubroutine");
+ }
+ else if(!strcmp(curr->m_name, "NdbSubroutine"))
+ {
+ update(curr, theImpl->theCallList, "NdbCall");
+ }
+ else if(!strcmp(curr->m_name, "NdbCall"))
+ {
+ update(curr, theImpl->theNdbBlobIdleList, "NdbBlob");
+ }
+ else if(!strcmp(curr->m_name, "NdbBlob"))
+ {
+ update(curr, theImpl->theScanList, "NdbReceiver");
+ }
+ else if(!strcmp(curr->m_name, "NdbReceiver"))
+ {
+ return 0;
+ }
+ else
+ {
+ update(curr, theImpl->theConIdleList, "NdbTransaction");
+ }
+
+ return curr;
+}
+
+#define TI(T) \
+ template Ndb::Free_list_usage* \
+ update(Ndb::Free_list_usage*, Ndb_free_list_t<T> &, const char * name);\
+ template struct Ndb_free_list_t<T>
+
+TI(NdbBlob);
+TI(NdbCall);
+TI(NdbLabel);
+TI(NdbBranch);
+TI(NdbSubroutine);
+TI(NdbApiSignal);
+TI(NdbRecAttr);
+TI(NdbOperation);
+TI(NdbReceiver);
+TI(NdbConnection);
+TI(NdbIndexOperation);
+TI(NdbIndexScanOperation);
diff --git a/ndb/src/ndbapi/ObjectMap.hpp b/ndb/src/ndbapi/ObjectMap.hpp
index 21407279f0b..c730d1ce6b1 100644
--- a/ndb/src/ndbapi/ObjectMap.hpp
+++ b/ndb/src/ndbapi/ObjectMap.hpp
@@ -30,7 +30,7 @@ class NdbObjectIdMap //: NdbLockable
{
public:
STATIC_CONST( InvalidId = ~(Uint32)0 );
- NdbObjectIdMap(Uint32 initalSize = 128, Uint32 expandSize = 10);
+ NdbObjectIdMap(NdbMutex*, Uint32 initalSize = 128, Uint32 expandSize = 10);
~NdbObjectIdMap();
Uint32 map(void * object);
@@ -46,14 +46,16 @@ private:
void * m_obj;
} * m_map;
+ NdbMutex * m_mutex;
void expand(Uint32 newSize);
};
inline
-NdbObjectIdMap::NdbObjectIdMap(Uint32 sz, Uint32 eSz) {
+NdbObjectIdMap::NdbObjectIdMap(NdbMutex* mutex, Uint32 sz, Uint32 eSz) {
m_size = 0;
m_firstFree = InvalidId;
m_map = 0;
+ m_mutex = mutex;
m_expandSize = eSz;
expand(sz);
#ifdef DEBUG_OBJECTMAP
@@ -131,21 +133,26 @@ NdbObjectIdMap::getObject(Uint32 id){
inline void
NdbObjectIdMap::expand(Uint32 incSize){
+ NdbMutex_Lock(m_mutex);
Uint32 newSize = m_size + incSize;
- MapEntry * tmp = (MapEntry*)malloc(newSize * sizeof(MapEntry));
+ MapEntry * tmp = (MapEntry*)realloc(m_map, newSize * sizeof(MapEntry));
- if (m_map) {
- memcpy(tmp, m_map, m_size * sizeof(MapEntry));
- free((void*)m_map);
+ if (likely(tmp != 0))
+ {
+ m_map = tmp;
+
+ for(Uint32 i = m_size; i<newSize; i++){
+ m_map[i].m_next = i + 1;
+ }
+ m_firstFree = m_size;
+ m_map[newSize-1].m_next = InvalidId;
+ m_size = newSize;
}
- m_map = tmp;
-
- for(Uint32 i = m_size; i<newSize; i++){
- m_map[i].m_next = i + 1;
+ else
+ {
+ ndbout_c("NdbObjectIdMap::expand unable to expand!!");
}
- m_firstFree = m_size;
- m_map[newSize-1].m_next = InvalidId;
- m_size = newSize;
+ NdbMutex_Unlock(m_mutex);
}
#endif
diff --git a/ndb/test/include/NDBT_Test.hpp b/ndb/test/include/NDBT_Test.hpp
index bcaa0bf4d40..44eb24cd87e 100644
--- a/ndb/test/include/NDBT_Test.hpp
+++ b/ndb/test/include/NDBT_Test.hpp
@@ -426,7 +426,7 @@ C##suitname():NDBT_TestSuite(#suitname){ \
pt->addTable(tableName, false);
#define NDBT_TESTSUITE_END(suitname) \
- } } ; C##suitname suitname;
+ } } ; C##suitname suitname
// Helper functions for retrieving variables from NDBT_Step
#define GETNDB(ps) ((NDBT_NdbApiStep*)ps)->getNdb()
diff --git a/ndb/test/ndbapi/bank/BankLoad.cpp b/ndb/test/ndbapi/bank/BankLoad.cpp
index 39dc8097115..2cc42240234 100644
--- a/ndb/test/ndbapi/bank/BankLoad.cpp
+++ b/ndb/test/ndbapi/bank/BankLoad.cpp
@@ -321,7 +321,7 @@ int Bank::loadGl(){
m_ndb.closeTransaction(pTrans);
return NDBT_OK;
-};
+}
int Bank::getBalanceForAccountType(const Uint32 accountType,
@@ -460,7 +460,7 @@ int Bank::loadAccountType(){
m_ndb.closeTransaction(pTrans);
return NDBT_OK;
-};
+}
/**
* Load ACCOUNT table
diff --git a/ndb/test/ndbapi/testOIBasic.cpp b/ndb/test/ndbapi/testOIBasic.cpp
index 9f8da850ff4..30a76da306a 100644
--- a/ndb/test/ndbapi/testOIBasic.cpp
+++ b/ndb/test/ndbapi/testOIBasic.cpp
@@ -2187,7 +2187,7 @@ pkinsert(Par par)
}
con.closeTransaction();
return 0;
-};
+}
static int
pkupdate(Par par)
@@ -2250,7 +2250,7 @@ pkupdate(Par par)
}
con.closeTransaction();
return 0;
-};
+}
static int
pkdelete(Par par)
@@ -2306,7 +2306,7 @@ pkdelete(Par par)
}
con.closeTransaction();
return 0;
-};
+}
static int
pkread(Par par)
diff --git a/ndb/test/src/HugoCalculator.cpp b/ndb/test/src/HugoCalculator.cpp
index 62c35c54a7a..86ff76831d7 100644
--- a/ndb/test/src/HugoCalculator.cpp
+++ b/ndb/test/src/HugoCalculator.cpp
@@ -51,7 +51,7 @@ HugoCalculator::HugoCalculator(const NdbDictionary::Table& tab) : m_tab(tab) {
#endif
// Check that idCol is not conflicting with updatesCol
assert(m_idCol != m_updatesCol && m_idCol != -1 && m_updatesCol != -1);
-};
+}
Int32
HugoCalculator::calcValue(int record,
@@ -73,7 +73,7 @@ HugoCalculator::calcValue(int record,
else
val = record + attrib + updates;
return val;
-};
+}
#if 0
HugoCalculator::U_Int32 calcValue(int record, int attrib, int updates) const;
HugoCalculator::U_Int64 calcValue(int record, int attrib, int updates) const;
@@ -123,7 +123,7 @@ HugoCalculator::calcValue(int record,
buf[len] = 0;
}
return buf;
-};
+}
int
HugoCalculator::verifyRowValues(NDBT_ResultRow* const pRow) const{
diff --git a/ndb/test/src/NDBT_Test.cpp b/ndb/test/src/NDBT_Test.cpp
index 6355c21c997..42bae193b35 100644
--- a/ndb/test/src/NDBT_Test.cpp
+++ b/ndb/test/src/NDBT_Test.cpp
@@ -624,7 +624,7 @@ int NDBT_TestCase::execute(NDBT_Context* ctx){
<< endl;
}
return res;
-};
+}
void NDBT_TestCase::startTimer(NDBT_Context* ctx){
diff --git a/ndb/test/src/NdbBackup.cpp b/ndb/test/src/NdbBackup.cpp
index 1e56db83c11..9f65fe6b3bc 100644
--- a/ndb/test/src/NdbBackup.cpp
+++ b/ndb/test/src/NdbBackup.cpp
@@ -345,7 +345,7 @@ NdbBackup::NF(NdbRestarter& _restarter, int *NFDuringBackup_codes, const int sz,
}
return NDBT_OK;
-};
+}
int
FailS_codes[] = {
diff --git a/ndb/test/src/NdbRestarts.cpp b/ndb/test/src/NdbRestarts.cpp
index 607e48c4126..c0f31af84ce 100644
--- a/ndb/test/src/NdbRestarts.cpp
+++ b/ndb/test/src/NdbRestarts.cpp
@@ -213,7 +213,7 @@ NdbRestarts::NdbRestart::NdbRestart(const char* _name,
m_restartFunc = _func;
m_numRequiredNodes = _requiredNodes;
// m_arg1 = arg1;
-};
+}
int NdbRestarts::getNumRestarts(){
@@ -367,7 +367,7 @@ int restartRandomNodeGraceful(NdbRestarter& _restarter,
"Could not restart node "<<nodeId);
return NDBT_OK;
-};
+}
int restartRandomNodeAbort(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -382,7 +382,7 @@ int restartRandomNodeAbort(NdbRestarter& _restarter,
"Could not restart node "<<nodeId);
return NDBT_OK;
-};
+}
int restartRandomNodeError(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -397,7 +397,7 @@ int restartRandomNodeError(NdbRestarter& _restarter,
"Could not restart node "<<nodeId);
return NDBT_OK;
-};
+}
int restartMasterNodeError(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -410,7 +410,7 @@ int restartMasterNodeError(NdbRestarter& _restarter,
"Could not restart node "<<nodeId);
return NDBT_OK;
-};
+}
int restartRandomNodeInitial(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -425,7 +425,7 @@ int restartRandomNodeInitial(NdbRestarter& _restarter,
"Could not restart node "<<nodeId);
return NDBT_OK;
-};
+}
int twoNodeFailure(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -453,7 +453,7 @@ int twoNodeFailure(NdbRestarter& _restarter,
"Could not restart node "<< nodeId);
return NDBT_OK;
-};
+}
int twoMasterNodeFailure(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -478,7 +478,7 @@ int twoMasterNodeFailure(NdbRestarter& _restarter,
"Could not restart node "<< nodeId);
return NDBT_OK;
-};
+}
int get50PercentOfNodes(NdbRestarter& restarter,
int * _nodes){
@@ -519,7 +519,7 @@ int fiftyPercentFail(NdbRestarter& _restarter,
"Could not start all nodes");
return NDBT_OK;
-};
+}
int restartAllNodesGracfeul(NdbRestarter& _restarter,
@@ -533,7 +533,7 @@ int restartAllNodesGracfeul(NdbRestarter& _restarter,
return NDBT_OK;
-};
+}
int restartAllNodesAbort(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -545,7 +545,7 @@ int restartAllNodesAbort(NdbRestarter& _restarter,
"Could not restart all nodes");
return NDBT_OK;
-};
+}
int restartAllNodesError9999(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -557,7 +557,7 @@ int restartAllNodesError9999(NdbRestarter& _restarter,
"Could not restart all nodes ");
return NDBT_OK;
-};
+}
int fiftyPercentStopAndWait(NdbRestarter& _restarter,
const NdbRestarts::NdbRestart* _restart){
@@ -590,7 +590,7 @@ int fiftyPercentStopAndWait(NdbRestarter& _restarter,
g_info << _restart->m_name << endl;
return NDBT_OK;
-};
+}
int
NFDuringNR_codes[] = {
@@ -713,7 +713,7 @@ int restartNFDuringNR(NdbRestarter& _restarter,
}
return NDBT_OK;
-};
+}
int
NRDuringLCP_Master_codes[] = {
@@ -864,7 +864,7 @@ int stopOnError(NdbRestarter& _restarter,
} while (false);
return NDBT_OK;
-};
+}
int getRandomNodeId(NdbRestarter& _restarter) {
myRandom48Init(NdbTick_CurrentMillisecond());
diff --git a/ndb/tools/restore/Restore.cpp b/ndb/tools/restore/Restore.cpp
index 26bc08c63a9..79df49c6f26 100644
--- a/ndb/tools/restore/Restore.cpp
+++ b/ndb/tools/restore/Restore.cpp
@@ -869,7 +869,7 @@ operator<<(NdbOut& ndbout, const AttributeS& attr){
return ndbout;
}
- NdbRecAttr tmprec;
+ NdbRecAttr tmprec(0);
tmprec.setup(desc.m_column, (char *)data.void_value);
ndbout << tmprec;
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 7998dd6d5f8..d61b3735c91 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -599,6 +599,9 @@ void field_conv(Field *to,Field *from)
!(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) &&
to->real_type() != FIELD_TYPE_ENUM &&
to->real_type() != FIELD_TYPE_SET &&
+ (to->real_type() != FIELD_TYPE_DECIMAL ||
+ (to->field_length == from->field_length &&
+ (((Field_num*) to)->dec == ((Field_num*) from)->dec))) &&
from->charset() == to->charset() &&
to->table->db_low_byte_first == from->table->db_low_byte_first)
{ // Identical fields
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index d8608c6a599..615cecb7a19 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -39,6 +39,12 @@ const char *myisam_recover_names[] =
TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
myisam_recover_names, NULL};
+const char *myisam_stats_method_names[] = {"nulls_inequal", "nulls_equal",
+ NullS};
+TYPELIB myisam_stats_method_typelib= {
+ array_elements(myisam_stats_method_names) - 1, "",
+ myisam_stats_method_names, NULL};
+
/*****************************************************************************
** MyISAM tables
@@ -278,6 +284,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt)
param.db_name = table->table_cache_key;
param.table_name = table->table_name;
param.testflag = check_opt->flags | T_CHECK | T_SILENT;
+ param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
if (!(table->db_stat & HA_READ_ONLY))
param.testflag|= T_STATISTICS;
@@ -367,6 +374,7 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
param.testflag=(T_FAST | T_CHECK | T_SILENT | T_STATISTICS |
T_DONT_CHECK_CHECKSUM);
param.using_global_keycache = 1;
+ param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
if (!(share->state.changed & STATE_NOT_ANALYZED))
return HA_ADMIN_ALREADY_DONE;
@@ -920,6 +928,7 @@ int ha_myisam::enable_indexes(uint mode)
T_CREATE_MISSING_KEYS);
param.myf_rw&= ~MY_WAIT_IF_FULL;
param.sort_buffer_length= thd->variables.myisam_sort_buff_size;
+ param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method;
param.tmpdir=&mysql_tmpdir_list;
if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair)
{
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index d1de0bd100e..cc60c807bc9 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -5096,4 +5096,50 @@ int ha_ndbcluster::write_ndb_file()
DBUG_RETURN(error);
}
+int
+ndbcluster_show_status(THD* thd)
+{
+ Protocol *protocol= thd->protocol;
+
+ DBUG_ENTER("ndbcluster_show_status");
+
+ if (have_ndbcluster != SHOW_OPTION_YES)
+ {
+ my_message(ER_NOT_SUPPORTED_YET,
+ "Cannot call SHOW NDBCLUSTER STATUS because skip-ndbcluster is defined",
+ MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
+ List<Item> field_list;
+ field_list.push_back(new Item_empty_string("free_list", 255));
+ field_list.push_back(new Item_return_int("created", 10,MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_return_int("free", 10,MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_return_int("sizeof", 10,MYSQL_TYPE_LONG));
+
+ if (protocol->send_fields(&field_list, 1))
+ DBUG_RETURN(TRUE);
+
+ if (thd->transaction.thd_ndb &&
+ ((Thd_ndb*)thd->transaction.thd_ndb)->ndb)
+ {
+ Ndb* ndb= ((Thd_ndb*)thd->transaction.thd_ndb)->ndb;
+ Ndb::Free_list_usage tmp; tmp.m_name= 0;
+ while (ndb->get_free_list_usage(&tmp))
+ {
+ protocol->prepare_for_resend();
+
+ protocol->store(tmp.m_name, &my_charset_bin);
+ protocol->store((uint)tmp.m_created);
+ protocol->store((uint)tmp.m_free);
+ protocol->store((uint)tmp.m_sizeof);
+ if (protocol->write())
+ DBUG_RETURN(TRUE);
+ }
+ }
+ send_eof(thd);
+
+ DBUG_RETURN(FALSE);
+}
+
#endif /* HAVE_NDBCLUSTER_DB */
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index 4b3a30fb9b9..90d5d59cabe 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -279,3 +279,5 @@ int ndbcluster_table_exists_in_engine(THD* thd,
int ndbcluster_drop_database(const char* path);
void ndbcluster_print_error(int error, const NdbOperation *error_op);
+
+int ndbcluster_show_status(THD*);
diff --git a/sql/handler.h b/sql/handler.h
index b69eec3edd5..d4bb19dd7b2 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -522,6 +522,7 @@ public:
extern struct show_table_type_st sys_table_types[];
extern const char *ha_row_type[];
extern TYPELIB tx_isolation_typelib;
+extern TYPELIB myisam_stats_method_typelib;
/* Wrapper functions */
#define ha_commit_stmt(thd) (ha_commit_trans((thd), &((thd)->transaction.stmt)))
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 0d889aaf0b1..32c5861028e 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -59,6 +59,7 @@ void kill_one_thread(THD *thd, ulong id);
bool net_request_file(NET* net, const char* fname);
char* query_table_status(THD *thd,const char *db,const char *table_name);
+
#define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); }
#define safeFree(x) { if(x) { my_free((gptr) x,MYF(0)); x = NULL; } }
#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
@@ -464,6 +465,7 @@ void mysql_reset_thd_for_next_command(THD *thd);
bool mysql_new_select(LEX *lex, bool move_down);
void create_select_for_variable(const char *var_name);
void mysql_init_multi_delete(LEX *lex);
+void fix_multi_delete_lex(LEX* lex);
void init_max_user_conn(void);
void init_update_queries(void);
void free_max_user_conn(void);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 86ba437596d..764b89812f5 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -369,6 +369,7 @@ char *mysqld_unix_port, *opt_mysql_tmpdir;
char *my_bind_addr_str;
const char **errmesg; /* Error messages */
const char *myisam_recover_options_str="OFF";
+const char *myisam_stats_method_str="nulls_inequal";
const char *sql_mode_str="OFF";
/* name of reference on left espression in rewritten IN subquery */
const char *in_left_expr_name= "<left expr>";
@@ -4169,6 +4170,7 @@ enum options_mysqld
OPT_MAX_ERROR_COUNT, OPT_MYISAM_DATA_POINTER_SIZE,
OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE,
+ OPT_MYISAM_STATS_METHOD,
OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT,
OPT_NET_READ_TIMEOUT, OPT_NET_WRITE_TIMEOUT,
OPT_OPEN_FILES_LIMIT,
@@ -5208,6 +5210,11 @@ The minimum value for this variable is 4096.",
(gptr*) &global_system_variables.myisam_sort_buff_size,
(gptr*) &max_system_variables.myisam_sort_buff_size, 0,
GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0},
+ {"myisam_stats_method", OPT_MYISAM_STATS_METHOD,
+ "Specifies how MyISAM index statistics collection code should threat NULLs. "
+ "Possible values of name are \"nulls_inequal\" (default behavior for 4.1/5.0), and \"nulls_equal\" (emulate 4.0 behavior).",
+ (gptr*) &myisam_stats_method_str, (gptr*) &myisam_stats_method_str, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"net_buffer_length", OPT_NET_BUFFER_LENGTH,
"Buffer length for TCP/IP and socket communication.",
(gptr*) &global_system_variables.net_buffer_length,
@@ -5492,6 +5499,7 @@ struct show_var_st status_vars[]= {
{"Com_show_fields", (char*) (com_stat+(uint) SQLCOM_SHOW_FIELDS),SHOW_LONG},
{"Com_show_grants", (char*) (com_stat+(uint) SQLCOM_SHOW_GRANTS),SHOW_LONG},
{"Com_show_innodb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_INNODB_STATUS),SHOW_LONG},
+ {"Com_show_ndb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_NDBCLUSTER_STATUS),SHOW_LONG},
{"Com_show_keys", (char*) (com_stat+(uint) SQLCOM_SHOW_KEYS),SHOW_LONG},
{"Com_show_logs", (char*) (com_stat+(uint) SQLCOM_SHOW_LOGS),SHOW_LONG},
{"Com_show_master_status", (char*) (com_stat+(uint) SQLCOM_SHOW_MASTER_STAT),SHOW_LONG},
@@ -5759,6 +5767,7 @@ static void mysql_init_variables(void)
query_id= thread_id= 1L;
strmov(server_version, MYSQL_SERVER_VERSION);
myisam_recover_options_str= sql_mode_str= "OFF";
+ myisam_stats_method_str= "nulls_inequal";
my_bind_addr = htonl(INADDR_ANY);
threads.empty();
thread_cache.empty();
@@ -5807,6 +5816,12 @@ static void mysql_init_variables(void)
global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
global_system_variables.old_passwords= 0;
+
+ /*
+ Default behavior for 4.1 and 5.0 is to treat NULL values as inequal
+ when collecting index statistics for MyISAM tables.
+ */
+ global_system_variables.myisam_stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
/* Variables that depends on compile options */
#ifndef DBUG_OFF
@@ -6388,6 +6403,20 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
ha_open_options|=HA_OPEN_ABORT_IF_CRASHED;
break;
}
+ case OPT_MYISAM_STATS_METHOD:
+ {
+ myisam_stats_method_str= argument;
+ int method;
+ if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0)
+ {
+ fprintf(stderr, "Invalid value of myisam_stats_method: %s.\n", argument);
+ exit(1);
+ }
+ global_system_variables.myisam_stats_method=
+ test(method-1)? MI_STATS_METHOD_NULLS_EQUAL :
+ MI_STATS_METHOD_NULLS_NOT_EQUAL;
+ break;
+ }
case OPT_SQL_MODE:
{
sql_mode_str= argument;
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 4ab506cc4e1..cb8e3c2d273 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -661,7 +661,8 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
If key_part2 may be NULL, then we want to find the first row
that is not null
*/
- ref->key_buff[ref->key_length++]= 1;
+ ref->key_buff[ref->key_length]= 1;
+ ref->key_length+= part->store_length;
*range_fl&= ~NO_MIN_RANGE;
*range_fl|= NEAR_MIN; // > NULL
}
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 94968f664fd..e10bfda62b7 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -256,6 +256,12 @@ sys_var_thd_ulonglong sys_myisam_max_extra_sort_file_size("myisam_max_extra_sort
sys_var_thd_ulonglong sys_myisam_max_sort_file_size("myisam_max_sort_file_size", &SV::myisam_max_sort_file_size, fix_myisam_max_sort_file_size, 1);
sys_var_thd_ulong sys_myisam_repair_threads("myisam_repair_threads", &SV::myisam_repair_threads);
sys_var_thd_ulong sys_myisam_sort_buffer_size("myisam_sort_buffer_size", &SV::myisam_sort_buff_size);
+
+sys_var_thd_enum sys_myisam_stats_method("myisam_stats_method",
+ &SV::myisam_stats_method,
+ &myisam_stats_method_typelib,
+ NULL);
+
sys_var_thd_ulong sys_net_buffer_length("net_buffer_length",
&SV::net_buffer_length);
sys_var_thd_ulong sys_net_read_timeout("net_read_timeout",
@@ -574,6 +580,7 @@ sys_var *sys_variables[]=
&sys_myisam_max_sort_file_size,
&sys_myisam_repair_threads,
&sys_myisam_sort_buffer_size,
+ &sys_myisam_stats_method,
&sys_net_buffer_length,
&sys_net_read_timeout,
&sys_net_retry_count,
@@ -810,6 +817,9 @@ struct show_var_st init_vars[]= {
{sys_myisam_repair_threads.name, (char*) &sys_myisam_repair_threads,
SHOW_SYS},
{sys_myisam_sort_buffer_size.name, (char*) &sys_myisam_sort_buffer_size, SHOW_SYS},
+
+ {sys_myisam_stats_method.name, (char*) &sys_myisam_stats_method, SHOW_SYS},
+
#ifdef __NT__
{"named_pipe", (char*) &opt_enable_named_pipe, SHOW_MY_BOOL},
#endif
diff --git a/sql/slave.cc b/sql/slave.cc
index 9ff7a432b89..1be3e3b4a17 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -746,14 +746,7 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
rules (see code below). For that reason, users should not set conflicting
rules because they may get unpredicted results (precedence order is
explained in the manual).
- If no table of the list is marked "updating" (so far this can only happen
- if the statement is a multi-delete (SQLCOM_DELETE_MULTI) and the "tables"
- is the tables in the FROM): then we always return 0, because there is no
- reason we play this statement on this slave if it updates nothing. In the
- case of SQLCOM_DELETE_MULTI, there will be a second call to tables_ok(),
- with tables having "updating==TRUE" (those after the DELETE), so this
- second call will make the decision (because
- all_tables_not_ok() = !tables_ok(1st_list) && !tables_ok(2nd_list)).
+
RETURN VALUES
0 should not be logged/replicated
diff --git a/sql/sql_class.h b/sql/sql_class.h
index bc651b32d94..41170192892 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -363,6 +363,7 @@ struct system_variables
ulong max_insert_delayed_threads;
ulong myisam_repair_threads;
ulong myisam_sort_buff_size;
+ ulong myisam_stats_method;
ulong net_buffer_length;
ulong net_interactive_timeout;
ulong net_read_timeout;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 07b5c9d8edf..8d919f12563 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -49,7 +49,7 @@ enum enum_sql_command {
SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS,
SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_LOGS, SQLCOM_SHOW_STATUS,
- SQLCOM_SHOW_INNODB_STATUS,
+ SQLCOM_SHOW_INNODB_STATUS,SQLCOM_SHOW_NDBCLUSTER_STATUS,
SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT,
SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS,
SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB,
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index c4f5b1427af..7b963c7ea31 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -114,6 +114,10 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
MYF(0));
DBUG_RETURN(-1);
}
+ /*
+ This needs to be done before external_lock
+ */
+ ha_enable_transaction(thd, FALSE);
if (!(table = open_ltable(thd,table_list,lock_type)))
DBUG_RETURN(-1);
transactional_table= table->file->has_transactions();
@@ -273,7 +277,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (ignore ||
handle_duplicates == DUP_REPLACE)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- ha_enable_transaction(thd, FALSE);
table->file->start_bulk_insert((ha_rows) 0);
table->copy_blobs=1;
if (!field_term->length() && !enclosed->length())
@@ -284,10 +287,10 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
skip_lines);
if (table->file->end_bulk_insert())
error=1; /* purecov: inspected */
- ha_enable_transaction(thd, TRUE);
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->next_number_field=0;
}
+ ha_enable_transaction(thd, TRUE);
if (file >= 0)
my_close(file,MYF(0));
free_blobs(table); /* if pack_blob was used */
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 131fe3d691d..5d233fd7be0 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -25,6 +25,10 @@
#include "ha_innodb.h"
#endif
+#ifdef HAVE_NDBCLUSTER_DB
+#include "ha_ndbcluster.h"
+#endif
+
#ifdef HAVE_OPENSSL
/*
Without SSL the handshake consists of one packet. This packet
@@ -59,6 +63,9 @@ static void remove_escape(char *name);
static void refresh_status(void);
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
const char *table_name);
+
+static TABLE_LIST* get_table_by_alias(TABLE_LIST* tl, const char* db,
+ const char* alias);
const char *any_db="*any*"; // Special symbol for check_access
@@ -125,10 +132,7 @@ static bool end_active_trans(THD *thd)
*/
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
{
- return (table_rules_on && tables && !tables_ok(thd,tables) &&
- ((thd->lex->sql_command != SQLCOM_DELETE_MULTI) ||
- !tables_ok(thd,
- (TABLE_LIST *)thd->lex->auxilliary_table_list.first)));
+ return (table_rules_on && tables && !tables_ok(thd,tables));
}
#endif
@@ -2386,6 +2390,13 @@ mysql_execute_command(THD *thd)
res = load_master_data(thd);
break;
#endif /* HAVE_REPLICATION */
+#ifdef HAVE_NDBCLUSTER_DB
+ case SQLCOM_SHOW_NDBCLUSTER_STATUS:
+ {
+ res = ndbcluster_show_status(thd);
+ break;
+ }
+#endif
#ifdef HAVE_INNOBASE_DB
case SQLCOM_SHOW_INNODB_STATUS:
{
@@ -4245,6 +4256,40 @@ void create_select_for_variable(const char *var_name)
DBUG_VOID_RETURN;
}
+static TABLE_LIST* get_table_by_alias(TABLE_LIST* tl, const char* db,
+ const char* alias)
+{
+ for (;tl;tl= tl->next)
+ {
+ if (!strcmp(db,tl->db) &&
+ tl->alias && !my_strcasecmp(table_alias_charset,tl->alias,alias))
+ return tl;
+ }
+
+ return 0;
+}
+
+/* Sets up lex->auxilliary_table_list */
+void fix_multi_delete_lex(LEX* lex)
+{
+ TABLE_LIST *tl;
+ TABLE_LIST *good_list= (TABLE_LIST*)lex->select_lex.table_list.first;
+
+ for (tl= (TABLE_LIST*)lex->auxilliary_table_list.first; tl; tl= tl->next)
+ {
+ TABLE_LIST* good_table= get_table_by_alias(good_list,tl->db,tl->alias);
+ if (good_table && !good_table->derived)
+ {
+ /*
+ real_name points to a member of Table_ident which is
+ allocated via thd->strmake() from THD memroot
+ */
+ tl->real_name= good_table->real_name;
+ tl->real_name_length= good_table->real_name_length;
+ good_table->updating= tl->updating;
+ }
+ }
+}
void mysql_init_multi_delete(LEX *lex)
{
@@ -5567,13 +5612,7 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
(*table_count)++;
/* All tables in aux_tables must be found in FROM PART */
TABLE_LIST *walk;
- for (walk= delete_tables; walk; walk= walk->next)
- {
- if (!my_strcasecmp(table_alias_charset,
- target_tbl->alias, walk->alias) &&
- !strcmp(walk->db, target_tbl->db))
- break;
- }
+ walk= get_table_by_alias(delete_tables,target_tbl->db,target_tbl->alias);
if (!walk)
{
my_error(ER_UNKNOWN_TABLE, MYF(0), target_tbl->real_name,
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 6283cad7cc8..670e9a9bcb4 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4295,12 +4295,10 @@ single_multi:
}
where_clause opt_order_clause
delete_limit_clause {}
- | table_wild_list
- { mysql_init_multi_delete(Lex); }
- FROM join_table_list where_clause
- | FROM table_wild_list
- { mysql_init_multi_delete(Lex); }
- USING join_table_list where_clause
+ | table_wild_list {mysql_init_multi_delete(Lex);}
+ FROM join_table_list {fix_multi_delete_lex(Lex);} where_clause
+ | FROM table_wild_list { mysql_init_multi_delete(Lex);}
+ USING join_table_list {fix_multi_delete_lex(Lex);} where_clause
{}
;
@@ -4533,6 +4531,9 @@ show_engine_param:
STATUS_SYM
{
switch (Lex->create_info.db_type) {
+ case DB_TYPE_NDBCLUSTER:
+ Lex->sql_command = SQLCOM_SHOW_NDBCLUSTER_STATUS;
+ break;
case DB_TYPE_INNODB:
Lex->sql_command = SQLCOM_SHOW_INNODB_STATUS;
break;